Feat: アバターデコレーションの受信を許可制に
Signed-off-by: mattyatea <mattyacocacora0@gmail.com>
This commit is contained in:
parent
4bee1a45a1
commit
082e48056c
|
@ -220,6 +220,8 @@ export interface Locale {
|
||||||
"blockedInstancesDescription": string;
|
"blockedInstancesDescription": string;
|
||||||
"silencedInstances": string;
|
"silencedInstances": string;
|
||||||
"silencedInstancesDescription": string;
|
"silencedInstancesDescription": string;
|
||||||
|
"avatarDecorationsAcceptInstance": string;
|
||||||
|
"avatarDecorationsAcceptInstancesDescription": string;
|
||||||
"muteAndBlock": string;
|
"muteAndBlock": string;
|
||||||
"mutedUsers": string;
|
"mutedUsers": string;
|
||||||
"blockedUsers": string;
|
"blockedUsers": string;
|
||||||
|
|
|
@ -217,6 +217,8 @@ blockedInstances: "ブロックしたサーバー"
|
||||||
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このインスタンスとやり取りできなくなります。"
|
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このインスタンスとやり取りできなくなります。"
|
||||||
silencedInstances: "サイレンスしたサーバー"
|
silencedInstances: "サイレンスしたサーバー"
|
||||||
silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。"
|
silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。"
|
||||||
|
avatarDecorationsAcceptInstance: "アイコンデコレーションを表示できるサーバー"
|
||||||
|
avatarDecorationsAcceptInstancesDescription: "アイコンデコレーションを受け入れたいサーバーのホストを改行で区切って設定します。"
|
||||||
muteAndBlock: "ミュートとブロック"
|
muteAndBlock: "ミュートとブロック"
|
||||||
mutedUsers: "ミュートしたユーザー"
|
mutedUsers: "ミュートしたユーザー"
|
||||||
blockedUsers: "ブロックしたユーザー"
|
blockedUsers: "ブロックしたユーザー"
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export class Avatardecorationaccepthost1698363835246 {
|
||||||
|
name = 'Avatardecorationaccepthost1698363835246'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "avatarDecorationAcceptHosts" character varying(1024) array NOT NULL DEFAULT '{}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "avatarDecorationAcceptHosts"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,6 +41,12 @@ export class UtilityService {
|
||||||
return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
|
return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public avatarDecorationAcceptHost(AcceptHost: string[] | undefined, host: string | null): boolean {
|
||||||
|
if (!AcceptHost || host == null) return false;
|
||||||
|
return AcceptHost.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public extractDbHost(uri: string): string {
|
public extractDbHost(uri: string): string {
|
||||||
const url = new URL(uri);
|
const url = new URL(uri);
|
||||||
|
|
|
@ -294,21 +294,24 @@ export class ApPersonService implements OnModuleInit {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region アバターデコレーション取得
|
//#region アバターデコレーション取得
|
||||||
const _avatarDecorations = await this.apNoteService.extractAvatarDecorations(person.tag ?? [], host)
|
|
||||||
.catch(err => {
|
|
||||||
this.logger.error('error occurred while fetching user avatar decorations', { stack: err });
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
|
|
||||||
const avatarDecorations: {id: string, angle: number, flipH: boolean}[] = [];
|
const avatarDecorations: {id: string, angle: number, flipH: boolean}[] = [];
|
||||||
|
if (this.utilityService.avatarDecorationAcceptHost((await this.metaService.fetch()).avatarDecorationAcceptHosts, host)) {
|
||||||
|
const _avatarDecorations = await this.apNoteService.extractAvatarDecorations(person.tag ?? [], host)
|
||||||
|
.catch(err => {
|
||||||
|
this.logger.error('error occurred while fetching user avatar decorations', { stack: err });
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
_avatarDecorations.forEach((value, index) => {
|
_avatarDecorations.forEach((value, index) => {
|
||||||
avatarDecorations.push({
|
avatarDecorations.push({
|
||||||
id: value.id,
|
id: value.id,
|
||||||
angle: person.AvatarDecorations ? person.AvatarDecorations[index].angle : 0,
|
angle: person.AvatarDecorations ? person.AvatarDecorations[index].angle : 0,
|
||||||
flipH: person.AvatarDecorations ? person.AvatarDecorations[index].flipH : false,
|
flipH: person.AvatarDecorations ? person.AvatarDecorations[index].flipH : false,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -439,22 +442,22 @@ export class ApPersonService implements OnModuleInit {
|
||||||
const person = this.validateActor(object, uri);
|
const person = this.validateActor(object, uri);
|
||||||
|
|
||||||
this.logger.info(`Updating the Person: ${person.id}`);
|
this.logger.info(`Updating the Person: ${person.id}`);
|
||||||
|
|
||||||
const _avatarDecorations = await this.apNoteService.extractAvatarDecorations(person.tag ?? [], exist.host)
|
|
||||||
.catch(err => {
|
|
||||||
this.logger.error('error occurred while fetching user avatar decorations', { stack: err });
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
|
|
||||||
const avatarDecorations: {id: string, angle: number, flipH: boolean}[] = [];
|
const avatarDecorations: {id: string, angle: number, flipH: boolean}[] = [];
|
||||||
|
if (this.utilityService.avatarDecorationAcceptHost((await this.metaService.fetch()).avatarDecorationAcceptHosts, exist.host)) {
|
||||||
|
const _avatarDecorations = await this.apNoteService.extractAvatarDecorations(person.tag ?? [], exist.host)
|
||||||
|
.catch(err => {
|
||||||
|
this.logger.error('error occurred while fetching user avatar decorations', { stack: err });
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
_avatarDecorations.forEach((value, index) => {
|
_avatarDecorations.forEach((value, index) => {
|
||||||
avatarDecorations.push({
|
avatarDecorations.push({
|
||||||
id: value.id,
|
id: value.id,
|
||||||
angle: person.AvatarDecorations ? person.AvatarDecorations[index].angle : 0,
|
angle: person.AvatarDecorations ? person.AvatarDecorations[index].angle : 0,
|
||||||
flipH: person.AvatarDecorations ? person.AvatarDecorations[index].flipH : false,
|
flipH: person.AvatarDecorations ? person.AvatarDecorations[index].flipH : false,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
// カスタム絵文字取得
|
// カスタム絵文字取得
|
||||||
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], exist.host).catch(e => {
|
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], exist.host).catch(e => {
|
||||||
|
|
|
@ -81,6 +81,11 @@ export class MiMeta {
|
||||||
})
|
})
|
||||||
public silencedHosts: string[];
|
public silencedHosts: string[];
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024, array: true, default: '{}',
|
||||||
|
})
|
||||||
|
public avatarDecorationAcceptHosts: string[];
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 1024,
|
length: 1024,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -11,6 +11,9 @@ import type Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
|
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||||
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
|
|
||||||
|
@ -33,6 +36,9 @@ export class CleanProcessorService {
|
||||||
|
|
||||||
private queueLoggerService: QueueLoggerService,
|
private queueLoggerService: QueueLoggerService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
|
private metaService: MetaService,
|
||||||
|
private utilityService: UtilityService,
|
||||||
|
private avatarDecorationService: AvatarDecorationService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('clean');
|
this.logger = this.queueLoggerService.logger.createSubLogger('clean');
|
||||||
}
|
}
|
||||||
|
@ -54,6 +60,14 @@ export class CleanProcessorService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { avatarDecorationAcceptHosts } = await this.metaService.fetch();
|
||||||
|
const allAvatarDecorations = await this.avatarDecorationService.getAll();
|
||||||
|
for (const avatarDecoration of allAvatarDecorations) {
|
||||||
|
if (avatarDecoration.host !== null && !this.utilityService.avatarDecorationAcceptHost(avatarDecorationAcceptHosts, avatarDecoration.host)) {
|
||||||
|
await this.avatarDecorationService.delete(avatarDecoration.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const expiredRoleAssignments = await this.roleAssignmentsRepository.createQueryBuilder('assign')
|
const expiredRoleAssignments = await this.roleAssignmentsRepository.createQueryBuilder('assign')
|
||||||
.where('assign.expiresAt IS NOT NULL')
|
.where('assign.expiresAt IS NOT NULL')
|
||||||
.andWhere('assign.expiresAt < :now', { now: new Date() })
|
.andWhere('assign.expiresAt < :now', { now: new Date() })
|
||||||
|
|
|
@ -86,8 +86,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const avatarDecorations = await this.avatarDecorationService.getAll(true);
|
const avatarDecorations = await this.avatarDecorationService.getAll(true);
|
||||||
|
return avatarDecorations.filter(x => x.host === null).map(avatarDecoration => ({
|
||||||
return avatarDecorations.map(avatarDecoration => ({
|
|
||||||
id: avatarDecoration.id,
|
id: avatarDecoration.id,
|
||||||
createdAt: this.idService.parse(avatarDecoration.id).date.toISOString(),
|
createdAt: this.idService.parse(avatarDecoration.id).date.toISOString(),
|
||||||
updatedAt: avatarDecoration.updatedAt?.toISOString() ?? null,
|
updatedAt: avatarDecoration.updatedAt?.toISOString() ?? null,
|
||||||
|
|
|
@ -115,6 +115,16 @@ export const meta = {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
avatarDecorationAcceptHosts: {
|
||||||
|
type: 'array',
|
||||||
|
optional: true,
|
||||||
|
nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false,
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
pinnedUsers: {
|
pinnedUsers: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@ -382,6 +392,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
hiddenTags: instance.hiddenTags,
|
hiddenTags: instance.hiddenTags,
|
||||||
blockedHosts: instance.blockedHosts,
|
blockedHosts: instance.blockedHosts,
|
||||||
silencedHosts: instance.silencedHosts,
|
silencedHosts: instance.silencedHosts,
|
||||||
|
avatarDecorationAcceptHosts: instance.avatarDecorationAcceptHosts,
|
||||||
sensitiveWords: instance.sensitiveWords,
|
sensitiveWords: instance.sensitiveWords,
|
||||||
preservedUsernames: instance.preservedUsernames,
|
preservedUsernames: instance.preservedUsernames,
|
||||||
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
||||||
|
|
|
@ -35,6 +35,20 @@ export const paramDef = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
silencedHosts: {
|
||||||
|
type: 'array',
|
||||||
|
nullable: true,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
avatarDecorationAcceptHosts: {
|
||||||
|
type: 'array',
|
||||||
|
nullable: true,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
sensitiveWords: {
|
sensitiveWords: {
|
||||||
type: 'array', nullable: true, items: {
|
type: 'array', nullable: true, items: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -126,13 +140,6 @@ export const paramDef = {
|
||||||
perUserHomeTimelineCacheMax: { type: 'integer' },
|
perUserHomeTimelineCacheMax: { type: 'integer' },
|
||||||
perUserListTimelineCacheMax: { type: 'integer' },
|
perUserListTimelineCacheMax: { type: 'integer' },
|
||||||
notesPerOneAd: { type: 'integer' },
|
notesPerOneAd: { type: 'integer' },
|
||||||
silencedHosts: {
|
|
||||||
type: 'array',
|
|
||||||
nullable: true,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -173,6 +180,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
return h !== '' && h !== lv && !set.blockedHosts?.includes(h);
|
return h !== '' && h !== lv && !set.blockedHosts?.includes(h);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(ps.avatarDecorationAcceptHosts)) {
|
||||||
|
let lastValue = '';
|
||||||
|
set.avatarDecorationAcceptHosts = ps.avatarDecorationAcceptHosts.sort().filter((h) => {
|
||||||
|
const lv = lastValue;
|
||||||
|
lastValue = h;
|
||||||
|
return h !== '' && h !== lv && !set.avatarDecorationAcceptHosts?.includes(h);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.themeColor !== undefined) {
|
if (ps.themeColor !== undefined) {
|
||||||
set.themeColor = ps.themeColor;
|
set.themeColor = ps.themeColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const decorations = await this.avatarDecorationService.getAll(true);
|
const decorations = await this.avatarDecorationService.getAll(true);
|
||||||
const allRoles = await this.roleService.getRoles();
|
const allRoles = await this.roleService.getRoles();
|
||||||
|
|
||||||
return decorations.map(decoration => ({
|
return decorations.filter(x => x.host === null).map(decoration => ({
|
||||||
id: decoration.id,
|
id: decoration.id,
|
||||||
name: decoration.name,
|
name: decoration.name,
|
||||||
description: decoration.description,
|
description: decoration.description,
|
||||||
|
|
|
@ -313,6 +313,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const allRoles = await this.roleService.getRoles();
|
const allRoles = await this.roleService.getRoles();
|
||||||
const decorationIds = decorations
|
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)))
|
.filter(d => d.roleIdsThatCanBeUsedThisDecoration.filter(roleId => allRoles.some(r => r.id === roleId)).length === 0 || myRoles.some(r => d.roleIdsThatCanBeUsedThisDecoration.includes(r.id)))
|
||||||
|
.filter(d => d.host === null)
|
||||||
.map(d => d.id);
|
.map(d => d.id);
|
||||||
|
|
||||||
updates.avatarDecorations = ps.avatarDecorations.filter(d => decorationIds.includes(d.id)).map(d => ({
|
updates.avatarDecorations = ps.avatarDecorations.filter(d => decorationIds.includes(d.id)).map(d => ({
|
||||||
|
|
|
@ -5,9 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="900">
|
<MkSpacer :contentMax="900">
|
||||||
<div class="_gaps">
|
<div v-if="tab === 'avatarDecorations'" class="_gaps">
|
||||||
<MkFolder v-for="avatarDecoration in avatarDecorations" :key="avatarDecoration.id ?? avatarDecoration._id" :defaultOpen="avatarDecoration.id == null">
|
<MkFolder v-for="avatarDecoration in avatarDecorations" :key="avatarDecoration.id ?? avatarDecoration._id" :defaultOpen="avatarDecoration.id == null">
|
||||||
<template #label>{{ avatarDecoration.name }}</template>
|
<template #label>{{ avatarDecoration.name }}</template>
|
||||||
<template #caption>{{ avatarDecoration.description }}</template>
|
<template #caption>{{ avatarDecoration.description }}</template>
|
||||||
|
@ -29,6 +29,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="tab === 'avatarDecorationsAcceptHosts'">
|
||||||
|
<MkTextarea v-model="acceptHosts">
|
||||||
|
<span>{{ i18n.ts.avatarDecorationsAcceptInstance }}</span>
|
||||||
|
<template #caption>{{ i18n.ts.avatarDecorationsAcceptInstancesDescription }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
<MkButton primary @click="acceptSave"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
||||||
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</template>
|
</template>
|
||||||
|
@ -48,7 +55,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
|
||||||
let avatarDecorations: any[] = $ref([]);
|
let avatarDecorations: any[] = $ref([]);
|
||||||
|
let tab = $ref('avatarDecorations');
|
||||||
|
let acceptHosts: string = $ref('');
|
||||||
function add() {
|
function add() {
|
||||||
avatarDecorations.unshift({
|
avatarDecorations.unshift({
|
||||||
_id: Math.random().toString(36),
|
_id: Math.random().toString(36),
|
||||||
|
@ -79,10 +87,19 @@ async function save(avatarDecoration) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function acceptSave() {
|
||||||
|
await os.apiWithDialog('admin/update-meta', {
|
||||||
|
avatarDecorationAcceptHosts: acceptHosts.split('\n') || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
os.api('admin/avatar-decorations/list').then(_avatarDecorations => {
|
os.api('admin/avatar-decorations/list').then(_avatarDecorations => {
|
||||||
avatarDecorations = _avatarDecorations;
|
avatarDecorations = _avatarDecorations;
|
||||||
});
|
});
|
||||||
|
os.api('admin/meta').then(_meta => {
|
||||||
|
acceptHosts = _meta.avatarDecorationAcceptHosts.join('\n');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
load();
|
load();
|
||||||
|
@ -94,7 +111,15 @@ const headerActions = $computed(() => [{
|
||||||
handler: add,
|
handler: add,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
const headerTabs = $computed(() => []);
|
const headerTabs = $computed(() => [{
|
||||||
|
key: 'avatarDecorations',
|
||||||
|
title: i18n.ts.avatarDecorations,
|
||||||
|
icon: 'ti ti-sparkles',
|
||||||
|
}, {
|
||||||
|
key: 'avatarDecorationsAcceptHosts',
|
||||||
|
title: i18n.ts.avatarDecorationsAcceptInstance,
|
||||||
|
icon: 'ti ti-thumb-up-filled',
|
||||||
|
}]);
|
||||||
|
|
||||||
definePageMetadata({
|
definePageMetadata({
|
||||||
title: i18n.ts.avatarDecorations,
|
title: i18n.ts.avatarDecorations,
|
||||||
|
|
|
@ -393,6 +393,7 @@ export type InstanceMetadata = LiteInstanceMetadata | DetailedInstanceMetadata;
|
||||||
export type AdminInstanceMetadata = DetailedInstanceMetadata & {
|
export type AdminInstanceMetadata = DetailedInstanceMetadata & {
|
||||||
// TODO: There are more fields.
|
// TODO: There are more fields.
|
||||||
blockedHosts: string[];
|
blockedHosts: string[];
|
||||||
|
avatarDecorationAcceptHosts: string[];
|
||||||
silencedHosts: string[];
|
silencedHosts: string[];
|
||||||
app192IconUrl: string | null;
|
app192IconUrl: string | null;
|
||||||
app512IconUrl: string | null;
|
app512IconUrl: string | null;
|
||||||
|
|
Loading…
Reference in New Issue