From 7b39483966b7c5cd9fa43aa573dc2b387ade34a7 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 22 Dec 2022 15:39:18 +0100 Subject: [PATCH 001/108] server: drive endpoint to fetch files and folders Changelog: Added --- packages/backend/src/server/api/endpoints.ts | 2 + .../src/server/api/endpoints/drive/show.ts | 70 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 packages/backend/src/server/api/endpoints/drive/show.ts diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 6e69b3b11..4f4f2c16f 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -105,6 +105,7 @@ import * as ep___clips_show from './endpoints/clips/show.js'; import * as ep___clips_update from './endpoints/clips/update.js'; import * as ep___drive from './endpoints/drive.js'; import * as ep___drive_files from './endpoints/drive/files.js'; +import * as ep___drive_show from './endpoints/drive/show.js'; import * as ep___drive_files_attachedNotes from './endpoints/drive/files/attached-notes.js'; import * as ep___drive_files_checkExistence from './endpoints/drive/files/check-existence.js'; import * as ep___drive_files_create from './endpoints/drive/files/create.js'; @@ -414,6 +415,7 @@ const eps = [ ['clips/update', ep___clips_update], ['drive', ep___drive], ['drive/files', ep___drive_files], + ['drive/show', ep___drive_show], ['drive/files/attached-notes', ep___drive_files_attachedNotes], ['drive/files/check-existence', ep___drive_files_checkExistence], ['drive/files/create', ep___drive_files_create], diff --git a/packages/backend/src/server/api/endpoints/drive/show.ts b/packages/backend/src/server/api/endpoints/drive/show.ts new file mode 100644 index 000000000..3d88ed5f5 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/drive/show.ts @@ -0,0 +1,70 @@ +import { DriveFiles, DriveFolders } from '@/models/index.js'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; + +export const meta = { + tags: ['drive'], + + description: "Lists all folders and files in the authenticated user's drive. Folders are always listed first. The limit, if specified, is applied over the total number of elements.", + + requireCredential: true, + + kind: 'read:drive', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + oneOf: [{ + type: 'object', + optional: false, nullable: false, + ref: 'DriveFile', + }, { + type: 'object', + optional: false, nullable: false, + ref: 'DriveFolder', + }], + }, + }, +} 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' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + }, + required: [], +} as const; + +// eslint-disable-next-line import/no-default-export +export default define(meta, paramDef, async (ps, user) => { + const foldersQuery = makePaginationQuery(DriveFolders.createQueryBuilder('folder'), ps.sinceId, ps.untilId) + .andWhere('folder.userId = :userId', { userId: user.id }); + const filesQuery = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId) + .andWhere('file.userId = :userId', { userId: user.id }); + + if (ps.folderId) { + foldersQuery.andWhere('folder.parentId = :parentId', { parentId: ps.folderId }); + filesQuery.andWhere('file.folderId = :folderId', { folderId: ps.folderId }); + } else { + foldersQuery.andWhere('folder.parentId IS NULL'); + filesQuery.andWhere('file.folderId IS NULL'); + } + + const folders = await foldersQuery.take(ps.limit).getMany(); + + const [files, ...packedFolders] = await Promise.all([ + filesQuery.take(ps.limit - folders.length).getMany(), + ...(folders.map(folder => DriveFolders.pack(folder))), + ]); + + const packedFiles = await DriveFiles.packMany(files, { detail: false, self: true }); + + return [ + ...packedFolders, + ...packedFiles, + ]; +}); From 240cf9892079b5d834e123184501ae7282a1aef9 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 22 Dec 2022 17:06:52 +0100 Subject: [PATCH 002/108] client: refactor drive drag&drop --- packages/client/src/components/drive.vue | 27 +++++++++--------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index c01c328af..adce71b79 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -210,9 +210,8 @@ function onStreamDriveFolderDeleted(folderId: string) { function onDragover(ev: DragEvent): any { if (!ev.dataTransfer) return; - // ドラッグ元が自分自身の所有するアイテムだったら if (isDragSource) { - // 自分自身にはドロップさせない + // We are the drag source, do not allow to drop. ev.dataTransfer.dropEffect = 'none'; return; } @@ -257,17 +256,16 @@ function onDrop(ev: DragEvent): any { if (!ev.dataTransfer) return; - // ドロップされてきたものがファイルだったら + const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_); + const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_); + if (ev.dataTransfer.files.length > 0) { + // dropping operating system files for (const file of Array.from(ev.dataTransfer.files)) { upload(file, folder); } - return; - } - - //#region ドライブのファイル - const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_); - if (driveFile != null && driveFile !== '') { + } else if (driveFile != null && driveFile !== '') { + // dropping drive files const file = JSON.parse(driveFile); // cannot move file within parent folder @@ -278,18 +276,14 @@ function onDrop(ev: DragEvent): any { fileId: file.id, folderId: folder?.id ?? null, }); - } - //#endregion - - //#region ドライブのフォルダ - const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_); - if (driveFolder != null && driveFolder !== '') { + } else if (driveFolder != null && driveFolder !== '') { + // dropping drive folders const droppedFolder = JSON.parse(driveFolder); // cannot move folder into itself if (droppedFolder.id === folder?.id) return false; // cannot move folder within parent folder - if (foldersPaginationElem.items.some(f => f.id === droppedFolder.id)) return false; + if (folder.id === droppedFolder.parentId) return false; removeFolder(droppedFolder.id); os.api('drive/folders/update', { @@ -311,7 +305,6 @@ function onDrop(ev: DragEvent): any { } }); } - //#endregion } function selectLocalFile() { From d96070bc8057a0a3988af87309a5e340ef78bd76 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 22 Dec 2022 17:32:05 +0100 Subject: [PATCH 003/108] client: fix duplicate folder when creating new folder --- packages/client/src/components/drive.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index adce71b79..02d46f185 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -339,8 +339,6 @@ function createFolder() { os.api('drive/folders/create', { name, parentId: folder?.id ?? undefined, - }).then(createdFolder => { - addFolder(createdFolder, true); }); }); } From c983c4860c5257694360181b72e07f66ad86f562 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 22 Dec 2022 17:55:13 +0100 Subject: [PATCH 004/108] client: use combined drive endpoint --- packages/client/src/components/drive.vue | 172 ++++++++--------------- 1 file changed, 55 insertions(+), 117 deletions(-) diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index 02d46f185..10f0be183 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -35,27 +35,35 @@ @drop.prevent.stop="onDrop" @contextmenu.stop="onContextmenu" > -
- - + + - +
@@ -145,13 +116,7 @@ const emit = defineEmits<{ (ev: 'open-folder', v: foundkey.entities.DriveFolder): void; }>(); -let foldersPaginationElem = $ref>(); -let filesPaginationElem = $ref>(); - -let foldersLoading = $ref(true); -let filesLoading = $ref(true); -const empty = $computed(() => !foldersLoading && !filesLoading - && foldersPaginationElem?.items.length === 0 && filesPaginationElem?.items.length === 0); +let paginationElem = $ref>(); let fileInput = $ref(); @@ -434,10 +399,6 @@ function chooseFolder(folderToChoose: foundkey.entities.DriveFolder) { } function move(target?: string | foundkey.entities.DriveFolder) { - // reset loading state - foldersLoading = true; - filesLoading = true; - if (!target) { goRoot(); return; @@ -466,13 +427,13 @@ function addFolder(folderToAdd: foundkey.entities.DriveFolder, unshift = false) const current = folder?.id ?? null; if (current !== folderToAdd.parentId) return; - const exist = foldersPaginationElem.items.some(f => f.id === folderToAdd.id); + const exist = paginationElem.items.some(f => f.id === folderToAdd.id); if (exist) { - foldersPaginationElem.updateItem(folderToAdd.id, () => folderToAdd); + paginationElem.updateItem(folderToAdd.id, () => folderToAdd); } else if (unshift) { - foldersPaginationElem.prepend(folderToAdd); + paginationElem.prepend(folderToAdd); } else { - foldersPaginationElem.append(folderToAdd); + paginationElem.append(folderToAdd); } } @@ -480,24 +441,24 @@ function addFile(fileToAdd: foundkey.entities.DriveFile, unshift = false) { const current = folder?.id ?? null; if (current !== fileToAdd.folderId) return; - const exist = filesPaginationElem.items.some(f => f.id === fileToAdd.id); + const exist = paginationElem.items.some(f => f.id === fileToAdd.id); if (exist) { - filesPaginationElem.updateItem(fileToAdd.id, () => fileToAdd); + paginationElem.updateItem(fileToAdd.id, () => fileToAdd); } else if (unshift) { - filesPaginationElem.prepend(fileToAdd); + paginationElem.prepend(fileToAdd); } else { - filesPaginationElem.append(fileToAdd); + paginationElem.append(fileToAdd); } } function removeFolder(folderToRemove: foundkey.entities.DriveFolder | string): void { const folderIdToRemove = typeof folderToRemove === 'object' ? folderToRemove.id : folderToRemove; - foldersPaginationElem.removeItem(item => item.id === folderIdToRemove); + paginationElem.removeItem(item => item.id === folderIdToRemove); } function removeFile(fileToRemove: foundkey.entities.DriveFile | string): void { const fileIdToRemove = typeof fileToRemove === 'object' ? fileToRemove.id : fileToRemove; - filesPaginationElem.removeItem(item => item.id === fileIdToRemove); + paginationElem.removeItem(item => item.id === fileIdToRemove); } function goRoot() { @@ -509,23 +470,14 @@ function goRoot() { emit('move-root'); } -const foldersPagination = { - endpoint: 'drive/folders' as const, +const pagination = { + endpoint: 'drive/show' as const, limit: 30, params: computed(() => ({ folderId: folder?.id ?? null, })), }; -const filesPagination = { - endpoint: 'drive/files' as const, - limit: 30, - params: computed(() => ({ - folderId: folder?.id ?? null, - type: props.type, - })), -}; - function getMenu() { return [{ type: 'switch', @@ -669,37 +621,23 @@ onBeforeUnmount(() => { } > .contents { + display: flex; + flex-wrap: wrap; - > .folders, - > .files { - display: flex; - flex-wrap: wrap; - - > .folder, - > .file { - flex-grow: 1; - width: 128px; - margin: 4px; - box-sizing: border-box; - } - - > .padding { - flex-grow: 1; - pointer-events: none; - width: 128px + 8px; - } + > .item { + flex-grow: 1; + width: 128px; + margin: 4px; + box-sizing: border-box; } + } - > .empty { - padding: 16px; - text-align: center; - pointer-events: none; - opacity: 0.5; - - > p { - margin: 0; - } - } + > .empty { + padding: 16px; + text-align: center; + pointer-events: none; + opacity: 0.5; + margin: 0; } } From f7c4107ca4076e9a838991c43c013d0d2f630118 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 22 Dec 2022 18:55:06 +0100 Subject: [PATCH 005/108] client: drive uses grid instead of flexbox --- packages/client/src/components/drive.vue | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index 10f0be183..e4611a2f8 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -51,7 +51,6 @@ v-if="'size' in f" :key="f.id" v-anim="i" - class="item" :file="f" :select-mode="select === 'file'" :is-selected="selectedFiles.some(x => x.id === f.id)" @@ -63,7 +62,6 @@ v-else :key="f.id" v-anim="i" - class="item" :folder="f" :select-mode="select === 'folder'" :is-selected="selectedFolders.some(x => x.id === f.id)" @@ -621,15 +619,9 @@ onBeforeUnmount(() => { } > .contents { - display: flex; - flex-wrap: wrap; - - > .item { - flex-grow: 1; - width: 128px; - margin: 4px; - box-sizing: border-box; - } + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: .5em; } > .empty { From df9064c284f06d331d57a75998178853d3707546 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Fri, 23 Dec 2022 02:02:20 +0100 Subject: [PATCH 006/108] client: remove driveFolderBg theme color Changelog: Removed --- packages/client/src/components/drive.folder.vue | 1 - packages/client/src/components/drive.vue | 2 -- packages/client/src/themes/_dark.json5 | 1 - packages/client/src/themes/_light.json5 | 1 - packages/client/src/themes/d-astro.json5 | 1 - packages/client/src/themes/d-pumpkin.json5 | 1 - packages/client/src/themes/l-vivid.json5 | 1 - 7 files changed, 8 deletions(-) diff --git a/packages/client/src/components/drive.folder.vue b/packages/client/src/components/drive.folder.vue index 028dc7f2b..1584b15c0 100644 --- a/packages/client/src/components/drive.folder.vue +++ b/packages/client/src/components/drive.folder.vue @@ -261,7 +261,6 @@ function onContextmenu(ev: MouseEvent) { position: relative; padding: 8px; height: 64px; - background: var(--driveFolderBg); border-radius: 4px; &, * { diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index e4611a2f8..1ca4f8c57 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -52,7 +52,6 @@ :key="f.id" v-anim="i" :file="f" - :select-mode="select === 'file'" :is-selected="selectedFiles.some(x => x.id === f.id)" @chosen="chooseFile" @dragstart="isDragSource = true" @@ -63,7 +62,6 @@ :key="f.id" v-anim="i" :folder="f" - :select-mode="select === 'folder'" :is-selected="selectedFolders.some(x => x.id === f.id)" @chosen="chooseFolder" @move="move" diff --git a/packages/client/src/themes/_dark.json5 b/packages/client/src/themes/_dark.json5 index cda66a508..a4c51819b 100644 --- a/packages/client/src/themes/_dark.json5 +++ b/packages/client/src/themes/_dark.json5 @@ -64,7 +64,6 @@ inputBorder: 'rgba(255, 255, 255, 0.1)', inputBorderHover: 'rgba(255, 255, 255, 0.2)', listItemHoverBg: 'rgba(255, 255, 255, 0.03)', - driveFolderBg: ':alpha<0.3<@accent', wallpaperOverlay: 'rgba(0, 0, 0, 0.5)', badge: '#31b1ce', messageBg: '@bg', diff --git a/packages/client/src/themes/_light.json5 b/packages/client/src/themes/_light.json5 index 50c5388e0..1aae2b8cf 100644 --- a/packages/client/src/themes/_light.json5 +++ b/packages/client/src/themes/_light.json5 @@ -64,7 +64,6 @@ inputBorder: 'rgba(0, 0, 0, 0.1)', inputBorderHover: 'rgba(0, 0, 0, 0.2)', listItemHoverBg: 'rgba(0, 0, 0, 0.03)', - driveFolderBg: ':alpha<0.3<@accent', wallpaperOverlay: 'rgba(255, 255, 255, 0.5)', badge: '#31b1ce', messageBg: '@bg', diff --git a/packages/client/src/themes/d-astro.json5 b/packages/client/src/themes/d-astro.json5 index 7b9034020..873636981 100644 --- a/packages/client/src/themes/d-astro.json5 +++ b/packages/client/src/themes/d-astro.json5 @@ -46,7 +46,6 @@ buttonHoverBg: 'rgba(255, 255, 255, 0.1)', buttonGradateA: '@accent', buttonGradateB: ':hue<-20<@accent', - driveFolderBg: ':alpha<0.3<@accent', fgHighlighted: ':lighten<3<@fg', panelHeaderBg: ':lighten<3<@panel', panelHeaderFg: '@fg', diff --git a/packages/client/src/themes/d-pumpkin.json5 b/packages/client/src/themes/d-pumpkin.json5 index ff2bc9509..e466eb688 100644 --- a/packages/client/src/themes/d-pumpkin.json5 +++ b/packages/client/src/themes/d-pumpkin.json5 @@ -66,7 +66,6 @@ navIndicator: '@indicator', accentLighten: ':lighten<10<@accent', buttonHoverBg: 'rgba(255, 255, 255, 0.1)', - driveFolderBg: ':alpha<0.3<@accent', fgHighlighted: ':lighten<3<@fg', fgTransparent: ':alpha<0.5<@fg', panelHeaderBg: ':lighten<3<@panel', diff --git a/packages/client/src/themes/l-vivid.json5 b/packages/client/src/themes/l-vivid.json5 index 66d97f3a0..ede4e0571 100644 --- a/packages/client/src/themes/l-vivid.json5 +++ b/packages/client/src/themes/l-vivid.json5 @@ -47,7 +47,6 @@ navIndicator: '@accent', accentLighten: ':lighten<10<@accent', buttonHoverBg: 'rgba(0, 0, 0, 0.1)', - driveFolderBg: ':alpha<0.3<@accent', fgHighlighted: ':darken<3<@fg', fgTransparent: ':alpha<0.5<@fg', panelHeaderBg: ':lighten<3<@panel', From d26e2588e3f2662a488664d8dac8ffb386f22106 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Fri, 23 Dec 2022 02:20:36 +0100 Subject: [PATCH 007/108] client: combine selection of files & folders --- packages/client/src/components/drive.file.vue | 8 +- .../client/src/components/drive.folder.vue | 100 ++++++++++-------- packages/client/src/components/drive.vue | 86 ++++++++------- 3 files changed, 105 insertions(+), 89 deletions(-) diff --git a/packages/client/src/components/drive.file.vue b/packages/client/src/components/drive.file.vue index 6e3d38612..f6713947e 100644 --- a/packages/client/src/components/drive.file.vue +++ b/packages/client/src/components/drive.file.vue @@ -52,7 +52,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'chosen', r: foundkey.entities.DriveFile): void; + (ev: 'chosen', r: foundkey.entities.DriveFile, extendSelection: boolean): void; (ev: 'dragstart'): void; (ev: 'dragend'): void; }>(); @@ -95,9 +95,7 @@ function getMenu(): MenuItem[] { function onClick(ev: MouseEvent): void { if (props.selectMode) { - emit('chosen', props.file); - } else { - os.popupMenu(getMenu(), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); + emit('chosen', props.file, ev.ctrlKey); } } @@ -330,7 +328,7 @@ async function deleteFile(): Promise { overflow: hidden; > .ext { - opacity: 0.5; + opacity: 0.7; } } } diff --git a/packages/client/src/components/drive.folder.vue b/packages/client/src/components/drive.folder.vue index 1584b15c0..c613571f5 100644 --- a/packages/client/src/components/drive.folder.vue +++ b/packages/client/src/components/drive.folder.vue @@ -1,10 +1,10 @@ @@ -44,7 +45,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'chosen', v: foundkey.entities.DriveFolder): void; + (ev: 'chosen', v: foundkey.entities.DriveFolder, extendSelection: boolean): void; (ev: 'move', v: foundkey.entities.DriveFolder): void; (ev: 'upload', file: File, folder: foundkey.entities.DriveFolder); (ev: 'removeFile', v: foundkey.entities.DriveFile['id']): void; @@ -59,20 +60,10 @@ const isDragging = ref(false); const title = computed(() => props.folder.name); -function checkboxClicked() { - emit('chosen', props.folder); -} - -function onClick() { - emit('move', props.folder); -} - -function onMouseover() { - hover.value = true; -} - -function onMouseout() { - hover.value = false; +function selected(ev: MouseEvent) { + if (props.selectMode) { + emit('chosen', props.folder, ev.ctrlKey); + } } function onDragover(ev: DragEvent) { @@ -260,29 +251,34 @@ function onContextmenu(ev: MouseEvent) { .rghtznwe { position: relative; padding: 8px; - height: 64px; - border-radius: 4px; + min-height: 180px; + border-radius: 8px; &, * { cursor: pointer; } - *:not(.checkbox) { - pointer-events: none; - } + > .thumbnail { + width: 110px; + height: 110px; + margin: auto; - > .checkbox { - position: absolute; - bottom: 8px; - right: 8px; - width: 16px; - height: 16px; - background: #fff; - border: solid 1px #000; + /* same style as drive-file-thumbnail.vue */ + position: relative; + display: flex; + background: var(--panel); + border-radius: 8px; + overflow: clip; - &.checked { - background: var(--accent); + > i { + pointer-events: none; + margin: auto; + font-size: 33px; + color: #777; } + + &:not(:hover) > i.hover, + &:hover > i:not(.hover) { display: none; } } &.draghover { @@ -299,23 +295,37 @@ function onContextmenu(ev: MouseEvent) { } } - > .name { - margin: 0; - font-size: 0.9em; - color: var(--desktopDriveFolderFg); + &.isSelected { + background: var(--accent); - > i { - margin-right: 4px; - margin-left: 2px; - text-align: left; + &:hover { + background: var(--accentLighten); } + + > .name { + color: #fff; + } + + > .thumbnail { + color: #fff; + } + } + + > .name { + display: block; + margin: 4px 0 0 0; + font-size: 0.8em; + text-align: center; + word-break: break-all; + color: var(--fg); + overflow: hidden; } > .upload { margin: 4px 4px; font-size: 0.8em; - text-align: right; - color: var(--desktopDriveFolderFg); + text-align: center; + opacity: 0.7; } } diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index 1ca4f8c57..ec985ea9d 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -52,8 +52,9 @@ :key="f.id" v-anim="i" :file="f" - :is-selected="selectedFiles.some(x => x.id === f.id)" - @chosen="chooseFile" + :select-mode="select !== 'folder'" + :is-selected="selected.some(x => x.id === f.id)" + @chosen="choose" @dragstart="isDragSource = true" @dragend="isDragSource = false" /> @@ -62,8 +63,9 @@ :key="f.id" v-anim="i" :folder="f" - :is-selected="selectedFolders.some(x => x.id === f.id)" - @chosen="chooseFolder" + :select-mode="select !== 'file'" + :is-selected="selected.some(x => x.id === f.id)" + @chosen="choose" @move="move" @upload="upload" @removeFile="removeFile" @@ -106,7 +108,7 @@ const props = withDefaults(defineProps<{ const emit = defineEmits<{ (ev: 'selected', v: foundkey.entities.DriveFile | foundkey.entities.DriveFolder): void; - (ev: 'change-selection', v: foundkey.entities.DriveFile[] | foundkey.entities.DriveFolder[]): void; + (ev: 'change-selection', v: Array): void; (ev: 'move-root'): void; (ev: 'cd', v: foundkey.entities.DriveFolder | null): void; (ev: 'open-folder', v: foundkey.entities.DriveFolder): void; @@ -121,8 +123,7 @@ const connection = stream.useChannel('drive'); let folder = $ref(null); let hierarchyFolders = $ref([]); -let selectedFiles = $ref([]); -let selectedFolders = $ref([]); +let selected = $ref>([]); let keepOriginal = $ref(defaultStore.state.keepOriginalUploading); // ドロップされようとしているか @@ -356,42 +357,49 @@ function upload(file: File, folderToUpload?: foundkey.entities.DriveFolder | nul uploadFile(file, folderToUpload?.id ?? null, undefined, keepOriginal); } -function chooseFile(file: foundkey.entities.DriveFile) { - const isAlreadySelected = selectedFiles.some(f => f.id === file.id); - if (props.multiple) { - if (isAlreadySelected) { - selectedFiles = selectedFiles.filter(f => f.id !== file.id); - } else { - selectedFiles.push(file); - } - emit('change-selection', selectedFiles); - } else { - if (isAlreadySelected) { - emit('selected', file); - } else { - selectedFiles = [file]; - emit('change-selection', [file]); - } - } -} +function choose(choice: foundkey.entities.DriveFile | foundkey.entities.DriveFolder, extendSelection: boolean) { + const alreadySelected = selectedFiles.some(f => f.id === file.id); -function chooseFolder(folderToChoose: foundkey.entities.DriveFolder) { - const isAlreadySelected = selectedFolders.some(f => f.id === folderToChoose.id); - if (props.multiple) { - if (isAlreadySelected) { - selectedFolders = selectedFolders.filter(f => f.id !== folderToChoose.id); + const action = (() => { + if (props.select != null) { + // file picker mode, extendSelection is disregarded + if (props.multiple && alreadySelected) { + return 'remove'; + } else if (props.multiple) { + return 'add'; + } else if (!props.multiple && alreadySelected) { + return 'emit'; + } else { + return 'set'; + } } else { - selectedFolders.push(folderToChoose); - } - emit('change-selection', selectedFolders); - } else { - if (isAlreadySelected) { - emit('selected', folderToChoose); - } else { - selectedFolders = [folderToChoose]; - emit('change-selection', [folderToChoose]); + // explorer mode, props.multiple is disregarded + if (extendSelection && alreadySelected) { + return 'remove'; + } else if (extendSelection) { + return 'add'; + } else if (!alreadySelected) { + return 'set'; + } + // already selected && ! extend selection is a noop } + })(); + + switch (action) { + case 'emit': + emit('selected', choice); + return; // don't emit the change-selection event + case 'add': + selected.push(choice); + break; + case 'set': + selected = [choice]; + break; + case 'remove': + selected = selected.filter(f => f.id !== choice.id); + break; } + emit('change-selection', selected); } function move(target?: string | foundkey.entities.DriveFolder) { From 02aaee6050758dcce7ee9728464056de9b790d35 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Fri, 23 Dec 2022 02:21:52 +0100 Subject: [PATCH 008/108] client: select folder when entering it As a convenience when a user is in the "select a folder" dialog, opens a folder an then clicks on the checkmark, the currently open folder is selected. --- packages/client/src/components/drive.vue | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index ec985ea9d..3b9ebd85c 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -98,7 +98,6 @@ import { uploadFile, uploads } from '@/scripts/upload'; const props = withDefaults(defineProps<{ initialFolder?: foundkey.entities.DriveFolder; - type?: string; multiple?: boolean; select?: 'file' | 'folder' | null; }>(), { @@ -133,7 +132,14 @@ let draghover = $ref(false); // (自分自身の階層にドロップできないようにするためのフラグ) let isDragSource = $ref(false); -watch($$(folder), () => emit('cd', folder)); +watch($$(folder), () => { + emit('cd', folder) + if (props.select === 'folder') { + // convenience: entering a folder selects it + selected = [folder]; + emit('change-selection', selected); + } +}); function onStreamDriveFileCreated(file: foundkey.entities.DriveFile) { addFile(file, true); From 6ed13ea9a70648e4bd7d65cd40eeafde4a309b07 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 10:23:03 +0100 Subject: [PATCH 009/108] fix typo, the 2nd --- packages/client/src/components/global/url.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/components/global/url.vue b/packages/client/src/components/global/url.vue index 47811ae00..5b4e831b1 100644 --- a/packages/client/src/components/global/url.vue +++ b/packages/client/src/components/global/url.vue @@ -35,7 +35,7 @@ const props = withDefaults(defineProps<{ const self = props.url.startsWith(local); const uri = new URL(props.url); -if (!['http:', 'https:'].includes(url.protocol)) throw new Error('invalid url'); +if (!['http:', 'https:'].includes(uri.protocol)) throw new Error('invalid url'); let el: HTMLElement | null = $ref(null); let schema = $ref(uri.protocol); From 7c89e99243191e3fe41fe139cc3ce34c5847361c Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 12:52:28 +0100 Subject: [PATCH 010/108] fix registry migration It can happen that registry items were created at exactly the same time for some reason. --- .../backend/migration/1675375940759-registry-remove-domain.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/migration/1675375940759-registry-remove-domain.js b/packages/backend/migration/1675375940759-registry-remove-domain.js index d3ee12ca9..41ca930f3 100644 --- a/packages/backend/migration/1675375940759-registry-remove-domain.js +++ b/packages/backend/migration/1675375940759-registry-remove-domain.js @@ -5,8 +5,8 @@ export class registryRemoveDomain1675375940759 { await queryRunner.query(`DROP INDEX "public"."IDX_0a72bdfcdb97c0eca11fe7ecad"`); await queryRunner.query(`ALTER TABLE "registry_item" DROP COLUMN "domain"`); await queryRunner.query(`ALTER TABLE "registry_item" ALTER COLUMN "key" TYPE text USING "key"::text`); - // delete existing duplicated entries, keeping the latest updated one - await queryRunner.query(`DELETE FROM "registry_item" AS "a" WHERE "updatedAt" != (SELECT MAX("updatedAt") FROM "registry_item" AS "b" WHERE "a"."userId" = "b"."userId" AND "a"."key" = "b"."key" AND "a"."scope" = "b"."scope" GROUP BY "userId", "key", "scope")`); + // delete existing duplicated entries, keeping the latest created one + await queryRunner.query(`DELETE FROM "registry_item" AS "a" WHERE "id" != (SELECT MAX("id") FROM "registry_item" AS "b" WHERE "a"."userId" = "b"."userId" AND "a"."key" = "b"."key" AND "a"."scope" = "b"."scope" GROUP BY "userId", "key", "scope")`); await queryRunner.query(`ALTER TABLE "registry_item" ADD CONSTRAINT "UQ_b8d6509f847331273ab99daccc7" UNIQUE ("userId", "key", "scope")`); } From fff93c696565b9ee46a5ab653766cf1793f94f4f Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 17:25:24 +0100 Subject: [PATCH 011/108] activitypub: remove _misskey_content attribute As already noted back in https://github.com/misskey-dev/misskey/pull/8787 the intention was to replace the `_misskey_content` attribute with the ActivityPub-defined `source` property. Misskey and by extension Foundkey have shipped with the `source` property and the respective parsing for quite a while so it seems reasonable to remove it now. Changelog: Removed --- packages/backend/src/remote/activitypub/models/note.ts | 2 -- packages/backend/src/remote/activitypub/renderer/index.ts | 1 - packages/backend/src/remote/activitypub/renderer/note.ts | 1 - 3 files changed, 4 deletions(-) diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index fb9621b85..d7adc7b67 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -207,8 +207,6 @@ export async function createNote(value: string | IObject, resolver: Resolver, si let text: string | null = null; if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') { text = note.source.content; - } else if (typeof note._misskey_content !== 'undefined') { - text = note._misskey_content; } else if (typeof note.content === 'string') { text = fromHtml(note.content, quote?.uri); } diff --git a/packages/backend/src/remote/activitypub/renderer/index.ts b/packages/backend/src/remote/activitypub/renderer/index.ts index 37e73d37b..8ec9f7ade 100644 --- a/packages/backend/src/remote/activitypub/renderer/index.ts +++ b/packages/backend/src/remote/activitypub/renderer/index.ts @@ -35,7 +35,6 @@ export const renderActivity = (x: any): IActivity | null => { value: 'schema:value', // Misskey misskey: 'https://misskey-hub.net/ns#', - '_misskey_content': 'misskey:_misskey_content', '_misskey_quote': 'misskey:_misskey_quote', '_misskey_reaction': 'misskey:_misskey_reaction', '_misskey_votes': 'misskey:_misskey_votes', diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts index 6fd50c158..5ca251617 100644 --- a/packages/backend/src/remote/activitypub/renderer/note.ts +++ b/packages/backend/src/remote/activitypub/renderer/note.ts @@ -145,7 +145,6 @@ export default async function renderNote(note: Note, dive = true, isTalk = false attributedTo, summary, content, - _misskey_content: text, source: { content: text, mediaType: 'text/x.misskeymarkdown', From 68bc2e314bc5f55b452ac31ae410d8722bbd55d3 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 17:43:44 +0100 Subject: [PATCH 012/108] activitypub: remove _misskey_reaction property This property is duplicated by the `content` property so seems unnecessary. Changelog: Removed --- packages/backend/src/remote/activitypub/kernel/like.ts | 2 +- packages/backend/src/remote/activitypub/renderer/index.ts | 1 - packages/backend/src/remote/activitypub/renderer/like.ts | 1 - packages/backend/src/remote/activitypub/type.ts | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/remote/activitypub/kernel/like.ts b/packages/backend/src/remote/activitypub/kernel/like.ts index 76272eea7..9650312b3 100644 --- a/packages/backend/src/remote/activitypub/kernel/like.ts +++ b/packages/backend/src/remote/activitypub/kernel/like.ts @@ -11,7 +11,7 @@ export default async (actor: CacheableRemoteUser, activity: ILike) => { await extractEmojis(activity.tag || [], actor.host).catch(() => null); - return await createReaction(actor, note, activity._misskey_reaction || activity.content || activity.name).catch(e => { + return await createReaction(actor, note, activity.content || activity.name).catch(e => { if (e.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') { return 'skip: already reacted'; } else { diff --git a/packages/backend/src/remote/activitypub/renderer/index.ts b/packages/backend/src/remote/activitypub/renderer/index.ts index 8ec9f7ade..0ea143cda 100644 --- a/packages/backend/src/remote/activitypub/renderer/index.ts +++ b/packages/backend/src/remote/activitypub/renderer/index.ts @@ -36,7 +36,6 @@ export const renderActivity = (x: any): IActivity | null => { // Misskey misskey: 'https://misskey-hub.net/ns#', '_misskey_quote': 'misskey:_misskey_quote', - '_misskey_reaction': 'misskey:_misskey_reaction', '_misskey_votes': 'misskey:_misskey_votes', '_misskey_talk': 'misskey:_misskey_talk', 'isCat': 'misskey:isCat', diff --git a/packages/backend/src/remote/activitypub/renderer/like.ts b/packages/backend/src/remote/activitypub/renderer/like.ts index 3978bc961..a52d9c706 100644 --- a/packages/backend/src/remote/activitypub/renderer/like.ts +++ b/packages/backend/src/remote/activitypub/renderer/like.ts @@ -14,7 +14,6 @@ export const renderLike = async (noteReaction: NoteReaction, note: Note) => { actor: `${config.url}/users/${noteReaction.userId}`, object: note.uri ? note.uri : `${config.url}/notes/${noteReaction.noteId}`, content: reaction, - _misskey_reaction: reaction, } as any; if (reaction.startsWith(':')) { diff --git a/packages/backend/src/remote/activitypub/type.ts b/packages/backend/src/remote/activitypub/type.ts index 28868297d..a14133ddc 100644 --- a/packages/backend/src/remote/activitypub/type.ts +++ b/packages/backend/src/remote/activitypub/type.ts @@ -282,7 +282,7 @@ export interface IRemove extends IActivity { export interface ILike extends IActivity { type: 'Like' | 'EmojiReaction' | 'EmojiReact'; - _misskey_reaction?: string; + content?: string; } export interface IAnnounce extends IActivity { From b8796cb1faeca3f547759ba4709ce525ce23af1f Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 17:49:12 +0100 Subject: [PATCH 013/108] activitypub: remove _misskey_votes property This is a duplication of `replies.totalItems` and seems unnecessary, it is even only parsed by Misskey if the afforementioned property is not available. Changelog: Removed --- packages/backend/src/remote/activitypub/models/question.ts | 2 +- packages/backend/src/remote/activitypub/renderer/index.ts | 1 - packages/backend/src/remote/activitypub/renderer/question.ts | 1 - packages/backend/src/remote/activitypub/type.ts | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/backend/src/remote/activitypub/models/question.ts b/packages/backend/src/remote/activitypub/models/question.ts index 5d88e1d44..803acee66 100644 --- a/packages/backend/src/remote/activitypub/models/question.ts +++ b/packages/backend/src/remote/activitypub/models/question.ts @@ -23,7 +23,7 @@ export async function extractPollFromQuestion(source: string | IObject, resolver .map(x => x.name!); const votes = question[multiple ? 'anyOf' : 'oneOf']! - .map(x => x.replies && x.replies.totalItems || x._misskey_votes || 0); + .map(x => x.replies && x.replies.totalItems || 0); return { choices, diff --git a/packages/backend/src/remote/activitypub/renderer/index.ts b/packages/backend/src/remote/activitypub/renderer/index.ts index 0ea143cda..b66f766a2 100644 --- a/packages/backend/src/remote/activitypub/renderer/index.ts +++ b/packages/backend/src/remote/activitypub/renderer/index.ts @@ -36,7 +36,6 @@ export const renderActivity = (x: any): IActivity | null => { // Misskey misskey: 'https://misskey-hub.net/ns#', '_misskey_quote': 'misskey:_misskey_quote', - '_misskey_votes': 'misskey:_misskey_votes', '_misskey_talk': 'misskey:_misskey_talk', 'isCat': 'misskey:isCat', // vcard diff --git a/packages/backend/src/remote/activitypub/renderer/question.ts b/packages/backend/src/remote/activitypub/renderer/question.ts index d4d1b590a..a6116888a 100644 --- a/packages/backend/src/remote/activitypub/renderer/question.ts +++ b/packages/backend/src/remote/activitypub/renderer/question.ts @@ -11,7 +11,6 @@ export default async function renderQuestion(user: { id: User['id'] }, note: Not content: note.text || '', [poll.multiple ? 'anyOf' : 'oneOf']: poll.choices.map((text, i) => ({ name: text, - _misskey_votes: poll.votes[i], replies: { type: 'Collection', totalItems: poll.votes[i], diff --git a/packages/backend/src/remote/activitypub/type.ts b/packages/backend/src/remote/activitypub/type.ts index a14133ddc..b4d0499c5 100644 --- a/packages/backend/src/remote/activitypub/type.ts +++ b/packages/backend/src/remote/activitypub/type.ts @@ -171,7 +171,6 @@ export const isQuestion = (object: IObject): object is IQuestion => interface IQuestionChoice { name?: string; replies?: ICollection; - _misskey_votes?: number; } export interface ITombstone extends IObject { type: 'Tombstone'; From 3a7e8cfe5097f867d978e1a59f677030ee92c5f0 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 19:16:28 +0100 Subject: [PATCH 014/108] server: check instance description length limit Changelog: Fixed --- packages/backend/src/services/fetch-instance-metadata.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index ad312c3c8..71eb3269a 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -246,19 +246,20 @@ async function getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | n async function getDescription(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { if (info && info.metadata) { - if (info.metadata.nodeDescription || info.metadata.description) { - return info.metadata.nodeDescription || info.metadata.description; + const description = info.metadata.nodeDescription || info.metadata.description; + if (description && description.length < 4096) { + return description; } } if (doc) { const meta = doc.querySelector('meta[name="description"]')?.getAttribute('content'); - if (meta) { + if (meta && meta.length < 4096) { return meta; } const og = doc.querySelector('meta[property="og:description"]')?.getAttribute('content'); - if (og) { + if (og && og.length < 4096) { return og; } } From c9d395961e56664075e130587064edd40c63d355 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 19:17:11 +0100 Subject: [PATCH 015/108] server: refactor packing User --- .../backend/src/models/repositories/user.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 6a796b223..060bc0cd6 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -270,16 +270,14 @@ export const UserRepository = db.getRepository(User).extend({ const followingCount = profile == null ? null : (profile.ffVisibility === 'public') || isMe ? user.followingCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : + (profile.ffVisibility === 'followers') && relation?.isFollowing ? user.followingCount : null; const followersCount = profile == null ? null : (profile.ffVisibility === 'public') || isMe ? user.followersCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : + (profile.ffVisibility === 'followers') && relation?.isFollowing ? user.followersCount : null; - const falsy = opts.detail ? false : undefined; - const packed = { id: user.id, name: user.name, @@ -287,10 +285,10 @@ export const UserRepository = db.getRepository(User).extend({ host: user.host, avatarUrl: this.getAvatarUrlSync(user), avatarBlurhash: user.avatar?.blurhash || null, - isAdmin: user.isAdmin || falsy, - isModerator: user.isModerator || falsy, - isBot: user.isBot || falsy, - isCat: user.isCat || falsy, + isAdmin: user.isAdmin, + isModerator: user.isModerator, + isBot: user.isBot, + isCat: user.isCat, instance: !user.host ? undefined : userInstanceCache.fetch(user.host) .then(instance => !instance ? undefined : { name: instance.name, @@ -312,8 +310,8 @@ export const UserRepository = db.getRepository(User).extend({ bannerUrl: user.banner ? DriveFiles.getPublicUrl(user.banner, false) : null, bannerBlurhash: user.banner?.blurhash || null, isLocked: user.isLocked, - isSilenced: user.isSilenced || falsy, - isSuspended: user.isSuspended || falsy, + isSilenced: user.isSilenced, + isSuspended: user.isSuspended, description: profile!.description, location: profile!.location, birthday: profile!.birthday, @@ -369,7 +367,7 @@ export const UserRepository = db.getRepository(User).extend({ mutedInstances: profile!.mutedInstances, mutingNotificationTypes: profile!.mutingNotificationTypes, emailNotificationTypes: profile!.emailNotificationTypes, - showTimelineReplies: user.showTimelineReplies || falsy, + showTimelineReplies: user.showTimelineReplies, federateBlocks: user!.federateBlocks, } : {}), From 1ffa4b08e049e95f159b3128fde0fa184d42a3a4 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 11 Feb 2023 19:25:51 +0100 Subject: [PATCH 016/108] client: reformat notification component who the hell is supposed to read this --- .../client/src/components/notification.vue | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/notification.vue b/packages/client/src/components/notification.vue index 233e99aad..43ceb38a4 100644 --- a/packages/client/src/components/notification.vue +++ b/packages/client/src/components/notification.vue @@ -63,10 +63,29 @@ - {{ i18n.ts.youGotNewFollower }}
- {{ i18n.ts.followRequestAccepted }} - {{ i18n.ts.receiveFollowRequest }}
|
- {{ i18n.ts.groupInvited }}: {{ notification.invitation.group.name }}
|
+ + {{ i18n.ts.youGotNewFollower }} +
+ +
+
+ + {{ i18n.ts.followRequestAccepted }} + + + {{ i18n.ts.receiveFollowRequest }} +
+ | + +
+
+ + {{ i18n.ts.groupInvited }}: {{ notification.invitation.group.name }} +
+ | + +
+
From bf445964b54040e58bb0c5a6485d2544eafc3aae Mon Sep 17 00:00:00 2001 From: Johann150 Date: Wed, 15 Feb 2023 20:42:24 +0100 Subject: [PATCH 017/108] improve documentation for fetch-rss endpoint Changelog: Fixed --- .../src/server/api/endpoints/fetch-rss.ts | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts index 7c32e2e4d..fc216e90e 100644 --- a/packages/backend/src/server/api/endpoints/fetch-rss.ts +++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts @@ -10,7 +10,79 @@ export const meta = { requireCredential: true, allowGet: true, - cacheSec: 60 * 3, + cacheSec: 60 * 3, // 3min + + res: { + type: 'object', + properties: { + feedUrl: { + type: 'string', + optional: true, + }, + title: { + type: 'string', + optional: true, + }, + description: { + type: 'string', + optional: true, + }, + generator: { + type: 'string', + description: 'The application used to generate the feed (self-proclaimed).', + optional: true, + }, + link: { + type: 'string', + optional: true, + }, + lastBuildDate: { + type: 'string', + description: 'The last update timestamp, in ISO 8601 format.', + optional: true, + }, + items: { + type: 'array', + items: { + type: 'object', + properties: { + title: { + type: 'string', + optional: true, + }, + link: { + type: 'string', + optional: true, + }, + creator: { + type: 'string', + description: 'The author of this feed item.', + optional: true, + }, + content: { + type: 'string', + description: 'Content of the feed item, which possibly contains HTML.', + optional: true, + }, + contentSnippet: { + type: 'string', + description: 'The same as `content` but with HTML markup and unescaped HTML entities removed. (best effort, not guaranteed to work)', + optional: true, + }, + guid: { + type: 'string', + optional: true, + }, + isoDate: { + type: 'string', + description: 'The publication date, in ISO 8601 format.', + optional: true, + }, + }, + }, + }, + }, + }, } as const; export const paramDef = { From acaca35ff720e5b5b58a565f682bde6c96c6de5b Mon Sep 17 00:00:00 2001 From: Johann150 Date: Wed, 15 Feb 2023 20:42:40 +0100 Subject: [PATCH 018/108] client: fix authentication error in RSS widgets closes https://akkoma.dev/FoundKeyGang/FoundKey/issues/341 Changelog: Fixed --- packages/client/src/widgets/rss-ticker.vue | 11 +++++------ packages/client/src/widgets/rss.vue | 8 +++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/client/src/widgets/rss-ticker.vue b/packages/client/src/widgets/rss-ticker.vue index 55d9009bc..1c08078c5 100644 --- a/packages/client/src/widgets/rss-ticker.vue +++ b/packages/client/src/widgets/rss-ticker.vue @@ -25,6 +25,7 @@ import MarqueeText from '@/components/marquee.vue'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/ui/container.vue'; import { useInterval } from '@/scripts/use-interval'; +import * as os from '@/os'; const name = 'rssTicker'; @@ -77,12 +78,10 @@ const fetching = ref(true); let key = $ref(0); const tick = (): void => { - fetch(`/api/fetch-rss?url=${widgetProps.url}`, {}).then(res => { - res.json().then(feed => { - items.value = feed.items; - fetching.value = false; - key++; - }); + os.apiGet('fetch-rss', { url: widgetProps.url }).then(feed => { + items.value = feed.items; + fetching.value = false; + key++; }); }; diff --git a/packages/client/src/widgets/rss.vue b/packages/client/src/widgets/rss.vue index 72f624982..df1d88c65 100644 --- a/packages/client/src/widgets/rss.vue +++ b/packages/client/src/widgets/rss.vue @@ -51,11 +51,9 @@ const items = ref([]); const fetching = ref(true); const tick = () => { - fetch(`/api/fetch-rss?url=${widgetProps.url}`, {}).then(res => { - res.json().then(feed => { - items.value = feed.items; - fetching.value = false; - }); + os.apiGet('fetch-rss', { url: widgetProps.url }).then(feed => { + items.value = feed.items; + fetching.value = false; }); }; From 6aeb033507ec455628c4515d25d27f4d4f406c31 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 16 Feb 2023 21:49:02 +0100 Subject: [PATCH 019/108] client: change Misskey to Foundkey --- packages/client/src/init.ts | 2 +- packages/client/src/pages/admin/overview.vue | 2 +- packages/client/src/pages/welcome.setup.vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts index 692617abd..eae153878 100644 --- a/packages/client/src/init.ts +++ b/packages/client/src/init.ts @@ -40,7 +40,7 @@ import { getUrlWithoutLoginId } from '@/scripts/login-id'; import { getAccountFromId } from '@/scripts/get-account-from-id'; (async () => { - console.info(`Misskey v${version}`); + console.info(`Foundkey v${version}`); if (_DEV_) { console.warn('Development mode!!!'); diff --git a/packages/client/src/pages/admin/overview.vue b/packages/client/src/pages/admin/overview.vue index a47a7a740..99b9e6e9f 100644 --- a/packages/client/src/pages/admin/overview.vue +++ b/packages/client/src/pages/admin/overview.vue @@ -39,7 +39,7 @@
-
Misskey
+
Foundkey
{{ version }}
diff --git a/packages/client/src/pages/welcome.setup.vue b/packages/client/src/pages/welcome.setup.vue index 26f87c52e..80bbf5950 100644 --- a/packages/client/src/pages/welcome.setup.vue +++ b/packages/client/src/pages/welcome.setup.vue @@ -1,6 +1,6 @@