Merge branch 'develop' into 'main'
release: v20240728 Co-authored-by: 老周部落 <laozhoubuluo@gmail.com> Co-authored-by: GitLab CI <project_7_bot_1bfaee5701aed20091a86249a967a6c1@noreply.firefish.dev> See merge request firefish/firefish!11211
This commit is contained in:
commit
22b89fe3bd
185 changed files with 2004 additions and 1823 deletions
|
@ -40,6 +40,7 @@ packages/backend/assets/instance.css
|
||||||
.gitattributes
|
.gitattributes
|
||||||
.weblate
|
.weblate
|
||||||
animated.svg
|
animated.svg
|
||||||
|
compose.yml
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
docker-compose.example.yml
|
docker-compose.example.yml
|
||||||
title.svg
|
title.svg
|
||||||
|
@ -48,6 +49,7 @@ title.svg
|
||||||
/dev
|
/dev
|
||||||
/docs
|
/docs
|
||||||
/scripts
|
/scripts
|
||||||
|
!/scripts/copy-index.mjs
|
||||||
!/scripts/copy-assets.mjs
|
!/scripts/copy-assets.mjs
|
||||||
biome.json
|
biome.json
|
||||||
CODE_OF_CONDUCT.md
|
CODE_OF_CONDUCT.md
|
||||||
|
|
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
|
@ -15,7 +15,7 @@
|
||||||
"biomejs.biome",
|
"biomejs.biome",
|
||||||
"rust-lang.rust-analyzer",
|
"rust-lang.rust-analyzer",
|
||||||
"vadimcn.vscode-lldb",
|
"vadimcn.vscode-lldb",
|
||||||
"serayuzgur.crates",
|
"fill-labs.dependi",
|
||||||
"tamasfe.even-better-toml",
|
"tamasfe.even-better-toml",
|
||||||
"aaron-bond.better-comments"
|
"aaron-bond.better-comments"
|
||||||
]
|
]
|
||||||
|
|
63
Cargo.lock
generated
63
Cargo.lock
generated
|
@ -84,6 +84,12 @@ version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
|
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arc-swap"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arg_enum_proc_macro"
|
name = "arg_enum_proc_macro"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
|
@ -871,9 +877,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "emojis"
|
name = "emojis"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f619a926616ae7149a0d82610b051134a0d6c4ae2962d990c06c847a445c5d9"
|
checksum = "e72f23d65b46527e461b161ab9a126c378aa2249d8a8d15718d23ab1fb4d8786"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf",
|
"phf",
|
||||||
]
|
]
|
||||||
|
@ -1576,9 +1582,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.31"
|
version = "0.1.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
|
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
@ -1768,6 +1774,8 @@ dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"syn 2.0.72",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1919,14 +1927,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom-exif"
|
name = "nom-exif"
|
||||||
version = "1.2.6"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dac386e49252f313c88764101ca16681caa4a5b0260d494d58b6af7f04edd3a"
|
checksum = "ab35c38930e837f191de96c6f23e8dee7547916fbae0ce25e4d5fad405bbc2d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"nom",
|
"nom",
|
||||||
"regex",
|
"regex",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2073,9 +2082,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.36.1"
|
version = "0.36.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
|
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -2621,15 +2630,17 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redis"
|
name = "redis"
|
||||||
version = "0.25.4"
|
version = "0.26.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0d7a6955c7511f60f3ba9e86c6d02b3c3f144f8c24b288d1f4e18074ab8bbec"
|
checksum = "8cc5b667390cb038bc65fc4b18c06e2550469f7e06a02d886f1a018a11f63563"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
"combine",
|
"combine",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"num-bigint",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
@ -3021,9 +3032,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.6"
|
version = "0.6.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
|
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -3676,9 +3687,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.39.1"
|
version = "1.39.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a"
|
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -3741,9 +3752,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
|
checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
|
@ -3753,18 +3764,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.6"
|
version = "0.6.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
|
checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.16"
|
version = "0.22.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -3975,9 +3986,9 @@ checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waker-fn"
|
name = "waker-fn"
|
||||||
|
@ -4285,9 +4296,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.6.14"
|
version = "0.6.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "374ec40a2d767a3c1b4972d9475ecd557356637be906f2cb3f7fe17a6eb5e22f"
|
checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -4461,9 +4472,9 @@ checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-jpeg"
|
name = "zune-jpeg"
|
||||||
version = "0.4.11"
|
version = "0.4.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448"
|
checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zune-core",
|
"zune-core",
|
||||||
]
|
]
|
||||||
|
|
|
@ -22,17 +22,17 @@ bcrypt = { version = "0.15.1", default-features = false }
|
||||||
chrono = { version = "0.4.38", default-features = false }
|
chrono = { version = "0.4.38", default-features = false }
|
||||||
convert_case = { version = "0.6.0", default-features = false }
|
convert_case = { version = "0.6.0", default-features = false }
|
||||||
cuid2 = { version = "0.1.2", default-features = false }
|
cuid2 = { version = "0.1.2", default-features = false }
|
||||||
emojis = { version = "0.6.2", default-features = false }
|
emojis = { version = "0.6.3", default-features = false }
|
||||||
idna = { version = "1.0.2", default-features = false }
|
idna = { version = "1.0.2", default-features = false }
|
||||||
image = { version = "0.25.2", default-features = false }
|
image = { version = "0.25.2", default-features = false }
|
||||||
isahc = { version = "1.7.2", default-features = false }
|
isahc = { version = "1.7.2", default-features = false }
|
||||||
nom-exif = { version = "1.2.6", default-features = false }
|
nom-exif = { version = "1.3.0", default-features = false }
|
||||||
once_cell = { version = "1.19.0", default-features = false }
|
once_cell = { version = "1.19.0", default-features = false }
|
||||||
pretty_assertions = { version = "1.4.0", default-features = false }
|
pretty_assertions = { version = "1.4.0", default-features = false }
|
||||||
proc-macro2 = { version = "1.0.86", default-features = false }
|
proc-macro2 = { version = "1.0.86", default-features = false }
|
||||||
quote = { version = "1.0.36", default-features = false }
|
quote = { version = "1.0.36", default-features = false }
|
||||||
rand = { version = "0.8.5", default-features = false }
|
rand = { version = "0.8.5", default-features = false }
|
||||||
redis = { version = "0.25.4", default-features = false }
|
redis = { version = "0.26.0", default-features = false }
|
||||||
regex = { version = "1.10.5", default-features = false }
|
regex = { version = "1.10.5", default-features = false }
|
||||||
rmp-serde = { version = "1.3.0", default-features = false }
|
rmp-serde = { version = "1.3.0", default-features = false }
|
||||||
sea-orm = { version = "0.12.15", default-features = false }
|
sea-orm = { version = "0.12.15", default-features = false }
|
||||||
|
@ -42,7 +42,7 @@ serde_yaml = { version = "0.9.34", default-features = false }
|
||||||
syn = { version = "2.0.72", default-features = false }
|
syn = { version = "2.0.72", default-features = false }
|
||||||
sysinfo = { version = "0.30.13", default-features = false }
|
sysinfo = { version = "0.30.13", default-features = false }
|
||||||
thiserror = { version = "1.0.63", default-features = false }
|
thiserror = { version = "1.0.63", default-features = false }
|
||||||
tokio = { version = "1.39.1", default-features = false }
|
tokio = { version = "1.39.2", default-features = false }
|
||||||
tokio-test = { version = "0.4.4", default-features = false }
|
tokio-test = { version = "0.4.4", default-features = false }
|
||||||
tracing = { version = "0.1.40", default-features = false }
|
tracing = { version = "0.1.40", default-features = false }
|
||||||
tracing-subscriber = { version = "0.3.18", default-features = false }
|
tracing-subscriber = { version = "0.3.18", default-features = false }
|
||||||
|
|
56
Dockerfile
56
Dockerfile
|
@ -1,56 +1,28 @@
|
||||||
## Install dev and compilation dependencies, build files
|
# Install dev and compilation dependencies, build files
|
||||||
FROM docker.io/node:20-alpine as build
|
FROM docker.io/node:20-alpine AS build
|
||||||
WORKDIR /firefish
|
WORKDIR /firefish
|
||||||
|
|
||||||
# Copy only backend-rs pnpm-related files first, to cache efficiently
|
# Install build tools and work around the linker name issue
|
||||||
COPY package.json pnpm-workspace.yaml ./
|
|
||||||
COPY packages/backend-rs/package.json packages/backend-rs/package.json
|
|
||||||
|
|
||||||
# Install compilation dependencies
|
|
||||||
RUN apk update && apk add --no-cache build-base linux-headers curl ca-certificates python3 perl
|
RUN apk update && apk add --no-cache build-base linux-headers curl ca-certificates python3 perl
|
||||||
|
RUN ln -s $(which gcc) /usr/bin/aarch64-linux-musl-gcc
|
||||||
|
|
||||||
|
# Install Rust toolchain
|
||||||
RUN curl --proto '=https' --tlsv1.2 --silent --show-error --fail https://sh.rustup.rs | sh -s -- -y
|
RUN curl --proto '=https' --tlsv1.2 --silent --show-error --fail https://sh.rustup.rs | sh -s -- -y
|
||||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||||
|
|
||||||
# Copy only backend-rs dependency-related files first, to cache efficiently
|
# Configure pnpm
|
||||||
COPY packages/macro-rs packages/macro-rs/
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
COPY packages/backend-rs/src/lib.rs packages/backend-rs/src/
|
|
||||||
COPY packages/backend-rs/Cargo.toml packages/backend-rs/Cargo.toml
|
|
||||||
COPY Cargo.toml Cargo.lock ./
|
|
||||||
|
|
||||||
# Configure pnpm, and install backend-rs dependencies
|
# Build
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm --filter backend-rs install
|
|
||||||
RUN cargo fetch --locked --manifest-path Cargo.toml
|
|
||||||
|
|
||||||
# Copy in the rest of the rust files
|
|
||||||
COPY packages/backend-rs packages/backend-rs/
|
|
||||||
|
|
||||||
# Compile backend-rs
|
|
||||||
RUN ln -s $(which gcc) /usr/bin/aarch64-linux-musl-gcc
|
|
||||||
RUN NODE_ENV='production' NODE_OPTIONS='--max_old_space_size=3072' pnpm run --filter backend-rs build
|
|
||||||
|
|
||||||
# Copy/Overwrite index.js to mitigate the bug in napi-rs codegen
|
|
||||||
COPY packages/backend-rs/index.js packages/backend-rs/built/index.js
|
|
||||||
|
|
||||||
# Copy only the dependency-related files first, to cache efficiently
|
|
||||||
COPY packages/backend/package.json packages/backend/package.json
|
|
||||||
COPY packages/client/package.json packages/client/package.json
|
|
||||||
COPY packages/sw/package.json packages/sw/package.json
|
|
||||||
COPY packages/firefish-js/package.json packages/firefish-js/package.json
|
|
||||||
COPY pnpm-lock.yaml ./
|
|
||||||
|
|
||||||
# Install dev mode dependencies for compilation
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
# Copy in the rest of the files to build
|
|
||||||
COPY . ./
|
COPY . ./
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
# Build other workspaces
|
RUN cargo fetch --locked --manifest-path Cargo.toml
|
||||||
RUN NODE_ENV='production' NODE_OPTIONS='--max_old_space_size=3072' pnpm run --recursive --filter '!backend-rs' build && pnpm run build:assets
|
RUN NODE_ENV='production' NODE_OPTIONS='--max_old_space_size=3072' pnpm run build
|
||||||
|
|
||||||
# Trim down the dependencies to only those for production
|
# Trim down the dependencies to only those for production
|
||||||
RUN find . -path '*/node_modules/*' -delete && pnpm install --prod --frozen-lockfile
|
RUN find . -path '*/node_modules/*' -delete && pnpm install --prod --frozen-lockfile
|
||||||
|
|
||||||
## Runtime container
|
# Runtime container
|
||||||
FROM docker.io/node:20-alpine
|
FROM docker.io/node:20-alpine
|
||||||
WORKDIR /firefish
|
WORKDIR /firefish
|
||||||
|
|
||||||
|
@ -66,7 +38,7 @@ COPY --from=build /firefish/packages/backend/node_modules /firefish/packages/bac
|
||||||
# COPY --from=build /firefish/packages/client/node_modules /firefish/packages/client/node_modules
|
# COPY --from=build /firefish/packages/client/node_modules /firefish/packages/client/node_modules
|
||||||
COPY --from=build /firefish/packages/firefish-js/node_modules /firefish/packages/firefish-js/node_modules
|
COPY --from=build /firefish/packages/firefish-js/node_modules /firefish/packages/firefish-js/node_modules
|
||||||
|
|
||||||
# Copy the finished compiled files
|
# Copy the build artifacts
|
||||||
COPY --from=build /firefish/built /firefish/built
|
COPY --from=build /firefish/built /firefish/built
|
||||||
COPY --from=build /firefish/packages/backend/built /firefish/packages/backend/built
|
COPY --from=build /firefish/packages/backend/built /firefish/packages/backend/built
|
||||||
COPY --from=build /firefish/packages/backend/assets/instance.css /firefish/packages/backend/assets/instance.css
|
COPY --from=build /firefish/packages/backend/assets/instance.css /firefish/packages/backend/assets/instance.css
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
Breaking changes are indicated by the :warning: icon.
|
Breaking changes are indicated by the :warning: icon.
|
||||||
|
|
||||||
|
## v20240728
|
||||||
|
|
||||||
|
- Added `name`, `category`, `aliases`, `license` optional parameters to `admin/emoji/add` endpoint.
|
||||||
|
- Added `name` optional parameter to `drive/files/upload-from-url` endpoint.
|
||||||
|
|
||||||
## v20240725
|
## v20240725
|
||||||
|
|
||||||
- Added `i/export-followers` endpoint.
|
- Added `i/export-followers` endpoint.
|
||||||
|
|
|
@ -2,9 +2,16 @@
|
||||||
|
|
||||||
Critical security updates are indicated by the :warning: icon.
|
Critical security updates are indicated by the :warning: icon.
|
||||||
|
|
||||||
|
This changelog is not an exhaustive list. Code refactorings, minor bug fixes, documentation/dependency updates, etc. are usually not listed here. If you want to see all changes, click on the version number and check the commit history.
|
||||||
|
|
||||||
- Server administrators must check [notice-for-admins.md](https://firefish.dev/firefish/firefish/-/blob/main/docs/notice-for-admins.md) as well.
|
- Server administrators must check [notice-for-admins.md](https://firefish.dev/firefish/firefish/-/blob/main/docs/notice-for-admins.md) as well.
|
||||||
- Third-party client/bot developers may want to check [api-change.md](https://firefish.dev/firefish/firefish/-/blob/main/docs/api-change.md) as well.
|
- Third-party client/bot developers may want to check [api-change.md](https://firefish.dev/firefish/firefish/-/blob/main/docs/api-change.md) as well.
|
||||||
|
|
||||||
|
## [v20240728](https://firefish.dev/firefish/firefish/-/merge_requests/11211/commits)
|
||||||
|
|
||||||
|
- Improve `admin/emoji/add` API
|
||||||
|
- Fix bugs
|
||||||
|
|
||||||
## [v20240725](https://firefish.dev/firefish/firefish/-/merge_requests/11196/commits)
|
## [v20240725](https://firefish.dev/firefish/firefish/-/merge_requests/11196/commits)
|
||||||
|
|
||||||
- Add followers list export feature
|
- Add followers list export feature
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
# Install Firefish
|
# Install Firefish
|
||||||
|
|
||||||
|
Please check the [v20240206 release note](https://firefish.dev/firefish/firefish/-/releases/v20240206) first. This project is barely maintained for those who really want to keep using Firefish. Please understand this before proceeding.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
Firefish depends on the following software.
|
Firefish depends on the following software.
|
||||||
|
|
||||||
## Runtime dependencies
|
### Runtime dependencies
|
||||||
|
|
||||||
- At least [NodeJS](https://nodejs.org/en/) v18.19.0 (v20/v22 recommended)
|
- At least [NodeJS](https://nodejs.org/en/) v18.19.0 (v20/v22 recommended)
|
||||||
- At least [PostgreSQL](https://www.postgresql.org/) v12 (v16 recommended) with [PGroonga](https://pgroonga.github.io/) extension
|
- At least [PostgreSQL](https://www.postgresql.org/) v12 (v16 recommended) with [PGroonga](https://pgroonga.github.io/) extension
|
||||||
|
@ -17,7 +21,7 @@ Firefish depends on the following software.
|
||||||
- [KeyDB](https://keydb.dev/)
|
- [KeyDB](https://keydb.dev/)
|
||||||
- Another [Redis](https://redis.io/) / [Valkey](https://valkey.io/) server
|
- Another [Redis](https://redis.io/) / [Valkey](https://valkey.io/) server
|
||||||
|
|
||||||
## Build dependencies
|
### Build dependencies
|
||||||
|
|
||||||
- At least [Rust](https://www.rust-lang.org/) v1.74
|
- At least [Rust](https://www.rust-lang.org/) v1.74
|
||||||
- C/C++ compiler & build tools (like [GNU Make](https://www.gnu.org/software/make/))
|
- C/C++ compiler & build tools (like [GNU Make](https://www.gnu.org/software/make/))
|
||||||
|
@ -35,7 +39,7 @@ We don't test Firefish on non-Linux systems, so please install Firefish on such
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
<summary>Possible setup on FreeBSD (as of version <code>20240630</code>)</summary>
|
<summary>Possible setup on FreeBSD (as of version <code>20240725</code>)</summary>
|
||||||
|
|
||||||
You can install Firefish on FreeBSD by adding these extra steps to the standard instructions:
|
You can install Firefish on FreeBSD by adding these extra steps to the standard instructions:
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@ You can install Firefish on FreeBSD by adding these extra steps to the standard
|
||||||
```json
|
```json
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"rollup": "npm:@rollup/wasm-node@4.17.2"
|
"rollup": "npm:@rollup/wasm-node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "firefish",
|
"name": "firefish",
|
||||||
"version": "20240725",
|
"version": "20240728",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://firefish.dev/firefish/firefish.git"
|
"url": "https://firefish.dev/firefish/firefish.git"
|
||||||
|
|
97
packages/backend-rs/index.d.ts
vendored
97
packages/backend-rs/index.d.ts
vendored
|
@ -48,6 +48,8 @@ export interface Acct {
|
||||||
|
|
||||||
export declare function acctToString(acct: Acct): string
|
export declare function acctToString(acct: Acct): string
|
||||||
|
|
||||||
|
export type Activity = 'Follow';
|
||||||
|
|
||||||
export interface Ad {
|
export interface Ad {
|
||||||
id: string
|
id: string
|
||||||
createdAt: DateTimeWithTimeZone
|
createdAt: DateTimeWithTimeZone
|
||||||
|
@ -217,7 +219,7 @@ export interface Config {
|
||||||
proxySmtp?: string
|
proxySmtp?: string
|
||||||
proxyBypassHosts?: Array<string>
|
proxyBypassHosts?: Array<string>
|
||||||
allowedPrivateNetworks?: Array<string>
|
allowedPrivateNetworks?: Array<string>
|
||||||
maxFileSize?: number
|
maxFileSize: number
|
||||||
accessLog?: string
|
accessLog?: string
|
||||||
clusterLimits: WorkerConfig
|
clusterLimits: WorkerConfig
|
||||||
cuid?: IdConfig
|
cuid?: IdConfig
|
||||||
|
@ -369,6 +371,40 @@ export interface Emoji {
|
||||||
height: number | null
|
height: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export declare enum Event {
|
||||||
|
Notification = 0,
|
||||||
|
NewNotification = 1,
|
||||||
|
Mention = 2,
|
||||||
|
NewMention = 3,
|
||||||
|
Chat = 4,
|
||||||
|
NewChat = 5,
|
||||||
|
NewDm = 6,
|
||||||
|
Reply = 7,
|
||||||
|
Renote = 8,
|
||||||
|
Follow = 9,
|
||||||
|
Followed = 10,
|
||||||
|
Unfollow = 11,
|
||||||
|
NewFollowRequest = 12,
|
||||||
|
Page = 13,
|
||||||
|
ReadAllNotifications = 14,
|
||||||
|
ReadAllMentions = 15,
|
||||||
|
ReadNotifications = 16,
|
||||||
|
ReadAllDms = 17,
|
||||||
|
ReadAllChats = 18,
|
||||||
|
ReadAntenna = 19,
|
||||||
|
ReadAllAntennaPosts = 20,
|
||||||
|
NewAntennaPost = 21,
|
||||||
|
ReadAllAnnouncements = 22,
|
||||||
|
ReadAllChannelPosts = 23,
|
||||||
|
NewChannelPost = 24,
|
||||||
|
DriveFile = 25,
|
||||||
|
UrlUploadFinished = 26,
|
||||||
|
Me = 27,
|
||||||
|
RegenerateMyToken = 28,
|
||||||
|
Signin = 29,
|
||||||
|
Registry = 30
|
||||||
|
}
|
||||||
|
|
||||||
export declare function extractHost(uri: string): string
|
export declare function extractHost(uri: string): string
|
||||||
|
|
||||||
export declare function fetchMeta(): Promise<Meta>
|
export declare function fetchMeta(): Promise<Meta>
|
||||||
|
@ -389,6 +425,13 @@ export interface Following {
|
||||||
followeeSharedInbox: string | null
|
followeeSharedInbox: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FollowRelay {
|
||||||
|
id: string
|
||||||
|
type: Activity
|
||||||
|
actor: string
|
||||||
|
object: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface FollowRequest {
|
export interface FollowRequest {
|
||||||
id: string
|
id: string
|
||||||
createdAt: DateTimeWithTimeZone
|
createdAt: DateTimeWithTimeZone
|
||||||
|
@ -448,10 +491,12 @@ export declare function getFullApAccount(username: string, host?: string | undef
|
||||||
|
|
||||||
export declare function getImageSizeFromUrl(url: string): Promise<ImageSize>
|
export declare function getImageSizeFromUrl(url: string): Promise<ImageSize>
|
||||||
|
|
||||||
export declare function getInternalActor(actor: InternalActor): Promise<User>
|
export declare function getInstanceActor(): Promise<User>
|
||||||
|
|
||||||
export declare function getNoteSummary(fileIds: Array<string>, text: string | undefined | null, cw: string | undefined | null, hasPoll: boolean): string
|
export declare function getNoteSummary(fileIds: Array<string>, text: string | undefined | null, cw: string | undefined | null, hasPoll: boolean): string
|
||||||
|
|
||||||
|
export declare function getRelayActorId(): Promise<string>
|
||||||
|
|
||||||
export declare function getTimestamp(id: string): number
|
export declare function getTimestamp(id: string): number
|
||||||
|
|
||||||
/** Prints the greeting message and the Firefish version to stdout. */
|
/** Prints the greeting message and the Firefish version to stdout. */
|
||||||
|
@ -529,8 +574,20 @@ export interface Instance {
|
||||||
faviconUrl: string | null
|
faviconUrl: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InternalActor = 'instance'|
|
export declare enum InternalEvent {
|
||||||
'relay';
|
Suspend = 0,
|
||||||
|
Silence = 1,
|
||||||
|
Moderator = 2,
|
||||||
|
Token = 3,
|
||||||
|
LocalUser = 4,
|
||||||
|
RemoteUser = 5,
|
||||||
|
WebhookCreated = 6,
|
||||||
|
WebhookUpdated = 7,
|
||||||
|
WebhookDeleted = 8,
|
||||||
|
AntennaCreated = 9,
|
||||||
|
AntennaUpdated = 10,
|
||||||
|
AntennaDeleted = 11
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a server is allowlisted.
|
* Checks if a server is allowlisted.
|
||||||
|
@ -832,6 +889,15 @@ export interface NoteEdit {
|
||||||
emojis: Array<string>
|
emojis: Array<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export declare enum NoteEvent {
|
||||||
|
Delete = 0,
|
||||||
|
React = 1,
|
||||||
|
Unreact = 2,
|
||||||
|
Reply = 3,
|
||||||
|
Update = 4,
|
||||||
|
Vote = 5
|
||||||
|
}
|
||||||
|
|
||||||
export interface NoteFavorite {
|
export interface NoteFavorite {
|
||||||
id: string
|
id: string
|
||||||
createdAt: DateTimeWithTimeZone
|
createdAt: DateTimeWithTimeZone
|
||||||
|
@ -1113,10 +1179,20 @@ export declare function publishToDriveFolderStream(userId: string, kind: DriveFo
|
||||||
|
|
||||||
export declare function publishToGroupChatStream(groupId: string, kind: ChatEvent, object: any): Promise<void>
|
export declare function publishToGroupChatStream(groupId: string, kind: ChatEvent, object: any): Promise<void>
|
||||||
|
|
||||||
|
export declare function publishToInternalStream(kind: InternalEvent, object: any): Promise<void>
|
||||||
|
|
||||||
|
export declare function publishToMainStream(userId: string, kind: Event, object: any): Promise<void>
|
||||||
|
|
||||||
export declare function publishToModerationStream(moderatorId: string, report: AbuseUserReportLike): Promise<void>
|
export declare function publishToModerationStream(moderatorId: string, report: AbuseUserReportLike): Promise<void>
|
||||||
|
|
||||||
export declare function publishToNotesStream(note: Note): Promise<void>
|
export declare function publishToNotesStream(note: Note): Promise<void>
|
||||||
|
|
||||||
|
export declare function publishToNoteStream(noteId: string, kind: NoteEvent, object: any): Promise<void>
|
||||||
|
|
||||||
|
export declare function publishToNoteUpdatesStream(note: Note): Promise<void>
|
||||||
|
|
||||||
|
export declare function publishToUserStream(userId: string, kind: UserEvent, object: any): Promise<void>
|
||||||
|
|
||||||
export interface PugArgs {
|
export interface PugArgs {
|
||||||
img: string | null
|
img: string | null
|
||||||
title: string
|
title: string
|
||||||
|
@ -1189,6 +1265,8 @@ export type RelayStatus = 'accepted'|
|
||||||
/** Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago */
|
/** Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago */
|
||||||
export declare function removeOldAttestationChallenges(): Promise<void>
|
export declare function removeOldAttestationChallenges(): Promise<void>
|
||||||
|
|
||||||
|
export declare function renderFollowRelay(relayId: string): Promise<FollowRelay>
|
||||||
|
|
||||||
export interface RenoteMuting {
|
export interface RenoteMuting {
|
||||||
id: string
|
id: string
|
||||||
createdAt: DateTimeWithTimeZone
|
createdAt: DateTimeWithTimeZone
|
||||||
|
@ -1406,6 +1484,17 @@ export type UserEmojiModPerm = 'add'|
|
||||||
'mod'|
|
'mod'|
|
||||||
'unauthorized';
|
'unauthorized';
|
||||||
|
|
||||||
|
export declare enum UserEvent {
|
||||||
|
Disconnect = 0,
|
||||||
|
FollowChannel = 1,
|
||||||
|
UnfollowChannel = 2,
|
||||||
|
UpdateProfile = 3,
|
||||||
|
Mute = 4,
|
||||||
|
Unmute = 5,
|
||||||
|
Follow = 6,
|
||||||
|
Unfollow = 7
|
||||||
|
}
|
||||||
|
|
||||||
export interface UserGroup {
|
export interface UserGroup {
|
||||||
id: string
|
id: string
|
||||||
createdAt: DateTimeWithTimeZone
|
createdAt: DateTimeWithTimeZone
|
||||||
|
|
|
@ -362,6 +362,7 @@ if (!nativeBinding) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.acctToString = nativeBinding.acctToString
|
module.exports.acctToString = nativeBinding.acctToString
|
||||||
|
module.exports.Activity = nativeBinding.Activity
|
||||||
module.exports.AntennaSrc = nativeBinding.AntennaSrc
|
module.exports.AntennaSrc = nativeBinding.AntennaSrc
|
||||||
module.exports.ChatEvent = nativeBinding.ChatEvent
|
module.exports.ChatEvent = nativeBinding.ChatEvent
|
||||||
module.exports.ChatIndexEvent = nativeBinding.ChatIndexEvent
|
module.exports.ChatIndexEvent = nativeBinding.ChatIndexEvent
|
||||||
|
@ -374,6 +375,7 @@ module.exports.decodeReaction = nativeBinding.decodeReaction
|
||||||
module.exports.DriveFileEvent = nativeBinding.DriveFileEvent
|
module.exports.DriveFileEvent = nativeBinding.DriveFileEvent
|
||||||
module.exports.DriveFileUsageHint = nativeBinding.DriveFileUsageHint
|
module.exports.DriveFileUsageHint = nativeBinding.DriveFileUsageHint
|
||||||
module.exports.DriveFolderEvent = nativeBinding.DriveFolderEvent
|
module.exports.DriveFolderEvent = nativeBinding.DriveFolderEvent
|
||||||
|
module.exports.Event = nativeBinding.Event
|
||||||
module.exports.extractHost = nativeBinding.extractHost
|
module.exports.extractHost = nativeBinding.extractHost
|
||||||
module.exports.fetchMeta = nativeBinding.fetchMeta
|
module.exports.fetchMeta = nativeBinding.fetchMeta
|
||||||
module.exports.fetchNodeinfo = nativeBinding.fetchNodeinfo
|
module.exports.fetchNodeinfo = nativeBinding.fetchNodeinfo
|
||||||
|
@ -384,14 +386,15 @@ module.exports.genId = nativeBinding.genId
|
||||||
module.exports.genIdAt = nativeBinding.genIdAt
|
module.exports.genIdAt = nativeBinding.genIdAt
|
||||||
module.exports.getFullApAccount = nativeBinding.getFullApAccount
|
module.exports.getFullApAccount = nativeBinding.getFullApAccount
|
||||||
module.exports.getImageSizeFromUrl = nativeBinding.getImageSizeFromUrl
|
module.exports.getImageSizeFromUrl = nativeBinding.getImageSizeFromUrl
|
||||||
module.exports.getInternalActor = nativeBinding.getInternalActor
|
module.exports.getInstanceActor = nativeBinding.getInstanceActor
|
||||||
module.exports.getNoteSummary = nativeBinding.getNoteSummary
|
module.exports.getNoteSummary = nativeBinding.getNoteSummary
|
||||||
|
module.exports.getRelayActorId = nativeBinding.getRelayActorId
|
||||||
module.exports.getTimestamp = nativeBinding.getTimestamp
|
module.exports.getTimestamp = nativeBinding.getTimestamp
|
||||||
module.exports.greet = nativeBinding.greet
|
module.exports.greet = nativeBinding.greet
|
||||||
module.exports.hashPassword = nativeBinding.hashPassword
|
module.exports.hashPassword = nativeBinding.hashPassword
|
||||||
module.exports.Inbound = nativeBinding.Inbound
|
module.exports.Inbound = nativeBinding.Inbound
|
||||||
module.exports.initializeRustLogger = nativeBinding.initializeRustLogger
|
module.exports.initializeRustLogger = nativeBinding.initializeRustLogger
|
||||||
module.exports.InternalActor = nativeBinding.InternalActor
|
module.exports.InternalEvent = nativeBinding.InternalEvent
|
||||||
module.exports.isAllowedServer = nativeBinding.isAllowedServer
|
module.exports.isAllowedServer = nativeBinding.isAllowedServer
|
||||||
module.exports.isBlockedServer = nativeBinding.isBlockedServer
|
module.exports.isBlockedServer = nativeBinding.isBlockedServer
|
||||||
module.exports.isOldPasswordAlgorithm = nativeBinding.isOldPasswordAlgorithm
|
module.exports.isOldPasswordAlgorithm = nativeBinding.isOldPasswordAlgorithm
|
||||||
|
@ -408,6 +411,7 @@ module.exports.metaToPugArgs = nativeBinding.metaToPugArgs
|
||||||
module.exports.MutedNoteReason = nativeBinding.MutedNoteReason
|
module.exports.MutedNoteReason = nativeBinding.MutedNoteReason
|
||||||
module.exports.nodeinfo_2_0 = nativeBinding.nodeinfo_2_0
|
module.exports.nodeinfo_2_0 = nativeBinding.nodeinfo_2_0
|
||||||
module.exports.nodeinfo_2_1 = nativeBinding.nodeinfo_2_1
|
module.exports.nodeinfo_2_1 = nativeBinding.nodeinfo_2_1
|
||||||
|
module.exports.NoteEvent = nativeBinding.NoteEvent
|
||||||
module.exports.NoteVisibility = nativeBinding.NoteVisibility
|
module.exports.NoteVisibility = nativeBinding.NoteVisibility
|
||||||
module.exports.NotificationType = nativeBinding.NotificationType
|
module.exports.NotificationType = nativeBinding.NotificationType
|
||||||
module.exports.nyaify = nativeBinding.nyaify
|
module.exports.nyaify = nativeBinding.nyaify
|
||||||
|
@ -422,12 +426,18 @@ module.exports.publishToChatStream = nativeBinding.publishToChatStream
|
||||||
module.exports.publishToDriveFileStream = nativeBinding.publishToDriveFileStream
|
module.exports.publishToDriveFileStream = nativeBinding.publishToDriveFileStream
|
||||||
module.exports.publishToDriveFolderStream = nativeBinding.publishToDriveFolderStream
|
module.exports.publishToDriveFolderStream = nativeBinding.publishToDriveFolderStream
|
||||||
module.exports.publishToGroupChatStream = nativeBinding.publishToGroupChatStream
|
module.exports.publishToGroupChatStream = nativeBinding.publishToGroupChatStream
|
||||||
|
module.exports.publishToInternalStream = nativeBinding.publishToInternalStream
|
||||||
|
module.exports.publishToMainStream = nativeBinding.publishToMainStream
|
||||||
module.exports.publishToModerationStream = nativeBinding.publishToModerationStream
|
module.exports.publishToModerationStream = nativeBinding.publishToModerationStream
|
||||||
module.exports.publishToNotesStream = nativeBinding.publishToNotesStream
|
module.exports.publishToNotesStream = nativeBinding.publishToNotesStream
|
||||||
|
module.exports.publishToNoteStream = nativeBinding.publishToNoteStream
|
||||||
|
module.exports.publishToNoteUpdatesStream = nativeBinding.publishToNoteUpdatesStream
|
||||||
|
module.exports.publishToUserStream = nativeBinding.publishToUserStream
|
||||||
module.exports.PushNotificationKind = nativeBinding.PushNotificationKind
|
module.exports.PushNotificationKind = nativeBinding.PushNotificationKind
|
||||||
module.exports.PushSubscriptionType = nativeBinding.PushSubscriptionType
|
module.exports.PushSubscriptionType = nativeBinding.PushSubscriptionType
|
||||||
module.exports.RelayStatus = nativeBinding.RelayStatus
|
module.exports.RelayStatus = nativeBinding.RelayStatus
|
||||||
module.exports.removeOldAttestationChallenges = nativeBinding.removeOldAttestationChallenges
|
module.exports.removeOldAttestationChallenges = nativeBinding.removeOldAttestationChallenges
|
||||||
|
module.exports.renderFollowRelay = nativeBinding.renderFollowRelay
|
||||||
module.exports.safeForSql = nativeBinding.safeForSql
|
module.exports.safeForSql = nativeBinding.safeForSql
|
||||||
module.exports.sendPushNotification = nativeBinding.sendPushNotification
|
module.exports.sendPushNotification = nativeBinding.sendPushNotification
|
||||||
module.exports.shouldNyaify = nativeBinding.shouldNyaify
|
module.exports.shouldNyaify = nativeBinding.shouldNyaify
|
||||||
|
@ -445,6 +455,7 @@ module.exports.updateAntennasOnNewNote = nativeBinding.updateAntennasOnNewNote
|
||||||
module.exports.updateMetaCache = nativeBinding.updateMetaCache
|
module.exports.updateMetaCache = nativeBinding.updateMetaCache
|
||||||
module.exports.updateNodeinfoCache = nativeBinding.updateNodeinfoCache
|
module.exports.updateNodeinfoCache = nativeBinding.updateNodeinfoCache
|
||||||
module.exports.UserEmojiModPerm = nativeBinding.UserEmojiModPerm
|
module.exports.UserEmojiModPerm = nativeBinding.UserEmojiModPerm
|
||||||
|
module.exports.UserEvent = nativeBinding.UserEvent
|
||||||
module.exports.UserProfileFfvisibility = nativeBinding.UserProfileFfvisibility
|
module.exports.UserProfileFfvisibility = nativeBinding.UserProfileFfvisibility
|
||||||
module.exports.UserProfileMutingNotificationTypes = nativeBinding.UserProfileMutingNotificationTypes
|
module.exports.UserProfileMutingNotificationTypes = nativeBinding.UserProfileMutingNotificationTypes
|
||||||
module.exports.verifyPassword = nativeBinding.verifyPassword
|
module.exports.verifyPassword = nativeBinding.verifyPassword
|
||||||
|
|
|
@ -200,7 +200,7 @@ pub struct Config {
|
||||||
pub proxy_smtp: Option<String>,
|
pub proxy_smtp: Option<String>,
|
||||||
pub proxy_bypass_hosts: Option<Vec<String>>,
|
pub proxy_bypass_hosts: Option<Vec<String>>,
|
||||||
pub allowed_private_networks: Option<Vec<String>>,
|
pub allowed_private_networks: Option<Vec<String>>,
|
||||||
pub max_file_size: Option<i64>,
|
pub max_file_size: i64,
|
||||||
pub access_log: Option<String>,
|
pub access_log: Option<String>,
|
||||||
pub cluster_limits: WorkerConfig,
|
pub cluster_limits: WorkerConfig,
|
||||||
pub cuid: Option<IdConfig>,
|
pub cuid: Option<IdConfig>,
|
||||||
|
@ -309,7 +309,7 @@ pub fn load_config() -> Config {
|
||||||
proxy_smtp: server_config.proxy_smtp,
|
proxy_smtp: server_config.proxy_smtp,
|
||||||
proxy_bypass_hosts: server_config.proxy_bypass_hosts,
|
proxy_bypass_hosts: server_config.proxy_bypass_hosts,
|
||||||
allowed_private_networks: server_config.allowed_private_networks,
|
allowed_private_networks: server_config.allowed_private_networks,
|
||||||
max_file_size: server_config.max_file_size,
|
max_file_size: server_config.max_file_size.unwrap_or(262144000),
|
||||||
access_log: server_config.access_log,
|
access_log: server_config.access_log,
|
||||||
cluster_limits,
|
cluster_limits,
|
||||||
cuid: server_config.cuid,
|
cuid: server_config.cuid,
|
||||||
|
|
1
packages/backend-rs/src/federation/activitypub/mod.rs
Normal file
1
packages/backend-rs/src/federation/activitypub/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod object;
|
|
@ -0,0 +1,9 @@
|
||||||
|
pub mod relay;
|
||||||
|
|
||||||
|
pub trait ActivityPubObject {}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
#[macros::export(string_enum)]
|
||||||
|
pub enum Activity {
|
||||||
|
Follow,
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
use super::*;
|
||||||
|
use crate::{config::CONFIG, federation::internal_actor};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[macros::export(object)]
|
||||||
|
pub struct FollowRelay {
|
||||||
|
pub id: String,
|
||||||
|
pub r#type: Activity,
|
||||||
|
pub actor: String,
|
||||||
|
pub object: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivityPubObject for FollowRelay {}
|
||||||
|
|
||||||
|
#[macros::export(js_name = "renderFollowRelay")]
|
||||||
|
pub async fn follow(relay_id: &str) -> Result<FollowRelay, internal_actor::relay::Error> {
|
||||||
|
Ok(FollowRelay {
|
||||||
|
id: format!("{}/activities/follow-relay/{}", CONFIG.url, relay_id),
|
||||||
|
r#type: Activity::Follow,
|
||||||
|
actor: format!(
|
||||||
|
"{}/users/{}",
|
||||||
|
CONFIG.url,
|
||||||
|
internal_actor::relay::get_id().await?
|
||||||
|
),
|
||||||
|
object: "https://www.w3.org/ns/activitystreams#Public".to_owned(),
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,87 +0,0 @@
|
||||||
//! In-memory internal actor cache handler
|
|
||||||
|
|
||||||
// TODO: refactoring
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::{database::db_conn, model::entity::user};
|
|
||||||
use sea_orm::prelude::*;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
#[macros::errors]
|
|
||||||
pub enum Error {
|
|
||||||
#[error(transparent)]
|
|
||||||
#[doc = "database error"]
|
|
||||||
Db(#[from] DbErr),
|
|
||||||
#[error("{} does not exist", Acct::from(.0.to_owned()))]
|
|
||||||
#[doc = "internal actor does not exist"]
|
|
||||||
InternalActorNotFound(InternalActor),
|
|
||||||
}
|
|
||||||
|
|
||||||
static INSTANCE_ACTOR: Mutex<Option<user::Model>> = Mutex::new(None);
|
|
||||||
static RELAY_ACTOR: Mutex<Option<user::Model>> = Mutex::new(None);
|
|
||||||
|
|
||||||
fn set_instance_actor(value: &user::Model) {
|
|
||||||
let _ = INSTANCE_ACTOR
|
|
||||||
.lock()
|
|
||||||
.map(|mut cache| *cache = Some(value.to_owned()));
|
|
||||||
}
|
|
||||||
fn set_relay_actor(value: &user::Model) {
|
|
||||||
let _ = RELAY_ACTOR
|
|
||||||
.lock()
|
|
||||||
.map(|mut cache| *cache = Some(value.to_owned()));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn cache_instance_actor() -> Result<user::Model, Error> {
|
|
||||||
let actor = user::Entity::find()
|
|
||||||
.filter(user::Column::Username.eq(INSTANCE_ACTOR_USERNAME))
|
|
||||||
.filter(user::Column::Host.is_null())
|
|
||||||
.one(db_conn().await?)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let Some(actor) = actor {
|
|
||||||
set_instance_actor(&actor);
|
|
||||||
Ok(actor)
|
|
||||||
} else {
|
|
||||||
Err(Error::InternalActorNotFound(InternalActor::Instance))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async fn cache_relay_actor() -> Result<user::Model, Error> {
|
|
||||||
let actor = user::Entity::find()
|
|
||||||
.filter(user::Column::Username.eq(RELAY_ACTOR_USERNAME))
|
|
||||||
.filter(user::Column::Host.is_null())
|
|
||||||
.one(db_conn().await?)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let Some(actor) = actor {
|
|
||||||
set_relay_actor(&actor);
|
|
||||||
Ok(actor)
|
|
||||||
} else {
|
|
||||||
Err(Error::InternalActorNotFound(InternalActor::Relay))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for napi export
|
|
||||||
// https://github.com/napi-rs/napi-rs/issues/2060
|
|
||||||
type User = user::Model;
|
|
||||||
|
|
||||||
#[macros::export(js_name = "getInternalActor")]
|
|
||||||
pub async fn get(actor: InternalActor) -> Result<User, Error> {
|
|
||||||
match actor {
|
|
||||||
InternalActor::Instance => {
|
|
||||||
if let Some(cache) = INSTANCE_ACTOR.lock().ok().and_then(|cache| cache.clone()) {
|
|
||||||
tracing::debug!("Using cached instance.actor");
|
|
||||||
return Ok(cache);
|
|
||||||
}
|
|
||||||
tracing::debug!("Caching instance.actor");
|
|
||||||
cache_instance_actor().await
|
|
||||||
}
|
|
||||||
InternalActor::Relay => {
|
|
||||||
if let Some(cache) = RELAY_ACTOR.lock().ok().and_then(|cache| cache.clone()) {
|
|
||||||
tracing::debug!("Using cached relay.actor");
|
|
||||||
return Ok(cache);
|
|
||||||
}
|
|
||||||
tracing::debug!("Caching relay.actor");
|
|
||||||
cache_relay_actor().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
//! In-memory instance actor cache
|
||||||
|
|
||||||
|
use crate::{database::db_conn, model::entity::user};
|
||||||
|
use sea_orm::prelude::*;
|
||||||
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
|
// for napi export
|
||||||
|
// https://github.com/napi-rs/napi-rs/issues/2060
|
||||||
|
type User = user::Model;
|
||||||
|
|
||||||
|
pub const USERNAME: &str = "instance.actor";
|
||||||
|
static INSTANCE_ACTOR: OnceCell<User> = OnceCell::const_new();
|
||||||
|
|
||||||
|
#[macros::errors]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("@instance.actor not found")]
|
||||||
|
InstanceActorNotFound,
|
||||||
|
#[error(transparent)]
|
||||||
|
#[doc = "database error"]
|
||||||
|
Db(#[from] DbErr),
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_cache() -> Result<&'static User, Error> {
|
||||||
|
let instance_actor = INSTANCE_ACTOR
|
||||||
|
.get_or_try_init(|| async {
|
||||||
|
tracing::debug!("caching @instance.actor");
|
||||||
|
let found_model = user::Entity::find()
|
||||||
|
.filter(user::Column::Username.eq(USERNAME))
|
||||||
|
.filter(user::Column::Host.is_null())
|
||||||
|
.one(db_conn().await?)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
found_model.ok_or(Error::InstanceActorNotFound)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(instance_actor)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get() -> Result<&'static User, Error> {
|
||||||
|
match INSTANCE_ACTOR.get() {
|
||||||
|
Some(model) => Ok(model),
|
||||||
|
None => set_cache().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macros::ts_export(js_name = "getInstanceActor")]
|
||||||
|
pub async fn get_js() -> Result<User, Error> {
|
||||||
|
Ok(get().await?.to_owned())
|
||||||
|
}
|
|
@ -1,34 +1,4 @@
|
||||||
mod cache;
|
pub mod instance;
|
||||||
|
pub mod relay;
|
||||||
|
|
||||||
pub use cache::get;
|
|
||||||
|
|
||||||
use super::acct::Acct;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[macros::derive_clone_and_export(string_enum = "lowercase")]
|
|
||||||
pub enum InternalActor {
|
|
||||||
Instance,
|
|
||||||
Relay,
|
|
||||||
}
|
|
||||||
|
|
||||||
const INSTANCE_ACTOR_USERNAME: &str = "instance.actor";
|
|
||||||
const RELAY_ACTOR_USERNAME: &str = "relay.actor";
|
|
||||||
|
|
||||||
// TODO: When `std::mem::variant_count` is stabilized, use
|
|
||||||
// it to count system actors instead of hard coding the magic number
|
|
||||||
pub const INTERNAL_ACTORS: u64 = 2;
|
pub const INTERNAL_ACTORS: u64 = 2;
|
||||||
|
|
||||||
impl From<InternalActor> for Acct {
|
|
||||||
fn from(actor: InternalActor) -> Self {
|
|
||||||
match actor {
|
|
||||||
InternalActor::Instance => Acct {
|
|
||||||
username: INSTANCE_ACTOR_USERNAME.to_owned(),
|
|
||||||
host: None,
|
|
||||||
},
|
|
||||||
InternalActor::Relay => Acct {
|
|
||||||
username: RELAY_ACTOR_USERNAME.to_owned(),
|
|
||||||
host: None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
45
packages/backend-rs/src/federation/internal_actor/relay.rs
Normal file
45
packages/backend-rs/src/federation/internal_actor/relay.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//! In-memory relay actor id cache
|
||||||
|
|
||||||
|
use crate::{database::db_conn, model::entity::user};
|
||||||
|
use sea_orm::{prelude::*, QuerySelect, SelectColumns};
|
||||||
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
|
pub const USERNAME: &str = "relay.actor";
|
||||||
|
static RELAY_ACTOR_ID: OnceCell<String> = OnceCell::const_new();
|
||||||
|
|
||||||
|
#[macros::errors]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("@relay.actor not found")]
|
||||||
|
RelayActorNotFound,
|
||||||
|
#[error(transparent)]
|
||||||
|
#[doc = "database error"]
|
||||||
|
Db(#[from] DbErr),
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_id_cache() -> Result<&'static str, Error> {
|
||||||
|
let id = RELAY_ACTOR_ID
|
||||||
|
.get_or_try_init(|| async {
|
||||||
|
tracing::debug!("caching @relay.actor");
|
||||||
|
let found_id = user::Entity::find()
|
||||||
|
.select_only()
|
||||||
|
.select_column(user::Column::Id)
|
||||||
|
.filter(user::Column::Username.eq(USERNAME))
|
||||||
|
.filter(user::Column::Host.is_null())
|
||||||
|
.into_tuple::<String>()
|
||||||
|
.one(db_conn().await?)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
found_id.ok_or(Error::RelayActorNotFound)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macros::export(js_name = "getRelayActorId")]
|
||||||
|
pub async fn get_id() -> Result<&'static str, Error> {
|
||||||
|
match RELAY_ACTOR_ID.get() {
|
||||||
|
Some(id) => Ok(id),
|
||||||
|
None => set_id_cache().await,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
//! Services used to federate with other servers
|
//! Services used to federate with other servers
|
||||||
|
|
||||||
pub mod acct;
|
pub mod acct;
|
||||||
|
pub mod activitypub;
|
||||||
pub mod internal_actor;
|
pub mod internal_actor;
|
||||||
pub mod nodeinfo;
|
pub mod nodeinfo;
|
||||||
|
|
|
@ -5,8 +5,13 @@ pub mod chat_index;
|
||||||
pub mod custom_emoji;
|
pub mod custom_emoji;
|
||||||
pub mod drive;
|
pub mod drive;
|
||||||
pub mod group_chat;
|
pub mod group_chat;
|
||||||
|
pub mod internal;
|
||||||
|
pub mod main;
|
||||||
pub mod moderation;
|
pub mod moderation;
|
||||||
|
pub mod note;
|
||||||
|
pub mod note_edit;
|
||||||
pub mod notes;
|
pub mod notes;
|
||||||
|
pub mod user;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CONFIG,
|
config::CONFIG,
|
||||||
|
@ -30,9 +35,7 @@ pub enum Stream {
|
||||||
note_id: String,
|
note_id: String,
|
||||||
},
|
},
|
||||||
Notes,
|
Notes,
|
||||||
UserList {
|
NoteEdit,
|
||||||
list_id: String,
|
|
||||||
},
|
|
||||||
Main {
|
Main {
|
||||||
user_id: String,
|
user_id: String,
|
||||||
},
|
},
|
||||||
|
@ -86,8 +89,8 @@ pub async fn publish_to_stream(
|
||||||
Stream::User { user_id } => format!("user:{user_id}"),
|
Stream::User { user_id } => format!("user:{user_id}"),
|
||||||
Stream::Channel { channel_id } => format!("channelStream:{channel_id}"),
|
Stream::Channel { channel_id } => format!("channelStream:{channel_id}"),
|
||||||
Stream::Note { note_id } => format!("noteStream:{note_id}"),
|
Stream::Note { note_id } => format!("noteStream:{note_id}"),
|
||||||
|
Stream::NoteEdit => "noteUpdatesStream".to_owned(),
|
||||||
Stream::Notes => "notesStream".to_owned(),
|
Stream::Notes => "notesStream".to_owned(),
|
||||||
Stream::UserList { list_id } => format!("userListStream:{list_id}"),
|
|
||||||
Stream::Main { user_id } => format!("mainStream:{user_id}"),
|
Stream::Main { user_id } => format!("mainStream:{user_id}"),
|
||||||
Stream::Drive { user_id } => format!("driveStream:{user_id}"),
|
Stream::Drive { user_id } => format!("driveStream:{user_id}"),
|
||||||
Stream::Antenna { antenna_id } => format!("antennaStream:{antenna_id}"),
|
Stream::Antenna { antenna_id } => format!("antennaStream:{antenna_id}"),
|
||||||
|
|
45
packages/backend-rs/src/service/stream/internal.rs
Normal file
45
packages/backend-rs/src/service/stream/internal.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||||
|
|
||||||
|
#[macros::export]
|
||||||
|
pub enum InternalEvent {
|
||||||
|
Suspend,
|
||||||
|
Silence,
|
||||||
|
Moderator,
|
||||||
|
Token,
|
||||||
|
LocalUser,
|
||||||
|
RemoteUser,
|
||||||
|
WebhookCreated,
|
||||||
|
WebhookUpdated,
|
||||||
|
WebhookDeleted,
|
||||||
|
AntennaCreated,
|
||||||
|
AntennaUpdated,
|
||||||
|
AntennaDeleted,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to merge `kind` and `object` into a single enum
|
||||||
|
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||||
|
|
||||||
|
#[macros::export(js_name = "publishToInternalStream")]
|
||||||
|
pub async fn publish(kind: InternalEvent, object: &serde_json::Value) -> Result<(), Error> {
|
||||||
|
let kind = match kind {
|
||||||
|
InternalEvent::Suspend => "userChangeSuspendedState",
|
||||||
|
InternalEvent::Silence => "userChangeSilencedState",
|
||||||
|
InternalEvent::Moderator => "userChangeModeratorState",
|
||||||
|
InternalEvent::Token => "userTokenRegenerated",
|
||||||
|
InternalEvent::LocalUser => "localUserUpdated",
|
||||||
|
InternalEvent::RemoteUser => "remoteUserUpdated",
|
||||||
|
InternalEvent::WebhookCreated => "webhookCreated",
|
||||||
|
InternalEvent::WebhookUpdated => "webhookUpdated",
|
||||||
|
InternalEvent::WebhookDeleted => "webhookDeleted",
|
||||||
|
InternalEvent::AntennaCreated => "antennaCreated",
|
||||||
|
InternalEvent::AntennaUpdated => "antennaUpdated",
|
||||||
|
InternalEvent::AntennaDeleted => "antennaDeleted",
|
||||||
|
};
|
||||||
|
|
||||||
|
publish_to_stream(
|
||||||
|
&Stream::Internal,
|
||||||
|
Some(kind),
|
||||||
|
Some(serde_json::to_string(&object)?),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
87
packages/backend-rs/src/service/stream/main.rs
Normal file
87
packages/backend-rs/src/service/stream/main.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||||
|
|
||||||
|
#[macros::export]
|
||||||
|
pub enum Event {
|
||||||
|
Notification,
|
||||||
|
NewNotification,
|
||||||
|
Mention,
|
||||||
|
NewMention,
|
||||||
|
Chat,
|
||||||
|
NewChat,
|
||||||
|
NewDm,
|
||||||
|
Reply,
|
||||||
|
Renote,
|
||||||
|
Follow,
|
||||||
|
Followed,
|
||||||
|
Unfollow,
|
||||||
|
NewFollowRequest,
|
||||||
|
Page,
|
||||||
|
ReadAllNotifications,
|
||||||
|
ReadAllMentions,
|
||||||
|
ReadNotifications,
|
||||||
|
ReadAllDms,
|
||||||
|
ReadAllChats,
|
||||||
|
ReadAntenna,
|
||||||
|
ReadAllAntennaPosts,
|
||||||
|
NewAntennaPost,
|
||||||
|
ReadAllAnnouncements,
|
||||||
|
ReadAllChannelPosts,
|
||||||
|
NewChannelPost,
|
||||||
|
DriveFile,
|
||||||
|
UrlUploadFinished,
|
||||||
|
Me,
|
||||||
|
RegenerateMyToken,
|
||||||
|
Signin,
|
||||||
|
Registry,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to merge `kind` and `object` into a single enum
|
||||||
|
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||||
|
|
||||||
|
#[macros::export(js_name = "publishToMainStream")]
|
||||||
|
pub async fn publish(
|
||||||
|
user_id: String,
|
||||||
|
kind: Event,
|
||||||
|
object: &serde_json::Value,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let kind = match kind {
|
||||||
|
Event::Notification => "notification",
|
||||||
|
Event::Mention => "mention",
|
||||||
|
Event::Reply => "reply",
|
||||||
|
Event::Renote => "renote",
|
||||||
|
Event::Follow => "follow",
|
||||||
|
Event::Followed => "followed",
|
||||||
|
Event::Unfollow => "unfollow",
|
||||||
|
Event::Me => "meUpdated",
|
||||||
|
Event::Page => "pageEvent",
|
||||||
|
Event::UrlUploadFinished => "urlUploadFinished",
|
||||||
|
Event::ReadAllNotifications => "readAllNotifications",
|
||||||
|
Event::ReadNotifications => "readNotifications",
|
||||||
|
Event::NewNotification => "unreadNotification",
|
||||||
|
Event::NewMention => "unreadMention",
|
||||||
|
Event::ReadAllMentions => "readAllUnreadMentions",
|
||||||
|
Event::ReadAllDms => "readAllUnreadSpecifiedNotes",
|
||||||
|
Event::NewDm => "unreadSpecifiedNote",
|
||||||
|
Event::ReadAllChats => "readAllMessagingMessages",
|
||||||
|
Event::Chat => "messagingMessage",
|
||||||
|
Event::NewChat => "unreadMessagingMessage",
|
||||||
|
Event::ReadAllAntennaPosts => "readAllAntennas",
|
||||||
|
Event::NewAntennaPost => "unreadAntenna",
|
||||||
|
Event::ReadAllAnnouncements => "readAllAnnouncements",
|
||||||
|
Event::ReadAllChannelPosts => "readAllChannels",
|
||||||
|
Event::NewChannelPost => "unreadChannel",
|
||||||
|
Event::RegenerateMyToken => "myTokenRegenerated",
|
||||||
|
Event::Signin => "signin",
|
||||||
|
Event::Registry => "registryUpdated",
|
||||||
|
Event::DriveFile => "driveFileCreated",
|
||||||
|
Event::ReadAntenna => "readAntenna",
|
||||||
|
Event::NewFollowRequest => "receiveFollowRequest",
|
||||||
|
};
|
||||||
|
|
||||||
|
publish_to_stream(
|
||||||
|
&Stream::Main { user_id },
|
||||||
|
Some(kind),
|
||||||
|
Some(serde_json::to_string(&object)?),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
43
packages/backend-rs/src/service/stream/note.rs
Normal file
43
packages/backend-rs/src/service/stream/note.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[macros::export]
|
||||||
|
pub enum NoteEvent {
|
||||||
|
Delete,
|
||||||
|
React,
|
||||||
|
Unreact,
|
||||||
|
Reply,
|
||||||
|
Update,
|
||||||
|
Vote,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to merge `kind` and `object` into a single enum
|
||||||
|
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||||
|
|
||||||
|
#[macros::export(js_name = "publishToNoteStream")]
|
||||||
|
pub async fn publish(
|
||||||
|
note_id: String,
|
||||||
|
kind: NoteEvent,
|
||||||
|
object: &serde_json::Value,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let kind = match kind {
|
||||||
|
NoteEvent::Delete => "deleted",
|
||||||
|
NoteEvent::React => "reacted",
|
||||||
|
NoteEvent::Unreact => "unreacted",
|
||||||
|
NoteEvent::Reply => "replied",
|
||||||
|
NoteEvent::Update => "updated",
|
||||||
|
NoteEvent::Vote => "pollVoted",
|
||||||
|
};
|
||||||
|
|
||||||
|
let value = json!({
|
||||||
|
"id": note_id.clone(),
|
||||||
|
"body": object,
|
||||||
|
});
|
||||||
|
|
||||||
|
publish_to_stream(
|
||||||
|
&Stream::Note { note_id },
|
||||||
|
Some(kind),
|
||||||
|
Some(serde_json::to_string(&value)?),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
18
packages/backend-rs/src/service/stream/note_edit.rs
Normal file
18
packages/backend-rs/src/service/stream/note_edit.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use crate::{
|
||||||
|
model::entity::note,
|
||||||
|
service::stream::{publish_to_stream, Error, Stream},
|
||||||
|
};
|
||||||
|
|
||||||
|
// for napi export
|
||||||
|
// https://github.com/napi-rs/napi-rs/issues/2060
|
||||||
|
type Note = note::Model;
|
||||||
|
|
||||||
|
#[macros::export(js_name = "publishToNoteUpdatesStream")]
|
||||||
|
pub async fn publish(note: &Note) -> Result<(), Error> {
|
||||||
|
publish_to_stream(
|
||||||
|
&Stream::NoteEdit,
|
||||||
|
Some("updated"),
|
||||||
|
Some(serde_json::to_string(note)?),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
41
packages/backend-rs/src/service/stream/user.rs
Normal file
41
packages/backend-rs/src/service/stream/user.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||||
|
|
||||||
|
#[macros::export]
|
||||||
|
pub enum UserEvent {
|
||||||
|
Disconnect,
|
||||||
|
FollowChannel,
|
||||||
|
UnfollowChannel,
|
||||||
|
UpdateProfile,
|
||||||
|
Mute,
|
||||||
|
Unmute,
|
||||||
|
Follow,
|
||||||
|
Unfollow,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to merge `kind` and `object` into a single enum
|
||||||
|
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||||
|
|
||||||
|
#[macros::export(js_name = "publishToUserStream")]
|
||||||
|
pub async fn publish(
|
||||||
|
user_id: String,
|
||||||
|
kind: UserEvent,
|
||||||
|
object: &serde_json::Value,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let kind = match kind {
|
||||||
|
UserEvent::Disconnect => "terminate",
|
||||||
|
UserEvent::FollowChannel => "followChannel",
|
||||||
|
UserEvent::UnfollowChannel => "unfollowChannel",
|
||||||
|
UserEvent::UpdateProfile => "updateUserProfile",
|
||||||
|
UserEvent::Mute => "mute",
|
||||||
|
UserEvent::Unmute => "unmute",
|
||||||
|
UserEvent::Follow => "follow",
|
||||||
|
UserEvent::Unfollow => "unfollow",
|
||||||
|
};
|
||||||
|
|
||||||
|
publish_to_stream(
|
||||||
|
&Stream::User { user_id },
|
||||||
|
Some(kind),
|
||||||
|
Some(serde_json::to_string(&object)?),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
|
@ -33,7 +33,7 @@
|
||||||
"archiver": "7.0.1",
|
"archiver": "7.0.1",
|
||||||
"async-lock": "1.4.1",
|
"async-lock": "1.4.1",
|
||||||
"async-mutex": "0.5.0",
|
"async-mutex": "0.5.0",
|
||||||
"aws-sdk": "2.1662.0",
|
"aws-sdk": "2.1664.0",
|
||||||
"axios": "1.7.2",
|
"axios": "1.7.2",
|
||||||
"backend-rs": "workspace:*",
|
"backend-rs": "workspace:*",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
|
|
|
@ -18,7 +18,6 @@ export const DB_MAX_NOTE_TEXT_LENGTH = 100000;
|
||||||
*/
|
*/
|
||||||
export const DB_MAX_IMAGE_COMMENT_LENGTH = 8192;
|
export const DB_MAX_IMAGE_COMMENT_LENGTH = 8192;
|
||||||
|
|
||||||
|
|
||||||
export const MAX_NOTE_TEXT_LENGTH = Math.min(
|
export const MAX_NOTE_TEXT_LENGTH = Math.min(
|
||||||
config.maxNoteLength ?? 3000,
|
config.maxNoteLength ?? 3000,
|
||||||
DB_MAX_NOTE_TEXT_LENGTH,
|
DB_MAX_NOTE_TEXT_LENGTH,
|
||||||
|
|
|
@ -13,8 +13,8 @@ export default async function () {
|
||||||
ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50));
|
ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50));
|
||||||
});
|
});
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (!meta.enableServerMachineStats) return;
|
if (!instanceMeta.enableServerMachineStats) return;
|
||||||
|
|
||||||
async function tick() {
|
async function tick() {
|
||||||
const stats = {
|
const stats = {
|
||||||
|
|
|
@ -1,9 +1,29 @@
|
||||||
import type { MigrationInterface, QueryRunner } from "typeorm";
|
import type { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import { genRsaKeyPair } from "@/misc/gen-key-pair.js";
|
|
||||||
import { generateUserToken, genIdAt, hashPassword } from "backend-rs";
|
import { generateUserToken, genIdAt, hashPassword } from "backend-rs";
|
||||||
|
|
||||||
|
import * as crypto from "node:crypto";
|
||||||
|
import * as util from "node:util";
|
||||||
|
|
||||||
|
const generateKeyPair = util.promisify(crypto.generateKeyPair);
|
||||||
|
|
||||||
|
async function genRsaKeyPair(modulusLength = 2048) {
|
||||||
|
return await generateKeyPair("rsa", {
|
||||||
|
modulusLength,
|
||||||
|
publicKeyEncoding: {
|
||||||
|
type: "spki",
|
||||||
|
format: "pem",
|
||||||
|
},
|
||||||
|
privateKeyEncoding: {
|
||||||
|
type: "pkcs8",
|
||||||
|
format: "pem",
|
||||||
|
cipher: undefined,
|
||||||
|
passphrase: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function createSystemUser(username: string, queryRunner: QueryRunner) {
|
async function createSystemUser(username: string, queryRunner: QueryRunner) {
|
||||||
const password = uuid();
|
const password = uuid();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
|
||||||
|
|
||||||
const timeout = 30 * 1000;
|
const timeout = 30 * 1000;
|
||||||
const operationTimeout = 60 * 1000;
|
const operationTimeout = 60 * 1000;
|
||||||
const maxSize = config.maxFileSize || 262144000;
|
const maxSize = config.maxFileSize;
|
||||||
|
|
||||||
const req = got
|
const req = got
|
||||||
.stream(url, {
|
.stream(url, {
|
||||||
|
|
|
@ -3,9 +3,9 @@ import type { ILocalUser } from "@/models/entities/user.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
|
|
||||||
export async function fetchProxyAccount(): Promise<ILocalUser | null> {
|
export async function fetchProxyAccount(): Promise<ILocalUser | null> {
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.proxyAccountId == null) return null;
|
if (instanceMeta.proxyAccountId == null) return null;
|
||||||
return (await Users.findOneByOrFail({
|
return (await Users.findOneByOrFail({
|
||||||
id: meta.proxyAccountId,
|
id: instanceMeta.proxyAccountId,
|
||||||
})) as ILocalUser;
|
})) as ILocalUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
import * as crypto from "node:crypto";
|
|
||||||
import * as util from "node:util";
|
|
||||||
|
|
||||||
const generateKeyPair = util.promisify(crypto.generateKeyPair);
|
|
||||||
|
|
||||||
export async function genRsaKeyPair(modulusLength = 2048) {
|
|
||||||
return await generateKeyPair("rsa", {
|
|
||||||
modulusLength,
|
|
||||||
publicKeyEncoding: {
|
|
||||||
type: "spki",
|
|
||||||
format: "pem",
|
|
||||||
},
|
|
||||||
privateKeyEncoding: {
|
|
||||||
type: "pkcs8",
|
|
||||||
format: "pem",
|
|
||||||
cipher: undefined,
|
|
||||||
passphrase: undefined,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function genEcKeyPair(
|
|
||||||
namedCurve:
|
|
||||||
| "prime256v1"
|
|
||||||
| "secp384r1"
|
|
||||||
| "secp521r1"
|
|
||||||
| "curve25519" = "prime256v1",
|
|
||||||
) {
|
|
||||||
return await generateKeyPair("ec", {
|
|
||||||
namedCurve,
|
|
||||||
publicKeyEncoding: {
|
|
||||||
type: "spki",
|
|
||||||
format: "pem",
|
|
||||||
},
|
|
||||||
privateKeyEncoding: {
|
|
||||||
type: "pkcs8",
|
|
||||||
format: "pem",
|
|
||||||
cipher: undefined,
|
|
||||||
passphrase: undefined,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { noteVisibilities } from "@/types.js";
|
|
||||||
|
|
||||||
export type Post = {
|
|
||||||
text: string | undefined;
|
|
||||||
cw: string | null;
|
|
||||||
localOnly: boolean;
|
|
||||||
createdAt: Date;
|
|
||||||
visibility: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function parse(acct: any): Post {
|
|
||||||
return {
|
|
||||||
text: acct.text || undefined,
|
|
||||||
cw: acct.cw,
|
|
||||||
localOnly: acct.localOnly,
|
|
||||||
createdAt: new Date(acct.createdAt),
|
|
||||||
visibility: noteVisibilities.includes(acct.visibility)
|
|
||||||
? acct.visibility
|
|
||||||
: "specified",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toJson(acct: Post): string {
|
|
||||||
return { text: acct.text, cw: acct.cw, localOnly: acct.localOnly }.toString();
|
|
||||||
}
|
|
|
@ -231,13 +231,13 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({
|
||||||
if (url.startsWith(`${config.url}/identicon`)) return url;
|
if (url.startsWith(`${config.url}/identicon`)) return url;
|
||||||
if (url.startsWith(`${config.url}/avatar`)) return url;
|
if (url.startsWith(`${config.url}/avatar`)) return url;
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
const baseUrl = meta
|
const baseUrl = instanceMeta
|
||||||
? meta.objectStorageBaseUrl ??
|
? instanceMeta.objectStorageBaseUrl ??
|
||||||
`${meta.objectStorageUseSsl ? "https" : "http"}://${
|
`${instanceMeta.objectStorageUseSsl ? "https" : "http"}://${
|
||||||
meta.objectStorageEndpoint
|
instanceMeta.objectStorageEndpoint
|
||||||
}${meta.objectStoragePort ? `:${meta.objectStoragePort}` : ""}/${
|
}${instanceMeta.objectStoragePort ? `:${instanceMeta.objectStoragePort}` : ""}/${
|
||||||
meta.objectStorageBucket
|
instanceMeta.objectStorageBucket
|
||||||
}`
|
}`
|
||||||
: null;
|
: null;
|
||||||
if (baseUrl !== null && url.startsWith(baseUrl)) return url;
|
if (baseUrl !== null && url.startsWith(baseUrl)) return url;
|
||||||
|
|
|
@ -155,13 +155,13 @@ webhookDeliverQueue
|
||||||
webhookLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`),
|
webhookLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`),
|
||||||
);
|
);
|
||||||
|
|
||||||
export function deliver(user: ThinUser, content: unknown, to: string | null) {
|
export function deliver(userId: string, content: unknown, to: string | null) {
|
||||||
if (content == null) return null;
|
if (content == null) return null;
|
||||||
if (to == null) return null;
|
if (to == null) return null;
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
user: {
|
user: {
|
||||||
id: user.id,
|
id: userId,
|
||||||
},
|
},
|
||||||
content,
|
content,
|
||||||
to,
|
to,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import * as Post from "@/misc/post.js";
|
|
||||||
import create from "@/services/note/create.js";
|
import create from "@/services/note/create.js";
|
||||||
import { NoteFiles, Users } from "@/models/index.js";
|
import { NoteFiles, Users } from "@/models/index.js";
|
||||||
import type { DbUserImportMastoPostJobData } from "@/queue/types.js";
|
import type { DbUserImportMastoPostJobData } from "@/queue/types.js";
|
||||||
|
@ -10,6 +9,7 @@ import { createImportCkPostJob } from "@/queue/index.js";
|
||||||
import { Notes, NoteEdits } from "@/models/index.js";
|
import { Notes, NoteEdits } from "@/models/index.js";
|
||||||
import type { Note } from "@/models/entities/note.js";
|
import type { Note } from "@/models/entities/note.js";
|
||||||
import { genId } from "backend-rs";
|
import { genId } from "backend-rs";
|
||||||
|
import { noteVisibilities } from "@/types.js";
|
||||||
|
|
||||||
const logger = queueLogger.createSubLogger("import-firefish-post");
|
const logger = queueLogger.createSubLogger("import-firefish-post");
|
||||||
|
|
||||||
|
@ -52,10 +52,15 @@ export async function importCkPost(
|
||||||
logger.info(`Skipped adding file to drive: ${url}`);
|
logger.info(`Skipped adding file to drive: ${url}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { text, cw, localOnly, createdAt, visibility } = Post.parse(post);
|
|
||||||
|
const createdAt = new Date(post.createdAt);
|
||||||
|
const visibility = noteVisibilities.includes(post.visibility)
|
||||||
|
? post.visibility
|
||||||
|
: "specified";
|
||||||
|
|
||||||
let note = await Notes.findOneBy({
|
let note = await Notes.findOneBy({
|
||||||
createdAt: createdAt,
|
createdAt,
|
||||||
text: text,
|
text: post.text || undefined,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -95,16 +100,16 @@ export async function importCkPost(
|
||||||
note = await create(
|
note = await create(
|
||||||
user,
|
user,
|
||||||
{
|
{
|
||||||
createdAt: createdAt,
|
createdAt,
|
||||||
scheduledAt: undefined,
|
scheduledAt: undefined,
|
||||||
files: files.length === 0 ? undefined : files,
|
files: files.length === 0 ? undefined : files,
|
||||||
poll: undefined,
|
poll: undefined,
|
||||||
text: text || undefined,
|
text: post.text || undefined,
|
||||||
reply: post.replyId ? job.data.parent : null,
|
reply: post.replyId ? job.data.parent : null,
|
||||||
renote: post.renoteId ? job.data.parent : null,
|
renote: post.renoteId ? job.data.parent : null,
|
||||||
cw: cw,
|
cw: post.cw,
|
||||||
localOnly,
|
localOnly: post.localOnly,
|
||||||
visibility: visibility,
|
visibility,
|
||||||
visibleUsers: [],
|
visibleUsers: [],
|
||||||
channel: null,
|
channel: null,
|
||||||
apMentions: new Array(0),
|
apMentions: new Array(0),
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type Bull from "bull";
|
||||||
import { In } from "typeorm";
|
import { In } from "typeorm";
|
||||||
import { Mutings } from "@/models/index.js";
|
import { Mutings } from "@/models/index.js";
|
||||||
import { queueLogger } from "../../logger.js";
|
import { queueLogger } from "../../logger.js";
|
||||||
import { publishUserEvent } from "@/services/stream.js";
|
import { publishToUserStream, UserEvent } from "backend-rs";
|
||||||
|
|
||||||
const logger = queueLogger.createSubLogger("check-expired-mutings");
|
const logger = queueLogger.createSubLogger("check-expired-mutings");
|
||||||
|
|
||||||
|
@ -23,9 +23,11 @@ export async function checkExpiredMutings(
|
||||||
id: In(expired.map((m) => m.id)),
|
id: In(expired.map((m) => m.id)),
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const m of expired) {
|
await Promise.all(
|
||||||
publishUserEvent(m.muterId, "unmute", m.mutee!);
|
expired.map((m) =>
|
||||||
}
|
publishToUserStream(m.muterId, UserEvent.Unmute, m.mutee),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("All expired mutings checked.");
|
logger.info("All expired mutings checked.");
|
||||||
|
|
|
@ -15,8 +15,8 @@ import type { UserPublickey } from "@/models/entities/user-publickey.js";
|
||||||
import { verify } from "node:crypto";
|
import { verify } from "node:crypto";
|
||||||
|
|
||||||
export async function hasSignature(req: IncomingMessage): Promise<string> {
|
export async function hasSignature(req: IncomingMessage): Promise<string> {
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
const required = meta.secureMode || meta.privateMode;
|
const required = instanceMeta.secureMode || instanceMeta.privateMode;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
httpSignature.parseRequest(req, { headers: [] });
|
httpSignature.parseRequest(req, { headers: [] });
|
||||||
|
@ -30,8 +30,8 @@ export async function hasSignature(req: IncomingMessage): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkFetch(req: IncomingMessage): Promise<number> {
|
export async function checkFetch(req: IncomingMessage): Promise<number> {
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
if (req.headers.host !== config.host) return 400;
|
if (req.headers.host !== config.host) return 400;
|
||||||
|
|
||||||
let signature;
|
let signature;
|
||||||
|
|
|
@ -148,7 +148,7 @@ export default class DeliverManager {
|
||||||
// skip instances as indicated
|
// skip instances as indicated
|
||||||
if (instancesToSkip.includes(valid.host)) continue;
|
if (instancesToSkip.includes(valid.host)) continue;
|
||||||
|
|
||||||
deliver(this.actor, this.activity, valid.inbox);
|
deliver(this.actor.id, this.activity, valid.inbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,14 +36,14 @@ export async function createImage(
|
||||||
|
|
||||||
apLogger.info(`Creating an image: ${image.url}`);
|
apLogger.info(`Creating an image: ${image.url}`);
|
||||||
|
|
||||||
const instance = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
|
|
||||||
let file = await uploadFromUrl({
|
let file = await uploadFromUrl({
|
||||||
url: image.url,
|
url: image.url,
|
||||||
user: actor,
|
user: actor,
|
||||||
uri: image.url,
|
uri: image.url,
|
||||||
sensitive: image.sensitive,
|
sensitive: image.sensitive,
|
||||||
isLink: !instance.cacheRemoteFiles,
|
isLink: !instanceMeta.cacheRemoteFiles,
|
||||||
comment: truncate(image.name, config.maxCaptionLength),
|
comment: truncate(image.name, config.maxCaptionLength),
|
||||||
usageHint: usage,
|
usageHint: usage,
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,11 +15,13 @@ import { apLogger } from "../logger.js";
|
||||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||||
import {
|
import {
|
||||||
type ImageSize,
|
type ImageSize,
|
||||||
|
NoteEvent,
|
||||||
extractHost,
|
extractHost,
|
||||||
genId,
|
genId,
|
||||||
getImageSizeFromUrl,
|
getImageSizeFromUrl,
|
||||||
isBlockedServer,
|
isBlockedServer,
|
||||||
isSameOrigin,
|
isSameOrigin,
|
||||||
|
publishToNoteStream,
|
||||||
toPuny,
|
toPuny,
|
||||||
} from "backend-rs";
|
} from "backend-rs";
|
||||||
import {
|
import {
|
||||||
|
@ -47,7 +49,6 @@ import { parseAudience } from "../audience.js";
|
||||||
import { extractApMentions } from "./mention.js";
|
import { extractApMentions } from "./mention.js";
|
||||||
import DbResolver from "../db-resolver.js";
|
import DbResolver from "../db-resolver.js";
|
||||||
import { StatusError } from "@/misc/fetch.js";
|
import { StatusError } from "@/misc/fetch.js";
|
||||||
import { publishNoteStream } from "@/services/stream.js";
|
|
||||||
import { extractHashtags } from "@/misc/extract-hashtags.js";
|
import { extractHashtags } from "@/misc/extract-hashtags.js";
|
||||||
import { UserProfiles } from "@/models/index.js";
|
import { UserProfiles } from "@/models/index.js";
|
||||||
import { In } from "typeorm";
|
import { In } from "typeorm";
|
||||||
|
@ -795,7 +796,7 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) {
|
||||||
|
|
||||||
if (publishing) {
|
if (publishing) {
|
||||||
// Publish update event for the updated note details
|
// Publish update event for the updated note details
|
||||||
publishNoteStream(note.id, "updated", {
|
publishToNoteStream(note.id, NoteEvent.Update, {
|
||||||
updatedAt: update.updatedAt,
|
updatedAt: update.updatedAt,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,14 @@ import type { IRemoteUser, CacheableUser } from "@/models/entities/user.js";
|
||||||
import { User } from "@/models/entities/user.js";
|
import { User } from "@/models/entities/user.js";
|
||||||
import type { Emoji } from "@/models/entities/emoji.js";
|
import type { Emoji } from "@/models/entities/emoji.js";
|
||||||
import { UserNotePining } from "@/models/entities/user-note-pining.js";
|
import { UserNotePining } from "@/models/entities/user-note-pining.js";
|
||||||
import { genId, genIdAt, isSameOrigin, toPuny } from "backend-rs";
|
import {
|
||||||
|
genId,
|
||||||
|
genIdAt,
|
||||||
|
InternalEvent,
|
||||||
|
isSameOrigin,
|
||||||
|
publishToInternalStream,
|
||||||
|
toPuny,
|
||||||
|
} from "backend-rs";
|
||||||
import { UserPublickey } from "@/models/entities/user-publickey.js";
|
import { UserPublickey } from "@/models/entities/user-publickey.js";
|
||||||
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
||||||
import { UserProfile } from "@/models/entities/user-profile.js";
|
import { UserProfile } from "@/models/entities/user-profile.js";
|
||||||
|
@ -26,7 +33,6 @@ import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||||
import { truncate } from "@/misc/truncate.js";
|
import { truncate } from "@/misc/truncate.js";
|
||||||
import { StatusError } from "@/misc/fetch.js";
|
import { StatusError } from "@/misc/fetch.js";
|
||||||
import { uriPersonCache } from "@/services/user-cache.js";
|
import { uriPersonCache } from "@/services/user-cache.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
|
||||||
import { db } from "@/db/postgre.js";
|
import { db } from "@/db/postgre.js";
|
||||||
import { apLogger } from "../logger.js";
|
import { apLogger } from "../logger.js";
|
||||||
import { htmlToMfm } from "../misc/html-to-mfm.js";
|
import { htmlToMfm } from "../misc/html-to-mfm.js";
|
||||||
|
@ -611,7 +617,7 @@ export async function updatePerson(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
publishInternalEvent("remoteUserUpdated", { id: user.id });
|
publishToInternalStream(InternalEvent.RemoteUser, { id: user.id });
|
||||||
|
|
||||||
// Hashtag Update
|
// Hashtag Update
|
||||||
updateUsertags(user, tags);
|
updateUsertags(user, tags);
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { config } from "@/config.js";
|
|
||||||
import type { Relay } from "@/models/entities/relay.js";
|
|
||||||
import type { ILocalUser } from "@/models/entities/user.js";
|
|
||||||
|
|
||||||
export function renderFollowRelay(relay: Relay, relayActor: ILocalUser) {
|
|
||||||
const follow = {
|
|
||||||
id: `${config.url}/activities/follow-relay/${relay.id}`,
|
|
||||||
type: "Follow",
|
|
||||||
actor: `${config.url}/users/${relayActor.id}`,
|
|
||||||
object: "https://www.w3.org/ns/activitystreams#Public",
|
|
||||||
};
|
|
||||||
|
|
||||||
return follow;
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { config } from "@/config.js";
|
import { config } from "@/config.js";
|
||||||
import type { User } from "@/models/entities/user.js";
|
|
||||||
|
|
||||||
export default (object: any, user: { id: User["id"] }) => {
|
export const renderUndo = (object: any, userId: string) => {
|
||||||
if (object == null) return null;
|
if (object == null) return null;
|
||||||
const id =
|
const id =
|
||||||
typeof object.id === "string" && object.id.startsWith(config.url)
|
typeof object.id === "string" && object.id.startsWith(config.url)
|
||||||
|
@ -11,7 +10,7 @@ export default (object: any, user: { id: User["id"] }) => {
|
||||||
return {
|
return {
|
||||||
type: "Undo",
|
type: "Undo",
|
||||||
...(id ? { id } : {}),
|
...(id ? { id } : {}),
|
||||||
actor: `${config.url}/users/${user.id}`,
|
actor: `${config.url}/users/${userId}`,
|
||||||
object,
|
object,
|
||||||
published: new Date().toISOString(),
|
published: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { config } from "@/config.js";
|
||||||
import type { ILocalUser } from "@/models/entities/user.js";
|
import type { ILocalUser } from "@/models/entities/user.js";
|
||||||
import {
|
import {
|
||||||
extractHost,
|
extractHost,
|
||||||
getInternalActor,
|
getInstanceActor,
|
||||||
isAllowedServer,
|
isAllowedServer,
|
||||||
isBlockedServer,
|
isBlockedServer,
|
||||||
isSelfHost,
|
isSelfHost,
|
||||||
|
@ -112,7 +112,7 @@ export default class Resolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.user) {
|
if (!this.user) {
|
||||||
this.user = await getInternalActor("instance");
|
this.user = (await getInstanceActor()) as ILocalUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
apLogger.info(
|
apLogger.info(
|
||||||
|
|
|
@ -9,7 +9,7 @@ import renderKey from "@/remote/activitypub/renderer/key.js";
|
||||||
import { renderPerson } from "@/remote/activitypub/renderer/person.js";
|
import { renderPerson } from "@/remote/activitypub/renderer/person.js";
|
||||||
import renderEmoji from "@/remote/activitypub/renderer/emoji.js";
|
import renderEmoji from "@/remote/activitypub/renderer/emoji.js";
|
||||||
import { inbox as processInbox } from "@/queue/index.js";
|
import { inbox as processInbox } from "@/queue/index.js";
|
||||||
import { fetchMeta, getInternalActor, isSelfHost } from "backend-rs";
|
import { fetchMeta, getInstanceActor, isSelfHost } from "backend-rs";
|
||||||
import {
|
import {
|
||||||
Notes,
|
Notes,
|
||||||
Users,
|
Users,
|
||||||
|
@ -242,8 +242,8 @@ router.get("/notes/:note", async (ctx, next) => {
|
||||||
|
|
||||||
ctx.body = renderActivity(await renderNote(note, false));
|
ctx.body = renderActivity(await renderNote(note, false));
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
@ -272,8 +272,8 @@ router.get("/notes/:note/activity", async (ctx) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = renderActivity(await packActivity(note));
|
ctx.body = renderActivity(await packActivity(note));
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
@ -295,7 +295,7 @@ router.get("/users/:user/collections/featured", Featured);
|
||||||
|
|
||||||
// publickey
|
// publickey
|
||||||
router.get("/users/:user/publickey", async (ctx) => {
|
router.get("/users/:user/publickey", async (ctx) => {
|
||||||
const instanceActor = await getInternalActor("instance");
|
const instanceActor = (await getInstanceActor()) as ILocalUser;
|
||||||
if (ctx.params.user === instanceActor.id) {
|
if (ctx.params.user === instanceActor.id) {
|
||||||
ctx.body = renderActivity(
|
ctx.body = renderActivity(
|
||||||
renderKey(instanceActor, await getUserKeypair(instanceActor.id)),
|
renderKey(instanceActor, await getUserKeypair(instanceActor.id)),
|
||||||
|
@ -327,8 +327,8 @@ router.get("/users/:user/publickey", async (ctx) => {
|
||||||
|
|
||||||
if (Users.isLocalUser(user)) {
|
if (Users.isLocalUser(user)) {
|
||||||
ctx.body = renderActivity(renderKey(user, keypair));
|
ctx.body = renderActivity(renderKey(user, keypair));
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
@ -347,8 +347,8 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = renderActivity(await renderPerson(user as ILocalUser));
|
ctx.body = renderActivity(await renderPerson(user as ILocalUser));
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
@ -359,7 +359,7 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) {
|
||||||
router.get("/users/:user", async (ctx, next) => {
|
router.get("/users/:user", async (ctx, next) => {
|
||||||
if (!isActivityPubReq(ctx)) return await next();
|
if (!isActivityPubReq(ctx)) return await next();
|
||||||
|
|
||||||
const instanceActor = await getInternalActor("instance");
|
const instanceActor = (await getInstanceActor()) as ILocalUser;
|
||||||
if (ctx.params.user === instanceActor.id) {
|
if (ctx.params.user === instanceActor.id) {
|
||||||
await userInfo(ctx, instanceActor);
|
await userInfo(ctx, instanceActor);
|
||||||
return;
|
return;
|
||||||
|
@ -386,7 +386,7 @@ router.get("/@:user", async (ctx, next) => {
|
||||||
if (!isActivityPubReq(ctx)) return await next();
|
if (!isActivityPubReq(ctx)) return await next();
|
||||||
|
|
||||||
if (ctx.params.user === "instance.actor") {
|
if (ctx.params.user === "instance.actor") {
|
||||||
const instanceActor = await getInternalActor("instance");
|
const instanceActor = (await getInstanceActor()) as ILocalUser;
|
||||||
await userInfo(ctx, instanceActor);
|
await userInfo(ctx, instanceActor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ router.get("/@:user", async (ctx, next) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/actor", async (ctx, _next) => {
|
router.get("/actor", async (ctx, _next) => {
|
||||||
const instanceActor = await getInternalActor("instance");
|
const instanceActor = (await getInstanceActor()) as ILocalUser;
|
||||||
await userInfo(ctx, instanceActor);
|
await userInfo(ctx, instanceActor);
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@ -431,8 +431,8 @@ router.get("/emojis/:emoji", async (ctx) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = renderActivity(renderEmoji(emoji));
|
ctx.body = renderActivity(renderEmoji(emoji));
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
@ -463,8 +463,8 @@ router.get("/likes/:like", async (ctx) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = renderActivity(await renderLike(reaction, note));
|
ctx.body = renderActivity(await renderLike(reaction, note));
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
@ -501,8 +501,8 @@ router.get(
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = renderActivity(renderFollow(follower, followee));
|
ctx.body = renderActivity(renderFollow(follower, followee));
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
@ -544,8 +544,8 @@ router.get("/follows/:followRequestId", async (ctx: Router.RouterContext) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
|
|
@ -57,8 +57,8 @@ export default async (ctx: Router.RouterContext) => {
|
||||||
|
|
||||||
ctx.body = renderActivity(rendered);
|
ctx.body = renderActivity(rendered);
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
|
|
@ -110,8 +110,8 @@ export default async (ctx: Router.RouterContext) => {
|
||||||
ctx.body = renderActivity(rendered);
|
ctx.body = renderActivity(rendered);
|
||||||
setResponseType(ctx);
|
setResponseType(ctx);
|
||||||
}
|
}
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
|
|
@ -110,8 +110,8 @@ export default async (ctx: Router.RouterContext) => {
|
||||||
ctx.body = renderActivity(rendered);
|
ctx.body = renderActivity(rendered);
|
||||||
setResponseType(ctx);
|
setResponseType(ctx);
|
||||||
}
|
}
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
|
|
@ -117,8 +117,8 @@ export default async (ctx: Router.RouterContext) => {
|
||||||
|
|
||||||
setResponseType(ctx);
|
setResponseType(ctx);
|
||||||
}
|
}
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (meta.secureMode || meta.privateMode) {
|
if (instanceMeta.secureMode || instanceMeta.privateMode) {
|
||||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||||
} else {
|
} else {
|
||||||
ctx.set("Cache-Control", "public, max-age=180");
|
ctx.set("Cache-Control", "public, max-age=180");
|
||||||
|
|
|
@ -117,9 +117,9 @@ export default async (
|
||||||
}
|
}
|
||||||
|
|
||||||
// private mode
|
// private mode
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (
|
if (
|
||||||
meta.privateMode &&
|
instanceMeta.privateMode &&
|
||||||
ep.meta.requireCredentialPrivateMode &&
|
ep.meta.requireCredentialPrivateMode &&
|
||||||
user == null
|
user == null
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
import {
|
import {
|
||||||
publishToChatStream,
|
publishToChatStream,
|
||||||
publishToGroupChatStream,
|
publishToGroupChatStream,
|
||||||
publishToChatIndexStream,
|
publishToChatIndexStream,
|
||||||
sendPushNotification,
|
sendPushNotification,
|
||||||
|
publishToMainStream,
|
||||||
|
Event,
|
||||||
} from "backend-rs";
|
} from "backend-rs";
|
||||||
import type { User, IRemoteUser } from "@/models/entities/user.js";
|
import type { User, IRemoteUser } from "@/models/entities/user.js";
|
||||||
import type { MessagingMessage } from "@/models/entities/messaging-message.js";
|
import type { MessagingMessage } from "@/models/entities/messaging-message.js";
|
||||||
|
@ -61,7 +62,7 @@ export async function readUserMessagingMessage(
|
||||||
|
|
||||||
if (!(await Users.getHasUnreadMessagingMessage(userId))) {
|
if (!(await Users.getHasUnreadMessagingMessage(userId))) {
|
||||||
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
||||||
publishMainStream(userId, "readAllMessagingMessages");
|
await publishToMainStream(userId, Event.ReadAllChats, {});
|
||||||
await sendPushNotification(userId, "readAllChats", {});
|
await sendPushNotification(userId, "readAllChats", {});
|
||||||
} else {
|
} else {
|
||||||
// そのユーザーとのメッセージで未読がなければイベント発行
|
// そのユーザーとのメッセージで未読がなければイベント発行
|
||||||
|
@ -135,7 +136,7 @@ export async function readGroupMessagingMessage(
|
||||||
|
|
||||||
if (!(await Users.getHasUnreadMessagingMessage(userId))) {
|
if (!(await Users.getHasUnreadMessagingMessage(userId))) {
|
||||||
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
||||||
publishMainStream(userId, "readAllMessagingMessages");
|
await publishToMainStream(userId, Event.ReadAllChats, {});
|
||||||
await sendPushNotification(userId, "readAllChats", {});
|
await sendPushNotification(userId, "readAllChats", {});
|
||||||
} else {
|
} else {
|
||||||
// そのグループにおいて未読がなければイベント発行
|
// そのグループにおいて未読がなければイベント発行
|
||||||
|
@ -173,10 +174,10 @@ export async function deliverReadActivity(
|
||||||
undefined,
|
undefined,
|
||||||
contents,
|
contents,
|
||||||
);
|
);
|
||||||
deliver(user, renderActivity(collection), recipient.inbox);
|
deliver(user.id, renderActivity(collection), recipient.inbox);
|
||||||
} else {
|
} else {
|
||||||
for (const content of contents) {
|
for (const content of contents) {
|
||||||
deliver(user, renderActivity(content), recipient.inbox);
|
deliver(user.id, renderActivity(content), recipient.inbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { In } from "typeorm";
|
import { In } from "typeorm";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream, sendPushNotification } from "backend-rs";
|
||||||
import { sendPushNotification } from "backend-rs";
|
|
||||||
import type { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import type { Notification } from "@/models/entities/notification.js";
|
import type { Notification } from "@/models/entities/notification.js";
|
||||||
import { Notifications, Users } from "@/models/index.js";
|
import { Notifications, Users } from "@/models/index.js";
|
||||||
|
@ -46,7 +45,7 @@ export async function readNotificationByQuery(
|
||||||
}
|
}
|
||||||
|
|
||||||
function postReadAllNotifications(userId: User["id"]) {
|
function postReadAllNotifications(userId: User["id"]) {
|
||||||
publishMainStream(userId, "readAllNotifications");
|
publishToMainStream(userId, Event.ReadAllNotifications, {});
|
||||||
return sendPushNotification(userId, "readAllNotifications", {});
|
return sendPushNotification(userId, "readAllNotifications", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +53,7 @@ function postReadNotifications(
|
||||||
userId: User["id"],
|
userId: User["id"],
|
||||||
notificationIds: Notification["id"][],
|
notificationIds: Notification["id"][],
|
||||||
) {
|
) {
|
||||||
publishMainStream(userId, "readNotifications", notificationIds);
|
publishToMainStream(userId, Event.ReadNotifications, notificationIds);
|
||||||
return sendPushNotification(userId, "readNotifications", {
|
return sendPushNotification(userId, "readNotifications", {
|
||||||
notificationIds,
|
notificationIds,
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,8 +3,7 @@ import type Koa from "koa";
|
||||||
import { config } from "@/config.js";
|
import { config } from "@/config.js";
|
||||||
import type { ILocalUser } from "@/models/entities/user.js";
|
import type { ILocalUser } from "@/models/entities/user.js";
|
||||||
import { Signins } from "@/models/index.js";
|
import { Signins } from "@/models/index.js";
|
||||||
import { genIdAt } from "backend-rs";
|
import { Event, genIdAt, publishToMainStream } from "backend-rs";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
|
|
||||||
export default function (ctx: Koa.Context, user: ILocalUser, redirect = false) {
|
export default function (ctx: Koa.Context, user: ILocalUser, redirect = false) {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
|
@ -40,6 +39,6 @@ export default function (ctx: Koa.Context, user: ILocalUser, redirect = false) {
|
||||||
}).then((x) => Signins.findOneByOrFail(x.identifiers[0]));
|
}).then((x) => Signins.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
// Publish signin event
|
// Publish signin event
|
||||||
publishMainStream(user.id, "signin", await Signins.pack(record));
|
publishToMainStream(user.id, Event.Signin, await Signins.pack(record));
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
import { doPostSuspend } from "@/services/suspend-user.js";
|
import { doPostSuspend } from "@/services/suspend-user.js";
|
||||||
import { publishUserEvent } from "@/services/stream.js";
|
import { publishToUserStream, UserEvent } from "backend-rs";
|
||||||
import { createDeleteAccountJob } from "@/queue/index.js";
|
import { createDeleteAccountJob } from "@/queue/index.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -53,6 +53,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
|
|
||||||
if (Users.isLocalUser(user)) {
|
if (Users.isLocalUser(user)) {
|
||||||
// Terminate streaming
|
// Terminate streaming
|
||||||
publishUserEvent(user.id, "terminate", {});
|
await publishToUserStream(user.id, UserEvent.Disconnect, {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Users, UserProfiles } from "@/models/index.js";
|
import { Users, UserProfiles } from "@/models/index.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -36,5 +36,5 @@ export default define(meta, paramDef, async (ps) => {
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Users, UserProfiles, UserSecurityKeys } from "@/models/index.js";
|
import { Users, UserProfiles, UserSecurityKeys } from "@/models/index.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -38,5 +38,5 @@ export default define(meta, paramDef, async (ps) => {
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import { InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin"],
|
tags: ["admin"],
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
driveCapacityOverrideMb: ps.overrideMb,
|
driveCapacityOverrideMb: ps.overrideMb,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent("localUserUpdated", {
|
publishToInternalStream(InternalEvent.LocalUser, {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import define from "@/server/api/define.js";
|
||||||
import { Emojis, DriveFiles } from "@/models/index.js";
|
import { Emojis, DriveFiles } from "@/models/index.js";
|
||||||
import {
|
import {
|
||||||
type ImageSize,
|
type ImageSize,
|
||||||
genId,
|
genIdAt,
|
||||||
getImageSizeFromUrl,
|
getImageSizeFromUrl,
|
||||||
publishToBroadcastStream,
|
publishToBroadcastStream,
|
||||||
} from "backend-rs";
|
} from "backend-rs";
|
||||||
|
@ -36,7 +36,31 @@ export const meta = {
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
fileId: { type: "string", format: "misskey:id" },
|
fileId: {
|
||||||
|
type: "string",
|
||||||
|
format: "misskey:id",
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
type: "string",
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
|
aliases: {
|
||||||
|
type: "array",
|
||||||
|
nullable: false,
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
license: {
|
||||||
|
type: "string",
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
required: ["fileId"],
|
required: ["fileId"],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,9 +74,12 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
|
|
||||||
if (file == null) throw new ApiError(meta.errors.noSuchFile);
|
if (file == null) throw new ApiError(meta.errors.noSuchFile);
|
||||||
|
|
||||||
const name = file.name.split(".")[0].match(/^[a-z0-9_]+$/)
|
const name =
|
||||||
? file.name.split(".")[0]
|
ps.name != null
|
||||||
: `_${rndstr("a-z0-9", 8)}_`;
|
? ps.name
|
||||||
|
: file.name.split(".")[0].match(/^[a-z0-9_]+$/)
|
||||||
|
? file.name.split(".")[0]
|
||||||
|
: `_${rndstr("a-z0-9", 8)}_`;
|
||||||
|
|
||||||
let size: ImageSize | null = null;
|
let size: ImageSize | null = null;
|
||||||
try {
|
try {
|
||||||
|
@ -62,17 +89,19 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
apiLogger.debug(inspect(err));
|
apiLogger.debug(inspect(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
const emoji = await Emojis.insert({
|
const emoji = await Emojis.insert({
|
||||||
id: genId(),
|
id: genIdAt(now),
|
||||||
updatedAt: new Date(),
|
updatedAt: now,
|
||||||
name: name,
|
name: name,
|
||||||
category: null,
|
category: ps.category ?? null,
|
||||||
host: null,
|
host: null,
|
||||||
aliases: [],
|
aliases: ps.aliases ?? [],
|
||||||
originalUrl: file.url,
|
originalUrl: file.url,
|
||||||
publicUrl: file.webpublicUrl ?? file.url,
|
publicUrl: file.webpublicUrl ?? file.url,
|
||||||
type: file.webpublicType ?? file.type,
|
type: file.webpublicType ?? file.type,
|
||||||
license: null,
|
license: ps.license ?? null,
|
||||||
width: size?.width || null,
|
width: size?.width || null,
|
||||||
height: size?.height || null,
|
height: size?.height || null,
|
||||||
}).then((x) => Emojis.findOneByOrFail(x.identifiers[0]));
|
}).then((x) => Emojis.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
|
@ -470,97 +470,98 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async () => {
|
export default define(meta, paramDef, async () => {
|
||||||
const instance = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
maintainerName: instance.maintainerName,
|
maintainerName: instanceMeta.maintainerName,
|
||||||
maintainerEmail: instance.maintainerEmail,
|
maintainerEmail: instanceMeta.maintainerEmail,
|
||||||
version: config.version,
|
version: config.version,
|
||||||
name: instance.name,
|
name: instanceMeta.name,
|
||||||
uri: config.url,
|
uri: config.url,
|
||||||
description: instance.description,
|
description: instanceMeta.description,
|
||||||
langs: instance.langs,
|
langs: instanceMeta.langs,
|
||||||
tosUrl: instance.tosUrl,
|
tosUrl: instanceMeta.tosUrl,
|
||||||
moreUrls: instance.moreUrls,
|
moreUrls: instanceMeta.moreUrls,
|
||||||
repositoryUrl: instance.repositoryUrl,
|
repositoryUrl: instanceMeta.repositoryUrl,
|
||||||
feedbackUrl: instance.feedbackUrl,
|
feedbackUrl: instanceMeta.feedbackUrl,
|
||||||
disableRegistration: instance.disableRegistration,
|
disableRegistration: instanceMeta.disableRegistration,
|
||||||
disableLocalTimeline: instance.disableLocalTimeline,
|
disableLocalTimeline: instanceMeta.disableLocalTimeline,
|
||||||
disableRecommendedTimeline: instance.disableRecommendedTimeline,
|
disableRecommendedTimeline: instanceMeta.disableRecommendedTimeline,
|
||||||
disableGlobalTimeline: instance.disableGlobalTimeline,
|
disableGlobalTimeline: instanceMeta.disableGlobalTimeline,
|
||||||
enableGuestTimeline: instance.enableGuestTimeline,
|
enableGuestTimeline: instanceMeta.enableGuestTimeline,
|
||||||
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
|
driveCapacityPerLocalUserMb: instanceMeta.localDriveCapacityMb,
|
||||||
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
|
driveCapacityPerRemoteUserMb: instanceMeta.remoteDriveCapacityMb,
|
||||||
antennaLimit: instance.antennaLimit,
|
antennaLimit: instanceMeta.antennaLimit,
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
emailRequiredForSignup: instanceMeta.emailRequiredForSignup,
|
||||||
enableHcaptcha: instance.enableHcaptcha,
|
enableHcaptcha: instanceMeta.enableHcaptcha,
|
||||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
hcaptchaSiteKey: instanceMeta.hcaptchaSiteKey,
|
||||||
enableRecaptcha: instance.enableRecaptcha,
|
enableRecaptcha: instanceMeta.enableRecaptcha,
|
||||||
recaptchaSiteKey: instance.recaptchaSiteKey,
|
recaptchaSiteKey: instanceMeta.recaptchaSiteKey,
|
||||||
swPublickey: instance.swPublicKey,
|
swPublickey: instanceMeta.swPublicKey,
|
||||||
themeColor: instance.themeColor,
|
themeColor: instanceMeta.themeColor,
|
||||||
mascotImageUrl: instance.mascotImageUrl,
|
mascotImageUrl: instanceMeta.mascotImageUrl,
|
||||||
bannerUrl: instance.bannerUrl,
|
bannerUrl: instanceMeta.bannerUrl,
|
||||||
errorImageUrl: instance.errorImageUrl,
|
errorImageUrl: instanceMeta.errorImageUrl,
|
||||||
iconUrl: instance.iconUrl,
|
iconUrl: instanceMeta.iconUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
backgroundImageUrl: instanceMeta.backgroundImageUrl,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
logoImageUrl: instanceMeta.logoImageUrl,
|
||||||
maxNoteTextLength: config.maxNoteLength, // for backward compatibility
|
maxNoteTextLength: config.maxNoteLength, // for backward compatibility
|
||||||
maxCaptionTextLength: config.maxCaptionLength,
|
maxCaptionTextLength: config.maxCaptionLength,
|
||||||
defaultLightTheme: instance.defaultLightTheme,
|
defaultLightTheme: instanceMeta.defaultLightTheme,
|
||||||
defaultDarkTheme: instance.defaultDarkTheme,
|
defaultDarkTheme: instanceMeta.defaultDarkTheme,
|
||||||
enableEmail: instance.enableEmail,
|
enableEmail: instanceMeta.enableEmail,
|
||||||
enableServiceWorker: instance.enableServiceWorker,
|
enableServiceWorker: instanceMeta.enableServiceWorker,
|
||||||
translatorAvailable:
|
translatorAvailable:
|
||||||
instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null,
|
instanceMeta.deeplAuthKey != null ||
|
||||||
pinnedPages: instance.pinnedPages,
|
instanceMeta.libreTranslateApiUrl != null,
|
||||||
pinnedClipId: instance.pinnedClipId,
|
pinnedPages: instanceMeta.pinnedPages,
|
||||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
pinnedClipId: instanceMeta.pinnedClipId,
|
||||||
markLocalFilesNsfwByDefault: instance.markLocalFilesNsfwByDefault,
|
cacheRemoteFiles: instanceMeta.cacheRemoteFiles,
|
||||||
defaultReaction: instance.defaultReaction,
|
markLocalFilesNsfwByDefault: instanceMeta.markLocalFilesNsfwByDefault,
|
||||||
recommendedInstances: instance.recommendedInstances,
|
defaultReaction: instanceMeta.defaultReaction,
|
||||||
pinnedUsers: instance.pinnedUsers,
|
recommendedInstances: instanceMeta.recommendedInstances,
|
||||||
customMOTD: instance.customMotd,
|
pinnedUsers: instanceMeta.pinnedUsers,
|
||||||
customSplashIcons: instance.customSplashIcons,
|
customMOTD: instanceMeta.customMotd,
|
||||||
hiddenTags: instance.hiddenTags,
|
customSplashIcons: instanceMeta.customSplashIcons,
|
||||||
blockedHosts: instance.blockedHosts,
|
hiddenTags: instanceMeta.hiddenTags,
|
||||||
silencedHosts: instance.silencedHosts,
|
blockedHosts: instanceMeta.blockedHosts,
|
||||||
allowedHosts: instance.allowedHosts,
|
silencedHosts: instanceMeta.silencedHosts,
|
||||||
privateMode: instance.privateMode,
|
allowedHosts: instanceMeta.allowedHosts,
|
||||||
secureMode: instance.secureMode,
|
privateMode: instanceMeta.privateMode,
|
||||||
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
secureMode: instanceMeta.secureMode,
|
||||||
recaptchaSecretKey: instance.recaptchaSecretKey,
|
hcaptchaSecretKey: instanceMeta.hcaptchaSecretKey,
|
||||||
proxyAccountId: instance.proxyAccountId,
|
recaptchaSecretKey: instanceMeta.recaptchaSecretKey,
|
||||||
summalyProxy: instance.summalyProxy,
|
proxyAccountId: instanceMeta.proxyAccountId,
|
||||||
email: instance.email,
|
summalyProxy: instanceMeta.summalyProxy,
|
||||||
smtpSecure: instance.smtpSecure,
|
email: instanceMeta.email,
|
||||||
smtpHost: instance.smtpHost,
|
smtpSecure: instanceMeta.smtpSecure,
|
||||||
smtpPort: instance.smtpPort,
|
smtpHost: instanceMeta.smtpHost,
|
||||||
smtpUser: instance.smtpUser,
|
smtpPort: instanceMeta.smtpPort,
|
||||||
smtpPass: instance.smtpPass,
|
smtpUser: instanceMeta.smtpUser,
|
||||||
swPrivateKey: instance.swPrivateKey,
|
smtpPass: instanceMeta.smtpPass,
|
||||||
useObjectStorage: instance.useObjectStorage,
|
swPrivateKey: instanceMeta.swPrivateKey,
|
||||||
objectStorageBaseUrl: instance.objectStorageBaseUrl,
|
useObjectStorage: instanceMeta.useObjectStorage,
|
||||||
objectStorageBucket: instance.objectStorageBucket,
|
objectStorageBaseUrl: instanceMeta.objectStorageBaseUrl,
|
||||||
objectStoragePrefix: instance.objectStoragePrefix,
|
objectStorageBucket: instanceMeta.objectStorageBucket,
|
||||||
objectStorageEndpoint: instance.objectStorageEndpoint,
|
objectStoragePrefix: instanceMeta.objectStoragePrefix,
|
||||||
objectStorageRegion: instance.objectStorageRegion,
|
objectStorageEndpoint: instanceMeta.objectStorageEndpoint,
|
||||||
objectStoragePort: instance.objectStoragePort,
|
objectStorageRegion: instanceMeta.objectStorageRegion,
|
||||||
objectStorageAccessKey: instance.objectStorageAccessKey,
|
objectStoragePort: instanceMeta.objectStoragePort,
|
||||||
objectStorageSecretKey: instance.objectStorageSecretKey,
|
objectStorageAccessKey: instanceMeta.objectStorageAccessKey,
|
||||||
objectStorageUseSSL: instance.objectStorageUseSsl,
|
objectStorageSecretKey: instanceMeta.objectStorageSecretKey,
|
||||||
objectStorageUseProxy: instance.objectStorageUseProxy,
|
objectStorageUseSSL: instanceMeta.objectStorageUseSsl,
|
||||||
objectStorageSetPublicRead: instance.objectStorageSetPublicRead,
|
objectStorageUseProxy: instanceMeta.objectStorageUseProxy,
|
||||||
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
|
objectStorageSetPublicRead: instanceMeta.objectStorageSetPublicRead,
|
||||||
deeplAuthKey: instance.deeplAuthKey,
|
objectStorageS3ForcePathStyle: instanceMeta.objectStorageS3ForcePathStyle,
|
||||||
deeplIsPro: instance.deeplIsPro,
|
deeplAuthKey: instanceMeta.deeplAuthKey,
|
||||||
libreTranslateApiUrl: instance.libreTranslateApiUrl,
|
deeplIsPro: instanceMeta.deeplIsPro,
|
||||||
libreTranslateApiKey: instance.libreTranslateApiKey,
|
libreTranslateApiUrl: instanceMeta.libreTranslateApiUrl,
|
||||||
enableIpLogging: instance.enableIpLogging,
|
libreTranslateApiKey: instanceMeta.libreTranslateApiKey,
|
||||||
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
enableIpLogging: instanceMeta.enableIpLogging,
|
||||||
experimentalFeatures: instance.experimentalFeatures,
|
enableActiveEmailValidation: instanceMeta.enableActiveEmailValidation,
|
||||||
enableServerMachineStats: instance.enableServerMachineStats,
|
experimentalFeatures: instanceMeta.experimentalFeatures,
|
||||||
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
enableServerMachineStats: instanceMeta.enableServerMachineStats,
|
||||||
donationLink: instance.donationLink,
|
enableIdenticonGeneration: instanceMeta.enableIdenticonGeneration,
|
||||||
|
donationLink: instanceMeta.donationLink,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import { InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin"],
|
tags: ["admin"],
|
||||||
|
@ -32,7 +32,7 @@ export default define(meta, paramDef, async (ps) => {
|
||||||
isModerator: true,
|
isModerator: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent("userChangeModeratorState", {
|
publishToInternalStream(InternalEvent.Moderator, {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isModerator: true,
|
isModerator: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import { InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin"],
|
tags: ["admin"],
|
||||||
|
@ -28,7 +28,7 @@ export default define(meta, paramDef, async (ps) => {
|
||||||
isModerator: false,
|
isModerator: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent("userChangeModeratorState", {
|
publishToInternalStream(InternalEvent.Moderator, {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isModerator: false,
|
isModerator: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { AbuseUserReports, Users } from "@/models/index.js";
|
import { AbuseUserReports, Users } from "@/models/index.js";
|
||||||
import { getInternalActor } from "backend-rs";
|
import { getInstanceActor } from "backend-rs";
|
||||||
import { deliver } from "@/queue/index.js";
|
import { deliver } from "@/queue/index.js";
|
||||||
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
||||||
import { renderFlag } from "@/remote/activitypub/renderer/flag.js";
|
import { renderFlag } from "@/remote/activitypub/renderer/flag.js";
|
||||||
|
import { ILocalUser } from "@/models/entities/user";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin"],
|
tags: ["admin"],
|
||||||
|
@ -29,11 +30,11 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.forward && report.targetUserHost != null) {
|
if (ps.forward && report.targetUserHost != null) {
|
||||||
const actor = await getInternalActor("instance");
|
const actor = (await getInstanceActor()) as ILocalUser;
|
||||||
const targetUser = await Users.findOneByOrFail({ id: report.targetUserId });
|
const targetUser = await Users.findOneByOrFail({ id: report.targetUserId });
|
||||||
|
|
||||||
deliver(
|
deliver(
|
||||||
actor,
|
actor.id,
|
||||||
renderActivity(renderFlag(actor, [targetUser.uri!], report.comment)),
|
renderActivity(renderFlag(actor, [targetUser.uri!], report.comment)),
|
||||||
targetUser.inbox,
|
targetUser.inbox,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
|
||||||
import type { EmojiModPerm } from "@/models/entities/user.js";
|
import type { EmojiModPerm } from "@/models/entities/user.js";
|
||||||
import { unsafeCast } from "@/prelude/unsafe-cast.js";
|
import { unsafeCast } from "@/prelude/unsafe-cast.js";
|
||||||
|
|
||||||
|
@ -36,9 +35,4 @@ export default define(meta, paramDef, async (ps) => {
|
||||||
await Users.update(user.id, {
|
await Users.update(user.id, {
|
||||||
emojiModPerm: unsafeCast<EmojiModPerm>(ps.emojiModPerm),
|
emojiModPerm: unsafeCast<EmojiModPerm>(ps.emojiModPerm),
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent("userChangeModeratorState", {
|
|
||||||
id: user.id,
|
|
||||||
isModerator: true,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import { InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin"],
|
tags: ["admin"],
|
||||||
|
@ -33,7 +33,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
isSilenced: true,
|
isSilenced: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent("userChangeSilencedState", {
|
publishToInternalStream(InternalEvent.Silence, {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isSilenced: true,
|
isSilenced: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Users, Followings, Notifications } from "@/models/index.js";
|
||||||
import type { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
||||||
import { doPostSuspend } from "@/services/suspend-user.js";
|
import { doPostSuspend } from "@/services/suspend-user.js";
|
||||||
import { publishUserEvent } from "@/services/stream.js";
|
import { publishToUserStream, UserEvent } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin"],
|
tags: ["admin"],
|
||||||
|
@ -46,7 +46,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
|
|
||||||
// Terminate streaming
|
// Terminate streaming
|
||||||
if (Users.isLocalUser(user)) {
|
if (Users.isLocalUser(user)) {
|
||||||
publishUserEvent(user.id, "terminate", {});
|
await publishToUserStream(user.id, UserEvent.Disconnect, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users } from "@/models/index.js";
|
import { Users } from "@/models/index.js";
|
||||||
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import { InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin"],
|
tags: ["admin"],
|
||||||
|
@ -29,7 +29,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
isSilenced: false,
|
isSilenced: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent("userChangeSilencedState", {
|
publishToInternalStream(InternalEvent.Silence, {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isSilenced: false,
|
isSilenced: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { fetchMeta, genIdAt, updateAntennaCache } from "backend-rs";
|
import {
|
||||||
|
fetchMeta,
|
||||||
|
genIdAt,
|
||||||
|
InternalEvent,
|
||||||
|
publishToInternalStream,
|
||||||
|
updateAntennaCache,
|
||||||
|
} from "backend-rs";
|
||||||
import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js";
|
import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["antennas"],
|
tags: ["antennas"],
|
||||||
|
@ -123,12 +128,12 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
let userList;
|
let userList;
|
||||||
let userGroupJoining;
|
let userGroupJoining;
|
||||||
|
|
||||||
const instance = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
|
|
||||||
const antennas = await Antennas.findBy({
|
const antennas = await Antennas.findBy({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
if (antennas.length >= instance.antennaLimit) {
|
if (antennas.length >= instanceMeta.antennaLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyAntennas);
|
throw new ApiError(meta.errors.tooManyAntennas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +177,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
notify: ps.notify,
|
notify: ps.notify,
|
||||||
}).then((x) => Antennas.findOneByOrFail(x.identifiers[0]));
|
}).then((x) => Antennas.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
publishInternalEvent("antennaCreated", antenna);
|
await publishToInternalStream(InternalEvent.AntennaCreated, antenna);
|
||||||
await updateAntennaCache();
|
await updateAntennaCache();
|
||||||
|
|
||||||
return await Antennas.pack(antenna);
|
return await Antennas.pack(antenna);
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { Antennas } from "@/models/index.js";
|
import { Antennas } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import {
|
||||||
import { updateAntennaCache } from "backend-rs";
|
InternalEvent,
|
||||||
|
publishToInternalStream,
|
||||||
|
updateAntennaCache,
|
||||||
|
} from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["antennas"],
|
tags: ["antennas"],
|
||||||
|
@ -40,6 +43,6 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
|
||||||
await Antennas.delete(antenna.id);
|
await Antennas.delete(antenna.id);
|
||||||
|
|
||||||
publishInternalEvent("antennaDeleted", antenna);
|
await publishToInternalStream(InternalEvent.AntennaDeleted, antenna);
|
||||||
await updateAntennaCache();
|
await updateAntennaCache();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js";
|
import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import {
|
||||||
import { updateAntennaCache } from "backend-rs";
|
InternalEvent,
|
||||||
|
publishToInternalStream,
|
||||||
|
updateAntennaCache,
|
||||||
|
} from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["antennas"],
|
tags: ["antennas"],
|
||||||
|
@ -163,8 +166,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
notify: ps.notify,
|
notify: ps.notify,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent(
|
await publishToInternalStream(
|
||||||
"antennaUpdated",
|
InternalEvent.AntennaUpdated,
|
||||||
await Antennas.findOneByOrFail({ id: antenna.id }),
|
await Antennas.findOneByOrFail({ id: antenna.id }),
|
||||||
);
|
);
|
||||||
await updateAntennaCache();
|
await updateAntennaCache();
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { Channels, ChannelFollowings } from "@/models/index.js";
|
import { Channels, ChannelFollowings } from "@/models/index.js";
|
||||||
import { genIdAt } from "backend-rs";
|
import { genIdAt, publishToUserStream, UserEvent } from "backend-rs";
|
||||||
import { publishUserEvent } from "@/services/stream.js";
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["channels"],
|
tags: ["channels"],
|
||||||
|
@ -46,5 +45,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
followeeId: channel.id,
|
followeeId: channel.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishUserEvent(user.id, "followChannel", channel);
|
await publishToUserStream(user.id, UserEvent.FollowChannel, channel);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { Channels, ChannelFollowings } from "@/models/index.js";
|
import { Channels, ChannelFollowings } from "@/models/index.js";
|
||||||
import { publishUserEvent } from "@/services/stream.js";
|
import { publishToUserStream, UserEvent } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["channels"],
|
tags: ["channels"],
|
||||||
|
@ -41,5 +41,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
followeeId: channel.id,
|
followeeId: channel.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishUserEvent(user.id, "unfollowChannel", channel);
|
await publishToUserStream(user.id, UserEvent.UnfollowChannel, channel);
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async () => {
|
export default define(meta, paramDef, async () => {
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
const motd = await Promise.all(meta.customMotd.map((x) => x));
|
const motd = await Promise.all(instanceMeta.customMotd.map((x) => x));
|
||||||
return motd;
|
return motd;
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async () => {
|
export default define(meta, paramDef, async () => {
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
const icons = await Promise.all(meta.customSplashIcons.map((x) => x));
|
const icons = await Promise.all(instanceMeta.customSplashIcons.map((x) => x));
|
||||||
return icons;
|
return icons;
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
export default define(meta, paramDef, async (ps, user) => {
|
||||||
const instance = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
|
|
||||||
// Calculate drive usage
|
// Calculate drive usage
|
||||||
const usage = await DriveFiles.calcDriveUsageOf(user.id);
|
const usage = await DriveFiles.calcDriveUsageOf(user.id);
|
||||||
|
@ -44,7 +44,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
capacity:
|
capacity:
|
||||||
1024 *
|
1024 *
|
||||||
1024 *
|
1024 *
|
||||||
(user.driveCapacityOverrideMb || instance.localDriveCapacityMb),
|
(user.driveCapacityOverrideMb || instanceMeta.localDriveCapacityMb),
|
||||||
usage: usage,
|
usage: usage,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { uploadFromUrl } from "@/services/drive/upload-from-url.js";
|
import { uploadFromUrl } from "@/services/drive/upload-from-url.js";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { DriveFiles } from "@/models/index.js";
|
import { DriveFiles } from "@/models/index.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
import { HOUR } from "@/const.js";
|
import { HOUR } from "@/const.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -24,6 +24,7 @@ export const paramDef = {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
url: { type: "string" },
|
url: { type: "string" },
|
||||||
|
name: { type: "string" },
|
||||||
folderId: {
|
folderId: {
|
||||||
type: "string",
|
type: "string",
|
||||||
format: "misskey:id",
|
format: "misskey:id",
|
||||||
|
@ -41,6 +42,7 @@ export const paramDef = {
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
export default define(meta, paramDef, async (ps, user) => {
|
||||||
uploadFromUrl({
|
uploadFromUrl({
|
||||||
url: ps.url,
|
url: ps.url,
|
||||||
|
name: ps.name,
|
||||||
user,
|
user,
|
||||||
folderId: ps.folderId,
|
folderId: ps.folderId,
|
||||||
sensitive: ps.isSensitive,
|
sensitive: ps.isSensitive,
|
||||||
|
@ -48,7 +50,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
comment: ps.comment,
|
comment: ps.comment,
|
||||||
}).then((file) => {
|
}).then((file) => {
|
||||||
DriveFiles.pack(file, { self: true }).then((packedFile) => {
|
DriveFiles.pack(file, { self: true }).then((packedFile) => {
|
||||||
publishMainStream(user.id, "urlUploadFinished", {
|
publishToMainStream(user.id, Event.UrlUploadFinished, {
|
||||||
marker: ps.marker,
|
marker: ps.marker,
|
||||||
file: packedFile,
|
file: packedFile,
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,15 +37,13 @@ export const paramDef = {
|
||||||
required: ["name"],
|
required: ["name"],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, me) => {
|
export default define(meta, paramDef, async (ps) => {
|
||||||
const emoji = await Emojis.findOne({
|
const emoji = await Emojis.findOneBy({
|
||||||
where: {
|
name: ps.name,
|
||||||
name: ps.name,
|
host: IsNull(),
|
||||||
host: IsNull(),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!emoji) {
|
if (emoji == null) {
|
||||||
throw new ApiError(meta.errors.noSuchEmoji);
|
throw new ApiError(meta.errors.noSuchEmoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,33 +100,33 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof ps.blocked === "boolean") {
|
if (typeof ps.blocked === "boolean") {
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (ps.blocked) {
|
if (ps.blocked) {
|
||||||
if (meta.blockedHosts.length === 0) {
|
if (instanceMeta.blockedHosts.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
query.andWhere("instance.host IN (:...blocks)", {
|
query.andWhere("instance.host IN (:...blocks)", {
|
||||||
blocks: meta.blockedHosts,
|
blocks: instanceMeta.blockedHosts,
|
||||||
});
|
});
|
||||||
} else if (meta.blockedHosts.length > 0) {
|
} else if (instanceMeta.blockedHosts.length > 0) {
|
||||||
query.andWhere("instance.host NOT IN (:...blocks)", {
|
query.andWhere("instance.host NOT IN (:...blocks)", {
|
||||||
blocks: meta.blockedHosts,
|
blocks: instanceMeta.blockedHosts,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof ps.silenced === "boolean") {
|
if (typeof ps.silenced === "boolean") {
|
||||||
const meta = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
if (ps.silenced) {
|
if (ps.silenced) {
|
||||||
if (meta.silencedHosts.length === 0) {
|
if (instanceMeta.silencedHosts.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
query.andWhere("instance.host IN (:...silences)", {
|
query.andWhere("instance.host IN (:...silences)", {
|
||||||
silences: meta.silencedHosts,
|
silences: instanceMeta.silencedHosts,
|
||||||
});
|
});
|
||||||
} else if (meta.silencedHosts.length > 0) {
|
} else if (instanceMeta.silencedHosts.length > 0) {
|
||||||
query.andWhere("instance.host NOT IN (:...silences)", {
|
query.andWhere("instance.host NOT IN (:...silences)", {
|
||||||
silences: meta.silencedHosts,
|
silences: instanceMeta.silencedHosts,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,8 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async () => {
|
export default define(meta, paramDef, async () => {
|
||||||
const instance = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
const hiddenTags = instance.hiddenTags.map((t) => normalizeForSearch(t));
|
const hiddenTags = instanceMeta.hiddenTags.map((t) => normalizeForSearch(t));
|
||||||
|
|
||||||
const now = new Date(); // 5分単位で丸めた現在日時
|
const now = new Date(); // 5分単位で丸めた現在日時
|
||||||
now.setMinutes(Math.round(now.getMinutes() / 5) * 5, 0, 0);
|
now.setMinutes(Math.round(now.getMinutes() / 5) * 5, 0, 0);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
import * as OTPAuth from "otpauth";
|
import * as OTPAuth from "otpauth";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users, UserProfiles } from "@/models/index.js";
|
import { Users, UserProfiles } from "@/models/index.js";
|
||||||
|
@ -47,5 +47,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,8 +8,7 @@ import {
|
||||||
} from "@/models/index.js";
|
} from "@/models/index.js";
|
||||||
import { config } from "@/config.js";
|
import { config } from "@/config.js";
|
||||||
import { procedures, hash } from "@/server/api/2fa.js";
|
import { procedures, hash } from "@/server/api/2fa.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream, verifyPassword } from "backend-rs";
|
||||||
import { verifyPassword } from "backend-rs";
|
|
||||||
|
|
||||||
const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8"));
|
const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8"));
|
||||||
|
|
||||||
|
@ -132,9 +131,9 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publish meUpdated event
|
// Publish meUpdated event
|
||||||
publishMainStream(
|
publishToMainStream(
|
||||||
user.id,
|
user.id,
|
||||||
"meUpdated",
|
Event.Me,
|
||||||
await Users.pack(user.id, user, {
|
await Users.pack(user.id, user, {
|
||||||
detail: true,
|
detail: true,
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users, UserProfiles, UserSecurityKeys } from "@/models/index.js";
|
import { Users, UserProfiles, UserSecurityKeys } from "@/models/index.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -57,5 +57,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { verifyPassword } from "backend-rs";
|
import { Event, publishToMainStream, verifyPassword } from "backend-rs";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { UserProfiles, UserSecurityKeys, Users } from "@/models/index.js";
|
import { UserProfiles, UserSecurityKeys, Users } from "@/models/index.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
@ -54,9 +53,9 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish meUpdated event
|
// Publish meUpdated event
|
||||||
publishMainStream(
|
publishToMainStream(
|
||||||
user.id,
|
user.id,
|
||||||
"meUpdated",
|
Event.Me,
|
||||||
await Users.pack(user.id, user, {
|
await Users.pack(user.id, user, {
|
||||||
detail: true,
|
detail: true,
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users, UserProfiles } from "@/models/index.js";
|
import { Users, UserProfiles } from "@/models/index.js";
|
||||||
import { verifyPassword } from "backend-rs";
|
import { Event, publishToMainStream, verifyPassword } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
@ -38,5 +37,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users, UserSecurityKeys } from "@/models/index.js";
|
import { Users, UserSecurityKeys } from "@/models/index.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
@ -54,5 +54,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
includeSecrets: true,
|
includeSecrets: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,8 +3,7 @@ import { Users } from "@/models/index.js";
|
||||||
import { resolveUser } from "@/remote/resolve-user.js";
|
import { resolveUser } from "@/remote/resolve-user.js";
|
||||||
import acceptAllFollowRequests from "@/services/following/requests/accept-all.js";
|
import acceptAllFollowRequests from "@/services/following/requests/accept-all.js";
|
||||||
import { publishToFollowers } from "@/services/i/update.js";
|
import { publishToFollowers } from "@/services/i/update.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream, stringToAcct } from "backend-rs";
|
||||||
import { stringToAcct } from "backend-rs";
|
|
||||||
import { DAY } from "@/const.js";
|
import { DAY } from "@/const.js";
|
||||||
import { apiLogger } from "@/server/api/logger.js";
|
import { apiLogger } from "@/server/api/logger.js";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
|
@ -97,7 +96,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publish meUpdated event
|
// Publish meUpdated event
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
|
|
||||||
if (user.isLocked === false) {
|
if (user.isLocked === false) {
|
||||||
acceptAllFollowRequests(user);
|
acceptAllFollowRequests(user);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import { resolveUser } from "@/remote/resolve-user.js";
|
import { resolveUser } from "@/remote/resolve-user.js";
|
||||||
import { stringToAcct } from "backend-rs";
|
import { Event, publishToMainStream, stringToAcct } from "backend-rs";
|
||||||
import { DAY } from "@/const.js";
|
import { DAY } from "@/const.js";
|
||||||
import DeliverManager from "@/remote/activitypub/deliver-manager.js";
|
import DeliverManager from "@/remote/activitypub/deliver-manager.js";
|
||||||
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
||||||
|
@ -12,7 +12,6 @@ import create from "@/services/following/create.js";
|
||||||
import { getUser } from "@/server/api/common/getters.js";
|
import { getUser } from "@/server/api/common/getters.js";
|
||||||
import { Followings, Users } from "@/models/index.js";
|
import { Followings, Users } from "@/models/index.js";
|
||||||
import { config } from "@/config.js";
|
import { config } from "@/config.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
import { inspect } from "node:util";
|
import { inspect } from "node:util";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -134,7 +133,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
dm.execute();
|
dm.execute();
|
||||||
|
|
||||||
// Publish meUpdated event
|
// Publish meUpdated event
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
|
|
||||||
const followings = await Followings.findBy({
|
const followings = await Followings.findBy({
|
||||||
followeeId: user.id,
|
followeeId: user.id,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { MessagingMessages, UserGroupJoinings } from "@/models/index.js";
|
import { MessagingMessages, UserGroupJoinings } from "@/models/index.js";
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export const paramDef = {
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
export default define(meta, paramDef, async (_ps, user) => {
|
||||||
// Update documents
|
// Update documents
|
||||||
await MessagingMessages.update(
|
await MessagingMessages.update(
|
||||||
{
|
{
|
||||||
|
@ -44,5 +44,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
publishMainStream(user.id, "readAllMessagingMessages");
|
publishToMainStream(user.id, Event.ReadAllChats, {});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { Event, publishToMainStream } from "backend-rs";
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { NoteUnreads } from "@/models/index.js";
|
import { NoteUnreads } from "@/models/index.js";
|
||||||
|
|
||||||
|
@ -23,6 +23,6 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// 全て既読になったイベントを発行
|
// 全て既読になったイベントを発行
|
||||||
publishMainStream(user.id, "readAllUnreadMentions");
|
publishToMainStream(user.id, Event.ReadAllMentions, {});
|
||||||
publishMainStream(user.id, "readAllUnreadSpecifiedNotes");
|
publishToMainStream(user.id, Event.ReadAllDms, {});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { genIdAt } from "backend-rs";
|
import { Event, genIdAt, publishToMainStream } from "backend-rs";
|
||||||
import { AnnouncementReads, Announcements, Users } from "@/models/index.js";
|
import { AnnouncementReads, Announcements, Users } from "@/models/index.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["account"],
|
tags: ["account"],
|
||||||
|
@ -59,6 +58,6 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(await Users.getHasUnreadAnnouncement(user.id))) {
|
if (!(await Users.getHasUnreadAnnouncement(user.id))) {
|
||||||
publishMainStream(user.id, "readAllAnnouncements");
|
publishToMainStream(user.id, Event.ReadAllAnnouncements, {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import {
|
|
||||||
publishInternalEvent,
|
|
||||||
publishMainStream,
|
|
||||||
publishUserEvent,
|
|
||||||
} from "@/services/stream.js";
|
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { Users, UserProfiles } from "@/models/index.js";
|
import { Users, UserProfiles } from "@/models/index.js";
|
||||||
import { generateUserToken, verifyPassword } from "backend-rs";
|
import {
|
||||||
|
Event,
|
||||||
|
generateUserToken,
|
||||||
|
InternalEvent,
|
||||||
|
publishToInternalStream,
|
||||||
|
publishToMainStream,
|
||||||
|
publishToUserStream,
|
||||||
|
UserEvent,
|
||||||
|
verifyPassword,
|
||||||
|
} from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
@ -41,15 +45,15 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publish event
|
// Publish event
|
||||||
publishInternalEvent("userTokenRegenerated", {
|
publishToInternalStream(InternalEvent.Token, {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
oldToken,
|
oldToken,
|
||||||
newToken,
|
newToken,
|
||||||
});
|
});
|
||||||
publishMainStream(user.id, "myTokenRegenerated");
|
publishToMainStream(user.id, Event.RegenerateMyToken, {});
|
||||||
|
|
||||||
// Terminate streaming
|
// Terminate streaming
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
publishUserEvent(user.id, "terminate", {});
|
publishToUserStream(user.id, UserEvent.Disconnect, {});
|
||||||
}, 5000);
|
}, 5000);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { RegistryItems } from "@/models/index.js";
|
import { RegistryItems } from "@/models/index.js";
|
||||||
import { genIdAt } from "backend-rs";
|
import { Event, genIdAt, publishToMainStream } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
@ -55,7 +54,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: サードパーティアプリが傍受出来てしまうのでどうにかする
|
// TODO: サードパーティアプリが傍受出来てしまうのでどうにかする
|
||||||
publishMainStream(user.id, "registryUpdated", {
|
publishToMainStream(user.id, Event.Registry, {
|
||||||
scope: ps.scope,
|
scope: ps.scope,
|
||||||
key: ps.key,
|
key: ps.key,
|
||||||
value: ps.value,
|
value: ps.value,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { AccessTokens } from "@/models/index.js";
|
import { AccessTokens } from "@/models/index.js";
|
||||||
import { publishUserEvent } from "@/services/stream.js";
|
import { publishToUserStream, UserEvent } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
@ -26,6 +26,6 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Terminate streaming
|
// Terminate streaming
|
||||||
publishUserEvent(user.id, "terminate");
|
await publishToUserStream(user.id, UserEvent.Disconnect, {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import rndstr from "rndstr";
|
import rndstr from "rndstr";
|
||||||
import { config } from "@/config.js";
|
import { config } from "@/config.js";
|
||||||
|
@ -6,7 +5,7 @@ import { Users, UserProfiles } from "@/models/index.js";
|
||||||
import { sendEmail } from "@/services/send-email.js";
|
import { sendEmail } from "@/services/send-email.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { validateEmailForAccount } from "@/services/validate-email-for-account.js";
|
import { validateEmailForAccount } from "@/services/validate-email-for-account.js";
|
||||||
import { verifyPassword } from "backend-rs";
|
import { Event, publishToMainStream, verifyPassword } from "backend-rs";
|
||||||
import { HOUR } from "@/const.js";
|
import { HOUR } from "@/const.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -72,7 +71,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publish meUpdated event
|
// Publish meUpdated event
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
publishToMainStream(user.id, Event.Me, iObj);
|
||||||
|
|
||||||
if (ps.email != null) {
|
if (ps.email != null) {
|
||||||
const code = rndstr("a-z0-9", 16);
|
const code = rndstr("a-z0-9", 16);
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import * as mfm from "mfm-js";
|
import * as mfm from "mfm-js";
|
||||||
import { publishMainStream, publishUserEvent } from "@/services/stream.js";
|
import {
|
||||||
|
Event,
|
||||||
|
publishToMainStream,
|
||||||
|
publishToUserStream,
|
||||||
|
UserEvent,
|
||||||
|
} from "backend-rs";
|
||||||
import acceptAllFollowRequests from "@/services/following/requests/accept-all.js";
|
import acceptAllFollowRequests from "@/services/following/requests/accept-all.js";
|
||||||
import { publishToFollowers } from "@/services/i/update.js";
|
import { publishToFollowers } from "@/services/i/update.js";
|
||||||
import { extractCustomEmojisFromMfm } from "@/misc/extract-custom-emojis-from-mfm.js";
|
import { extractCustomEmojisFromMfm } from "@/misc/extract-custom-emojis-from-mfm.js";
|
||||||
|
@ -345,10 +350,10 @@ export default define(meta, paramDef, async (ps, _user, token) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publish meUpdated event
|
// Publish meUpdated event
|
||||||
publishMainStream(user.id, "meUpdated", iObj);
|
await publishToMainStream(user.id, Event.Me, iObj);
|
||||||
publishUserEvent(
|
await publishToUserStream(
|
||||||
user.id,
|
user.id,
|
||||||
"updateUserProfile",
|
UserEvent.UpdateProfile,
|
||||||
await UserProfiles.findOneBy({ userId: user.id }),
|
await UserProfiles.findOneBy({ userId: user.id }),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { genIdAt } from "backend-rs";
|
import { genIdAt, InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
import { Webhooks } from "@/models/index.js";
|
import { Webhooks } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
|
||||||
import { webhookEventTypes } from "@/models/entities/webhook.js";
|
import { webhookEventTypes } from "@/models/entities/webhook.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -41,7 +40,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
on: ps.on,
|
on: ps.on,
|
||||||
}).then((x) => Webhooks.findOneByOrFail(x.identifiers[0]));
|
}).then((x) => Webhooks.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
publishInternalEvent("webhookCreated", webhook);
|
publishToInternalStream(InternalEvent.WebhookCreated, webhook);
|
||||||
|
|
||||||
return webhook;
|
return webhook;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { Webhooks } from "@/models/index.js";
|
import { Webhooks } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import { InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["webhooks"],
|
tags: ["webhooks"],
|
||||||
|
@ -39,5 +39,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
|
||||||
await Webhooks.delete(webhook.id);
|
await Webhooks.delete(webhook.id);
|
||||||
|
|
||||||
publishInternalEvent("webhookDeleted", webhook);
|
publishToInternalStream(InternalEvent.WebhookDeleted, webhook);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import define from "@/server/api/define.js";
|
import define from "@/server/api/define.js";
|
||||||
import { ApiError } from "@/server/api/error.js";
|
import { ApiError } from "@/server/api/error.js";
|
||||||
import { Webhooks } from "@/models/index.js";
|
import { Webhooks } from "@/models/index.js";
|
||||||
import { publishInternalEvent } from "@/services/stream.js";
|
import { InternalEvent, publishToInternalStream } from "backend-rs";
|
||||||
import { webhookEventTypes } from "@/models/entities/webhook.js";
|
import { webhookEventTypes } from "@/models/entities/webhook.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -57,5 +57,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
active: ps.active,
|
active: ps.active,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent("webhookUpdated", webhook);
|
publishToInternalStream(InternalEvent.WebhookUpdated, webhook);
|
||||||
});
|
});
|
||||||
|
|
|
@ -402,7 +402,7 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, me) => {
|
export default define(meta, paramDef, async (ps, me) => {
|
||||||
const instance = await fetchMeta();
|
const instanceMeta = await fetchMeta();
|
||||||
|
|
||||||
const emojis = await Emojis.find({
|
const emojis = await Emojis.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -425,56 +425,57 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const response: any = {
|
const response: any = {
|
||||||
maintainerName: instance.maintainerName,
|
maintainerName: instanceMeta.maintainerName,
|
||||||
maintainerEmail: instance.maintainerEmail,
|
maintainerEmail: instanceMeta.maintainerEmail,
|
||||||
|
|
||||||
version: config.version,
|
version: config.version,
|
||||||
|
|
||||||
name: instance.name,
|
name: instanceMeta.name,
|
||||||
uri: config.url,
|
uri: config.url,
|
||||||
description: instance.description,
|
description: instanceMeta.description,
|
||||||
langs: instance.langs,
|
langs: instanceMeta.langs,
|
||||||
tosUrl: instance.tosUrl,
|
tosUrl: instanceMeta.tosUrl,
|
||||||
moreUrls: instance.moreUrls,
|
moreUrls: instanceMeta.moreUrls,
|
||||||
repositoryUrl: instance.repositoryUrl,
|
repositoryUrl: instanceMeta.repositoryUrl,
|
||||||
feedbackUrl: instance.feedbackUrl,
|
feedbackUrl: instanceMeta.feedbackUrl,
|
||||||
|
|
||||||
secureMode: instance.secureMode,
|
secureMode: instanceMeta.secureMode,
|
||||||
privateMode: instance.privateMode,
|
privateMode: instanceMeta.privateMode,
|
||||||
|
|
||||||
disableRegistration: instance.disableRegistration,
|
disableRegistration: instanceMeta.disableRegistration,
|
||||||
disableLocalTimeline: instance.disableLocalTimeline,
|
disableLocalTimeline: instanceMeta.disableLocalTimeline,
|
||||||
disableRecommendedTimeline: instance.disableRecommendedTimeline,
|
disableRecommendedTimeline: instanceMeta.disableRecommendedTimeline,
|
||||||
disableGlobalTimeline: instance.disableGlobalTimeline,
|
disableGlobalTimeline: instanceMeta.disableGlobalTimeline,
|
||||||
enableGuestTimeline: instance.enableGuestTimeline,
|
enableGuestTimeline: instanceMeta.enableGuestTimeline,
|
||||||
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
|
driveCapacityPerLocalUserMb: instanceMeta.localDriveCapacityMb,
|
||||||
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
|
driveCapacityPerRemoteUserMb: instanceMeta.remoteDriveCapacityMb,
|
||||||
antennaLimit: instance.antennaLimit,
|
antennaLimit: instanceMeta.antennaLimit,
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
emailRequiredForSignup: instanceMeta.emailRequiredForSignup,
|
||||||
enableHcaptcha: instance.enableHcaptcha,
|
enableHcaptcha: instanceMeta.enableHcaptcha,
|
||||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
hcaptchaSiteKey: instanceMeta.hcaptchaSiteKey,
|
||||||
enableRecaptcha: instance.enableRecaptcha,
|
enableRecaptcha: instanceMeta.enableRecaptcha,
|
||||||
recaptchaSiteKey: instance.recaptchaSiteKey,
|
recaptchaSiteKey: instanceMeta.recaptchaSiteKey,
|
||||||
swPublickey: instance.swPublicKey,
|
swPublickey: instanceMeta.swPublicKey,
|
||||||
themeColor: instance.themeColor,
|
themeColor: instanceMeta.themeColor,
|
||||||
mascotImageUrl: instance.mascotImageUrl,
|
mascotImageUrl: instanceMeta.mascotImageUrl,
|
||||||
bannerUrl: instance.bannerUrl,
|
bannerUrl: instanceMeta.bannerUrl,
|
||||||
errorImageUrl: instance.errorImageUrl,
|
errorImageUrl: instanceMeta.errorImageUrl,
|
||||||
iconUrl: instance.iconUrl,
|
iconUrl: instanceMeta.iconUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
backgroundImageUrl: instanceMeta.backgroundImageUrl,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
logoImageUrl: instanceMeta.logoImageUrl,
|
||||||
maxNoteTextLength: config.maxNoteLength, // for backward compatibility
|
maxNoteTextLength: config.maxNoteLength, // for backward compatibility
|
||||||
maxCaptionTextLength: config.maxCaptionLength,
|
maxCaptionTextLength: config.maxCaptionLength,
|
||||||
emojis: instance.privateMode && !me ? [] : await Emojis.packMany(emojis),
|
emojis:
|
||||||
|
instanceMeta.privateMode && !me ? [] : await Emojis.packMany(emojis),
|
||||||
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
||||||
defaultLightTheme: instance.defaultLightTheme
|
defaultLightTheme: instanceMeta.defaultLightTheme
|
||||||
? JSON.stringify(JSON5.parse(instance.defaultLightTheme))
|
? JSON.stringify(JSON5.parse(instanceMeta.defaultLightTheme))
|
||||||
: null,
|
: null,
|
||||||
defaultDarkTheme: instance.defaultDarkTheme
|
defaultDarkTheme: instanceMeta.defaultDarkTheme
|
||||||
? JSON.stringify(JSON5.parse(instance.defaultDarkTheme))
|
? JSON.stringify(JSON5.parse(instanceMeta.defaultDarkTheme))
|
||||||
: null,
|
: null,
|
||||||
ads:
|
ads:
|
||||||
instance.privateMode && !me
|
instanceMeta.privateMode && !me
|
||||||
? []
|
? []
|
||||||
: ads.map((ad) => ({
|
: ads.map((ad) => ({
|
||||||
id: ad.id,
|
id: ad.id,
|
||||||
|
@ -483,50 +484,52 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
ratio: ad.ratio,
|
ratio: ad.ratio,
|
||||||
imageUrl: ad.imageUrl,
|
imageUrl: ad.imageUrl,
|
||||||
})),
|
})),
|
||||||
enableEmail: instance.enableEmail,
|
enableEmail: instanceMeta.enableEmail,
|
||||||
|
|
||||||
enableServiceWorker: instance.enableServiceWorker,
|
enableServiceWorker: instanceMeta.enableServiceWorker,
|
||||||
|
|
||||||
translatorAvailable:
|
translatorAvailable:
|
||||||
instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null,
|
instanceMeta.deeplAuthKey != null ||
|
||||||
defaultReaction: instance.defaultReaction,
|
instanceMeta.libreTranslateApiUrl != null,
|
||||||
donationLink: instance.donationLink,
|
defaultReaction: instanceMeta.defaultReaction,
|
||||||
enableServerMachineStats: instance.enableServerMachineStats,
|
donationLink: instanceMeta.donationLink,
|
||||||
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
enableServerMachineStats: instanceMeta.enableServerMachineStats,
|
||||||
|
enableIdenticonGeneration: instanceMeta.enableIdenticonGeneration,
|
||||||
|
|
||||||
...(ps.detail
|
...(ps.detail
|
||||||
? {
|
? {
|
||||||
pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages,
|
pinnedPages:
|
||||||
|
instanceMeta.privateMode && !me ? [] : instanceMeta.pinnedPages,
|
||||||
pinnedClipId:
|
pinnedClipId:
|
||||||
instance.privateMode && !me ? [] : instance.pinnedClipId,
|
instanceMeta.privateMode && !me ? [] : instanceMeta.pinnedClipId,
|
||||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
cacheRemoteFiles: instanceMeta.cacheRemoteFiles,
|
||||||
markLocalFilesNsfwByDefault: instance.markLocalFilesNsfwByDefault,
|
markLocalFilesNsfwByDefault: instanceMeta.markLocalFilesNsfwByDefault,
|
||||||
requireSetup: (await countLocalUsers()) === 0,
|
requireSetup: (await countLocalUsers()) === 0,
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ps.detail) {
|
if (ps.detail) {
|
||||||
if (!instance.privateMode || me) {
|
if (!instanceMeta.privateMode || me) {
|
||||||
const proxyAccount = instance.proxyAccountId
|
const proxyAccount = instanceMeta.proxyAccountId
|
||||||
? await Users.pack(instance.proxyAccountId).catch(() => null)
|
? await Users.pack(instanceMeta.proxyAccountId).catch(() => null)
|
||||||
: null;
|
: null;
|
||||||
response.proxyAccountName = proxyAccount ? proxyAccount.username : null;
|
response.proxyAccountName = proxyAccount ? proxyAccount.username : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.features = {
|
response.features = {
|
||||||
registration: !instance.disableRegistration,
|
registration: !instanceMeta.disableRegistration,
|
||||||
localTimeLine: !instance.disableLocalTimeline,
|
localTimeLine: !instanceMeta.disableLocalTimeline,
|
||||||
recommendedTimeline: !instance.disableRecommendedTimeline,
|
recommendedTimeline: !instanceMeta.disableRecommendedTimeline,
|
||||||
globalTimeLine: !instance.disableGlobalTimeline,
|
globalTimeLine: !instanceMeta.disableGlobalTimeline,
|
||||||
guestTimeline: instance.enableGuestTimeline,
|
guestTimeline: instanceMeta.enableGuestTimeline,
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
emailRequiredForSignup: instanceMeta.emailRequiredForSignup,
|
||||||
hcaptcha: instance.enableHcaptcha,
|
hcaptcha: instanceMeta.enableHcaptcha,
|
||||||
recaptcha: instance.enableRecaptcha,
|
recaptcha: instanceMeta.enableRecaptcha,
|
||||||
objectStorage: instance.useObjectStorage,
|
objectStorage: instanceMeta.useObjectStorage,
|
||||||
serviceWorker: instance.enableServiceWorker,
|
serviceWorker: instanceMeta.enableServiceWorker,
|
||||||
postEditing: true,
|
postEditing: true,
|
||||||
postImports: instance.experimentalFeatures?.postImports || false,
|
postImports: instanceMeta.experimentalFeatures?.postImports || false,
|
||||||
miauth: true,
|
miauth: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue