diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-01-11 20:38:34 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-11 20:38:34 +0900 |
| commit | 6c975275f82c79eed2c7757d55283c95d23ca5b8 (patch) | |
| tree | 2871e4c3a1a67295ea5c3e19b9136ae79a17088c /src/server/api | |
| parent | fix context menu (diff) | |
| download | sharkey-6c975275f82c79eed2c7757d55283c95d23ca5b8.tar.gz sharkey-6c975275f82c79eed2c7757d55283c95d23ca5b8.tar.bz2 sharkey-6c975275f82c79eed2c7757d55283c95d23ca5b8.zip | |
Registry (#7073)
* wip
* wip
* wip
* wip
* wip
* Update registry.value.vue
* wip
* wip
* wip
* wip
* typo
Diffstat (limited to 'src/server/api')
| -rw-r--r-- | src/server/api/api-handler.ts | 5 | ||||
| -rw-r--r-- | src/server/api/endpoints/i.ts | 25 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/notifications.ts | 2 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/get-all.ts | 33 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/get-detail.ts | 48 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/get.ts | 45 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/keys-with-type.ts | 41 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/keys.ts | 28 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/remove.ts | 45 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/scopes.ts | 30 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/registry/set.ts | 61 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/update-client-setting.ts | 40 |
12 files changed, 359 insertions, 44 deletions
diff --git a/src/server/api/api-handler.ts b/src/server/api/api-handler.ts index 7fbc200fc0..80a4fd97c8 100644 --- a/src/server/api/api-handler.ts +++ b/src/server/api/api-handler.ts @@ -11,7 +11,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { const reply = (x?: any, y?: ApiError) => { if (x == null) { ctx.status = 204; - } else if (typeof x === 'number') { + } else if (typeof x === 'number' && y) { ctx.status = x; ctx.body = { error: { @@ -23,7 +23,8 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { } }; } else { - ctx.body = x; + // 文字列を返す場合は、JSON.stringify通さないとJSONと認識されない + ctx.body = typeof x === 'string' ? JSON.stringify(x) : x; } res(); }; diff --git a/src/server/api/endpoints/i.ts b/src/server/api/endpoints/i.ts index bceb9548ef..3d0c092adb 100644 --- a/src/server/api/endpoints/i.ts +++ b/src/server/api/endpoints/i.ts @@ -1,5 +1,7 @@ import define from '../define'; -import { Users } from '../../../models'; +import { RegistryItems, UserProfiles, Users } from '../../../models'; +import { ensure } from '../../../prelude/ensure'; +import { genId } from '../../../misc/gen-id'; export const meta = { desc: { @@ -22,6 +24,27 @@ export const meta = { export default define(meta, async (ps, user, token) => { const isSecure = token == null; + // TODO: そのうち消す + const profile = await UserProfiles.findOne(user.id).then(ensure); + for (const [k, v] of Object.entries(profile.clientData)) { + await RegistryItems.insert({ + id: genId(), + createdAt: new Date(), + updatedAt: new Date(), + userId: user.id, + domain: null, + scope: ['client', 'base'], + key: k, + value: v + }); + } + await UserProfiles.createQueryBuilder().update() + .set({ + clientData: {}, + }) + .where('userId = :id', { id: user.id }) + .execute(); + return await Users.pack(user, user, { detail: true, includeSecrets: isSecure diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts index fd355dab83..0e09bc73fd 100644 --- a/src/server/api/endpoints/i/notifications.ts +++ b/src/server/api/endpoints/i/notifications.ts @@ -80,7 +80,7 @@ export default define(meta, async (ps, user) => { .where('muting.muterId = :muterId', { muterId: user.id }); const suspendedQuery = Users.createQueryBuilder('users') - .select('id') + .select('users.id') .where('users.isSuspended = TRUE'); const query = makePaginationQuery(Notifications.createQueryBuilder('notification'), ps.sinceId, ps.untilId) diff --git a/src/server/api/endpoints/i/registry/get-all.ts b/src/server/api/endpoints/i/registry/get-all.ts new file mode 100644 index 0000000000..ce8653f22b --- /dev/null +++ b/src/server/api/endpoints/i/registry/get-all.ts @@ -0,0 +1,33 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + scope: { + validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), + default: [], + }, + } +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.id }) + .andWhere('item.scope = :scope', { scope: ps.scope }); + + const items = await query.getMany(); + + const res = {} as Record<string, any>; + + for (const item of items) { + res[item.key] = item.value; + } + + return res; +}); diff --git a/src/server/api/endpoints/i/registry/get-detail.ts b/src/server/api/endpoints/i/registry/get-detail.ts new file mode 100644 index 0000000000..441833d3d7 --- /dev/null +++ b/src/server/api/endpoints/i/registry/get-detail.ts @@ -0,0 +1,48 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; +import { ApiError } from '../../../error'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + key: { + validator: $.str + }, + + scope: { + validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), + default: [], + }, + }, + + errors: { + noSuchKey: { + message: 'No such key.', + code: 'NO_SUCH_KEY', + id: '97a1e8e7-c0f7-47d2-957a-92e61256e01a' + }, + }, +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.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); + } + + return { + updatedAt: item.updatedAt, + value: item.value, + }; +}); diff --git a/src/server/api/endpoints/i/registry/get.ts b/src/server/api/endpoints/i/registry/get.ts new file mode 100644 index 0000000000..275e660cb6 --- /dev/null +++ b/src/server/api/endpoints/i/registry/get.ts @@ -0,0 +1,45 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; +import { ApiError } from '../../../error'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + key: { + validator: $.str + }, + + scope: { + validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), + default: [], + }, + }, + + errors: { + noSuchKey: { + message: 'No such key.', + code: 'NO_SUCH_KEY', + id: 'ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a' + }, + }, +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.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); + } + + return item.value; +}); diff --git a/src/server/api/endpoints/i/registry/keys-with-type.ts b/src/server/api/endpoints/i/registry/keys-with-type.ts new file mode 100644 index 0000000000..06d77acbeb --- /dev/null +++ b/src/server/api/endpoints/i/registry/keys-with-type.ts @@ -0,0 +1,41 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + scope: { + validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), + default: [], + }, + } +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.id }) + .andWhere('item.scope = :scope', { scope: ps.scope }); + + const items = await query.getMany(); + + const res = {} as Record<string, string>; + + for (const item of items) { + const type = typeof item.value; + res[item.key] = + item.value === null ? 'null' : + Array.isArray(item.value) ? 'array' : + type === 'number' ? 'number' : + type === 'string' ? 'string' : + type === 'boolean' ? 'boolean' : + type === 'object' ? 'object' : + null as never; + } + + return res; +}); diff --git a/src/server/api/endpoints/i/registry/keys.ts b/src/server/api/endpoints/i/registry/keys.ts new file mode 100644 index 0000000000..e4dd5044b4 --- /dev/null +++ b/src/server/api/endpoints/i/registry/keys.ts @@ -0,0 +1,28 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + scope: { + validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), + default: [], + }, + } +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .select('item.key') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.id }) + .andWhere('item.scope = :scope', { scope: ps.scope }); + + const items = await query.getMany(); + + return items.map(x => x.key); +}); diff --git a/src/server/api/endpoints/i/registry/remove.ts b/src/server/api/endpoints/i/registry/remove.ts new file mode 100644 index 0000000000..e73444efd2 --- /dev/null +++ b/src/server/api/endpoints/i/registry/remove.ts @@ -0,0 +1,45 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; +import { ApiError } from '../../../error'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + key: { + validator: $.str + }, + + scope: { + validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), + default: [], + }, + }, + + errors: { + noSuchKey: { + message: 'No such key.', + code: 'NO_SUCH_KEY', + id: '1fac4e8a-a6cd-4e39-a4a5-3a7e11f1b019' + }, + }, +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.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); + } + + RegistryItems.remove(item); +}); diff --git a/src/server/api/endpoints/i/registry/scopes.ts b/src/server/api/endpoints/i/registry/scopes.ts new file mode 100644 index 0000000000..8b0e1a7fd8 --- /dev/null +++ b/src/server/api/endpoints/i/registry/scopes.ts @@ -0,0 +1,30 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + } +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .select('item.scope') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.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; +}); diff --git a/src/server/api/endpoints/i/registry/set.ts b/src/server/api/endpoints/i/registry/set.ts new file mode 100644 index 0000000000..c732cfc8f5 --- /dev/null +++ b/src/server/api/endpoints/i/registry/set.ts @@ -0,0 +1,61 @@ +import $ from 'cafy'; +import { publishMainStream } from '../../../../../services/stream'; +import define from '../../../define'; +import { RegistryItems } from '../../../../../models'; +import { genId } from '../../../../../misc/gen-id'; + +export const meta = { + requireCredential: true as const, + + secure: true, + + params: { + key: { + validator: $.str.min(1) + }, + + value: { + validator: $.nullable.any + }, + + scope: { + validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), + default: [], + }, + } +}; + +export default define(meta, async (ps, user) => { + const query = RegistryItems.createQueryBuilder('item') + .where('item.domain IS NULL') + .andWhere('item.userId = :userId', { userId: user.id }) + .andWhere('item.key = :key', { key: ps.key }) + .andWhere('item.scope = :scope', { scope: ps.scope }); + + const existingItem = await query.getOne(); + + if (existingItem) { + await RegistryItems.update(existingItem.id, { + updatedAt: new Date(), + value: ps.value + }); + } else { + await RegistryItems.insert({ + id: genId(), + createdAt: new Date(), + updatedAt: new Date(), + userId: user.id, + domain: null, + scope: ps.scope, + key: ps.key, + value: ps.value + }); + } + + // TODO: サードパーティアプリが傍受出来てしまうのでどうにかする + publishMainStream(user.id, 'registryUpdated', { + scope: ps.scope, + key: ps.key, + value: ps.value + }); +}); diff --git a/src/server/api/endpoints/i/update-client-setting.ts b/src/server/api/endpoints/i/update-client-setting.ts deleted file mode 100644 index 5143d3d9ba..0000000000 --- a/src/server/api/endpoints/i/update-client-setting.ts +++ /dev/null @@ -1,40 +0,0 @@ -import $ from 'cafy'; -import { publishMainStream } from '../../../../services/stream'; -import define from '../../define'; -import { UserProfiles } from '../../../../models'; -import { ensure } from '../../../../prelude/ensure'; - -export const meta = { - requireCredential: true as const, - - secure: true, - - params: { - name: { - validator: $.str.match(/^[a-zA-Z]+$/) - }, - - value: { - validator: $.nullable.any - } - } -}; - -export default define(meta, async (ps, user) => { - const profile = await UserProfiles.findOne(user.id).then(ensure); - - await UserProfiles.createQueryBuilder().update() - .set({ - clientData: Object.assign(profile.clientData, { - [ps.name]: ps.value - }), - }) - .where('userId = :id', { id: user.id }) - .execute(); - - // Publish event - publishMainStream(user.id, 'clientSettingUpdated', { - key: ps.name, - value: ps.value - }); -}); |