mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-07 11:36:55 +00:00
Compare commits
12 Commits
feat/repls
...
v0.12.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61fd13629f | ||
|
|
47336a7940 | ||
|
|
4ea8f90c0d | ||
|
|
fb8fe16557 | ||
|
|
f2c056a151 | ||
|
|
f30b729ca9 | ||
|
|
f81e3291bd | ||
|
|
1e80916b65 | ||
|
|
8814bf4c23 | ||
|
|
5466ada9ae | ||
|
|
f0e513ccae | ||
|
|
4d4b0dd864 |
24
.github/pull_request_template.md
vendored
Normal file
24
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<!-- Describe your changes -->
|
||||
|
||||
Fixes # (issue)
|
||||
|
||||
## How was this PR tested?
|
||||
|
||||
<!-- What did you do to test your changes? -->
|
||||
|
||||
- [ ] Test A
|
||||
- [ ] Test B
|
||||
|
||||
## Checklist:
|
||||
|
||||
- [ ] I have carefully read [the contributing guidelines](https://developers.stoat.chat/developing/contrib/)
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have made corresponding changes to the documentation if applicable
|
||||
- [ ] I have no unrelated changes in the PR
|
||||
- [ ] I have confirmed that any new dependencies are strictly necessary
|
||||
- [ ] I have written tests for new code (if applicable)
|
||||
- [ ] I have followed naming conventions/patterns in the surrounding code
|
||||
|
||||
## Please declare, if any, LLM usage involved in creating this PR
|
||||
|
||||
...
|
||||
@@ -16,4 +16,13 @@ idiomatic_version_file_enable_tools = ["rust"]
|
||||
[tasks.start]
|
||||
description = "Run all services"
|
||||
depends = ["docker:start", "build"]
|
||||
wait_for = ["docker:start", "build"]
|
||||
run = [{ task = "service:*" }]
|
||||
|
||||
[env]
|
||||
BUILDER = "cargo"
|
||||
DOCKER_NETWORK_NAME = "stoatchat_default"
|
||||
DATABASE_PORT = "27017"
|
||||
RABBIT_PORT = "5672"
|
||||
REDIS_PORT = "6379"
|
||||
_.file = { path = ".env", tools = true }
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
#MISE description="Build project"
|
||||
set -e
|
||||
|
||||
cargo build "$@"
|
||||
${BUILDER} build "$@"
|
||||
|
||||
@@ -3,3 +3,11 @@
|
||||
set -e
|
||||
|
||||
docker compose up -d
|
||||
|
||||
docker run \
|
||||
--network=${DOCKER_NETWORK_NAME} \
|
||||
--name wait \
|
||||
--rm dokku/wait -c \
|
||||
rabbit:${RABBIT_PORT},\
|
||||
database:${DATABASE_PORT},\
|
||||
redis:${REDIS_PORT}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
".": "0.11.5"
|
||||
".": "0.12.1"
|
||||
}
|
||||
47
CHANGELOG.md
47
CHANGELOG.md
@@ -1,5 +1,52 @@
|
||||
# Changelog
|
||||
|
||||
## [0.12.1](https://github.com/stoatchat/stoatchat/compare/v0.12.0...v0.12.1) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add migration to update existing files to be animated ([#705](https://github.com/stoatchat/stoatchat/issues/705)) ([f2c056a](https://github.com/stoatchat/stoatchat/commit/f2c056a1515be493b195f3f5db5886c2ddf36700))
|
||||
* don't send self dm notifications ([#706](https://github.com/stoatchat/stoatchat/issues/706)) ([f30b729](https://github.com/stoatchat/stoatchat/commit/f30b729ca90d0be6853c57ab4935694e5e59ae56))
|
||||
* mise start + missing docker image ([#564](https://github.com/stoatchat/stoatchat/issues/564)) ([fb8fe16](https://github.com/stoatchat/stoatchat/commit/fb8fe1655776791421284a6a093e86f0320c258a))
|
||||
* test failure due to wrong assertion ([#707](https://github.com/stoatchat/stoatchat/issues/707)) ([f81e329](https://github.com/stoatchat/stoatchat/commit/f81e3291bdd57af9ceedb2987b111acc7051d69c))
|
||||
|
||||
## [0.12.0](https://github.com/stoatchat/stoatchat/compare/v0.11.5...v0.12.0) (2026-03-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add bug report template for issue tracking ([#627](https://github.com/stoatchat/stoatchat/issues/627)) ([f777e28](https://github.com/stoatchat/stoatchat/commit/f777e2863c6ca50057c8b5d0a5be14915d287724))
|
||||
* Add slowmode functionality to text channels ([#680](https://github.com/stoatchat/stoatchat/issues/680)) ([6107f24](https://github.com/stoatchat/stoatchat/commit/6107f242fd3ebaff71a15f9a16330ffbcb4f2d7b))
|
||||
* Allow restricting server creation to specific users ([#685](https://github.com/stoatchat/stoatchat/issues/685)) ([edfa97d](https://github.com/stoatchat/stoatchat/commit/edfa97db108c9c81828547f98a1db5315cb5ba4a))
|
||||
* compute thumbhash for images ([#596](https://github.com/stoatchat/stoatchat/issues/596)) ([c2d4369](https://github.com/stoatchat/stoatchat/commit/c2d4369e160f32d79bce0a0b0f14677f89de3669))
|
||||
* Detect animation in image files for fetch_preview ([#574](https://github.com/stoatchat/stoatchat/issues/574)) ([3fa0abf](https://github.com/stoatchat/stoatchat/commit/3fa0abf47f5f42ddd8ee041fe4c44fbc5ba800c1))
|
||||
* expose global and user limits in root API response ([#644](https://github.com/stoatchat/stoatchat/issues/644)) ([0b522eb](https://github.com/stoatchat/stoatchat/commit/0b522ebddc17f2e3f792ff5e2347793e9849fa23))
|
||||
* implement time based message sweep on user ban ([#670](https://github.com/stoatchat/stoatchat/issues/670)) ([98c7b1b](https://github.com/stoatchat/stoatchat/commit/98c7b1b5a5b9fdac5c0ab83be10f0e23114dbfc9))
|
||||
* load config from env vars ([#576](https://github.com/stoatchat/stoatchat/issues/576)) ([5191bd1](https://github.com/stoatchat/stoatchat/commit/5191bd16b2a905b8409838e34eb0baca96f08580))
|
||||
* parse message push notification content and replace internal formatting ([#693](https://github.com/stoatchat/stoatchat/issues/693)) ([d1e72ce](https://github.com/stoatchat/stoatchat/commit/d1e72cee42c54e16f4e49af569897528b10a28ca))
|
||||
* Transfer ownership ([#396](https://github.com/stoatchat/stoatchat/issues/396)) ([735d644](https://github.com/stoatchat/stoatchat/commit/735d644e043793cb86e74aab5b88bb4b8bc17ba2))
|
||||
* update livekit ([#698](https://github.com/stoatchat/stoatchat/issues/698)) ([f181edc](https://github.com/stoatchat/stoatchat/commit/f181edc8f2ff3ce4b6d48938dfc73931ecfa2279))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add flag for disabling events instead of commenting them out ([#695](https://github.com/stoatchat/stoatchat/issues/695)) ([a5cd08a](https://github.com/stoatchat/stoatchat/commit/a5cd08a655dece4269f3ac84fa2387ae356709a5))
|
||||
* add masquerade permission to default direct message settings ([#665](https://github.com/stoatchat/stoatchat/issues/665)) ([ab52569](https://github.com/stoatchat/stoatchat/commit/ab525699bd6663333f0e9fed6d2455e482e6a09f))
|
||||
* Check for appropriate permission for removing other users avatar ([#657](https://github.com/stoatchat/stoatchat/issues/657)) ([d56135e](https://github.com/stoatchat/stoatchat/commit/d56135e0cbc713884c9378832952f7ad490fa315))
|
||||
* default video resolution is a non-existent size ([#601](https://github.com/stoatchat/stoatchat/issues/601)) ([0698e11](https://github.com/stoatchat/stoatchat/commit/0698e115e8d003d615e468c4fb9654e6bbc9107f)), closes [#588](https://github.com/stoatchat/stoatchat/issues/588)
|
||||
* **docs:** Update GitHub links ([#647](https://github.com/stoatchat/stoatchat/issues/647)) ([b830631](https://github.com/stoatchat/stoatchat/commit/b830631bd25a546844b7bdd30386084bb365e4de))
|
||||
* don't use a bitop for OR ([#676](https://github.com/stoatchat/stoatchat/issues/676)) ([5701b5c](https://github.com/stoatchat/stoatchat/commit/5701b5c18c513f796af365169ceaea372a22638c))
|
||||
* Fix typo for p256dh in vapid notification flow ([#622](https://github.com/stoatchat/stoatchat/issues/622)) ([a80ad1c](https://github.com/stoatchat/stoatchat/commit/a80ad1cbe58b8af5e45751e51d94d93c1cea1c9f))
|
||||
* improve generated openapi.json ([#584](https://github.com/stoatchat/stoatchat/issues/584)) ([52ed510](https://github.com/stoatchat/stoatchat/commit/52ed5100c2446e0b261085639e123e7e124cab2c))
|
||||
* no node state set on channel creation ([#653](https://github.com/stoatchat/stoatchat/issues/653)) ([24d0d2b](https://github.com/stoatchat/stoatchat/commit/24d0d2b7266f6f8a692d0a52704acfecf517674c))
|
||||
* only show first line on commit messages ([#696](https://github.com/stoatchat/stoatchat/issues/696)) ([91783b9](https://github.com/stoatchat/stoatchat/commit/91783b906697fc85305dee683f7c15dda55f0c50))
|
||||
* pass &str to Reference ([#697](https://github.com/stoatchat/stoatchat/issues/697)) ([ccda6f5](https://github.com/stoatchat/stoatchat/commit/ccda6f5c53ee043705f7ff6b5f6c393f020781de))
|
||||
* redis_url vs redis_uri in config ([#666](https://github.com/stoatchat/stoatchat/issues/666)) ([b0b728f](https://github.com/stoatchat/stoatchat/commit/b0b728fb0dbc9ee28360301de1c3ea501bbbff1d))
|
||||
* replace some links and Revolt mentions to current Stoat ([#515](https://github.com/stoatchat/stoatchat/issues/515)) ([d629e89](https://github.com/stoatchat/stoatchat/commit/d629e89304be2f0011e189293b278f07d346aa7d))
|
||||
* send push notifications for DM and group messages ([#660](https://github.com/stoatchat/stoatchat/issues/660)) ([52c0d2f](https://github.com/stoatchat/stoatchat/commit/52c0d2f266b76d8975bba2d5e75c62bb30149c45))
|
||||
* store server id in redis and in room metadata to be able to delete voice state in all scenarios ([#656](https://github.com/stoatchat/stoatchat/issues/656)) ([49c6289](https://github.com/stoatchat/stoatchat/commit/49c628958070e4f0a5edc764d3b48158589219d9))
|
||||
* uname is missing from crond ([#675](https://github.com/stoatchat/stoatchat/issues/675)) ([dc4438b](https://github.com/stoatchat/stoatchat/commit/dc4438bc3c7b2cad8d442b3cd438afb9ed566a5e))
|
||||
|
||||
## [0.11.5](https://github.com/stoatchat/stoatchat/compare/v0.11.4...v0.11.5) (2026-02-17)
|
||||
|
||||
|
||||
|
||||
36
Cargo.lock
generated
36
Cargo.lock
generated
@@ -6798,7 +6798,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-autumn"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-macros",
|
||||
@@ -6837,7 +6837,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"async-channel 2.5.0",
|
||||
"async-std",
|
||||
@@ -6868,7 +6868,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-coalesced"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"indexmap 2.13.0",
|
||||
"lru 0.16.3",
|
||||
@@ -6877,7 +6877,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-config"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"cached",
|
||||
@@ -6894,7 +6894,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-crond"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"revolt-config",
|
||||
@@ -6906,7 +6906,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-database"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"amqprs",
|
||||
"async-lock 2.8.0",
|
||||
@@ -6956,7 +6956,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-delta"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"amqprs",
|
||||
"async-channel 1.9.0",
|
||||
@@ -7006,7 +7006,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-files"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
@@ -7034,7 +7034,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-gifbox"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-extra",
|
||||
@@ -7057,7 +7057,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-january"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"axum",
|
||||
@@ -7085,7 +7085,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-models"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"indexmap 1.9.3",
|
||||
"iso8601-timestamp",
|
||||
@@ -7104,14 +7104,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-parser"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"logos",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "revolt-permissions"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-trait",
|
||||
@@ -7126,7 +7126,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-presence"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"log",
|
||||
@@ -7138,7 +7138,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-pushd"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"amqprs",
|
||||
"anyhow",
|
||||
@@ -7169,7 +7169,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-ratelimits"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"authifier",
|
||||
@@ -7186,7 +7186,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-result"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"log",
|
||||
@@ -7202,7 +7202,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-voice-ingress"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"amqprs",
|
||||
"async-std",
|
||||
|
||||
46
README.md
46
README.md
@@ -76,6 +76,14 @@ mise install
|
||||
mise build
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> You can override `BUILDER` in your `.env` file to run cargo with mold if you installed it:
|
||||
>
|
||||
> ```bash
|
||||
> # .env
|
||||
> BUILDER = "mold --run cargo"
|
||||
> ```
|
||||
|
||||
A default configuration `Revolt.toml` is present in this project that is suited for development.
|
||||
|
||||
If you'd like to change anything, create a `Revolt.overrides.toml` file and specify relevant variables.
|
||||
@@ -112,7 +120,7 @@ If you'd like to change anything, create a `Revolt.overrides.toml` file and spec
|
||||
> - "14672:15672"
|
||||
> ```
|
||||
>
|
||||
> And corresponding Revolt configuration:
|
||||
> With the corresponding Revolt configuration:
|
||||
>
|
||||
> ```toml
|
||||
> # Revolt.overrides.toml
|
||||
@@ -124,32 +132,25 @@ If you'd like to change anything, create a `Revolt.overrides.toml` file and spec
|
||||
> [rabbit]
|
||||
> port = 14072
|
||||
> ```
|
||||
>
|
||||
> And mise configuration
|
||||
>
|
||||
> ```bash
|
||||
> #.env
|
||||
> DATABASE_PORT = "14017"
|
||||
> RABBIT_PORT = "14072"
|
||||
> REDIS_PORT = "14079"
|
||||
> ```
|
||||
|
||||
Then continue:
|
||||
|
||||
```bash
|
||||
# start other necessary services
|
||||
docker compose up -d
|
||||
cp livekit.example.yml livekit.yml
|
||||
|
||||
# run the API server
|
||||
cargo run --bin revolt-delta
|
||||
# run the events server
|
||||
cargo run --bin revolt-bonfire
|
||||
# run the file server
|
||||
cargo run --bin revolt-autumn
|
||||
# run the proxy server
|
||||
cargo run --bin revolt-january
|
||||
# run the tenor proxy
|
||||
cargo run --bin revolt-gifbox
|
||||
# run the push daemon (not usually needed in regular development)
|
||||
cargo run --bin revolt-pushd
|
||||
|
||||
# hint:
|
||||
# mold -run <cargo build, cargo run, etc...>
|
||||
# mold -run ./scripts/start.sh
|
||||
mise start
|
||||
```
|
||||
|
||||
You can start a web client by doing the following:
|
||||
You can start a web client by doing the following in another terminal:
|
||||
|
||||
```bash
|
||||
# if you do not have yarn yet and have a modern Node.js:
|
||||
@@ -163,6 +164,9 @@ cd stoat-web
|
||||
|
||||
When signing up, go to http://localhost:14080 to find confirmation/password reset emails.
|
||||
|
||||
To stop all services, hit (CTRL + c) in the terminal you ran `mise start` and run `mise docker:stop`
|
||||
|
||||
|
||||
## Deployment Guide
|
||||
|
||||
### Cutting new crate releases
|
||||
@@ -198,7 +202,7 @@ If you have bumped the crate versions, proceed to [GitHub releases](https://gith
|
||||
First, start the required services:
|
||||
|
||||
```sh
|
||||
docker compose -f docker-compose.db.yml up -d
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Now run tests for whichever database:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[database]
|
||||
# MongoDB connection URL
|
||||
# Defaults to the container name specified in self-hosted
|
||||
mongodb = "mongodb://127.0.0.1:27017?directConnection=true&replicaSet=rs0"
|
||||
mongodb = "mongodb://127.0.0.1:27017"
|
||||
# Redis connection URL
|
||||
# Defaults to the container name specified in self-hosted
|
||||
redis = "redis://127.0.0.1:6379/"
|
||||
|
||||
19
compose.yml
19
compose.yml
@@ -8,29 +8,10 @@ services:
|
||||
# MongoDB
|
||||
database:
|
||||
image: mongo
|
||||
command: ["--replSet", "rs0", "--bind_ip_all"]
|
||||
ports:
|
||||
- "27017:27017"
|
||||
volumes:
|
||||
- ./.data/db:/data/db
|
||||
- ./scripts/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
|
||||
healthcheck:
|
||||
test: >
|
||||
mongosh --quiet --eval "
|
||||
try {
|
||||
const status = rs.status();
|
||||
if (status.ok === 1 && status.members[0].stateStr === 'PRIMARY') {
|
||||
quit(0);
|
||||
} else {
|
||||
quit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
quit(1);
|
||||
}"
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 65536
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
license = "AGPL-3.0-or-later"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-coalesced"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>", "Zomatree <me@zomatree.live>"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-config"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -38,4 +38,4 @@ sentry = { version = "0.31.5", optional = true }
|
||||
sentry-anyhow = { version = "0.38.1", optional = true }
|
||||
|
||||
# Core
|
||||
revolt-result = { version = "0.11.5", path = "../result", optional = true }
|
||||
revolt-result = { version = "0.12.1", path = "../result", optional = true }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[database]
|
||||
mongodb = "mongodb://localhost?directConnection=true&replicaSet=rs0"
|
||||
mongodb = "mongodb://localhost"
|
||||
redis = "redis://localhost/"
|
||||
|
||||
[rabbit]
|
||||
|
||||
@@ -4,7 +4,7 @@ disable_events_dont_use = false
|
||||
[database]
|
||||
# MongoDB connection URL
|
||||
# Defaults to the container name specified in self-hosted
|
||||
mongodb = "mongodb://database?directConnection=true&replicaSet=rs0"
|
||||
mongodb = "mongodb://database"
|
||||
# Redis connection URL
|
||||
# Defaults to the container name specified in self-hosted
|
||||
redis = "redis://redis/"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-database"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -32,19 +32,19 @@ default = ["mongodb", "async-std-runtime", "tasks"]
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-config = { version = "0.11.5", path = "../config", features = [
|
||||
revolt-config = { version = "0.12.1", path = "../config", features = [
|
||||
"report-macros",
|
||||
] }
|
||||
revolt-result = { version = "0.11.5", path = "../result" }
|
||||
revolt-models = { version = "0.11.5", path = "../models", features = [
|
||||
revolt-result = { version = "0.12.1", path = "../result" }
|
||||
revolt-models = { version = "0.12.1", path = "../models", features = [
|
||||
"validator",
|
||||
] }
|
||||
revolt-presence = { version = "0.11.5", path = "../presence" }
|
||||
revolt-permissions = { version = "0.11.5", path = "../permissions", features = [
|
||||
revolt-presence = { version = "0.12.1", path = "../presence" }
|
||||
revolt-permissions = { version = "0.12.1", path = "../permissions", features = [
|
||||
"serde",
|
||||
"bson",
|
||||
] }
|
||||
revolt-parser = { version = "0.11.5", path = "../parser" }
|
||||
revolt-parser = { version = "0.12.1", path = "../parser" }
|
||||
|
||||
# Utility
|
||||
log = "0.4"
|
||||
|
||||
@@ -46,8 +46,7 @@ auto_derived!(
|
||||
width: isize,
|
||||
height: isize,
|
||||
thumbhash: Option<Vec<u8>>,
|
||||
#[serde(default)]
|
||||
animated: bool,
|
||||
animated: Option<bool>,
|
||||
},
|
||||
/// File is a video with specific dimensions
|
||||
Video { width: isize, height: isize },
|
||||
|
||||
@@ -17,6 +17,12 @@ pub trait AbstractAttachmentHashes: Sync + Send {
|
||||
/// Update an attachment hash nonce value.
|
||||
async fn set_attachment_hash_nonce(&self, hash: &str, nonce: &str) -> Result<()>;
|
||||
|
||||
/// Updates the attachments animated metadata value.
|
||||
///
|
||||
/// The primary use for this is to update the metadata for existing uploaded files, this
|
||||
/// can only be used for images.
|
||||
async fn set_attachment_hash_animated(&self, hash: &str, animated: bool) -> Result<()>;
|
||||
|
||||
/// Delete attachment hash by id.
|
||||
async fn delete_attachment_hash(&self, id: &str) -> Result<()>;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,29 @@ impl AbstractAttachmentHashes for MongoDb {
|
||||
.map_err(|_| create_database_error!("update_one", COL))
|
||||
}
|
||||
|
||||
/// Updates the attachments animated metadata value.
|
||||
///
|
||||
/// The primary use for this is to update the metadata for existing uploaded files, this
|
||||
/// can only be used for images.
|
||||
async fn set_attachment_hash_animated(&self, hash: &str, animated: bool) -> Result<()> {
|
||||
self.col::<FileHash>(COL)
|
||||
.update_one(
|
||||
doc! {
|
||||
"_id": hash,
|
||||
"metadata.type": "Image",
|
||||
"metadata.animated": { "$exists": false },
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"metadata.animated": animated
|
||||
}
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| create_database_error!("update_one", COL))
|
||||
}
|
||||
|
||||
/// Delete attachment hash by id.
|
||||
async fn delete_attachment_hash(&self, id: &str) -> Result<()> {
|
||||
query!(self, delete_one_by_id, COL, id).map(|_| ())
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::FileHash;
|
||||
use crate::ReferenceDb;
|
||||
use crate::{FileHash, Metadata, ReferenceDb};
|
||||
|
||||
use super::AbstractAttachmentHashes;
|
||||
|
||||
@@ -39,6 +38,29 @@ impl AbstractAttachmentHashes for ReferenceDb {
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the attachments animated metadata value.
|
||||
///
|
||||
/// The primary use for this is to update the metadata for existing uploaded files, this
|
||||
/// can only be used for images.
|
||||
async fn set_attachment_hash_animated(&self, hash: &str, animated: bool) -> Result<()> {
|
||||
let mut hashes = self.file_hashes.lock().await;
|
||||
if let Some(FileHash {
|
||||
metadata:
|
||||
Metadata::Image {
|
||||
animated: Some(animated_metadata),
|
||||
..
|
||||
},
|
||||
..
|
||||
}) = hashes.get_mut(hash)
|
||||
{
|
||||
*animated_metadata = animated;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete attachment hash by id.
|
||||
async fn delete_attachment_hash(&self, id: &str) -> Result<()> {
|
||||
let mut file_hashes = self.file_hashes.lock().await;
|
||||
|
||||
@@ -705,7 +705,7 @@ impl Message {
|
||||
Some(
|
||||
PushNotification::from(
|
||||
self.clone().into_model(user, member),
|
||||
Some(author),
|
||||
Some(author.clone()),
|
||||
channel.to_owned().into(),
|
||||
)
|
||||
.await,
|
||||
@@ -713,7 +713,11 @@ impl Message {
|
||||
self.clone(),
|
||||
match channel {
|
||||
Channel::DirectMessage { recipients, .. }
|
||||
| Channel::Group { recipients, .. } => recipients.clone(),
|
||||
| Channel::Group { recipients, .. } => recipients
|
||||
.iter()
|
||||
.filter(|uid| *uid != author.id())
|
||||
.cloned()
|
||||
.collect(),
|
||||
Channel::TextChannel { .. } => {
|
||||
self.mentions.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-files"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -27,10 +27,10 @@ typenum = "1.17.0"
|
||||
aws-config = "1.5.5"
|
||||
aws-sdk-s3 = { version = "1.46.0", features = ["behavior-version-latest"] }
|
||||
|
||||
revolt-config = { version = "0.11.5", path = "../config", features = [
|
||||
revolt-config = { version = "0.12.1", path = "../config", features = [
|
||||
"report-macros",
|
||||
] }
|
||||
revolt-result = { version = "0.11.5", path = "../result" }
|
||||
revolt-result = { version = "0.12.1", path = "../result" }
|
||||
|
||||
# image processing
|
||||
jxl-oxide = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-models"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -21,8 +21,8 @@ default = ["serde", "partials", "rocket"]
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-config = { version = "0.11.5", path = "../config" }
|
||||
revolt-permissions = { version = "0.11.5", path = "../permissions" }
|
||||
revolt-config = { version = "0.12.1", path = "../config" }
|
||||
revolt-permissions = { version = "0.12.1", path = "../permissions" }
|
||||
|
||||
# Utility
|
||||
regex = "1.11"
|
||||
|
||||
@@ -51,7 +51,7 @@ auto_derived!(
|
||||
width: usize,
|
||||
height: usize,
|
||||
thumbhash: Option<Vec<u8>>,
|
||||
animated: bool,
|
||||
animated: Option<bool>,
|
||||
},
|
||||
/// File is a video with specific dimensions
|
||||
Video { width: usize, height: usize },
|
||||
|
||||
@@ -391,6 +391,7 @@ auto_derived!(
|
||||
);
|
||||
|
||||
/// Message Author Abstraction
|
||||
#[derive(Clone)]
|
||||
pub enum MessageAuthor<'a> {
|
||||
User(&'a User),
|
||||
Webhook(&'a Webhook),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-parser"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Zomatree <me@zomatree.live>", "Paul Makles <me@insrt.uk>"]
|
||||
|
||||
@@ -262,7 +262,7 @@ mod tests {
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(output.len(), 6);
|
||||
assert_eq!(output.len(), 7);
|
||||
assert_eq!(output[0], MessageToken::CodeblockMarker(1));
|
||||
assert_eq!(
|
||||
output[1],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-permissions"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -22,7 +22,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-result = { version = "0.11.5", path = "../result" }
|
||||
revolt-result = { version = "0.12.1", path = "../result" }
|
||||
|
||||
# Utility
|
||||
auto_ops = "0.3.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-presence"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -17,7 +17,7 @@ redis-is-patched = []
|
||||
async-std = { version = "1.8.0", features = ["attributes"] }
|
||||
|
||||
# Config for loading Redis URI
|
||||
revolt-config = { version = "0.11.5", path = "../config" }
|
||||
revolt-config = { version = "0.12.1", path = "../config" }
|
||||
|
||||
[dependencies]
|
||||
# Utility
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-ratelimits"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
authors = ["Zomatree <me@zomatree.live>", "Paul Makles <me@insrt.uk>"]
|
||||
@@ -18,9 +18,9 @@ axum = ["dep:axum", "revolt-database/axum-impl"]
|
||||
default = ["rocket", "axum"]
|
||||
|
||||
[dependencies]
|
||||
revolt-database = { version = "0.11.5", path = "../database" }
|
||||
revolt-result = { version = "0.11.5", path = "../result" }
|
||||
revolt-config = { version = "0.11.5", path = "../config" }
|
||||
revolt-database = { version = "0.12.1", path = "../database" }
|
||||
revolt-result = { version = "0.12.1", path = "../result" }
|
||||
revolt-config = { version = "0.12.1", path = "../config" }
|
||||
|
||||
rocket = { version = "0.5.1", optional = true }
|
||||
revolt_rocket_okapi = { version = "0.10.0", optional = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-result"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-crond"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
edition = "2021"
|
||||
@@ -17,7 +17,7 @@ log = "0.4"
|
||||
tokio = { version = "1" }
|
||||
|
||||
# Core
|
||||
revolt-database = { version = "0.11.5", path = "../../core/database" }
|
||||
revolt-result = { version = "0.11.5", path = "../../core/result" }
|
||||
revolt-config = { version = "0.11.5", path = "../../core/config" }
|
||||
revolt-files = { version = "0.11.5", path = "../../core/files" }
|
||||
revolt-database = { version = "0.12.1", path = "../../core/database" }
|
||||
revolt-result = { version = "0.12.1", path = "../../core/result" }
|
||||
revolt-config = { version = "0.12.1", path = "../../core/config" }
|
||||
revolt-files = { version = "0.12.1", path = "../../core/files" }
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
[package]
|
||||
name = "revolt-pushd"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
revolt-result = { version = "0.11.5", path = "../../core/result" }
|
||||
revolt-config = { version = "0.11.5", path = "../../core/config", features = [
|
||||
revolt-result = { version = "0.12.1", path = "../../core/result" }
|
||||
revolt-config = { version = "0.12.1", path = "../../core/config", features = [
|
||||
"report-macros",
|
||||
"anyhow",
|
||||
] }
|
||||
revolt-database = { version = "0.11.5", path = "../../core/database" }
|
||||
revolt-models = { version = "0.11.5", path = "../../core/models", features = [
|
||||
revolt-database = { version = "0.12.1", path = "../../core/database" }
|
||||
revolt-models = { version = "0.12.1", path = "../../core/models", features = [
|
||||
"validator",
|
||||
] }
|
||||
revolt-presence = { version = "0.11.5", path = "../../core/presence", features = [
|
||||
revolt-presence = { version = "0.12.1", path = "../../core/presence", features = [
|
||||
"redis-is-patched",
|
||||
] }
|
||||
revolt-parser = { version = "0.11.5", path = "../../core/parser" }
|
||||
revolt-parser = { version = "0.12.1", path = "../../core/parser" }
|
||||
|
||||
anyhow = { version = "1.0.98" }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-voice-ingress"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
license = "AGPL-3.0-or-later"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-delta"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-autumn"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
publish = false
|
||||
@@ -45,16 +45,16 @@ tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
# Core crates
|
||||
revolt-files = { version = "0.11.5", path = "../../core/files" }
|
||||
revolt-config = { version = "0.11.5", path = "../../core/config" }
|
||||
revolt-database = { version = "0.11.5", path = "../../core/database", features = [
|
||||
revolt-files = { version = "0.12.1", path = "../../core/files" }
|
||||
revolt-config = { version = "0.12.1", path = "../../core/config" }
|
||||
revolt-database = { version = "0.12.1", path = "../../core/database", features = [
|
||||
"axum-impl",
|
||||
] }
|
||||
revolt-result = { version = "0.11.5", path = "../../core/result", features = [
|
||||
revolt-result = { version = "0.12.1", path = "../../core/result", features = [
|
||||
"utoipa",
|
||||
"axum",
|
||||
] }
|
||||
revolt-ratelimits = { version = "0.11.5", path = "../../core/ratelimits", features = ["axum"] }
|
||||
revolt-ratelimits = { version = "0.12.1", path = "../../core/ratelimits", features = ["axum"] }
|
||||
|
||||
# Axum / web server
|
||||
tempfile = "3.12.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
io::{Cursor, Read},
|
||||
io::{Cursor, Read, Write},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
@@ -15,9 +15,10 @@ use lazy_static::lazy_static;
|
||||
use revolt_config::{config, report_internal_error};
|
||||
use revolt_database::{iso8601_timestamp::Timestamp, Database, FileHash, Metadata, User};
|
||||
use revolt_files::{
|
||||
create_thumbnail, decode_image, fetch_from_s3, upload_to_s3, AUTHENTICATION_TAG_SIZE_BYTES,
|
||||
create_thumbnail, decode_image, fetch_from_s3, is_animated, upload_to_s3,
|
||||
AUTHENTICATION_TAG_SIZE_BYTES,
|
||||
};
|
||||
use revolt_result::{create_error, Error, Result};
|
||||
use revolt_result::{create_error, Error, Result, ToRevoltError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Digest;
|
||||
use tempfile::NamedTempFile;
|
||||
@@ -25,7 +26,9 @@ use tokio::time::Instant;
|
||||
use tower_http::cors::{AllowHeaders, Any, CorsLayer};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::{exif::strip_metadata, metadata::generate_metadata, mime_type::determine_mime_type, AppState};
|
||||
use crate::{
|
||||
exif::strip_metadata, metadata::generate_metadata, mime_type::determine_mime_type, AppState,
|
||||
};
|
||||
|
||||
/// Build the API router
|
||||
pub async fn router() -> Router<AppState> {
|
||||
@@ -380,7 +383,30 @@ async fn fetch_preview(
|
||||
|
||||
let hash = file.as_hash(&db).await?;
|
||||
|
||||
let is_animated = matches!(hash.metadata, Metadata::Image { animated: true, .. });
|
||||
let mut data = None;
|
||||
|
||||
// If animated is unset, check the file contents to see if it is animated and update the filehash
|
||||
let is_animated = match &hash.metadata {
|
||||
Metadata::Image {
|
||||
animated: Some(value),
|
||||
..
|
||||
} => *value,
|
||||
Metadata::Image { animated: None, .. } => {
|
||||
let file_data = retrieve_file_by_hash(&hash).await?;
|
||||
|
||||
let mut named_file = NamedTempFile::new().to_internal_error()?;
|
||||
named_file.write(&file_data).to_internal_error()?;
|
||||
|
||||
data = Some(file_data);
|
||||
|
||||
// If it fails for some reason, set it to not be animated
|
||||
let animated = is_animated(&named_file, &hash.content_type).unwrap_or(false);
|
||||
db.set_attachment_hash_animated(&hash.id, animated).await?;
|
||||
|
||||
animated
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// Only process image files and don't process GIFs if not avatar or icon
|
||||
if !matches!(hash.metadata, Metadata::Image { .. })
|
||||
@@ -392,7 +418,11 @@ async fn fetch_preview(
|
||||
}
|
||||
|
||||
// Original image data
|
||||
let data = retrieve_file_by_hash(&hash).await?;
|
||||
let data = if let Some(data) = data {
|
||||
data
|
||||
} else {
|
||||
retrieve_file_by_hash(&hash).await?
|
||||
};
|
||||
|
||||
// Read image and create thumbnail
|
||||
let data = create_thumbnail(
|
||||
|
||||
@@ -37,7 +37,7 @@ pub fn generate_metadata(f: &NamedTempFile, mime_type: &str) -> Metadata {
|
||||
thumbhash::rgba_to_thumb_hash(width as usize, height as usize, &rgba)
|
||||
})
|
||||
.ok(),
|
||||
animated: is_animated(f, mime_type).unwrap_or(false),
|
||||
animated: is_animated(f, mime_type).or(Some(false)),
|
||||
})
|
||||
.unwrap_or_default()
|
||||
} else if mime_type.starts_with("video/") {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-gifbox"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
publish = false
|
||||
@@ -17,19 +17,19 @@ tokio = { version = "1.0", features = ["full"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
|
||||
# Core crates
|
||||
revolt-config = { version = "0.11.5", path = "../../core/config" }
|
||||
revolt-models = { version = "0.11.5", path = "../../core/models" }
|
||||
revolt-result = { version = "0.11.5", path = "../../core/result", features = [
|
||||
revolt-config = { version = "0.12.1", path = "../../core/config" }
|
||||
revolt-models = { version = "0.12.1", path = "../../core/models" }
|
||||
revolt-result = { version = "0.12.1", path = "../../core/result", features = [
|
||||
"utoipa",
|
||||
"axum",
|
||||
] }
|
||||
revolt-coalesced = { version = "0.11.5", path = "../../core/coalesced", features = [
|
||||
revolt-coalesced = { version = "0.12.1", path = "../../core/coalesced", features = [
|
||||
"queue",
|
||||
] }
|
||||
revolt-database = { version = "0.11.5", path = "../../core/database", features = [
|
||||
revolt-database = { version = "0.12.1", path = "../../core/database", features = [
|
||||
"axum-impl",
|
||||
] }
|
||||
revolt-ratelimits = { version = "0.11.5", path = "../../core/ratelimits", features = [
|
||||
revolt-ratelimits = { version = "0.12.1", path = "../../core/ratelimits", features = [
|
||||
"axum",
|
||||
] }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-january"
|
||||
version = "0.11.5"
|
||||
version = "0.12.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
publish = false
|
||||
@@ -33,13 +33,13 @@ tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
# Core crates
|
||||
revolt-config = { version = "0.11.5", path = "../../core/config" }
|
||||
revolt-models = { version = "0.11.5", path = "../../core/models" }
|
||||
revolt-result = { version = "0.11.5", path = "../../core/result", features = [
|
||||
revolt-config = { version = "0.12.1", path = "../../core/config" }
|
||||
revolt-models = { version = "0.12.1", path = "../../core/models" }
|
||||
revolt-result = { version = "0.12.1", path = "../../core/result", features = [
|
||||
"utoipa",
|
||||
"axum",
|
||||
] }
|
||||
revolt-files = { version = "0.11.5", path = "../../core/files" }
|
||||
revolt-files = { version = "0.12.1", path = "../../core/files" }
|
||||
|
||||
# Axum / web server
|
||||
axum = { version = "0.7.5" }
|
||||
|
||||
@@ -23,7 +23,7 @@ You can contribute translations through [**Weblate**](https://translate.stoat.ch
|
||||
### 3. Donate
|
||||
|
||||
Stoat is not backed by a big company, is not currently monetised (for example, via a subscription service) and does not serve you advertisements; as such, Stoat currently relies entirely on donations.
|
||||
You can learn more about donating [here](https://wiki.revolt.chat/notes/project/financial-support/) - if you want to make a larger donation, please consult me first.
|
||||
You can learn more about donating [here](https://ko-fi.com/stoatchat) - if you want to make a larger donation, please consult me first.
|
||||
|
||||
### 4. Join the project
|
||||
|
||||
|
||||
@@ -205,6 +205,11 @@
|
||||
"path": "crates/daemons/pushd/Cargo.toml",
|
||||
"jsonpath": "$.dependencies['revolt-presence'].version"
|
||||
},
|
||||
{
|
||||
"type": "toml",
|
||||
"path": "crates/daemons/pushd/Cargo.toml",
|
||||
"jsonpath": "$.dependencies['revolt-parser'].version"
|
||||
},
|
||||
{
|
||||
"type": "toml",
|
||||
"path": "crates/daemons/voice-ingress/Cargo.toml",
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
try {
|
||||
rs.status();
|
||||
} catch (e) {
|
||||
rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:27017" }] });
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
0.11.5
|
||||
0.12.1
|
||||
|
||||
Reference in New Issue
Block a user