v12 (#5712)
Co-authored-by: MeiMei <30769358+mei23@users.noreply.github.com> Co-authored-by: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com>
This commit is contained in:
parent
a5955c1123
commit
f6154dc0af
871 changed files with 26140 additions and 71950 deletions
33
src/server/api/endpoints/admin/accounts/create.ts
Normal file
33
src/server/api/endpoints/admin/accounts/create.ts
Normal file
|
|
@ -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;
|
||||
});
|
||||
36
src/server/api/endpoints/admin/announcements/create.ts
Normal file
36
src/server/api/endpoints/admin/announcements/create.ts
Normal file
|
|
@ -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;
|
||||
});
|
||||
34
src/server/api/endpoints/admin/announcements/delete.ts
Normal file
34
src/server/api/endpoints/admin/announcements/delete.ts
Normal file
|
|
@ -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);
|
||||
});
|
||||
41
src/server/api/endpoints/admin/announcements/list.ts
Normal file
41
src/server/api/endpoints/admin/announcements/list.ts
Normal file
|
|
@ -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;
|
||||
});
|
||||
48
src/server/api/endpoints/admin/announcements/update.ts
Normal file
48
src/server/api/endpoints/admin/announcements/update.ts
Normal file
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
62
src/server/api/endpoints/admin/emoji/list-remote.ts
Normal file
62
src/server/api/endpoints/admin/emoji/list-remote.ts
Normal file
|
|
@ -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
|
||||
}));
|
||||
});
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
31
src/server/api/endpoints/admin/queue/deliver-delayed.ts
Normal file
31
src/server/api/endpoints/admin/queue/deliver-delayed.ts
Normal file
|
|
@ -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;
|
||||
});
|
||||
31
src/server/api/endpoints/admin/queue/inbox-delayed.ts
Normal file
31
src/server/api/endpoints/admin/queue/inbox-delayed.ts
Normal file
|
|
@ -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;
|
||||
});
|
||||
45
src/server/api/endpoints/admin/server-info.ts
Normal file
45
src/server/api/endpoints/admin/server-info.ts
Normal file
|
|
@ -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
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue