Merge branch 'pag-back' of https://github.com/misskey-dev/misskey into pag-back

This commit is contained in:
tamaina 2023-07-13 03:54:08 +00:00
commit af00c2c96c
49 changed files with 310 additions and 209 deletions

View file

@ -30,6 +30,7 @@
- ユーザーのContextMenuに「アンテナに追加」ボタンを追加 - ユーザーのContextMenuに「アンテナに追加」ボタンを追加
- フォローやお気に入り登録をしていないチャンネルを開く時は概要ページを開くように - フォローやお気に入り登録をしていないチャンネルを開く時は概要ページを開くように
- 画面ビューワをタップした場合、マウスクリックと同様に画像ビューワを閉じるように - 画面ビューワをタップした場合、マウスクリックと同様に画像ビューワを閉じるように
- オフライン時の画面にリロードボタンを追加
- Fix: サーバーメトリクスが90度傾いている - Fix: サーバーメトリクスが90度傾いている
- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正 - Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正
- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正 - Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正

2
locales/index.d.ts vendored
View file

@ -2158,4 +2158,4 @@ export interface Locale {
declare const locales: { declare const locales: {
[lang: string]: Locale; [lang: string]: Locale;
}; };
export = locales; export default locales;

View file

@ -570,12 +570,14 @@ export class NoteCreateService implements OnApplicationShutdown {
if (data.reply) { if (data.reply) {
// 通知 // 通知
if (data.reply.userHost === null) { if (data.reply.userHost === null) {
const threadMuted = await this.noteThreadMutingsRepository.findOneBy({ const isThreadMuted = await this.noteThreadMutingsRepository.exist({
where: {
userId: data.reply.userId, userId: data.reply.userId,
threadId: data.reply.threadId ?? data.reply.id, threadId: data.reply.threadId ?? data.reply.id,
}
}); });
if (!threadMuted) { if (!isThreadMuted) {
nm.push(data.reply.userId, 'reply'); nm.push(data.reply.userId, 'reply');
this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj); this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
@ -712,12 +714,14 @@ export class NoteCreateService implements OnApplicationShutdown {
@bindThis @bindThis
private async createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) { private async createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) { for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
const threadMuted = await this.noteThreadMutingsRepository.findOneBy({ const isThreadMuted = await this.noteThreadMutingsRepository.exist({
where: {
userId: u.id, userId: u.id,
threadId: note.threadId ?? note.id, threadId: note.threadId ?? note.id,
},
}); });
if (threadMuted) { if (isThreadMuted) {
continue; continue;
} }

View file

@ -43,11 +43,13 @@ export class NoteReadService implements OnApplicationShutdown {
//#endregion //#endregion
// スレッドミュート // スレッドミュート
const threadMute = await this.noteThreadMutingsRepository.findOneBy({ const isThreadMuted = await this.noteThreadMutingsRepository.exist({
where: {
userId: userId, userId: userId,
threadId: note.threadId ?? note.id, threadId: note.threadId ?? note.id,
},
}); });
if (threadMute) return; if (isThreadMuted) return;
const unread = { const unread = {
id: this.idService.genId(), id: this.idService.genId(),
@ -62,9 +64,9 @@ export class NoteReadService implements OnApplicationShutdown {
// 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する // 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する
setTimeout(2000, 'unread note', { signal: this.#shutdownController.signal }).then(async () => { setTimeout(2000, 'unread note', { signal: this.#shutdownController.signal }).then(async () => {
const exist = await this.noteUnreadsRepository.findOneBy({ id: unread.id }); const exist = await this.noteUnreadsRepository.exist({ where: { id: unread.id } });
if (exist == null) return; if (!exist) return;
if (params.isMentioned) { if (params.isMentioned) {
this.globalEventService.publishMainStream(userId, 'unreadMention', note.id); this.globalEventService.publishMainStream(userId, 'unreadMention', note.id);

View file

@ -71,12 +71,12 @@ export class SignupService {
const secret = generateUserToken(); const secret = generateUserToken();
// Check username duplication // Check username duplication
if (await this.usersRepository.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull() })) { if (await this.usersRepository.exist({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) {
throw new Error('DUPLICATED_USERNAME'); throw new Error('DUPLICATED_USERNAME');
} }
// Check deleted username duplication // Check deleted username duplication
if (await this.usedUsernamesRepository.findOneBy({ username: username.toLowerCase() })) { if (await this.usedUsernamesRepository.exist({ where: { username: username.toLowerCase() } })) {
throw new Error('USED_USERNAME'); throw new Error('USED_USERNAME');
} }

View file

@ -122,22 +122,26 @@ export class UserFollowingService implements OnModuleInit {
let autoAccept = false; let autoAccept = false;
// 鍵アカウントであっても、既にフォローされていた場合はスルー // 鍵アカウントであっても、既にフォローされていた場合はスルー
const following = await this.followingsRepository.findOneBy({ const isFollowing = await this.followingsRepository.exist({
where: {
followerId: follower.id, followerId: follower.id,
followeeId: followee.id, followeeId: followee.id,
},
}); });
if (following) { if (isFollowing) {
autoAccept = true; autoAccept = true;
} }
// フォローしているユーザーは自動承認オプション // フォローしているユーザーは自動承認オプション
if (!autoAccept && (this.userEntityService.isLocalUser(followee) && followeeProfile.autoAcceptFollowed)) { if (!autoAccept && (this.userEntityService.isLocalUser(followee) && followeeProfile.autoAcceptFollowed)) {
const followed = await this.followingsRepository.findOneBy({ const isFollowed = await this.followingsRepository.exist({
where: {
followerId: followee.id, followerId: followee.id,
followeeId: follower.id, followeeId: follower.id,
},
}); });
if (followed) autoAccept = true; if (isFollowed) autoAccept = true;
} }
// Automatically accept if the follower is an account who has moved and the locked followee had accepted the old account. // Automatically accept if the follower is an account who has moved and the locked followee had accepted the old account.
@ -206,12 +210,14 @@ export class UserFollowingService implements OnModuleInit {
this.cacheService.userFollowingsCache.refresh(follower.id); this.cacheService.userFollowingsCache.refresh(follower.id);
const req = await this.followRequestsRepository.findOneBy({ const requestExist = await this.followRequestsRepository.exist({
where: {
followeeId: followee.id, followeeId: followee.id,
followerId: follower.id, followerId: follower.id,
},
}); });
if (req) { if (requestExist) {
await this.followRequestsRepository.delete({ await this.followRequestsRepository.delete({
followeeId: followee.id, followeeId: followee.id,
followerId: follower.id, followerId: follower.id,
@ -505,12 +511,14 @@ export class UserFollowingService implements OnModuleInit {
} }
} }
const request = await this.followRequestsRepository.findOneBy({ const requestExist = await this.followRequestsRepository.exist({
where: {
followeeId: followee.id, followeeId: followee.id,
followerId: follower.id, followerId: follower.id,
},
}); });
if (request == null) { if (!requestExist) {
throw new IdentifiableError('17447091-ce07-46dd-b331-c1fd4f15b1e7', 'request not found'); throw new IdentifiableError('17447091-ce07-46dd-b331-c1fd4f15b1e7', 'request not found');
} }

View file

@ -618,12 +618,14 @@ export class ApInboxService {
return 'skip: follower not found'; return 'skip: follower not found';
} }
const following = await this.followingsRepository.findOneBy({ const isFollowing = await this.followingsRepository.exist({
where: {
followerId: follower.id, followerId: follower.id,
followeeId: actor.id, followeeId: actor.id,
},
}); });
if (following) { if (isFollowing) {
await this.userFollowingService.unfollow(follower, actor); await this.userFollowingService.unfollow(follower, actor);
return 'ok: unfollowed'; return 'ok: unfollowed';
} }
@ -673,22 +675,26 @@ export class ApInboxService {
return 'skip: フォロー解除しようとしているユーザーはローカルユーザーではありません'; return 'skip: フォロー解除しようとしているユーザーはローカルユーザーではありません';
} }
const req = await this.followRequestsRepository.findOneBy({ const requestExist = await this.followRequestsRepository.exist({
where: {
followerId: actor.id, followerId: actor.id,
followeeId: followee.id, followeeId: followee.id,
},
}); });
const following = await this.followingsRepository.findOneBy({ const isFollowing = await this.followingsRepository.exist({
where: {
followerId: actor.id, followerId: actor.id,
followeeId: followee.id, followeeId: followee.id,
},
}); });
if (req) { if (requestExist) {
await this.userFollowingService.cancelFollowRequest(followee, actor); await this.userFollowingService.cancelFollowRequest(followee, actor);
return 'ok: follow request canceled'; return 'ok: follow request canceled';
} }
if (following) { if (isFollowing) {
await this.userFollowingService.unfollow(actor, followee); await this.userFollowingService.unfollow(actor, followee);
return 'ok: unfollowed'; return 'ok: unfollowed';
} }

View file

@ -323,9 +323,9 @@ export class ApRendererService {
inReplyToNote = await this.notesRepository.findOneBy({ id: note.replyId }); inReplyToNote = await this.notesRepository.findOneBy({ id: note.replyId });
if (inReplyToNote != null) { if (inReplyToNote != null) {
const inReplyToUser = await this.usersRepository.findOneBy({ id: inReplyToNote.userId }); const inReplyToUserExist = await this.usersRepository.exist({ where: { id: inReplyToNote.userId } });
if (inReplyToUser != null) { if (inReplyToUserExist) {
if (inReplyToNote.uri) { if (inReplyToNote.uri) {
inReplyTo = inReplyToNote.uri; inReplyTo = inReplyToNote.uri;
} else { } else {

View file

@ -47,17 +47,26 @@ export class ChannelEntityService {
const banner = channel.bannerId ? await this.driveFilesRepository.findOneBy({ id: channel.bannerId }) : null; const banner = channel.bannerId ? await this.driveFilesRepository.findOneBy({ id: channel.bannerId }) : null;
const hasUnreadNote = meId ? (await this.noteUnreadsRepository.findOneBy({ noteChannelId: channel.id, userId: meId })) != null : undefined; const hasUnreadNote = meId ? await this.noteUnreadsRepository.exist({
where: {
noteChannelId: channel.id,
userId: meId
},
}) : undefined;
const following = meId ? await this.channelFollowingsRepository.findOneBy({ const isFollowing = meId ? await this.channelFollowingsRepository.exist({
where: {
followerId: meId, followerId: meId,
followeeId: channel.id, followeeId: channel.id,
}) : null; },
}) : false;
const favorite = meId ? await this.channelFavoritesRepository.findOneBy({ const isFavorited = meId ? await this.channelFavoritesRepository.exist({
where: {
userId: meId, userId: meId,
channelId: channel.id, channelId: channel.id,
}) : null; },
}) : false;
const pinnedNotes = channel.pinnedNoteIds.length > 0 ? await this.notesRepository.find({ const pinnedNotes = channel.pinnedNoteIds.length > 0 ? await this.notesRepository.find({
where: { where: {
@ -80,8 +89,8 @@ export class ChannelEntityService {
notesCount: channel.notesCount, notesCount: channel.notesCount,
...(me ? { ...(me ? {
isFollowing: following != null, isFollowing,
isFavorited: favorite != null, isFavorited,
hasUnreadNote, hasUnreadNote,
} : {}), } : {}),

View file

@ -39,7 +39,7 @@ export class ClipEntityService {
description: clip.description, description: clip.description,
isPublic: clip.isPublic, isPublic: clip.isPublic,
favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }), favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }),
isFavorited: meId ? await this.clipFavoritesRepository.findOneBy({ clipId: clip.id, userId: meId }).then(x => x != null) : undefined, isFavorited: meId ? await this.clipFavoritesRepository.exist({ where: { clipId: clip.id, userId: meId } }) : undefined,
}); });
} }

View file

@ -40,7 +40,7 @@ export class FlashEntityService {
summary: flash.summary, summary: flash.summary,
script: flash.script, script: flash.script,
likedCount: flash.likedCount, likedCount: flash.likedCount,
isLiked: meId ? await this.flashLikesRepository.findOneBy({ flashId: flash.id, userId: meId }).then(x => x != null) : undefined, isLiked: meId ? await this.flashLikesRepository.exist({ where: { flashId: flash.id, userId: meId } }) : undefined,
}); });
} }

View file

@ -46,7 +46,7 @@ export class GalleryPostEntityService {
tags: post.tags.length > 0 ? post.tags : undefined, tags: post.tags.length > 0 ? post.tags : undefined,
isSensitive: post.isSensitive, isSensitive: post.isSensitive,
likedCount: post.likedCount, likedCount: post.likedCount,
isLiked: meId ? await this.galleryLikesRepository.findOneBy({ postId: post.id, userId: meId }).then(x => x != null) : undefined, isLiked: meId ? await this.galleryLikesRepository.exist({ where: { postId: post.id, userId: meId } }) : undefined,
}); });
} }

View file

@ -106,16 +106,14 @@ export class NoteEntityService implements OnModuleInit {
hide = false; hide = false;
} else { } else {
// フォロワーかどうか // フォロワーかどうか
const following = await this.followingsRepository.findOneBy({ const isFollowing = await this.followingsRepository.exist({
where: {
followeeId: packedNote.userId, followeeId: packedNote.userId,
followerId: meId, followerId: meId,
},
}); });
if (following == null) { hide = !isFollowing;
hide = true;
} else {
hide = false;
}
} }
} }

View file

@ -97,7 +97,7 @@ export class PageEntityService {
eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null, eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null,
attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter((x): x is DriveFile => x != null)), attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter((x): x is DriveFile => x != null)),
likedCount: page.likedCount, likedCount: page.likedCount,
isLiked: meId ? await this.pageLikesRepository.findOneBy({ pageId: page.id, userId: meId }).then(x => x != null) : undefined, isLiked: meId ? await this.pageLikesRepository.exist({ where: { pageId: page.id, userId: meId } }) : undefined,
}); });
} }

View file

@ -230,12 +230,14 @@ export class UserEntityService implements OnModuleInit {
/* /*
const myAntennas = (await this.antennaService.getAntennas()).filter(a => a.userId === userId); const myAntennas = (await this.antennaService.getAntennas()).filter(a => a.userId === userId);
const unread = myAntennas.length > 0 ? await this.antennaNotesRepository.findOneBy({ const isUnread = (myAntennas.length > 0 ? await this.antennaNotesRepository.exist({
where: {
antennaId: In(myAntennas.map(x => x.id)), antennaId: In(myAntennas.map(x => x.id)),
read: false, read: false,
}) : null; },
}) : false);
return unread != null; return isUnread;
*/ */
return false; // TODO return false; // TODO
} }

View file

@ -128,12 +128,12 @@ export class SignupApiService {
} }
if (instance.emailRequiredForSignup) { if (instance.emailRequiredForSignup) {
if (await this.usersRepository.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull() })) { if (await this.usersRepository.exist({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) {
throw new FastifyReplyError(400, 'DUPLICATED_USERNAME'); throw new FastifyReplyError(400, 'DUPLICATED_USERNAME');
} }
// Check deleted username duplication // Check deleted username duplication
if (await this.usedUsernamesRepository.findOneBy({ username: username.toLowerCase() })) { if (await this.usedUsernamesRepository.exist({ where: { username: username.toLowerCase() } })) {
throw new FastifyReplyError(400, 'USED_USERNAME'); throw new FastifyReplyError(400, 'USED_USERNAME');
} }

View file

@ -50,9 +50,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw e; throw e;
}); });
const exist = await this.promoNotesRepository.findOneBy({ noteId: note.id }); const exist = await this.promoNotesRepository.exist({ where: { noteId: note.id } });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyPromoted); throw new ApiError(meta.errors.alreadyPromoted);
} }

View file

@ -69,8 +69,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private globalEventService: GlobalEventService, private globalEventService: GlobalEventService,
) { ) {
super(meta, paramDef, async (ps) => { super(meta, paramDef, async (ps) => {
const role = await this.rolesRepository.findOneBy({ id: ps.roleId }); const roleExist = await this.rolesRepository.exist({ where: { id: ps.roleId } });
if (role == null) { if (!roleExist) {
throw new ApiError(meta.errors.noSuchRole); throw new ApiError(meta.errors.noSuchRole);
} }

View file

@ -58,12 +58,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const accessToken = secureRndstr(32); const accessToken = secureRndstr(32);
// Fetch exist access token // Fetch exist access token
const exist = await this.accessTokensRepository.findOneBy({ const exist = await this.accessTokensRepository.exist({
where: {
appId: session.appId, appId: session.appId,
userId: me.id, userId: me.id,
},
}); });
if (exist == null) { if (!exist) {
const app = await this.appsRepository.findOneByOrFail({ id: session.appId }); const app = await this.appsRepository.findOneByOrFail({ id: session.appId });
// Generate Hash // Generate Hash

View file

@ -84,12 +84,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
// Check if already blocking // Check if already blocking
const exist = await this.blockingsRepository.findOneBy({ const exist = await this.blockingsRepository.exist({
where: {
blockerId: blocker.id, blockerId: blocker.id,
blockeeId: blockee.id, blockeeId: blockee.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyBlocking); throw new ApiError(meta.errors.alreadyBlocking);
} }

View file

@ -84,12 +84,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
// Check not blocking // Check not blocking
const exist = await this.blockingsRepository.findOneBy({ const exist = await this.blockingsRepository.exist({
where: {
blockerId: blocker.id, blockerId: blocker.id,
blockeeId: blockee.id, blockeeId: blockee.id,
}
}); });
if (exist == null) { if (!exist) {
throw new ApiError(meta.errors.notBlocking); throw new ApiError(meta.errors.notBlocking);
} }

View file

@ -87,12 +87,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw e; throw e;
}); });
const exist = await this.clipNotesRepository.findOneBy({ const exist = await this.clipNotesRepository.exist({
where: {
noteId: note.id, noteId: note.id,
clipId: clip.id, clipId: clip.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyClipped); throw new ApiError(meta.errors.alreadyClipped);
} }

View file

@ -58,12 +58,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new ApiError(meta.errors.noSuchClip); throw new ApiError(meta.errors.noSuchClip);
} }
const exist = await this.clipFavoritesRepository.findOneBy({ const exist = await this.clipFavoritesRepository.exist({
where: {
clipId: clip.id, clipId: clip.id,
userId: me.id, userId: me.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyFavorited); throw new ApiError(meta.errors.alreadyFavorited);
} }

View file

@ -34,12 +34,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private driveFilesRepository: DriveFilesRepository, private driveFilesRepository: DriveFilesRepository,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const file = await this.driveFilesRepository.findOneBy({ const exist = await this.driveFilesRepository.exist({
where: {
md5: ps.md5, md5: ps.md5,
userId: me.id, userId: me.id,
},
}); });
return file != null; return exist;
}); });
} }
} }

View file

@ -66,12 +66,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
} }
// if already liked // if already liked
const exist = await this.flashLikesRepository.findOneBy({ const exist = await this.flashLikesRepository.exist({
where: {
flashId: flash.id, flashId: flash.id,
userId: me.id, userId: me.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyLiked); throw new ApiError(meta.errors.alreadyLiked);
} }

View file

@ -99,12 +99,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
// Check if already following // Check if already following
const exist = await this.followingsRepository.findOneBy({ const exist = await this.followingsRepository.exist({
where: {
followerId: follower.id, followerId: follower.id,
followeeId: followee.id, followeeId: followee.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyFollowing); throw new ApiError(meta.errors.alreadyFollowing);
} }

View file

@ -84,12 +84,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
// Check not following // Check not following
const exist = await this.followingsRepository.findOneBy({ const exist = await this.followingsRepository.exist({
where: {
followerId: follower.id, followerId: follower.id,
followeeId: followee.id, followeeId: followee.id,
},
}); });
if (exist == null) { if (!exist) {
throw new ApiError(meta.errors.notFollowing); throw new ApiError(meta.errors.notFollowing);
} }

View file

@ -66,12 +66,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
} }
// if already liked // if already liked
const exist = await this.galleryLikesRepository.findOneBy({ const exist = await this.galleryLikesRepository.exist({
where: {
postId: post.id, postId: post.id,
userId: me.id, userId: me.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyLiked); throw new ApiError(meta.errors.alreadyLiked);
} }

View file

@ -66,8 +66,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private downloadService: DownloadService, private downloadService: DownloadService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const users = await this.usersRepository.findOneBy({ id: me.id }); const userExist = await this.usersRepository.exist({ where: { id: me.id } });
if (users === null) throw new ApiError(meta.errors.noSuchUser); if (!userExist) throw new ApiError(meta.errors.noSuchUser);
const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
if (file === null) throw new ApiError(meta.errors.noSuchFile); if (file === null) throw new ApiError(meta.errors.noSuchFile);
if (file.size === 0) throw new ApiError(meta.errors.emptyFile); if (file.size === 0) throw new ApiError(meta.errors.emptyFile);

View file

@ -47,19 +47,21 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
// Check if announcement exists // Check if announcement exists
const announcement = await this.announcementsRepository.findOneBy({ id: ps.announcementId }); const announcementExist = await this.announcementsRepository.exist({ where: { id: ps.announcementId } });
if (announcement == null) { if (!announcementExist) {
throw new ApiError(meta.errors.noSuchAnnouncement); throw new ApiError(meta.errors.noSuchAnnouncement);
} }
// Check if already read // Check if already read
const read = await this.announcementReadsRepository.findOneBy({ const alreadyRead = await this.announcementReadsRepository.exist({
where: {
announcementId: ps.announcementId, announcementId: ps.announcementId,
userId: me.id, userId: me.id,
},
}); });
if (read != null) { if (alreadyRead) {
return; return;
} }

View file

@ -28,9 +28,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private globalEventService: GlobalEventService, private globalEventService: GlobalEventService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const token = await this.accessTokensRepository.findOneBy({ id: ps.tokenId }); const tokenExist = await this.accessTokensRepository.exist({ where: { id: ps.tokenId } });
if (token) { if (tokenExist) {
await this.accessTokensRepository.delete({ await this.accessTokensRepository.delete({
id: ps.tokenId, id: ps.tokenId,
userId: me.id, userId: me.id,

View file

@ -79,12 +79,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
// Check if already muting // Check if already muting
const exist = await this.mutingsRepository.findOneBy({ const exist = await this.mutingsRepository.exist({
where: {
muterId: muter.id, muterId: muter.id,
muteeId: mutee.id, muteeId: mutee.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyMuting); throw new ApiError(meta.errors.alreadyMuting);
} }

View file

@ -217,11 +217,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Check blocking // Check blocking
if (renote.userId !== me.id) { if (renote.userId !== me.id) {
const block = await this.blockingsRepository.findOneBy({ const blockExist = await this.blockingsRepository.exist({
where: {
blockerId: renote.userId, blockerId: renote.userId,
blockeeId: me.id, blockeeId: me.id,
},
}); });
if (block) { if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked); throw new ApiError(meta.errors.youHaveBeenBlocked);
} }
} }
@ -240,11 +242,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Check blocking // Check blocking
if (reply.userId !== me.id) { if (reply.userId !== me.id) {
const block = await this.blockingsRepository.findOneBy({ const blockExist = await this.blockingsRepository.exist({
where: {
blockerId: reply.userId, blockerId: reply.userId,
blockeeId: me.id, blockeeId: me.id,
},
}); });
if (block) { if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked); throw new ApiError(meta.errors.youHaveBeenBlocked);
} }
} }

View file

@ -63,12 +63,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
// if already favorited // if already favorited
const exist = await this.noteFavoritesRepository.findOneBy({ const exist = await this.noteFavoritesRepository.exist({
where: {
noteId: note.id, noteId: note.id,
userId: me.id, userId: me.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyFavorited); throw new ApiError(meta.errors.alreadyFavorited);
} }

View file

@ -66,12 +66,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
} }
// if already liked // if already liked
const exist = await this.pageLikesRepository.findOneBy({ const exist = await this.pageLikesRepository.exist({
where: {
pageId: page.id, pageId: page.id,
userId: me.id, userId: me.id,
},
}); });
if (exist != null) { if (exist) {
throw new ApiError(meta.errors.alreadyLiked); throw new ApiError(meta.errors.alreadyLiked);
} }

View file

@ -44,12 +44,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw err; throw err;
}); });
const exist = await this.promoReadsRepository.findOneBy({ const exist = await this.promoReadsRepository.exist({
where: {
noteId: note.id, noteId: note.id,
userId: me.id, userId: me.id,
},
}); });
if (exist != null) { if (exist) {
return; return;
} }

View file

@ -97,11 +97,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (me == null) { if (me == null) {
throw new ApiError(meta.errors.forbidden); throw new ApiError(meta.errors.forbidden);
} else if (me.id !== user.id) { } else if (me.id !== user.id) {
const following = await this.followingsRepository.findOneBy({ const isFollowing = await this.followingsRepository.exist({
where: {
followeeId: user.id, followeeId: user.id,
followerId: me.id, followerId: me.id,
},
}); });
if (following == null) { if (!isFollowing) {
throw new ApiError(meta.errors.forbidden); throw new ApiError(meta.errors.forbidden);
} }
} }

View file

@ -97,11 +97,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (me == null) { if (me == null) {
throw new ApiError(meta.errors.forbidden); throw new ApiError(meta.errors.forbidden);
} else if (me.id !== user.id) { } else if (me.id !== user.id) {
const following = await this.followingsRepository.findOneBy({ const isFollowing = await this.followingsRepository.exist({
where: {
followeeId: user.id, followeeId: user.id,
followerId: me.id, followerId: me.id,
},
}); });
if (following == null) { if (!isFollowing) {
throw new ApiError(meta.errors.forbidden); throw new ApiError(meta.errors.forbidden);
} }
} }

View file

@ -84,11 +84,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private roleService: RoleService, private roleService: RoleService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const list = await this.userListsRepository.findOneBy({ const listExist = await this.userListsRepository.exist({
where: {
id: ps.listId, id: ps.listId,
isPublic: true, isPublic: true,
},
}); });
if (list === null) throw new ApiError(meta.errors.noSuchList); if (!listExist) throw new ApiError(meta.errors.noSuchList);
const currentCount = await this.userListsRepository.countBy({ const currentCount = await this.userListsRepository.countBy({
userId: me.id, userId: me.id,
}); });
@ -114,18 +116,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
if (currentUser.id !== me.id) { if (currentUser.id !== me.id) {
const block = await this.blockingsRepository.findOneBy({ const blockExist = await this.blockingsRepository.exist({
where: {
blockerId: currentUser.id, blockerId: currentUser.id,
blockeeId: me.id, blockeeId: me.id,
},
}); });
if (block) { if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked); throw new ApiError(meta.errors.youHaveBeenBlocked);
} }
} }
const exist = await this.userListJoiningsRepository.findOneBy({ const exist = await this.userListJoiningsRepository.exist({
where: {
userListId: userList.id, userListId: userList.id,
userId: currentUser.id, userId: currentUser.id,
},
}); });
if (exist) { if (exist) {

View file

@ -41,21 +41,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private idService: IdService, private idService: IdService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const userList = await this.userListsRepository.findOneBy({ const userListExist = await this.userListsRepository.exist({
where: {
id: ps.listId, id: ps.listId,
isPublic: true, isPublic: true,
},
}); });
if (userList === null) { if (!userListExist) {
throw new ApiError(meta.errors.noSuchList); throw new ApiError(meta.errors.noSuchList);
} }
const exist = await this.userListFavoritesRepository.findOneBy({ const exist = await this.userListFavoritesRepository.exist({
where: {
userId: me.id, userId: me.id,
userListId: ps.listId, userListId: ps.listId,
},
}); });
if (exist !== null) { if (exist) {
throw new ApiError(meta.errors.alreadyFavorited); throw new ApiError(meta.errors.alreadyFavorited);
} }

View file

@ -100,18 +100,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Check blocking // Check blocking
if (user.id !== me.id) { if (user.id !== me.id) {
const block = await this.blockingsRepository.findOneBy({ const blockExist = await this.blockingsRepository.exist({
where: {
blockerId: user.id, blockerId: user.id,
blockeeId: me.id, blockeeId: me.id,
},
}); });
if (block) { if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked); throw new ApiError(meta.errors.youHaveBeenBlocked);
} }
} }
const exist = await this.userListJoiningsRepository.findOneBy({ const exist = await this.userListJoiningsRepository.exist({
where: {
userListId: userList.id, userListId: userList.id,
userId: user.id, userId: user.id,
},
}); });
if (exist) { if (exist) {

View file

@ -69,10 +69,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
userListId: ps.listId, userListId: ps.listId,
}); });
if (me !== null) { if (me !== null) {
additionalProperties.isLiked = (await this.userListFavoritesRepository.findOneBy({ additionalProperties.isLiked = await this.userListFavoritesRepository.exist({
where: {
userId: me.id, userId: me.id,
userListId: ps.listId, userListId: ps.listId,
}) !== null); },
});
} else { } else {
additionalProperties.isLiked = false; additionalProperties.isLiked = false;
} }

View file

@ -39,12 +39,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private userListFavoritesRepository: UserListFavoritesRepository, private userListFavoritesRepository: UserListFavoritesRepository,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const userList = await this.userListsRepository.findOneBy({ const userListExist = await this.userListsRepository.exist({
where: {
id: ps.listId, id: ps.listId,
isPublic: true, isPublic: true,
},
}); });
if (userList === null) { if (!userListExist) {
throw new ApiError(meta.errors.noSuchList); throw new ApiError(meta.errors.noSuchList);
} }

View file

@ -34,11 +34,13 @@ class UserListChannel extends Channel {
this.listId = params.listId as string; this.listId = params.listId as string;
// Check existence and owner // Check existence and owner
const list = await this.userListsRepository.findOneBy({ const listExist = await this.userListsRepository.exist({
where: {
id: this.listId, id: this.listId,
userId: this.user!.id, userId: this.user!.id,
},
}); });
if (!list) return; if (!listExist) return;
// Subscribe stream // Subscribe stream
this.subscriber.on(`userListStream:${this.listId}`, this.send); this.subscriber.on(`userListStream:${this.listId}`, this.send);

View file

@ -1,5 +1,5 @@
import { writeFile } from 'node:fs/promises'; import { writeFile } from 'node:fs/promises';
import * as locales from '../../../locales/index.js'; import locales from '../../../locales/index.js';
await writeFile( await writeFile(
new URL('locale.ts', import.meta.url), new URL('locale.ts', import.meta.url),

View file

@ -29,11 +29,11 @@ export const Default = {
const canvas = within(canvasElement); const canvas = within(canvasElement);
const a = canvas.getByRole<HTMLAnchorElement>('link'); const a = canvas.getByRole<HTMLAnchorElement>('link');
await expect(a.href).toMatch(/^https?:\/\/.*#test$/); await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
await userEvent.click(a, { button: 2 }); await userEvent.pointer({ keys: '[MouseRight]', target: a });
await tick(); await tick();
const menu = canvas.getByRole('menu'); const menu = canvas.getByRole('menu');
await expect(menu).toBeInTheDocument(); await expect(menu).toBeInTheDocument();
await userEvent.click(a, { button: 0 }); await userEvent.click(a);
a.blur(); a.blur();
await tick(); await tick();
await expect(menu).not.toBeInTheDocument(); await expect(menu).not.toBeInTheDocument();

View file

@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/explicit-function-return-type */
import { expect } from '@storybook/jest'; import { expect } from '@storybook/jest';
import { userEvent, within } from '@storybook/testing-library'; import { userEvent, waitFor, within } from '@storybook/testing-library';
import { StoryObj } from '@storybook/vue3'; import { StoryObj } from '@storybook/vue3';
import { i18n } from '@/i18n';
import MkAd from './MkAd.vue'; import MkAd from './MkAd.vue';
import { i18n } from '@/i18n';
const common = { const common = {
render(args) { render(args) {
return { return {
@ -36,6 +36,7 @@ const common = {
const i = buttons[0]; const i = buttons[0];
await expect(i).toBeInTheDocument(); await expect(i).toBeInTheDocument();
await userEvent.click(i); await userEvent.click(i);
await waitFor(() => expect(canvasElement).toHaveTextContent(i18n.ts._ad.back));
await expect(a).not.toBeInTheDocument(); await expect(a).not.toBeInTheDocument();
await expect(i).not.toBeInTheDocument(); await expect(i).not.toBeInTheDocument();
buttons = canvas.getAllByRole<HTMLButtonElement>('button'); buttons = canvas.getAllByRole<HTMLButtonElement>('button');
@ -49,6 +50,7 @@ const common = {
await expect(back).toBeInTheDocument(); await expect(back).toBeInTheDocument();
await expect(back).toHaveTextContent(i18n.ts._ad.back); await expect(back).toHaveTextContent(i18n.ts._ad.back);
await userEvent.click(back); await userEvent.click(back);
await waitFor(() => expect(canvas.queryByRole('img')).toBeTruthy());
if (reduce) { if (reduce) {
await expect(reduce).not.toBeInTheDocument(); await expect(reduce).not.toBeInTheDocument();
} }

View file

@ -18,7 +18,7 @@
<MkButton inline @click="setTagBulk">Set tag</MkButton> <MkButton inline @click="setTagBulk">Set tag</MkButton>
<MkButton inline @click="addTagBulk">Add tag</MkButton> <MkButton inline @click="addTagBulk">Add tag</MkButton>
<MkButton inline @click="removeTagBulk">Remove tag</MkButton> <MkButton inline @click="removeTagBulk">Remove tag</MkButton>
<MkButton inline @click="setLisenceBulk">Set Lisence</MkButton> <MkButton inline @click="setLicenseBulk">Set License</MkButton>
<MkButton inline danger @click="delBulk">Delete</MkButton> <MkButton inline danger @click="delBulk">Delete</MkButton>
</div> </div>
<MkPagination ref="emojisPaginationComponent" :pagination="pagination"> <MkPagination ref="emojisPaginationComponent" :pagination="pagination">
@ -221,7 +221,7 @@ const setCategoryBulk = async () => {
emojisPaginationComponent.value.reload(); emojisPaginationComponent.value.reload();
}; };
const setLisenceBulk = async () => { const setLicenseBulk = async () => {
const { canceled, result } = await os.inputText({ const { canceled, result } = await os.inputText({
title: 'License', title: 'License',
}); });

View file

@ -21,6 +21,10 @@ globalThis.addEventListener('activate', ev => {
); );
}); });
function offlineContentHTML(): string {
return `<!doctype html>Offline. Service Worker @${_VERSION_} <button onclick="location.reload()">reload</button>`
}
globalThis.addEventListener('fetch', ev => { globalThis.addEventListener('fetch', ev => {
let isHTMLRequest = false; let isHTMLRequest = false;
if (ev.request.headers.get('sec-fetch-dest') === 'document') { if (ev.request.headers.get('sec-fetch-dest') === 'document') {
@ -34,7 +38,14 @@ globalThis.addEventListener('fetch', ev => {
if (!isHTMLRequest) return; if (!isHTMLRequest) return;
ev.respondWith( ev.respondWith(
fetch(ev.request) fetch(ev.request)
.catch(() => new Response(`Offline. Service Worker @${_VERSION_}`, { status: 200 })), .catch(() => {
return new Response(offlineContentHTML(), {
status: 200,
headers: {
'content-type': 'text/html',
},
});
}),
); );
}); });