Revert "feat: レジストリAPIをサードパーティから利用可能に (#12229)"
This reverts commit 79346272f8
.
This commit is contained in:
parent
46bf8de14a
commit
bae684e484
|
@ -54,7 +54,6 @@
|
||||||
- Fix: 絵文字ピッカーでバッテリーの絵文字が複数表示される問題を修正 #12197
|
- Fix: 絵文字ピッカーでバッテリーの絵文字が複数表示される問題を修正 #12197
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Feat: Registry APIがサードパーティから利用可能になりました
|
|
||||||
- Enhance: RedisへのTLのキャッシュ(FTT)をオフにできるように
|
- Enhance: RedisへのTLのキャッシュ(FTT)をオフにできるように
|
||||||
- Enhance: フォローしているチャンネルをフォロー解除した時(またはその逆)、タイムラインに反映される間隔を改善
|
- Enhance: フォローしているチャンネルをフォロー解除した時(またはその逆)、タイムラインに反映される間隔を改善
|
||||||
- Enhance: プロフィールの自己紹介欄のMFMが連合するようになりました
|
- Enhance: プロフィールの自己紹介欄のMFMが連合するようになりました
|
||||||
|
|
|
@ -64,7 +64,6 @@ import { ClipService } from './ClipService.js';
|
||||||
import { FeaturedService } from './FeaturedService.js';
|
import { FeaturedService } from './FeaturedService.js';
|
||||||
import { FunoutTimelineService } from './FunoutTimelineService.js';
|
import { FunoutTimelineService } from './FunoutTimelineService.js';
|
||||||
import { ChannelFollowingService } from './ChannelFollowingService.js';
|
import { ChannelFollowingService } from './ChannelFollowingService.js';
|
||||||
import { RegistryApiService } from './RegistryApiService.js';
|
|
||||||
import { ChartLoggerService } from './chart/ChartLoggerService.js';
|
import { ChartLoggerService } from './chart/ChartLoggerService.js';
|
||||||
import FederationChart from './chart/charts/federation.js';
|
import FederationChart from './chart/charts/federation.js';
|
||||||
import NotesChart from './chart/charts/notes.js';
|
import NotesChart from './chart/charts/notes.js';
|
||||||
|
@ -196,7 +195,6 @@ const $ClipService: Provider = { provide: 'ClipService', useExisting: ClipServic
|
||||||
const $FeaturedService: Provider = { provide: 'FeaturedService', useExisting: FeaturedService };
|
const $FeaturedService: Provider = { provide: 'FeaturedService', useExisting: FeaturedService };
|
||||||
const $FunoutTimelineService: Provider = { provide: 'FunoutTimelineService', useExisting: FunoutTimelineService };
|
const $FunoutTimelineService: Provider = { provide: 'FunoutTimelineService', useExisting: FunoutTimelineService };
|
||||||
const $ChannelFollowingService: Provider = { provide: 'ChannelFollowingService', useExisting: ChannelFollowingService };
|
const $ChannelFollowingService: Provider = { provide: 'ChannelFollowingService', useExisting: ChannelFollowingService };
|
||||||
const $RegistryApiService: Provider = { provide: 'RegistryApiService', useExisting: RegistryApiService };
|
|
||||||
|
|
||||||
const $ChartLoggerService: Provider = { provide: 'ChartLoggerService', useExisting: ChartLoggerService };
|
const $ChartLoggerService: Provider = { provide: 'ChartLoggerService', useExisting: ChartLoggerService };
|
||||||
const $FederationChart: Provider = { provide: 'FederationChart', useExisting: FederationChart };
|
const $FederationChart: Provider = { provide: 'FederationChart', useExisting: FederationChart };
|
||||||
|
@ -332,7 +330,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
FeaturedService,
|
FeaturedService,
|
||||||
FunoutTimelineService,
|
FunoutTimelineService,
|
||||||
ChannelFollowingService,
|
ChannelFollowingService,
|
||||||
RegistryApiService,
|
|
||||||
ChartLoggerService,
|
ChartLoggerService,
|
||||||
FederationChart,
|
FederationChart,
|
||||||
NotesChart,
|
NotesChart,
|
||||||
|
@ -461,7 +458,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$FeaturedService,
|
$FeaturedService,
|
||||||
$FunoutTimelineService,
|
$FunoutTimelineService,
|
||||||
$ChannelFollowingService,
|
$ChannelFollowingService,
|
||||||
$RegistryApiService,
|
|
||||||
$ChartLoggerService,
|
$ChartLoggerService,
|
||||||
$FederationChart,
|
$FederationChart,
|
||||||
$NotesChart,
|
$NotesChart,
|
||||||
|
@ -591,7 +587,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
FeaturedService,
|
FeaturedService,
|
||||||
FunoutTimelineService,
|
FunoutTimelineService,
|
||||||
ChannelFollowingService,
|
ChannelFollowingService,
|
||||||
RegistryApiService,
|
|
||||||
FederationChart,
|
FederationChart,
|
||||||
NotesChart,
|
NotesChart,
|
||||||
UsersChart,
|
UsersChart,
|
||||||
|
@ -719,7 +714,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$FeaturedService,
|
$FeaturedService,
|
||||||
$FunoutTimelineService,
|
$FunoutTimelineService,
|
||||||
$ChannelFollowingService,
|
$ChannelFollowingService,
|
||||||
$RegistryApiService,
|
|
||||||
$FederationChart,
|
$FederationChart,
|
||||||
$NotesChart,
|
$NotesChart,
|
||||||
$UsersChart,
|
$UsersChart,
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { MiRegistryItem, RegistryItemsRepository } from '@/models/_.js';
|
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|
||||||
import type { MiUser } from '@/models/User.js';
|
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RegistryApiService {
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.registryItemsRepository)
|
|
||||||
private registryItemsRepository: RegistryItemsRepository,
|
|
||||||
|
|
||||||
private idService: IdService,
|
|
||||||
private globalEventService: GlobalEventService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async set(userId: MiUser['id'], domain: string | null, scope: string[], key: string, value: any) {
|
|
||||||
// TODO: 作成できるキーの数を制限する
|
|
||||||
|
|
||||||
const query = this.registryItemsRepository.createQueryBuilder('item');
|
|
||||||
if (domain) {
|
|
||||||
query.where('item.domain = :domain', { domain: domain });
|
|
||||||
} else {
|
|
||||||
query.where('item.domain IS NULL');
|
|
||||||
}
|
|
||||||
query.andWhere('item.userId = :userId', { userId: userId });
|
|
||||||
query.andWhere('item.key = :key', { key: key });
|
|
||||||
query.andWhere('item.scope = :scope', { scope: scope });
|
|
||||||
|
|
||||||
const existingItem = await query.getOne();
|
|
||||||
|
|
||||||
if (existingItem) {
|
|
||||||
await this.registryItemsRepository.update(existingItem.id, {
|
|
||||||
updatedAt: new Date(),
|
|
||||||
value: value,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await this.registryItemsRepository.insert({
|
|
||||||
id: this.idService.gen(),
|
|
||||||
updatedAt: new Date(),
|
|
||||||
userId: userId,
|
|
||||||
domain: domain,
|
|
||||||
scope: scope,
|
|
||||||
key: key,
|
|
||||||
value: value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (domain == null) {
|
|
||||||
// TODO: サードパーティアプリが傍受出来てしまうのでどうにかする
|
|
||||||
this.globalEventService.publishMainStream(userId, 'registryUpdated', {
|
|
||||||
scope: scope,
|
|
||||||
key: key,
|
|
||||||
value: value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async getItem(userId: MiUser['id'], domain: string | null, scope: string[], key: string): Promise<MiRegistryItem | null> {
|
|
||||||
const query = this.registryItemsRepository.createQueryBuilder('item')
|
|
||||||
.where(domain == null ? 'item.domain IS NULL' : 'item.domain = :domain', { domain: domain })
|
|
||||||
.andWhere('item.userId = :userId', { userId: userId })
|
|
||||||
.andWhere('item.key = :key', { key: key })
|
|
||||||
.andWhere('item.scope = :scope', { scope: scope });
|
|
||||||
|
|
||||||
const item = await query.getOne();
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async getAllItemsOfScope(userId: MiUser['id'], domain: string | null, scope: string[]): Promise<MiRegistryItem[]> {
|
|
||||||
const query = this.registryItemsRepository.createQueryBuilder('item');
|
|
||||||
query.where(domain == null ? 'item.domain IS NULL' : 'item.domain = :domain', { domain: domain });
|
|
||||||
query.andWhere('item.userId = :userId', { userId: userId });
|
|
||||||
query.andWhere('item.scope = :scope', { scope: scope });
|
|
||||||
|
|
||||||
const items = await query.getMany();
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async getAllKeysOfScope(userId: MiUser['id'], domain: string | null, scope: string[]): Promise<string[]> {
|
|
||||||
const query = this.registryItemsRepository.createQueryBuilder('item');
|
|
||||||
query.select('item.key');
|
|
||||||
query.where(domain == null ? 'item.domain IS NULL' : 'item.domain = :domain', { domain: domain });
|
|
||||||
query.andWhere('item.userId = :userId', { userId: userId });
|
|
||||||
query.andWhere('item.scope = :scope', { scope: scope });
|
|
||||||
|
|
||||||
const items = await query.getMany();
|
|
||||||
|
|
||||||
return items.map(x => x.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async getAllScopeAndDomains(userId: MiUser['id']): Promise<{ domain: string | null; scopes: string[][] }[]> {
|
|
||||||
const query = this.registryItemsRepository.createQueryBuilder('item')
|
|
||||||
.select(['item.scope', 'item.domain'])
|
|
||||||
.where('item.userId = :userId', { userId: userId });
|
|
||||||
|
|
||||||
const items = await query.getMany();
|
|
||||||
|
|
||||||
const res = [] as { domain: string | null; scopes: string[][] }[];
|
|
||||||
|
|
||||||
for (const item of items) {
|
|
||||||
const target = res.find(x => x.domain === item.domain);
|
|
||||||
if (target) {
|
|
||||||
if (target.scopes.some(scope => scope.join('.') === item.scope.join('.'))) continue;
|
|
||||||
target.scopes.push(item.scope);
|
|
||||||
} else {
|
|
||||||
res.push({
|
|
||||||
domain: item.domain,
|
|
||||||
scopes: [item.scope],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async remove(userId: MiUser['id'], domain: string | null, scope: string[], key: string) {
|
|
||||||
const query = this.registryItemsRepository.createQueryBuilder().delete();
|
|
||||||
if (domain) {
|
|
||||||
query.where('domain = :domain', { domain: domain });
|
|
||||||
} else {
|
|
||||||
query.where('domain IS NULL');
|
|
||||||
}
|
|
||||||
query.andWhere('userId = :userId', { userId: userId });
|
|
||||||
query.andWhere('key = :key', { key: key });
|
|
||||||
query.andWhere('scope = :scope', { scope: scope });
|
|
||||||
|
|
||||||
await query.execute();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -230,7 +230,7 @@ import * as ep___i_registry_get from './endpoints/i/registry/get.js';
|
||||||
import * as ep___i_registry_keysWithType from './endpoints/i/registry/keys-with-type.js';
|
import * as ep___i_registry_keysWithType from './endpoints/i/registry/keys-with-type.js';
|
||||||
import * as ep___i_registry_keys from './endpoints/i/registry/keys.js';
|
import * as ep___i_registry_keys from './endpoints/i/registry/keys.js';
|
||||||
import * as ep___i_registry_remove from './endpoints/i/registry/remove.js';
|
import * as ep___i_registry_remove from './endpoints/i/registry/remove.js';
|
||||||
import * as ep___i_registry_scopesWithDomain from './endpoints/i/registry/scopes-with-domain.js';
|
import * as ep___i_registry_scopes from './endpoints/i/registry/scopes.js';
|
||||||
import * as ep___i_registry_set from './endpoints/i/registry/set.js';
|
import * as ep___i_registry_set from './endpoints/i/registry/set.js';
|
||||||
import * as ep___i_revokeToken from './endpoints/i/revoke-token.js';
|
import * as ep___i_revokeToken from './endpoints/i/revoke-token.js';
|
||||||
import * as ep___i_signinHistory from './endpoints/i/signin-history.js';
|
import * as ep___i_signinHistory from './endpoints/i/signin-history.js';
|
||||||
|
@ -588,7 +588,7 @@ const $i_registry_get: Provider = { provide: 'ep:i/registry/get', useClass: ep__
|
||||||
const $i_registry_keysWithType: Provider = { provide: 'ep:i/registry/keys-with-type', useClass: ep___i_registry_keysWithType.default };
|
const $i_registry_keysWithType: Provider = { provide: 'ep:i/registry/keys-with-type', useClass: ep___i_registry_keysWithType.default };
|
||||||
const $i_registry_keys: Provider = { provide: 'ep:i/registry/keys', useClass: ep___i_registry_keys.default };
|
const $i_registry_keys: Provider = { provide: 'ep:i/registry/keys', useClass: ep___i_registry_keys.default };
|
||||||
const $i_registry_remove: Provider = { provide: 'ep:i/registry/remove', useClass: ep___i_registry_remove.default };
|
const $i_registry_remove: Provider = { provide: 'ep:i/registry/remove', useClass: ep___i_registry_remove.default };
|
||||||
const $i_registry_scopesWithDomain: Provider = { provide: 'ep:i/registry/scopes-with-domain', useClass: ep___i_registry_scopesWithDomain.default };
|
const $i_registry_scopes: Provider = { provide: 'ep:i/registry/scopes', useClass: ep___i_registry_scopes.default };
|
||||||
const $i_registry_set: Provider = { provide: 'ep:i/registry/set', useClass: ep___i_registry_set.default };
|
const $i_registry_set: Provider = { provide: 'ep:i/registry/set', useClass: ep___i_registry_set.default };
|
||||||
const $i_revokeToken: Provider = { provide: 'ep:i/revoke-token', useClass: ep___i_revokeToken.default };
|
const $i_revokeToken: Provider = { provide: 'ep:i/revoke-token', useClass: ep___i_revokeToken.default };
|
||||||
const $i_signinHistory: Provider = { provide: 'ep:i/signin-history', useClass: ep___i_signinHistory.default };
|
const $i_signinHistory: Provider = { provide: 'ep:i/signin-history', useClass: ep___i_signinHistory.default };
|
||||||
|
@ -950,7 +950,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
||||||
$i_registry_keysWithType,
|
$i_registry_keysWithType,
|
||||||
$i_registry_keys,
|
$i_registry_keys,
|
||||||
$i_registry_remove,
|
$i_registry_remove,
|
||||||
$i_registry_scopesWithDomain,
|
$i_registry_scopes,
|
||||||
$i_registry_set,
|
$i_registry_set,
|
||||||
$i_revokeToken,
|
$i_revokeToken,
|
||||||
$i_signinHistory,
|
$i_signinHistory,
|
||||||
|
@ -1306,7 +1306,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
||||||
$i_registry_keysWithType,
|
$i_registry_keysWithType,
|
||||||
$i_registry_keys,
|
$i_registry_keys,
|
||||||
$i_registry_remove,
|
$i_registry_remove,
|
||||||
$i_registry_scopesWithDomain,
|
$i_registry_scopes,
|
||||||
$i_registry_set,
|
$i_registry_set,
|
||||||
$i_revokeToken,
|
$i_revokeToken,
|
||||||
$i_signinHistory,
|
$i_signinHistory,
|
||||||
|
|
|
@ -230,7 +230,7 @@ import * as ep___i_registry_get from './endpoints/i/registry/get.js';
|
||||||
import * as ep___i_registry_keysWithType from './endpoints/i/registry/keys-with-type.js';
|
import * as ep___i_registry_keysWithType from './endpoints/i/registry/keys-with-type.js';
|
||||||
import * as ep___i_registry_keys from './endpoints/i/registry/keys.js';
|
import * as ep___i_registry_keys from './endpoints/i/registry/keys.js';
|
||||||
import * as ep___i_registry_remove from './endpoints/i/registry/remove.js';
|
import * as ep___i_registry_remove from './endpoints/i/registry/remove.js';
|
||||||
import * as ep___i_registry_scopesWithDomain from './endpoints/i/registry/scopes-with-domain.js';
|
import * as ep___i_registry_scopes from './endpoints/i/registry/scopes.js';
|
||||||
import * as ep___i_registry_set from './endpoints/i/registry/set.js';
|
import * as ep___i_registry_set from './endpoints/i/registry/set.js';
|
||||||
import * as ep___i_revokeToken from './endpoints/i/revoke-token.js';
|
import * as ep___i_revokeToken from './endpoints/i/revoke-token.js';
|
||||||
import * as ep___i_signinHistory from './endpoints/i/signin-history.js';
|
import * as ep___i_signinHistory from './endpoints/i/signin-history.js';
|
||||||
|
@ -586,7 +586,7 @@ const eps = [
|
||||||
['i/registry/keys-with-type', ep___i_registry_keysWithType],
|
['i/registry/keys-with-type', ep___i_registry_keysWithType],
|
||||||
['i/registry/keys', ep___i_registry_keys],
|
['i/registry/keys', ep___i_registry_keys],
|
||||||
['i/registry/remove', ep___i_registry_remove],
|
['i/registry/remove', ep___i_registry_remove],
|
||||||
['i/registry/scopes-with-domain', ep___i_registry_scopesWithDomain],
|
['i/registry/scopes', ep___i_registry_scopes],
|
||||||
['i/registry/set', ep___i_registry_set],
|
['i/registry/set', ep___i_registry_set],
|
||||||
['i/revoke-token', ep___i_revokeToken],
|
['i/revoke-token', ep___i_revokeToken],
|
||||||
['i/signin-history', ep___i_signinHistory],
|
['i/signin-history', ep___i_signinHistory],
|
||||||
|
|
|
@ -5,10 +5,13 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { RegistryApiService } from '@/core/RegistryApiService.js';
|
import type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@ -17,18 +20,23 @@ export const paramDef = {
|
||||||
scope: { type: 'array', default: [], items: {
|
scope: { type: 'array', default: [], items: {
|
||||||
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
||||||
} },
|
} },
|
||||||
domain: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['scope'],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private registryApiService: RegistryApiService,
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me, accessToken) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const items = await this.registryApiService.getAllItemsOfScope(me.id, accessToken != null ? accessToken.id : (ps.domain ?? null), ps.scope);
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id })
|
||||||
|
.andWhere('item.scope = :scope', { scope: ps.scope });
|
||||||
|
|
||||||
|
const items = await query.getMany();
|
||||||
|
|
||||||
const res = {} as Record<string, any>;
|
const res = {} as Record<string, any>;
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,15 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { RegistryApiService } from '@/core/RegistryApiService.js';
|
import type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ApiError } from '../../../error.js';
|
import { ApiError } from '../../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchKey: {
|
noSuchKey: {
|
||||||
message: 'No such key.',
|
message: 'No such key.',
|
||||||
|
@ -27,18 +30,24 @@ export const paramDef = {
|
||||||
scope: { type: 'array', default: [], items: {
|
scope: { type: 'array', default: [], items: {
|
||||||
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
||||||
} },
|
} },
|
||||||
domain: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['key', 'scope'],
|
required: ['key'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private registryApiService: RegistryApiService,
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me, accessToken) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const item = await this.registryApiService.getItem(me.id, accessToken != null ? accessToken.id : (ps.domain ?? null), ps.scope, ps.key);
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id })
|
||||||
|
.andWhere('item.key = :key', { key: ps.key })
|
||||||
|
.andWhere('item.scope = :scope', { scope: ps.scope });
|
||||||
|
|
||||||
|
const item = await query.getOne();
|
||||||
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
throw new ApiError(meta.errors.noSuchKey);
|
throw new ApiError(meta.errors.noSuchKey);
|
||||||
|
|
|
@ -5,12 +5,15 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { RegistryApiService } from '@/core/RegistryApiService.js';
|
import type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ApiError } from '../../../error.js';
|
import { ApiError } from '../../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchKey: {
|
noSuchKey: {
|
||||||
message: 'No such key.',
|
message: 'No such key.',
|
||||||
|
@ -27,18 +30,24 @@ export const paramDef = {
|
||||||
scope: { type: 'array', default: [], items: {
|
scope: { type: 'array', default: [], items: {
|
||||||
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
||||||
} },
|
} },
|
||||||
domain: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['key', 'scope'],
|
required: ['key'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private registryApiService: RegistryApiService,
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me, accessToken) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const item = await this.registryApiService.getItem(me.id, accessToken != null ? accessToken.id : (ps.domain ?? null), ps.scope, ps.key);
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id })
|
||||||
|
.andWhere('item.key = :key', { key: ps.key })
|
||||||
|
.andWhere('item.scope = :scope', { scope: ps.scope });
|
||||||
|
|
||||||
|
const item = await query.getOne();
|
||||||
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
throw new ApiError(meta.errors.noSuchKey);
|
throw new ApiError(meta.errors.noSuchKey);
|
||||||
|
|
|
@ -5,10 +5,13 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { RegistryApiService } from '@/core/RegistryApiService.js';
|
import type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@ -17,31 +20,36 @@ export const paramDef = {
|
||||||
scope: { type: 'array', default: [], items: {
|
scope: { type: 'array', default: [], items: {
|
||||||
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
||||||
} },
|
} },
|
||||||
domain: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['scope'],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private registryApiService: RegistryApiService,
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me, accessToken) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const items = await this.registryApiService.getAllItemsOfScope(me.id, accessToken != null ? accessToken.id : (ps.domain ?? null), ps.scope);
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id })
|
||||||
|
.andWhere('item.scope = :scope', { scope: ps.scope });
|
||||||
|
|
||||||
|
const items = await query.getMany();
|
||||||
|
|
||||||
const res = {} as Record<string, string>;
|
const res = {} as Record<string, string>;
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const type = typeof item.value;
|
const type = typeof item.value;
|
||||||
res[item.key] =
|
res[item.key] =
|
||||||
item.value === null ? 'null' :
|
item.value === null ? 'null' :
|
||||||
Array.isArray(item.value) ? 'array' :
|
Array.isArray(item.value) ? 'array' :
|
||||||
type === 'number' ? 'number' :
|
type === 'number' ? 'number' :
|
||||||
type === 'string' ? 'string' :
|
type === 'string' ? 'string' :
|
||||||
type === 'boolean' ? 'boolean' :
|
type === 'boolean' ? 'boolean' :
|
||||||
type === 'object' ? 'object' :
|
type === 'object' ? 'object' :
|
||||||
null as never;
|
null as never;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -5,10 +5,13 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { RegistryApiService } from '@/core/RegistryApiService.js';
|
import type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@ -17,18 +20,26 @@ export const paramDef = {
|
||||||
scope: { type: 'array', default: [], items: {
|
scope: { type: 'array', default: [], items: {
|
||||||
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
||||||
} },
|
} },
|
||||||
domain: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['scope'],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private registryApiService: RegistryApiService,
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me, accessToken) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
return await this.registryApiService.getAllKeysOfScope(me.id, accessToken != null ? accessToken.id : (ps.domain ?? null), ps.scope);
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.select('item.key')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id })
|
||||||
|
.andWhere('item.scope = :scope', { scope: ps.scope });
|
||||||
|
|
||||||
|
const items = await query.getMany();
|
||||||
|
|
||||||
|
return items.map(x => x.key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,13 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { RegistryItemsRepository } from '@/models/_.js';
|
import type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { RegistryApiService } from '@/core/RegistryApiService.js';
|
|
||||||
import { ApiError } from '../../../error.js';
|
import { ApiError } from '../../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchKey: {
|
noSuchKey: {
|
||||||
message: 'No such key.',
|
message: 'No such key.',
|
||||||
|
@ -29,18 +30,30 @@ export const paramDef = {
|
||||||
scope: { type: 'array', default: [], items: {
|
scope: { type: 'array', default: [], items: {
|
||||||
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
||||||
} },
|
} },
|
||||||
domain: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['key', 'scope'],
|
required: ['key'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private registryApiService: RegistryApiService,
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me, accessToken) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
await this.registryApiService.remove(me.id, accessToken != null ? accessToken.id : (ps.domain ?? null), ps.scope, ps.key);
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id })
|
||||||
|
.andWhere('item.key = :key', { key: ps.key })
|
||||||
|
.andWhere('item.scope = :scope', { scope: ps.scope });
|
||||||
|
|
||||||
|
const item = await query.getOne();
|
||||||
|
|
||||||
|
if (item == null) {
|
||||||
|
throw new ApiError(meta.errors.noSuchKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.registryItemsRepository.remove(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 { RegistryApiService } from '@/core/RegistryApiService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
requireCredential: true,
|
|
||||||
secure: true,
|
|
||||||
} 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 registryApiService: RegistryApiService,
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
return await this.registryApiService.getAllScopeAndDomains(me.id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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 type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
|
} 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(
|
||||||
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.select('item.scope')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id });
|
||||||
|
|
||||||
|
const items = await query.getMany();
|
||||||
|
|
||||||
|
const res = [] as string[][];
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (res.some(scope => scope.join('.') === item.scope.join('.'))) continue;
|
||||||
|
res.push(item.scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { RegistryApiService } from '@/core/RegistryApiService.js';
|
import type { RegistryItemsRepository } from '@/models/_.js';
|
||||||
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
secure: true,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@ -19,18 +24,51 @@ export const paramDef = {
|
||||||
scope: { type: 'array', default: [], items: {
|
scope: { type: 'array', default: [], items: {
|
||||||
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1),
|
||||||
} },
|
} },
|
||||||
domain: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['key', 'value', 'scope'],
|
required: ['key', 'value'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private registryApiService: RegistryApiService,
|
@Inject(DI.registryItemsRepository)
|
||||||
|
private registryItemsRepository: RegistryItemsRepository,
|
||||||
|
|
||||||
|
private idService: IdService,
|
||||||
|
private globalEventService: GlobalEventService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me, accessToken) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
await this.registryApiService.set(me.id, accessToken ? accessToken.id : (ps.domain ?? null), ps.scope, ps.key, ps.value);
|
const query = this.registryItemsRepository.createQueryBuilder('item')
|
||||||
|
.where('item.domain IS NULL')
|
||||||
|
.andWhere('item.userId = :userId', { userId: me.id })
|
||||||
|
.andWhere('item.key = :key', { key: ps.key })
|
||||||
|
.andWhere('item.scope = :scope', { scope: ps.scope });
|
||||||
|
|
||||||
|
const existingItem = await query.getOne();
|
||||||
|
|
||||||
|
if (existingItem) {
|
||||||
|
await this.registryItemsRepository.update(existingItem.id, {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
value: ps.value,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await this.registryItemsRepository.insert({
|
||||||
|
id: this.idService.gen(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
userId: me.id,
|
||||||
|
domain: null,
|
||||||
|
scope: ps.scope,
|
||||||
|
key: ps.key,
|
||||||
|
value: ps.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: サードパーティアプリが傍受出来てしまうのでどうにかする
|
||||||
|
this.globalEventService.publishMainStream(me.id, 'registryUpdated', {
|
||||||
|
scope: ps.scope,
|
||||||
|
key: ps.key,
|
||||||
|
value: ps.value,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Misskey</MkButton>
|
<MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Misskey</MkButton>
|
||||||
</div>
|
</div>
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<div class="_gaps_s">
|
<div class="_formLinks">
|
||||||
<FormLink to="https://github.com/misskey-dev/misskey" external>
|
<FormLink to="https://github.com/misskey-dev/misskey" external>
|
||||||
<template #icon><i class="ti ti-code"></i></template>
|
<template #icon><i class="ti ti-code"></i></template>
|
||||||
{{ i18n.ts._aboutMisskey.source }}
|
{{ i18n.ts._aboutMisskey.source }}
|
||||||
|
|
|
@ -47,7 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
</FormSplit>
|
</FormSplit>
|
||||||
<FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>{{ i18n.ts.impressum }}</FormLink>
|
<FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>{{ i18n.ts.impressum }}</FormLink>
|
||||||
<div class="_gaps_s">
|
<div class="_formLinks">
|
||||||
<MkFolder v-if="instance.serverRules.length > 0">
|
<MkFolder v-if="instance.serverRules.length > 0">
|
||||||
<template #label>{{ i18n.ts.serverRules }}</template>
|
<template #label>{{ i18n.ts.serverRules }}</template>
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>Well-known resources</template>
|
<template #label>Well-known resources</template>
|
||||||
<div class="_gaps_s">
|
<div class="_formLinks">
|
||||||
<FormLink :to="`/.well-known/host-meta`" external>host-meta</FormLink>
|
<FormLink :to="`/.well-known/host-meta`" external>host-meta</FormLink>
|
||||||
<FormLink :to="`/.well-known/host-meta.json`" external>host-meta.json</FormLink>
|
<FormLink :to="`/.well-known/host-meta.json`" external>host-meta.json</FormLink>
|
||||||
<FormLink :to="`/.well-known/nodeinfo`" external>nodeinfo</FormLink>
|
<FormLink :to="`/.well-known/nodeinfo`" external>nodeinfo</FormLink>
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<FormSplit>
|
<FormSplit>
|
||||||
<MkKeyValue>
|
<MkKeyValue>
|
||||||
<template #key>{{ i18n.ts._registry.domain }}</template>
|
<template #key>{{ i18n.ts._registry.domain }}</template>
|
||||||
<template #value>{{ props.domain === '@' ? i18n.ts.system : props.domain.toUpperCase() }}</template>
|
<template #value>{{ i18n.ts.system }}</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<MkKeyValue>
|
<MkKeyValue>
|
||||||
<template #key>{{ i18n.ts._registry.scope }}</template>
|
<template #key>{{ i18n.ts._registry.scope }}</template>
|
||||||
|
@ -23,8 +23,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<FormSection v-if="keys">
|
<FormSection v-if="keys">
|
||||||
<template #label>{{ i18n.ts.keys }}</template>
|
<template #label>{{ i18n.ts.keys }}</template>
|
||||||
<div class="_gaps_s">
|
<div class="_formLinks">
|
||||||
<FormLink v-for="key in keys" :to="`/registry/value/${props.domain}/${scope.join('/')}/${key[0]}`" class="_monospace">{{ key[0] }}<template #suffix>{{ key[1].toUpperCase() }}</template></FormLink>
|
<FormLink v-for="key in keys" :to="`/registry/value/system/${scope.join('/')}/${key[0]}`" class="_monospace">{{ key[0] }}<template #suffix>{{ key[1].toUpperCase() }}</template></FormLink>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,17 +46,15 @@ import FormSplit from '@/components/form/split.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
path: string;
|
path: string;
|
||||||
domain: string;
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const scope = $computed(() => props.path ? props.path.split('/') : []);
|
const scope = $computed(() => props.path.split('/'));
|
||||||
|
|
||||||
let keys = $ref(null);
|
let keys = $ref(null);
|
||||||
|
|
||||||
function fetchKeys() {
|
function fetchKeys() {
|
||||||
os.api('i/registry/keys-with-type', {
|
os.api('i/registry/keys-with-type', {
|
||||||
scope: scope,
|
scope: scope,
|
||||||
domain: props.domain === '@' ? null : props.domain,
|
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
keys = Object.entries(res).sort((a, b) => a[0].localeCompare(b[0]));
|
keys = Object.entries(res).sort((a, b) => a[0].localeCompare(b[0]));
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<FormSplit>
|
<FormSplit>
|
||||||
<MkKeyValue>
|
<MkKeyValue>
|
||||||
<template #key>{{ i18n.ts._registry.domain }}</template>
|
<template #key>{{ i18n.ts._registry.domain }}</template>
|
||||||
<template #value>{{ props.domain === '@' ? i18n.ts.system : props.domain.toUpperCase() }}</template>
|
<template #value>{{ i18n.ts.system }}</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<MkKeyValue>
|
<MkKeyValue>
|
||||||
<template #key>{{ i18n.ts._registry.scope }}</template>
|
<template #key>{{ i18n.ts._registry.scope }}</template>
|
||||||
|
@ -58,7 +58,6 @@ import FormInfo from '@/components/MkInfo.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
path: string;
|
path: string;
|
||||||
domain: string;
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const scope = $computed(() => props.path.split('/').slice(0, -1));
|
const scope = $computed(() => props.path.split('/').slice(0, -1));
|
||||||
|
@ -71,7 +70,6 @@ function fetchValue() {
|
||||||
os.api('i/registry/get-detail', {
|
os.api('i/registry/get-detail', {
|
||||||
scope,
|
scope,
|
||||||
key,
|
key,
|
||||||
domain: props.domain === '@' ? null : props.domain,
|
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
value = res;
|
value = res;
|
||||||
valueForEditor = JSON5.stringify(res.value, null, '\t');
|
valueForEditor = JSON5.stringify(res.value, null, '\t');
|
||||||
|
@ -97,7 +95,6 @@ async function save() {
|
||||||
scope,
|
scope,
|
||||||
key,
|
key,
|
||||||
value: JSON5.parse(valueForEditor),
|
value: JSON5.parse(valueForEditor),
|
||||||
domain: props.domain === '@' ? null : props.domain,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -111,7 +108,6 @@ function del() {
|
||||||
os.apiWithDialog('i/registry/remove', {
|
os.apiWithDialog('i/registry/remove', {
|
||||||
scope,
|
scope,
|
||||||
key,
|
key,
|
||||||
domain: props.domain === '@' ? null : props.domain,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSpacer :contentMax="600" :marginMin="16">
|
<MkSpacer :contentMax="600" :marginMin="16">
|
||||||
<MkButton primary @click="createKey">{{ i18n.ts._registry.createKey }}</MkButton>
|
<MkButton primary @click="createKey">{{ i18n.ts._registry.createKey }}</MkButton>
|
||||||
|
|
||||||
<div v-if="scopesWithDomain" class="_gaps_m">
|
<FormSection v-if="scopes">
|
||||||
<FormSection v-for="domain in scopesWithDomain" :key="domain.domain">
|
<template #label>{{ i18n.ts.system }}</template>
|
||||||
<template #label>{{ domain.domain ? domain.domain.toUpperCase() : i18n.ts.system }}</template>
|
<div class="_formLinks">
|
||||||
<div class="_gaps_s">
|
<FormLink v-for="scope in scopes" :to="`/registry/keys/system/${scope.join('/')}`" class="_monospace">{{ scope.join('/') }}</FormLink>
|
||||||
<FormLink v-for="scope in domain.scopes" :to="`/registry/keys/${domain.domain ?? '@'}/${scope.join('/')}`" class="_monospace">{{ scope.length === 0 ? '(root)' : scope.join('/') }}</FormLink>
|
</div>
|
||||||
</div>
|
</FormSection>
|
||||||
</FormSection>
|
|
||||||
</div>
|
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</template>
|
</template>
|
||||||
|
@ -30,11 +28,11 @@ import FormLink from '@/components/form/link.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
|
||||||
let scopesWithDomain = $ref(null);
|
let scopes = $ref(null);
|
||||||
|
|
||||||
function fetchScopes() {
|
function fetchScopes() {
|
||||||
os.api('i/registry/scopes-with-domain').then(res => {
|
os.api('i/registry/scopes').then(res => {
|
||||||
scopesWithDomain = res;
|
scopes = res.slice().sort((a, b) => a.join('/').localeCompare(b.join('/')));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AsyncComponentLoader, defineAsyncComponent, inject } from 'vue';
|
import { AsyncComponentLoader, defineAsyncComponent, inject } from 'vue';
|
||||||
import { Router } from '@/nirax.js';
|
import { Router } from '@/nirax';
|
||||||
import { $i, iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
import MkLoading from '@/pages/_loading_.vue';
|
import MkLoading from '@/pages/_loading_.vue';
|
||||||
import MkError from '@/pages/_error_.vue';
|
import MkError from '@/pages/_error_.vue';
|
||||||
|
@ -318,10 +318,10 @@ export const routes = [{
|
||||||
name: 'avatarDecorations',
|
name: 'avatarDecorations',
|
||||||
component: page(() => import('./pages/avatar-decorations.vue')),
|
component: page(() => import('./pages/avatar-decorations.vue')),
|
||||||
}, {
|
}, {
|
||||||
path: '/registry/keys/:domain/:path(*)?',
|
path: '/registry/keys/system/:path(*)?',
|
||||||
component: page(() => import('./pages/registry.keys.vue')),
|
component: page(() => import('./pages/registry.keys.vue')),
|
||||||
}, {
|
}, {
|
||||||
path: '/registry/value/:domain/:path(*)?',
|
path: '/registry/value/system/:path(*)?',
|
||||||
component: page(() => import('./pages/registry.value.vue')),
|
component: page(() => import('./pages/registry.value.vue')),
|
||||||
}, {
|
}, {
|
||||||
path: '/registry',
|
path: '/registry',
|
||||||
|
|
|
@ -344,6 +344,12 @@ hr {
|
||||||
grid-gap: 12px;
|
grid-gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
._formLinks {
|
||||||
|
> *:not(:last-child) {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
._beta {
|
._beta {
|
||||||
margin-left: 0.7em;
|
margin-left: 0.7em;
|
||||||
font-size: 65%;
|
font-size: 65%;
|
||||||
|
|
|
@ -1482,6 +1482,10 @@ export type Endpoints = {
|
||||||
};
|
};
|
||||||
res: null;
|
res: null;
|
||||||
};
|
};
|
||||||
|
'i/registry/scopes': {
|
||||||
|
req: NoParams;
|
||||||
|
res: string[][];
|
||||||
|
};
|
||||||
'i/registry/set': {
|
'i/registry/set': {
|
||||||
req: {
|
req: {
|
||||||
key: string;
|
key: string;
|
||||||
|
@ -3019,7 +3023,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
|
||||||
//
|
//
|
||||||
// src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts
|
// src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts
|
||||||
// src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
|
// src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
|
||||||
// src/api.types.ts:632:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
|
// src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
|
||||||
// src/entities.ts:116:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
|
// src/entities.ts:116:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
|
||||||
// src/entities.ts:612:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
|
// src/entities.ts:612:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
|
||||||
// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts
|
// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts
|
||||||
|
|
|
@ -399,6 +399,7 @@ export type Endpoints = {
|
||||||
'i/registry/keys-with-type': { req: { scope?: string[]; }; res: Record<string, 'null' | 'array' | 'number' | 'string' | 'boolean' | 'object'>; };
|
'i/registry/keys-with-type': { req: { scope?: string[]; }; res: Record<string, 'null' | 'array' | 'number' | 'string' | 'boolean' | 'object'>; };
|
||||||
'i/registry/keys': { req: { scope?: string[]; }; res: string[]; };
|
'i/registry/keys': { req: { scope?: string[]; }; res: string[]; };
|
||||||
'i/registry/remove': { req: { key: string; scope?: string[]; }; res: null; };
|
'i/registry/remove': { req: { key: string; scope?: string[]; }; res: null; };
|
||||||
|
'i/registry/scopes': { req: NoParams; res: string[][]; };
|
||||||
'i/registry/set': { req: { key: string; value: any; scope?: string[]; }; res: null; };
|
'i/registry/set': { req: { key: string; value: any; scope?: string[]; }; res: null; };
|
||||||
'i/revoke-token': { req: TODO; res: TODO; };
|
'i/revoke-token': { req: TODO; res: TODO; };
|
||||||
'i/signin-history': { req: { limit?: number; sinceId?: Signin['id']; untilId?: Signin['id']; }; res: Signin[]; };
|
'i/signin-history': { req: { limit?: number; sinceId?: Signin['id']; untilId?: Signin['id']; }; res: Signin[]; };
|
||||||
|
|
Loading…
Reference in a new issue