From 63d8b7986b077124ea2c20efd248aa141a65b1ea Mon Sep 17 00:00:00 2001 From: tamaina Date: Tue, 3 Jan 2023 14:58:10 +0000 Subject: [PATCH 01/75] do `yarn cache clean --all` in clean-all.js --- scripts/clean-all.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/clean-all.js b/scripts/clean-all.js index c65a1c3a32..563b6bc922 100644 --- a/scripts/clean-all.js +++ b/scripts/clean-all.js @@ -1,3 +1,4 @@ +const { execSync } = require('child_process'); const fs = require('fs'); (async () => { @@ -12,5 +13,9 @@ const fs = require('fs'); fs.rmSync(__dirname + '/../built', { recursive: true, force: true }); fs.rmSync(__dirname + '/../node_modules', { recursive: true, force: true }); - fs.rmSync(__dirname + '/../.yarn/cache', { recursive: true, force: true }); + + execSync('yarn cache clean --all', { + cwd: __dirname + '/../', + stdio: 'inherit', + }); })(); From c89410cab0ffb6a089a4ea442f2e33407864d6fd Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 08:32:44 +0900 Subject: [PATCH 02/75] :art: --- packages/frontend/src/components/MkMenu.vue | 1 + packages/frontend/src/components/form/input.vue | 4 ++-- packages/frontend/src/components/form/select.vue | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 263030e015..e9076138c6 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -217,6 +217,7 @@ onBeforeUnmount(() => { content: ""; display: block; position: absolute; + z-index: -1; top: 0; left: 0; right: 0; diff --git a/packages/frontend/src/components/form/input.vue b/packages/frontend/src/components/form/input.vue index 4f3e50c31a..f72e1429f5 100644 --- a/packages/frontend/src/components/form/input.vue +++ b/packages/frontend/src/components/form/input.vue @@ -78,8 +78,8 @@ const inputEl = shallowRef(); const prefixEl = shallowRef(); const suffixEl = shallowRef(); const height = - props.small ? 35 : - props.large ? 39 : + props.small ? 34 : + props.large ? 40 : 37; const focus = () => inputEl.value.focus(); diff --git a/packages/frontend/src/components/form/select.vue b/packages/frontend/src/components/form/select.vue index 2cd5ae6f4a..c8cdd9e508 100644 --- a/packages/frontend/src/components/form/select.vue +++ b/packages/frontend/src/components/form/select.vue @@ -64,8 +64,8 @@ const prefixEl = ref(null); const suffixEl = ref(null); const container = ref(null); const height = - props.small ? 35 : - props.large ? 39 : + props.small ? 34 : + props.large ? 40 : 37; const focus = () => inputEl.value.focus(); From 697836c17cc41ee8dff7d4daca51a89d9b0bd319 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 08:54:54 +0900 Subject: [PATCH 03/75] perf(client): improve MkTime performance --- packages/frontend/src/components/global/MkTime.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue index 0bbb0f5399..704e6d0de0 100644 --- a/packages/frontend/src/components/global/MkTime.vue +++ b/packages/frontend/src/components/global/MkTime.vue @@ -37,12 +37,13 @@ const relative = $computed(() => { }); function tick() { - // TODO: パフォーマンス向上のため、このコンポーネントが画面内に表示されている場合のみ更新する now = new Date(); + const ago = (now.getTime() - _time.getTime()) / 1000/*ms*/; + const next = ago < 60 ? 10000 : ago < 3600 ? 60000 : 180000; tickId = window.setTimeout(() => { window.requestAnimationFrame(tick); - }, 10000); + }, next); } let tickId: number; From 5906de5ca0e4ac7a96e4b1e0b722b6763cfeab4d Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 09:52:49 +0900 Subject: [PATCH 04/75] :art: --- packages/frontend/src/components/MkSuperMenu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue index e79794aea4..36960bfc31 100644 --- a/packages/frontend/src/components/MkSuperMenu.vue +++ b/packages/frontend/src/components/MkSuperMenu.vue @@ -62,7 +62,7 @@ export default defineComponent({ align-items: center; width: 100%; box-sizing: border-box; - padding: 10px 16px 10px 8px; + padding: 9px 16px 9px 8px; border-radius: 9px; font-size: 0.9em; From 1ed078d7f9ac04956ed99cad832c0b78f49cdd33 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 17:41:09 +0900 Subject: [PATCH 05/75] fix(server): fix pages/update --- packages/backend/src/server/api/endpoints/pages/update.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts index 4db0f80b26..35b402ec56 100644 --- a/packages/backend/src/server/api/endpoints/pages/update.ts +++ b/packages/backend/src/server/api/endpoints/pages/update.ts @@ -111,7 +111,7 @@ export default class extends Endpoint { updatedAt: new Date(), title: ps.title, name: ps.name === undefined ? page.name : ps.name, - summary: ps.name === undefined ? page.summary : ps.summary, + summary: ps.summary === undefined ? page.summary : ps.summary, content: ps.content, variables: ps.variables, script: ps.script, From d306db4ff8a79c674c44f6ad1013d657e4f71136 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 17:41:39 +0900 Subject: [PATCH 06/75] =?UTF-8?q?fix(server):=20pages/like=E3=81=AE?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BCID=E3=81=8C=E9=87=8D=E8=A4=87?= =?UTF-8?q?=E3=81=97=E3=81=A6=E3=81=84=E3=82=8B=E3=81=AE=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/api/endpoints/pages/like.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts index 41a11d1a31..d27990f7e1 100644 --- a/packages/backend/src/server/api/endpoints/pages/like.ts +++ b/packages/backend/src/server/api/endpoints/pages/like.ts @@ -28,7 +28,7 @@ export const meta = { alreadyLiked: { message: 'The page has already been liked.', code: 'ALREADY_LIKED', - id: 'cc98a8a2-0dc3-4123-b198-62c71df18ed3', + id: 'd4c1edbe-7da2-4eae-8714-1acfd2d63941', }, }, } as const; From 9bec87d9a569b3235c78a111c864e901ad8dd8ee Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 17:54:47 +0900 Subject: [PATCH 07/75] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a5e566263..ce996f5acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,8 @@ You should also include the user name that made the change. - Server: trim long text of note from ap @syuilo - Server: Ap inboxの最大ペイロードサイズを64kbに制限 @syuilo - Server: アンテナの作成数上限を追加 @syuilo +- Server: pages/likeのエラーIDが重複しているのを修正 @syuilo +- Server: pages/updateのパラメータによってはsummaryの値が更新されないのを修正 @syuilo - Client: case insensitive emoji search @saschanaz - Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina - Client: use proxied image for instance icon @syuilo From e02183bb1b14522c8ed7c4bb1cbd48f76026c208 Mon Sep 17 00:00:00 2001 From: tamaina Date: Wed, 4 Jan 2023 11:09:05 +0000 Subject: [PATCH 08/75] chore: remove unused function (truncateUnreadAntennaNote) --- .../src/core/PushNotificationService.ts | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts index 667dc9c1fa..b18b7bb2cd 100644 --- a/packages/backend/src/core/PushNotificationService.ts +++ b/packages/backend/src/core/PushNotificationService.ts @@ -47,26 +47,6 @@ function truncateBody(type: T, body: pus return body; } -function truncateUnreadAntennaNote(notification: pushNotificationsTypes['unreadAntennaNote']): pushNotificationsTypes['unreadAntennaNote'] { - if (notification.note) { - return { - ...notification, - note: { - ...notification.note, - // textをgetNoteSummaryしたものに置き換える - text: getNoteSummary(('type' in notification && notification.type === 'renote') ? notification.note.renote as Packed<'Note'> : notification.note), - - cw: undefined, - reply: undefined, - renote: undefined, - user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる アンテナの場合も不要なのでいらない - }, - }; - } - - return notification; -} - @Injectable() export class PushNotificationService { constructor( From e1fe06e5974df6a56345258c7b8bc2bf62c49178 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 21:22:47 +0900 Subject: [PATCH 09/75] New Crowdin updates (#9458) * New translations ja-JP.yml (German) * New translations ja-JP.yml (English) * New translations ja-JP.yml (Thai) * New translations ja-JP.yml (Chinese Simplified) * New translations ja-JP.yml (Italian) * New translations ja-JP.yml (Romanian) * New translations ja-JP.yml (French) * New translations ja-JP.yml (Spanish) * New translations ja-JP.yml (Arabic) * New translations ja-JP.yml (Catalan) * New translations ja-JP.yml (Czech) * New translations ja-JP.yml (German) * New translations ja-JP.yml (Italian) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Dutch) * New translations ja-JP.yml (Polish) * New translations ja-JP.yml (Portuguese) * New translations ja-JP.yml (Russian) * New translations ja-JP.yml (Slovak) * New translations ja-JP.yml (Swedish) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Chinese Simplified) * New translations ja-JP.yml (Chinese Traditional) * New translations ja-JP.yml (English) * New translations ja-JP.yml (Vietnamese) * New translations ja-JP.yml (Indonesian) * New translations ja-JP.yml (Bengali) * New translations ja-JP.yml (Thai) * New translations ja-JP.yml (Japanese, Kansai) * New translations ja-JP.yml (French) * New translations ja-JP.yml (French) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Spanish) --- locales/ar-SA.yml | 1 - locales/bn-BD.yml | 1 - locales/ca-ES.yml | 1 - locales/cs-CZ.yml | 1 - locales/de-DE.yml | 2 +- locales/en-US.yml | 2 +- locales/es-ES.yml | 26 +++++++++++++++++++++++++- locales/fr-FR.yml | 26 +++++++++++++++++++++++++- locales/id-ID.yml | 1 - locales/it-IT.yml | 10 +++++++++- locales/ja-KS.yml | 1 - locales/ko-KR.yml | 3 ++- locales/nl-NL.yml | 1 - locales/pl-PL.yml | 1 - locales/pt-PT.yml | 1 - locales/ro-RO.yml | 1 - locales/ru-RU.yml | 1 - locales/sk-SK.yml | 1 - locales/sv-SE.yml | 1 - locales/th-TH.yml | 2 +- locales/uk-UA.yml | 1 - locales/vi-VN.yml | 1 - locales/zh-CN.yml | 5 +++-- locales/zh-TW.yml | 1 - 24 files changed, 67 insertions(+), 25 deletions(-) diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index eefb41007b..7a9c235235 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -164,7 +164,6 @@ annotation: "التعليقات" federation: "الفديرالية" instances: "مثيل الخادم" registeredAt: "مسجل منذ" -latestRequestSentAt: "آخر طلب أرسِل في" latestRequestReceivedAt: "آخر طلب تُلقي في" latestStatus: "الحالات الأخيرة" storageUsage: "مساحة التخزين المستخدمة" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 85ec1d9935..a56c06c9da 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -164,7 +164,6 @@ annotation: "মন্তব্য" federation: "ফেডিভার্স" instances: "ইন্সট্যান্স" registeredAt: "যোগ দিয়েছেন" -latestRequestSentAt: "শেষ রিকুয়েস্ট পাঠানো হয়েছে" latestRequestReceivedAt: "শেষ রিকুয়েস্ট গৃহীত হয়েছে" latestStatus: "সর্বশেষ অবস্থা" storageUsage: "স্টোরেজের ব্যাবহার" diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 406fdff0b4..5127803ebc 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -165,7 +165,6 @@ annotation: "Comentaris" federation: "Federació" instances: "Servidors" registeredAt: "Registrat a" -latestRequestSentAt: "Darrera petició enviada" latestRequestReceivedAt: "Última petició rebuda" latestStatus: "Últim estat" storageUsage: "Emmagatzematge utilitzat" diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index 552b56a430..ebe866651c 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -161,7 +161,6 @@ annotation: "Komentáře" federation: "Federace" instances: "Instance" registeredAt: "Registrován" -latestRequestSentAt: "Poslední požadavek poslán" latestRequestReceivedAt: "Poslední požadavek přijat" latestStatus: "Poslední status" storageUsage: "Využití úložiště" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index dfac4fb791..275e4677d6 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -167,7 +167,6 @@ annotation: "Anmerkung" federation: "Föderation" instances: "Instanzen" registeredAt: "Registriert am" -latestRequestSentAt: "Letzte Anfrage gesendet" latestRequestReceivedAt: "Letzte Anfrage erhalten" latestStatus: "Neuster Status" storageUsage: "Verbrauchter Speicherplatz" @@ -916,6 +915,7 @@ caption: "Beschreibung" loggedInAsBot: "Momentan als Bot angemeldet" tools: "Werkzeuge" cannotLoad: "Kann nicht geladen werden" +numberOfProfileView: "Profilaufrufe" _sensitiveMediaDetection: description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht." sensitivity: "Erkennungssensitivität" diff --git a/locales/en-US.yml b/locales/en-US.yml index 414bc1df51..9ff4461522 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -167,7 +167,6 @@ annotation: "Comments" federation: "Federation" instances: "Instances" registeredAt: "Registered at" -latestRequestSentAt: "Last request sent" latestRequestReceivedAt: "Last request received" latestStatus: "Latest status" storageUsage: "Storage usage" @@ -916,6 +915,7 @@ caption: "Caption" loggedInAsBot: "Currently logged in as bot" tools: "Tools" cannotLoad: "Unable to load" +numberOfProfileView: "Profile views" _sensitiveMediaDetection: description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server." sensitivity: "Detection sensitivity" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 50db3fe306..0a1157230a 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -13,6 +13,7 @@ fetchingAsApObject: "Buscando en el fediverso" ok: "OK" gotIt: "¡Lo tengo!" cancel: "Cancelar" +noThankYou: "No gracias" enterUsername: "Introduce el nombre de usuario" renotedBy: "Renotado por {user}" noNotes: "No hay notas" @@ -48,6 +49,7 @@ deleteAndEdit: "Borrar y editar" deleteAndEditConfirm: "¿Estás seguro de que quieres borrar esta nota y editarla? Perderás todas las reacciones, renotas y respuestas." addToList: "Agregar a lista" sendMessage: "Enviar un mensaje" +copyRSS: "Copiar RSS" copyUsername: "Copiar nombre de usuario" searchUser: "Buscar un usuario" reply: "Responder" @@ -165,7 +167,6 @@ annotation: "Anotación" federation: "Federación" instances: "Instancia" registeredAt: "Registrado en" -latestRequestSentAt: "Ultimo pedido enviado" latestRequestReceivedAt: "Ultimo pedido recibido" latestStatus: "Último status" storageUsage: "Almacenamiento usado" @@ -455,6 +456,8 @@ language: "Idioma" uiLanguage: "Idioma de visualización de la interfaz" groupInvited: "Invitado al grupo" aboutX: "Acerca de {x}" +emojiStyle: "Estilo de emoji" +native: "Nativo" disableDrawer: "No mostrar los menús en cajones" youHaveNoGroups: "Sin grupos" joinOrCreateGroup: "Obtenga una invitación para unirse al grupos o puede crear su propio grupo." @@ -713,6 +716,7 @@ accentColor: "Acento" textColor: "Texto" saveAs: "Guardar como…" advanced: "Avanzado" +advancedSettings: "Configuración avanzada" value: "Valores" createdAt: "Fecha de creación" updatedAt: "Actualizado" @@ -898,6 +902,20 @@ navbar: "Barra de navegación" shuffle: "Aleatorio" account: "Cuentas" move: "Mover" +pushNotification: "Alerta emergente" +subscribePushNotification: "Activar las notificaciones emergentes" +unsubscribePushNotification: "Desactivar las notificaciones emergentes" +pushNotificationAlreadySubscribed: "Notificaciones emergentes ya activadas" +pushNotificationNotSupported: "El navegador o la instancia no admiten notificaciones push" +sendPushNotificationReadMessage: "Eliminar las notificaciones push después de leer las notificaciones y los mensajes" +sendPushNotificationReadMessageCaption: "La notificación \"{emptyPushNotificationMessage}\" aparecerá momentáneamente. Esto puede aumentar el consumo de batería del dispositivo." +windowMaximize: "Maximizar" +windowRestore: "Regresar" +caption: "Pie de foto" +loggedInAsBot: "Inicio sesión como cuenta bot." +tools: "Utilidades" +cannotLoad: "No se puede cargar." +numberOfProfileView: "Número de vistas de perfil" _sensitiveMediaDetection: description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor." sensitivity: "Sensibilidad de detección" @@ -1208,6 +1226,9 @@ _tutorial: step7_1: "Así terminó la explicación del funcionamiento básico de Misskey. Eso fue todo." step7_2: "Si quieres conocer más sobre Misskey, prueba con la sección {help}." step7_3: "Así, disfruta de Misskey 🚀" + step8_1: "Por último, ¿por qué no activar las notificaciones emergentes?" + step8_2: "Al recibir notificaciones emergentes, estarás al tanto de reacciones, seguimientos y menciones incluso cuando Misskey no esté abierto." + step8_3: "La configuración de las notificaciones puede modificarse posteriormente." _2fa: alreadyRegistered: "Ya has completado la configuración." registerDevice: "Registrar dispositivo" @@ -1295,6 +1316,7 @@ _widgets: serverMetric: "Estadísticas del servidor" aiscript: "Consola de AiScript" aichan: "indigo" + userList: "Lista de usuarios" _userList: chooseList: "Seleccione una lista" _cw: @@ -1360,6 +1382,7 @@ _profile: changeBanner: "Cambiar banner" _exportOrImport: allNotes: "Todas las notas" + favoritedNotes: "Notas favoritas" followingList: "Siguiendo" muteList: "Silenciados" blockingList: "Bloqueados" @@ -1464,6 +1487,7 @@ _notification: yourFollowRequestAccepted: "Tu solicitud de seguimiento fue aceptada" youWereInvitedToGroup: "Invitado al grupo" pollEnded: "Estan disponibles los resultados de la encuesta" + unreadAntennaNote: "Antena {name}" emptyPushNotificationMessage: "Se han actualizado las notificaciones push" _types: all: "Todo" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 0df7ee2e12..35c490bcff 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -2,6 +2,7 @@ _lang_: "Français" headlineMisskey: "Réseau relié par des notes" introMisskey: "Bienvenue ! Misskey est un service de microblogage décentralisé, libre et ouvert.\nÉcrivez des « notes » et partagez ce qui se passe à l’instant présent, autour de vous avec les autres 📡\nLa fonction « réactions », vous permet également d’ajouter une réaction rapide aux notes des autres utilisateur·rice·s 👍\nExplorons un nouveau monde 🚀" +poweredByMisskeyDescription: "{nom} est l'un des services propulsés par la plateforme ouverte Misskey (appelée \"instance Misskey\")." monthAndDay: "{day}/{month}" search: "Rechercher" notifications: "Notifications" @@ -12,6 +13,7 @@ fetchingAsApObject: "Récupération depuis le fédiverse …" ok: "OK" gotIt: "J’ai compris !" cancel: "Annuler" +noThankYou: "Pas maintenant" enterUsername: "Entrer un nom d’utilisateur·rice" renotedBy: "Renoté par {user}" noNotes: "Aucune note" @@ -47,6 +49,7 @@ deleteAndEdit: "Supprimer et réécrire" deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la reformuler ? Vous perdrez toutes les réactions, renotes et réponses y afférentes." addToList: "Ajouter à une liste" sendMessage: "Envoyer un message" +copyRSS: "Copier le RSS" copyUsername: "Copier le nom d’utilisateur·rice" searchUser: "Chercher un·e utilisateur·rice" reply: "Répondre" @@ -143,6 +146,7 @@ flagAsBotDescription: "Si ce compte est géré de manière automatisée, choisis flagAsCat: "Ce compte est un chat" flagAsCatDescription: "Activer l'option \" Je suis un chat \" pour ce compte." flagShowTimelineReplies: "Afficher les réponses dans le fil" +flagShowTimelineRepliesDescription: "Affiche les réponses des utilisateurs aux notes des autres utilisateurs dans la timeline si cette option est activée." autoAcceptFollowed: "Accepter automatiquement les demandes d’abonnement venant d’utilisateur·rice·s que vous suivez" addAccount: "Ajouter un compte" loginFailed: "Échec de la connexion" @@ -163,7 +167,6 @@ annotation: "Commentaires" federation: "Fédération" instances: "Instance" registeredAt: "Premier contact le" -latestRequestSentAt: "Dernière requête envoyée" latestRequestReceivedAt: "Dernière requête reçue" latestStatus: "Dernier statut" storageUsage: "Stockage utilisé" @@ -453,6 +456,8 @@ language: "Langue" uiLanguage: "Langue d’affichage de l’interface" groupInvited: "Invité au groupe" aboutX: "À propos de {x}" +emojiStyle: "Style des émojis" +native: "Natif" disableDrawer: "Les menus ne s'affichent pas dans le tiroir" youHaveNoGroups: "Vous n’avez aucun groupe" joinOrCreateGroup: "Vous pouvez être invité·e à rejoindre des groupes existants ou créer votre propre nouveau groupe." @@ -600,6 +605,7 @@ smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé" testEmail: "Tester la distribution de courriel" wordMute: "Filtre de mots" regexpError: "Erreur d’expression régulière" +regexpErrorDescription: "Une erreur s'est produite dans l'expression régulière sur la ligne {ligne} de votre mot muet {tab} :" instanceMute: "Instance en sourdine" userSaysSomething: "{name} a dit quelque chose" makeActive: "Activer" @@ -708,6 +714,7 @@ accentColor: "Accentuation" textColor: "Texte" saveAs: "Enregistrer sous ..." advanced: "Avancé" +advancedSettings: "Paramètres avancés" value: "Valeur" createdAt: "Date de création" updatedAt: "Mis à jour le" @@ -852,6 +859,7 @@ rateLimitExceeded: "Limite de taux dépassée" cropImage: "Recadrer l'image" cropImageAsk: "Voulez-vous recadrer cette image ?" file: "Fichiers" +recentNHours: "Dernières {n} heures" noEmailServerWarning: "Serveur de courrier non configuré." thereIsUnresolvedAbuseReportWarning: "Il n’y a aucun rapport non résolu." recommended: "Recommandé" @@ -891,6 +899,17 @@ navbar: "Barre de navigation" shuffle: "Lecture aléatoire" account: "Comptes" move: "Déplacer" +pushNotification: "Notifications push" +subscribePushNotification: "Autoriser les notifications push" +unsubscribePushNotification: "Désactiver les notifications push" +pushNotificationAlreadySubscribed: "Les notifications push sont déjà activées" +pushNotificationNotSupported: "Votre navigateur ou votre instance ne prend pas en charge les notifications push" +sendPushNotificationReadMessage: "Supprimer les notifications push une fois que les notifications ou messages pertinents ont été lus." +windowRestore: "Restaurer" +caption: "Libellé" +loggedInAsBot: "Connecté actuellement en tant que bot" +tools: "Outils" +cannotLoad: "Chargement impossible" _sensitiveMediaDetection: description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement." sensitivity: "Sensibilité de la détection" @@ -1201,6 +1220,8 @@ _tutorial: step7_1: "Félicitations ! Vous avez atteint la fin du tutoriel de base pour l’utilisation de Misskey." step7_2: "Si vous désirez en savoir plus sur Misskey, jetez un œil sur la section {help}." step7_3: "Bon courage et amusez-vous bien sur Misskey ! 🚀" + step8_1: "Enfin, souhaitez-vous activer les notifications push ?" + step8_2: "En les activant, vous recevrez des notifications pour les mentions, les réactions, les suivis, etc., même lorsque Misskey n'est pas ouvert." _2fa: alreadyRegistered: "Configuration déjà achevée." registerDevice: "Ajouter un nouvel appareil" @@ -1287,6 +1308,7 @@ _widgets: serverMetric: "Statistiques du serveur" aiscript: "Console AiScript" aichan: "Ai" + userList: "Liste utilisateur" _userList: chooseList: "Sélectionner une liste" _cw: @@ -1456,6 +1478,7 @@ _notification: yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté" youWereInvitedToGroup: "Invité·e au groupe" pollEnded: "Les résultats du sondage sont disponibles" + unreadAntennaNote: "Antenne {name}" emptyPushNotificationMessage: "Les notifications push ont été mises à jour" _types: all: "Toutes" @@ -1490,6 +1513,7 @@ _deck: newProfile: "Nouveau profil" deleteProfile: "Supprimer le profil" introduction: "Créez l’interface parfaite qui vous sied en arrangeant librement les colonnes !" + introduction2: "Cliquez sur le + à droite de l'écran pour ajouter de nouvelles colonnes quand vous le souhaitez." _columns: main: "Principale" widgets: "Widgets" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index a73e108d7f..1fdba0dd40 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -164,7 +164,6 @@ annotation: "Keterangan konten" federation: "Federasi" instances: "Instansi" registeredAt: "Terdaftar" -latestRequestSentAt: "Permintaan terakhir dikirim pada" latestRequestReceivedAt: "Permintaan terakhir diterima pada" latestStatus: "Status terakhir" storageUsage: "Penggunaan penyimpanan" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 6b1b47f4e2..0298be19ea 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -49,6 +49,7 @@ deleteAndEdit: "Elimina e modifica" deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo? Verrano eliminate anche tutte le reazioni, Rinote e risposte collegate." addToList: "Aggiungi alla lista" sendMessage: "Invia messaggio" +copyRSS: "Copia RSS" copyUsername: "Copia nome utente" searchUser: "Cerca utente" reply: "Rispondi" @@ -166,7 +167,6 @@ annotation: "Descrizione" federation: "Federazione" instances: "Istanza" registeredAt: "Registrato presso" -latestRequestSentAt: "Ultima richiesta inviata" latestRequestReceivedAt: "Ultima richiesta ricevuta" latestStatus: "Ultimo stato" storageUsage: "Capienza dei dischi" @@ -456,6 +456,8 @@ language: "Lingua" uiLanguage: "Lingua di visualizzazione dell'interfaccia" groupInvited: "Invitat@ al gruppo" aboutX: "Informazioni su {x}" +emojiStyle: "Stile emoji" +native: "Nativo" disableDrawer: "Non mostrare il menù sul drawer" youHaveNoGroups: "Nessun gruppo" joinOrCreateGroup: "Puoi creare il tuo gruppo o essere invitat@ a gruppi che già esistono." @@ -714,6 +716,7 @@ accentColor: "Colore principale" textColor: "Testo" saveAs: "Salva con nome" advanced: "Avanzato" +advancedSettings: "Impostazioni avanzate" value: "Valore" createdAt: "Data di creazione" updatedAt: "Aggiornato il" @@ -910,6 +913,9 @@ windowMaximize: "Ingrandisci" windowRestore: "Ripristina" caption: "Didascalia" loggedInAsBot: "Connessione come Bot" +tools: "Strumenti" +cannotLoad: "Caricamento impossibile" +numberOfProfileView: "Visualizzazioni profilo" _sensitiveMediaDetection: description: "L'apprendimento automatico può essere utilizzato per individuare automaticamente i media sensibili da moderare. Il carico del server aumenta leggermente." sensitivity: "Sensibilità di rilevamento" @@ -1310,6 +1316,7 @@ _widgets: serverMetric: "Statistiche server" aiscript: "Console AiScript" aichan: "indaco (tintura)" + userList: "Elenco utenti" _userList: chooseList: "Seleziona una lista" _cw: @@ -1375,6 +1382,7 @@ _profile: changeBanner: "Cambia intestazione" _exportOrImport: allNotes: "Tutte le note" + favoritedNotes: "Note preferite" followingList: "Follows" muteList: "Elenco profili silenziati" blockingList: "Elenco profili bloccati" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 994fe9a195..6e1bed8269 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -167,7 +167,6 @@ annotation: "注釈" federation: "連合" instances: "インスタンス" registeredAt: "初観測" -latestRequestSentAt: "ちょっと前のリクエスト送信" latestRequestReceivedAt: "ちょっと前のリクエスト受信" latestStatus: "ちょっと前のステータス" storageUsage: "ストレージ使うた量" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index fa73d49a34..746b59fc2a 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -167,7 +167,6 @@ annotation: "내용에 대한 주석" federation: "연합" instances: "인스턴스" registeredAt: "등록 날짜" -latestRequestSentAt: "마지막으로 요청을 보낸 시간" latestRequestReceivedAt: "마지막으로 요청을 받은 시간" latestStatus: "마지막 상태" storageUsage: "스토리지 사용량" @@ -916,6 +915,7 @@ caption: "캡션" loggedInAsBot: "봇 계정으로 로그인중" tools: "도구" cannotLoad: "불러오지 못했습니다" +numberOfProfileView: "프로필 뷰 수" _sensitiveMediaDetection: description: "기계학습을 통해 자동으로 민감한 미디어를 탐지하여, 모더레이션에 참고할 수 있도록 합니다. 서버의 부하를 약간 증가시킵니다." sensitivity: "탐지 민감도" @@ -1382,6 +1382,7 @@ _profile: changeBanner: "배너 이미지 변경" _exportOrImport: allNotes: "모든 노트" + favoritedNotes: "즐겨찾기한 노트" followingList: "팔로잉" muteList: "뮤트" blockingList: "차단" diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index ad7ab9723e..93ed3fa7e2 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -165,7 +165,6 @@ annotation: "Reacties" federation: "Federatie" instances: "Server" registeredAt: "Geregistreerd op" -latestRequestSentAt: "Laatste aanvraag verstuurd" latestRequestReceivedAt: "Laatste aanvraag ontvangen" latestStatus: "Laatste status" storageUsage: "Gebruikte opslagruimte" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 6c3b100885..f898f52929 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -165,7 +165,6 @@ annotation: "Komentarze" federation: "Federacja" instances: "Instancja" registeredAt: "Zarejestrowano" -latestRequestSentAt: "Ostatnie żądanie wysłano o" latestRequestReceivedAt: "Ostatnie żądanie otrzymano o" latestStatus: "Najnowszy status" storageUsage: "Użycie pamięci" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index d333405316..dd1c2954b7 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -164,7 +164,6 @@ annotation: "Anotação" federation: "União" instances: "Instância" registeredAt: "Registrado em" -latestRequestSentAt: "Enviar a solicitação mais recente" latestRequestReceivedAt: "Recebeu a última solicitação" latestStatus: "Status mais recente" storageUsage: "Uso de armazenamento" diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 4bb1d4f09a..54d382474d 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -164,7 +164,6 @@ annotation: "Adnotări" federation: "Federație" instances: "Instanțe" registeredAt: "Înregistrat în" -latestRequestSentAt: "Ultima cerere trimisă" latestRequestReceivedAt: "Ultima cerere primită" latestStatus: "Ultimul status" storageUsage: "Utilizare stocare" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 7c256b3bef..19dfcc3af9 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -164,7 +164,6 @@ annotation: "Описание" federation: "Федерация" instances: "Инстанс" registeredAt: "Первое наблюдение" -latestRequestSentAt: "Последний отправленный запрос" latestRequestReceivedAt: "Последний полученный запрос" latestStatus: "Последний статус" storageUsage: "Использовано" diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 03a531e63b..1c57b6c2bb 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -167,7 +167,6 @@ annotation: "Komentáre" federation: "Federácia" instances: "Inštancia" registeredAt: "Registrácia" -latestRequestSentAt: "Posledná odoslaná požiadavka" latestRequestReceivedAt: "Posledná prijatá požiadavka" latestStatus: "Posledný status" storageUsage: "Využité úložisko" diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index b00808d3d0..e4e00e341d 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -163,7 +163,6 @@ annotation: "Kommentarer" federation: "Federation" instances: "Instanser" registeredAt: "Registrerad på" -latestRequestSentAt: "Senaste förfrågan skickad" latestRequestReceivedAt: "Senaste begäran mottagen" latestStatus: "Senaste status" storageUsage: "Använt lagringsutrymme" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 9dfcf0d2c4..7fc54f5f19 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -167,7 +167,6 @@ annotation: "ความคิดเห็น" federation: "เฟดิเวิร์ส" instances: "ตัวอย่าง" registeredAt: "จดทะเบียนที่" -latestRequestSentAt: "ส่งคำขอล่าสุดไปแล้ว" latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว" latestStatus: "สถานะล่าสุด" storageUsage: "พื้นที่จัดเก็บข้อมูลที่ใช้ไป" @@ -916,6 +915,7 @@ caption: "รายละเอียด" loggedInAsBot: "ล็อกอินเป็นบอตอยู่ในขณะนี้" tools: "เครื่องมือ" cannotLoad: "ไม่สามารถโหลดได้" +numberOfProfileView: "มุมมองโปรไฟล์" _sensitiveMediaDetection: description: "ลดความพยายามในการดูแลเซิร์ฟเวอร์ผ่านการจดจำสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่อง การทำสิ่งนี้อาจจะเพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย" sensitivity: "การตรวจจับความไว" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index cb52a86d98..49a59500ff 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -166,7 +166,6 @@ annotation: "Коментарі" federation: "Федіверс" instances: "Інстанс" registeredAt: "Приєднався(лась)" -latestRequestSentAt: "Останній запит надіслано" latestRequestReceivedAt: "Останній запит прийнято" latestStatus: "Останній статус" storageUsage: "Використання простору" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index fdb6ec2647..b496cfaf22 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -164,7 +164,6 @@ annotation: "Bình luận" federation: "Liên hợp" instances: "Máy chủ" registeredAt: "Đăng ký vào" -latestRequestSentAt: "Yêu cầu cuối gửi lúc" latestRequestReceivedAt: "Yêu cầu cuối nhận lúc" latestStatus: "Trạng thái cuối cùng" storageUsage: "Dung lượng lưu trữ" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 80d367a284..1e147752db 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -167,7 +167,6 @@ annotation: "注解" federation: "联合" instances: "实例" registeredAt: "初次观测" -latestRequestSentAt: "上次发送的请求" latestRequestReceivedAt: "上次收到的请求" latestStatus: "最后状态" storageUsage: "已用存储" @@ -913,9 +912,10 @@ sendPushNotificationReadMessageCaption: "“{emptyPushNotificationMessage}”的 windowMaximize: "最大化" windowRestore: "还原" caption: "标题" -loggedInAsBot: "已登录的Bot" +loggedInAsBot: "以Bot账户登录" tools: "工具" cannotLoad: "无法加载" +numberOfProfileView: "个人资料展示次数" _sensitiveMediaDetection: description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。" sensitivity: "检测敏感度" @@ -1382,6 +1382,7 @@ _profile: changeBanner: "修改横幅" _exportOrImport: allNotes: "所有帖子" + favoritedNotes: "收藏的帖子" followingList: "关注中" muteList: "屏蔽" blockingList: "拉黑" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index a97593e59c..8f8a8865ac 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -167,7 +167,6 @@ annotation: "註解" federation: "站台聯邦" instances: "實例" registeredAt: "初次觀測" -latestRequestSentAt: "上次發送的請求" latestRequestReceivedAt: "上次收到的請求" latestStatus: "最後狀態" storageUsage: "已使用容量" From f51220a5bfeacb7ff14ac3a7ee68a1158b94b4aa Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2023 21:23:48 +0900 Subject: [PATCH 10/75] 13.0.0-beta.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e3bf82a7b..5ab38a56ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.0.0-beta.20", + "version": "13.0.0-beta.21", "codename": "indigo", "repository": { "type": "git", From b1a75177a0165f726741219206bb52c02c5f6221 Mon Sep 17 00:00:00 2001 From: tamaina Date: Thu, 5 Jan 2023 03:28:25 +0900 Subject: [PATCH 11/75] =?UTF-8?q?enhance:=20RSS=E3=82=A6=E3=82=A3=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=83=83=E3=83=88=20/=20RSS=E3=83=86=E3=82=A3?= =?UTF-8?q?=E3=83=83=E3=82=AB=E3=83=BC=E3=82=A6=E3=82=A3=E3=82=B8=E3=82=A7?= =?UTF-8?q?=E3=83=83=E3=83=88=E3=82=92=E3=81=84=E3=81=84=E6=84=9F=E3=81=98?= =?UTF-8?q?=E3=81=AB=E3=81=99=E3=82=8B=20(#9469)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :v: * use useInterval * :v: * rawItems.value.length !== 0 * fix * https://github.com/misskey-dev/misskey/pull/9469#discussion_r1061763613 --- packages/frontend/src/scripts/use-interval.ts | 11 +- packages/frontend/src/widgets/rss-ticker.vue | 157 +++++++++++------- packages/frontend/src/widgets/rss.vue | 88 ++++++---- 3 files changed, 159 insertions(+), 97 deletions(-) diff --git a/packages/frontend/src/scripts/use-interval.ts b/packages/frontend/src/scripts/use-interval.ts index 201ba417ef..601dea6724 100644 --- a/packages/frontend/src/scripts/use-interval.ts +++ b/packages/frontend/src/scripts/use-interval.ts @@ -3,7 +3,7 @@ import { onMounted, onUnmounted } from 'vue'; export function useInterval(fn: () => void, interval: number, options: { immediate: boolean; afterMounted: boolean; -}): void { +}): (() => void) | undefined { if (Number.isNaN(interval)) return; let intervalId: number | null = null; @@ -18,7 +18,14 @@ export function useInterval(fn: () => void, interval: number, options: { intervalId = window.setInterval(fn, interval); } - onUnmounted(() => { + const clear = () => { if (intervalId) window.clearInterval(intervalId); + intervalId = null; + }; + + onUnmounted(() => { + clear(); }); + + return clear; } diff --git a/packages/frontend/src/widgets/rss-ticker.vue b/packages/frontend/src/widgets/rss-ticker.vue index c2d6dd2873..37672e13cf 100644 --- a/packages/frontend/src/widgets/rss-ticker.vue +++ b/packages/frontend/src/widgets/rss-ticker.vue @@ -3,13 +3,15 @@ -
- -
- +
+
+ +
+
+ - - {{ item.title }} + + {{ item.title }} @@ -19,14 +21,14 @@ - diff --git a/packages/frontend/src/widgets/rss.vue b/packages/frontend/src/widgets/rss.vue index c0338c8e47..554413cd1e 100644 --- a/packages/frontend/src/widgets/rss.vue +++ b/packages/frontend/src/widgets/rss.vue @@ -5,19 +5,24 @@
-
- {{ item.title }} +
+ +
{{ i18n.ts.nothing }}
+
+
- From 5d904b05dd09c635f9bfe4582eede3727b0aa382 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 5 Jan 2023 03:29:50 +0900 Subject: [PATCH 12/75] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce996f5acd..83d013ce99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ You should also include the user name that made the change. - Client: Make widgets of universal/classic sync between devices @tamaina - Client: Implement the button to subscribe push notification @tamaina - Client: Implement the toggle to or not to close push notifications when notifications or messages are read @tamaina +- Client: Improve RSS widget @tamaina - Client: show Unicode emoji tooltip with its name in MkReactionsViewer.reaction @saschanaz - Client: OpenSearch support @SoniEx2 @chaoticryptidz - Client: add user list widget @syuilo From ebe340d5105595abe2406e8f386c3ab69703b73b Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 5 Jan 2023 13:59:48 +0900 Subject: [PATCH 13/75] MisskeyPlay (#9467) * wip * wip * wip * wip * wip * Update ui.ts * wip * wip * wip * wip * wip * wip * wip * wip * Update CHANGELOG.md * wip * wip * wip * wip * :art: * wip * :v: --- CHANGELOG.md | 10 +- locales/ja-JP.yml | 21 + .../backend/migration/1672822262496-Flash.js | 29 + packages/backend/src/core/CoreModule.ts | 12 + .../src/core/entities/FlashEntityService.ts | 55 ++ .../core/entities/FlashLikeEntityService.ts | 44 ++ packages/backend/src/di-symbols.ts | 2 + .../backend/src/models/RepositoryModule.ts | 18 +- packages/backend/src/models/entities/Flash.ts | 60 ++ .../backend/src/models/entities/FlashLike.ts | 33 ++ packages/backend/src/models/index.ts | 6 + packages/backend/src/postgre.ts | 4 + .../backend/src/server/api/EndpointsModule.ts | 36 ++ packages/backend/src/server/api/endpoints.ts | 18 + .../src/server/api/endpoints/flash/create.ts | 66 +++ .../src/server/api/endpoints/flash/delete.ts | 56 ++ .../server/api/endpoints/flash/featured.ts | 48 ++ .../src/server/api/endpoints/flash/like.ts | 87 +++ .../server/api/endpoints/flash/my-likes.ts | 68 +++ .../src/server/api/endpoints/flash/my.ts | 57 ++ .../src/server/api/endpoints/flash/show.ts | 60 ++ .../src/server/api/endpoints/flash/unlike.ts | 68 +++ .../src/server/api/endpoints/flash/update.ts | 78 +++ packages/frontend/src/components/MkAsUi.vue | 107 ++++ packages/frontend/src/components/MkButton.vue | 40 +- .../frontend/src/components/MkChartLegend.vue | 2 +- .../src/components/MkFlashPreview.vue | 112 ++++ .../frontend/src/components/MkLaunchPad.vue | 2 +- .../frontend/src/components/MkPagePreview.vue | 19 +- .../frontend/src/components/form/select.vue | 2 +- packages/frontend/src/navbar.ts | 39 +- .../frontend/src/pages/flash/flash-edit.vue | 111 ++++ .../frontend/src/pages/flash/flash-index.vue | 99 ++++ packages/frontend/src/pages/flash/flash.vue | 291 ++++++++++ packages/frontend/src/pages/page.vue | 18 +- packages/frontend/src/pages/scratchpad.vue | 104 ++-- .../frontend/src/pages/settings/navbar.vue | 2 +- packages/frontend/src/router.ts | 14 + packages/frontend/src/scripts/aiscript/ui.ts | 526 ++++++++++++++++++ .../src/ui/_common_/navbar-for-mobile.vue | 2 +- packages/frontend/src/ui/_common_/navbar.vue | 4 +- packages/frontend/src/ui/classic.header.vue | 2 +- packages/frontend/src/ui/classic.sidebar.vue | 2 +- .../frontend/src/widgets/aiscript-app.vue | 122 ++++ packages/frontend/src/widgets/index.ts | 2 + 45 files changed, 2465 insertions(+), 93 deletions(-) create mode 100644 packages/backend/migration/1672822262496-Flash.js create mode 100644 packages/backend/src/core/entities/FlashEntityService.ts create mode 100644 packages/backend/src/core/entities/FlashLikeEntityService.ts create mode 100644 packages/backend/src/models/entities/Flash.ts create mode 100644 packages/backend/src/models/entities/FlashLike.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/create.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/delete.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/featured.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/like.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/my-likes.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/my.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/show.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/unlike.ts create mode 100644 packages/backend/src/server/api/endpoints/flash/update.ts create mode 100644 packages/frontend/src/components/MkAsUi.vue create mode 100644 packages/frontend/src/components/MkFlashPreview.vue create mode 100644 packages/frontend/src/pages/flash/flash-edit.vue create mode 100644 packages/frontend/src/pages/flash/flash-index.vue create mode 100644 packages/frontend/src/pages/flash/flash.vue create mode 100644 packages/frontend/src/scripts/aiscript/ui.ts create mode 100644 packages/frontend/src/widgets/aiscript-app.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 83d013ce99..005b011592 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ You should also include the user name that made the change. - Migrate to Yarn Berry (v3.2.1) @ThatOneCalculator - You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic - 新たに動的なPagesを作ることはできなくなりました - - 代わりに今後AiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能の実装を予定しています。 + - 代わりにAiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能が実装されています。 - AiScriptが0.12.0にアップデートされました - 0.12.0の変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120 - 0.12.0未満のプラグインは読み込むことはできません @@ -33,12 +33,13 @@ You should also include the user name that made the change. - API: `instance`エンティティに`latestStatus`、`lastCommunicatedAt`、`latestRequestSentAt`プロパティが含まれなくなりました ### Improvements -- Push notification of Antenna note @tamaina -- AVIF support @tamaina -- Add Cloudflare Turnstile CAPTCHA support @CyberRex0 +- Misskey Play @syuilo - Introduce retention-rate aggregation @syuilo - Make possible to export favorited notes @syuilo - Add per user pv chart @syuilo +- Push notification of Antenna note @tamaina +- AVIF support @tamaina +- Add Cloudflare Turnstile CAPTCHA support @CyberRex0 - Server: signToActivityPubGet is set to true by default @syuilo - Server: improve syslog performance @syuilo - Server: improve note scoring for featured notes @CyberRex0 @@ -47,6 +48,7 @@ You should also include the user name that made the change. - Server: delete outdated notes of antenna regularly to improve db performance @syuilo - Server: improve activitypub deliver performance @syuilo - Client: use tabler-icons instead of fontawesome to better design @syuilo +- Client: Add AiScript App widget - Client: Add new gabber kick sounds (thanks for noizenecio) - Client: Add link to user RSS feed in profile menu @ssmucny - Client: Compress non-animated PNG files @saschanaz diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index d6a5518196..32bafcd661 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -916,6 +916,10 @@ loggedInAsBot: "Botアカウントでログイン中" tools: "ツール" cannotLoad: "読み込めません" numberOfProfileView: "プロフィール表示回数" +like: "いいね!" +unlike: "いいねを解除" +numberOfLikes: "いいね数" +show: "表示" _sensitiveMediaDetection: description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。" @@ -1348,6 +1352,7 @@ _widgets: jobQueue: "ジョブキュー" serverMetric: "サーバーメトリクス" aiscript: "AiScriptコンソール" + aiscriptApp: "AiScript App" aichan: "藍" userList: "ユーザーリスト" _userList: @@ -1463,6 +1468,22 @@ _timelines: social: "ソーシャル" global: "グローバル" +_play: + new: "Playの作成" + edit: "Playの編集" + created: "Playを作成しました" + updated: "Playを更新しました" + deleted: "Playを削除しました" + pageSetting: "Play設定" + editThisPage: "このPlayを編集" + viewSource: "ソースを表示" + my: "自分のPlay" + liked: "いいねしたPlay" + featured: "人気" + title: "タイトル" + script: "スクリプト" + summary: "説明" + _pages: newPage: "ページの作成" editPage: "ページの編集" diff --git a/packages/backend/migration/1672822262496-Flash.js b/packages/backend/migration/1672822262496-Flash.js new file mode 100644 index 0000000000..6c2338fab2 --- /dev/null +++ b/packages/backend/migration/1672822262496-Flash.js @@ -0,0 +1,29 @@ +export class Flash1672822262496 { + name = 'Flash1672822262496' + + async up(queryRunner) { + await queryRunner.query(`CREATE TABLE "flash" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "title" character varying(256) NOT NULL, "summary" character varying(1024) NOT NULL, "userId" character varying(32) NOT NULL, "script" character varying(16384) NOT NULL, "permissions" character varying(256) array NOT NULL DEFAULT '{}', "likedCount" integer NOT NULL DEFAULT '0', CONSTRAINT "PK_0c01a2c1c5f2266942dd1b3fdbc" PRIMARY KEY ("id")); COMMENT ON COLUMN "flash"."createdAt" IS 'The created date of the Flash.'; COMMENT ON COLUMN "flash"."updatedAt" IS 'The updated date of the Flash.'; COMMENT ON COLUMN "flash"."userId" IS 'The ID of author.'`); + await queryRunner.query(`CREATE INDEX "IDX_149d2e44785707548c82999b01" ON "flash" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_3aa8ea9a8f15214ad91638c0a7" ON "flash" ("updatedAt") `); + await queryRunner.query(`CREATE INDEX "IDX_9b88250fc2fd009b8f1b5623ed" ON "flash" ("userId") `); + await queryRunner.query(`CREATE TABLE "flash_like" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "flashId" character varying(32) NOT NULL, CONSTRAINT "PK_d110109ee310588d63d6183b233" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE INDEX "IDX_60c4af1c19a7a75f1592f93b28" ON "flash_like" ("userId") `); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_cfbfeeccb0cbedcd660b17eb07" ON "flash_like" ("userId", "flashId") `); + await queryRunner.query(`ALTER TABLE "flash" ADD CONSTRAINT "FK_9b88250fc2fd009b8f1b5623ed5" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "flash_like" ADD CONSTRAINT "FK_60c4af1c19a7a75f1592f93b287" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "flash_like" ADD CONSTRAINT "FK_6c16fe0e93b7a1951eca624b76a" FOREIGN KEY ("flashId") REFERENCES "flash"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "flash_like" DROP CONSTRAINT "FK_6c16fe0e93b7a1951eca624b76a"`); + await queryRunner.query(`ALTER TABLE "flash_like" DROP CONSTRAINT "FK_60c4af1c19a7a75f1592f93b287"`); + await queryRunner.query(`ALTER TABLE "flash" DROP CONSTRAINT "FK_9b88250fc2fd009b8f1b5623ed5"`); + await queryRunner.query(`DROP INDEX "public"."IDX_cfbfeeccb0cbedcd660b17eb07"`); + await queryRunner.query(`DROP INDEX "public"."IDX_60c4af1c19a7a75f1592f93b28"`); + await queryRunner.query(`DROP TABLE "flash_like"`); + await queryRunner.query(`DROP INDEX "public"."IDX_9b88250fc2fd009b8f1b5623ed"`); + await queryRunner.query(`DROP INDEX "public"."IDX_3aa8ea9a8f15214ad91638c0a7"`); + await queryRunner.query(`DROP INDEX "public"."IDX_149d2e44785707548c82999b01"`); + await queryRunner.query(`DROP TABLE "flash"`); + } +} diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index 7c6d12abf8..2f17fa389a 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -95,6 +95,8 @@ import { UserEntityService } from './entities/UserEntityService.js'; import { UserGroupEntityService } from './entities/UserGroupEntityService.js'; import { UserGroupInvitationEntityService } from './entities/UserGroupInvitationEntityService.js'; import { UserListEntityService } from './entities/UserListEntityService.js'; +import { FlashEntityService } from './entities/FlashEntityService.js'; +import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js'; import { ApAudienceService } from './activitypub/ApAudienceService.js'; import { ApDbResolverService } from './activitypub/ApDbResolverService.js'; import { ApDeliverManagerService } from './activitypub/ApDeliverManagerService.js'; @@ -216,6 +218,8 @@ const $UserEntityService: Provider = { provide: 'UserEntityService', useExisting const $UserGroupEntityService: Provider = { provide: 'UserGroupEntityService', useExisting: UserGroupEntityService }; const $UserGroupInvitationEntityService: Provider = { provide: 'UserGroupInvitationEntityService', useExisting: UserGroupInvitationEntityService }; const $UserListEntityService: Provider = { provide: 'UserListEntityService', useExisting: UserListEntityService }; +const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisting: FlashEntityService }; +const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService }; const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService }; const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService }; @@ -338,6 +342,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting UserGroupEntityService, UserGroupInvitationEntityService, UserListEntityService, + FlashEntityService, + FlashLikeEntityService, ApAudienceService, ApDbResolverService, ApDeliverManagerService, @@ -455,6 +461,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $UserGroupEntityService, $UserGroupInvitationEntityService, $UserListEntityService, + $FlashEntityService, + $FlashLikeEntityService, $ApAudienceService, $ApDbResolverService, $ApDeliverManagerService, @@ -572,6 +580,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting UserGroupEntityService, UserGroupInvitationEntityService, UserListEntityService, + FlashEntityService, + FlashLikeEntityService, ApAudienceService, ApDbResolverService, ApDeliverManagerService, @@ -688,6 +698,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $UserGroupEntityService, $UserGroupInvitationEntityService, $UserListEntityService, + $FlashEntityService, + $FlashLikeEntityService, $ApAudienceService, $ApDbResolverService, $ApDeliverManagerService, diff --git a/packages/backend/src/core/entities/FlashEntityService.ts b/packages/backend/src/core/entities/FlashEntityService.ts new file mode 100644 index 0000000000..61bd18c04f --- /dev/null +++ b/packages/backend/src/core/entities/FlashEntityService.ts @@ -0,0 +1,55 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { DI } from '@/di-symbols.js'; +import type { FlashsRepository, FlashLikesRepository } from '@/models/index.js'; +import { awaitAll } from '@/misc/prelude/await-all.js'; +import type { Packed } from '@/misc/schema.js'; +import type { } from '@/models/entities/Blocking.js'; +import type { User } from '@/models/entities/User.js'; +import type { Flash } from '@/models/entities/Flash.js'; +import { bindThis } from '@/decorators.js'; +import { UserEntityService } from './UserEntityService.js'; + +@Injectable() +export class FlashEntityService { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + @Inject(DI.flashLikesRepository) + private flashLikesRepository: FlashLikesRepository, + + private userEntityService: UserEntityService, + ) { + } + + @bindThis + public async pack( + src: Flash['id'] | Flash, + me?: { id: User['id'] } | null | undefined, + ): Promise> { + const meId = me ? me.id : null; + const flash = typeof src === 'object' ? src : await this.flashsRepository.findOneByOrFail({ id: src }); + + return await awaitAll({ + id: flash.id, + createdAt: flash.createdAt.toISOString(), + updatedAt: flash.updatedAt.toISOString(), + userId: flash.userId, + user: this.userEntityService.pack(flash.user ?? flash.userId, me), // { detail: true } すると無限ループするので注意 + title: flash.title, + summary: flash.summary, + script: flash.script, + likedCount: flash.likedCount, + isLiked: meId ? await this.flashLikesRepository.findOneBy({ flashId: flash.id, userId: meId }).then(x => x != null) : undefined, + }); + } + + @bindThis + public packMany( + flashs: Flash[], + me?: { id: User['id'] } | null | undefined, + ) { + return Promise.all(flashs.map(x => this.pack(x, me))); + } +} + diff --git a/packages/backend/src/core/entities/FlashLikeEntityService.ts b/packages/backend/src/core/entities/FlashLikeEntityService.ts new file mode 100644 index 0000000000..dcf12d53ea --- /dev/null +++ b/packages/backend/src/core/entities/FlashLikeEntityService.ts @@ -0,0 +1,44 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { DI } from '@/di-symbols.js'; +import type { FlashLikesRepository } from '@/models/index.js'; +import { awaitAll } from '@/misc/prelude/await-all.js'; +import type { Packed } from '@/misc/schema.js'; +import type { } from '@/models/entities/Blocking.js'; +import type { User } from '@/models/entities/User.js'; +import type { FlashLike } from '@/models/entities/FlashLike.js'; +import { bindThis } from '@/decorators.js'; +import { UserEntityService } from './UserEntityService.js'; +import { FlashEntityService } from './FlashEntityService.js'; + +@Injectable() +export class FlashLikeEntityService { + constructor( + @Inject(DI.flashLikesRepository) + private flashLikesRepository: FlashLikesRepository, + + private flashEntityService: FlashEntityService, + ) { + } + + @bindThis + public async pack( + src: FlashLike['id'] | FlashLike, + me?: { id: User['id'] } | null | undefined, + ) { + const like = typeof src === 'object' ? src : await this.flashLikesRepository.findOneByOrFail({ id: src }); + + return { + id: like.id, + flash: await this.flashEntityService.pack(like.flash ?? like.flashId, me), + }; + } + + @bindThis + public packMany( + likes: any[], + me: { id: User['id'] }, + ) { + return Promise.all(likes.map(x => this.pack(x, me))); + } +} + diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index d2a361405f..9719d773ca 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -69,5 +69,7 @@ export const DI = { adsRepository: Symbol('adsRepository'), passwordResetRequestsRepository: Symbol('passwordResetRequestsRepository'), retentionAggregationsRepository: Symbol('retentionAggregationsRepository'), + flashsRepository: Symbol('flashsRepository'), + flashLikesRepository: Symbol('flashLikesRepository'), //#endregion }; diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts index e22f0517ca..a5d5a63931 100644 --- a/packages/backend/src/models/RepositoryModule.ts +++ b/packages/backend/src/models/RepositoryModule.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; -import { User, Note, Announcement, AnnouncementRead, App, NoteFavorite, NoteThreadMuting, NoteReaction, NoteUnread, Notification, Poll, PollVote, UserProfile, UserKeypair, UserPending, AttestationChallenge, UserSecurityKey, UserPublickey, UserList, UserListJoining, UserGroup, UserGroupJoining, UserGroupInvitation, UserNotePining, UserIp, UsedUsername, Following, FollowRequest, Instance, Emoji, DriveFile, DriveFolder, Meta, Muting, Blocking, SwSubscription, Hashtag, AbuseUserReport, RegistrationTicket, AuthSession, AccessToken, Signin, MessagingMessage, Page, PageLike, GalleryPost, GalleryLike, ModerationLog, Clip, ClipNote, Antenna, AntennaNote, PromoNote, PromoRead, Relay, MutedNote, Channel, ChannelFollowing, ChannelNotePining, RegistryItem, Webhook, Ad, PasswordResetRequest, RetentionAggregation } from './index.js'; +import { User, Note, Announcement, AnnouncementRead, App, NoteFavorite, NoteThreadMuting, NoteReaction, NoteUnread, Notification, Poll, PollVote, UserProfile, UserKeypair, UserPending, AttestationChallenge, UserSecurityKey, UserPublickey, UserList, UserListJoining, UserGroup, UserGroupJoining, UserGroupInvitation, UserNotePining, UserIp, UsedUsername, Following, FollowRequest, Instance, Emoji, DriveFile, DriveFolder, Meta, Muting, Blocking, SwSubscription, Hashtag, AbuseUserReport, RegistrationTicket, AuthSession, AccessToken, Signin, MessagingMessage, Page, PageLike, GalleryPost, GalleryLike, ModerationLog, Clip, ClipNote, Antenna, AntennaNote, PromoNote, PromoRead, Relay, MutedNote, Channel, ChannelFollowing, ChannelNotePining, RegistryItem, Webhook, Ad, PasswordResetRequest, RetentionAggregation, FlashLike, Flash } from './index.js'; import type { DataSource } from 'typeorm'; import type { Provider } from '@nestjs/common'; @@ -388,6 +388,18 @@ const $retentionAggregationsRepository: Provider = { inject: [DI.db], }; +const $flashsRepository: Provider = { + provide: DI.flashsRepository, + useFactory: (db: DataSource) => db.getRepository(Flash), + inject: [DI.db], +}; + +const $flashLikesRepository: Provider = { + provide: DI.flashLikesRepository, + useFactory: (db: DataSource) => db.getRepository(FlashLike), + inject: [DI.db], +}; + @Module({ imports: [ ], @@ -456,6 +468,8 @@ const $retentionAggregationsRepository: Provider = { $adsRepository, $passwordResetRequestsRepository, $retentionAggregationsRepository, + $flashsRepository, + $flashLikesRepository, ], exports: [ $usersRepository, @@ -522,6 +536,8 @@ const $retentionAggregationsRepository: Provider = { $adsRepository, $passwordResetRequestsRepository, $retentionAggregationsRepository, + $flashsRepository, + $flashLikesRepository, ], }) export class RepositoryModule {} diff --git a/packages/backend/src/models/entities/Flash.ts b/packages/backend/src/models/entities/Flash.ts new file mode 100644 index 0000000000..d9a6ac987c --- /dev/null +++ b/packages/backend/src/models/entities/Flash.ts @@ -0,0 +1,60 @@ +import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; +import { id } from '../id.js'; +import { User } from './User.js'; +import { DriveFile } from './DriveFile.js'; + +@Entity() +export class Flash { + @PrimaryColumn(id()) + public id: string; + + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Flash.', + }) + public createdAt: Date; + + @Index() + @Column('timestamp with time zone', { + comment: 'The updated date of the Flash.', + }) + public updatedAt: Date; + + @Column('varchar', { + length: 256, + }) + public title: string; + + @Column('varchar', { + length: 1024, + }) + public summary: string; + + @Index() + @Column({ + ...id(), + comment: 'The ID of author.', + }) + public userId: User['id']; + + @ManyToOne(type => User, { + onDelete: 'CASCADE', + }) + @JoinColumn() + public user: User | null; + + @Column('varchar', { + length: 16384, + }) + public script: string; + + @Column('varchar', { + length: 256, array: true, default: '{}', + }) + public permissions: string[]; + + @Column('integer', { + default: 0, + }) + public likedCount: number; +} diff --git a/packages/backend/src/models/entities/FlashLike.ts b/packages/backend/src/models/entities/FlashLike.ts new file mode 100644 index 0000000000..81d39191ca --- /dev/null +++ b/packages/backend/src/models/entities/FlashLike.ts @@ -0,0 +1,33 @@ +import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; +import { id } from '../id.js'; +import { User } from './User.js'; +import { Flash } from './Flash.js'; + +@Entity() +@Index(['userId', 'flashId'], { unique: true }) +export class FlashLike { + @PrimaryColumn(id()) + public id: string; + + @Column('timestamp with time zone') + public createdAt: Date; + + @Index() + @Column(id()) + public userId: User['id']; + + @ManyToOne(type => User, { + onDelete: 'CASCADE', + }) + @JoinColumn() + public user: User | null; + + @Column(id()) + public flashId: Flash['id']; + + @ManyToOne(type => Flash, { + onDelete: 'CASCADE', + }) + @JoinColumn() + public flash: Flash | null; +} diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index ca7a7c9e56..b132475747 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -62,6 +62,8 @@ import { UserSecurityKey } from '@/models/entities/UserSecurityKey.js'; import { Webhook } from '@/models/entities/Webhook.js'; import { Channel } from '@/models/entities/Channel.js'; import { RetentionAggregation } from '@/models/entities/RetentionAggregation.js'; +import { Flash } from '@/models/entities/Flash.js'; +import { FlashLike } from '@/models/entities/FlashLike.js'; import type { Repository } from 'typeorm'; export { @@ -129,6 +131,8 @@ export { Webhook, Channel, RetentionAggregation, + Flash, + FlashLike, }; export type AbuseUserReportsRepository = Repository; @@ -195,3 +199,5 @@ export type UserSecurityKeysRepository = Repository; export type WebhooksRepository = Repository; export type ChannelsRepository = Repository; export type RetentionAggregationsRepository = Repository; +export type FlashsRepository = Repository; +export type FlashLikesRepository = Repository; diff --git a/packages/backend/src/postgre.ts b/packages/backend/src/postgre.ts index 4b4490a0c3..4f6b157d80 100644 --- a/packages/backend/src/postgre.ts +++ b/packages/backend/src/postgre.ts @@ -70,6 +70,8 @@ import { UserSecurityKey } from '@/models/entities/UserSecurityKey.js'; import { Webhook } from '@/models/entities/Webhook.js'; import { Channel } from '@/models/entities/Channel.js'; import { RetentionAggregation } from '@/models/entities/RetentionAggregation.js'; +import { Flash } from '@/models/entities/Flash.js'; +import { FlashLike } from '@/models/entities/FlashLike.js'; import { Config } from '@/config.js'; import MisskeyLogger from '@/logger.js'; @@ -184,6 +186,8 @@ export const entities = [ Webhook, UserIp, RetentionAggregation, + Flash, + FlashLike, ...charts, ]; diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 32eff7f312..60beca4f47 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -266,6 +266,15 @@ import * as ep___pages_like from './endpoints/pages/like.js'; import * as ep___pages_show from './endpoints/pages/show.js'; import * as ep___pages_unlike from './endpoints/pages/unlike.js'; import * as ep___pages_update from './endpoints/pages/update.js'; +import * as ep___flash_create from './endpoints/flash/create.js'; +import * as ep___flash_delete from './endpoints/flash/delete.js'; +import * as ep___flash_featured from './endpoints/flash/featured.js'; +import * as ep___flash_like from './endpoints/flash/like.js'; +import * as ep___flash_show from './endpoints/flash/show.js'; +import * as ep___flash_unlike from './endpoints/flash/unlike.js'; +import * as ep___flash_update from './endpoints/flash/update.js'; +import * as ep___flash_my from './endpoints/flash/my.js'; +import * as ep___flash_myLikes from './endpoints/flash/my-likes.js'; import * as ep___ping from './endpoints/ping.js'; import * as ep___pinnedUsers from './endpoints/pinned-users.js'; import * as ep___promo_read from './endpoints/promo/read.js'; @@ -587,6 +596,15 @@ const $pages_like: Provider = { provide: 'ep:pages/like', useClass: ep___pages_l const $pages_show: Provider = { provide: 'ep:pages/show', useClass: ep___pages_show.default }; const $pages_unlike: Provider = { provide: 'ep:pages/unlike', useClass: ep___pages_unlike.default }; const $pages_update: Provider = { provide: 'ep:pages/update', useClass: ep___pages_update.default }; +const $flash_create: Provider = { provide: 'ep:flash/create', useClass: ep___flash_create.default }; +const $flash_delete: Provider = { provide: 'ep:flash/delete', useClass: ep___flash_delete.default }; +const $flash_featured: Provider = { provide: 'ep:flash/featured', useClass: ep___flash_featured.default }; +const $flash_like: Provider = { provide: 'ep:flash/like', useClass: ep___flash_like.default }; +const $flash_show: Provider = { provide: 'ep:flash/show', useClass: ep___flash_show.default }; +const $flash_unlike: Provider = { provide: 'ep:flash/unlike', useClass: ep___flash_unlike.default }; +const $flash_update: Provider = { provide: 'ep:flash/update', useClass: ep___flash_update.default }; +const $flash_my: Provider = { provide: 'ep:flash/my', useClass: ep___flash_my.default }; +const $flash_myLikes: Provider = { provide: 'ep:flash/my-likes', useClass: ep___flash_myLikes.default }; const $ping: Provider = { provide: 'ep:ping', useClass: ep___ping.default }; const $pinnedUsers: Provider = { provide: 'ep:pinned-users', useClass: ep___pinnedUsers.default }; const $promo_read: Provider = { provide: 'ep:promo/read', useClass: ep___promo_read.default }; @@ -912,6 +930,15 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $pages_show, $pages_unlike, $pages_update, + $flash_create, + $flash_delete, + $flash_featured, + $flash_like, + $flash_show, + $flash_unlike, + $flash_update, + $flash_my, + $flash_myLikes, $ping, $pinnedUsers, $promo_read, @@ -1231,6 +1258,15 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $pages_show, $pages_unlike, $pages_update, + $flash_create, + $flash_delete, + $flash_featured, + $flash_like, + $flash_show, + $flash_unlike, + $flash_update, + $flash_my, + $flash_myLikes, $ping, $pinnedUsers, $promo_read, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 49dc3b224f..d4f8be5b85 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -265,6 +265,15 @@ import * as ep___pages_like from './endpoints/pages/like.js'; import * as ep___pages_show from './endpoints/pages/show.js'; import * as ep___pages_unlike from './endpoints/pages/unlike.js'; import * as ep___pages_update from './endpoints/pages/update.js'; +import * as ep___flash_create from './endpoints/flash/create.js'; +import * as ep___flash_delete from './endpoints/flash/delete.js'; +import * as ep___flash_featured from './endpoints/flash/featured.js'; +import * as ep___flash_like from './endpoints/flash/like.js'; +import * as ep___flash_show from './endpoints/flash/show.js'; +import * as ep___flash_unlike from './endpoints/flash/unlike.js'; +import * as ep___flash_update from './endpoints/flash/update.js'; +import * as ep___flash_my from './endpoints/flash/my.js'; +import * as ep___flash_myLikes from './endpoints/flash/my-likes.js'; import * as ep___ping from './endpoints/ping.js'; import * as ep___pinnedUsers from './endpoints/pinned-users.js'; import * as ep___promo_read from './endpoints/promo/read.js'; @@ -584,6 +593,15 @@ const eps = [ ['pages/show', ep___pages_show], ['pages/unlike', ep___pages_unlike], ['pages/update', ep___pages_update], + ['flash/create', ep___flash_create], + ['flash/delete', ep___flash_delete], + ['flash/featured', ep___flash_featured], + ['flash/like', ep___flash_like], + ['flash/show', ep___flash_show], + ['flash/unlike', ep___flash_unlike], + ['flash/update', ep___flash_update], + ['flash/my', ep___flash_my], + ['flash/my-likes', ep___flash_myLikes], ['ping', ep___ping], ['pinned-users', ep___pinnedUsers], ['promo/read', ep___promo_read], diff --git a/packages/backend/src/server/api/endpoints/flash/create.ts b/packages/backend/src/server/api/endpoints/flash/create.ts new file mode 100644 index 0000000000..a652047d98 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/create.ts @@ -0,0 +1,66 @@ +import ms from 'ms'; +import { Inject, Injectable } from '@nestjs/common'; +import type { DriveFilesRepository, FlashsRepository, PagesRepository } from '@/models/index.js'; +import { IdService } from '@/core/IdService.js'; +import { Page } from '@/models/entities/Page.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { PageEntityService } from '@/core/entities/PageEntityService.js'; +import { DI } from '@/di-symbols.js'; +import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; +import { ApiError } from '../../error.js'; + +export const meta = { + tags: ['flash'], + + requireCredential: true, + + kind: 'write:flash', + + limit: { + duration: ms('1hour'), + max: 10, + }, + + errors: { + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + title: { type: 'string' }, + summary: { type: 'string' }, + script: { type: 'string' }, + permissions: { type: 'array', items: { + type: 'string', + } }, + }, + required: ['title', 'summary', 'script', 'permissions'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + private flashEntityService: FlashEntityService, + private idService: IdService, + ) { + super(meta, paramDef, async (ps, me) => { + const flash = await this.flashsRepository.insert({ + id: this.idService.genId(), + userId: me.id, + createdAt: new Date(), + updatedAt: new Date(), + title: ps.title, + summary: ps.summary, + script: ps.script, + permissions: ps.permissions, + }).then(x => this.flashsRepository.findOneByOrFail(x.identifiers[0])); + + return await this.flashEntityService.pack(flash); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/delete.ts b/packages/backend/src/server/api/endpoints/flash/delete.ts new file mode 100644 index 0000000000..e94ede9f68 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/delete.ts @@ -0,0 +1,56 @@ +import { Inject, Injectable } from '@nestjs/common'; +import type { FlashsRepository } from '@/models/index.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '../../error.js'; + +export const meta = { + tags: ['flashs'], + + requireCredential: true, + + kind: 'write:flash', + + errors: { + noSuchFlash: { + message: 'No such flash.', + code: 'NO_SUCH_FLASH', + id: 'de1623ef-bbb3-4289-a71e-14cfa83d9740', + }, + + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: '1036ad7b-9f92-4fff-89c3-0e50dc941704', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + flashId: { type: 'string', format: 'misskey:id' }, + }, + required: ['flashId'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const flash = await this.flashsRepository.findOneBy({ id: ps.flashId }); + if (flash == null) { + throw new ApiError(meta.errors.noSuchFlash); + } + if (flash.userId !== me.id) { + throw new ApiError(meta.errors.accessDenied); + } + + await this.flashsRepository.delete(flash.id); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/featured.ts b/packages/backend/src/server/api/endpoints/flash/featured.ts new file mode 100644 index 0000000000..570aef96d2 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/featured.ts @@ -0,0 +1,48 @@ +import { Inject, Injectable } from '@nestjs/common'; +import type { FlashsRepository } from '@/models/index.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['flash'], + + requireCredential: false, + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Flash', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + private flashEntityService: FlashEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.flashsRepository.createQueryBuilder('flash') + .andWhere('flash.likedCount > 0') + .orderBy('flash.likedCount', 'DESC'); + + const flashs = await query.take(10).getMany(); + + return await this.flashEntityService.packMany(flashs, me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/like.ts b/packages/backend/src/server/api/endpoints/flash/like.ts new file mode 100644 index 0000000000..5581b8ec60 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/like.ts @@ -0,0 +1,87 @@ +import { Inject, Injectable } from '@nestjs/common'; +import type { FlashsRepository, FlashLikesRepository } from '@/models/index.js'; +import { IdService } from '@/core/IdService.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '../../error.js'; + +export const meta = { + tags: ['flash'], + + requireCredential: true, + + kind: 'write:flash-likes', + + errors: { + noSuchFlash: { + message: 'No such flash.', + code: 'NO_SUCH_FLASH', + id: 'c07c1491-9161-4c5c-9d75-01906f911f73', + }, + + yourFlash: { + message: 'You cannot like your flash.', + code: 'YOUR_FLASH', + id: '3fd8a0e7-5955-4ba9-85bb-bf3e0c30e13b', + }, + + alreadyLiked: { + message: 'The flash has already been liked.', + code: 'ALREADY_LIKED', + id: '010065cf-ad43-40df-8067-abff9f4686e3', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + flashId: { type: 'string', format: 'misskey:id' }, + }, + required: ['flashId'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + @Inject(DI.flashLikesRepository) + private flashLikesRepository: FlashLikesRepository, + + private idService: IdService, + ) { + super(meta, paramDef, async (ps, me) => { + const flash = await this.flashsRepository.findOneBy({ id: ps.flashId }); + if (flash == null) { + throw new ApiError(meta.errors.noSuchFlash); + } + + if (flash.userId === me.id) { + throw new ApiError(meta.errors.yourFlash); + } + + // if already liked + const exist = await this.flashLikesRepository.findOneBy({ + flashId: flash.id, + userId: me.id, + }); + + if (exist != null) { + throw new ApiError(meta.errors.alreadyLiked); + } + + // Create like + await this.flashLikesRepository.insert({ + id: this.idService.genId(), + createdAt: new Date(), + flashId: flash.id, + userId: me.id, + }); + + this.flashsRepository.increment({ id: flash.id }, 'likedCount', 1); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/my-likes.ts b/packages/backend/src/server/api/endpoints/flash/my-likes.ts new file mode 100644 index 0000000000..f7716ea74a --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/my-likes.ts @@ -0,0 +1,68 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { FlashLikesRepository } from '@/models/index.js'; +import { QueryService } from '@/core/QueryService.js'; +import { FlashLikeEntityService } from '@/core/entities/FlashLikeEntityService.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['account', 'flash'], + + requireCredential: true, + + kind: 'read:flash-likes', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + flash: { + type: 'object', + optional: false, nullable: false, + ref: 'Flash', + }, + }, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashLikesRepository) + private flashLikesRepository: FlashLikesRepository, + + private flashLikeEntityService: FlashLikeEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.flashLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId) + .andWhere('like.userId = :meId', { meId: me.id }) + .leftJoinAndSelect('like.flash', 'flash'); + + const likes = await query + .take(ps.limit) + .getMany(); + + return this.flashLikeEntityService.packMany(likes, me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/my.ts b/packages/backend/src/server/api/endpoints/flash/my.ts new file mode 100644 index 0000000000..baed7f000f --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/my.ts @@ -0,0 +1,57 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { FlashsRepository } from '@/models/index.js'; +import { QueryService } from '@/core/QueryService.js'; +import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['account', 'flash'], + + requireCredential: true, + + kind: 'read:flash', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Flash', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + private flashEntityService: FlashEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.flashsRepository.createQueryBuilder('flash'), ps.sinceId, ps.untilId) + .andWhere('flash.userId = :meId', { meId: me.id }); + + const flashs = await query + .take(ps.limit) + .getMany(); + + return await this.flashEntityService.packMany(flashs); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/show.ts b/packages/backend/src/server/api/endpoints/flash/show.ts new file mode 100644 index 0000000000..48114c5a60 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/show.ts @@ -0,0 +1,60 @@ +import { IsNull } from 'typeorm'; +import { Inject, Injectable } from '@nestjs/common'; +import type { UsersRepository, FlashsRepository } from '@/models/index.js'; +import type { Flash } from '@/models/entities/Flash.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '../../error.js'; + +export const meta = { + tags: ['flashs'], + + requireCredential: false, + + res: { + type: 'object', + optional: false, nullable: false, + ref: 'Flash', + }, + + errors: { + noSuchFlash: { + message: 'No such flash.', + code: 'NO_SUCH_FLASH', + id: 'f0d34a1a-d29a-401d-90ba-1982122b5630', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + flashId: { type: 'string', format: 'misskey:id' }, + }, + required: ['flashId'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + private flashEntityService: FlashEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const flash = await this.flashsRepository.findOneBy({ id: ps.flashId }); + + if (flash == null) { + throw new ApiError(meta.errors.noSuchFlash); + } + + return await this.flashEntityService.pack(flash, me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/unlike.ts b/packages/backend/src/server/api/endpoints/flash/unlike.ts new file mode 100644 index 0000000000..b994f5d347 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/unlike.ts @@ -0,0 +1,68 @@ +import { Inject, Injectable } from '@nestjs/common'; +import type { FlashsRepository, FlashLikesRepository } from '@/models/index.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '../../error.js'; + +export const meta = { + tags: ['flash'], + + requireCredential: true, + + kind: 'write:flash-likes', + + errors: { + noSuchFlash: { + message: 'No such flash.', + code: 'NO_SUCH_FLASH', + id: 'afe8424a-a69e-432d-a5f2-2f0740c62410', + }, + + notLiked: { + message: 'You have not liked that flash.', + code: 'NOT_LIKED', + id: '755f25a7-9871-4f65-9f34-51eaad9ae0ac', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + flashId: { type: 'string', format: 'misskey:id' }, + }, + required: ['flashId'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + @Inject(DI.flashLikesRepository) + private flashLikesRepository: FlashLikesRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const flash = await this.flashsRepository.findOneBy({ id: ps.flashId }); + if (flash == null) { + throw new ApiError(meta.errors.noSuchFlash); + } + + const exist = await this.flashLikesRepository.findOneBy({ + flashId: flash.id, + userId: me.id, + }); + + if (exist == null) { + throw new ApiError(meta.errors.notLiked); + } + + // Delete like + await this.flashLikesRepository.delete(exist.id); + + this.flashsRepository.decrement({ id: flash.id }, 'likedCount', 1); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/flash/update.ts b/packages/backend/src/server/api/endpoints/flash/update.ts new file mode 100644 index 0000000000..9ab17a61e8 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/flash/update.ts @@ -0,0 +1,78 @@ +import ms from 'ms'; +import { Not } from 'typeorm'; +import { Inject, Injectable } from '@nestjs/common'; +import type { FlashsRepository, DriveFilesRepository } from '@/models/index.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '../../error.js'; + +export const meta = { + tags: ['flash'], + + requireCredential: true, + + kind: 'write:flash', + + limit: { + duration: ms('1hour'), + max: 300, + }, + + errors: { + noSuchFlash: { + message: 'No such flash.', + code: 'NO_SUCH_FLASH', + id: '611e13d2-309e-419a-a5e4-e0422da39b02', + }, + + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: '08e60c88-5948-478e-a132-02ec701d67b2', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + flashId: { type: 'string', format: 'misskey:id' }, + title: { type: 'string' }, + summary: { type: 'string' }, + script: { type: 'string' }, + permissions: { type: 'array', items: { + type: 'string', + } }, + }, + required: ['flashId', 'title', 'summary', 'script', 'permissions'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.flashsRepository) + private flashsRepository: FlashsRepository, + + @Inject(DI.driveFilesRepository) + private driveFilesRepository: DriveFilesRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const flash = await this.flashsRepository.findOneBy({ id: ps.flashId }); + if (flash == null) { + throw new ApiError(meta.errors.noSuchFlash); + } + if (flash.userId !== me.id) { + throw new ApiError(meta.errors.accessDenied); + } + + await this.flashsRepository.update(flash.id, { + updatedAt: new Date(), + title: ps.title, + summary: ps.summary, + script: ps.script, + permissions: ps.permissions, + }); + }); + } +} diff --git a/packages/frontend/src/components/MkAsUi.vue b/packages/frontend/src/components/MkAsUi.vue new file mode 100644 index 0000000000..bc1e25957b --- /dev/null +++ b/packages/frontend/src/components/MkAsUi.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index daf47e12d4..f9602de787 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -2,7 +2,7 @@
@@ -207,20 +207,6 @@ definePageMetadata(computed(() => page ? { padding: 16px 0 0 0; border-top: solid 0.5px var(--divider); - > .like { - > .button { - --accent: rgb(241 97 132); - --X8: rgb(241 92 128); - --buttonBg: rgb(216 71 106 / 5%); - --buttonHoverBg: rgb(216 71 106 / 10%); - color: #ff002f; - - ::v-deep(.count) { - margin-left: 0.5em; - } - } - } - > .other { margin-left: auto; diff --git a/packages/frontend/src/pages/scratchpad.vue b/packages/frontend/src/pages/scratchpad.vue index 9db17efc03..7d097fbaaa 100644 --- a/packages/frontend/src/pages/scratchpad.vue +++ b/packages/frontend/src/pages/scratchpad.vue @@ -1,25 +1,34 @@ - diff --git a/packages/frontend/src/widgets/index.ts b/packages/frontend/src/widgets/index.ts index 39826f13c8..3966649da4 100644 --- a/packages/frontend/src/widgets/index.ts +++ b/packages/frontend/src/widgets/index.ts @@ -22,6 +22,7 @@ export default function(app: App) { app.component('MkwInstanceCloud', defineAsyncComponent(() => import('./instance-cloud.vue'))); app.component('MkwButton', defineAsyncComponent(() => import('./button.vue'))); app.component('MkwAiscript', defineAsyncComponent(() => import('./aiscript.vue'))); + app.component('MkwAiscriptApp', defineAsyncComponent(() => import('./aiscript-app.vue'))); app.component('MkwAichan', defineAsyncComponent(() => import('./aichan.vue'))); app.component('MkwUserList', defineAsyncComponent(() => import('./user-list.vue'))); } @@ -48,6 +49,7 @@ export const widgets = [ 'jobQueue', 'button', 'aiscript', + 'aiscriptApp', 'aichan', 'userList', ]; From 5de699e233820644b7112e0641cad9008efda842 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 5 Jan 2023 14:00:28 +0900 Subject: [PATCH 14/75] 13.0.0-beta.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ab38a56ec..f5c033c457 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.0.0-beta.21", + "version": "13.0.0-beta.22", "codename": "indigo", "repository": { "type": "git", From df291b00d86b7271f28e808be80910e3ae72ea93 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 5 Jan 2023 14:08:21 +0900 Subject: [PATCH 15/75] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 005b011592..5da590cab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,18 +12,23 @@ You should also include the user name that made the change. ## 13.0.0 (unreleased) ### Changes +#### For sabakans - Node.js 18.x or later is required - Elasticsearchのサポートが削除されました - 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます -- ノートのウォッチ機能が削除されました - Migrate to Yarn Berry (v3.2.1) @ThatOneCalculator - You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic + +#### For users +- ノートのウォッチ機能が削除されました - 新たに動的なPagesを作ることはできなくなりました - 代わりにAiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能が実装されています。 - AiScriptが0.12.0にアップデートされました - 0.12.0の変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120 - 0.12.0未満のプラグインは読み込むことはできません - iOS15以下のデバイスはサポートされなくなりました + +#### For developers - API: カスタム絵文字エンティティに`url`プロパティが含まれなくなりました - 絵文字画像を表示するには、`/emoji/.webp`にリクエストすると画像が返ります。 - e.g. `https://p1.a9z.dev/emoji/misskey.webp` From 6f9aa94e3ae59a5ab8b38a6cb9c179f96033efa8 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 5 Jan 2023 16:38:12 +0900 Subject: [PATCH 16/75] fix instance sort --- .../backend/src/server/api/endpoints/federation/instances.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 180887285a..5e2f204661 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -64,8 +64,8 @@ export default class extends Endpoint { case '-followers': query.orderBy('instance.followersCount', 'ASC'); break; case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break; case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break; - case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC'); break; - case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC'); break; + case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC', 'NULLS LAST'); break; + case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC', 'NULLS FIRST'); break; default: query.orderBy('instance.id', 'DESC'); break; } From 1cae688ccbb3fc298d9c95db4c0670de206899d9 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 5 Jan 2023 16:57:49 +0900 Subject: [PATCH 17/75] update aiscript --- CHANGELOG.md | 6 ++-- packages/frontend/package.json | 2 +- .../frontend/src/pages/flash/flash-edit.vue | 2 +- .../src/pages/settings/plugin.install.vue | 2 +- yarn.lock | 30 +++++++++---------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5da590cab9..8adf88bae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,9 +23,9 @@ You should also include the user name that made the change. - ノートのウォッチ機能が削除されました - 新たに動的なPagesを作ることはできなくなりました - 代わりにAiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能が実装されています。 -- AiScriptが0.12.0にアップデートされました - - 0.12.0の変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120 - - 0.12.0未満のプラグインは読み込むことはできません +- AiScriptが0.12.1にアップデートされました + - 0.12.xの変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120 + - 0.12.1未満のプラグインは読み込むことはできません - iOS15以下のデバイスはサポートされなくなりました #### For developers diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 2506e8e9d3..d151a7b3af 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -11,7 +11,7 @@ "@rollup/plugin-alias": "4.0.2", "@rollup/plugin-json": "6.0.0", "@rollup/pluginutils": "5.0.2", - "@syuilo/aiscript": "0.12.0", + "@syuilo/aiscript": "0.12.1", "@tabler/icons": "^1.118.0", "@vitejs/plugin-vue": "4.0.0", "@vue/compiler-sfc": "3.2.45", diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue index 561331e002..b2eba292f2 100644 --- a/packages/frontend/src/pages/flash/flash-edit.vue +++ b/packages/frontend/src/pages/flash/flash-edit.vue @@ -47,7 +47,7 @@ if (props.id) { let title = $ref(flash?.title ?? 'New Play'); let summary = $ref(flash?.summary ?? ''); let permissions = $ref(flash?.permissions ?? []); -let script = $ref(flash?.script ?? `/// @ 0.12.0 +let script = $ref(flash?.script ?? `/// @ 0.12.1 var name = "" diff --git a/packages/frontend/src/pages/settings/plugin.install.vue b/packages/frontend/src/pages/settings/plugin.install.vue index 40ad9a95dd..3d77cadaaa 100644 --- a/packages/frontend/src/pages/settings/plugin.install.vue +++ b/packages/frontend/src/pages/settings/plugin.install.vue @@ -49,7 +49,7 @@ async function install() { text: 'No language version annotation found :(', }); return; - } else if (lv !== '0.12.0') { + } else if (!lv.startsWith('0.12.')) { os.alert({ type: 'error', text: `aiscript version '${lv}' is not supported :(`, diff --git a/yarn.lock b/yarn.lock index 7ce29e1543..208f0724d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1973,15 +1973,15 @@ __metadata: languageName: node linkType: hard -"@syuilo/aiscript@npm:0.12.0": - version: 0.12.0 - resolution: "@syuilo/aiscript@npm:0.12.0" +"@syuilo/aiscript@npm:0.12.1": + version: 0.12.1 + resolution: "@syuilo/aiscript@npm:0.12.1" dependencies: autobind-decorator: 2.4.0 seedrandom: 3.0.5 stringz: 2.1.0 - uuid: 8.3.2 - checksum: 82b52a6c602a8c3090b9457a0e9de99898b03cd8f054855b2f57439534257ef2780013a53eaeeef68c9893d96d3ec02fc6d0ede56396c2bcf054cf43b2297b67 + uuid: 9.0.0 + checksum: 0bee3031cbc8358e159fc8fde6e1ab7204e1a8e17e07f394f337d70cd3a8558e591145ca03afe37c76bbb91f84b2b2af70b892935e9c98507f9d1455c7be1107 languageName: node linkType: hard @@ -8026,7 +8026,7 @@ __metadata: "@rollup/plugin-alias": 4.0.2 "@rollup/plugin-json": 6.0.0 "@rollup/pluginutils": 5.0.2 - "@syuilo/aiscript": 0.12.0 + "@syuilo/aiscript": 0.12.1 "@tabler/icons": ^1.118.0 "@types/escape-regexp": 0.0.1 "@types/glob": 8.0.0 @@ -16912,15 +16912,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:8.3.2, uuid@npm:^8.3.0, uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df - languageName: node - linkType: hard - "uuid@npm:9.0.0": version: 9.0.0 resolution: "uuid@npm:9.0.0" @@ -16939,6 +16930,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^8.3.0, uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + "v8-to-istanbul@npm:^9.0.1": version: 9.0.1 resolution: "v8-to-istanbul@npm:9.0.1" From d890383a008b542c46819a1ce98a2646725a10e7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 5 Jan 2023 17:09:36 +0900 Subject: [PATCH 18/75] add Ui:C:folder for AiScript --- packages/frontend/src/components/MkAsUi.vue | 7 +++++ packages/frontend/src/scripts/aiscript/ui.ts | 33 +++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkAsUi.vue b/packages/frontend/src/components/MkAsUi.vue index bc1e25957b..ec214f0396 100644 --- a/packages/frontend/src/components/MkAsUi.vue +++ b/packages/frontend/src/components/MkAsUi.vue @@ -33,6 +33,12 @@ {{ c.text }} + + + +