feat: Avatar decoration (#12096)
* wip * Update ja-JP.yml * Update profile.vue * .js * Update home.test.ts
This commit is contained in:
		| @@ -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'; | ||||
| @@ -176,6 +180,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'; | ||||
| @@ -368,6 +373,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 }; | ||||
| @@ -526,6 +535,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 }; | ||||
| @@ -722,6 +732,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, | ||||
| @@ -880,6 +894,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 +1085,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, | ||||
| @@ -1228,6 +1247,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention | ||||
| 		$gallery_posts_unlike, | ||||
| 		$gallery_posts_update, | ||||
| 		$getOnlineUsersCount, | ||||
| 		$getAvatarDecorations, | ||||
| 		$hashtags_list, | ||||
| 		$hashtags_search, | ||||
| 		$hashtags_show, | ||||
|   | ||||
| @@ -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'; | ||||
| @@ -176,6 +180,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'; | ||||
| @@ -366,6 +371,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], | ||||
| @@ -524,6 +533,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], | ||||
|   | ||||
| @@ -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,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 }); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo