Compare commits
5 Commits
f55ff2b761
...
72ed3391fc
Author | SHA1 | Date |
---|---|---|
|
72ed3391fc | |
|
10bddd886e | |
|
c3e7791b3e | |
|
f23aae4ac7 | |
|
cb8e42d219 |
|
@ -187,20 +187,20 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.6.20"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
|
||||
checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"axum-macros",
|
||||
"bitflags 1.3.2",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
|
@ -221,26 +221,51 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.3.4"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
|
||||
checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-extra"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "523ae92256049a3b02d3bb4df80152386cd97ddba0c8c5077619bdc8c4b1859b"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-macros"
|
||||
version = "0.3.8"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62"
|
||||
checksum = "5a2edad600410b905404c594e2523549f1bcd4bded1e252c8f74524ccce0b867"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
@ -274,15 +299,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
version = "0.21.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
|
@ -1039,9 +1058,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.20"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
|
||||
checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
|
@ -1049,7 +1068,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
@ -1095,12 +1114,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
version = "0.3.8"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
|
||||
checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"bitflags 1.3.2",
|
||||
"base64",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http",
|
||||
|
@ -1111,9 +1129,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "headers-core"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
|
||||
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||
dependencies = [
|
||||
"http",
|
||||
]
|
||||
|
@ -1168,9 +1186,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
|
||||
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
|
@ -1179,20 +1197,32 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.5"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range-header"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
|
||||
checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
|
@ -1214,13 +1244,12 @@ checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
|
|||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.27"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
|
||||
checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
|
@ -1229,13 +1258,28 @@ dependencies = [
|
|||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.5",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.57"
|
||||
|
@ -1275,6 +1319,16 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.20"
|
||||
|
@ -1292,16 +1346,6 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
|
@ -1360,9 +1404,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -1393,9 +1437,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
|
@ -1450,6 +1494,7 @@ name = "magnetar"
|
|||
version = "0.3.0-alpha"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"cached",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
|
@ -1460,8 +1505,8 @@ dependencies = [
|
|||
"futures-util",
|
||||
"headers",
|
||||
"hyper",
|
||||
"idna",
|
||||
"itertools 0.11.0",
|
||||
"idna 0.5.0",
|
||||
"itertools 0.12.0",
|
||||
"lazy_static",
|
||||
"lru",
|
||||
"magnetar_calckey_model",
|
||||
|
@ -1492,8 +1537,10 @@ name = "magnetar_calckey_fe"
|
|||
version = "0.3.0-alpha"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"chrono",
|
||||
"dotenvy",
|
||||
"headers",
|
||||
"hyper",
|
||||
"magnetar_common",
|
||||
"miette",
|
||||
|
@ -1540,7 +1587,7 @@ dependencies = [
|
|||
name = "magnetar_common"
|
||||
version = "0.3.0-alpha"
|
||||
dependencies = [
|
||||
"idna",
|
||||
"idna 0.5.0",
|
||||
"magnetar_core",
|
||||
"magnetar_sdk",
|
||||
"percent-encoding",
|
||||
|
@ -2198,9 +2245,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "0.23.1"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff5d95dd18a4d76650f0c2607ed8ebdbf63baf9cb934e1c233cd220c694db1d7"
|
||||
checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
|
@ -2213,7 +2260,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sha1_smol",
|
||||
"socket2",
|
||||
"socket2 0.4.9",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"url",
|
||||
|
@ -2399,7 +2446,7 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2784,6 +2831,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
|
@ -2857,7 +2914,7 @@ dependencies = [
|
|||
"futures-util",
|
||||
"hashlink",
|
||||
"hex",
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
|
@ -2927,7 +2984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.2",
|
||||
"base64",
|
||||
"bigdecimal",
|
||||
"bitflags 2.3.3",
|
||||
"byteorder",
|
||||
|
@ -2974,7 +3031,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.2",
|
||||
"base64",
|
||||
"bigdecimal",
|
||||
"bitflags 2.3.3",
|
||||
"byteorder",
|
||||
|
@ -3313,7 +3370,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"socket2 0.4.9",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
]
|
||||
|
@ -3390,7 +3447,7 @@ version = "0.20.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca676d9ba1a322c1b64eb8045a5ec5c0cfb0c9d08e15e9ff622589ad5221c8fe"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
|
@ -3415,16 +3472,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.4.3"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82"
|
||||
checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"http-range-header",
|
||||
"httpdate",
|
||||
"mime",
|
||||
|
@ -3681,7 +3738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"idna 0.4.0",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
|
|
20
Cargo.toml
20
Cargo.toml
|
@ -24,7 +24,8 @@ edition = "2021"
|
|||
|
||||
[workspace.dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = "0.6"
|
||||
axum = "0.7"
|
||||
axum-extra = "0.9"
|
||||
cached = "0.46"
|
||||
cfg-if = "1"
|
||||
chrono = "0.4"
|
||||
|
@ -35,11 +36,11 @@ emojis = "0.6"
|
|||
futures = "0.3"
|
||||
futures-core = "0.3"
|
||||
futures-util = "0.3"
|
||||
headers = "0.3"
|
||||
http = "0.2"
|
||||
hyper = "0.14"
|
||||
idna = "0.4"
|
||||
itertools = "0.11"
|
||||
headers = "0.4"
|
||||
http = "1.0"
|
||||
hyper = "1.1"
|
||||
idna = "0.5"
|
||||
itertools = "0.12"
|
||||
lazy_static = "1.4"
|
||||
lru = "0.12"
|
||||
miette = "5.9"
|
||||
|
@ -47,7 +48,7 @@ nom = "7"
|
|||
nom_locate = "4"
|
||||
percent-encoding = "2.2"
|
||||
quick-xml = "0.31"
|
||||
redis = "0.23"
|
||||
redis = "0.24"
|
||||
regex = "1.9"
|
||||
reqwest = "0.11"
|
||||
sea-orm = "0.12"
|
||||
|
@ -62,7 +63,7 @@ tokio = "1.24"
|
|||
tokio-util = "0.7"
|
||||
toml = "0.8"
|
||||
tower = "0.4"
|
||||
tower-http = "0.4"
|
||||
tower-http = "0.5"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
ts-rs = "7"
|
||||
|
@ -84,7 +85,8 @@ lru = { workspace = true }
|
|||
chrono = { workspace = true }
|
||||
dotenvy = { workspace = true }
|
||||
|
||||
axum = { workspace = true, features = ["macros", "headers"] }
|
||||
axum = { workspace = true, features = ["macros"] }
|
||||
axum-extra = { workspace = true, features = ["typed-header"]}
|
||||
headers = { workspace = true }
|
||||
hyper = { workspace = true, features = ["full"] }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
|
|
|
@ -11,7 +11,9 @@ miette = { workspace = true }
|
|||
|
||||
dotenvy = { workspace = true }
|
||||
|
||||
axum = { workspace = true, features = ["headers"] }
|
||||
axum = { workspace = true }
|
||||
axum-extra = { workspace = true, features = ["typed-header"]}
|
||||
headers = { workspace = true}
|
||||
hyper = { workspace = true, features = ["full"] }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tower = { workspace = true }
|
||||
|
@ -29,4 +31,4 @@ serde_json = { workspace = true }
|
|||
|
||||
chrono = { workspace = true }
|
||||
|
||||
walkdir = { workspace = true }
|
||||
walkdir = { workspace = true }
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
:note="note"
|
||||
:detailedView="true"
|
||||
/>
|
||||
<MkLoading v-else-if="note.parent_note" mini />
|
||||
<MkLoading v-else-if="appearNote.parent_note_id" mini />
|
||||
<MkNoteSub
|
||||
v-if="note.parent_note"
|
||||
:note="note.parent_note"
|
||||
v-if="parentNote"
|
||||
:note="parentNote"
|
||||
class="reply-to"
|
||||
:detailedView="true"
|
||||
/>
|
||||
|
@ -64,14 +64,14 @@
|
|||
</MkTab>
|
||||
|
||||
<MkNoteSub
|
||||
v-if="directReplies && tab === 'replies'"
|
||||
v-if="directReplies.length && tab === 'replies'"
|
||||
v-for="note in directReplies"
|
||||
:key="note.id"
|
||||
:note="note"
|
||||
class="reply"
|
||||
:conversation="replies"
|
||||
:detailedView="true"
|
||||
:parentId="note.id"
|
||||
:parentId="appearNote.id"
|
||||
/>
|
||||
<MkLoading v-else-if="tab === 'replies' && note.reply_count > 0" />
|
||||
|
||||
|
@ -83,7 +83,7 @@
|
|||
class="reply"
|
||||
:conversation="replies"
|
||||
:detailedView="true"
|
||||
:parentId="note.id"
|
||||
:parentId="appearNote.id"
|
||||
/>
|
||||
<MkLoading v-else-if="tab === 'quotes' && directQuotes.length > 0" />
|
||||
|
||||
|
@ -101,7 +101,9 @@
|
|||
:with-chart="false"
|
||||
/>
|
||||
<!-- </MkPagination> -->
|
||||
<MkLoading v-else-if="tab === 'renotes' && note.renote_count > 0" />
|
||||
<MkLoading
|
||||
v-else-if="tab === 'renotes' && appearNote.renote_count > 0"
|
||||
/>
|
||||
|
||||
<div v-if="tab === 'clips' && clips.length > 0" class="_content clips">
|
||||
<MkA
|
||||
|
@ -127,7 +129,7 @@
|
|||
<MkLoading v-else-if="tab === 'clips' && clips.length > 0" />
|
||||
|
||||
<MkReactedUsers
|
||||
v-if="tab === 'reactions' && magReactionCount(note) > 0"
|
||||
v-if="tab === 'reactions' && magReactionCount(appearNote) > 0"
|
||||
:note-id="note.id"
|
||||
></MkReactedUsers>
|
||||
</div>
|
||||
|
@ -135,11 +137,11 @@
|
|||
<I18n :src="softMuteReasonI18nSrc(muted.what)" tag="small">
|
||||
<template #name>
|
||||
<MkA
|
||||
v-user-preview="note.user.id"
|
||||
v-user-preview="appearNote.user.id"
|
||||
class="name"
|
||||
:to="userPage(note.user)"
|
||||
:to="userPage(appearNote.user)"
|
||||
>
|
||||
<MkUserName :user="note.user" />
|
||||
<MkUserName :user="appearNote.user" />
|
||||
</MkA>
|
||||
</template>
|
||||
<template #reason>
|
||||
|
@ -150,7 +152,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, onUpdated, ref, toRaw } from "vue";
|
||||
import { onMounted, onUnmounted, onUpdated, ref, toRaw, watch } from "vue";
|
||||
import * as misskey from "calckey-js";
|
||||
import MkTab from "@/components/MkTab.vue";
|
||||
import MkNoteSub from "@/components/MkNoteSub.vue";
|
||||
|
@ -169,8 +171,9 @@ import { getNoteMenu } from "@/scripts/get-note-menu";
|
|||
import { useNoteCapture } from "@/scripts/use-note-capture";
|
||||
import { stream } from "@/stream";
|
||||
import { NoteUpdatedEvent } from "calckey-js/built/streaming.types";
|
||||
import { packed } from "magnetar-common";
|
||||
import { endpoints, packed } from "magnetar-common";
|
||||
import {
|
||||
magEffectiveNote,
|
||||
magIsRenote,
|
||||
magReactionCount,
|
||||
magReactionToLegacy,
|
||||
|
@ -212,14 +215,20 @@ const noteEl = $ref();
|
|||
const menuButton = ref<HTMLElement>();
|
||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||
const reactButton = ref<HTMLElement>();
|
||||
let appearNote = $computed(
|
||||
() => magEffectiveNote(note) as packed.PackNoteMaybeFull
|
||||
);
|
||||
let parentNote = $ref(appearNote.parent_note);
|
||||
const showContent = ref(false);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords));
|
||||
const muted = ref(
|
||||
getWordSoftMute(appearNote, $i, defaultStore.state.mutedWords)
|
||||
);
|
||||
const translation = ref(null);
|
||||
const translating = ref(false);
|
||||
let conversation = $ref<null | misskey.entities.Note[]>([]);
|
||||
const replies = ref<misskey.entities.Note[]>([]);
|
||||
let directReplies = $ref<null | misskey.entities.Note[]>([]);
|
||||
let directReplies = $ref<misskey.entities.Note[]>([]);
|
||||
let directQuotes = $ref<null | misskey.entities.Note[]>([]);
|
||||
let clips = $ref();
|
||||
let renotes = $ref();
|
||||
|
@ -236,7 +245,7 @@ const keymap = {
|
|||
|
||||
useNoteCapture({
|
||||
rootEl: el,
|
||||
note: $$(note),
|
||||
note: $$(appearNote),
|
||||
isDeletedRef: isDeleted,
|
||||
});
|
||||
|
||||
|
@ -257,7 +266,7 @@ function react(viaKeyboard = false): void {
|
|||
reactButton.value,
|
||||
(reaction) => {
|
||||
os.api("notes/reactions/create", {
|
||||
noteId: note.id,
|
||||
noteId: appearNote.id,
|
||||
reaction: magReactionToLegacy(reaction),
|
||||
});
|
||||
},
|
||||
|
@ -267,14 +276,6 @@ function react(viaKeyboard = false): void {
|
|||
);
|
||||
}
|
||||
|
||||
function undoReact(note): void {
|
||||
const oldReaction = note.myReaction;
|
||||
if (!oldReaction) return;
|
||||
os.api("notes/reactions/delete", {
|
||||
noteId: note.id,
|
||||
});
|
||||
}
|
||||
|
||||
function onContextmenu(ev: MouseEvent): void {
|
||||
const isLink = (el: HTMLElement) => {
|
||||
if (el.tagName === "A") return true;
|
||||
|
@ -326,29 +327,52 @@ function blur() {
|
|||
noteEl.blur();
|
||||
}
|
||||
|
||||
directReplies = null;
|
||||
async function updateParent(note: packed.PackNoteMaybeFull) {
|
||||
if (note.parent_note) {
|
||||
parentNote = note.parent_note;
|
||||
return;
|
||||
} else if (note.parent_note_id) {
|
||||
parentNote = null;
|
||||
parentNote = await os.magApi(
|
||||
endpoints.GetNoteById,
|
||||
{ attachments: true, context: true },
|
||||
{ id: note.parent_note_id }
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
parentNote = null;
|
||||
}
|
||||
|
||||
watch(appearNote, updateParent);
|
||||
updateParent(note);
|
||||
|
||||
directReplies = [];
|
||||
os.api("notes/children", {
|
||||
noteId: note.id,
|
||||
noteId: appearNote.id,
|
||||
limit: 30,
|
||||
depth: 12,
|
||||
}).then((res) => {
|
||||
res = res.reduce((acc, resNote) => {
|
||||
if (resNote.userId == note.user.id) {
|
||||
return [...acc, resNote];
|
||||
}
|
||||
return [resNote, ...acc];
|
||||
}, []);
|
||||
res = res.reduce(
|
||||
(acc: misskey.entities.Note[], resNote: misskey.entities.Note) => {
|
||||
if (resNote.userId == appearNote.user.id) {
|
||||
return [...acc, resNote];
|
||||
}
|
||||
return [resNote, ...acc];
|
||||
},
|
||||
[]
|
||||
);
|
||||
replies.value = res;
|
||||
directReplies = res
|
||||
.filter((resNote) => resNote.replyId === note.id)
|
||||
.filter((resNote) => resNote.replyId === appearNote.id)
|
||||
.reverse();
|
||||
directQuotes = res.filter((resNote) => resNote.renoteId === note.id);
|
||||
directQuotes = res.filter((resNote) => resNote.renoteId === appearNote.id);
|
||||
});
|
||||
|
||||
conversation = null;
|
||||
if (note.parent_note_id) {
|
||||
if (appearNote.parent_note_id) {
|
||||
os.api("notes/conversation", {
|
||||
noteId: note.parent_note_id,
|
||||
noteId: appearNote.parent_note_id,
|
||||
limit: 30,
|
||||
}).then((res) => {
|
||||
conversation = res.reverse();
|
||||
|
@ -358,7 +382,7 @@ if (note.parent_note_id) {
|
|||
|
||||
clips = null;
|
||||
os.api("notes/clips", {
|
||||
noteId: note.id,
|
||||
noteId: appearNote.id,
|
||||
}).then((res) => {
|
||||
clips = res;
|
||||
});
|
||||
|
@ -375,7 +399,7 @@ renotes = null;
|
|||
function loadTab() {
|
||||
if (tab === "renotes" && !renotes) {
|
||||
os.api("notes/renotes", {
|
||||
noteId: note.id,
|
||||
noteId: appearNote.id,
|
||||
limit: 100,
|
||||
}).then((res) => {
|
||||
renotes = res;
|
||||
|
@ -387,7 +411,7 @@ async function onNoteUpdated(noteData: NoteUpdatedEvent): Promise<void> {
|
|||
const { type, id, body } = noteData;
|
||||
|
||||
let found = -1;
|
||||
if (id === note.id) {
|
||||
if (id === appearNote.id) {
|
||||
found = 0;
|
||||
} else {
|
||||
for (let i = 0; i < replies.value.length; i++) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
v-size="{ max: [500, 350] }"
|
||||
class="tkcbzcuz note-container"
|
||||
:tabindex="!isDeleted ? '-1' : null"
|
||||
:class="{ renote: isRenote }"
|
||||
:class="{ renote: magIsRenote(note) }"
|
||||
:id="appearNote.id"
|
||||
>
|
||||
<MkNoteSub
|
||||
|
@ -264,7 +264,11 @@ import { getNoteMenu } from "@/scripts/get-note-menu";
|
|||
import { useNoteCapture } from "@/scripts/use-note-capture";
|
||||
import { notePage } from "@/filters/note";
|
||||
import { getNoteSummary } from "@/scripts/get-note-summary";
|
||||
import { magReactionToLegacy } from "@/scripts-mag/mag-util";
|
||||
import {
|
||||
magEffectiveNote,
|
||||
magIsRenote,
|
||||
magReactionToLegacy,
|
||||
} from "@/scripts-mag/mag-util";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -298,12 +302,6 @@ if (noteViewInterruptors.length > 0) {
|
|||
});
|
||||
}
|
||||
|
||||
const isRenote =
|
||||
note.renote != null &&
|
||||
note.text == null &&
|
||||
note.fileIds.length === 0 &&
|
||||
note.poll == null;
|
||||
|
||||
const el = ref<HTMLElement>();
|
||||
const footerEl = ref<HTMLElement>();
|
||||
const menuButton = ref<HTMLElement>();
|
||||
|
@ -311,8 +309,8 @@ const starButton = ref<InstanceType<typeof XStarButton>>();
|
|||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||
const renoteTime = ref<HTMLElement>();
|
||||
const reactButton = ref<HTMLElement>();
|
||||
let appearNote = $computed(() =>
|
||||
isRenote ? (note.renote as misskey.entities.Note) : note
|
||||
let appearNote = $computed(
|
||||
() => magEffectiveNote(note) as misskey.entities.Note
|
||||
);
|
||||
const isMyRenote = $i && $i.id === note.userId;
|
||||
const showContent = ref(false);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<div class="body">
|
||||
<div class="content">
|
||||
<Mfm
|
||||
:customEmojis="$instance.emojis"
|
||||
:text="preprocess(text).trim()"
|
||||
:author="$i"
|
||||
:i="$i"
|
||||
|
@ -20,7 +21,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import { preprocess } from "@/scripts/preprocess";
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -221,7 +221,6 @@ import {
|
|||
magIsRenote,
|
||||
magReactionCount,
|
||||
magReactionToLegacy,
|
||||
magTransMap,
|
||||
magTransProperty,
|
||||
} from "@/scripts-mag/mag-util";
|
||||
|
||||
|
@ -280,8 +279,8 @@ const replies: misskey.entities.Note[] =
|
|||
props.conversation
|
||||
?.filter(
|
||||
(item) =>
|
||||
item.replyId === props.note.id ||
|
||||
item.renoteId === props.note.id
|
||||
item.replyId === appearNote.id ||
|
||||
item.renoteId === appearNote.id
|
||||
)
|
||||
.reverse() ?? [];
|
||||
const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { VNode } from "vue";
|
||||
import { defineComponent, h } from "vue";
|
||||
import * as mfm from "mfm-js";
|
||||
import type { VNode } from "vue";
|
||||
import MkUrl from "@/components/global/MkUrl.vue";
|
||||
import MkLink from "@/components/MkLink.vue";
|
||||
import MagMention from "@/components/MagMention.vue";
|
||||
|
@ -11,12 +11,11 @@ import MkSparkle from "@/components/MkSparkle.vue";
|
|||
import MkA from "@/components/global/MkA.vue";
|
||||
import { host } from "@/config";
|
||||
import { reducedMotion } from "@/scripts/reduced-motion";
|
||||
import { defaultStore } from "@/store";
|
||||
import MagEmoji from "@/components/global/MagEmoji.vue";
|
||||
import {
|
||||
magConvertReaction,
|
||||
magIsMissingEmoji,
|
||||
magReactionEquals,
|
||||
magReactionToLegacy,
|
||||
magTransProperty,
|
||||
} from "@/scripts-mag/mag-util";
|
||||
|
||||
|
@ -542,25 +541,32 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
case "emojiCode": {
|
||||
const shortcode = `:${token.props.name}:`;
|
||||
const emoji = magConvertReaction(
|
||||
shortcode,
|
||||
(name, host) =>
|
||||
this.customEmojis.find((e) =>
|
||||
magReactionEquals(
|
||||
magConvertReaction(
|
||||
`:${magTransProperty(
|
||||
e,
|
||||
"shortcode",
|
||||
"name"
|
||||
)}:`
|
||||
),
|
||||
{ name, host, url: null! }
|
||||
)
|
||||
)?.url ?? null
|
||||
);
|
||||
|
||||
if (magIsMissingEmoji(emoji)) {
|
||||
return [shortcode];
|
||||
}
|
||||
|
||||
return [
|
||||
h(MagEmoji, {
|
||||
key: Math.random(),
|
||||
emoji: magConvertReaction(
|
||||
`:${token.props.name}:`,
|
||||
(name, host) =>
|
||||
this.customEmojis.find((e) =>
|
||||
magReactionEquals(
|
||||
magConvertReaction(
|
||||
`:${magTransProperty(
|
||||
e,
|
||||
"shortcode",
|
||||
"name"
|
||||
)}:`
|
||||
),
|
||||
{ name, host, url: null! }
|
||||
)
|
||||
)?.url ?? null
|
||||
),
|
||||
emoji,
|
||||
normal: this.plain,
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -226,6 +226,10 @@ export function magIsCustomEmoji(
|
|||
);
|
||||
}
|
||||
|
||||
export function magIsMissingEmoji(emoji: types.Reaction): boolean {
|
||||
return magIsCustomEmoji(emoji) && !emoji["url"];
|
||||
}
|
||||
|
||||
export function magIsUnicodeEmoji(
|
||||
emoji: types.Reaction
|
||||
): emoji is types.ReactionUnicode {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface UserRelationExt { follows_you: boolean, you_follow: boolean, you_request_follow: boolean, they_request_follow: boolean, blocks_you: boolean, you_block: boolean, mute: boolean, mute_renotes: boolean, }
|
||||
export interface UserRelationExt { follows_you: boolean, you_follow: boolean, they_request_follow: boolean, you_request_follow: boolean, blocks_you: boolean, you_block: boolean, mute: boolean, mute_renotes: boolean, }
|
|
@ -1,9 +1,10 @@
|
|||
use axum::extract::State;
|
||||
use axum::headers::CacheControl;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::{Html, IntoResponse};
|
||||
use axum::routing::get;
|
||||
use axum::{Router, TypedHeader};
|
||||
use axum::Router;
|
||||
use axum_extra::TypedHeader;
|
||||
use headers::CacheControl;
|
||||
use magnetar_common::config::MagnetarConfig;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
|
|
@ -9,10 +9,11 @@ use crate::frontend_render::{new_frontend_render_router, FrontendConfig};
|
|||
use crate::manifest::handle_manifest;
|
||||
use crate::static_serve::{static_serve, static_serve_svg, static_serve_sw};
|
||||
use crate::summary_proxy::generate_summary;
|
||||
use axum::headers::CacheControl;
|
||||
use axum::routing::{any, get};
|
||||
use axum::{Router, TypedHeader};
|
||||
use axum::Router;
|
||||
use axum_extra::TypedHeader;
|
||||
use dotenvy::dotenv;
|
||||
use headers::CacheControl;
|
||||
use hyper::StatusCode;
|
||||
use magnetar_common::config::MagnetarConfig;
|
||||
use miette::{miette, IntoDiagnostic};
|
||||
|
@ -21,6 +22,7 @@ use std::sync::Arc;
|
|||
use std::time::Duration;
|
||||
use tera::Tera;
|
||||
use thiserror::Error;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::signal;
|
||||
use tower_http::services::ServeFile;
|
||||
use tower_http::trace::TraceLayer;
|
||||
|
@ -116,14 +118,16 @@ async fn main() -> miette::Result<()> {
|
|||
config.calckey_frontend.bind_addr,
|
||||
config.calckey_frontend.port,
|
||||
));
|
||||
info!("Serving on: {addr}");
|
||||
axum::Server::bind(&addr)
|
||||
.serve(app.into_make_service())
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
tracing::info!("Binding to: {addr}");
|
||||
let listener = TcpListener::bind(addr).await.into_diagnostic()?;
|
||||
tracing::info!("Serving...");
|
||||
axum::serve(listener, app.into_make_service())
|
||||
.await
|
||||
.map_err(|e| miette!("Error running server: {}", e))
|
||||
}
|
||||
|
||||
// FIXME: Plug this back in when Axum reimplements graceful shutdown
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
if let Err(e) = signal::ctrl_c().await {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use axum::extract::State;
|
||||
use axum::headers::AccessControlMaxAge;
|
||||
use axum::response::IntoResponse;
|
||||
use axum::{Json, TypedHeader};
|
||||
use axum::Json;
|
||||
use axum_extra::headers::AccessControlMaxAge;
|
||||
use axum_extra::TypedHeader;
|
||||
use magnetar_common::config::MagnetarConfig;
|
||||
use serde_json::Value;
|
||||
use std::time::Duration;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use axum::headers::{AccessControlMaxAge, HeaderMapExt};
|
||||
use axum::http::header::CONTENT_SECURITY_POLICY;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use axum::middleware::{from_fn, Next};
|
||||
use axum::Router;
|
||||
use headers::{AccessControlMaxAge, HeaderMapExt};
|
||||
use hyper::Response;
|
||||
use std::time::Duration;
|
||||
use tower::util::MapResponseLayer;
|
||||
|
@ -37,7 +37,7 @@ pub fn static_serve_svg(dir: &str) -> Router {
|
|||
let serve_dir = ServeDir::new(dir);
|
||||
Router::new()
|
||||
.nest_service("", serve_dir)
|
||||
.layer(from_fn(|req: Request<_>, next: Next<_>| async {
|
||||
.layer(from_fn(|req: Request<_>, next: Next| async {
|
||||
if !req.uri().path().ends_with(".svg") {
|
||||
return Err(StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ impl EmojiContext {
|
|||
|
||||
self.0.extend(
|
||||
more.iter()
|
||||
.filter(|&e| existing.contains(&e.emoji.0.shortcode))
|
||||
.filter(|&e| !existing.contains(&e.emoji.0.shortcode))
|
||||
.cloned(),
|
||||
);
|
||||
}
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -16,6 +16,7 @@ use magnetar_calckey_model::{CacheConnectorConfig, CalckeyCache, CalckeyModel, C
|
|||
use miette::{miette, IntoDiagnostic};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::signal;
|
||||
use tower_http::cors::{Any, CorsLayer};
|
||||
use tower_http::trace::TraceLayer;
|
||||
|
@ -85,14 +86,15 @@ async fn main() -> miette::Result<()> {
|
|||
.layer(TraceLayer::new_for_http());
|
||||
|
||||
let addr = SocketAddr::from((config.networking.bind_addr, config.networking.port));
|
||||
info!("Serving on: {addr}");
|
||||
axum::Server::bind(&addr)
|
||||
.serve(app.into_make_service())
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
info!("Binding to: {addr}");
|
||||
let listener = TcpListener::bind(addr).await.into_diagnostic()?;
|
||||
info!("Serving...");
|
||||
axum::serve(listener, app.into_make_service())
|
||||
.await
|
||||
.map_err(|e| miette!("Error running server: {}", e))
|
||||
}
|
||||
|
||||
// FIXME: Plug this back in when Axum reimplements graceful shutdown
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
if let Err(e) = signal::ctrl_c().await {
|
||||
|
|
|
@ -3,9 +3,9 @@ use crate::service::MagnetarService;
|
|||
use crate::web::{ApiError, IntoErrorCode};
|
||||
use axum::async_trait;
|
||||
use axum::extract::rejection::ExtensionRejection;
|
||||
use axum::extract::{FromRequestParts, State};
|
||||
use axum::extract::{FromRequestParts, Request, State};
|
||||
use axum::http::request::Parts;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use axum::http::{HeaderMap, StatusCode};
|
||||
use axum::middleware::Next;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use headers::authorization::Bearer;
|
||||
|
@ -17,7 +17,7 @@ use strum::IntoStaticStr;
|
|||
use thiserror::Error;
|
||||
use tracing::error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AuthMode {
|
||||
User {
|
||||
user: Arc<ck::user::Model>,
|
||||
|
@ -230,12 +230,13 @@ impl AuthState {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn auth<B>(
|
||||
pub async fn auth(
|
||||
State(state): State<AuthState>,
|
||||
mut req: Request<B>,
|
||||
next: Next<B>,
|
||||
header_map: HeaderMap,
|
||||
mut req: Request,
|
||||
next: Next,
|
||||
) -> Result<Response, ApiError> {
|
||||
let auth_bearer = match req.headers().typed_try_get::<Authorization<Bearer>>() {
|
||||
let auth_bearer = match header_map.typed_try_get::<Authorization<Bearer>>() {
|
||||
Ok(Some(auth)) => auth,
|
||||
Ok(None) => {
|
||||
req.extensions_mut().insert(AuthMode::Anonymous);
|
||||
|
|
Loading…
Reference in New Issue