diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2022-06-11 19:31:03 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-11 19:31:03 +0900 |
| commit | 182a1bf653ecfbcf76e4530b3077c6252b0d4827 (patch) | |
| tree | 45d1472747d4cac017e96616f844292f5785ccdd /packages/backend/src/services | |
| parent | 12.110.1 (diff) | |
| parent | 12.111.0 (diff) | |
| download | sharkey-182a1bf653ecfbcf76e4530b3077c6252b0d4827.tar.gz sharkey-182a1bf653ecfbcf76e4530b3077c6252b0d4827.tar.bz2 sharkey-182a1bf653ecfbcf76e4530b3077c6252b0d4827.zip | |
Merge pull request #8783 from misskey-dev/develop
Release: 12.111.0
Diffstat (limited to 'packages/backend/src/services')
18 files changed, 147 insertions, 152 deletions
diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts index 5e96e5037f..a2c61cca22 100644 --- a/packages/backend/src/services/blocking/create.ts +++ b/packages/backend/src/services/blocking/create.ts @@ -2,9 +2,10 @@ import { publishMainStream, publishUserEvent } from '@/services/stream.js'; import { renderActivity } from '@/remote/activitypub/renderer/index.js'; import renderFollow from '@/remote/activitypub/renderer/follow.js'; import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import renderBlock from '@/remote/activitypub/renderer/block.js'; +import { renderBlock } from '@/remote/activitypub/renderer/block.js'; import { deliver } from '@/queue/index.js'; import renderReject from '@/remote/activitypub/renderer/reject.js'; +import { Blocking } from '@/models/entities/blocking.js'; import { User } from '@/models/entities/user.js'; import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index.js'; import { perUserFollowingChart } from '@/services/chart/index.js'; @@ -22,15 +23,19 @@ export default async function(blocker: User, blockee: User) { removeFromList(blockee, blocker), ]); - await Blockings.insert({ + const blocking = { id: genId(), createdAt: new Date(), + blocker, blockerId: blocker.id, + blockee, blockeeId: blockee.id, - }); + } as Blocking; + + await Blockings.insert(blocking); if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) { - const content = renderActivity(renderBlock(blocker, blockee)); + const content = renderActivity(renderBlock(blocking)); deliver(blocker, content, blockee.inbox); } } @@ -95,17 +100,12 @@ async function unFollow(follower: User, followee: User) { return; } - Followings.delete(following.id); - - //#region Decrement following count - Users.decrement({ id: follower.id }, 'followingCount', 1); - //#endregion - - //#region Decrement followers count - Users.decrement({ id: followee.id }, 'followersCount', 1); - //#endregion - - perUserFollowingChart.update(follower, followee, false); + await Promise.all([ + Followings.delete(following.id), + Users.decrement({ id: follower.id }, 'followingCount', 1), + Users.decrement({ id: followee.id }, 'followersCount', 1), + perUserFollowingChart.update(follower, followee, false), + ]); // Publish unfollow event if (Users.isLocalUser(follower)) { diff --git a/packages/backend/src/services/blocking/delete.ts b/packages/backend/src/services/blocking/delete.ts index d7b5ddd5ff..cb16651bc0 100644 --- a/packages/backend/src/services/blocking/delete.ts +++ b/packages/backend/src/services/blocking/delete.ts @@ -1,5 +1,5 @@ import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderBlock from '@/remote/activitypub/renderer/block.js'; +import { renderBlock } from '@/remote/activitypub/renderer/block.js'; import renderUndo from '@/remote/activitypub/renderer/undo.js'; import { deliver } from '@/queue/index.js'; import Logger from '../logger.js'; @@ -19,11 +19,16 @@ export default async function(blocker: CacheableUser, blockee: CacheableUser) { return; } + // Since we already have the blocker and blockee, we do not need to fetch + // them in the query above and can just manually insert them here. + blocking.blocker = blocker; + blocking.blockee = blockee; + Blockings.delete(blocking.id); // deliver if remote bloking if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) { - const content = renderActivity(renderUndo(renderBlock(blocker, blockee), blocker)); + const content = renderActivity(renderUndo(renderBlock(blocking), blocker)); deliver(blocker, content, blockee.inbox); } } diff --git a/packages/backend/src/services/chart/core.ts b/packages/backend/src/services/chart/core.ts index cf69e2194d..2960bac8f7 100644 --- a/packages/backend/src/services/chart/core.ts +++ b/packages/backend/src/services/chart/core.ts @@ -91,27 +91,20 @@ type ToJsonSchema<S> = { }; export function getJsonSchema<S extends Schema>(schema: S): ToJsonSchema<Unflatten<ChartResult<S>>> { - const object = {}; - for (const [k, v] of Object.entries(schema)) { - nestedProperty.set(object, k, null); - } + const jsonSchema = { + type: 'object', + properties: {} as Record<string, unknown>, + required: [], + }; - function f(obj: Record<string, null | Record<string, unknown>>) { - const jsonSchema = { - type: 'object', - properties: {} as Record<string, unknown>, - required: [], + for (const k in schema) { + jsonSchema.properties[k] = { + type: 'array', + items: { type: 'number' }, }; - for (const [k, v] of Object.entries(obj)) { - jsonSchema.properties[k] = v === null ? { - type: 'array', - items: { type: 'number' }, - } : f(v as Record<string, null | Record<string, unknown>>); - } - return jsonSchema; } - return f(object) as ToJsonSchema<Unflatten<ChartResult<S>>>; + return jsonSchema as ToJsonSchema<Unflatten<ChartResult<S>>>; } /** diff --git a/packages/backend/src/services/chart/entities.ts b/packages/backend/src/services/chart/entities.ts index 13e994cb65..a9eeabd639 100644 --- a/packages/backend/src/services/chart/entities.ts +++ b/packages/backend/src/services/chart/entities.ts @@ -11,6 +11,11 @@ import { entity as PerUserFollowingChart } from './charts/entities/per-user-foll import { entity as PerUserDriveChart } from './charts/entities/per-user-drive.js'; import { entity as ApRequestChart } from './charts/entities/ap-request.js'; +import { entity as TestChart } from './charts/entities/test.js'; +import { entity as TestGroupedChart } from './charts/entities/test-grouped.js'; +import { entity as TestUniqueChart } from './charts/entities/test-unique.js'; +import { entity as TestIntersectionChart } from './charts/entities/test-intersection.js'; + export const entities = [ FederationChart.hour, FederationChart.day, NotesChart.hour, NotesChart.day, @@ -24,4 +29,11 @@ export const entities = [ PerUserFollowingChart.hour, PerUserFollowingChart.day, PerUserDriveChart.hour, PerUserDriveChart.day, ApRequestChart.hour, ApRequestChart.day, + + ...(process.env.NODE_ENV === 'test' ? [ + TestChart.hour, TestChart.day, + TestGroupedChart.hour, TestGroupedChart.day, + TestUniqueChart.hour, TestUniqueChart.day, + TestIntersectionChart.hour, TestIntersectionChart.day, + ] : []), ]; diff --git a/packages/backend/src/services/create-notification.ts b/packages/backend/src/services/create-notification.ts index 9a53db1f38..d53a4235b8 100644 --- a/packages/backend/src/services/create-notification.ts +++ b/packages/backend/src/services/create-notification.ts @@ -1,5 +1,5 @@ import { publishMainStream } from '@/services/stream.js'; -import pushSw from './push-notification.js'; +import { pushNotification } from '@/services/push-notification.js'; import { Notifications, Mutings, UserProfiles, Users } from '@/models/index.js'; import { genId } from '@/misc/gen-id.js'; import { User } from '@/models/entities/user.js'; @@ -52,8 +52,8 @@ export async function createNotification( //#endregion publishMainStream(notifieeId, 'unreadNotification', packed); + pushNotification(notifieeId, 'notification', packed); - pushSw(notifieeId, 'notification', packed); if (type === 'follow') sendEmailNotification.follow(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! })); if (type === 'receiveFollowRequest') sendEmailNotification.receiveFollowRequest(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! })); }, 2000); diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 549b11c9fe..cfbcb60ddf 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -7,7 +7,7 @@ import { deleteFile } from './delete-file.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { GenerateVideoThumbnail } from './generate-video-thumbnail.js'; import { driveLogger } from './logger.js'; -import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng, convertSharpToPngOrJpeg } from './image-processor.js'; +import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng } from './image-processor.js'; import { contentDisposition } from '@/misc/content-disposition.js'; import { getFileInfo } from '@/misc/get-file-info.js'; import { DriveFiles, DriveFolders, Users, Instances, UserProfiles } from '@/models/index.js'; @@ -179,6 +179,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool } let img: sharp.Sharp | null = null; + let satisfyWebpublic: boolean; try { img = sharp(path); @@ -192,6 +193,13 @@ export async function generateAlts(path: string, type: string, generateWeb: bool thumbnail: null, }; } + + satisfyWebpublic = !!( + type !== 'image/svg+xml' && type !== 'image/webp' && + !(metadata.exif || metadata.iptc || metadata.xmp || metadata.tifftagPhotoshop) && + metadata.width && metadata.width <= 2048 && + metadata.height && metadata.height <= 2048 + ); } catch (err) { logger.warn(`sharp failed: ${err}`); return { @@ -203,15 +211,15 @@ export async function generateAlts(path: string, type: string, generateWeb: bool // #region webpublic let webpublic: IImage | null = null; - if (generateWeb) { + if (generateWeb && !satisfyWebpublic) { logger.info(`creating web image`); try { - if (['image/jpeg'].includes(type)) { + if (['image/jpeg', 'image/webp'].includes(type)) { webpublic = await convertSharpToJpeg(img, 2048, 2048); - } else if (['image/webp'].includes(type)) { - webpublic = await convertSharpToWebp(img, 2048, 2048); - } else if (['image/png', 'image/svg+xml'].includes(type)) { + } else if (['image/png'].includes(type)) { + webpublic = await convertSharpToPng(img, 2048, 2048); + } else if (['image/svg+xml'].includes(type)) { webpublic = await convertSharpToPng(img, 2048, 2048); } else { logger.debug(`web image not created (not an required image)`); @@ -220,7 +228,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool logger.warn(`web image not created (an error occured)`, err as Error); } } else { - logger.info(`web image not created (from remote)`); + if (satisfyWebpublic) logger.info(`web image not created (original satisfies webpublic)`); + else logger.info(`web image not created (from remote)`); } // #endregion webpublic @@ -228,10 +237,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool let thumbnail: IImage | null = null; try { - if (['image/jpeg', 'image/webp'].includes(type)) { - thumbnail = await convertSharpToJpeg(img, 498, 280); - } else if (['image/png', 'image/svg+xml'].includes(type)) { - thumbnail = await convertSharpToPngOrJpeg(img, 498, 280); + if (['image/jpeg', 'image/webp', 'image/png', 'image/svg+xml'].includes(type)) { + thumbnail = await convertSharpToWebp(img, 498, 280); } else { logger.debug(`thumbnail not created (not an required file)`); } diff --git a/packages/backend/src/services/drive/generate-video-thumbnail.ts b/packages/backend/src/services/drive/generate-video-thumbnail.ts index 04a7a83346..ca12ab8d3d 100644 --- a/packages/backend/src/services/drive/generate-video-thumbnail.ts +++ b/packages/backend/src/services/drive/generate-video-thumbnail.ts @@ -1,37 +1,31 @@ import * as fs from 'node:fs'; -import * as tmp from 'tmp'; +import * as path from 'node:path'; +import { createTemp } from '@/misc/create-temp.js'; import { IImage, convertToJpeg } from './image-processor.js'; -import * as FFmpeg from 'fluent-ffmpeg'; +import FFmpeg from 'fluent-ffmpeg'; -export async function GenerateVideoThumbnail(path: string): Promise<IImage> { - const [outDir, cleanup] = await new Promise<[string, any]>((res, rej) => { - tmp.dir((e, path, cleanup) => { - if (e) return rej(e); - res([path, cleanup]); - }); - }); +export async function GenerateVideoThumbnail(source: string): Promise<IImage> { + const [file, cleanup] = await createTemp(); + const parsed = path.parse(file); - await new Promise((res, rej) => { - FFmpeg({ - source: path, - }) - .on('end', res) - .on('error', rej) - .screenshot({ - folder: outDir, - filename: 'output.png', - count: 1, - timestamps: ['5%'], + try { + await new Promise((res, rej) => { + FFmpeg({ + source, + }) + .on('end', res) + .on('error', rej) + .screenshot({ + folder: parsed.dir, + filename: parsed.base, + count: 1, + timestamps: ['5%'], + }); }); - }); - - const outPath = `${outDir}/output.png`; - - const thumbnail = await convertToJpeg(outPath, 498, 280); - - // cleanup - await fs.promises.unlink(outPath); - cleanup(); - return thumbnail; + // JPEGに変換 (Webpでもいいが、MastodonはWebpをサポートせず表示できなくなる) + return await convertToJpeg(498, 280); + } finally { + cleanup(); + } } diff --git a/packages/backend/src/services/drive/image-processor.ts b/packages/backend/src/services/drive/image-processor.ts index 146dcfb6ca..2c564ea595 100644 --- a/packages/backend/src/services/drive/image-processor.ts +++ b/packages/backend/src/services/drive/image-processor.ts @@ -38,11 +38,11 @@ export async function convertSharpToJpeg(sharp: sharp.Sharp, width: number, heig * Convert to WebP * with resize, remove metadata, resolve orientation, stop animation */ -export async function convertToWebp(path: string, width: number, height: number): Promise<IImage> { - return convertSharpToWebp(await sharp(path), width, height); +export async function convertToWebp(path: string, width: number, height: number, quality: number = 85): Promise<IImage> { + return convertSharpToWebp(await sharp(path), width, height, quality); } -export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> { +export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number, quality: number = 85): Promise<IImage> { const data = await sharp .resize(width, height, { fit: 'inside', @@ -50,7 +50,7 @@ export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, heig }) .rotate() .webp({ - quality: 85, + quality, }) .toBuffer(); @@ -85,23 +85,3 @@ export async function convertSharpToPng(sharp: sharp.Sharp, width: number, heigh type: 'image/png', }; } - -/** - * Convert to PNG or JPEG - * with resize, remove metadata, resolve orientation, stop animation - */ -export async function convertToPngOrJpeg(path: string, width: number, height: number): Promise<IImage> { - return convertSharpToPngOrJpeg(await sharp(path), width, height); -} - -export async function convertSharpToPngOrJpeg(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> { - const stats = await sharp.stats(); - const metadata = await sharp.metadata(); - - // 不透明で300x300pxの範囲を超えていればJPEG - if (stats.isOpaque && ((metadata.width && metadata.width >= 300) || (metadata.height && metadata!.height >= 300))) { - return await convertSharpToJpeg(sharp, width, height); - } else { - return await convertSharpToPng(sharp, width, height); - } -} diff --git a/packages/backend/src/services/drive/upload-from-url.ts b/packages/backend/src/services/drive/upload-from-url.ts index 79b1b8c2e1..001fc49ee4 100644 --- a/packages/backend/src/services/drive/upload-from-url.ts +++ b/packages/backend/src/services/drive/upload-from-url.ts @@ -45,29 +45,20 @@ export async function uploadFromUrl({ // Create temp file const [path, cleanup] = await createTemp(); - // write content at URL to temp file - await downloadUrl(url, path); - - let driveFile: DriveFile; - let error; - try { - driveFile = await addFile({ user, path, name, comment, folderId, force, isLink, url, uri, sensitive }); + // write content at URL to temp file + await downloadUrl(url, path); + + const driveFile = await addFile({ user, path, name, comment, folderId, force, isLink, url, uri, sensitive }); logger.succ(`Got: ${driveFile.id}`); + return driveFile!; } catch (e) { - error = e; logger.error(`Failed to create drive file: ${e}`, { url: url, e: e, }); - } - - // clean-up - cleanup(); - - if (error) { - throw error; - } else { - return driveFile!; + throw e; + } finally { + cleanup(); } } diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index d5294c5fe8..029c388dc2 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -1,5 +1,6 @@ import { DOMWindow, JSDOM } from 'jsdom'; import fetch from 'node-fetch'; +import tinycolor from 'tinycolor2'; import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js'; import { Instance } from '@/models/entities/instance.js'; import { Instances } from '@/models/index.js'; @@ -208,16 +209,11 @@ async function fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | nul } async function getThemeColor(doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> { - if (doc) { - const themeColor = doc.querySelector('meta[name="theme-color"]')?.getAttribute('content'); + const themeColor = doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') || manifest?.theme_color; - if (themeColor) { - return themeColor; - } - } - - if (manifest) { - return manifest.theme_color; + if (themeColor) { + const color = new tinycolor(themeColor); + if (color.isValid()) return color.toHexString(); } return null; diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index 7491c44f83..72c24676bb 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -67,8 +67,10 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ if (alreadyFollowed) return; //#region Increment counts - Users.increment({ id: follower.id }, 'followingCount', 1); - Users.increment({ id: followee.id }, 'followersCount', 1); + await Promise.all([ + Users.increment({ id: follower.id }, 'followingCount', 1), + Users.increment({ id: followee.id }, 'followersCount', 1), + ]); //#endregion //#region Update instance stats diff --git a/packages/backend/src/services/following/delete.ts b/packages/backend/src/services/following/delete.ts index 241f9606e5..91b5a3d61d 100644 --- a/packages/backend/src/services/following/delete.ts +++ b/packages/backend/src/services/following/delete.ts @@ -58,12 +58,11 @@ export default async function(follower: { id: User['id']; host: User['host']; ur } export async function decrementFollowing(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }) { - //#region Decrement following count - Users.decrement({ id: follower.id }, 'followingCount', 1); - //#endregion - - //#region Decrement followers count - Users.decrement({ id: followee.id }, 'followersCount', 1); + //#region Decrement following / followers counts + await Promise.all([ + Users.decrement({ id: follower.id }, 'followingCount', 1), + Users.decrement({ id: followee.id }, 'followersCount', 1), + ]); //#endregion //#region Update instance stats diff --git a/packages/backend/src/services/messages/create.ts b/packages/backend/src/services/messages/create.ts index e5cd5a30d2..e6b3204922 100644 --- a/packages/backend/src/services/messages/create.ts +++ b/packages/backend/src/services/messages/create.ts @@ -5,7 +5,7 @@ import { MessagingMessages, UserGroupJoinings, Mutings, Users } from '@/models/i import { genId } from '@/misc/gen-id.js'; import { MessagingMessage } from '@/models/entities/messaging-message.js'; import { publishMessagingStream, publishMessagingIndexStream, publishMainStream, publishGroupMessagingStream } from '@/services/stream.js'; -import pushNotification from '../push-notification.js'; +import { pushNotification } from '@/services/push-notification.js'; import { Not } from 'typeorm'; import { Note } from '@/models/entities/note.js'; import renderNote from '@/remote/activitypub/renderer/note.js'; diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index f14bc2059b..e2bf9d5b59 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -187,6 +187,8 @@ export default async (user: { id: User['id']; username: User['username']; host: if (data.text) { data.text = data.text.trim(); + } else { + data.text = null; } let tags = data.apHashtags; @@ -310,7 +312,8 @@ export default async (user: { id: User['id']; username: User['username']; host: endedPollNotificationQueue.add({ noteId: note.id, }, { - delay + delay, + removeOnComplete: true, }); } diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index ffd609dd84..4963200161 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -1,3 +1,4 @@ +import { Brackets, In } from 'typeorm'; import { publishNoteStream } from '@/services/stream.js'; import renderDelete from '@/remote/activitypub/renderer/delete.js'; import renderAnnounce from '@/remote/activitypub/renderer/announce.js'; @@ -5,15 +6,14 @@ import renderUndo from '@/remote/activitypub/renderer/undo.js'; import { renderActivity } from '@/remote/activitypub/renderer/index.js'; import renderTombstone from '@/remote/activitypub/renderer/tombstone.js'; import config from '@/config/index.js'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; import { Notes, Users, Instances } from '@/models/index.js'; import { notesChart, perUserNotesChart, instanceChart } from '@/services/chart/index.js'; import { deliverToFollowers, deliverToUser } from '@/remote/activitypub/deliver-manager.js'; import { countSameRenotes } from '@/misc/count-same-renotes.js'; +import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; import { deliverToRelays } from '../relay.js'; -import { Brackets, In } from 'typeorm'; /** * 投稿を削除します。 @@ -40,7 +40,7 @@ export default async function(user: { id: User['id']; uri: User['uri']; host: Us //#region ローカルの投稿なら削除アクティビティを配送 if (Users.isLocalUser(user) && !note.localOnly) { - let renote: Note | null; + let renote: Note | null = null; // if deletd note is renote if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { @@ -113,7 +113,7 @@ async function getMentionedRemoteUsers(note: Note) { const uris = (JSON.parse(note.mentionedRemoteUsers) as IMentionedRemoteUsers).map(x => x.uri); if (uris.length > 0) { where.push( - { uri: In(uris) } + { uri: In(uris) }, ); } diff --git a/packages/backend/src/services/note/reaction/create.ts b/packages/backend/src/services/note/reaction/create.ts index 5a0948bca9..83d302826a 100644 --- a/packages/backend/src/services/note/reaction/create.ts +++ b/packages/backend/src/services/note/reaction/create.ts @@ -27,6 +27,11 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, } } + // check visibility + if (!await Notes.isVisibleForMe(note, user.id)) { + throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.'); + } + // TODO: cache reaction = await toDbReaction(reaction, user.host); diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index 41122c92e8..5c3bafbb34 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -5,8 +5,15 @@ import { fetchMeta } from '@/misc/fetch-meta.js'; import { Packed } from '@/misc/schema.js'; import { getNoteSummary } from '@/misc/get-note-summary.js'; -type notificationType = 'notification' | 'unreadMessagingMessage'; -type notificationBody = Packed<'Notification'> | Packed<'MessagingMessage'>; +// Defined also packages/sw/types.ts#L14-L21 +type pushNotificationsTypes = { + 'notification': Packed<'Notification'>; + 'unreadMessagingMessage': Packed<'MessagingMessage'>; + 'readNotifications': { notificationIds: string[] }; + 'readAllNotifications': undefined; + 'readAllMessagingMessages': undefined; + 'readAllMessagingMessagesOfARoom': { userId: string } | { groupId: string }; +}; // プッシュメッセージサーバーには文字数制限があるため、内容を削減します function truncateNotification(notification: Packed<'Notification'>): any { @@ -17,12 +24,11 @@ function truncateNotification(notification: Packed<'Notification'>): any { ...notification.note, // textをgetNoteSummaryしたものに置き換える text: getNoteSummary(notification.type === 'renote' ? notification.note.renote as Packed<'Note'> : notification.note), - ...{ - cw: undefined, - reply: undefined, - renote: undefined, - user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる - } + + cw: undefined, + reply: undefined, + renote: undefined, + user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる } }; } @@ -30,7 +36,7 @@ function truncateNotification(notification: Packed<'Notification'>): any { return notification; } -export default async function(userId: string, type: notificationType, body: notificationBody) { +export async function pushNotification<T extends keyof pushNotificationsTypes>(userId: string, type: T, body: pushNotificationsTypes[T]) { const meta = await fetchMeta(); if (!meta.enableServiceWorker || meta.swPublicKey == null || meta.swPrivateKey == null) return; diff --git a/packages/backend/src/services/relay.ts b/packages/backend/src/services/relay.ts index 1ab45588da..6bc4304436 100644 --- a/packages/backend/src/services/relay.ts +++ b/packages/backend/src/services/relay.ts @@ -1,4 +1,4 @@ -import { createSystemUser } from './create-system-user.js'; +import { IsNull } from 'typeorm'; import { renderFollowRelay } from '@/remote/activitypub/renderer/follow-relay.js'; import { renderActivity, attachLdSignature } from '@/remote/activitypub/renderer/index.js'; import renderUndo from '@/remote/activitypub/renderer/undo.js'; @@ -8,7 +8,7 @@ import { Users, Relays } from '@/models/index.js'; import { genId } from '@/misc/gen-id.js'; import { Cache } from '@/misc/cache.js'; import { Relay } from '@/models/entities/relay.js'; -import { IsNull } from 'typeorm'; +import { createSystemUser } from './create-system-user.js'; const ACTOR_USERNAME = 'relay.actor' as const; @@ -88,6 +88,8 @@ export async function deliverToRelays(user: { id: User['id']; host: null; }, act })); if (relays.length === 0) return; + // TODO + //const copy = structuredClone(activity); const copy = JSON.parse(JSON.stringify(activity)); if (!copy.to) copy.to = ['https://www.w3.org/ns/activitystreams#Public']; |