summaryrefslogtreecommitdiff
path: root/src/server/api/endpoints/admin
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/api/endpoints/admin')
-rw-r--r--src/server/api/endpoints/admin/accounts/create.ts33
-rw-r--r--src/server/api/endpoints/admin/announcements/create.ts36
-rw-r--r--src/server/api/endpoints/admin/announcements/delete.ts34
-rw-r--r--src/server/api/endpoints/admin/announcements/list.ts41
-rw-r--r--src/server/api/endpoints/admin/announcements/update.ts48
-rw-r--r--src/server/api/endpoints/admin/emoji/list-remote.ts62
-rw-r--r--src/server/api/endpoints/admin/emoji/list.ts32
-rw-r--r--src/server/api/endpoints/admin/queue/deliver-delayed.ts31
-rw-r--r--src/server/api/endpoints/admin/queue/inbox-delayed.ts31
-rw-r--r--src/server/api/endpoints/admin/server-info.ts45
-rw-r--r--src/server/api/endpoints/admin/update-meta.ts30
11 files changed, 384 insertions, 39 deletions
diff --git a/src/server/api/endpoints/admin/accounts/create.ts b/src/server/api/endpoints/admin/accounts/create.ts
new file mode 100644
index 0000000000..ac80b579b7
--- /dev/null
+++ b/src/server/api/endpoints/admin/accounts/create.ts
@@ -0,0 +1,33 @@
+import define from '../../../define';
+import { Users } from '../../../../../models';
+import { signup } from '../../../common/signup';
+
+export const meta = {
+ tags: ['admin'],
+
+ params: {
+ username: {
+ validator: Users.validateLocalUsername,
+ },
+
+ password: {
+ validator: Users.validatePassword,
+ }
+ }
+};
+
+export default define(meta, async (ps, me) => {
+ const noUsers = (await Users.count({})) === 0;
+ if (!noUsers && me == null) throw new Error('access denied');
+
+ const { account, secret } = await signup(ps.username, ps.password);
+
+ const res = await Users.pack(account, account, {
+ detail: true,
+ includeSecrets: true
+ });
+
+ (res as any).token = secret;
+
+ return res;
+});
diff --git a/src/server/api/endpoints/admin/announcements/create.ts b/src/server/api/endpoints/admin/announcements/create.ts
new file mode 100644
index 0000000000..c1d48a7d38
--- /dev/null
+++ b/src/server/api/endpoints/admin/announcements/create.ts
@@ -0,0 +1,36 @@
+import $ from 'cafy';
+import define from '../../../define';
+import { Announcements } from '../../../../../models';
+import { genId } from '../../../../../misc/gen-id';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ title: {
+ validator: $.str.min(1)
+ },
+ text: {
+ validator: $.str.min(1)
+ },
+ imageUrl: {
+ validator: $.nullable.str.min(1)
+ }
+ }
+};
+
+export default define(meta, async (ps) => {
+ const announcement = await Announcements.save({
+ id: genId(),
+ createdAt: new Date(),
+ updatedAt: null,
+ title: ps.title,
+ text: ps.text,
+ imageUrl: ps.imageUrl,
+ });
+
+ return announcement;
+});
diff --git a/src/server/api/endpoints/admin/announcements/delete.ts b/src/server/api/endpoints/admin/announcements/delete.ts
new file mode 100644
index 0000000000..284b4bf549
--- /dev/null
+++ b/src/server/api/endpoints/admin/announcements/delete.ts
@@ -0,0 +1,34 @@
+import $ from 'cafy';
+import define from '../../../define';
+import { ID } from '../../../../../misc/cafy-id';
+import { Announcements } from '../../../../../models';
+import { ApiError } from '../../../error';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ id: {
+ validator: $.type(ID)
+ }
+ },
+
+ errors: {
+ noSuchAnnouncement: {
+ message: 'No such announcement.',
+ code: 'NO_SUCH_ANNOUNCEMENT',
+ id: 'ecad8040-a276-4e85-bda9-015a708d291e'
+ }
+ }
+};
+
+export default define(meta, async (ps, me) => {
+ const announcement = await Announcements.findOne(ps.id);
+
+ if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
+
+ await Announcements.delete(announcement.id);
+});
diff --git a/src/server/api/endpoints/admin/announcements/list.ts b/src/server/api/endpoints/admin/announcements/list.ts
new file mode 100644
index 0000000000..f4e622144e
--- /dev/null
+++ b/src/server/api/endpoints/admin/announcements/list.ts
@@ -0,0 +1,41 @@
+import $ from 'cafy';
+import { ID } from '../../../../../misc/cafy-id';
+import define from '../../../define';
+import { Announcements, AnnouncementReads } from '../../../../../models';
+import { makePaginationQuery } from '../../../common/make-pagination-query';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ limit: {
+ validator: $.optional.num.range(1, 100),
+ default: 10
+ },
+
+ sinceId: {
+ validator: $.optional.type(ID),
+ },
+
+ untilId: {
+ validator: $.optional.type(ID),
+ },
+ }
+};
+
+export default define(meta, async (ps) => {
+ const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
+
+ const announcements = await query.take(ps.limit!).getMany();
+
+ for (const announcement of announcements) {
+ (announcement as any).reads = await AnnouncementReads.count({
+ announcementId: announcement.id
+ });
+ }
+
+ return announcements;
+});
diff --git a/src/server/api/endpoints/admin/announcements/update.ts b/src/server/api/endpoints/admin/announcements/update.ts
new file mode 100644
index 0000000000..b65c3a4f93
--- /dev/null
+++ b/src/server/api/endpoints/admin/announcements/update.ts
@@ -0,0 +1,48 @@
+import $ from 'cafy';
+import define from '../../../define';
+import { ID } from '../../../../../misc/cafy-id';
+import { Announcements } from '../../../../../models';
+import { ApiError } from '../../../error';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ id: {
+ validator: $.type(ID)
+ },
+ title: {
+ validator: $.str.min(1)
+ },
+ text: {
+ validator: $.str.min(1)
+ },
+ imageUrl: {
+ validator: $.nullable.str.min(1)
+ }
+ },
+
+ errors: {
+ noSuchAnnouncement: {
+ message: 'No such announcement.',
+ code: 'NO_SUCH_ANNOUNCEMENT',
+ id: 'd3aae5a7-6372-4cb4-b61c-f511ffc2d7cc'
+ }
+ }
+};
+
+export default define(meta, async (ps, me) => {
+ const announcement = await Announcements.findOne(ps.id);
+
+ if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
+
+ await Announcements.update(announcement.id, {
+ updatedAt: new Date(),
+ title: ps.title,
+ text: ps.text,
+ imageUrl: ps.imageUrl,
+ });
+});
diff --git a/src/server/api/endpoints/admin/emoji/list-remote.ts b/src/server/api/endpoints/admin/emoji/list-remote.ts
new file mode 100644
index 0000000000..0a3e74c333
--- /dev/null
+++ b/src/server/api/endpoints/admin/emoji/list-remote.ts
@@ -0,0 +1,62 @@
+import $ from 'cafy';
+import define from '../../../define';
+import { Emojis } from '../../../../../models';
+import { toPuny } from '../../../../../misc/convert-host';
+import { makePaginationQuery } from '../../../common/make-pagination-query';
+import { ID } from '../../../../../misc/cafy-id';
+
+export const meta = {
+ desc: {
+ 'ja-JP': 'カスタム絵文字を取得します。'
+ },
+
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ host: {
+ validator: $.optional.nullable.str,
+ default: null as any
+ },
+
+ limit: {
+ validator: $.optional.num.range(1, 100),
+ default: 10
+ },
+
+ sinceId: {
+ validator: $.optional.type(ID),
+ },
+
+ untilId: {
+ validator: $.optional.type(ID),
+ }
+ }
+};
+
+export default define(meta, async (ps) => {
+ const q = makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId);
+
+ if (ps.host == null) {
+ q.andWhere(`emoji.host IS NOT NULL`);
+ } else {
+ q.andWhere(`emoji.host = :host`, { host: toPuny(ps.host) });
+ }
+
+ const emojis = await q
+ .orderBy('emoji.category', 'ASC')
+ .orderBy('emoji.name', 'ASC')
+ .take(ps.limit!)
+ .getMany();
+
+ return emojis.map(e => ({
+ id: e.id,
+ name: e.name,
+ category: e.category,
+ aliases: e.aliases,
+ host: e.host,
+ url: e.url
+ }));
+});
diff --git a/src/server/api/endpoints/admin/emoji/list.ts b/src/server/api/endpoints/admin/emoji/list.ts
index d2a5e7df0d..d525a659c0 100644
--- a/src/server/api/endpoints/admin/emoji/list.ts
+++ b/src/server/api/endpoints/admin/emoji/list.ts
@@ -1,7 +1,8 @@
import $ from 'cafy';
import define from '../../../define';
import { Emojis } from '../../../../../models';
-import { toPunyNullable } from '../../../../../misc/convert-host';
+import { makePaginationQuery } from '../../../common/make-pagination-query';
+import { ID } from '../../../../../misc/cafy-id';
export const meta = {
desc: {
@@ -14,23 +15,28 @@ export const meta = {
requireModerator: true,
params: {
- host: {
- validator: $.optional.nullable.str,
- default: null as any
+ limit: {
+ validator: $.optional.num.range(1, 100),
+ default: 10
+ },
+
+ sinceId: {
+ validator: $.optional.type(ID),
+ },
+
+ untilId: {
+ validator: $.optional.type(ID),
}
}
};
export default define(meta, async (ps) => {
- const emojis = await Emojis.find({
- where: {
- host: toPunyNullable(ps.host)
- },
- order: {
- category: 'ASC',
- name: 'ASC'
- }
- });
+ const emojis = await makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId)
+ .andWhere(`emoji.host IS NULL`)
+ .orderBy('emoji.category', 'ASC')
+ .orderBy('emoji.name', 'ASC')
+ .take(ps.limit!)
+ .getMany();
return emojis.map(e => ({
id: e.id,
diff --git a/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/src/server/api/endpoints/admin/queue/deliver-delayed.ts
new file mode 100644
index 0000000000..d33837c099
--- /dev/null
+++ b/src/server/api/endpoints/admin/queue/deliver-delayed.ts
@@ -0,0 +1,31 @@
+import define from '../../../define';
+import { deliverQueue } from '../../../../../queue';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ }
+};
+
+export default define(meta, async (ps) => {
+ const jobs = await deliverQueue.getJobs(['delayed']);
+
+ const res = [] as [string, number][];
+
+ for (const job of jobs) {
+ const host = new URL(job.data.to).host;
+ if (res.find(x => x[0] === host)) {
+ res.find(x => x[0] === host)![1]++;
+ } else {
+ res.push([host, 1]);
+ }
+ }
+
+ res.sort((a, b) => b[1] - a[1]);
+
+ return res;
+});
diff --git a/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/src/server/api/endpoints/admin/queue/inbox-delayed.ts
new file mode 100644
index 0000000000..643e22f10d
--- /dev/null
+++ b/src/server/api/endpoints/admin/queue/inbox-delayed.ts
@@ -0,0 +1,31 @@
+import define from '../../../define';
+import { inboxQueue } from '../../../../../queue';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ }
+};
+
+export default define(meta, async (ps) => {
+ const jobs = await inboxQueue.getJobs(['delayed']);
+
+ const res = [] as [string, number][];
+
+ for (const job of jobs) {
+ const host = new URL(job.data.signature.keyId).host;
+ if (res.find(x => x[0] === host)) {
+ res.find(x => x[0] === host)![1]++;
+ } else {
+ res.push([host, 1]);
+ }
+ }
+
+ res.sort((a, b) => b[1] - a[1]);
+
+ return res;
+});
diff --git a/src/server/api/endpoints/admin/server-info.ts b/src/server/api/endpoints/admin/server-info.ts
new file mode 100644
index 0000000000..f51040a2c8
--- /dev/null
+++ b/src/server/api/endpoints/admin/server-info.ts
@@ -0,0 +1,45 @@
+import * as os from 'os';
+import * as si from 'systeminformation';
+import { getConnection } from 'typeorm';
+import define from '../../define';
+import redis from '../../../../db/redis';
+
+export const meta = {
+ requireCredential: false,
+
+ desc: {
+ },
+
+ tags: ['meta'],
+
+ params: {
+ },
+};
+
+export default define(meta, async () => {
+ const memStats = await si.mem();
+ const fsStats = await si.fsSize();
+ const netInterface = await si.networkInterfaceDefault();
+
+ return {
+ machine: os.hostname(),
+ os: os.platform(),
+ node: process.version,
+ psql: await getConnection().query('SHOW server_version').then(x => x[0].server_version),
+ redis: redis.server_info.redis_version,
+ cpu: {
+ model: os.cpus()[0].model,
+ cores: os.cpus().length
+ },
+ mem: {
+ total: memStats.total
+ },
+ fs: {
+ total: fsStats[0].size,
+ used: fsStats[0].used,
+ },
+ net: {
+ interface: netInterface
+ }
+ };
+});
diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts
index bc37228d0a..65650f1295 100644
--- a/src/server/api/endpoints/admin/update-meta.ts
+++ b/src/server/api/endpoints/admin/update-meta.ts
@@ -13,16 +13,9 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
- requireModerator: true,
+ requireAdmin: true,
params: {
- announcements: {
- validator: $.optional.nullable.arr($.obj()),
- desc: {
- 'ja-JP': 'お知らせ'
- }
- },
-
disableRegistration: {
validator: $.optional.nullable.bool,
desc: {
@@ -44,13 +37,6 @@ export const meta = {
}
},
- enableEmojiReaction: {
- validator: $.optional.nullable.bool,
- desc: {
- 'ja-JP': '絵文字リアクションを有効にするか否か'
- }
- },
-
useStarForReactionFallback: {
validator: $.optional.nullable.bool,
desc: {
@@ -347,7 +333,7 @@ export const meta = {
}
},
- ToSUrl: {
+ tosUrl: {
validator: $.optional.nullable.str,
desc: {
'ja-JP': '利用規約のURL'
@@ -413,10 +399,6 @@ export const meta = {
export default define(meta, async (ps, me) => {
const set = {} as Partial<Meta>;
- if (ps.announcements) {
- set.announcements = ps.announcements;
- }
-
if (typeof ps.disableRegistration === 'boolean') {
set.disableRegistration = ps.disableRegistration;
}
@@ -429,10 +411,6 @@ export default define(meta, async (ps, me) => {
set.disableGlobalTimeline = ps.disableGlobalTimeline;
}
- if (typeof ps.enableEmojiReaction === 'boolean') {
- set.enableEmojiReaction = ps.enableEmojiReaction;
- }
-
if (typeof ps.useStarForReactionFallback === 'boolean') {
set.useStarForReactionFallback = ps.useStarForReactionFallback;
}
@@ -601,8 +579,8 @@ export default define(meta, async (ps, me) => {
set.swPrivateKey = ps.swPrivateKey;
}
- if (ps.ToSUrl !== undefined) {
- set.ToSUrl = ps.ToSUrl;
+ if (ps.tosUrl !== undefined) {
+ set.ToSUrl = ps.tosUrl;
}
if (ps.repositoryUrl !== undefined) {