Merge branch 'develop' of https://firefish.dev/firefish/firefish into refactor/types
This commit is contained in:
commit
07d39cb5ac
40 changed files with 225 additions and 105 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -222,6 +222,7 @@ dependencies = [
|
|||
"rand",
|
||||
"redis",
|
||||
"regex",
|
||||
"rmp-serde",
|
||||
"schemars",
|
||||
"sea-orm",
|
||||
"serde",
|
||||
|
@ -2012,6 +2013,28 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rmp"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"num-traits",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rmp-serde"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938a142ab806f18b88a97b0dea523d39e0fd730a064b035726adcfc58a8a5188"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"rmp",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.6"
|
||||
|
|
|
@ -28,6 +28,7 @@ quote = "1.0.36"
|
|||
rand = "0.8.5"
|
||||
redis = "0.25.3"
|
||||
regex = "1.10.4"
|
||||
rmp-serde = "1.2.0"
|
||||
schemars = "0.8.16"
|
||||
sea-orm = "0.12.15"
|
||||
serde = "1.0.197"
|
||||
|
|
|
@ -69,7 +69,7 @@ renameFile: Преименуване на файла
|
|||
_widgets:
|
||||
activity: Дейност
|
||||
notifications: Известия
|
||||
timeline: Инфопоток
|
||||
timeline: Хронология
|
||||
clock: Часовник
|
||||
trends: Актуални
|
||||
photos: Снимки
|
||||
|
@ -187,7 +187,7 @@ notesAndReplies: Публикации и отговори
|
|||
noSuchUser: Потребителят не е намерен
|
||||
pinnedPages: Закачени страници
|
||||
pinLimitExceeded: Не може да закачаш повече публикации
|
||||
flagShowTimelineReplies: Показване на отговори в инфопотока
|
||||
flagShowTimelineReplies: Показване на отговори в хронологията
|
||||
followersCount: Брой последователи
|
||||
receivedReactionsCount: Брой получени реакции
|
||||
federation: Федерация
|
||||
|
@ -340,7 +340,7 @@ _deck:
|
|||
_columns:
|
||||
notifications: Известия
|
||||
mentions: Споменавания
|
||||
tl: Инфопоток
|
||||
tl: Хронология
|
||||
direct: Директни съобщения
|
||||
list: Списък
|
||||
antenna: Антена
|
||||
|
@ -375,7 +375,7 @@ basicSettings: Основни настройки
|
|||
otherSettings: Други настройки
|
||||
openInWindow: Отваряне в прозорец
|
||||
profile: Профил
|
||||
timeline: Инфопоток
|
||||
timeline: Хронология
|
||||
noAccountDescription: Този потребител все още не е написал своята биография.
|
||||
login: Вход
|
||||
loggingIn: Вписване
|
||||
|
@ -558,12 +558,12 @@ _visibility:
|
|||
specified: Директна
|
||||
localOnly: Само местни
|
||||
public: Общодостъпна
|
||||
publicDescription: Публикацията ще бъде видима във всички публични инфопотоци
|
||||
publicDescription: Публикацията ще бъде видима във всички публични хронологии
|
||||
home: Скрита
|
||||
localOnlyDescription: Не е видима за отдалечени потребители
|
||||
specifiedDescription: Видима само за определени потребители
|
||||
followersDescription: Видима само за последователите ти и споменатите потребители
|
||||
homeDescription: Публикуване само в началния инфопоток
|
||||
homeDescription: Публикуване само в началната хронология
|
||||
explore: Разглеждане
|
||||
theme: Теми
|
||||
wallpaper: Тапет
|
||||
|
@ -594,21 +594,21 @@ _tutorial:
|
|||
да разберат дали искат да видят вашите публикации или да ви следват.
|
||||
title: Как се използва Firefish
|
||||
step1_1: Добре дошли!
|
||||
step5_1: Инфопотоци, инфопотоци навсякъде!
|
||||
step5_1: Хронологии, хронологии навсякъде!
|
||||
step3_1: Сега е време да последвате няколко хора!
|
||||
step1_2: Нека да ви настроим. Ще бъдете готови за нула време!
|
||||
step5_3: Началният {icon} инфопоток е мястото, където можете да видите публикации
|
||||
step5_3: Началната {icon} хронология е мястото, където можете да видите публикации
|
||||
от акаунтите, които следвате.
|
||||
step6_1: И така, какво е това място?
|
||||
step5_7: Глобалният {icon} инфопоток е мястото, където можете да видите публикации
|
||||
step5_7: Глобалната {icon} хронология е мястото, където можете да видите публикации
|
||||
от всеки друг свързан сървър.
|
||||
step4_2: За първата си публикация някои хора обичат да правят публикация {introduction}
|
||||
или просто „Здравей свят!“
|
||||
step5_2: Вашият сървър има активирани {timelines} различни инфопотоци.
|
||||
step5_4: Местният {icon} инфопоток е мястото, където можете да видите публикации
|
||||
step5_2: Вашият сървър има активирани {timelines} различни хронологии.
|
||||
step5_4: Местната {icon} хронология е мястото, където можете да видите публикации
|
||||
от всички останали на този сървър.
|
||||
step5_5: Социалният {icon} инфопоток е комбинация от Началния и Местния инфопоток.
|
||||
step5_6: Препоръчаният {icon} инфопоток е мястото, където можете да видите публикации
|
||||
step5_5: Социалната {icon} хронология е комбинация от Началната и Местната хронология.
|
||||
step5_6: Препоръчаната {icon} хронология е мястото, където можете да видите публикации
|
||||
от сървъри, препоръчани от администраторите.
|
||||
step6_4: Сега отидете, изследвайте и се забавлявайте!
|
||||
step6_3: Всеки сървър работи по различни начини и не всички сървъри работят с Firefish.
|
||||
|
@ -754,7 +754,7 @@ _feeds:
|
|||
general: Общи
|
||||
metadata: Метаданни
|
||||
disk: Диск
|
||||
featured: Представени
|
||||
featured: Препоръчани
|
||||
yearsOld: на {age} години
|
||||
reload: Опресняване
|
||||
invites: Покани
|
||||
|
@ -778,8 +778,8 @@ uploadFromUrl: Качване от URL адрес
|
|||
instanceName: Име на сървъра
|
||||
instanceDescription: Описание на сървъра
|
||||
accept: Приемане
|
||||
enableLocalTimeline: Включване на местния инфопоток
|
||||
enableGlobalTimeline: Включване на глобалния инфопоток
|
||||
enableLocalTimeline: Включване на местната хронология
|
||||
enableGlobalTimeline: Включване на глобалната хронология
|
||||
removeMember: Премахване на член
|
||||
isAdmin: Администратор
|
||||
isModerator: Модератор
|
||||
|
@ -862,8 +862,8 @@ apply: Прилагане
|
|||
selectAccount: Избор на акаунт
|
||||
muteThread: Заглушаване на нишката
|
||||
ffVisibility: Видимост на Последвани/Последователи
|
||||
renoteMute: Заглушаване на подсилванията в инфопотоците
|
||||
replyMute: Заглушаване на отговорите в инфопотоците
|
||||
renoteMute: Заглуш. на подсилванията в хронолог.
|
||||
replyMute: Заглуш. на отговорите в хронолог.
|
||||
blockConfirm: Сигурни ли сте, че искате да блокирате този акаунт?
|
||||
appearance: Облик
|
||||
fontSize: Размер на шрифта
|
||||
|
@ -893,7 +893,7 @@ charts: Диаграми
|
|||
disablePagesScript: Изключване на AiScript в Страниците
|
||||
updatedAt: Обновено на
|
||||
privateDescription: Видима само за теб
|
||||
enableTimelineStreaming: Автоматично обновяване на инфопотоците
|
||||
enableTimelineStreaming: Автоматично обновяване на хронологиите
|
||||
toEdit: Редактиране
|
||||
showEmojisInReactionNotifications: Показване на емоджита в известията за реакции
|
||||
rememberNoteVisibility: Запомняне на настройките за видимост на публикациите
|
||||
|
@ -932,3 +932,11 @@ clientSettings: Настройки за устройството
|
|||
behavior: Поведение
|
||||
detectPostLanguage: Автоматично откриване на езика и показване на бутон за превеждане
|
||||
за публикации на чужди езици
|
||||
replyUnmute: Отмяна на заглушаването на отговорите
|
||||
searchWords: Думи за търсене / ID или URL за поглеждане
|
||||
reloadConfirm: Искате ли да опресните хронологията?
|
||||
enableRecommendedTimeline: Включване на препоръчаната хронология
|
||||
showGapBetweenNotesInTimeline: Показване на празнина между публикациите в хронологията
|
||||
lookup: Поглеждане
|
||||
media: Мултимедия
|
||||
welcomeBackWithName: Добре дошли отново, {name}
|
||||
|
|
|
@ -32,6 +32,7 @@ parse-display = { workspace = true }
|
|||
rand = { workspace = true }
|
||||
redis = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
rmp-serde = { workspace = true }
|
||||
schemars = { workspace = true, features = ["chrono"] }
|
||||
sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
|
|
@ -11,3 +11,4 @@ pub mod meta;
|
|||
pub mod nyaify;
|
||||
pub mod password;
|
||||
pub mod reaction;
|
||||
pub mod redis_cache;
|
||||
|
|
84
packages/backend-rs/src/misc/redis_cache.rs
Normal file
84
packages/backend-rs/src/misc/redis_cache.rs
Normal file
|
@ -0,0 +1,84 @@
|
|||
use crate::database::{redis_conn, redis_key};
|
||||
use redis::{Commands, RedisError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Redis error: {0}")]
|
||||
RedisError(#[from] RedisError),
|
||||
#[error("Data serialization error: {0}")]
|
||||
SerializeError(#[from] rmp_serde::encode::Error),
|
||||
#[error("Data deserialization error: {0}")]
|
||||
DeserializeError(#[from] rmp_serde::decode::Error),
|
||||
}
|
||||
|
||||
pub fn set_cache<V: for<'a> Deserialize<'a> + Serialize>(
|
||||
key: &str,
|
||||
value: &V,
|
||||
expire_seconds: u64,
|
||||
) -> Result<(), Error> {
|
||||
redis_conn()?.set_ex(
|
||||
redis_key(key),
|
||||
rmp_serde::encode::to_vec(&value)?,
|
||||
expire_seconds,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_cache<V: for<'a> Deserialize<'a> + Serialize>(key: &str) -> Result<Option<V>, Error> {
|
||||
let serialized_value: Option<Vec<u8>> = redis_conn()?.get(redis_key(key))?;
|
||||
Ok(match serialized_value {
|
||||
Some(v) => Some(rmp_serde::from_slice::<V>(v.as_ref())?),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::{get_cache, set_cache};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn set_get_expire() {
|
||||
#[derive(serde::Deserialize, serde::Serialize, PartialEq, Debug)]
|
||||
struct Data {
|
||||
id: u32,
|
||||
kind: String,
|
||||
}
|
||||
|
||||
let key_1 = "CARGO_TEST_CACHE_KEY_1";
|
||||
let value_1: Vec<i32> = vec![1, 2, 3, 4, 5];
|
||||
|
||||
let key_2 = "CARGO_TEST_CACHE_KEY_2";
|
||||
let value_2 = "Hello fedizens".to_string();
|
||||
|
||||
let key_3 = "CARGO_TEST_CACHE_KEY_3";
|
||||
let value_3 = Data {
|
||||
id: 1000000007,
|
||||
kind: "prime number".to_string(),
|
||||
};
|
||||
|
||||
set_cache(key_1, &value_1, 1).unwrap();
|
||||
set_cache(key_2, &value_2, 1).unwrap();
|
||||
set_cache(key_3, &value_3, 1).unwrap();
|
||||
|
||||
let cached_value_1: Vec<i32> = get_cache(key_1).unwrap().unwrap();
|
||||
let cached_value_2: String = get_cache(key_2).unwrap().unwrap();
|
||||
let cached_value_3: Data = get_cache(key_3).unwrap().unwrap();
|
||||
|
||||
assert_eq!(value_1, cached_value_1);
|
||||
assert_eq!(value_2, cached_value_2);
|
||||
assert_eq!(value_3, cached_value_3);
|
||||
|
||||
// wait for the cache to expire
|
||||
std::thread::sleep(std::time::Duration::from_millis(1100));
|
||||
|
||||
let expired_value_1: Option<Vec<i32>> = get_cache(key_1).unwrap();
|
||||
let expired_value_2: Option<Vec<i32>> = get_cache(key_2).unwrap();
|
||||
let expired_value_3: Option<Vec<i32>> = get_cache(key_3).unwrap();
|
||||
|
||||
assert!(expired_value_1.is_none());
|
||||
assert!(expired_value_2.is_none());
|
||||
assert!(expired_value_3.is_none());
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
<i :class="icon('ph-dots-three-outline')"></i>
|
||||
</button>
|
||||
<button
|
||||
v-if="!hideFollowButton && isSignedIn && me!.id != user.id"
|
||||
v-if="!hideFollowButton && isSignedIn(me) && me.id != user.id"
|
||||
v-tooltip="full ? null : `${state} ${user.name || user.username}`"
|
||||
class="kpoogebi _button follow-button"
|
||||
:class="{
|
||||
|
|
|
@ -51,9 +51,9 @@ const canonical =
|
|||
const url = `/${canonical}`;
|
||||
|
||||
const isMe =
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
`@${props.username}@${toUnicode(props.host)}`.toLowerCase() ===
|
||||
`@${me!.username}@${toUnicode(localHost)}`.toLowerCase();
|
||||
`@${me.username}@${toUnicode(localHost)}`.toLowerCase();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
<XQuoteButton class="button" :note="appearNote" />
|
||||
<button
|
||||
v-if="
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
isForeignLanguage &&
|
||||
translation == null
|
||||
"
|
||||
|
@ -370,7 +370,7 @@ const reactButton = ref<HTMLElement | null>(null);
|
|||
const appearNote = computed(() =>
|
||||
isRenote ? (note.value.renote as NoteType) : note.value,
|
||||
);
|
||||
const isMyRenote = isSignedIn && me!.id === note.value.userId;
|
||||
const isMyRenote = isSignedIn(me) && me.id === note.value.userId;
|
||||
// const showContent = ref(false);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref(
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
<XQuoteButton class="button" :note="appearNote" />
|
||||
<button
|
||||
v-if="
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
isForeignLanguage &&
|
||||
translation == null
|
||||
"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<MkButton
|
||||
v-else-if="
|
||||
!showOnlyToRegister &&
|
||||
(isSignedIn ? pushRegistrationInServer : pushSubscription)
|
||||
(isSignedIn(me) ? pushRegistrationInServer : pushSubscription)
|
||||
"
|
||||
type="button"
|
||||
:primary="false"
|
||||
|
@ -31,7 +31,7 @@
|
|||
{{ i18n.ts.unsubscribePushNotification }}
|
||||
</MkButton>
|
||||
<MkButton
|
||||
v-else-if="isSignedIn && pushRegistrationInServer"
|
||||
v-else-if="isSignedIn(me) && pushRegistrationInServer"
|
||||
disabled
|
||||
:rounded="rounded"
|
||||
:inline="inline"
|
||||
|
@ -142,7 +142,7 @@ async function unsubscribe() {
|
|||
|
||||
pushRegistrationInServer.value = undefined;
|
||||
|
||||
if (isSignedIn && accounts.length >= 2) {
|
||||
if (isSignedIn(me) && accounts.length >= 2) {
|
||||
apiWithDialog("sw/unregister", {
|
||||
i: me.token,
|
||||
endpoint,
|
||||
|
@ -189,7 +189,7 @@ if (navigator.serviceWorker == null) {
|
|||
if (
|
||||
instance.swPublickey &&
|
||||
"PushManager" in window &&
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
me.token
|
||||
) {
|
||||
supported.value = true;
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import type { entitites } from "firefish-js";
|
||||
import type { entities } from "firefish-js";
|
||||
import XDetails from "@/components/MkReactionsViewer.details.vue";
|
||||
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
||||
import * as os from "@/os";
|
||||
import { useTooltip } from "@/scripts/use-tooltip";
|
||||
import { isSignedIn } from "@/me";
|
||||
import { isSignedIn, me } from "@/me";
|
||||
|
||||
const props = defineProps<{
|
||||
reaction: string;
|
||||
|
@ -43,7 +43,9 @@ const emit = defineEmits<{
|
|||
|
||||
const buttonRef = ref<HTMLElement>();
|
||||
|
||||
const canToggle = computed(() => isSignedIn && !props.reaction.match(/@\w/));
|
||||
const canToggle = computed(
|
||||
() => isSignedIn(me) && !props.reaction.match(/@\w/),
|
||||
);
|
||||
|
||||
const toggleReaction = () => {
|
||||
if (!canToggle.value) return;
|
||||
|
|
|
@ -30,7 +30,7 @@ const reactionsEl = ref<HTMLElement>();
|
|||
|
||||
const initialReactions = new Set(Object.keys(props.note.reactions));
|
||||
|
||||
const isMe = computed(() => isSignedIn && me.id === props.note.userId);
|
||||
const isMe = computed(() => isSignedIn(me) && me.id === props.note.userId);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -74,10 +74,10 @@ useTooltip(buttonRef, async (showing) => {
|
|||
|
||||
const hasRenotedBefore = ref(false);
|
||||
|
||||
if (isSignedIn) {
|
||||
if (isSignedIn(me)) {
|
||||
os.api("notes/renotes", {
|
||||
noteId: props.note.id,
|
||||
userId: me!.id,
|
||||
userId: me.id,
|
||||
limit: 1,
|
||||
}).then((res) => {
|
||||
hasRenotedBefore.value = res.length > 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<MkInfo
|
||||
v-if="tlHint && !tlHintClosed && isSignedIn"
|
||||
v-if="tlHint && !tlHintClosed && isSignedIn(me)"
|
||||
:closeable="true"
|
||||
class="_gap"
|
||||
@close="closeHint"
|
||||
|
@ -120,7 +120,7 @@ const prepend = (note: entities.Note) => {
|
|||
emit("note");
|
||||
|
||||
if (props.sound) {
|
||||
sound.play(isSignedIn && note.userId === me?.id ? "noteMy" : "note");
|
||||
sound.play(isSignedIn(me) && note.userId === me?.id ? "noteMy" : "note");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
:class="{ detailed }"
|
||||
>
|
||||
<span
|
||||
v-if="isSignedIn && me.id !== user.id && user.isFollowed"
|
||||
v-if="isSignedIn(me) && me.id !== user.id && user.isFollowed"
|
||||
class="followed"
|
||||
>{{ i18n.ts.followsYou }}</span
|
||||
>
|
||||
|
@ -80,7 +80,7 @@
|
|||
<div class="buttons">
|
||||
<slot>
|
||||
<MkFollowButton
|
||||
v-if="isSignedIn && user.id !== me.id"
|
||||
v-if="isSignedIn(me) && user.id !== me.id"
|
||||
:user="user"
|
||||
/>
|
||||
</slot>
|
||||
|
|
|
@ -262,7 +262,7 @@ function checkForSplash() {
|
|||
}
|
||||
|
||||
if (
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
defaultStore.state.tutorial === -1 &&
|
||||
!["/announcements", "/announcements/"].includes(window.location.pathname)
|
||||
) {
|
||||
|
@ -417,7 +417,7 @@ function checkForSplash() {
|
|||
s: search,
|
||||
};
|
||||
|
||||
if (isSignedIn) {
|
||||
if (isSignedIn(me)) {
|
||||
// only add post shortcuts if logged in
|
||||
hotkeys["p|n"] = post;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ export const me = accountData
|
|||
? reactive(JSON.parse(accountData) as Account)
|
||||
: null;
|
||||
|
||||
export const isSignedIn = me != null;
|
||||
export const isSignedIn = (i: typeof me): i is Account => i != null;
|
||||
export const isModerator = me != null && (me.isModerator || me.isAdmin);
|
||||
export const isEmojiMod = isModerator || me?.emojiModPerm !== "unauthorized";
|
||||
export const isAdmin = me?.isAdmin;
|
||||
|
|
|
@ -11,21 +11,21 @@ export const navbarItemDef = reactive({
|
|||
notifications: {
|
||||
title: "notifications",
|
||||
icon: `${icon("ph-bell")}`,
|
||||
show: computed(() => isSignedIn),
|
||||
show: computed(() => isSignedIn(me)),
|
||||
indicated: computed(() => me?.hasUnreadNotification),
|
||||
to: "/my/notifications",
|
||||
},
|
||||
messaging: {
|
||||
title: "messaging",
|
||||
icon: `${icon("ph-chats-teardrop")}`,
|
||||
show: computed(() => isSignedIn),
|
||||
show: computed(() => isSignedIn(me)),
|
||||
indicated: computed(() => me?.hasUnreadMessagingMessage),
|
||||
to: "/my/messaging",
|
||||
},
|
||||
drive: {
|
||||
title: "drive",
|
||||
icon: `${icon("ph-cloud")}`,
|
||||
show: computed(() => isSignedIn),
|
||||
show: computed(() => isSignedIn(me)),
|
||||
to: "/my/drive",
|
||||
},
|
||||
followRequests: {
|
||||
|
@ -54,19 +54,19 @@ export const navbarItemDef = reactive({
|
|||
lists: {
|
||||
title: "lists",
|
||||
icon: `${icon("ph-list-bullets")}`,
|
||||
show: computed(() => isSignedIn),
|
||||
show: computed(() => isSignedIn(me)),
|
||||
to: "/my/lists",
|
||||
},
|
||||
antennas: {
|
||||
title: "antennas",
|
||||
icon: `${icon("ph-flying-saucer")}`,
|
||||
show: computed(() => isSignedIn),
|
||||
show: computed(() => isSignedIn(me)),
|
||||
to: "/my/antennas",
|
||||
},
|
||||
favorites: {
|
||||
title: "favorites",
|
||||
icon: `${icon("ph-bookmark-simple")}`,
|
||||
show: computed(() => isSignedIn),
|
||||
show: computed(() => isSignedIn(me)),
|
||||
to: "/my/favorites",
|
||||
},
|
||||
pages: {
|
||||
|
@ -82,7 +82,7 @@ export const navbarItemDef = reactive({
|
|||
clips: {
|
||||
title: "clips",
|
||||
icon: `${icon("ph-paperclip")}`,
|
||||
show: computed(() => isSignedIn),
|
||||
show: computed(() => isSignedIn(me)),
|
||||
to: "/my/clips",
|
||||
},
|
||||
channels: {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
>
|
||||
<div class="_title">
|
||||
<h3>
|
||||
<span v-if="isSignedIn && !announcement.isRead">
|
||||
<span v-if="isSignedIn(me) && !announcement.isRead">
|
||||
🆕
|
||||
</span>
|
||||
{{ announcement.title }}
|
||||
|
@ -37,7 +37,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isSignedIn && !announcement.isRead"
|
||||
v-if="isSignedIn(me) && !announcement.isRead"
|
||||
class="_footer"
|
||||
>
|
||||
<MkButton primary @click="read(announcement.id)"
|
||||
|
@ -60,7 +60,7 @@ import * as os from "@/os";
|
|||
import { i18n } from "@/i18n";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
import icon from "@/scripts/icon";
|
||||
import { isSignedIn } from "@/me";
|
||||
import { isSignedIn, me } from "@/me";
|
||||
|
||||
const pagination = {
|
||||
endpoint: "announcements" as const,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<div v-if="isSignedIn && fetching" class="">
|
||||
<div v-if="isSignedIn(me) && fetching" class="">
|
||||
<MkLoading />
|
||||
</div>
|
||||
<div v-else-if="isSignedIn">
|
||||
<div v-else-if="isSignedIn(me)">
|
||||
<XForm
|
||||
v-if="state == 'waiting'"
|
||||
ref="form"
|
||||
|
@ -52,7 +52,7 @@ import MkSignin from "@/components/MkSignin.vue";
|
|||
import MkKeyValue from "@/components/MkKeyValue.vue";
|
||||
import * as os from "@/os";
|
||||
import { signIn } from "@/account";
|
||||
import { isSignedIn } from "@/me";
|
||||
import { isSignedIn, me } from "@/me";
|
||||
import { i18n } from "@/i18n";
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -64,7 +64,7 @@ const fetching = ref(true);
|
|||
const auth_code = ref("");
|
||||
|
||||
onMounted(() => {
|
||||
if (!isSignedIn) return;
|
||||
if (!isSignedIn(me)) return;
|
||||
|
||||
os.api("auth/session/show", { token: props.token })
|
||||
.then((sess: any) => {
|
||||
|
|
|
@ -51,7 +51,7 @@ const pagination = {
|
|||
};
|
||||
|
||||
const isOwned: boolean | null = computed<boolean | null>(
|
||||
() => isSignedIn && clip.value && me.id === clip.value.userId,
|
||||
() => isSignedIn(me) && clip.value && me.id === clip.value.userId,
|
||||
);
|
||||
|
||||
watch(
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<XUserList :pagination="pinnedUsers" />
|
||||
</MkFolder>
|
||||
<MkFolder
|
||||
v-if="isSignedIn"
|
||||
v-if="isSignedIn(me)"
|
||||
class="_gap"
|
||||
persist-key="explore-popular-users"
|
||||
>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<XUserList :pagination="popularUsers" />
|
||||
</MkFolder>
|
||||
<MkFolder
|
||||
v-if="isSignedIn"
|
||||
v-if="isSignedIn(me)"
|
||||
class="_gap"
|
||||
persist-key="explore-recently-updated-users"
|
||||
>
|
||||
|
@ -45,7 +45,7 @@
|
|||
<XUserList :pagination="recentlyUpdatedUsers" />
|
||||
</MkFolder>
|
||||
<MkFolder
|
||||
v-if="isSignedIn"
|
||||
v-if="isSignedIn(me)"
|
||||
class="_gap"
|
||||
persist-key="explore-recently-registered-users"
|
||||
>
|
||||
|
@ -103,7 +103,7 @@
|
|||
<XUserList :pagination="tagUsers" />
|
||||
</MkFolder>
|
||||
|
||||
<template v-if="tag == null && isSignedIn">
|
||||
<template v-if="tag == null && isSignedIn(me)">
|
||||
<MkFolder class="_gap">
|
||||
<template #header
|
||||
><i
|
||||
|
@ -146,7 +146,7 @@ import MkFolder from "@/components/MkFolder.vue";
|
|||
import MkTab from "@/components/MkTab.vue";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import { isSignedIn } from "@/me";
|
||||
import { isSignedIn, me } from "@/me";
|
||||
import icon from "@/scripts/icon";
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
<div class="other">
|
||||
<button
|
||||
v-if="
|
||||
isSignedIn && me!.id === post.user.id
|
||||
isSignedIn(me) && me.id === post.user.id
|
||||
"
|
||||
v-tooltip="i18n.ts.toEdit"
|
||||
v-click-anime
|
||||
|
@ -105,7 +105,7 @@
|
|||
<MkAcct :user="post.user" />
|
||||
</div>
|
||||
<MkFollowButton
|
||||
v-if="!isSignedIn || me!.id != post.user.id"
|
||||
v-if="!isSignedIn(me) || me.id != post.user.id"
|
||||
:user="post.user"
|
||||
:inline="true"
|
||||
:transparent="false"
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
/></MkA>
|
||||
<template
|
||||
v-if="
|
||||
isSignedIn && me.id === page.userId
|
||||
isSignedIn(me) && me.id === page.userId
|
||||
"
|
||||
>
|
||||
<MkA
|
||||
|
@ -159,7 +159,7 @@
|
|||
</div>
|
||||
<!-- <div class="links">
|
||||
<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ i18n.ts._pages.viewSource }}</MkA>
|
||||
<template v-if="isSignedIn && me.id === page.userId">
|
||||
<template v-if="isSignedIn(me) && me.id === page.userId">
|
||||
<MkA :to="`/pages/edit/${page.id}`" class="link">{{ i18n.ts._pages.editThisPage }}</MkA>
|
||||
<button v-if="me.pinnedPageId === page.id" class="link _textButton" @click="pin(false)">{{ i18n.ts.unpin }}</button>
|
||||
<button v-else class="link _textButton" @click="pin(true)">{{ i18n.ts.pin }}</button>
|
||||
|
|
|
@ -64,7 +64,7 @@ const fetching = ref(true);
|
|||
const usage = ref<any>(null);
|
||||
const capacity = ref<any>(null);
|
||||
const uploadFolder = ref<any>(null);
|
||||
const alwaysMarkNsfw = ref<boolean>(isSignedIn && me.alwaysMarkNsfw);
|
||||
const alwaysMarkNsfw = ref<boolean>(isSignedIn(me) && me.alwaysMarkNsfw);
|
||||
|
||||
const meterStyle = computed(() => {
|
||||
return {
|
||||
|
|
|
@ -65,7 +65,7 @@ import * as os from "@/os";
|
|||
import { ColdDeviceStorage, defaultStore } from "@/store";
|
||||
import { unisonReload } from "@/scripts/unison-reload";
|
||||
import { useStream } from "@/stream";
|
||||
import { isSignedIn } from "@/me";
|
||||
import { isSignedIn, me } from "@/me";
|
||||
import { i18n } from "@/i18n";
|
||||
import { host, version } from "@/config";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
|
@ -170,7 +170,7 @@ interface Profile {
|
|||
};
|
||||
}
|
||||
|
||||
const connection = isSignedIn && stream.useChannel("main");
|
||||
const connection = isSignedIn(me) && stream.useChannel("main");
|
||||
|
||||
const profiles = ref<Record<string, Profile> | null>(null);
|
||||
|
||||
|
|
|
@ -75,28 +75,28 @@ import * as os from "@/os";
|
|||
import { defaultStore } from "@/store";
|
||||
import { i18n } from "@/i18n";
|
||||
import { instance } from "@/instance";
|
||||
import { isModerator, isSignedIn } from "@/me";
|
||||
import { isModerator, isSignedIn, me } from "@/me";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
import { deviceKind } from "@/scripts/device-kind";
|
||||
import icon from "@/scripts/icon";
|
||||
import "swiper/scss";
|
||||
import "swiper/scss/virtual";
|
||||
|
||||
if (isSignedIn && defaultStore.reactiveState.tutorial.value !== -1) {
|
||||
if (isSignedIn(me) && defaultStore.reactiveState.tutorial.value !== -1) {
|
||||
os.popup(XTutorial, {}, {}, "closed");
|
||||
}
|
||||
|
||||
const isHomeTimelineAvailable = isSignedIn;
|
||||
const isHomeTimelineAvailable = isSignedIn(me);
|
||||
const isLocalTimelineAvailable =
|
||||
(!instance.disableLocalTimeline &&
|
||||
(isSignedIn || instance.enableGuestTimeline)) ||
|
||||
(isSignedIn(me) || instance.enableGuestTimeline)) ||
|
||||
isModerator;
|
||||
const isSocialTimelineAvailable = isLocalTimelineAvailable && isSignedIn;
|
||||
const isSocialTimelineAvailable = isLocalTimelineAvailable && isSignedIn(me);
|
||||
const isRecommendedTimelineAvailable =
|
||||
!instance.disableRecommendedTimeline && isSignedIn;
|
||||
!instance.disableRecommendedTimeline && isSignedIn(me);
|
||||
const isGlobalTimelineAvailable =
|
||||
(!instance.disableGlobalTimeline &&
|
||||
(isSignedIn || instance.enableGuestTimeline)) ||
|
||||
(isSignedIn(me) || instance.enableGuestTimeline)) ||
|
||||
isModerator;
|
||||
const keymap = {
|
||||
t: focus,
|
||||
|
@ -205,7 +205,7 @@ function focus(): void {
|
|||
}
|
||||
|
||||
const headerActions = computed(() =>
|
||||
isSignedIn
|
||||
isSignedIn(me)
|
||||
? [
|
||||
{
|
||||
icon: `${icon("ph-list-bullets")}`,
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
<span
|
||||
v-if="
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
me.id !== user.id &&
|
||||
user.isFollowed
|
||||
"
|
||||
|
@ -120,7 +120,7 @@
|
|||
/>
|
||||
<span
|
||||
v-if="
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
me.id !== user.id &&
|
||||
user.isFollowed
|
||||
"
|
||||
|
@ -319,7 +319,7 @@
|
|||
/>
|
||||
</div>
|
||||
<MkInfo
|
||||
v-else-if="isSignedIn && me.id === user.id"
|
||||
v-else-if="isSignedIn(me) && me.id === user.id"
|
||||
style="margin: 12px 0"
|
||||
>{{ i18n.ts.userPagePinTip }}</MkInfo
|
||||
>
|
||||
|
|
|
@ -93,7 +93,7 @@ const headerTabs = computed(() =>
|
|||
title: i18n.ts.media,
|
||||
icon: `${icon("ph-grid-four")}`,
|
||||
},
|
||||
...((isSignedIn && me.id === user.value.id) ||
|
||||
...((isSignedIn(me) && me.id === user.value.id) ||
|
||||
user.value.publicReactions
|
||||
? [
|
||||
{
|
||||
|
|
|
@ -18,7 +18,7 @@ type StateDef = Record<
|
|||
type ArrayElement<A> = A extends readonly (infer T)[] ? T : never;
|
||||
|
||||
const stream = useStream();
|
||||
const connection = isSignedIn && stream.useChannel("main");
|
||||
const connection = isSignedIn(me) ? stream.useChannel("main") : null;
|
||||
|
||||
export class Storage<T extends StateDef> {
|
||||
public readonly key: string;
|
||||
|
@ -44,12 +44,12 @@ export class Storage<T extends StateDef> {
|
|||
const deviceState = JSON.parse(
|
||||
localStorage.getItem(this.keyForLocalStorage) || "{}",
|
||||
);
|
||||
const deviceAccountState = isSignedIn
|
||||
const deviceAccountState = isSignedIn(me)
|
||||
? JSON.parse(
|
||||
localStorage.getItem(`${this.keyForLocalStorage}::${me.id}`) || "{}",
|
||||
)
|
||||
: {};
|
||||
const registryCache = isSignedIn
|
||||
const registryCache = isSignedIn(me)
|
||||
? JSON.parse(
|
||||
localStorage.getItem(`${this.keyForLocalStorage}::cache::${me.id}`) ||
|
||||
"{}",
|
||||
|
@ -66,7 +66,7 @@ export class Storage<T extends StateDef> {
|
|||
state[k] = deviceState[k];
|
||||
} else if (
|
||||
v.where === "account" &&
|
||||
isSignedIn &&
|
||||
isSignedIn(me) &&
|
||||
Object.prototype.hasOwnProperty.call(registryCache, k)
|
||||
) {
|
||||
state[k] = registryCache[k];
|
||||
|
@ -86,7 +86,7 @@ export class Storage<T extends StateDef> {
|
|||
this.state = state as typeof this.state;
|
||||
this.reactiveState = reactiveState as typeof this.reactiveState;
|
||||
|
||||
if (isSignedIn) {
|
||||
if (isSignedIn(me)) {
|
||||
// なぜかsetTimeoutしないとapi関数内でエラーになる(おそらく循環参照してることに原因がありそう)
|
||||
window.setTimeout(() => {
|
||||
api("i/registry/get-all", { scope: ["client", this.key] }).then(
|
||||
|
@ -170,7 +170,7 @@ export class Storage<T extends StateDef> {
|
|||
break;
|
||||
}
|
||||
case "deviceAccount": {
|
||||
if (!isSignedIn) break;
|
||||
if (!isSignedIn(me)) break;
|
||||
const deviceAccountState = JSON.parse(
|
||||
localStorage.getItem(`${this.keyForLocalStorage}::${me.id}`) || "{}",
|
||||
);
|
||||
|
@ -182,7 +182,7 @@ export class Storage<T extends StateDef> {
|
|||
break;
|
||||
}
|
||||
case "account": {
|
||||
if (!isSignedIn) break;
|
||||
if (!isSignedIn(me)) break;
|
||||
const cache = JSON.parse(
|
||||
localStorage.getItem(`${this.keyForLocalStorage}::cache::${me.id}`) ||
|
||||
"{}",
|
||||
|
|
|
@ -293,7 +293,7 @@ export function getNoteMenu(props: {
|
|||
}
|
||||
|
||||
let menu: MenuItem[];
|
||||
if (isSignedIn) {
|
||||
if (isSignedIn(me)) {
|
||||
const statePromise = os.api("notes/state", {
|
||||
noteId: appearNote.id,
|
||||
});
|
||||
|
|
|
@ -335,7 +335,7 @@ export function getUserMenu(user, router: Router = mainRouter) {
|
|||
},
|
||||
] as any;
|
||||
|
||||
if (isSignedIn && me.id !== user.id) {
|
||||
if (isSignedIn(me) && me.id !== user.id) {
|
||||
menu = menu.concat([
|
||||
{
|
||||
icon: user.isMuted ? "ph-eye ph-lg" : "ph-eye-slash ph-lg",
|
||||
|
@ -386,7 +386,7 @@ export function getUserMenu(user, router: Router = mainRouter) {
|
|||
}
|
||||
}
|
||||
|
||||
if (isSignedIn && me.id === user.id) {
|
||||
if (isSignedIn(me) && me.id === user.id) {
|
||||
menu = menu.concat([
|
||||
null,
|
||||
{
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { defineAsyncComponent } from "vue";
|
||||
import { isSignedIn } from "@/me";
|
||||
import { isSignedIn, me } from "@/me";
|
||||
import { i18n } from "@/i18n";
|
||||
import { popup } from "@/os";
|
||||
import { vibrate } from "@/scripts/vibrate";
|
||||
|
||||
export function pleaseLogin(path?: string) {
|
||||
if (isSignedIn) return;
|
||||
if (isSignedIn(me)) return;
|
||||
vibrate(100);
|
||||
|
||||
popup(
|
||||
|
|
|
@ -11,7 +11,7 @@ export function useNoteCapture(props: {
|
|||
isDeletedRef: Ref<boolean>;
|
||||
}) {
|
||||
const note = props.note;
|
||||
const connection = isSignedIn ? useStream() : null;
|
||||
const connection = isSignedIn(me) ? useStream() : null;
|
||||
|
||||
async function onStreamNoteUpdated(noteData): Promise<void> {
|
||||
const { type, id, body } = noteData;
|
||||
|
@ -34,7 +34,7 @@ export function useNoteCapture(props: {
|
|||
|
||||
note.value.reactions[reaction] = currentCount + 1;
|
||||
|
||||
if (isSignedIn && body.userId === me.id) {
|
||||
if (isSignedIn(me) && body.userId === me.id) {
|
||||
note.value.myReaction = reaction;
|
||||
}
|
||||
break;
|
||||
|
@ -48,7 +48,7 @@ export function useNoteCapture(props: {
|
|||
|
||||
note.value.reactions[reaction] = Math.max(0, currentCount - 1);
|
||||
|
||||
if (isSignedIn && body.userId === me.id) {
|
||||
if (isSignedIn(me) && body.userId === me.id) {
|
||||
note.value.myReaction = undefined;
|
||||
}
|
||||
break;
|
||||
|
@ -62,7 +62,7 @@ export function useNoteCapture(props: {
|
|||
choices[choice] = {
|
||||
...choices[choice],
|
||||
votes: choices[choice].votes + 1,
|
||||
...(isSignedIn && body.userId === me.id
|
||||
...(isSignedIn(me) && body.userId === me.id
|
||||
? {
|
||||
isVoted: true,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { markRaw, ref } from "vue";
|
||||
import type { ApiTypes, entities } from "firefish-js";
|
||||
import { isSignedIn } from "./me";
|
||||
import { isSignedIn, me } from "./me";
|
||||
import { Storage } from "./pizzax";
|
||||
import type { NoteVisibility } from "@/types/note";
|
||||
|
||||
|
@ -167,7 +167,7 @@ export const defaultStore = markRaw(
|
|||
tl: {
|
||||
where: "deviceAccount",
|
||||
default: {
|
||||
src: (isSignedIn ? "home" : "local") as
|
||||
src: (isSignedIn(me) ? "home" : "local") as
|
||||
| "home"
|
||||
| "local"
|
||||
| "social"
|
||||
|
|
|
@ -2,14 +2,14 @@ import type { Theme } from "./scripts/theme";
|
|||
import { isSignedIn, me } from "@/me";
|
||||
import { api } from "@/os";
|
||||
|
||||
const lsCacheKey = isSignedIn ? `themes:${me.id}` : "";
|
||||
const lsCacheKey = isSignedIn(me) ? `themes:${me.id}` : "";
|
||||
|
||||
export function getThemes(): Theme[] {
|
||||
return JSON.parse(localStorage.getItem(lsCacheKey) || "[]");
|
||||
}
|
||||
|
||||
export async function fetchThemes(): Promise<void> {
|
||||
if (!isSignedIn) return;
|
||||
if (!isSignedIn(me)) return;
|
||||
|
||||
try {
|
||||
const themes = await api("i/registry/get", {
|
||||
|
|
|
@ -57,7 +57,7 @@ const onNotification = (notification) => {
|
|||
sound.play("notification");
|
||||
};
|
||||
|
||||
if (isSignedIn) {
|
||||
if (isSignedIn(me)) {
|
||||
const connection = stream.useChannel("main", null, "UI");
|
||||
connection.on("notification", onNotification);
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ watch(route, () => {
|
|||
const columns = deckStore.reactiveState.columns;
|
||||
const layout = deckStore.reactiveState.layout;
|
||||
const menuIndicated = computed(() => {
|
||||
if (!isSignedIn) return false;
|
||||
if (!isSignedIn(me)) return false;
|
||||
for (const def in navbarItemDef) {
|
||||
if (navbarItemDef[def].indicated) return true;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ import type { Column } from "./deck-store";
|
|||
import { removeColumn, updateColumn } from "./deck-store";
|
||||
import XTimeline from "@/components/MkTimeline.vue";
|
||||
import * as os from "@/os";
|
||||
import { isModerator, isSignedIn } from "@/me";
|
||||
import { isModerator, isSignedIn, me } from "@/me";
|
||||
import { instance } from "@/instance";
|
||||
import { i18n } from "@/i18n";
|
||||
import icon from "@/scripts/icon";
|
||||
|
@ -72,7 +72,7 @@ const columnActive = ref(true);
|
|||
onMounted(() => {
|
||||
if (props.column.tl == null) {
|
||||
setType();
|
||||
} else if (isSignedIn) {
|
||||
} else if (isSignedIn(me)) {
|
||||
disabled.value =
|
||||
!isModerator &&
|
||||
((instance.disableLocalTimeline &&
|
||||
|
|
Loading…
Reference in a new issue