Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ea8f50fb8 | ||
|
|
68bcfcb626 | ||
|
|
9632a0dc1b | ||
|
|
a4a0934475 | ||
|
|
2061794305 | ||
|
|
3a7ebad883 | ||
|
|
6daa8223b2 | ||
|
|
4a58d6eae0 | ||
|
|
a8a2e491b0 | ||
|
|
f98f09a5ea | ||
|
|
7a4e12a732 | ||
|
|
aa8f8575bc | ||
|
|
70d6a5ac08 | ||
|
|
7f85ad5e7b | ||
|
|
c785ae615d | ||
|
|
9c8a362e9f | ||
|
|
e708c612cf |
+121
-69
@@ -2,24 +2,13 @@ name: Docker Test & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
# branches:
|
||||
# - "main"
|
||||
tags:
|
||||
- "*"
|
||||
paths-ignore:
|
||||
- ".github/**"
|
||||
- "!.github/workflows/docker.yml"
|
||||
- ".vscode/**"
|
||||
- "doc/**"
|
||||
- ".gitignore"
|
||||
- "LICENSE"
|
||||
- "README"
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
paths:
|
||||
- "Dockerfile"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -27,8 +16,9 @@ permissions:
|
||||
|
||||
jobs:
|
||||
base:
|
||||
name: Test base image build
|
||||
runs-on: ubuntu-latest
|
||||
name: Build base image
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
# Configure build environment
|
||||
- name: Checkout
|
||||
@@ -36,33 +26,21 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# Authenticate with GHCR
|
||||
- name: Login to Github Container Registry
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Build the image
|
||||
- name: Build base image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
push: false
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
cache-from: type=gha,scope=buildx-base-multi-arch
|
||||
cache-to: type=gha,scope=buildx-base-multi-arch,mode=max
|
||||
|
||||
publish:
|
||||
needs: [base]
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: self-hosted
|
||||
if: github.event_name != 'pull_request'
|
||||
strategy:
|
||||
matrix:
|
||||
project: [delta, bonfire, autumn, january, pushd]
|
||||
name: Build ${{ matrix.project }} image
|
||||
name: Publish Docker images
|
||||
steps:
|
||||
# Configure build environment
|
||||
- name: Checkout
|
||||
@@ -77,6 +55,7 @@ jobs:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to Github Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
@@ -84,58 +63,131 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Resolve the correct project
|
||||
- uses: kanga333/variable-mapper@master
|
||||
id: export
|
||||
# Build the image
|
||||
- name: Build base image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
key: "${{ matrix.project }}"
|
||||
map: |
|
||||
{
|
||||
"delta": {
|
||||
"path": "crates/delta",
|
||||
"tag": "${{ github.repository_owner }}/server"
|
||||
},
|
||||
"bonfire": {
|
||||
"path": "crates/bonfire",
|
||||
"tag": "${{ github.repository_owner }}/bonfire"
|
||||
},
|
||||
"autumn": {
|
||||
"path": "crates/services/autumn",
|
||||
"tag": "${{ github.repository_owner }}/autumn"
|
||||
},
|
||||
"january": {
|
||||
"path": "crates/services/january",
|
||||
"tag": "${{ github.repository_owner }}/january"
|
||||
},
|
||||
"pushd": {
|
||||
"path": "crates/daemons/pushd",
|
||||
"tag": "${{ github.repository_owner }}/pushd"
|
||||
},
|
||||
"crond": {
|
||||
"path": "crates/daemons/crond",
|
||||
"tag": "${{ github.repository_owner }}/crond"
|
||||
}
|
||||
}
|
||||
export_to: output
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
|
||||
# Configure metadata
|
||||
# revoltchat/server
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
id: meta-delta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
docker.io/${{ steps.export.outputs.tag }}
|
||||
ghcr.io/${{ steps.export.outputs.tag }}
|
||||
|
||||
# Build crate image
|
||||
docker.io/revoltchat/server
|
||||
ghcr.io/revoltchat/server
|
||||
- name: Publish
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: ${{ steps.export.outputs.path }}/Dockerfile
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
file: crates/delta/Dockerfile
|
||||
tags: ${{ steps.meta-delta.outputs.tags }}
|
||||
build-args: |
|
||||
BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
labels: ${{ steps.meta-delta.outputs.labels }}
|
||||
|
||||
# revoltchat/bonfire
|
||||
- name: Docker meta
|
||||
id: meta-bonfire
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
docker.io/revoltchat/bonfire
|
||||
ghcr.io/revoltchat/bonfire
|
||||
- name: Publish
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: crates/bonfire/Dockerfile
|
||||
tags: ${{ steps.meta-bonfire.outputs.tags }}
|
||||
build-args: |
|
||||
BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
labels: ${{ steps.meta-bonfire.outputs.labels }}
|
||||
|
||||
# revoltchat/autumn
|
||||
- name: Docker meta
|
||||
id: meta-autumn
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
docker.io/revoltchat/autumn
|
||||
ghcr.io/revoltchat/autumn
|
||||
- name: Publish
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: crates/services/autumn/Dockerfile
|
||||
tags: ${{ steps.meta-autumn.outputs.tags }}
|
||||
build-args: |
|
||||
BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
labels: ${{ steps.meta-autumn.outputs.labels }}
|
||||
|
||||
# revoltchat/january
|
||||
- name: Docker meta
|
||||
id: meta-january
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
docker.io/revoltchat/january
|
||||
ghcr.io/revoltchat/january
|
||||
- name: Publish
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: crates/services/january/Dockerfile
|
||||
tags: ${{ steps.meta-january.outputs.tags }}
|
||||
build-args: |
|
||||
BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
labels: ${{ steps.meta-january.outputs.labels }}
|
||||
|
||||
# revoltchat/crond
|
||||
- name: Docker meta
|
||||
id: meta-crond
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
docker.io/revoltchat/crond
|
||||
ghcr.io/revoltchat/crond
|
||||
- name: Publish
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: crates/daemons/crond/Dockerfile
|
||||
tags: ${{ steps.meta-crond.outputs.tags }}
|
||||
build-args: |
|
||||
BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
labels: ${{ steps.meta-crond.outputs.labels }}
|
||||
|
||||
# revoltchat/pushd
|
||||
- name: Docker meta
|
||||
id: meta-pushd
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
docker.io/revoltchat/pushd
|
||||
ghcr.io/revoltchat/pushd
|
||||
- name: Publish
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: crates/daemons/pushd/Dockerfile
|
||||
tags: ${{ steps.meta-pushd.outputs.tags }}
|
||||
build-args: |
|
||||
BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/base:latest
|
||||
labels: ${{ steps.meta-pushd.outputs.labels }}
|
||||
|
||||
Generated
+25
-134
@@ -443,9 +443,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "authifier"
|
||||
version = "1.0.10"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edfe88c4a9fcf24b18a216b27c9766966af2a40603d24c7782237afd6ca0d5cd"
|
||||
checksum = "ca26cb6b5ab776a1de5a8122fe6cc77fadd84fed30704c496f2aca451637877b"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-trait",
|
||||
@@ -454,7 +454,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"futures",
|
||||
"handlebars",
|
||||
"iso8601-timestamp 0.1.11",
|
||||
"iso8601-timestamp",
|
||||
"lazy_static",
|
||||
"lettre",
|
||||
"log",
|
||||
@@ -470,6 +470,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"totp-lite",
|
||||
"ulid 0.5.0",
|
||||
"validator 0.15.0",
|
||||
@@ -3647,17 +3648,6 @@ dependencies = [
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iso8601-timestamp"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b088f3296223f11d6bd70998132653b30b6f39e6ab4be055c0bda486fa8d11c7"
|
||||
dependencies = [
|
||||
"generic-array 0.14.7",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iso8601-timestamp"
|
||||
version = "0.2.17"
|
||||
@@ -3996,16 +3986,6 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.11"
|
||||
@@ -4499,43 +4479,6 @@ dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neon"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d75440242411c87dc39847b0e33e961ec1f10326a9d8ecf9c1ea64a3b3c13dc"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libloading",
|
||||
"neon-macros",
|
||||
"once_cell",
|
||||
"semver",
|
||||
"send_wrapper",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neon-macros"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6813fde79b646e47e7ad75f480aa80ef76a5d9599e2717407961531169ee38b"
|
||||
dependencies = [
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.94",
|
||||
"syn-mid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neon-serde4"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8778b4afaa506e067da24566623873c38797987be593232a4f9ad82c84bb3eb3"
|
||||
dependencies = [
|
||||
"neon",
|
||||
"num",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
@@ -4577,19 +4520,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||
dependencies = [
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
@@ -4617,15 +4547,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
@@ -5983,7 +5904,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-autumn"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-macros",
|
||||
@@ -6020,7 +5941,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"async-channel 2.3.1",
|
||||
"async-std",
|
||||
@@ -6050,7 +5971,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-config"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"cached",
|
||||
@@ -6066,7 +5987,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-crond"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"log",
|
||||
"revolt-config",
|
||||
@@ -6078,7 +5999,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-database"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"amqprs",
|
||||
"async-lock 2.8.0",
|
||||
@@ -6095,7 +6016,7 @@ dependencies = [
|
||||
"futures",
|
||||
"indexmap 1.9.3",
|
||||
"isahc",
|
||||
"iso8601-timestamp 0.2.17",
|
||||
"iso8601-timestamp",
|
||||
"linkify 0.8.1",
|
||||
"log",
|
||||
"lru 0.11.1",
|
||||
@@ -6128,7 +6049,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-delta"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"amqprs",
|
||||
"async-channel 1.9.0",
|
||||
@@ -6140,7 +6061,7 @@ dependencies = [
|
||||
"env_logger",
|
||||
"futures",
|
||||
"impl_ops",
|
||||
"iso8601-timestamp 0.2.17",
|
||||
"iso8601-timestamp",
|
||||
"lettre",
|
||||
"linkify 0.6.0",
|
||||
"log",
|
||||
@@ -6175,7 +6096,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-files"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"aws-config",
|
||||
@@ -6198,7 +6119,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-january"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"axum",
|
||||
@@ -6226,10 +6147,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-models"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"indexmap 1.9.3",
|
||||
"iso8601-timestamp 0.2.17",
|
||||
"iso8601-timestamp",
|
||||
"num_enum 0.6.1",
|
||||
"once_cell",
|
||||
"regex",
|
||||
@@ -6243,29 +6164,16 @@ dependencies = [
|
||||
"validator 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "revolt-nodejs-bindings"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"neon",
|
||||
"neon-serde4",
|
||||
"revolt-config",
|
||||
"revolt-database",
|
||||
"revolt-result",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "revolt-parser"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"logos",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "revolt-permissions"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-trait",
|
||||
@@ -6280,7 +6188,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-presence"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"log",
|
||||
@@ -6291,7 +6199,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-pushd"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"amqprs",
|
||||
"async-trait",
|
||||
@@ -6299,7 +6207,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"fcm_v1",
|
||||
"isahc",
|
||||
"iso8601-timestamp 0.2.17",
|
||||
"iso8601-timestamp",
|
||||
"log",
|
||||
"pretty_env_logger",
|
||||
"revolt-config",
|
||||
@@ -6317,7 +6225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-result"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"revolt_okapi",
|
||||
@@ -6517,12 +6425,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rocket_authifier"
|
||||
version = "1.0.10"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2aa1bfaee106d088b78de7c3cc2a8ab2c9e05a0286b6b912f0b18ea656b329e"
|
||||
checksum = "0490f4a6f0a359a9ffff9acbdf4eddf49890ec94941b8ddd88163c16f6159f5a"
|
||||
dependencies = [
|
||||
"authifier",
|
||||
"iso8601-timestamp 0.1.11",
|
||||
"iso8601-timestamp",
|
||||
"revolt_okapi",
|
||||
"revolt_rocket_okapi",
|
||||
"rocket",
|
||||
@@ -7001,12 +6909,6 @@ version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
|
||||
|
||||
[[package]]
|
||||
name = "send_wrapper"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
|
||||
|
||||
[[package]]
|
||||
name = "sentry"
|
||||
version = "0.31.8"
|
||||
@@ -7597,17 +7499,6 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn-mid"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5dc35bb08dd1ca3dfb09dce91fd2d13294d6711c88897d9a9d60acf39bce049"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.38",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
|
||||
+3
-4
@@ -6,7 +6,6 @@ members = [
|
||||
"crates/bonfire",
|
||||
"crates/core/*",
|
||||
"crates/services/*",
|
||||
"crates/bindings/*",
|
||||
"crates/daemons/*",
|
||||
]
|
||||
|
||||
@@ -16,6 +15,6 @@ redis23 = { package = "redis", version = "0.23.3", git = "https://github.com/rev
|
||||
# I'm 99% sure this is overloading the GitHub worker
|
||||
# hence builds have been failing since, let's just
|
||||
# disable it for now. In the future, we could use this
|
||||
# if we were rolling our own CI.
|
||||
# [profile.release]
|
||||
# lto = true
|
||||
# if we were rolling our own CI (that is now).
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
# Build Stage
|
||||
FROM --platform="${BUILDPLATFORM}" rust:1.77.2-slim-bookworm
|
||||
FROM --platform="${BUILDPLATFORM}" rust:1.86.0-slim-bookworm
|
||||
USER 0:0
|
||||
WORKDIR /home/rust/src
|
||||
|
||||
@@ -17,13 +17,13 @@ RUN sh /tmp/build-image-layer.sh tools
|
||||
|
||||
# Build all dependencies
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY crates/bindings/node/Cargo.toml ./crates/bindings/node/
|
||||
COPY crates/bonfire/Cargo.toml ./crates/bonfire/
|
||||
COPY crates/delta/Cargo.toml ./crates/delta/
|
||||
COPY crates/core/config/Cargo.toml ./crates/core/config/
|
||||
COPY crates/core/database/Cargo.toml ./crates/core/database/
|
||||
COPY crates/core/files/Cargo.toml ./crates/core/files/
|
||||
COPY crates/core/models/Cargo.toml ./crates/core/models/
|
||||
COPY crates/core/parser/Cargo.toml ./crates/core/parser/
|
||||
COPY crates/core/permissions/Cargo.toml ./crates/core/permissions/
|
||||
COPY crates/core/presence/Cargo.toml ./crates/core/presence/
|
||||
COPY crates/core/result/Cargo.toml ./crates/core/result/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Build Stage
|
||||
FROM rust:1.77.2-slim-bookworm
|
||||
FROM rust:1.86.0-slim-bookworm
|
||||
USER 0:0
|
||||
WORKDIR /home/rust/src
|
||||
|
||||
@@ -13,13 +13,13 @@ COPY scripts/build-image-layer.sh /tmp/
|
||||
|
||||
# Build all dependencies
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY crates/bindings/node/Cargo.toml ./crates/bindings/node/
|
||||
COPY crates/bonfire/Cargo.toml ./crates/bonfire/
|
||||
COPY crates/delta/Cargo.toml ./crates/delta/
|
||||
COPY crates/core/config/Cargo.toml ./crates/core/config/
|
||||
COPY crates/core/database/Cargo.toml ./crates/core/database/
|
||||
COPY crates/core/files/Cargo.toml ./crates/core/files/
|
||||
COPY crates/core/models/Cargo.toml ./crates/core/models/
|
||||
COPY crates/core/parser/Cargo.toml ./crates/core/parser/
|
||||
COPY crates/core/permissions/Cargo.toml ./crates/core/permissions/
|
||||
COPY crates/core/presence/Cargo.toml ./crates/core/presence/
|
||||
COPY crates/core/result/Cargo.toml ./crates/core/result/
|
||||
|
||||
@@ -12,32 +12,31 @@
|
||||
The services and libraries that power the Revolt service.<br/>
|
||||
<br/>
|
||||
|
||||
| Crate | Path | Description | |
|
||||
| ------------------ | -------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `core/config` | [crates/core/config](crates/core/config) | Core: Configuration |     |
|
||||
| `core/database` | [crates/core/database](crates/core/database) | Core: Database Implementation |     |
|
||||
| `core/files` | [crates/core/files](crates/core/files) | Core: S3 and encryption subroutines |     |
|
||||
| `core/models` | [crates/core/models](crates/core/models) | Core: API Models |     |
|
||||
| `core/permissions` | [crates/core/permissions](crates/core/permissions) | Core: Permission Logic |     |
|
||||
| `core/presence` | [crates/core/presence](crates/core/presence) | Core: User Presence |     |
|
||||
| `core/result` | [crates/core/result](crates/core/result) | Core: Result and Error types |     |
|
||||
| `delta` | [crates/delta](crates/delta) | REST API server |  |
|
||||
| `bonfire` | [crates/bonfire](crates/bonfire) | WebSocket events server |  |
|
||||
| `services/january` | [crates/services/january](crates/services/january) | Proxy server |  |
|
||||
| `services/autumn` | [crates/services/autumn](crates/services/autumn) | File server |  |
|
||||
| `bindings/node` | [crates/bindings/node](crates/bindings/node) | Node.js bindings for the Revolt software |  |
|
||||
| `daemons/crond` | [crates/daemons/crond](crates/daemons/crond) | Timed data clean up daemon server |  |
|
||||
| `daemons/pushd` | [crates/daemons/pushd](crates/daemons/pushd) | Push notification daemon server |  |
|
||||
| Crate | Path | Description | |
|
||||
| ------------------ | -------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `core/config` | [crates/core/config](crates/core/config) | Core: Configuration |     |
|
||||
| `core/database` | [crates/core/database](crates/core/database) | Core: Database Implementation |     |
|
||||
| `core/files` | [crates/core/files](crates/core/files) | Core: S3 and encryption subroutines |     |
|
||||
| `core/models` | [crates/core/models](crates/core/models) | Core: API Models |     |
|
||||
| `core/permissions` | [crates/core/permissions](crates/core/permissions) | Core: Permission Logic |     |
|
||||
| `core/presence` | [crates/core/presence](crates/core/presence) | Core: User Presence |     |
|
||||
| `core/result` | [crates/core/result](crates/core/result) | Core: Result and Error types |     |
|
||||
| `delta` | [crates/delta](crates/delta) | REST API server |  |
|
||||
| `bonfire` | [crates/bonfire](crates/bonfire) | WebSocket events server |  |
|
||||
| `services/january` | [crates/services/january](crates/services/january) | Proxy server |  |
|
||||
| `services/autumn` | [crates/services/autumn](crates/services/autumn) | File server |  |
|
||||
| `daemons/crond` | [crates/daemons/crond](crates/daemons/crond) | Timed data clean up daemon server |  |
|
||||
| `daemons/pushd` | [crates/daemons/pushd](crates/daemons/pushd) | Push notification daemon server |  |
|
||||
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
## Minimum Supported Rust Version
|
||||
|
||||
Rust 1.76 or higher.
|
||||
Rust 1.86.0 or higher.
|
||||
|
||||
> [!CAUTION]
|
||||
> The events server has a significant performance regression between Rust 1.77.2 and 1.78.0 onwards, see [issue #341](https://github.com/revoltchat/backend/issues/341).
|
||||
> The events server has a significant performance regression between Rust 1.77.2 and 1.78.0 onwards, see [issue #341](https://github.com/revoltchat/backend/issues/341). This is currently solved by build time options but we are looking for a proper fix.
|
||||
|
||||
## Development Guide
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ from_address = "development@revolt.chat"
|
||||
reply_to = "support@revolt.chat"
|
||||
port = 14025
|
||||
use_tls = false
|
||||
use_starttls = false
|
||||
|
||||
[files.s3]
|
||||
# S3 protocol endpoint
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
target
|
||||
index.node
|
||||
**/node_modules
|
||||
**/.DS_Store
|
||||
npm-debug.log*
|
||||
cargo.log
|
||||
cross.log
|
||||
@@ -1,25 +0,0 @@
|
||||
[package]
|
||||
name = "revolt-nodejs-bindings"
|
||||
version = "0.8.4"
|
||||
description = "Node.js bindings for the Revolt software"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
exclude = ["index.node"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
neon = "1.0.0"
|
||||
neon-serde4 = "1.0.0"
|
||||
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
async-std = "1.12.0"
|
||||
|
||||
revolt-config = { version = "0.8.4", path = "../../core/config" }
|
||||
revolt-result = { version = "0.8.4", path = "../../core/result" }
|
||||
revolt-database = { version = "0.8.4", path = "../../core/database" }
|
||||
@@ -1,92 +0,0 @@
|
||||
# revolt.node
|
||||
|
||||
**revolt.node:** Node.js bindings for the Revolt software
|
||||
|
||||
This project was bootstrapped by [create-neon](https://www.npmjs.com/package/create-neon).
|
||||
|
||||
## Building revolt.node
|
||||
|
||||
Building revolt.node requires a [supported version of Node and Rust](https://github.com/neon-bindings/neon#platform-support).
|
||||
|
||||
To run the build, run:
|
||||
|
||||
```sh
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
This command uses the [@neon-rs/cli](https://www.npmjs.com/package/@neon-rs/cli) utility to assemble the binary Node addon from the output of `cargo`.
|
||||
|
||||
## Exploring revolt.node
|
||||
|
||||
After building revolt.node, you can explore its exports at the Node console:
|
||||
|
||||
```sh
|
||||
$ npm i
|
||||
$ npm run build
|
||||
$ node
|
||||
> require('.').hello()
|
||||
'hello node'
|
||||
```
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
#### `npm install`
|
||||
|
||||
Installs the project, including running `npm run build`.
|
||||
|
||||
#### `npm run build`
|
||||
|
||||
Builds the Node addon (`index.node`) from source, generating a release build with `cargo --release`.
|
||||
|
||||
Additional [`cargo build`](https://doc.rust-lang.org/cargo/commands/cargo-build.html) arguments may be passed to `npm run build` and similar commands. For example, to enable a [cargo feature](https://doc.rust-lang.org/cargo/reference/features.html):
|
||||
|
||||
```
|
||||
npm run build -- --feature=beetle
|
||||
```
|
||||
|
||||
#### `npm run debug`
|
||||
|
||||
Similar to `npm run build` but generates a debug build with `cargo`.
|
||||
|
||||
#### `npm run cross`
|
||||
|
||||
Similar to `npm run build` but uses [cross-rs](https://github.com/cross-rs/cross) to cross-compile for another platform. Use the [`CARGO_BUILD_TARGET`](https://doc.rust-lang.org/cargo/reference/config.html#buildtarget) environment variable to select the build target.
|
||||
|
||||
#### `npm test`
|
||||
|
||||
Runs the unit tests by calling `cargo test`. You can learn more about [adding tests to your Rust code](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) from the [Rust book](https://doc.rust-lang.org/book/).
|
||||
|
||||
## Project Layout
|
||||
|
||||
The directory structure of this project is:
|
||||
|
||||
```
|
||||
revolt.node/
|
||||
├── Cargo.toml
|
||||
├── README.md
|
||||
├── src/
|
||||
| └── lib.rs
|
||||
├── index.node
|
||||
├── package.json
|
||||
└── target/
|
||||
```
|
||||
|
||||
| Entry | Purpose |
|
||||
|----------------|------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `Cargo.toml` | The Cargo [manifest file](https://doc.rust-lang.org/cargo/reference/manifest.html), which informs the `cargo` command. |
|
||||
| `README.md` | This file. |
|
||||
| `src/` | The directory tree containing the Rust source code for the project. |
|
||||
| `lib.rs` | Entry point for the Rust source code. |
|
||||
| `index.node` | The main module, a [Node addon](https://nodejs.org/api/addons.html) generated by the build and pointed to by `"main"` in `package.json`. |
|
||||
| `package.json` | The npm [manifest file](https://docs.npmjs.com/cli/v7/configuring-npm/package-json), which informs the `npm` command. |
|
||||
| `target/` | Binary artifacts generated by the Rust build. |
|
||||
|
||||
## Learn More
|
||||
|
||||
Learn more about:
|
||||
|
||||
- [Neon](https://neon-bindings.com).
|
||||
- [Rust](https://www.rust-lang.org).
|
||||
- [Node](https://nodejs.org).
|
||||
Vendored
-84
@@ -1,84 +0,0 @@
|
||||
import { Channel, User } from "revolt-api";
|
||||
|
||||
/**
|
||||
* Opaque type for Revolt database
|
||||
*/
|
||||
export declare interface Database {}
|
||||
|
||||
/**
|
||||
* Opaque type for Revolt database
|
||||
*/
|
||||
export declare interface OpaqueUser {}
|
||||
|
||||
/**
|
||||
* Error type from Revolt backend
|
||||
*/
|
||||
export declare interface Err {
|
||||
type: string;
|
||||
location: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises background tasks and logging, must be called before anything else!
|
||||
* Can be called multiple times!
|
||||
*/
|
||||
export declare function init();
|
||||
|
||||
/**
|
||||
* Gets a new handle to the Revolt database
|
||||
* @returns {Database} Handle
|
||||
*/
|
||||
export declare function database(): Database;
|
||||
|
||||
/**
|
||||
* Fetch user from database
|
||||
* @param {string} userId User's ID
|
||||
* @this {Database}
|
||||
*/
|
||||
export declare function database_fetch_user(userId: string): OpaqueUser;
|
||||
|
||||
/**
|
||||
* Fetch user from database
|
||||
* @param {string} username Username
|
||||
* @param {string} discriminator Discriminator
|
||||
* @this {Database}
|
||||
*/
|
||||
export declare function database_fetch_user_by_username(
|
||||
username: string,
|
||||
discriminator: string
|
||||
): OpaqueUser;
|
||||
|
||||
/**
|
||||
* Gets model data as JSON
|
||||
* @this {OpaqueUser}
|
||||
*/
|
||||
export declare function model_data(): User;
|
||||
|
||||
/**
|
||||
* Gets error if the model failed to fetch
|
||||
* @this {OpaqueUser}
|
||||
*/
|
||||
export declare function model_error(): Err;
|
||||
|
||||
/**
|
||||
* Open a direct message channel between two users
|
||||
* @param {string} userA User A ID
|
||||
* @param {string} userB User B ID
|
||||
* @returns Existing or newly created channel
|
||||
*/
|
||||
export declare function proc_channels_create_dm(
|
||||
userA: string,
|
||||
userB: string
|
||||
): Promise<Channel & { error: Err }>;
|
||||
|
||||
/**
|
||||
* Suspend a user
|
||||
* @param {string} user User
|
||||
* @param {number} duration Duration (in days), set to 0 for indefinite
|
||||
* @param {string} reason Pipe-separated list of reasons (e.g. reason1|reason2|reason3)
|
||||
*/
|
||||
export declare function proc_users_suspend(
|
||||
user: OpaqueUser,
|
||||
duration: number,
|
||||
reason: string
|
||||
): Promise<{ error: Err }>;
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "revolt-nodejs-bindings",
|
||||
"version": "0.7.15-rev0.0.3",
|
||||
"description": "Node.js bindings for the Revolt software",
|
||||
"main": "index.node",
|
||||
"scripts": {
|
||||
"test": "cargo test",
|
||||
"cargo-build": "cargo build --message-format=json > cargo.log",
|
||||
"cross-build": "cross build --message-format=json > cross.log",
|
||||
"postcargo-build": "neon dist < cargo.log",
|
||||
"postcross-build": "neon dist -m /target < cross.log",
|
||||
"debug": "npm run cargo-build --",
|
||||
"build": "npm run cargo-build -- --release",
|
||||
"cross": "npm run cross-build -- --release"
|
||||
},
|
||||
"author": "Paul Makles",
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
"@neon-rs/cli": "0.1.73"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/revoltchat/backend"
|
||||
},
|
||||
"keywords": [
|
||||
"revolt",
|
||||
"chat"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/revoltchat/backend/issues"
|
||||
},
|
||||
"homepage": "https://github.com/revoltchat/backend#readme",
|
||||
"dependencies": {
|
||||
"revolt-api": "^0.7.15"
|
||||
}
|
||||
}
|
||||
Generated
-117
@@ -1,117 +0,0 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
revolt-api:
|
||||
specifier: ^0.7.15
|
||||
version: 0.7.15
|
||||
|
||||
devDependencies:
|
||||
'@neon-rs/cli':
|
||||
specifier: 0.1.73
|
||||
version: 0.1.73
|
||||
|
||||
packages:
|
||||
|
||||
/@cargo-messages/android-arm-eabi@0.1.72:
|
||||
resolution: {integrity: sha512-gGZxIM1mj+Y5x+ULND6ZCNr7f70OJi9wDlycSK8hGONy9wrChN6JAIHryddC5cqcwlYAoQ6IDcDFElnhAYbybA==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cargo-messages/darwin-arm64@0.1.72:
|
||||
resolution: {integrity: sha512-EAzN5MLaXPljZKZDO5qR+aBs44eSq2ZbEnS7AI/FziE3MzeXbrGOS3fLba5+7yWPFXJyZolXzePm8N1EBv8ovg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cargo-messages/darwin-x64@0.1.72:
|
||||
resolution: {integrity: sha512-RLo6j8s3nYbjdd1LDct4wamfChyRit7zokUuxtIYCu9XOlltkN5vnj1vwnrPvoqCMZ/7CbbuHFwSTn9A71de/w==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cargo-messages/linux-arm-gnueabihf@0.1.72:
|
||||
resolution: {integrity: sha512-tHsRshuzfjrX6SDW3jg6al8vMNLTMgczGnVYl5RuBZf/yrAUuwe30KxA9ge6w6mW6Ox797DyBchzAc9OLgTgmQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cargo-messages/linux-x64-gnu@0.1.72:
|
||||
resolution: {integrity: sha512-VGtL6CCnUbhsP4aYuBNT5kfrAL7o0qjrxw97a+ax13t+nJd26tVEEIKHMu5drvvS/Nm/hn7sLT8zMnnCv0pvHg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cargo-messages/win32-arm64-msvc@0.1.72:
|
||||
resolution: {integrity: sha512-V93Cgz39K+yqa3MveNbhh29pYCp8izK5uEavjPoxlNxAbsMCWH+s0verGDdUcfGxjR1H2V7oZ4FszPqR2SqMRQ==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cargo-messages/win32-x64-msvc@0.1.72:
|
||||
resolution: {integrity: sha512-knz3uSrO0OSbq3U5VWfCY8FB4NsM43BOWLZ7x4sfaMOC1XWv+IyvDdkLe6DhJx8KUw46KIAimYs9YROrp6l46Q==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@neon-rs/cli@0.1.73:
|
||||
resolution: {integrity: sha512-1kv8S/feB6UQWQQwsnGfkSkEBOtlFDNExnioL81E2BwvUWgjQPaseHgpi2EpWVgsPUgur5eBm4QowmlpWkD4/w==}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
'@cargo-messages/android-arm-eabi': 0.1.72
|
||||
'@cargo-messages/darwin-arm64': 0.1.72
|
||||
'@cargo-messages/darwin-x64': 0.1.72
|
||||
'@cargo-messages/linux-arm-gnueabihf': 0.1.72
|
||||
'@cargo-messages/linux-x64-gnu': 0.1.72
|
||||
'@cargo-messages/win32-arm64-msvc': 0.1.72
|
||||
'@cargo-messages/win32-x64-msvc': 0.1.72
|
||||
dev: true
|
||||
|
||||
/axios@0.26.1:
|
||||
resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.6
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/follow-redirects@1.15.6:
|
||||
resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/lodash.defaultsdeep@4.6.1:
|
||||
resolution: {integrity: sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==}
|
||||
dev: false
|
||||
|
||||
/revolt-api@0.7.15:
|
||||
resolution: {integrity: sha512-rWRnjBFvoXt/RHRxHg9KuP+x1Jk61KdsOpKOczVJg5tIqGDmqp/6QZHw5rJTtG+wCH3Ah3YKwY+MM5NHfg1W3Q==}
|
||||
dependencies:
|
||||
axios: 0.26.1
|
||||
lodash.defaultsdeep: 4.6.1
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
@@ -1,221 +0,0 @@
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use neon::prelude::*;
|
||||
use revolt_database::{Database, DatabaseInfo};
|
||||
|
||||
fn js_init(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
// static INIT: OnceLock<()> = OnceLock::new();
|
||||
// if INIT.get().is_none() {
|
||||
// INIT.get_or_init(|| {
|
||||
// async_std::task::block_on(async {
|
||||
// revolt_config::configure!(api);
|
||||
|
||||
// match DatabaseInfo::Auto.connect().await {
|
||||
// Ok(db) => {
|
||||
// let authifier_db = db.clone().to_authifier().await.database;
|
||||
// revolt_database::tasks::start_workers(db, authifier_db);
|
||||
// Ok(())
|
||||
// }
|
||||
// Err(err) => Err(err),
|
||||
// }
|
||||
// })
|
||||
// .or_else(|err| cx.throw_error(err))
|
||||
// .unwrap();
|
||||
// });
|
||||
// }
|
||||
|
||||
Ok(cx.undefined())
|
||||
}
|
||||
|
||||
struct DatabaseBinding(Database, Channel);
|
||||
impl Finalize for DatabaseBinding {}
|
||||
impl DatabaseBinding {
|
||||
fn take(&self) -> (Database, Channel) {
|
||||
(self.0.clone(), self.1.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn js_database(mut cx: FunctionContext) -> JsResult<JsBox<DatabaseBinding>> {
|
||||
let db = async_std::task::block_on(DatabaseInfo::Auto.connect())
|
||||
.or_else(|err| cx.throw_error(err))?;
|
||||
|
||||
let channel = cx.channel();
|
||||
Ok(cx.boxed(DatabaseBinding(db, channel)))
|
||||
}
|
||||
|
||||
// Implementations for models
|
||||
#[derive(Clone)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum Model {
|
||||
User(revolt_database::User),
|
||||
Error(revolt_result::Error),
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn give(&self) -> Model {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Finalize for Model {}
|
||||
|
||||
macro_rules! shim_boxed {
|
||||
($cx: ident, $name: ident, $model: ident, $( $variable: ident $type: ident $id: expr )+, $cmd: ident, $( $arg: expr, )+) => {
|
||||
fn $name(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||
$(
|
||||
let $variable = cx.argument::<$type>($id)?.value(&mut cx);
|
||||
)+
|
||||
|
||||
let (db, channel) = cx.this::<JsBox<DatabaseBinding>>()?.take();
|
||||
let (deferred, promise) = cx.promise();
|
||||
|
||||
async_std::task::spawn(async move {
|
||||
let result = db.$cmd($($arg,)+).await;
|
||||
deferred.settle_with(&channel, move |mut cx| {
|
||||
Ok(cx.boxed(match result {
|
||||
Ok(value) => Model::$model(value),
|
||||
Err(error) => Model::Error(error)
|
||||
}))
|
||||
})
|
||||
});
|
||||
|
||||
Ok(promise)
|
||||
}
|
||||
|
||||
$cx.export_function(stringify!($name), $name)?;
|
||||
};
|
||||
}
|
||||
|
||||
fn js_data(mut cx: FunctionContext) -> JsResult<JsValue> {
|
||||
match cx.this::<JsBox<Model>>()?.give() {
|
||||
Model::Error(_) => neon_serde4::to_value(&mut cx, &None::<()>),
|
||||
Model::User(user) => neon_serde4::to_value(&mut cx, &user),
|
||||
}
|
||||
.or_else(|e| cx.throw_error(e.to_string()))
|
||||
}
|
||||
|
||||
fn js_error(mut cx: FunctionContext) -> JsResult<JsValue> {
|
||||
let value = match cx.this::<JsBox<Model>>()?.give() {
|
||||
Model::Error(err) => Some(err),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
neon_serde4::to_value(&mut cx, &value).or_else(|e| cx.throw_error(e.to_string()))
|
||||
}
|
||||
|
||||
// Basic data implementation
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ResultBinding<T> {
|
||||
#[serde(flatten)]
|
||||
value: Option<T>,
|
||||
error: Option<revolt_result::Error>,
|
||||
}
|
||||
|
||||
macro_rules! shim {
|
||||
($cx: ident, $name: ident, $( $variable: ident $type: ident $id: expr )*, $( $model: ident $modelType: ident $modelId: expr )*, | $db: ident | $closure: expr, $( $arg: expr, )+) => {
|
||||
fn $name(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||
$(
|
||||
let $variable = cx.argument::<$type>($id)?.value(&mut cx);
|
||||
)*
|
||||
|
||||
$(
|
||||
let mut $model = if let Model::$modelType(value) = cx.argument::<JsBox<Model>>($modelId)?.give() {
|
||||
value
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
)*
|
||||
|
||||
let (db, channel) = cx.this::<JsBox<DatabaseBinding>>()?.take();
|
||||
let (deferred, promise) = cx.promise();
|
||||
|
||||
async_std::task::spawn(async move {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let result = (|$db: $crate::Database| $closure)(db.clone()).await;
|
||||
deferred.settle_with(&channel, move |mut cx| {
|
||||
neon_serde4::to_value(
|
||||
&mut cx,
|
||||
&match result {
|
||||
Ok(value) => ResultBinding {
|
||||
value: Some(value),
|
||||
error: None,
|
||||
},
|
||||
Err(error) => ResultBinding {
|
||||
value: None,
|
||||
error: Some(error),
|
||||
},
|
||||
},
|
||||
)
|
||||
.or_else(|e| cx.throw_error(e.to_string()))
|
||||
})
|
||||
});
|
||||
|
||||
Ok(promise)
|
||||
}
|
||||
|
||||
$cx.export_function(stringify!($name), $name)?;
|
||||
};
|
||||
}
|
||||
|
||||
#[neon::main]
|
||||
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
// initialise required background stuff
|
||||
cx.export_function("init", js_init)?;
|
||||
|
||||
// database & model stuff
|
||||
cx.export_function("database", js_database)?;
|
||||
cx.export_function("model_data", js_data)?;
|
||||
cx.export_function("model_error", js_error)?;
|
||||
|
||||
shim_boxed!(
|
||||
cx,
|
||||
database_fetch_user,
|
||||
User,
|
||||
user_id JsString 0,
|
||||
fetch_user,
|
||||
&user_id,
|
||||
);
|
||||
|
||||
shim_boxed!(
|
||||
cx,
|
||||
database_fetch_user_by_username,
|
||||
User,
|
||||
username JsString 0
|
||||
discriminator JsString 1,
|
||||
fetch_user_by_username,
|
||||
&username, &discriminator,
|
||||
);
|
||||
|
||||
// procedure calls
|
||||
shim!(
|
||||
cx,
|
||||
proc_channels_create_dm,
|
||||
user_a JsString 0
|
||||
user_b JsString 1,
|
||||
,
|
||||
|db| async move {
|
||||
let user_a = db.fetch_user(&user_a).await?;
|
||||
let user_b = db.fetch_user(&user_b).await?;
|
||||
revolt_database::Channel::create_dm(&db, &user_a, &user_b).await
|
||||
},
|
||||
&userA, &userB,
|
||||
);
|
||||
|
||||
shim!(
|
||||
cx,
|
||||
proc_users_suspend,
|
||||
duration JsNumber 1
|
||||
reason JsString 2,
|
||||
user User 0,
|
||||
|db| async move {
|
||||
let duration = duration as usize;
|
||||
user.suspend(&db, if duration == 0 { None } else { Some(duration) }, Some(reason.split('|').map(|x| x.to_owned()).collect())).await
|
||||
},
|
||||
&user,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
const Internal = require(".");
|
||||
|
||||
// playing around with class wrapper, not practical
|
||||
class Model {
|
||||
constructor(model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
data() {
|
||||
return Internal.model_data.bind(this.model)();
|
||||
}
|
||||
|
||||
error() {
|
||||
return Internal.model_error.bind(this.model)();
|
||||
}
|
||||
}
|
||||
|
||||
class User extends Model {
|
||||
constructor(db, user) {
|
||||
super(user);
|
||||
this.db = db;
|
||||
}
|
||||
}
|
||||
|
||||
class Database {
|
||||
constructor() {
|
||||
this.db = Internal.database();
|
||||
}
|
||||
|
||||
async fetchUser(userId) {
|
||||
return new User(
|
||||
this,
|
||||
await Internal.database_fetch_user.bind(this.db)(userId)
|
||||
);
|
||||
}
|
||||
|
||||
async fetchUserByUsername(username, discriminator) {
|
||||
return new User(
|
||||
this,
|
||||
await Internal.database_fetch_user_by_username.bind(this.db)(
|
||||
username,
|
||||
discriminator
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const db = new Database();
|
||||
db.fetchUserByUsername("dos", "7624").then((user) => console.info(user.data()));
|
||||
db.fetchUserByUsername("dos", "1111").then((user) => console.info(user.data()));
|
||||
db.fetchUserByUsername("dos", "1111").then((user) =>
|
||||
console.info(user.error())
|
||||
);
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "bindings",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
license = "AGPL-3.0-or-later"
|
||||
edition = "2021"
|
||||
|
||||
@@ -36,12 +36,12 @@ async-std = { version = "1.8.0", features = [
|
||||
] }
|
||||
|
||||
# core
|
||||
authifier = { version = "1.0.10" }
|
||||
authifier = { version = "1.0.13" }
|
||||
revolt-result = { path = "../core/result" }
|
||||
revolt-models = { path = "../core/models" }
|
||||
revolt-config = { path = "../core/config" }
|
||||
revolt-database = { path = "../core/database" }
|
||||
revolt-permissions = { version = "0.8.4", path = "../core/permissions" }
|
||||
revolt-permissions = { version = "0.8.5", path = "../core/permissions" }
|
||||
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
|
||||
|
||||
# redis
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-config"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -34,4 +34,4 @@ pretty_env_logger = "0.4.0"
|
||||
sentry = "0.31.5"
|
||||
|
||||
# Core
|
||||
revolt-result = { version = "0.8.4", path = "../result", optional = true }
|
||||
revolt-result = { version = "0.8.5", path = "../result", optional = true }
|
||||
|
||||
@@ -54,6 +54,8 @@ authifier_shield_key = ""
|
||||
voso_legacy_token = ""
|
||||
# Whether services are behind the Cloudflare network
|
||||
trust_cloudflare = false
|
||||
# easypwned endpoint
|
||||
easypwned = ""
|
||||
|
||||
[api.security.captcha]
|
||||
# hCaptcha configuration
|
||||
@@ -200,7 +202,6 @@ message_reactions = 20
|
||||
server_emoji = 100
|
||||
server_roles = 200
|
||||
server_channels = 200
|
||||
server_categories = 50
|
||||
|
||||
# How many hours since creation a user is considered new
|
||||
new_user_hours = 72
|
||||
|
||||
@@ -123,6 +123,7 @@ pub struct ApiSmtp {
|
||||
pub reply_to: Option<String>,
|
||||
pub port: Option<i32>,
|
||||
pub use_tls: Option<bool>,
|
||||
pub use_starttls: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
@@ -168,6 +169,7 @@ pub struct ApiSecurity {
|
||||
pub voso_legacy_token: String,
|
||||
pub captcha: ApiSecurityCaptcha,
|
||||
pub trust_cloudflare: bool,
|
||||
pub easypwned: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
@@ -177,7 +179,7 @@ pub struct ApiWorkers {
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct ApiUsers {
|
||||
pub early_adopter_cutoff: Option<u64>
|
||||
pub early_adopter_cutoff: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
@@ -281,7 +283,6 @@ pub struct GlobalLimits {
|
||||
pub server_emoji: usize,
|
||||
pub server_roles: usize,
|
||||
pub server_channels: usize,
|
||||
pub server_categories: usize,
|
||||
|
||||
pub new_user_hours: usize,
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-database"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -24,19 +24,19 @@ default = ["mongodb", "async-std-runtime", "tasks"]
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-config = { version = "0.8.4", path = "../config", features = [
|
||||
revolt-config = { version = "0.8.5", path = "../config", features = [
|
||||
"report-macros",
|
||||
] }
|
||||
revolt-result = { version = "0.8.4", path = "../result" }
|
||||
revolt-models = { version = "0.8.4", path = "../models", features = [
|
||||
revolt-result = { version = "0.8.5", path = "../result" }
|
||||
revolt-models = { version = "0.8.5", path = "../models", features = [
|
||||
"validator",
|
||||
] }
|
||||
revolt-presence = { version = "0.8.4", path = "../presence" }
|
||||
revolt-permissions = { version = "0.8.4", path = "../permissions", features = [
|
||||
revolt-presence = { version = "0.8.5", path = "../presence" }
|
||||
revolt-permissions = { version = "0.8.5", path = "../permissions", features = [
|
||||
"serde",
|
||||
"bson",
|
||||
] }
|
||||
revolt-parser = { version = "0.1.0", path = "../parser" }
|
||||
revolt-parser = { version = "0.1.1", path = "../parser" }
|
||||
|
||||
# Utility
|
||||
log = "0.4"
|
||||
@@ -97,7 +97,7 @@ web-push = "0.10.0"
|
||||
revolt_a2 = { version = "0.10", default-features = false, features = ["ring"] }
|
||||
|
||||
# Authifier
|
||||
authifier = { version = "1.0.10", features = ["rocket_impl"] }
|
||||
authifier = { version = "1.0.13", features = ["rocket_impl"] }
|
||||
|
||||
# RabbitMQ
|
||||
amqprs = { version = "1.7.0" }
|
||||
|
||||
@@ -3,6 +3,7 @@ mod reference;
|
||||
|
||||
use authifier::config::Captcha;
|
||||
use authifier::config::EmailVerificationConfig;
|
||||
use authifier::config::PasswordScanning;
|
||||
use authifier::config::ResolveIp;
|
||||
use authifier::config::SMTPSettings;
|
||||
use authifier::config::Shield;
|
||||
@@ -102,6 +103,13 @@ impl Database {
|
||||
let config = config().await;
|
||||
|
||||
let mut auth_config = authifier::Config {
|
||||
password_scanning: if config.api.security.easypwned.is_empty() {
|
||||
Default::default()
|
||||
} else {
|
||||
PasswordScanning::EasyPwned {
|
||||
endpoint: config.api.security.easypwned,
|
||||
}
|
||||
},
|
||||
email_verification: if !config.api.smtp.host.is_empty() {
|
||||
EmailVerificationConfig::Enabled {
|
||||
smtp: SMTPSettings {
|
||||
@@ -118,6 +126,7 @@ impl Database {
|
||||
),
|
||||
port: config.api.smtp.port,
|
||||
use_tls: config.api.smtp.use_tls,
|
||||
use_starttls: config.api.smtp.use_starttls,
|
||||
},
|
||||
expiry: Default::default(),
|
||||
templates: if config.production {
|
||||
@@ -134,6 +143,15 @@ impl Database {
|
||||
url: format!("{}/login/reset/", config.hosts.app),
|
||||
html: Some(include_str!("../../templates/reset.html").into()),
|
||||
},
|
||||
reset_existing: Template {
|
||||
title: "You already have a Revolt account, reset your password."
|
||||
.into(),
|
||||
text: include_str!("../../templates/reset-existing.txt").into(),
|
||||
url: format!("{}/login/reset/", config.hosts.app),
|
||||
html: Some(
|
||||
include_str!("../../templates/reset-existing.html").into(),
|
||||
),
|
||||
},
|
||||
deletion: Template {
|
||||
title: "Confirm account deletion.".into(),
|
||||
text: include_str!("../../templates/deletion.txt").into(),
|
||||
@@ -156,9 +174,16 @@ impl Database {
|
||||
url: format!("{}/login/reset/", config.hosts.app),
|
||||
html: None,
|
||||
},
|
||||
reset_existing: Template {
|
||||
title: "Reset your password.".into(),
|
||||
text: include_str!("../../templates/reset.whitelabel.txt").into(),
|
||||
url: format!("{}/login/reset/", config.hosts.app),
|
||||
html: None,
|
||||
},
|
||||
deletion: Template {
|
||||
title: "Confirm account deletion.".into(),
|
||||
text: include_str!("../../templates/deletion.whitelabel.txt").into(),
|
||||
text: include_str!("../../templates/deletion.whitelabel.txt")
|
||||
.into(),
|
||||
url: format!("{}/delete/", config.hosts.app),
|
||||
html: None,
|
||||
},
|
||||
|
||||
@@ -100,10 +100,6 @@ auto_derived!(
|
||||
)]
|
||||
role_permissions: HashMap<String, OverrideField>,
|
||||
|
||||
/// Category the channel is in
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
parent: Option<String>,
|
||||
|
||||
/// Whether this channel is marked as not safe for work
|
||||
#[serde(skip_serializing_if = "crate::if_false", default)]
|
||||
nsfw: bool,
|
||||
@@ -135,10 +131,6 @@ auto_derived!(
|
||||
)]
|
||||
role_permissions: HashMap<String, OverrideField>,
|
||||
|
||||
/// Category the channel is in
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
parent: Option<String>,
|
||||
|
||||
/// Whether this channel is marked as not safe for work
|
||||
#[serde(skip_serializing_if = "crate::if_false", default)]
|
||||
nsfw: bool,
|
||||
@@ -169,8 +161,6 @@ auto_derived!(
|
||||
pub default_permissions: Option<OverrideField>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub last_message_id: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parent: Option<String>,
|
||||
}
|
||||
|
||||
/// Optional fields on channel object
|
||||
@@ -229,7 +219,6 @@ impl Channel {
|
||||
default_permissions: None,
|
||||
role_permissions: HashMap::new(),
|
||||
nsfw: data.nsfw.unwrap_or(false),
|
||||
parent: None
|
||||
},
|
||||
v0::LegacyServerChannelType::Voice => Channel::VoiceChannel {
|
||||
id: id.clone(),
|
||||
@@ -240,7 +229,6 @@ impl Channel {
|
||||
default_permissions: None,
|
||||
role_permissions: HashMap::new(),
|
||||
nsfw: data.nsfw.unwrap_or(false),
|
||||
parent: None
|
||||
},
|
||||
};
|
||||
|
||||
@@ -449,13 +437,6 @@ impl Channel {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<&str> {
|
||||
match self {
|
||||
Channel::TextChannel { parent, .. } | Channel::VoiceChannel { parent, .. } => parent.as_deref(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set role permission on a channel
|
||||
pub async fn set_role_permission(
|
||||
&mut self,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use revolt_models::v0::{self, DataCreateCategory, DataCreateServerChannel, DataEditCategory};
|
||||
use revolt_models::v0::{self, DataCreateServerChannel};
|
||||
use revolt_permissions::{OverrideField, DEFAULT_PERMISSION_SERVER};
|
||||
use revolt_result::Result;
|
||||
use ulid::Ulid;
|
||||
@@ -26,8 +26,8 @@ auto_derived_partial!(
|
||||
// TODO: investigate if this is redundant and can be removed
|
||||
pub channels: Vec<String>,
|
||||
/// Categories for this server
|
||||
#[serde(skip_serializing_if = "HashMap::is_empty")]
|
||||
pub categories: HashMap<String, Category>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub categories: Option<Vec<Category>>,
|
||||
/// Configuration for sending system event messages
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub system_messages: Option<SystemMessageChannels>,
|
||||
@@ -87,29 +87,17 @@ auto_derived_partial!(
|
||||
"PartialRole"
|
||||
);
|
||||
|
||||
auto_derived_partial!(
|
||||
auto_derived!(
|
||||
/// Channel category
|
||||
pub struct Category {
|
||||
/// Unique ID for this category
|
||||
pub id: String,
|
||||
/// Title for this category
|
||||
pub title: String,
|
||||
/// Default permissions assigned to users in this category
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub default_permissions: Option<OverrideField>,
|
||||
/// Permissions assigned based on role to this category
|
||||
#[serde(
|
||||
default = "HashMap::<String, OverrideField>::new",
|
||||
skip_serializing_if = "HashMap::<String, OverrideField>::is_empty"
|
||||
)]
|
||||
pub role_permissions: HashMap<String, OverrideField>,
|
||||
/// Channels in this category
|
||||
pub channels: Vec<String>,
|
||||
},
|
||||
"PartialCategory"
|
||||
);
|
||||
}
|
||||
|
||||
auto_derived!(
|
||||
/// System message channel assignments
|
||||
pub struct SystemMessageChannels {
|
||||
/// ID of channel to send user join messages in
|
||||
@@ -139,10 +127,6 @@ auto_derived!(
|
||||
pub enum FieldsRole {
|
||||
Colour,
|
||||
}
|
||||
|
||||
pub enum FieldsCategory {
|
||||
DefaultPermissions
|
||||
}
|
||||
);
|
||||
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
@@ -165,7 +149,7 @@ impl Server {
|
||||
|
||||
analytics: false,
|
||||
banner: None,
|
||||
categories: HashMap::new(),
|
||||
categories: None,
|
||||
discoverable: false,
|
||||
flags: None,
|
||||
icon: None,
|
||||
@@ -237,7 +221,7 @@ impl Server {
|
||||
pub fn remove_field(&mut self, field: &FieldsServer) {
|
||||
match field {
|
||||
FieldsServer::Description => self.description = None,
|
||||
FieldsServer::Categories => self.categories.clear(),
|
||||
FieldsServer::Categories => self.categories = None,
|
||||
FieldsServer::SystemMessages => self.system_messages = None,
|
||||
FieldsServer::Icon => self.icon = None,
|
||||
FieldsServer::Banner => self.banner = None,
|
||||
@@ -350,110 +334,6 @@ impl Role {
|
||||
}
|
||||
}
|
||||
|
||||
impl Category {
|
||||
pub fn remove_field(&mut self, field: FieldsCategory) {
|
||||
match field {
|
||||
FieldsCategory::DefaultPermissions => self.default_permissions = None
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn create(db: &Database, server: &mut Server, data: DataCreateCategory) -> Result<Category> {
|
||||
let channels = data.channels.clone().unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter(|c| server.channels.contains(&c))
|
||||
.collect();
|
||||
|
||||
let category = Category {
|
||||
id: Ulid::new().to_string(),
|
||||
title: data.title,
|
||||
channels: channels,
|
||||
default_permissions: None,
|
||||
role_permissions: HashMap::new()
|
||||
};
|
||||
|
||||
server.categories.insert(category.id.clone(), category.clone());
|
||||
|
||||
let partial_server = PartialServer { categories: Some(server.categories.clone()), ..Default::default() };
|
||||
|
||||
db.update_server(&server.id, &partial_server, Vec::new()).await?;
|
||||
|
||||
EventV1::ServerUpdate {
|
||||
id: server.id.clone(),
|
||||
data: partial_server.into(),
|
||||
clear: Vec::new(),
|
||||
}
|
||||
.p(server.id.clone())
|
||||
.await;
|
||||
|
||||
Ok(category)
|
||||
}
|
||||
|
||||
pub async fn delete(&self, db: &Database, server: &mut Server) -> Result<()> {
|
||||
// update the parent server model with the new category
|
||||
server.categories.remove(&self.id);
|
||||
|
||||
let partial_server = PartialServer { categories: Some(server.categories.clone()), ..Default::default() };
|
||||
|
||||
db.update_server(&server.id, &partial_server, Vec::new()).await?;
|
||||
|
||||
EventV1::ServerUpdate {
|
||||
id: server.id.clone(),
|
||||
data: partial_server.into(),
|
||||
clear: Vec::new(),
|
||||
}
|
||||
.p(server.id.clone())
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update(&mut self, db: &Database, server: &mut Server, partial: PartialCategory, remove: Vec<FieldsCategory>) -> Result<()> {
|
||||
for field in remove {
|
||||
self.remove_field(field);
|
||||
};
|
||||
|
||||
self.apply_options(partial);
|
||||
|
||||
// update the parent server model with the new category
|
||||
server.categories.insert(self.id.clone(), self.clone());
|
||||
|
||||
let partial_server = PartialServer { categories: Some(server.categories.clone()), ..Default::default() };
|
||||
|
||||
db.update_server(&server.id, &partial_server, Vec::new()).await?;
|
||||
|
||||
EventV1::ServerUpdate {
|
||||
id: server.id.clone(),
|
||||
data: partial_server.into(),
|
||||
clear: Vec::new(),
|
||||
}
|
||||
.p(server.id.clone())
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_role_permission(&mut self, db: &Database, server: &mut Server, role_id: String, role_override: OverrideField) -> Result<()> {
|
||||
self.role_permissions.insert(role_id, role_override);
|
||||
|
||||
// update the parent server model with the new category
|
||||
server.categories.insert(self.id.clone(), self.clone());
|
||||
|
||||
let partial_server = PartialServer { categories: Some(server.categories.clone()), ..Default::default() };
|
||||
|
||||
db.update_server(&server.id, &partial_server, Vec::new()).await?;
|
||||
|
||||
EventV1::ServerUpdate {
|
||||
id: server.id.clone(),
|
||||
data: partial_server.into(),
|
||||
clear: Vec::new(),
|
||||
}
|
||||
.p(server.id.clone())
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemMessageChannels {
|
||||
pub fn into_channel_ids(self) -> HashSet<String> {
|
||||
let mut ids = HashSet::new();
|
||||
|
||||
@@ -187,7 +187,6 @@ impl From<crate::Channel> for Channel {
|
||||
last_message_id,
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
} => Channel::TextChannel {
|
||||
id,
|
||||
@@ -198,7 +197,6 @@ impl From<crate::Channel> for Channel {
|
||||
last_message_id,
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
},
|
||||
crate::Channel::VoiceChannel {
|
||||
@@ -209,7 +207,6 @@ impl From<crate::Channel> for Channel {
|
||||
icon,
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
} => Channel::VoiceChannel {
|
||||
id,
|
||||
@@ -219,7 +216,6 @@ impl From<crate::Channel> for Channel {
|
||||
icon: icon.map(|file| file.into()),
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
},
|
||||
}
|
||||
@@ -271,7 +267,6 @@ impl From<Channel> for crate::Channel {
|
||||
last_message_id,
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
} => crate::Channel::TextChannel {
|
||||
id,
|
||||
@@ -282,7 +277,6 @@ impl From<Channel> for crate::Channel {
|
||||
last_message_id,
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
},
|
||||
Channel::VoiceChannel {
|
||||
@@ -293,7 +287,6 @@ impl From<Channel> for crate::Channel {
|
||||
icon,
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
} => crate::Channel::VoiceChannel {
|
||||
id,
|
||||
@@ -303,7 +296,6 @@ impl From<Channel> for crate::Channel {
|
||||
icon: icon.map(|file| file.into()),
|
||||
default_permissions,
|
||||
role_permissions,
|
||||
parent,
|
||||
nsfw,
|
||||
},
|
||||
}
|
||||
@@ -323,7 +315,6 @@ impl From<crate::PartialChannel> for PartialChannel {
|
||||
role_permissions: value.role_permissions,
|
||||
default_permissions: value.default_permissions,
|
||||
last_message_id: value.last_message_id,
|
||||
parent: value.parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,7 +332,6 @@ impl From<PartialChannel> for crate::PartialChannel {
|
||||
role_permissions: value.role_permissions,
|
||||
default_permissions: value.default_permissions,
|
||||
last_message_id: value.last_message_id,
|
||||
parent: value.parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -739,7 +729,9 @@ impl From<crate::Server> for Server {
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
channels: value.channels,
|
||||
categories: value.categories.into_iter().map(|(k, v)| (k, v.into())).collect(),
|
||||
categories: value
|
||||
.categories
|
||||
.map(|categories| categories.into_iter().map(|v| v.into()).collect()),
|
||||
system_messages: value.system_messages.map(|v| v.into()),
|
||||
roles: value
|
||||
.roles
|
||||
@@ -765,7 +757,9 @@ impl From<Server> for crate::Server {
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
channels: value.channels,
|
||||
categories: value.categories.into_iter().map(|(k, v)| (k, v.into())).collect(),
|
||||
categories: value
|
||||
.categories
|
||||
.map(|categories| categories.into_iter().map(|v| v.into()).collect()),
|
||||
system_messages: value.system_messages.map(|v| v.into()),
|
||||
roles: value
|
||||
.roles
|
||||
@@ -791,7 +785,9 @@ impl From<crate::PartialServer> for PartialServer {
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
channels: value.channels,
|
||||
categories: value.categories.map(|x| x.into_iter().map(|(k, v)| (k, v.into())).collect()),
|
||||
categories: value
|
||||
.categories
|
||||
.map(|categories| categories.into_iter().map(|v| v.into()).collect()),
|
||||
system_messages: value.system_messages.map(|v| v.into()),
|
||||
roles: value
|
||||
.roles
|
||||
@@ -815,7 +811,9 @@ impl From<PartialServer> for crate::PartialServer {
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
channels: value.channels,
|
||||
categories: value.categories.map(|x| x.into_iter().map(|(k, v)| (k, v.into())).collect()),
|
||||
categories: value
|
||||
.categories
|
||||
.map(|categories| categories.into_iter().map(|v| v.into()).collect()),
|
||||
system_messages: value.system_messages.map(|v| v.into()),
|
||||
roles: value
|
||||
.roles
|
||||
@@ -861,8 +859,6 @@ impl From<crate::Category> for Category {
|
||||
id: value.id,
|
||||
title: value.title,
|
||||
channels: value.channels,
|
||||
role_permissions: value.role_permissions,
|
||||
default_permissions: value.default_permissions,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -873,24 +869,6 @@ impl From<Category> for crate::Category {
|
||||
id: value.id,
|
||||
title: value.title,
|
||||
channels: value.channels,
|
||||
role_permissions: value.role_permissions,
|
||||
default_permissions: value.default_permissions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::FieldsCategory> for FieldsCategory {
|
||||
fn from(value: crate::FieldsCategory) -> Self {
|
||||
match value {
|
||||
crate::FieldsCategory::DefaultPermissions => FieldsCategory::DefaultPermissions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FieldsCategory> for crate::FieldsCategory {
|
||||
fn from(value: FieldsCategory) -> crate::FieldsCategory {
|
||||
match value {
|
||||
FieldsCategory::DefaultPermissions => crate::FieldsCategory::DefaultPermissions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use revolt_permissions::{
|
||||
DEFAULT_PERMISSION_DIRECT_MESSAGE,
|
||||
};
|
||||
|
||||
use crate::{Category, Channel, Database, Member, Server, User};
|
||||
use crate::{Channel, Database, Member, Server, User};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BulkDatabasePermissionQuery<'a> {
|
||||
@@ -197,7 +197,7 @@ async fn calculate_members_permissions<'a>(
|
||||
) -> HashMap<String, PermissionValue> {
|
||||
let mut resp = HashMap::new();
|
||||
|
||||
let (_, channel_role_permissions, channel_default_permissions, parent) = match query
|
||||
let (_, channel_role_permissions, channel_default_permissions) = match query
|
||||
.channel
|
||||
.as_ref()
|
||||
.expect("A channel must be assigned to calculate channel permissions")
|
||||
@@ -207,16 +207,14 @@ async fn calculate_members_permissions<'a>(
|
||||
id,
|
||||
role_permissions,
|
||||
default_permissions,
|
||||
parent,
|
||||
..
|
||||
}
|
||||
| Channel::VoiceChannel {
|
||||
id,
|
||||
role_permissions,
|
||||
default_permissions,
|
||||
parent,
|
||||
..
|
||||
} => (id, role_permissions, default_permissions, parent),
|
||||
} => (id, role_permissions, default_permissions),
|
||||
_ => panic!("Calculation of member permissions must be done on a server channel"),
|
||||
};
|
||||
|
||||
@@ -270,8 +268,6 @@ async fn calculate_members_permissions<'a>(
|
||||
.map(|m| (&m.id.user, m)),
|
||||
);
|
||||
|
||||
let category = parent.map(|parent| query.server.categories.get(&parent).expect("Channel parent doesnt exist"));
|
||||
|
||||
for user in users {
|
||||
let member = members.get(&user.id);
|
||||
|
||||
@@ -302,39 +298,11 @@ async fn calculate_members_permissions<'a>(
|
||||
// Get the user's server permissions
|
||||
let mut permission = calculate_server_permissions(&query.server, user, member);
|
||||
|
||||
// Apply category overrides
|
||||
if let Some(category) = category {
|
||||
if let Some(defaults) = category.default_permissions {
|
||||
permission.apply(defaults.into());
|
||||
};
|
||||
|
||||
// Get the applicable role overrides for the category
|
||||
let mut roles = category.role_permissions
|
||||
.iter()
|
||||
.filter(|(id, _)| member.roles.contains(id))
|
||||
.filter_map(|(id, permission)| {
|
||||
query.server.roles.get(id).map(|role| {
|
||||
let v: Override = (*permission).into();
|
||||
(role.rank, v)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<(i64, Override)>>();
|
||||
|
||||
roles.sort_by(|a, b| b.0.cmp(&a.0));
|
||||
let overrides = roles.into_iter().map(|(_, v)| v);
|
||||
|
||||
for role_override in overrides {
|
||||
permission.apply(role_override)
|
||||
}
|
||||
};
|
||||
|
||||
// apply channel overrides
|
||||
|
||||
if let Some(defaults) = channel_default_permissions {
|
||||
permission.apply(defaults.into());
|
||||
}
|
||||
|
||||
// Get the applicable role overrides for the channel
|
||||
// Get the applicable role overrides
|
||||
let mut roles = channel_role_permissions
|
||||
.iter()
|
||||
.filter(|(id, _)| member.roles.contains(id))
|
||||
|
||||
@@ -5,7 +5,7 @@ use revolt_permissions::{
|
||||
RelationshipStatus, DEFAULT_PERMISSION_DIRECT_MESSAGE,
|
||||
};
|
||||
|
||||
use crate::{Category, Channel, Database, Member, Server, User};
|
||||
use crate::{Channel, Database, Member, Server, User};
|
||||
|
||||
/// Permissions calculator
|
||||
#[derive(Clone)]
|
||||
@@ -16,7 +16,6 @@ pub struct DatabasePermissionQuery<'a> {
|
||||
perspective: &'a User,
|
||||
user: Option<Cow<'a, User>>,
|
||||
channel: Option<Cow<'a, Channel>>,
|
||||
category: Option<Cow<'a, Category>>,
|
||||
server: Option<Cow<'a, Server>>,
|
||||
member: Option<Cow<'a, Member>>,
|
||||
|
||||
@@ -289,40 +288,6 @@ impl PermissionQuery for DatabasePermissionQuery<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_default_category_permissions(&mut self) -> Override {
|
||||
if let Some(category) = &self.category {
|
||||
category.default_permissions.unwrap_or_default().into()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_our_category_role_overrides(&mut self) -> Vec<Override> {
|
||||
if let Some((server, category)) = self.server.as_ref().zip(self.category.as_ref()) {
|
||||
let member_roles = self
|
||||
.member
|
||||
.as_ref()
|
||||
.map(|member| member.roles.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut roles = category.role_permissions
|
||||
.iter()
|
||||
.filter(|(id, _)| member_roles.contains(id))
|
||||
.filter_map(|(id, permission)| {
|
||||
server.roles.get(id).map(|role| {
|
||||
let v: Override = (*permission).into();
|
||||
(role.rank, v)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<(i64, Override)>>();
|
||||
|
||||
roles.sort_by(|a, b| b.0.cmp(&a.0));
|
||||
roles.into_iter().map(|(_, v)| v).collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Do we own this group or saved messages channel if it is one of those?
|
||||
async fn do_we_own_the_channel(&mut self) -> bool {
|
||||
if let Some(channel) = &self.channel {
|
||||
@@ -410,14 +375,6 @@ impl PermissionQuery for DatabasePermissionQuery<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn set_category_from_channel(&mut self) {
|
||||
if let Some((server, channel)) = self.server.as_ref().zip(self.channel.as_ref()) {
|
||||
let category = channel.parent().and_then(|id| server.categories.get(id)).cloned();
|
||||
|
||||
self.category = category.map(Cow::Owned);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DatabasePermissionQuery<'a> {
|
||||
@@ -428,7 +385,6 @@ impl<'a> DatabasePermissionQuery<'a> {
|
||||
perspective,
|
||||
user: None,
|
||||
channel: None,
|
||||
category: None,
|
||||
server: None,
|
||||
member: None,
|
||||
|
||||
@@ -487,13 +443,6 @@ impl<'a> DatabasePermissionQuery<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn category(self, category: &'a Category) -> DatabasePermissionQuery<'a> {
|
||||
DatabasePermissionQuery {
|
||||
category: Some(Cow::Borrowed(category)),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Use member
|
||||
pub fn member(self, member: &'a Member) -> DatabasePermissionQuery {
|
||||
DatabasePermissionQuery {
|
||||
|
||||
@@ -10,7 +10,7 @@ use schemars::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Bot, Category, Channel, Database, Emoji, Invite, Member, Message, Server, ServerBan, User, Webhook
|
||||
Bot, Channel, Database, Emoji, Invite, Member, Message, Server, ServerBan, User, Webhook,
|
||||
};
|
||||
|
||||
/// Reference to some object in the database
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<!-- Compiled with Bootstrap Email version: 1.5.1 --><meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style type="text/css">
|
||||
body,table,td{font-family:Helvetica,Arial,sans-serif !important}.ExternalClass{width:100%}.ExternalClass,.ExternalClass p,.ExternalClass span,.ExternalClass font,.ExternalClass td,.ExternalClass div{line-height:150%}a{text-decoration:none}*{color:inherit}a[x-apple-data-detectors],u+#body a,#MessageViewBody a{color:inherit;text-decoration:none;font-size:inherit;font-family:inherit;font-weight:inherit;line-height:inherit}img{-ms-interpolation-mode:bicubic}table:not([class^=s-]){font-family:Helvetica,Arial,sans-serif;mso-table-lspace:0pt;mso-table-rspace:0pt;border-spacing:0px;border-collapse:collapse}table:not([class^=s-]) td{border-spacing:0px;border-collapse:collapse}@media screen and (max-width: 600px){.w-full,.w-full>tbody>tr>td{width:100% !important}.w-24,.w-24>tbody>tr>td{width:96px !important}.p-lg-10:not(table),.p-lg-10:not(.btn)>tbody>tr>td,.p-lg-10.btn td a{padding:0 !important}.p-3:not(table),.p-3:not(.btn)>tbody>tr>td,.p-3.btn td a{padding:12px !important}.p-6:not(table),.p-6:not(.btn)>tbody>tr>td,.p-6.btn td a{padding:24px !important}*[class*=s-lg-]>tbody>tr>td{font-size:0 !important;line-height:0 !important;height:0 !important}.s-4>tbody>tr>td{font-size:16px !important;line-height:16px !important;height:16px !important}.s-6>tbody>tr>td{font-size:24px !important;line-height:24px !important;height:24px !important}.s-10>tbody>tr>td{font-size:40px !important;line-height:40px !important;height:40px !important}}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
|
||||
<table class="bg-light body" valign="top" role="presentation" border="0" cellpadding="0" cellspacing="0" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top" style="line-height: 24px; font-size: 16px; margin: 0;" align="left" bgcolor="#f7fafc">
|
||||
<table class="container" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="line-height: 24px; font-size: 16px; margin: 0; padding: 0 16px;">
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" role="presentation">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="600">
|
||||
<![endif]-->
|
||||
<table align="center" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%; max-width: 600px; margin: 0 auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
|
||||
<table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="ax-center" role="presentation" align="center" border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
|
||||
<img class="w-24" src="https://app.revolt.chat/assets/logo_round.png" style="height: auto; line-height: 100%; outline: none; text-decoration: none; display: block; width: 96px; border-style: none; border-width: 0;" width="96">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="card p-6 p-lg-10 space-y-4" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; width: 100%; overflow: hidden; border: 1px solid #e2e8f0;" bgcolor="#ffffff">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 16px; width: 100%; margin: 0; padding: 40px;" align="left" bgcolor="#ffffff">
|
||||
<h1 class="h3 fw-700" style="padding-top: 0; padding-bottom: 0; font-weight: 700 !important; vertical-align: baseline; font-size: 28px; line-height: 33.6px; margin: 0;" align="left">Password Reset</h1>
|
||||
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="" style="line-height: 24px; font-size: 16px; width: 100%; margin: 0;" align="left">
|
||||
You tried to create a new account with or try to re-verify this email
|
||||
but there is already an existing verified account under this email.
|
||||
</p>
|
||||
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="" style="line-height: 24px; font-size: 16px; width: 100%; margin: 0;" align="left">
|
||||
If you wish, you can now proceed to reset the password on it, click
|
||||
below to continue.
|
||||
</p>
|
||||
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="btn btn-primary p-3 fw-700" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; font-weight: 700 !important;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 16px; border-radius: 6px; font-weight: 700 !important; margin: 0;" align="center" bgcolor="#0d6efd">
|
||||
<a href="{{url}}" style="color: #ffffff; font-size: 16px; font-family: Helvetica, Arial, sans-serif; text-decoration: none; border-radius: 6px; line-height: 20px; display: block; font-weight: 700 !important; white-space: nowrap; background-color: #0d6efd; padding: 12px; border: 1px solid #0d6efd;">Reset</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="text-muted text-center" style="color: #718096;" align="center">
|
||||
This email is intended for {{email}}<br>
|
||||
Sent from Revolt<br>
|
||||
Made in Europe
|
||||
</div>
|
||||
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="ax-center" role="presentation" align="center" border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
|
||||
<div class="text-muted text-xs" style="color: #718096; font-size: 12px; line-height: 14.4px;">
|
||||
Revolt Platforms Ltd. is a company incorporated and registered under the
|
||||
laws of England and Wales.<br>
|
||||
Registered Company Number: 16260658<br>
|
||||
Registered Office:<br>
|
||||
Suite 5703 Unit 3A, 34-35 Hatton Garden,<br>
|
||||
Holborn, United Kingdom, EC1N 8DX
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
|
||||
 
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,41 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<style>
|
||||
/* Add custom classes and styles that you want inlined here */
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container">
|
||||
<img
|
||||
class="ax-center my-10 w-24"
|
||||
src="https://app.revolt.chat/assets/logo_round.png"
|
||||
/>
|
||||
<div class="card p-6 p-lg-10 space-y-4">
|
||||
<h1 class="h3 fw-700">Password Reset</h1>
|
||||
<p>
|
||||
You tried to create a new account with or try to re-verify this email
|
||||
but there is already an existing verified account under this email.
|
||||
</p>
|
||||
<p>
|
||||
If you wish, you can now proceed to reset the password on it, click
|
||||
below to continue.
|
||||
</p>
|
||||
<a class="btn btn-primary p-3 fw-700" href="{{url}}">Reset</a>
|
||||
</div>
|
||||
<div class="text-muted text-center my-6">
|
||||
This email is intended for {{email}}<br />
|
||||
Sent from Revolt<br />
|
||||
Made in Europe
|
||||
</div>
|
||||
<div class="text-muted text-xs my-6 ax-center">
|
||||
Revolt Platforms Ltd. is a company incorporated and registered under the
|
||||
laws of England and Wales.<br />
|
||||
Registered Company Number: 16260658<br />
|
||||
Registered Office:<br />
|
||||
Suite 5703 Unit 3A, 34-35 Hatton Garden,<br />
|
||||
Holborn, United Kingdom, EC1N 8DX
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
You tried to create a new account with or try
|
||||
to re-verify this email but there is already
|
||||
an existing verified account under this email.
|
||||
|
||||
If you wish, you can now proceed to reset the
|
||||
password on it, click below to continue.
|
||||
|
||||
Please navigate to: {{url}}
|
||||
|
||||
This email is intended for {{email}}
|
||||
Sent by Revolt
|
||||
Made in Europe
|
||||
|
||||
Revolt Platforms Ltd. is a company incorporated and registered under the laws of England and Wales.
|
||||
|
||||
Registration Number: 16260658
|
||||
Registered Office:
|
||||
Suite 5703 Unit 3A, 34-35 Hatton Garden,
|
||||
Holborn, United Kingdom, EC1N 8DX
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-files"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -20,10 +20,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.8.4", path = "../config", features = [
|
||||
revolt-config = { version = "0.8.5", path = "../config", features = [
|
||||
"report-macros",
|
||||
] }
|
||||
revolt-result = { version = "0.8.4", path = "../result" }
|
||||
revolt-result = { version = "0.8.5", path = "../result" }
|
||||
|
||||
# image processing
|
||||
jxl-oxide = "0.8.1"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-models"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -20,8 +20,8 @@ default = ["serde", "partials", "rocket"]
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-config = { version = "0.8.4", path = "../config" }
|
||||
revolt-permissions = { version = "0.8.4", path = "../permissions" }
|
||||
revolt-config = { version = "0.8.5", path = "../config" }
|
||||
revolt-permissions = { version = "0.8.5", path = "../permissions" }
|
||||
|
||||
# Utility
|
||||
regex = "1.11"
|
||||
|
||||
@@ -101,10 +101,6 @@ auto_derived!(
|
||||
)]
|
||||
role_permissions: HashMap<String, OverrideField>,
|
||||
|
||||
/// Category the channel is in
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
parent: Option<String>,
|
||||
|
||||
/// Whether this channel is marked as not safe for work
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
@@ -142,10 +138,6 @@ auto_derived!(
|
||||
)]
|
||||
role_permissions: HashMap<String, OverrideField>,
|
||||
|
||||
/// Category the channel is in
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
parent: Option<String>,
|
||||
|
||||
/// Whether this channel is marked as not safe for work
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
@@ -178,8 +170,6 @@ auto_derived!(
|
||||
pub default_permissions: Option<OverrideField>,
|
||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub last_message_id: Option<String>,
|
||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub parent: Option<String>
|
||||
}
|
||||
|
||||
/// Optional fields on channel object
|
||||
|
||||
@@ -28,8 +28,8 @@ auto_derived_partial!(
|
||||
// TODO: investigate if this is redundant and can be removed
|
||||
pub channels: Vec<String>,
|
||||
/// Categories for this server
|
||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "HashMap::is_empty"))]
|
||||
pub categories: HashMap<String, Category>,
|
||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub categories: Option<Vec<Category>>,
|
||||
/// Configuration for sending system event messages
|
||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub system_messages: Option<SystemMessageChannels>,
|
||||
@@ -126,52 +126,15 @@ auto_derived!(
|
||||
#[cfg_attr(feature = "validator", derive(Validate))]
|
||||
pub struct Category {
|
||||
/// Unique ID for this category
|
||||
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))]
|
||||
pub id: String,
|
||||
/// Title for this category
|
||||
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))]
|
||||
pub title: String,
|
||||
/// Default permissions assigned to users in this channel
|
||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub default_permissions: Option<OverrideField>,
|
||||
/// Permissions assigned based on role to this channel
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
default = "HashMap::<String, OverrideField>::new",
|
||||
skip_serializing_if = "HashMap::<String, OverrideField>::is_empty"
|
||||
)
|
||||
)]
|
||||
pub role_permissions: HashMap<String, OverrideField>,
|
||||
/// Channels in this category
|
||||
pub channels: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "validator", derive(Validate))]
|
||||
pub struct DataCreateCategory {
|
||||
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))]
|
||||
pub title: String,
|
||||
/// Channels in this category
|
||||
pub channels: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "validator", derive(Validate))]
|
||||
pub struct DataEditCategory {
|
||||
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))]
|
||||
pub title: Option<String>,
|
||||
/// Channels in this category
|
||||
pub channels: Option<Vec<String>>,
|
||||
/// Fields to remove from category object
|
||||
pub remove: Option<Vec<FieldsCategory>>,
|
||||
}
|
||||
|
||||
pub enum FieldsCategory {
|
||||
DefaultPermissions
|
||||
}
|
||||
|
||||
pub struct DataDefaultCategoryPermissions {
|
||||
pub permissions: Override
|
||||
}
|
||||
|
||||
/// System message channel assignments
|
||||
pub struct SystemMessageChannels {
|
||||
/// ID of channel to send user join messages in
|
||||
@@ -263,6 +226,10 @@ auto_derived!(
|
||||
pub icon: Option<String>,
|
||||
/// Attachment Id for banner
|
||||
pub banner: Option<String>,
|
||||
|
||||
/// Category structure for server
|
||||
#[cfg_attr(feature = "validator", validate)]
|
||||
pub categories: Option<Vec<Category>>,
|
||||
/// System message configuration
|
||||
pub system_messages: Option<SystemMessageChannels>,
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "revolt-parser"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
logos = { version = "*" }
|
||||
logos = { version = "*" }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-permissions"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
@@ -21,7 +21,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-result = { version = "0.8.4", path = "../result" }
|
||||
revolt-result = { version = "0.8.5", path = "../result" }
|
||||
|
||||
# Utility
|
||||
auto_ops = "0.3.0"
|
||||
|
||||
@@ -68,26 +68,6 @@ pub async fn calculate_server_permissions<P: PermissionQuery>(query: &mut P) ->
|
||||
permissions
|
||||
}
|
||||
|
||||
pub async fn calculate_category_permissions<P: PermissionQuery>(query: &mut P) -> PermissionValue {
|
||||
let mut permissions = calculate_server_permissions(query).await;
|
||||
|
||||
permissions.apply(query.get_default_category_permissions().await);
|
||||
|
||||
for role_override in query.get_our_category_role_overrides().await {
|
||||
permissions.apply(role_override)
|
||||
}
|
||||
|
||||
if !permissions.has_channel_permission(ChannelPermission::ViewChannel) {
|
||||
permissions.revoke_all();
|
||||
}
|
||||
|
||||
if query.are_we_timed_out().await {
|
||||
permissions.restrict(*ALLOW_IN_TIMEOUT);
|
||||
}
|
||||
|
||||
permissions
|
||||
}
|
||||
|
||||
/// Calculate permissions against a channel
|
||||
pub async fn calculate_channel_permissions<P: PermissionQuery>(query: &mut P) -> PermissionValue {
|
||||
if query.are_we_privileged().await {
|
||||
@@ -129,19 +109,11 @@ pub async fn calculate_channel_permissions<P: PermissionQuery>(query: &mut P) ->
|
||||
}
|
||||
ChannelType::ServerChannel => {
|
||||
query.set_server_from_channel().await;
|
||||
query.set_category_from_channel().await;
|
||||
|
||||
if query.are_we_server_owner().await {
|
||||
ChannelPermission::GrantAllSafe.into()
|
||||
} else if query.are_we_a_member().await {
|
||||
let mut permissions = calculate_server_permissions(query).await;
|
||||
|
||||
permissions.apply(query.get_default_category_permissions().await);
|
||||
|
||||
for role_override in query.get_our_category_role_overrides().await {
|
||||
permissions.apply(role_override)
|
||||
}
|
||||
|
||||
permissions.apply(query.get_default_channel_permissions().await);
|
||||
|
||||
for role_override in query.get_our_channel_role_overrides().await {
|
||||
@@ -163,4 +135,4 @@ pub async fn calculate_channel_permissions<P: PermissionQuery>(query: &mut P) ->
|
||||
}
|
||||
ChannelType::Unknown => 0_u64.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,10 +96,8 @@ pub enum ChannelPermission {
|
||||
/// Mention roles
|
||||
MentionRoles = 1 << 38,
|
||||
|
||||
MoveChannels = 1 << 39,
|
||||
|
||||
// * Misc. permissions
|
||||
// % Bits 40 to 52: free area
|
||||
// % Bits 38 to 52: free area
|
||||
// % Bits 53 to 64: do not use
|
||||
|
||||
// * Grant all permissions
|
||||
|
||||
@@ -91,18 +91,6 @@ async fn validate_user_permissions() {
|
||||
async fn set_server_from_channel(&mut self) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn get_default_category_permissions(&mut self) -> Override {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn get_our_category_role_overrides(&mut self) -> Vec<Override> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn set_category_from_channel(&mut self) {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,18 +183,6 @@ async fn validate_group_permissions() {
|
||||
async fn set_server_from_channel(&mut self) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn get_default_category_permissions(&mut self) -> Override {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn get_our_category_role_overrides(&mut self) -> Vec<Override> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn set_category_from_channel(&mut self) {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,18 +287,6 @@ async fn validate_server_permissions() {
|
||||
async fn set_server_from_channel(&mut self) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
async fn get_default_category_permissions(&mut self) -> Override {
|
||||
Override { allow: 0, deny: 0 }
|
||||
}
|
||||
|
||||
async fn get_our_category_role_overrides(&mut self) -> Vec<Override> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
async fn set_category_from_channel(&mut self) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,126 +373,5 @@ async fn validate_timed_out_member() {
|
||||
async fn set_server_from_channel(&mut self) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
async fn get_default_category_permissions(&mut self) -> Override {
|
||||
Override { allow: 0, deny: 0 }
|
||||
}
|
||||
|
||||
async fn get_our_category_role_overrides(&mut self) -> Vec<Override> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
async fn set_category_from_channel(&mut self) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn validate_category_permissions() {
|
||||
/// Scenario in which we are in a channel in a server and has a role
|
||||
/// Server defaults let us send messages, view channels
|
||||
/// Category default denies sending, allows reacting
|
||||
/// Category role allows sending message
|
||||
struct Scenario {}
|
||||
let mut query = Scenario {};
|
||||
|
||||
let perms = calculate_channel_permissions(&mut query).await;
|
||||
let value: u64 = perms.into();
|
||||
assert_eq!(value, ChannelPermission::ViewChannel as u64 | ChannelPermission::React as u64 | ChannelPermission::SendMessage as u64);
|
||||
|
||||
#[async_trait]
|
||||
impl PermissionQuery for Scenario {
|
||||
async fn are_we_privileged(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
async fn are_we_a_bot(&mut self) -> bool {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn are_the_users_same(&mut self) -> bool {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn user_relationship(&mut self) -> RelationshipStatus {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn user_is_bot(&mut self) -> bool {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn have_mutual_connection(&mut self) -> bool {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn are_we_server_owner(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
async fn are_we_a_member(&mut self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
async fn get_default_server_permissions(&mut self) -> u64 {
|
||||
ChannelPermission::SendMessage as u64 | ChannelPermission::ViewChannel as u64
|
||||
}
|
||||
|
||||
async fn get_our_server_role_overrides(&mut self) -> Vec<Override> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
async fn are_we_timed_out(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
async fn get_channel_type(&mut self) -> ChannelType {
|
||||
ChannelType::ServerChannel
|
||||
}
|
||||
|
||||
async fn get_default_channel_permissions(&mut self) -> Override {
|
||||
Override { allow: 0, deny: 0 }
|
||||
}
|
||||
|
||||
async fn get_our_channel_role_overrides(&mut self) -> Vec<Override> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
async fn do_we_own_the_channel(&mut self) -> bool {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn are_we_part_of_the_channel(&mut self) -> bool {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn set_recipient_as_user(&mut self) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn set_server_from_channel(&mut self) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
async fn get_default_category_permissions(&mut self) -> Override {
|
||||
Override {
|
||||
allow: ChannelPermission::React as u64,
|
||||
deny: ChannelPermission::SendMessage as u64
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_our_category_role_overrides(&mut self) -> Vec<Override> {
|
||||
vec![
|
||||
Override {
|
||||
allow: ChannelPermission::SendMessage as u64,
|
||||
deny: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async fn set_category_from_channel(&mut self) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,12 +51,6 @@ pub trait PermissionQuery {
|
||||
/// Get the ordered role overrides (from lowest to highest) for this member in this channel
|
||||
async fn get_our_channel_role_overrides(&mut self) -> Vec<Override>;
|
||||
|
||||
/// Get the default category permissions
|
||||
async fn get_default_category_permissions(&mut self) -> Override;
|
||||
|
||||
/// Get the ordered role overrides (from lowest to highest) for this member in this category
|
||||
async fn get_our_category_role_overrides(&mut self) -> Vec<Override>;
|
||||
|
||||
/// Do we own this group or saved messages channel if it is one of those?
|
||||
async fn do_we_own_the_channel(&mut self) -> bool;
|
||||
|
||||
@@ -70,7 +64,4 @@ pub trait PermissionQuery {
|
||||
/// Set the current server as the server owning this channel
|
||||
/// (this will only ever be called for server channels, use unimplemented!() for other code paths)
|
||||
async fn set_server_from_channel(&mut self);
|
||||
|
||||
//// SEts the current category as the category the channel is in
|
||||
async fn set_category_from_channel(&mut self);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-presence"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-result"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
|
||||
@@ -42,14 +42,12 @@ impl IntoResponse for Error {
|
||||
ErrorType::Banned => StatusCode::FORBIDDEN,
|
||||
ErrorType::AlreadyInServer => StatusCode::CONFLICT,
|
||||
ErrorType::CannotTimeoutYourself => StatusCode::BAD_REQUEST,
|
||||
ErrorType::UnknownCategory => StatusCode::NOT_FOUND,
|
||||
|
||||
ErrorType::TooManyServers { .. } => StatusCode::BAD_REQUEST,
|
||||
ErrorType::TooManyEmbeds { .. } => StatusCode::BAD_REQUEST,
|
||||
ErrorType::TooManyEmoji { .. } => StatusCode::BAD_REQUEST,
|
||||
ErrorType::TooManyChannels { .. } => StatusCode::BAD_REQUEST,
|
||||
ErrorType::TooManyRoles { .. } => StatusCode::BAD_REQUEST,
|
||||
ErrorType::TooManyCategories { .. } => StatusCode::BAD_REQUEST,
|
||||
|
||||
ErrorType::ReachedMaximumBots => StatusCode::BAD_REQUEST,
|
||||
ErrorType::IsBot => StatusCode::BAD_REQUEST,
|
||||
|
||||
@@ -115,10 +115,6 @@ pub enum ErrorType {
|
||||
TooManyRoles {
|
||||
max: usize,
|
||||
},
|
||||
TooManyCategories {
|
||||
max: usize,
|
||||
},
|
||||
UnknownCategory,
|
||||
AlreadyInServer,
|
||||
CannotTimeoutYourself,
|
||||
|
||||
|
||||
@@ -49,14 +49,12 @@ impl<'r> Responder<'r, 'static> for Error {
|
||||
ErrorType::Banned => Status::Forbidden,
|
||||
ErrorType::AlreadyInServer => Status::Conflict,
|
||||
ErrorType::CannotTimeoutYourself => Status::BadRequest,
|
||||
ErrorType::UnknownCategory => Status::NotFound,
|
||||
|
||||
|
||||
ErrorType::TooManyServers { .. } => Status::BadRequest,
|
||||
ErrorType::TooManyEmbeds { .. } => Status::BadRequest,
|
||||
ErrorType::TooManyEmoji { .. } => Status::BadRequest,
|
||||
ErrorType::TooManyChannels { .. } => Status::BadRequest,
|
||||
ErrorType::TooManyRoles { .. } => Status::BadRequest,
|
||||
ErrorType::TooManyCategories { .. } => Status::BadRequest,
|
||||
|
||||
ErrorType::ReachedMaximumBots => Status::BadRequest,
|
||||
ErrorType::IsBot => Status::BadRequest,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-crond"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <me@insrt.uk>"]
|
||||
edition = "2021"
|
||||
@@ -16,7 +16,7 @@ log = "0.4"
|
||||
tokio = { version = "1" }
|
||||
|
||||
# Core
|
||||
revolt-database = { version = "0.8.4", path = "../../core/database" }
|
||||
revolt-result = { version = "0.8.4", path = "../../core/result" }
|
||||
revolt-config = { version = "0.8.4", path = "../../core/config" }
|
||||
revolt-files = { version = "0.8.4", path = "../../core/files" }
|
||||
revolt-database = { version = "0.8.5", path = "../../core/database" }
|
||||
revolt-result = { version = "0.8.5", path = "../../core/result" }
|
||||
revolt-config = { version = "0.8.5", path = "../../core/config" }
|
||||
revolt-files = { version = "0.8.5", path = "../../core/files" }
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
[package]
|
||||
name = "revolt-pushd"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
||||
[dependencies]
|
||||
revolt-config = { version = "0.8.4", path = "../../core/config" }
|
||||
revolt-database = { version = "0.8.4", path = "../../core/database" }
|
||||
revolt-models = { version = "0.8.4", path = "../../core/models", features = [
|
||||
revolt-config = { version = "0.8.5", path = "../../core/config" }
|
||||
revolt-database = { version = "0.8.5", path = "../../core/database" }
|
||||
revolt-models = { version = "0.8.5", path = "../../core/models", features = [
|
||||
"validator",
|
||||
] }
|
||||
revolt-presence = { version = "0.8.1", path = "../../core/presence", features = [
|
||||
revolt-presence = { version = "0.8.5", path = "../../core/presence", features = [
|
||||
"redis-is-patched",
|
||||
] }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-delta"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
||||
edition = "2018"
|
||||
@@ -52,10 +52,11 @@ async-std = { version = "1.8.0", features = [
|
||||
lettre = "0.10.0-alpha.4"
|
||||
|
||||
# web
|
||||
|
||||
rocket = { version = "0.5.1", default-features = false, features = ["json"] }
|
||||
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "072d90359b23e9b291df6b672c07c93de9c46011" }
|
||||
rocket_empty = { version = "0.1.1", features = ["schema"] }
|
||||
rocket_authifier = { version = "1.0.10" }
|
||||
rocket_authifier = { version = "1.0.13" }
|
||||
rocket_prometheus = "0.10.0-rc.3"
|
||||
|
||||
# spec generation
|
||||
@@ -66,7 +67,7 @@ revolt_rocket_okapi = { version = "0.10.0", features = ["swagger"] }
|
||||
amqprs = { version = "1.7.0" }
|
||||
|
||||
# core
|
||||
authifier = "1.0.10"
|
||||
authifier = "1.0.13"
|
||||
revolt-config = { path = "../core/config" }
|
||||
revolt-database = { path = "../core/database", features = [
|
||||
"rocket-impl",
|
||||
|
||||
@@ -192,7 +192,6 @@ mod test {
|
||||
d: ChannelPermission::ViewChannel as i64,
|
||||
}),
|
||||
last_message_id: None,
|
||||
parent: None,
|
||||
};
|
||||
locked_channel
|
||||
.update(&harness.db, partial, vec![])
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, Category, Database, Role, User
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
|
||||
/// # Create a category
|
||||
///
|
||||
/// Creates a new server category.
|
||||
#[openapi(tag = "Server Categories")]
|
||||
#[post("/<target>/categories", data = "<data>")]
|
||||
pub async fn create(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
data: Json<v0::DataCreateCategory>,
|
||||
) -> Result<Json<v0::Category>> {
|
||||
let data = data.into_inner();
|
||||
data.validate().map_err(|error| {
|
||||
create_error!(FailedValidation {
|
||||
error: error.to_string()
|
||||
})
|
||||
})?;
|
||||
|
||||
let mut server = target.as_server(db).await?;
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).server(&server);
|
||||
calculate_server_permissions(&mut query)
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?;
|
||||
|
||||
let config = config().await;
|
||||
if server.categories.len() >= config.features.limits.global.server_categories {
|
||||
return Err(create_error!(TooManyCategories {
|
||||
max: config.features.limits.global.server_categories,
|
||||
}));
|
||||
};
|
||||
|
||||
let category = Category::create(db, &mut server, data).await?;
|
||||
|
||||
Ok(Json(category.into()))
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, Category, Database, PartialCategory, Role, User
|
||||
};
|
||||
use revolt_models::v0::{self, DataEditCategory};
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use rocket_empty::EmptyResponse;
|
||||
use validator::Validate;
|
||||
|
||||
/// # Edits a category
|
||||
///
|
||||
/// Edits a server category.
|
||||
#[openapi(tag = "Server Categories")]
|
||||
#[delete("/<server>/categories/<category>")]
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
server: Reference,
|
||||
category: String
|
||||
) -> Result<EmptyResponse> {
|
||||
let mut server = server.as_server(db).await?;
|
||||
|
||||
let category = server.categories
|
||||
.get(&category)
|
||||
.ok_or(create_error!(UnknownCategory))?
|
||||
.clone();
|
||||
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).server(&server);
|
||||
calculate_server_permissions(&mut query)
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?;
|
||||
|
||||
category.delete(db, &mut server).await?;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, Category, Channel, Database, PartialCategory, PartialChannel, Role, User
|
||||
};
|
||||
use revolt_models::v0::{self, DataEditCategory};
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
|
||||
/// # Edits a category
|
||||
///
|
||||
/// Edits a server category.
|
||||
#[openapi(tag = "Server Categories")]
|
||||
#[patch("/<server>/categories/<category>", data = "<data>")]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
server: Reference,
|
||||
category: String,
|
||||
data: Json<v0::DataEditCategory>,
|
||||
) -> Result<Json<v0::Category>> {
|
||||
let data = data.into_inner();
|
||||
data.validate().map_err(|error| {
|
||||
create_error!(FailedValidation {
|
||||
error: error.to_string()
|
||||
})
|
||||
})?;
|
||||
|
||||
let mut server = server.as_server(db).await?;
|
||||
|
||||
let mut category = server.categories
|
||||
.get(&category)
|
||||
.ok_or(create_error!(UnknownCategory))?
|
||||
.clone();
|
||||
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).server(&server).category(&category);
|
||||
let permissions = calculate_server_permissions(&mut query)
|
||||
.await;
|
||||
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?;
|
||||
|
||||
let DataEditCategory {
|
||||
title,
|
||||
mut channels,
|
||||
remove
|
||||
} = data;
|
||||
|
||||
if channels.is_some() {
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::MoveChannels)?;
|
||||
}
|
||||
|
||||
// if any channel we are adding to this category are in another category we need to make sure we have MoveChannels in the category before moving it over.
|
||||
for category in server.categories.values() {
|
||||
if category.channels.iter().any(|c| channels.as_ref().is_some_and(|cs| cs.contains(c))) {
|
||||
let mut category_query = query.clone().category(category);
|
||||
|
||||
calculate_server_permissions(&mut category_query)
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::MoveChannels)?;
|
||||
}
|
||||
}
|
||||
|
||||
// remove the channels from any existing categories to avoid it having two
|
||||
for category in server.categories.values_mut() {
|
||||
category.channels.retain(|c| channels.as_ref().is_some_and(|cs| cs.contains(c)));
|
||||
}
|
||||
|
||||
// only keep channels which exist in the server
|
||||
if let Some(channels) = &mut channels {
|
||||
channels.retain(|c| server.channels.contains(c));
|
||||
}
|
||||
|
||||
// unset parent from all channels which are removed from the category
|
||||
for channel_id in &category.channels {
|
||||
if channels.as_ref().is_some_and(|cs| !cs.contains(channel_id)) {
|
||||
db.update_channel(channel_id, &PartialChannel { parent: None, ..Default::default() }, Vec::new()).await?;
|
||||
};
|
||||
};
|
||||
|
||||
// update the category with the new values
|
||||
category.update(
|
||||
db,
|
||||
&mut server,
|
||||
PartialCategory {
|
||||
title,
|
||||
channels: channels.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
remove
|
||||
.map(|v| v.into_iter().map(Into::into).collect())
|
||||
.unwrap_or_default()
|
||||
).await?;
|
||||
|
||||
let channels = db.fetch_channels(&channels.unwrap_or_default()).await?;
|
||||
|
||||
// update all channels to have the parent set
|
||||
for channel in channels {
|
||||
if let Channel::TextChannel { ref parent, .. } | Channel::VoiceChannel { ref parent, .. } = channel {
|
||||
if parent.as_ref() != Some(&category.id) {
|
||||
db.update_channel(channel.id(), &PartialChannel { parent: Some(category.id.clone()), ..Default::default() }, Vec::new()).await?;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Ok(Json(category.into()))
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, Database, User
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_category_permissions, ChannelPermission, Override};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Set Role Permission
|
||||
///
|
||||
/// Sets permissions for the specified role in this channel.
|
||||
///
|
||||
/// Channel must be a `TextChannel` or `VoiceChannel`.
|
||||
#[openapi(tag = "Channel Permissions")]
|
||||
#[put("/<server>/categories/<category>/permissions/<role_id>", data = "<data>", rank = 2)]
|
||||
pub async fn set_role_permissions(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
server: Reference,
|
||||
category: String,
|
||||
role_id: String,
|
||||
data: Json<v0::DataSetRolePermissions>,
|
||||
) -> Result<Json<v0::Category>> {
|
||||
let mut server = server.as_server(db).await?;
|
||||
let mut category = server.categories.get(&category).ok_or(create_error!(UnknownCategory))?.clone();
|
||||
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).server(&server).category(&category);
|
||||
let permissions = calculate_category_permissions(&mut query).await;
|
||||
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::ManagePermissions)?;
|
||||
|
||||
if let Some(role) = server.roles.get(&role_id) {
|
||||
if role.rank <= query.get_member_rank().unwrap_or(i64::MIN) {
|
||||
return Err(create_error!(NotElevated));
|
||||
}
|
||||
|
||||
let current_value: Override = role.permissions.into();
|
||||
permissions
|
||||
.throw_permission_override(current_value, &data.permissions)
|
||||
.await?;
|
||||
|
||||
category
|
||||
.set_role_permission(db, &mut server, role_id, data.permissions.clone().into())
|
||||
.await?;
|
||||
|
||||
Ok(Json(category.into()))
|
||||
} else {
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, Channel, Database, PartialCategory, PartialChannel, User
|
||||
};
|
||||
use revolt_models::v0::{self, DataDefaultChannelPermissions};
|
||||
use revolt_permissions::{calculate_category_permissions, calculate_channel_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Set Default Permission
|
||||
///
|
||||
/// Sets permissions for the default role in this channel.
|
||||
///
|
||||
/// Channel must be a `Group`, `TextChannel` or `VoiceChannel`.
|
||||
#[openapi(tag = "Category Permissions")]
|
||||
#[put("/<server>/categories/<target>/permissions/default", data = "<data>", rank = 1)]
|
||||
pub async fn set_default_permissions(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
server: Reference,
|
||||
target: String,
|
||||
data: Json<v0::DataDefaultCategoryPermissions>,
|
||||
) -> Result<Json<v0::Category>> {
|
||||
let data = data.into_inner();
|
||||
|
||||
let mut server = server.as_server(db).await?;
|
||||
let mut category = server.categories.get(&target).ok_or(create_error!(UnknownCategory))?.clone();
|
||||
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).server(&server).category(&category);
|
||||
let permissions = calculate_category_permissions(&mut query).await;
|
||||
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::ManagePermissions)?;
|
||||
|
||||
permissions
|
||||
.throw_permission_override(category.default_permissions.map(|x| x.into()), &data.permissions)
|
||||
.await?;
|
||||
|
||||
category
|
||||
.update(
|
||||
db,
|
||||
&mut server,
|
||||
PartialCategory {
|
||||
default_permissions: Some(data.permissions.into()),
|
||||
..Default::default()
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(category.into()))
|
||||
}
|
||||
@@ -23,11 +23,6 @@ mod server_create;
|
||||
mod server_delete;
|
||||
mod server_edit;
|
||||
mod server_fetch;
|
||||
mod category_create;
|
||||
mod category_edit;
|
||||
mod category_delete;
|
||||
mod category_permissions_set_default;
|
||||
mod category_permissions_set;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
@@ -52,11 +47,6 @@ pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
roles_delete::delete,
|
||||
permissions_set::set_role_permission,
|
||||
permissions_set_default::set_default_permissions,
|
||||
emoji_list::list_emoji,
|
||||
category_create::create,
|
||||
category_edit::edit,
|
||||
category_delete::delete,
|
||||
category_permissions_set_default::set_default_permissions,
|
||||
category_permissions_set::set_role_permissions,
|
||||
emoji_list::list_emoji
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
@@ -38,6 +38,7 @@ pub async fn edit(
|
||||
&& data.icon.is_none()
|
||||
&& data.banner.is_none()
|
||||
&& data.system_messages.is_none()
|
||||
&& data.categories.is_none()
|
||||
// && data.nsfw.is_none()
|
||||
&& data.flags.is_none()
|
||||
&& data.analytics.is_none()
|
||||
@@ -62,11 +63,18 @@ pub async fn edit(
|
||||
{
|
||||
return Err(create_error!(NotPrivileged));
|
||||
}
|
||||
|
||||
// Changing categories requires manage channel
|
||||
if data.categories.is_some() {
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?;
|
||||
}
|
||||
|
||||
let v0::DataEditServer {
|
||||
name,
|
||||
description,
|
||||
icon,
|
||||
banner,
|
||||
categories,
|
||||
system_messages,
|
||||
flags,
|
||||
// nsfw,
|
||||
@@ -78,6 +86,7 @@ pub async fn edit(
|
||||
let mut partial = PartialServer {
|
||||
name,
|
||||
description,
|
||||
categories: categories.map(|v| v.into_iter().map(Into::into).collect()),
|
||||
system_messages: system_messages.map(Into::into),
|
||||
flags,
|
||||
// nsfw,
|
||||
@@ -110,6 +119,23 @@ pub async fn edit(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(categories) = &mut partial.categories {
|
||||
let mut channel_ids = HashSet::new();
|
||||
for category in categories {
|
||||
for channel in &category.channels {
|
||||
if channel_ids.contains(channel) {
|
||||
return Err(create_error!(InvalidOperation));
|
||||
}
|
||||
|
||||
channel_ids.insert(channel.to_string());
|
||||
}
|
||||
|
||||
category
|
||||
.channels
|
||||
.retain(|item| server.channels.contains(item));
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Apply new icon
|
||||
if let Some(icon) = icon {
|
||||
partial.icon = Some(File::use_server_icon(db, &icon, &server.id, &user.id).await?);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-autumn"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
||||
@@ -43,12 +43,12 @@ tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
# Core crates
|
||||
revolt-files = { version = "0.8.4", path = "../../core/files" }
|
||||
revolt-config = { version = "0.8.4", path = "../../core/config" }
|
||||
revolt-database = { version = "0.8.4", path = "../../core/database", features = [
|
||||
revolt-files = { version = "0.8.5", path = "../../core/files" }
|
||||
revolt-config = { version = "0.8.5", path = "../../core/config" }
|
||||
revolt-database = { version = "0.8.5", path = "../../core/database", features = [
|
||||
"axum-impl",
|
||||
] }
|
||||
revolt-result = { version = "0.8.4", path = "../../core/result", features = [
|
||||
revolt-result = { version = "0.8.5", path = "../../core/result", features = [
|
||||
"utoipa",
|
||||
"axum",
|
||||
] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-january"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
||||
@@ -32,13 +32,13 @@ tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
# Core crates
|
||||
revolt-config = { version = "0.8.4", path = "../../core/config" }
|
||||
revolt-models = { version = "0.8.4", path = "../../core/models" }
|
||||
revolt-result = { version = "0.8.4", path = "../../core/result", features = [
|
||||
revolt-config = { version = "0.8.5", path = "../../core/config" }
|
||||
revolt-models = { version = "0.8.5", path = "../../core/models" }
|
||||
revolt-result = { version = "0.8.5", path = "../../core/result", features = [
|
||||
"utoipa",
|
||||
"axum",
|
||||
] }
|
||||
revolt-files = { version = "0.8.4", path = "../../core/files" }
|
||||
revolt-files = { version = "0.8.5", path = "../../core/files" }
|
||||
|
||||
# Axum / web server
|
||||
axum = { version = "0.7.5" }
|
||||
|
||||
@@ -22,13 +22,13 @@ tools() {
|
||||
|
||||
deps() {
|
||||
mkdir -p \
|
||||
crates/bindings/node/src \
|
||||
crates/bonfire/src \
|
||||
crates/delta/src \
|
||||
crates/core/config/src \
|
||||
crates/core/database/src \
|
||||
crates/core/files/src \
|
||||
crates/core/models/src \
|
||||
crates/core/parser/src \
|
||||
crates/core/permissions/src \
|
||||
crates/core/presence/src \
|
||||
crates/core/result/src \
|
||||
@@ -44,19 +44,19 @@ deps() {
|
||||
tee crates/daemons/crond/src/main.rs |
|
||||
tee crates/daemons/pushd/src/main.rs
|
||||
echo '' |
|
||||
tee crates/bindings/node/src/lib.rs |
|
||||
tee crates/core/config/src/lib.rs |
|
||||
tee crates/core/database/src/lib.rs |
|
||||
tee crates/core/files/src/lib.rs |
|
||||
tee crates/core/models/src/lib.rs |
|
||||
tee crates/core/parser/src/lib.rs |
|
||||
tee crates/core/permissions/src/lib.rs |
|
||||
tee crates/core/presence/src/lib.rs |
|
||||
tee crates/core/result/src/lib.rs
|
||||
|
||||
if [ -z "$TARGETARCH" ]; then
|
||||
cargo build --locked --release
|
||||
cargo build -j 10 --locked --release
|
||||
else
|
||||
cargo build --locked --release --target "${BUILD_TARGET}"
|
||||
cargo build -j 10 --locked --release --target "${BUILD_TARGET}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -69,14 +69,15 @@ apps() {
|
||||
crates/core/config/src/lib.rs \
|
||||
crates/core/database/src/lib.rs \
|
||||
crates/core/models/src/lib.rs \
|
||||
crates/core/parser/src/lib.rs \
|
||||
crates/core/permissions/src/lib.rs \
|
||||
crates/core/presence/src/lib.rs \
|
||||
crates/core/result/src/lib.rs
|
||||
|
||||
if [ -z "$TARGETARCH" ]; then
|
||||
cargo build --locked --release
|
||||
cargo build -j 10 --locked --release
|
||||
else
|
||||
cargo build --locked --release --target "${BUILD_TARGET}"
|
||||
cargo build -j 10 --locked --release --target "${BUILD_TARGET}"
|
||||
mv target _target && mv _target/"${BUILD_TARGET}" target
|
||||
fi
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user