Skip to content

Commit

Permalink
Enhance: Fedibird形式の絵文字情報連合に対応 (#604)
Browse files Browse the repository at this point in the history
  • Loading branch information
penginn-net authored Jan 10, 2025
1 parent 14141fe commit 30cae00
Show file tree
Hide file tree
Showing 25 changed files with 870 additions and 52 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG_YOJO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

### General
- Feat: システムユーザーのファイル一覧を追加 [#595](https://github.com/yojo-art/cherrypick/pull/595)
- Enhance: Fedibird形式の絵文字情報連合に対応 [#604](https://github.com/yojo-art/cherrypick/pull/604)
- 以下の情報が対応ソフト間で連合されます
- キーワード
- コピー条件
- カテゴリ
- 製作者
- ライセンス
- 説明
- 使用に関しての説明

### Client
- Fix: チュートリアルを現状に合わせて更新[#586](https://github.com/yojo-art/cherrypick/pull/586)
Expand Down
38 changes: 38 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12676,6 +12676,44 @@ export interface Locale extends ILocale {
*/
"private": string;
};
"_emoji": {
/**
* この絵文字のコピーは許可されていません
*/
"copyPermissionIsDeny": string;
/**
* ライセンスと使用に関しての情報を読んで同意できるならOkを選択してください
*/
"seeLicense": string;
/**
* 使用に関して
*/
"usageInfo": string;
/**
* 作成者
*/
"author": string;
/**
* コピーの許可
*/
"copyPermission": string;
/**
* 許可
*/
"allow": string;
/**
* 禁止
*/
"deny": string;
/**
* 条件付き
*/
"conditional": string;
/**
* 絵文字ベース
*/
"isBasedOn": string;
};
}
declare const locales: {
[lang: string]: Locale;
Expand Down
11 changes: 11 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3384,3 +3384,14 @@ _searchbility:
followersAndReacted: "フォロワーと反応した人"
reactedOnly: "反応した人"
private: "自分だけ"

_emoji:
copyPermissionIsDeny: "この絵文字のコピーは許可されていません"
seeLicense: "ライセンスと使用に関しての情報を読んで同意できるならOkを選択してください"
usageInfo: "使用に関して"
author: "作成者"
copyPermission: "コピーの許可"
allow: "許可"
deny: "禁止"
conditional: "条件付き"
isBasedOn: "絵文字ベース"
24 changes: 24 additions & 0 deletions packages/backend/migration/1735299834220-EmojiInfoFederation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project, noridev and cherryPick-project, yojo-art team
* SPDX-License-Identifier: AGPL-3.0-only
*/

export class EmojiInfoFederation1735299834220 {
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "emoji" ADD "usageInfo" character varying(512)`);
await queryRunner.query(`ALTER TABLE "emoji" ADD "description" character varying(512)`);
await queryRunner.query(`ALTER TABLE "emoji" ADD "author" character varying(128)`);
await queryRunner.query(`ALTER TABLE "emoji" ADD "isBasedOn" character varying(1024)`);
await queryRunner.query(`CREATE TYPE "public"."emoji_copypermission_enum" AS ENUM('allow', 'deny', 'conditional', 'null')`);
await queryRunner.query(`ALTER TABLE "emoji" ADD "copyPermission" "public"."emoji_copypermission_enum"`);
}

async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "copyPermission"`);
await queryRunner.query(`DROP TYPE "public"."emoji_copypermission_enum"`);
await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "isBasedOn"`);
await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "author"`);
await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "description"`);
await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "usageInfo"`);
}
}
21 changes: 21 additions & 0 deletions packages/backend/src/core/CustomEmojiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { query } from '@/misc/prelude/url.js';
import type { Serialized } from '@/types.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { DriveService } from '@/core/DriveService.js';
import { emojiCopyPermissions } from '@/types.js';

const parseEmojiStrRegexp = /^([-\w]+)(?:@([\w.-]+))?$/;

Expand Down Expand Up @@ -69,6 +70,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
isSensitive: boolean;
localOnly: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][];
copyPermission: 'allow' | 'deny' | 'conditional' | null,
usageInfo: string | null,
author: string | null,
description: string | null,
isBasedOn: string | null,
}, moderator?: MiUser): Promise<MiEmoji> {
// システムユーザーとして再アップロード
if (!data.driveFile.user?.isRoot) {
Expand All @@ -93,6 +99,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
isSensitive: data.isSensitive,
localOnly: data.localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction,
copyPermission: data.copyPermission,
usageInfo: data.usageInfo,
author: data.author,
description: data.description,
isBasedOn: data.isBasedOn,
});

if (data.host == null) {
Expand Down Expand Up @@ -127,6 +138,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
isSensitive?: boolean;
localOnly?: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction?: MiRole['id'][];
copyPermission?: 'allow' | 'deny' | 'conditional' | null,
usageInfo?: string | null,
author?: string | null,
description?: string | null,
isBasedOn?: string | null,
}, moderator?: MiUser): Promise<
null
| 'NO_SUCH_EMOJI'
Expand Down Expand Up @@ -157,6 +173,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
publicUrl: data.driveFile != null ? (data.driveFile.webpublicUrl ?? data.driveFile.url) : undefined,
type: data.driveFile != null ? (data.driveFile.webpublicType ?? data.driveFile.type) : undefined,
roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction ?? undefined,
copyPermission: data.copyPermission,
usageInfo: data.usageInfo,
author: data.author,
description: data.description,
isBasedOn: data.isBasedOn,
});

this.localEmojisCache.refresh();
Expand Down
8 changes: 8 additions & 0 deletions packages/backend/src/core/activitypub/ApRendererService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,14 @@ export class ApRendererService {
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
url: emoji.publicUrl || emoji.originalUrl,
},
keywords: emoji.aliases,
...(emoji.copyPermission === null ? { } : { copyPermission: emoji.copyPermission }),
...(emoji.category === null ? { } : { category: emoji.category }),
...(emoji.license === null ? { } : { license: emoji.license }),
...(emoji.usageInfo === null ? { } : { usageInfo: emoji.usageInfo }),
...(emoji.author === null ? { } : { author: emoji.author }),
...(emoji.description === null ? { } : { description: emoji.description }),
...(emoji.isBasedOn === null ? { } : { isBasedOn: emoji.isBasedOn }),
};
}

Expand Down
17 changes: 16 additions & 1 deletion packages/backend/src/core/activitypub/models/ApNoteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,14 @@ export class ApNoteService {
originalUrl: tag.icon.url,
publicUrl: tag.icon.url,
updatedAt: new Date(),
copyPermission: tag.copyPermission,
category: tag.category,
license: tag.license,
aliases: tag.keywords,
usageInfo: tag.usageInfo,
author: tag.author,
description: tag.description,
isBasedOn: tag.isBasedOn,
});

const emoji = await this.emojisRepository.findOneBy({ host, name });
Expand All @@ -539,7 +547,14 @@ export class ApNoteService {
originalUrl: tag.icon.url,
publicUrl: tag.icon.url,
updatedAt: new Date(),
aliases: [],
copyPermission: tag.copyPermission,
category: tag.category,
license: tag.license,
aliases: tag.keywords,
usageInfo: tag.usageInfo,
author: tag.author,
description: tag.description,
isBasedOn: tag.isBasedOn,
});
}));
}
Expand Down
8 changes: 8 additions & 0 deletions packages/backend/src/core/activitypub/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ export interface IApEmoji extends IObject {
type: 'Emoji';
name: string;
updated: string;
copyPermission?: 'allow' | 'deny' | 'conditional';
category?: string;
license?: string;
keywords?: string[];
usageInfo?: string;
author?: string;
description?: string;
isBasedOn?: string;
}

export const isEmoji = (object: IObject): object is IApEmoji =>
Expand Down
5 changes: 5 additions & 0 deletions packages/backend/src/core/entities/EmojiEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ export class EmojiEntityService {
isSensitive: emoji.isSensitive,
localOnly: emoji.localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction,
copyPermission: emoji.copyPermission,
usageInfo: emoji.usageInfo,
author: emoji.author,
description: emoji.description,
isBasedOn: emoji.isBasedOn,
};
}

Expand Down
35 changes: 35 additions & 0 deletions packages/backend/src/models/Emoji.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { PrimaryColumn, Entity, Index, Column } from 'typeorm';
import { id } from './util/id.js';
import { emojiCopyPermissions } from "@/types.js";

@Entity('emoji')
@Index(['name', 'host'], { unique: true })
Expand Down Expand Up @@ -76,6 +77,40 @@ export class MiEmoji {
})
public isSensitive: boolean;

@Column('varchar', {
length: 512,
default: null,
nullable: true,
})
public usageInfo: string | null;

@Column('varchar', {
length: 512,
default: null,
nullable: true,
})
public description: string | null;

@Column('varchar', {
length: 128,
default: null,
nullable: true,
})
public author: string | null;

@Column('enum',
{
enum: emojiCopyPermissions,
nullable: true,
})
public copyPermission: typeof emojiCopyPermissions[number] | null;

@Column('varchar', {
length: 1024,
default: null,
})
public isBasedOn: string | null;

// TODO: 定期ジョブで存在しなくなったロールIDを除去するようにする
@Column('varchar', {
array: true, length: 128, default: '{}',
Expand Down
7 changes: 7 additions & 0 deletions packages/backend/src/models/json-schema/emoji.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { emojiCopyPermissions } from '@/types.js';

export const packedEmojiSimpleSchema = {
type: 'object',
properties: {
Expand Down Expand Up @@ -102,5 +104,10 @@ export const packedEmojiDetailedSchema = {
format: 'id',
},
},
copyPermission: { type: 'string', enum: emojiCopyPermissions, nullable: true, },
usageInfo: { type: 'string', nullable: true, },
author: { type: 'string', nullable: true, },
description: { type: 'string', nullable: true, },
isBasedOn: { type: 'string', nullable: true, },
},
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ export class ImportCustomEmojisProcessorService {
license: emojiInfo.license,
isSensitive: emojiInfo.isSensitive,
localOnly: emojiInfo.localOnly,
author: emojiInfo.author ?? null,
description: emojiInfo.description ?? null,
usageInfo: emojiInfo.usageInfo ?? null,
copyPermission: emojiInfo.copyPermission ?? null,
isBasedOn: emojiInfo.isBasedOn ?? null,
roleIdsThatCanBeUsedThisEmojiAsReaction: [],
});
} catch (e) {
Expand Down
12 changes: 12 additions & 0 deletions packages/backend/src/server/api/endpoints/admin/emoji/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { DriveFilesRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
import { emojiCopyPermissions } from '@/types.js';
import { ApiError } from '../../../error.js';

export const meta = {
Expand Down Expand Up @@ -56,6 +57,12 @@ export const paramDef = {
roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: {
type: 'string',
} },

copyPermission: { type: 'string', enum: emojiCopyPermissions, nullable: true, default: emojiCopyPermissions[0], description: 'この絵文字を外部サーバーへコピーすることの許可' },
usageInfo: { type: 'string', nullable: true, description: '使用する際の説明' },
author: { type: 'string', nullable: true, description: '作者情報' },
description: { type: 'string', nullable: true, description: '絵文字の説明' },
isBasedOn: { type: 'string', nullable: true, description: 'もとになったもののURLなど' },
},
required: ['name', 'fileId'],
} as const;
Expand Down Expand Up @@ -88,6 +95,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
isSensitive: ps.isSensitive ?? false,
localOnly: ps.localOnly ?? false,
roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [],
copyPermission: ps.copyPermission ?? null,
usageInfo: ps.usageInfo ?? null,
author: ps.author ?? null,
description: ps.description ?? null,
isBasedOn: ps.isBasedOn ?? null,
}, me);

return this.emojiEntityService.packDetailed(emoji);
Expand Down
11 changes: 11 additions & 0 deletions packages/backend/src/server/api/endpoints/admin/emoji/adds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
import { secureRndstr } from '@/misc/secure-rndstr.js';
import { ApiError } from '../../../error.js';
import { emojiCopyPermissions } from '@/types.js';

export const meta = {
tags: ['admin'],
Expand Down Expand Up @@ -57,6 +58,11 @@ export const paramDef = {
roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: {
type: 'string',
} },
copyPermission: { type: 'string', enum: emojiCopyPermissions, nullable: true, default: emojiCopyPermissions[0], description: 'この絵文字を外部サーバーへコピーすることの許可' },
usageInfo: { type: 'string', nullable: true, description: '使用する際の説明' },
author: { type: 'string', nullable: true, description: '作者情報' },
description: { type: 'string', nullable: true, description: '絵文字の説明' },
isBasedOn: { type: 'string', nullable: true, description: 'もとになったもののURLなど' },
},
required: ['fileId'],
} as const;
Expand Down Expand Up @@ -92,6 +98,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
isSensitive: ps.isSensitive ?? false,
localOnly: ps.localOnly ?? false,
roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [],
copyPermission: ps.copyPermission ?? null,
usageInfo: ps.usageInfo ?? null,
author: ps.author ?? null,
description: ps.description ?? null,
isBasedOn: ps.isBasedOn ?? null,
}, me);

return this.emojiEntityService.packDetailed(emoji);
Expand Down
Loading

0 comments on commit 30cae00

Please sign in to comment.