Merge remote-tracking branch 'misskey-original/develop' into develop
# Conflicts: # package.json # packages/frontend/package.json # packages/frontend/src/components/MkMention.vue # packages/frontend/src/components/global/MkAvatar.vue # packages/frontend/src/pages/settings/general.vue
This commit is contained in:
commit
366ea80a06
68 changed files with 2748 additions and 655 deletions
|
|
@ -18,6 +18,10 @@ import * as ep___admin_announcements_create from './endpoints/admin/announcement
|
|||
import * as ep___admin_announcements_delete from './endpoints/admin/announcements/delete.js';
|
||||
import * as ep___admin_announcements_list from './endpoints/admin/announcements/list.js';
|
||||
import * as ep___admin_announcements_update from './endpoints/admin/announcements/update.js';
|
||||
import * as ep___admin_avatarDecorations_create from './endpoints/admin/avatar-decorations/create.js';
|
||||
import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-decorations/delete.js';
|
||||
import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js';
|
||||
import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js';
|
||||
import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js';
|
||||
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
|
||||
import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js';
|
||||
|
|
@ -164,6 +168,7 @@ import * as ep___federation_stats from './endpoints/federation/stats.js';
|
|||
import * as ep___following_create from './endpoints/following/create.js';
|
||||
import * as ep___following_delete from './endpoints/following/delete.js';
|
||||
import * as ep___following_update from './endpoints/following/update.js';
|
||||
import * as ep___following_update_all from './endpoints/following/update-all.js';
|
||||
import * as ep___following_invalidate from './endpoints/following/invalidate.js';
|
||||
import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
|
||||
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
|
||||
|
|
@ -179,6 +184,7 @@ import * as ep___gallery_posts_show from './endpoints/gallery/posts/show.js';
|
|||
import * as ep___gallery_posts_unlike from './endpoints/gallery/posts/unlike.js';
|
||||
import * as ep___gallery_posts_update from './endpoints/gallery/posts/update.js';
|
||||
import * as ep___getOnlineUsersCount from './endpoints/get-online-users-count.js';
|
||||
import * as ep___getAvatarDecorations from './endpoints/get-avatar-decorations.js';
|
||||
import * as ep___hashtags_list from './endpoints/hashtags/list.js';
|
||||
import * as ep___hashtags_search from './endpoints/hashtags/search.js';
|
||||
import * as ep___hashtags_show from './endpoints/hashtags/show.js';
|
||||
|
|
@ -356,6 +362,7 @@ import * as ep___users_show from './endpoints/users/show.js';
|
|||
import * as ep___users_achievements from './endpoints/users/achievements.js';
|
||||
import * as ep___users_updateMemo from './endpoints/users/update-memo.js';
|
||||
import * as ep___fetchRss from './endpoints/fetch-rss.js';
|
||||
import * as ep___fetchExternalResources from './endpoints/fetch-external-resources.js';
|
||||
import * as ep___retention from './endpoints/retention.js';
|
||||
import { GetterService } from './GetterService.js';
|
||||
import { ApiLoggerService } from './ApiLoggerService.js';
|
||||
|
|
@ -373,6 +380,10 @@ const $admin_announcements_create: Provider = { provide: 'ep:admin/announcements
|
|||
const $admin_announcements_delete: Provider = { provide: 'ep:admin/announcements/delete', useClass: ep___admin_announcements_delete.default };
|
||||
const $admin_announcements_list: Provider = { provide: 'ep:admin/announcements/list', useClass: ep___admin_announcements_list.default };
|
||||
const $admin_announcements_update: Provider = { provide: 'ep:admin/announcements/update', useClass: ep___admin_announcements_update.default };
|
||||
const $admin_avatarDecorations_create: Provider = { provide: 'ep:admin/avatar-decorations/create', useClass: ep___admin_avatarDecorations_create.default };
|
||||
const $admin_avatarDecorations_delete: Provider = { provide: 'ep:admin/avatar-decorations/delete', useClass: ep___admin_avatarDecorations_delete.default };
|
||||
const $admin_avatarDecorations_list: Provider = { provide: 'ep:admin/avatar-decorations/list', useClass: ep___admin_avatarDecorations_list.default };
|
||||
const $admin_avatarDecorations_update: Provider = { provide: 'ep:admin/avatar-decorations/update', useClass: ep___admin_avatarDecorations_update.default };
|
||||
const $admin_deleteAllFilesOfAUser: Provider = { provide: 'ep:admin/delete-all-files-of-a-user', useClass: ep___admin_deleteAllFilesOfAUser.default };
|
||||
const $admin_drive_cleanRemoteFiles: Provider = { provide: 'ep:admin/drive/clean-remote-files', useClass: ep___admin_drive_cleanRemoteFiles.default };
|
||||
const $admin_drive_cleanup: Provider = { provide: 'ep:admin/drive/cleanup', useClass: ep___admin_drive_cleanup.default };
|
||||
|
|
@ -519,6 +530,7 @@ const $federation_stats: Provider = { provide: 'ep:federation/stats', useClass:
|
|||
const $following_create: Provider = { provide: 'ep:following/create', useClass: ep___following_create.default };
|
||||
const $following_delete: Provider = { provide: 'ep:following/delete', useClass: ep___following_delete.default };
|
||||
const $following_update: Provider = { provide: 'ep:following/update', useClass: ep___following_update.default };
|
||||
const $following_update_all: Provider = { provide: 'ep:following/update-all', useClass: ep___following_update_all.default };
|
||||
const $following_invalidate: Provider = { provide: 'ep:following/invalidate', useClass: ep___following_invalidate.default };
|
||||
const $following_requests_accept: Provider = { provide: 'ep:following/requests/accept', useClass: ep___following_requests_accept.default };
|
||||
const $following_requests_cancel: Provider = { provide: 'ep:following/requests/cancel', useClass: ep___following_requests_cancel.default };
|
||||
|
|
@ -534,6 +546,7 @@ const $gallery_posts_show: Provider = { provide: 'ep:gallery/posts/show', useCla
|
|||
const $gallery_posts_unlike: Provider = { provide: 'ep:gallery/posts/unlike', useClass: ep___gallery_posts_unlike.default };
|
||||
const $gallery_posts_update: Provider = { provide: 'ep:gallery/posts/update', useClass: ep___gallery_posts_update.default };
|
||||
const $getOnlineUsersCount: Provider = { provide: 'ep:get-online-users-count', useClass: ep___getOnlineUsersCount.default };
|
||||
const $getAvatarDecorations: Provider = { provide: 'ep:get-avatar-decorations', useClass: ep___getAvatarDecorations.default };
|
||||
const $hashtags_list: Provider = { provide: 'ep:hashtags/list', useClass: ep___hashtags_list.default };
|
||||
const $hashtags_search: Provider = { provide: 'ep:hashtags/search', useClass: ep___hashtags_search.default };
|
||||
const $hashtags_show: Provider = { provide: 'ep:hashtags/show', useClass: ep___hashtags_show.default };
|
||||
|
|
@ -711,6 +724,7 @@ const $users_show: Provider = { provide: 'ep:users/show', useClass: ep___users_s
|
|||
const $users_achievements: Provider = { provide: 'ep:users/achievements', useClass: ep___users_achievements.default };
|
||||
const $users_updateMemo: Provider = { provide: 'ep:users/update-memo', useClass: ep___users_updateMemo.default };
|
||||
const $fetchRss: Provider = { provide: 'ep:fetch-rss', useClass: ep___fetchRss.default };
|
||||
const $fetchExternalResources: Provider = { provide: 'ep:fetch-external-resources', useClass: ep___fetchExternalResources.default };
|
||||
const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention.default };
|
||||
|
||||
@Module({
|
||||
|
|
@ -732,6 +746,10 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$admin_announcements_delete,
|
||||
$admin_announcements_list,
|
||||
$admin_announcements_update,
|
||||
$admin_avatarDecorations_create,
|
||||
$admin_avatarDecorations_delete,
|
||||
$admin_avatarDecorations_list,
|
||||
$admin_avatarDecorations_update,
|
||||
$admin_deleteAllFilesOfAUser,
|
||||
$admin_drive_cleanRemoteFiles,
|
||||
$admin_drive_cleanup,
|
||||
|
|
@ -879,6 +897,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$following_create,
|
||||
$following_delete,
|
||||
$following_update,
|
||||
$following_update_all,
|
||||
$following_invalidate,
|
||||
$following_requests_accept,
|
||||
$following_requests_cancel,
|
||||
|
|
@ -894,6 +913,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$gallery_posts_unlike,
|
||||
$gallery_posts_update,
|
||||
$getOnlineUsersCount,
|
||||
$getAvatarDecorations,
|
||||
$hashtags_list,
|
||||
$hashtags_search,
|
||||
$hashtags_show,
|
||||
|
|
@ -1070,6 +1090,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$users_achievements,
|
||||
$users_updateMemo,
|
||||
$fetchRss,
|
||||
$fetchExternalResources,
|
||||
$retention,
|
||||
],
|
||||
exports: [
|
||||
|
|
@ -1085,6 +1106,10 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$admin_announcements_delete,
|
||||
$admin_announcements_list,
|
||||
$admin_announcements_update,
|
||||
$admin_avatarDecorations_create,
|
||||
$admin_avatarDecorations_delete,
|
||||
$admin_avatarDecorations_list,
|
||||
$admin_avatarDecorations_update,
|
||||
$admin_deleteAllFilesOfAUser,
|
||||
$admin_drive_cleanRemoteFiles,
|
||||
$admin_drive_cleanup,
|
||||
|
|
@ -1232,6 +1257,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$following_create,
|
||||
$following_delete,
|
||||
$following_update,
|
||||
$following_update_all,
|
||||
$following_invalidate,
|
||||
$following_requests_accept,
|
||||
$following_requests_cancel,
|
||||
|
|
@ -1247,6 +1273,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$gallery_posts_unlike,
|
||||
$gallery_posts_update,
|
||||
$getOnlineUsersCount,
|
||||
$getAvatarDecorations,
|
||||
$hashtags_list,
|
||||
$hashtags_search,
|
||||
$hashtags_show,
|
||||
|
|
@ -1420,6 +1447,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$users_achievements,
|
||||
$users_updateMemo,
|
||||
$fetchRss,
|
||||
$fetchExternalResources,
|
||||
$retention,
|
||||
],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ import * as ep___admin_announcements_create from './endpoints/admin/announcement
|
|||
import * as ep___admin_announcements_delete from './endpoints/admin/announcements/delete.js';
|
||||
import * as ep___admin_announcements_list from './endpoints/admin/announcements/list.js';
|
||||
import * as ep___admin_announcements_update from './endpoints/admin/announcements/update.js';
|
||||
import * as ep___admin_avatarDecorations_create from './endpoints/admin/avatar-decorations/create.js';
|
||||
import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-decorations/delete.js';
|
||||
import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js';
|
||||
import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js';
|
||||
import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js';
|
||||
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
|
||||
import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js';
|
||||
|
|
@ -163,6 +167,7 @@ import * as ep___federation_stats from './endpoints/federation/stats.js';
|
|||
import * as ep___following_create from './endpoints/following/create.js';
|
||||
import * as ep___following_delete from './endpoints/following/delete.js';
|
||||
import * as ep___following_update from './endpoints/following/update.js';
|
||||
import * as ep___following_update_all from './endpoints/following/update-all.js';
|
||||
import * as ep___following_invalidate from './endpoints/following/invalidate.js';
|
||||
import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
|
||||
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
|
||||
|
|
@ -178,6 +183,7 @@ import * as ep___gallery_posts_show from './endpoints/gallery/posts/show.js';
|
|||
import * as ep___gallery_posts_unlike from './endpoints/gallery/posts/unlike.js';
|
||||
import * as ep___gallery_posts_update from './endpoints/gallery/posts/update.js';
|
||||
import * as ep___getOnlineUsersCount from './endpoints/get-online-users-count.js';
|
||||
import * as ep___getAvatarDecorations from './endpoints/get-avatar-decorations.js';
|
||||
import * as ep___hashtags_list from './endpoints/hashtags/list.js';
|
||||
import * as ep___hashtags_search from './endpoints/hashtags/search.js';
|
||||
import * as ep___hashtags_show from './endpoints/hashtags/show.js';
|
||||
|
|
@ -355,6 +361,7 @@ import * as ep___users_show from './endpoints/users/show.js';
|
|||
import * as ep___users_achievements from './endpoints/users/achievements.js';
|
||||
import * as ep___users_updateMemo from './endpoints/users/update-memo.js';
|
||||
import * as ep___fetchRss from './endpoints/fetch-rss.js';
|
||||
import * as ep___fetchExternalResources from './endpoints/fetch-external-resources.js';
|
||||
import * as ep___retention from './endpoints/retention.js';
|
||||
|
||||
const eps = [
|
||||
|
|
@ -370,6 +377,10 @@ const eps = [
|
|||
['admin/announcements/delete', ep___admin_announcements_delete],
|
||||
['admin/announcements/list', ep___admin_announcements_list],
|
||||
['admin/announcements/update', ep___admin_announcements_update],
|
||||
['admin/avatar-decorations/create', ep___admin_avatarDecorations_create],
|
||||
['admin/avatar-decorations/delete', ep___admin_avatarDecorations_delete],
|
||||
['admin/avatar-decorations/list', ep___admin_avatarDecorations_list],
|
||||
['admin/avatar-decorations/update', ep___admin_avatarDecorations_update],
|
||||
['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser],
|
||||
['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles],
|
||||
['admin/drive/cleanup', ep___admin_drive_cleanup],
|
||||
|
|
@ -516,6 +527,7 @@ const eps = [
|
|||
['following/create', ep___following_create],
|
||||
['following/delete', ep___following_delete],
|
||||
['following/update', ep___following_update],
|
||||
['following/update-all', ep___following_update_all],
|
||||
['following/invalidate', ep___following_invalidate],
|
||||
['following/requests/accept', ep___following_requests_accept],
|
||||
['following/requests/cancel', ep___following_requests_cancel],
|
||||
|
|
@ -531,6 +543,7 @@ const eps = [
|
|||
['gallery/posts/unlike', ep___gallery_posts_unlike],
|
||||
['gallery/posts/update', ep___gallery_posts_update],
|
||||
['get-online-users-count', ep___getOnlineUsersCount],
|
||||
['get-avatar-decorations', ep___getAvatarDecorations],
|
||||
['hashtags/list', ep___hashtags_list],
|
||||
['hashtags/search', ep___hashtags_search],
|
||||
['hashtags/show', ep___hashtags_show],
|
||||
|
|
@ -708,6 +721,7 @@ const eps = [
|
|||
['users/achievements', ep___users_achievements],
|
||||
['users/update-memo', ep___users_updateMemo],
|
||||
['fetch-rss', ep___fetchRss],
|
||||
['fetch-external-resources', ep___fetchExternalResources],
|
||||
['retention', ep___retention],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', minLength: 1 },
|
||||
description: { type: 'string' },
|
||||
url: { type: 'string', minLength: 1 },
|
||||
roleIdsThatCanBeUsedThisDecoration: { type: 'array', items: {
|
||||
type: 'string',
|
||||
} },
|
||||
},
|
||||
required: ['name', 'description', 'url'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private avatarDecorationService: AvatarDecorationService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
await this.avatarDecorationService.create({
|
||||
name: ps.name,
|
||||
description: ps.description,
|
||||
url: ps.url,
|
||||
roleIdsThatCanBeUsedThisDecoration: ps.roleIdsThatCanBeUsedThisDecoration,
|
||||
}, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['id'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private avatarDecorationService: AvatarDecorationService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
await this.avatarDecorationService.delete(ps.id, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { AnnouncementsRepository, AnnouncementReadsRepository } from '@/models/_.js';
|
||||
import type { MiAnnouncement } from '@/models/Announcement.js';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'date-time',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
roleIdsThatCanBeUsedThisDecoration: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} 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' },
|
||||
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private avatarDecorationService: AvatarDecorationService,
|
||||
private idService: IdService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const avatarDecorations = await this.avatarDecorationService.getAll(true);
|
||||
|
||||
return avatarDecorations.map(avatarDecoration => ({
|
||||
id: avatarDecoration.id,
|
||||
createdAt: this.idService.parse(avatarDecoration.id).date.toISOString(),
|
||||
updatedAt: avatarDecoration.updatedAt?.toISOString() ?? null,
|
||||
name: avatarDecoration.name,
|
||||
description: avatarDecoration.description,
|
||||
url: avatarDecoration.url,
|
||||
roleIdsThatCanBeUsedThisDecoration: avatarDecoration.roleIdsThatCanBeUsedThisDecoration,
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
name: { type: 'string', minLength: 1 },
|
||||
description: { type: 'string' },
|
||||
url: { type: 'string', minLength: 1 },
|
||||
roleIdsThatCanBeUsedThisDecoration: { type: 'array', items: {
|
||||
type: 'string',
|
||||
} },
|
||||
},
|
||||
required: ['id'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private avatarDecorationService: AvatarDecorationService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
await this.avatarDecorationService.update(ps.id, {
|
||||
name: ps.name,
|
||||
description: ps.description,
|
||||
url: ps.url,
|
||||
roleIdsThatCanBeUsedThisDecoration: ps.roleIdsThatCanBeUsedThisDecoration,
|
||||
}, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { createHash } from 'crypto';
|
||||
import ms from 'ms';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { ApiError } from '../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['meta'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
max: 50,
|
||||
},
|
||||
|
||||
errors: {
|
||||
invalidSchema: {
|
||||
message: 'External resource returned invalid schema.',
|
||||
code: 'EXT_RESOURCE_RETURNED_INVALID_SCHEMA',
|
||||
id: 'bb774091-7a15-4a70-9dc5-6ac8cf125856',
|
||||
},
|
||||
hashUnmached: {
|
||||
message: 'Hash did not match.',
|
||||
code: 'EXT_RESOURCE_HASH_DIDNT_MATCH',
|
||||
id: '693ba8ba-b486-40df-a174-72f8279b56a4',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: { type: 'string' },
|
||||
hash: { type: 'string' },
|
||||
},
|
||||
required: ['url', 'hash'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private httpRequestService: HttpRequestService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps) => {
|
||||
const res = await this.httpRequestService.getJson<{
|
||||
type: string;
|
||||
data: string;
|
||||
}>(ps.url);
|
||||
|
||||
if (!res.data || !res.type) {
|
||||
throw new ApiError(meta.errors.invalidSchema);
|
||||
}
|
||||
|
||||
const resHash = createHash('sha512').update(res.data.replace(/\r\n/g, '\n')).digest('hex');
|
||||
if (resHash !== ps.hash) {
|
||||
throw new ApiError(meta.errors.hashUnmached);
|
||||
}
|
||||
|
||||
return {
|
||||
type: res.type,
|
||||
data: res.data,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import ms from 'ms';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import type { FollowingsRepository } from '@/models/_.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { GetterService } from '@/server/api/GetterService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['following', 'users'],
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
max: 10,
|
||||
},
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:following',
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
notify: { type: 'string', enum: ['normal', 'none'] },
|
||||
withReplies: { type: 'boolean' },
|
||||
},
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
@Inject(DI.followingsRepository)
|
||||
private followingsRepository: FollowingsRepository,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
await this.followingsRepository.update({
|
||||
followerId: me.id,
|
||||
}, {
|
||||
notify: ps.notify != null ? (ps.notify === 'none' ? null : ps.notify) : undefined,
|
||||
withReplies: ps.withReplies != null ? ps.withReplies : undefined,
|
||||
});
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { IsNull } from 'typeorm';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['users'],
|
||||
|
||||
requireCredential: false,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
roleIdsThatCanBeUsedThisDecoration: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private avatarDecorationService: AvatarDecorationService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const decorations = await this.avatarDecorationService.getAll(true);
|
||||
|
||||
return decorations.map(decoration => ({
|
||||
id: decoration.id,
|
||||
name: decoration.name,
|
||||
description: decoration.description,
|
||||
url: decoration.url,
|
||||
roleIdsThatCanBeUsedThisDecoration: decoration.roleIdsThatCanBeUsedThisDecoration,
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.j
|
|||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { safeForSql } from '@/misc/safe-for-sql.js';
|
||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
import { ApiLoggerService } from '../../ApiLoggerService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
|
|
@ -131,6 +132,9 @@ export const paramDef = {
|
|||
birthday: { ...birthdaySchema, nullable: true },
|
||||
lang: { type: 'string', enum: [null, ...Object.keys(langmap)] as string[], nullable: true },
|
||||
avatarId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
avatarDecorations: { type: 'array', maxItems: 1, items: {
|
||||
type: 'string',
|
||||
} },
|
||||
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
fields: {
|
||||
type: 'array',
|
||||
|
|
@ -207,6 +211,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private roleService: RoleService,
|
||||
private cacheService: CacheService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
private avatarDecorationService: AvatarDecorationService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, _user, token) => {
|
||||
const user = await this.usersRepository.findOneByOrFail({ id: _user.id }) as MiLocalUser;
|
||||
|
|
@ -296,6 +301,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
updates.bannerBlurhash = null;
|
||||
}
|
||||
|
||||
if (ps.avatarDecorations) {
|
||||
const decorations = await this.avatarDecorationService.getAll(true);
|
||||
const myRoles = await this.roleService.getUserRoles(user.id);
|
||||
const allRoles = await this.roleService.getRoles();
|
||||
const decorationIds = decorations
|
||||
.filter(d => d.roleIdsThatCanBeUsedThisDecoration.filter(roleId => allRoles.some(r => r.id === roleId)).length === 0 || myRoles.some(r => d.roleIdsThatCanBeUsedThisDecoration.includes(r.id)))
|
||||
.map(d => d.id);
|
||||
|
||||
updates.avatarDecorations = ps.avatarDecorations.filter(id => decorationIds.includes(id));
|
||||
}
|
||||
|
||||
if (ps.pinnedPageId) {
|
||||
const page = await this.pagesRepository.findOneBy({ id: ps.pinnedPageId });
|
||||
|
||||
|
|
@ -421,9 +437,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
const myLink = `${this.config.url}/@${user.username}`;
|
||||
|
||||
const includesMyLink = Array.from(doc.getElementsByTagName('a')).some(a => a.href === myLink);
|
||||
const aEls = Array.from(doc.getElementsByTagName('a'));
|
||||
const linkEls = Array.from(doc.getElementsByTagName('link'));
|
||||
|
||||
if (includesMyLink) {
|
||||
const includesMyLink = aEls.some(a => a.href === myLink);
|
||||
const includesRelMeLinks = [...aEls, ...linkEls].some(link => link.rel === 'me' && link.href === myLink);
|
||||
|
||||
if (includesMyLink || includesRelMeLinks) {
|
||||
await this.userProfilesRepository.createQueryBuilder('profile').update()
|
||||
.where('userId = :userId', { userId: user.id })
|
||||
.set({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue