Merge remote-tracking branch 'misskey-mattyatea/emoji-request' into develop
# Conflicts: # locales/index.d.ts # locales/ja-JP.yml # packages/backend/src/core/UserFollowingService.ts # packages/frontend/src/components/MkEmojiPicker.vue # packages/frontend/src/pages/custom-emojis-manager.vue
This commit is contained in:
commit
c7c70c1c30
36 changed files with 1089 additions and 421 deletions
|
|
@ -0,0 +1,11 @@
|
|||
export class AddEmojiDraftFlag1684236161625 {
|
||||
name = 'AddEmojiDraftFlag1684236161625'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "emoji" ADD "draft" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "draft"`);
|
||||
}
|
||||
}
|
||||
|
|
@ -16,10 +16,8 @@ import type { EmojisRepository, MiRole, MiUser } from '@/models/_.js';
|
|||
import { bindThis } from '@/decorators.js';
|
||||
import { MemoryKVCache, RedisSingleCache } from '@/misc/cache.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { query } from '@/misc/prelude/url.js';
|
||||
import type { Serialized } from '@/types.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
|
||||
const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/;
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -66,6 +64,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
|||
license: string | null;
|
||||
isSensitive: boolean;
|
||||
localOnly: boolean;
|
||||
draft: boolean;
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][];
|
||||
}, moderator?: MiUser): Promise<MiEmoji> {
|
||||
const emoji = await this.emojisRepository.insert({
|
||||
|
|
@ -82,6 +81,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
|||
isSensitive: data.isSensitive,
|
||||
localOnly: data.localOnly,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction,
|
||||
draft: data.draft,
|
||||
}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
|
||||
|
||||
if (data.host == null) {
|
||||
|
|
@ -111,6 +111,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
|||
license?: string | null;
|
||||
isSensitive?: boolean;
|
||||
localOnly?: boolean;
|
||||
draft: boolean;
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction?: MiRole['id'][];
|
||||
}, moderator?: MiUser): Promise<void> {
|
||||
const emoji = await this.emojisRepository.findOneByOrFail({ id: id });
|
||||
|
|
@ -125,6 +126,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
|||
license: data.license,
|
||||
isSensitive: data.isSensitive,
|
||||
localOnly: data.localOnly,
|
||||
draft: data.draft,
|
||||
originalUrl: data.driveFile != null ? data.driveFile.url : undefined,
|
||||
publicUrl: data.driveFile != null ? (data.driveFile.webpublicUrl ?? data.driveFile.url) : undefined,
|
||||
type: data.driveFile != null ? (data.driveFile.webpublicType ?? data.driveFile.type) : undefined,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export type RolePolicies = {
|
|||
inviteLimitCycle: number;
|
||||
inviteExpirationTime: number;
|
||||
canManageCustomEmojis: boolean;
|
||||
canRequestCustomEmojis: boolean;
|
||||
canSearchNotes: boolean;
|
||||
canUseTranslator: boolean;
|
||||
canHideAds: boolean;
|
||||
|
|
@ -59,6 +60,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
|||
inviteLimitCycle: 60 * 24 * 7,
|
||||
inviteExpirationTime: 0,
|
||||
canManageCustomEmojis: false,
|
||||
canRequestCustomEmojis: false,
|
||||
canSearchNotes: false,
|
||||
canUseTranslator: true,
|
||||
canHideAds: false,
|
||||
|
|
@ -303,6 +305,7 @@ export class RoleService implements OnApplicationShutdown {
|
|||
inviteLimitCycle: calc('inviteLimitCycle', vs => Math.max(...vs)),
|
||||
inviteExpirationTime: calc('inviteExpirationTime', vs => Math.max(...vs)),
|
||||
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
|
||||
canRequestCustomEmojis: calc('canRequestCustomEmojis', vs => vs.some(v => v === true)),
|
||||
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
|
||||
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
|
||||
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,13 @@ import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
|||
import { WebhookService } from '@/core/WebhookService.js';
|
||||
import { NotificationService } from '@/core/NotificationService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { FollowingsRepository, FollowRequestsRepository, InstancesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type {
|
||||
FollowingsRepository,
|
||||
FollowRequestsRepository,
|
||||
InstancesRepository,
|
||||
UserProfilesRepository,
|
||||
UsersRepository,
|
||||
} from '@/models/_.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
|
|
@ -53,25 +59,18 @@ export class UserFollowingService implements OnModuleInit {
|
|||
|
||||
constructor(
|
||||
private moduleRef: ModuleRef,
|
||||
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@Inject(DI.userProfilesRepository)
|
||||
private userProfilesRepository: UserProfilesRepository,
|
||||
|
||||
@Inject(DI.followingsRepository)
|
||||
private followingsRepository: FollowingsRepository,
|
||||
|
||||
@Inject(DI.followRequestsRepository)
|
||||
private followRequestsRepository: FollowRequestsRepository,
|
||||
|
||||
@Inject(DI.instancesRepository)
|
||||
private instancesRepository: InstancesRepository,
|
||||
|
||||
private cacheService: CacheService,
|
||||
private utilityService: UtilityService,
|
||||
private userEntityService: UserEntityService,
|
||||
|
|
@ -197,10 +196,18 @@ export class UserFollowingService implements OnModuleInit {
|
|||
@bindThis
|
||||
private async insertFollowingDoc(
|
||||
followee: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox']
|
||||
},
|
||||
follower: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox']
|
||||
},
|
||||
silent = false,
|
||||
withReplies?: boolean,
|
||||
|
|
@ -247,8 +254,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||
});
|
||||
|
||||
// 通知を作成
|
||||
this.notificationService.createNotification(follower.id, 'followRequestAccepted', {
|
||||
}, followee.id);
|
||||
this.notificationService.createNotification(follower.id, 'followRequestAccepted', {}, followee.id);
|
||||
}
|
||||
|
||||
if (alreadyFollowed) return;
|
||||
|
|
@ -322,18 +328,25 @@ export class UserFollowingService implements OnModuleInit {
|
|||
});
|
||||
|
||||
// 通知を作成
|
||||
this.notificationService.createNotification(followee.id, 'follow', {
|
||||
}, follower.id);
|
||||
this.notificationService.createNotification(followee.id, 'follow', {}, follower.id);
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async unfollow(
|
||||
follower: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox'];
|
||||
},
|
||||
followee: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox'];
|
||||
},
|
||||
silent = false,
|
||||
): Promise<void> {
|
||||
|
|
@ -464,10 +477,18 @@ export class UserFollowingService implements OnModuleInit {
|
|||
@bindThis
|
||||
public async createFollowRequest(
|
||||
follower: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox'];
|
||||
},
|
||||
followee: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox'];
|
||||
},
|
||||
requestId?: string,
|
||||
withReplies?: boolean,
|
||||
|
|
@ -560,7 +581,11 @@ export class UserFollowingService implements OnModuleInit {
|
|||
@bindThis
|
||||
public async acceptFollowRequest(
|
||||
followee: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox'];
|
||||
},
|
||||
follower: MiUser,
|
||||
): Promise<void> {
|
||||
|
|
@ -588,7 +613,11 @@ export class UserFollowingService implements OnModuleInit {
|
|||
@bindThis
|
||||
public async acceptAllFollowRequests(
|
||||
user: {
|
||||
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
|
||||
id: MiUser['id'];
|
||||
host: MiUser['host'];
|
||||
uri: MiUser['host'];
|
||||
inbox: MiUser['inbox'];
|
||||
sharedInbox: MiUser['sharedInbox'];
|
||||
},
|
||||
): Promise<void> {
|
||||
const requests = await this.followRequestsRepository.findBy({
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export class EmojiEntityService {
|
|||
url: emoji.publicUrl || emoji.originalUrl,
|
||||
isSensitive: emoji.isSensitive ? true : undefined,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length > 0 ? emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : undefined,
|
||||
draft: emoji.draft,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +62,7 @@ export class EmojiEntityService {
|
|||
isSensitive: emoji.isSensitive,
|
||||
localOnly: emoji.localOnly,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction,
|
||||
draft: emoji.draft,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,4 +81,10 @@ export class MiEmoji {
|
|||
array: true, length: 128, default: '{}',
|
||||
})
|
||||
public roleIdsThatCanBeUsedThisEmojiAsReaction: string[];
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
nullable: false,
|
||||
})
|
||||
public draft: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ export const packedEmojiSimpleSchema = {
|
|||
format: 'id',
|
||||
},
|
||||
},
|
||||
draft: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
|
@ -81,6 +85,10 @@ export const packedEmojiDetailedSchema = {
|
|||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
draft: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
isSensitive: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ export class ImportCustomEmojisProcessorService {
|
|||
isSensitive: emojiInfo.isSensitive,
|
||||
localOnly: emojiInfo.localOnly,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: [],
|
||||
draft: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import * as ep___admin_emoji_addAliasesBulk from './endpoints/admin/emoji/add-al
|
|||
import * as ep___admin_emoji_setlocalOnlyBulk from './endpoints/admin/emoji/set-localonly-bulk.js';
|
||||
import * as ep___admin_emoji_setisSensitiveBulk from './endpoints/admin/emoji/set-issensitive-bulk.js';
|
||||
import * as ep___admin_emoji_add from './endpoints/admin/emoji/add.js';
|
||||
import * as ep___admin_emoji_addDraft from './endpoints/admin/emoji/add-draft.js';
|
||||
import * as ep___admin_emoji_copy from './endpoints/admin/emoji/copy.js';
|
||||
import * as ep___admin_emoji_deleteBulk from './endpoints/admin/emoji/delete-bulk.js';
|
||||
import * as ep___admin_emoji_delete from './endpoints/admin/emoji/delete.js';
|
||||
|
|
@ -382,6 +383,7 @@ const $admin_emoji_addAliasesBulk: Provider = { provide: 'ep:admin/emoji/add-ali
|
|||
const $admin_emoji_setlocalOnlyBulk: Provider = { provide: 'ep:admin/emoji/set-localonly-bulk', useClass: ep___admin_emoji_setlocalOnlyBulk.default };
|
||||
const $admin_emoji_setisSensitiveBulk: Provider = { provide: 'ep:admin/emoji/set-issensitive-bulk', useClass: ep___admin_emoji_setisSensitiveBulk.default };
|
||||
const $admin_emoji_add: Provider = { provide: 'ep:admin/emoji/add', useClass: ep___admin_emoji_add.default };
|
||||
const $admin_emoji_addDraft: Provider = { provide: 'ep:admin/emoji/add-draft', useClass: ep___admin_emoji_addDraft.default };
|
||||
const $admin_emoji_copy: Provider = { provide: 'ep:admin/emoji/copy', useClass: ep___admin_emoji_copy.default };
|
||||
const $admin_emoji_deleteBulk: Provider = { provide: 'ep:admin/emoji/delete-bulk', useClass: ep___admin_emoji_deleteBulk.default };
|
||||
const $admin_emoji_delete: Provider = { provide: 'ep:admin/emoji/delete', useClass: ep___admin_emoji_delete.default };
|
||||
|
|
@ -741,6 +743,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$admin_emoji_setlocalOnlyBulk,
|
||||
$admin_emoji_setisSensitiveBulk,
|
||||
$admin_emoji_add,
|
||||
$admin_emoji_addDraft,
|
||||
$admin_emoji_copy,
|
||||
$admin_emoji_deleteBulk,
|
||||
$admin_emoji_delete,
|
||||
|
|
@ -1092,6 +1095,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$admin_drive_showFile,
|
||||
$admin_emoji_addAliasesBulk,
|
||||
$admin_emoji_add,
|
||||
$admin_emoji_addDraft,
|
||||
$admin_emoji_copy,
|
||||
$admin_emoji_deleteBulk,
|
||||
$admin_emoji_delete,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import * as ep___admin_drive_files from './endpoints/admin/drive/files.js';
|
|||
import * as ep___admin_drive_showFile from './endpoints/admin/drive/show-file.js';
|
||||
import * as ep___admin_emoji_addAliasesBulk from './endpoints/admin/emoji/add-aliases-bulk.js';
|
||||
import * as ep___admin_emoji_add from './endpoints/admin/emoji/add.js';
|
||||
import * as ep___admin_emoji_addDraft from './endpoints/admin/emoji/add-draft.js';
|
||||
import * as ep___admin_emoji_copy from './endpoints/admin/emoji/copy.js';
|
||||
import * as ep___admin_emoji_deleteBulk from './endpoints/admin/emoji/delete-bulk.js';
|
||||
import * as ep___admin_emoji_delete from './endpoints/admin/emoji/delete.js';
|
||||
|
|
@ -377,6 +378,7 @@ const eps = [
|
|||
['admin/drive/show-file', ep___admin_drive_showFile],
|
||||
['admin/emoji/add-aliases-bulk', ep___admin_emoji_addAliasesBulk],
|
||||
['admin/emoji/add', ep___admin_emoji_add],
|
||||
['admin/emoji/add-draft', ep___admin_emoji_addDraft],
|
||||
['admin/emoji/copy', ep___admin_emoji_copy],
|
||||
['admin/emoji/delete-bulk', ep___admin_emoji_deleteBulk],
|
||||
['admin/emoji/delete', ep___admin_emoji_delete],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import type { DriveFilesRepository } from '@/models/_.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canRequestCustomEmojis',
|
||||
|
||||
errors: {
|
||||
noSuchFile: {
|
||||
message: 'No such file.',
|
||||
code: 'NO_SUCH_FILE',
|
||||
id: 'fc46b5a4-6b92-4c33-ac66-b806659bb5cf',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', pattern: '^[a-zA-Z0-9_]+$' },
|
||||
category: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Use `null` to reset the category.',
|
||||
},
|
||||
aliases: { type: 'array', items: {
|
||||
type: 'string',
|
||||
} },
|
||||
license: { type: 'string', nullable: true },
|
||||
fileId: { type: 'string', format: 'misskey:id' },
|
||||
isSensitive: { type: 'boolean' },
|
||||
localOnly: { type: 'boolean' },
|
||||
},
|
||||
required: ['name', 'fileId'],
|
||||
} as const;
|
||||
|
||||
// TODO: ロジックをサービスに切り出す
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
constructor(
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
||||
private customEmojiService: CustomEmojiService,
|
||||
|
||||
private moderationLogService: ModerationLogService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
|
||||
|
||||
if (driveFile == null) throw new ApiError(meta.errors.noSuchFile);
|
||||
|
||||
const emoji = await this.customEmojiService.add({
|
||||
driveFile,
|
||||
name: ps.name,
|
||||
category: ps.category ?? null,
|
||||
aliases: ps.aliases ?? [],
|
||||
license: ps.license ?? null,
|
||||
host: null,
|
||||
draft: true,
|
||||
isSensitive: ps.isSensitive ?? false,
|
||||
localOnly: ps.localOnly ?? false,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: [],
|
||||
});
|
||||
|
||||
return {
|
||||
id: emoji.id,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -41,17 +41,21 @@ export const paramDef = {
|
|||
nullable: true,
|
||||
description: 'Use `null` to reset the category.',
|
||||
},
|
||||
aliases: { type: 'array', items: {
|
||||
type: 'string',
|
||||
} },
|
||||
aliases: {
|
||||
type: 'array', items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
license: { type: 'string', nullable: true },
|
||||
isSensitive: { type: 'boolean' },
|
||||
localOnly: { type: 'boolean' },
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: {
|
||||
type: 'string',
|
||||
} },
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: {
|
||||
type: 'array', items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['name', 'fileId'],
|
||||
required: ['name', 'fileId', 'draft'],
|
||||
} as const;
|
||||
|
||||
// TODO: ロジックをサービスに切り出す
|
||||
|
|
@ -61,13 +65,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
constructor(
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
||||
private customEmojiService: CustomEmojiService,
|
||||
|
||||
private emojiEntityService: EmojiEntityService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
|
||||
|
||||
if (driveFile == null) throw new ApiError(meta.errors.noSuchFile);
|
||||
const isDuplicate = await this.customEmojiService.checkDuplicate(ps.name);
|
||||
if (isDuplicate) throw new ApiError(meta.errors.duplicateName);
|
||||
|
|
@ -81,6 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
license: ps.license ?? null,
|
||||
isSensitive: ps.isSensitive ?? false,
|
||||
localOnly: ps.localOnly ?? false,
|
||||
draft: false,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [],
|
||||
}, me);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ export const paramDef = {
|
|||
type: 'object',
|
||||
properties: {
|
||||
query: { type: 'string', nullable: true, default: null },
|
||||
draft: { type: 'boolean', nullable: true, default: null },
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||
sinceId: { type: 'string', format: 'misskey:id' },
|
||||
untilId: { type: 'string', format: 'misskey:id' },
|
||||
|
|
@ -86,6 +87,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
let emojis: MiEmoji[];
|
||||
|
||||
if (ps.draft !== null) {
|
||||
if (ps.draft) {
|
||||
q.andWhere('emoji.draft = TRUE');
|
||||
} else {
|
||||
q.andWhere('emoji.draft = FALSE');
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.query) {
|
||||
//q.andWhere('emoji.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
|
||||
//const emojis = await q.limit(ps.limit).getMany();
|
||||
|
|
|
|||
|
|
@ -60,8 +60,9 @@ export const paramDef = {
|
|||
roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: {
|
||||
type: 'string',
|
||||
} },
|
||||
draft: { type: 'boolean' },
|
||||
},
|
||||
required: ['id', 'name', 'aliases'],
|
||||
required: ['id', 'name', 'draft', 'aliases'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -97,6 +98,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
isSensitive: ps.isSensitive,
|
||||
localOnly: ps.localOnly,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction,
|
||||
draft: ps.draft,
|
||||
}, me);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue