parent
7be4b2145b
commit
58e83f8e4f
24 changed files with 146 additions and 46 deletions
|
@ -12,6 +12,7 @@ You should also include the user name that made the change.
|
||||||
## 12.x.x (unreleased)
|
## 12.x.x (unreleased)
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
- Server: Allow GET method for some endpoints @syuilo
|
||||||
- Server: Add rate limit to i/notifications @tamaina
|
- Server: Add rate limit to i/notifications @tamaina
|
||||||
- Client: Improve control panel @syuilo
|
- Client: Improve control panel @syuilo
|
||||||
- Client: Show warning in control panel when there is an unresolved abuse report @syuilo
|
- Client: Show warning in control panel when there is an unresolved abuse report @syuilo
|
||||||
|
|
|
@ -6,7 +6,11 @@ import call from './call.js';
|
||||||
import { ApiError } from './error.js';
|
import { ApiError } from './error.js';
|
||||||
|
|
||||||
export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res) => {
|
export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res) => {
|
||||||
const body = ctx.request.body;
|
const body = ctx.is('multipart/form-data')
|
||||||
|
? (ctx.req as any).body
|
||||||
|
: ctx.method === 'GET'
|
||||||
|
? ctx.query
|
||||||
|
: ctx.request.body;
|
||||||
|
|
||||||
const reply = (x?: any, y?: ApiError) => {
|
const reply = (x?: any, y?: ApiError) => {
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
|
@ -33,6 +37,9 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res
|
||||||
authenticate(body['i']).then(([user, app]) => {
|
authenticate(body['i']).then(([user, app]) => {
|
||||||
// API invoking
|
// API invoking
|
||||||
call(endpoint.name, user, app, body, ctx).then((res: any) => {
|
call(endpoint.name, user, app, body, ctx).then((res: any) => {
|
||||||
|
if (ctx.method === 'GET' && endpoint.meta.cacheSec && !body['i'] && !user) {
|
||||||
|
ctx.set('Cache-Control', `public, max-age=${endpoint.meta.cacheSec}`);
|
||||||
|
}
|
||||||
reply(res);
|
reply(res);
|
||||||
}).catch((e: ApiError) => {
|
}).catch((e: ApiError) => {
|
||||||
reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e);
|
reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e);
|
||||||
|
|
|
@ -94,7 +94,7 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast non JSON input
|
// Cast non JSON input
|
||||||
if (ep.meta.requireFile && ep.params.properties) {
|
if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) {
|
||||||
for (const k of Object.keys(ep.params.properties)) {
|
for (const k of Object.keys(ep.params.properties)) {
|
||||||
const param = ep.params.properties![k];
|
const param = ep.params.properties![k];
|
||||||
if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') {
|
if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') {
|
||||||
|
|
|
@ -701,6 +701,16 @@ export interface IEndpointMeta {
|
||||||
readonly kind?: string;
|
readonly kind?: string;
|
||||||
|
|
||||||
readonly description?: string;
|
readonly description?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GETでのリクエストを許容するか否か
|
||||||
|
*/
|
||||||
|
readonly allowGet?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常応答をキャッシュ (Cache-Control: public) する秒数
|
||||||
|
*/
|
||||||
|
readonly cacheSec?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEndpoint {
|
export interface IEndpoint {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { activeUsersChart } from '@/services/chart/index.js';
|
import { activeUsersChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'users'],
|
tags: ['charts', 'users'],
|
||||||
|
|
||||||
res: getJsonSchema(activeUsersChart.schema),
|
res: getJsonSchema(activeUsersChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { apRequestChart } from '@/services/chart/index.js';
|
import { apRequestChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts'],
|
tags: ['charts'],
|
||||||
|
|
||||||
res: getJsonSchema(apRequestChart.schema),
|
res: getJsonSchema(apRequestChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { driveChart } from '@/services/chart/index.js';
|
import { driveChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'drive'],
|
tags: ['charts', 'drive'],
|
||||||
|
|
||||||
res: getJsonSchema(driveChart.schema),
|
res: getJsonSchema(driveChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { federationChart } from '@/services/chart/index.js';
|
import { federationChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts'],
|
tags: ['charts'],
|
||||||
|
|
||||||
res: getJsonSchema(federationChart.schema),
|
res: getJsonSchema(federationChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { hashtagChart } from '@/services/chart/index.js';
|
import { hashtagChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'hashtags'],
|
tags: ['charts', 'hashtags'],
|
||||||
|
|
||||||
res: getJsonSchema(hashtagChart.schema),
|
res: getJsonSchema(hashtagChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { instanceChart } from '@/services/chart/index.js';
|
import { instanceChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts'],
|
tags: ['charts'],
|
||||||
|
|
||||||
res: getJsonSchema(instanceChart.schema),
|
res: getJsonSchema(instanceChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { notesChart } from '@/services/chart/index.js';
|
import { notesChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'notes'],
|
tags: ['charts', 'notes'],
|
||||||
|
|
||||||
res: getJsonSchema(notesChart.schema),
|
res: getJsonSchema(notesChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { perUserDriveChart } from '@/services/chart/index.js';
|
import { perUserDriveChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'drive', 'users'],
|
tags: ['charts', 'drive', 'users'],
|
||||||
|
|
||||||
res: getJsonSchema(perUserDriveChart.schema),
|
res: getJsonSchema(perUserDriveChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -6,6 +6,9 @@ export const meta = {
|
||||||
tags: ['charts', 'users', 'following'],
|
tags: ['charts', 'users', 'following'],
|
||||||
|
|
||||||
res: getJsonSchema(perUserFollowingChart.schema),
|
res: getJsonSchema(perUserFollowingChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { perUserNotesChart } from '@/services/chart/index.js';
|
import { perUserNotesChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'users', 'notes'],
|
tags: ['charts', 'users', 'notes'],
|
||||||
|
|
||||||
res: getJsonSchema(perUserNotesChart.schema),
|
res: getJsonSchema(perUserNotesChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { perUserReactionsChart } from '@/services/chart/index.js';
|
import { perUserReactionsChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'users', 'reactions'],
|
tags: ['charts', 'users', 'reactions'],
|
||||||
|
|
||||||
res: getJsonSchema(perUserReactionsChart.schema),
|
res: getJsonSchema(perUserReactionsChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import define from '../../define.js';
|
|
||||||
import { getJsonSchema } from '@/services/chart/core.js';
|
import { getJsonSchema } from '@/services/chart/core.js';
|
||||||
import { usersChart } from '@/services/chart/index.js';
|
import { usersChart } from '@/services/chart/index.js';
|
||||||
|
import define from '../../define.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['charts', 'users'],
|
tags: ['charts', 'users'],
|
||||||
|
|
||||||
res: getJsonSchema(usersChart.schema),
|
res: getJsonSchema(usersChart.schema),
|
||||||
|
|
||||||
|
allowGet: true,
|
||||||
|
cacheSec: 60 * 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -8,6 +8,8 @@ import multer from '@koa/multer';
|
||||||
import bodyParser from 'koa-bodyparser';
|
import bodyParser from 'koa-bodyparser';
|
||||||
import cors from '@koa/cors';
|
import cors from '@koa/cors';
|
||||||
|
|
||||||
|
import { Instances, AccessTokens, Users } from '@/models/index.js';
|
||||||
|
import config from '@/config/index.js';
|
||||||
import endpoints from './endpoints.js';
|
import endpoints from './endpoints.js';
|
||||||
import handler from './api-handler.js';
|
import handler from './api-handler.js';
|
||||||
import signup from './private/signup.js';
|
import signup from './private/signup.js';
|
||||||
|
@ -16,8 +18,6 @@ import signupPending from './private/signup-pending.js';
|
||||||
import discord from './service/discord.js';
|
import discord from './service/discord.js';
|
||||||
import github from './service/github.js';
|
import github from './service/github.js';
|
||||||
import twitter from './service/twitter.js';
|
import twitter from './service/twitter.js';
|
||||||
import { Instances, AccessTokens, Users } from '@/models/index.js';
|
|
||||||
import config from '@/config/index.js';
|
|
||||||
|
|
||||||
// Init app
|
// Init app
|
||||||
const app = new Koa();
|
const app = new Koa();
|
||||||
|
@ -56,11 +56,24 @@ for (const endpoint of endpoints) {
|
||||||
if (endpoint.meta.requireFile) {
|
if (endpoint.meta.requireFile) {
|
||||||
router.post(`/${endpoint.name}`, upload.single('file'), handler.bind(null, endpoint));
|
router.post(`/${endpoint.name}`, upload.single('file'), handler.bind(null, endpoint));
|
||||||
} else {
|
} else {
|
||||||
|
// 後方互換性のため
|
||||||
if (endpoint.name.includes('-')) {
|
if (endpoint.name.includes('-')) {
|
||||||
// 後方互換性のため
|
|
||||||
router.post(`/${endpoint.name.replace(/-/g, '_')}`, handler.bind(null, endpoint));
|
router.post(`/${endpoint.name.replace(/-/g, '_')}`, handler.bind(null, endpoint));
|
||||||
|
|
||||||
|
if (endpoint.meta.allowGet) {
|
||||||
|
router.get(`/${endpoint.name.replace(/-/g, '_')}`, handler.bind(null, endpoint));
|
||||||
|
} else {
|
||||||
|
router.get(`/${endpoint.name.replace(/-/g, '_')}`, async ctx => { ctx.status = 405; });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
router.post(`/${endpoint.name}`, handler.bind(null, endpoint));
|
router.post(`/${endpoint.name}`, handler.bind(null, endpoint));
|
||||||
|
|
||||||
|
if (endpoint.meta.allowGet) {
|
||||||
|
router.get(`/${endpoint.name}`, handler.bind(null, endpoint));
|
||||||
|
} else {
|
||||||
|
router.get(`/${endpoint.name}`, async ctx => { ctx.status = 405; });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,7 @@ const exportData = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchFederationChart = async (): Promise<typeof chartData> => {
|
const fetchFederationChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/federation', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/federation', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Received',
|
name: 'Received',
|
||||||
|
@ -392,7 +392,7 @@ const fetchFederationChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchApRequestChart = async (): Promise<typeof chartData> => {
|
const fetchApRequestChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/ap-request', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/ap-request', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'In',
|
name: 'In',
|
||||||
|
@ -414,7 +414,7 @@ const fetchApRequestChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
|
const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/notes', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/notes', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'All',
|
name: 'All',
|
||||||
|
@ -461,7 +461,7 @@ const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchNotesTotalChart = async (): Promise<typeof chartData> => {
|
const fetchNotesTotalChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/notes', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/notes', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Combined',
|
name: 'Combined',
|
||||||
|
@ -480,7 +480,7 @@ const fetchNotesTotalChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
|
const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/users', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/users', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Combined',
|
name: 'Combined',
|
||||||
|
@ -508,7 +508,7 @@ const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchActiveUsersChart = async (): Promise<typeof chartData> => {
|
const fetchActiveUsersChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/active-users', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/active-users', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Read & Write',
|
name: 'Read & Write',
|
||||||
|
@ -560,7 +560,7 @@ const fetchActiveUsersChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchDriveChart = async (): Promise<typeof chartData> => {
|
const fetchDriveChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/drive', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/drive', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
bytes: true,
|
bytes: true,
|
||||||
series: [{
|
series: [{
|
||||||
|
@ -596,7 +596,7 @@ const fetchDriveChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchDriveFilesChart = async (): Promise<typeof chartData> => {
|
const fetchDriveFilesChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/drive', { limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/drive', { limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'All',
|
name: 'All',
|
||||||
|
@ -631,7 +631,7 @@ const fetchDriveFilesChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchInstanceRequestsChart = async (): Promise<typeof chartData> => {
|
const fetchInstanceRequestsChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'In',
|
name: 'In',
|
||||||
|
@ -653,7 +653,7 @@ const fetchInstanceRequestsChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchInstanceUsersChart = async (total: boolean): Promise<typeof chartData> => {
|
const fetchInstanceUsersChart = async (total: boolean): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Users',
|
name: 'Users',
|
||||||
|
@ -668,7 +668,7 @@ const fetchInstanceUsersChart = async (total: boolean): Promise<typeof chartData
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchInstanceNotesChart = async (total: boolean): Promise<typeof chartData> => {
|
const fetchInstanceNotesChart = async (total: boolean): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Notes',
|
name: 'Notes',
|
||||||
|
@ -683,7 +683,7 @@ const fetchInstanceNotesChart = async (total: boolean): Promise<typeof chartData
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchInstanceFfChart = async (total: boolean): Promise<typeof chartData> => {
|
const fetchInstanceFfChart = async (total: boolean): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Following',
|
name: 'Following',
|
||||||
|
@ -706,7 +706,7 @@ const fetchInstanceFfChart = async (total: boolean): Promise<typeof chartData> =
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchInstanceDriveUsageChart = async (total: boolean): Promise<typeof chartData> => {
|
const fetchInstanceDriveUsageChart = async (total: boolean): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
bytes: true,
|
bytes: true,
|
||||||
series: [{
|
series: [{
|
||||||
|
@ -722,7 +722,7 @@ const fetchInstanceDriveUsageChart = async (total: boolean): Promise<typeof char
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchInstanceDriveFilesChart = async (total: boolean): Promise<typeof chartData> => {
|
const fetchInstanceDriveFilesChart = async (total: boolean): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Drive files',
|
name: 'Drive files',
|
||||||
|
@ -737,7 +737,7 @@ const fetchInstanceDriveFilesChart = async (total: boolean): Promise<typeof char
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchPerUserNotesChart = async (): Promise<typeof chartData> => {
|
const fetchPerUserNotesChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [...(props.args.withoutAll ? [] : [{
|
series: [...(props.args.withoutAll ? [] : [{
|
||||||
name: 'All',
|
name: 'All',
|
||||||
|
@ -769,7 +769,7 @@ const fetchPerUserNotesChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchPerUserFollowingChart = async (): Promise<typeof chartData> => {
|
const fetchPerUserFollowingChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Local',
|
name: 'Local',
|
||||||
|
@ -784,7 +784,7 @@ const fetchPerUserFollowingChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchPerUserFollowersChart = async (): Promise<typeof chartData> => {
|
const fetchPerUserFollowersChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Local',
|
name: 'Local',
|
||||||
|
@ -799,7 +799,7 @@ const fetchPerUserFollowersChart = async (): Promise<typeof chartData> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchPerUserDriveChart = async (): Promise<typeof chartData> => {
|
const fetchPerUserDriveChart = async (): Promise<typeof chartData> => {
|
||||||
const raw = await os.api('charts/user/drive', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
const raw = await os.apiGet('charts/user/drive', { userId: props.args.user.id, limit: props.limit, span: props.span });
|
||||||
return {
|
return {
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Inc',
|
name: 'Inc',
|
||||||
|
|
|
@ -20,7 +20,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const chart = $ref(null);
|
const chart = $ref(null);
|
||||||
|
|
||||||
os.api('charts/instance', { host: props.instance.host, limit: 16, span: 'day' }).then(res => {
|
os.apiGet('charts/instance', { host: props.instance.host, limit: 16, span: 'day' }).then(res => {
|
||||||
chart = res;
|
chart = res;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -21,7 +21,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const chart = $ref(null);
|
const chart = $ref(null);
|
||||||
|
|
||||||
os.api('charts/user/notes', { userId: props.user.id, limit: 16, span: 'day' }).then(res => {
|
os.apiGet('charts/user/notes', { userId: props.user.id, limit: 16, span: 'day' }).then(res => {
|
||||||
chart = res;
|
chart = res;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -52,6 +52,39 @@ export const api = ((endpoint: string, data: Record<string, any> = {}, token?: s
|
||||||
return promise;
|
return promise;
|
||||||
}) as typeof apiClient.request;
|
}) as typeof apiClient.request;
|
||||||
|
|
||||||
|
export const apiGet = ((endpoint: string, data: Record<string, any> = {}) => {
|
||||||
|
pendingApiRequestsCount.value++;
|
||||||
|
|
||||||
|
const onFinally = () => {
|
||||||
|
pendingApiRequestsCount.value--;
|
||||||
|
};
|
||||||
|
|
||||||
|
const query = new URLSearchParams(data);
|
||||||
|
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
// Send request
|
||||||
|
fetch(`${apiUrl}/${endpoint}?${query}`, {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'omit',
|
||||||
|
cache: 'default',
|
||||||
|
}).then(async (res) => {
|
||||||
|
const body = res.status === 204 ? null : await res.json();
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
resolve(body);
|
||||||
|
} else if (res.status === 204) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(body.error);
|
||||||
|
}
|
||||||
|
}).catch(reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
promise.then(onFinally, onFinally);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}) as typeof apiClient.request;
|
||||||
|
|
||||||
export const apiWithDialog = ((
|
export const apiWithDialog = ((
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
data: Record<string, any> = {},
|
data: Record<string, any> = {},
|
||||||
|
|
|
@ -90,11 +90,11 @@ onMounted(async () => {
|
||||||
os.api('stats', {}).then(statsResponse => {
|
os.api('stats', {}).then(statsResponse => {
|
||||||
stats = statsResponse;
|
stats = statsResponse;
|
||||||
|
|
||||||
os.api('charts/users', { limit: 2, span: 'day' }).then(chart => {
|
os.apiGet('charts/users', { limit: 2, span: 'day' }).then(chart => {
|
||||||
usersComparedToThePrevDay = stats.originalUsersCount - chart.local.total[1];
|
usersComparedToThePrevDay = stats.originalUsersCount - chart.local.total[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
os.api('charts/notes', { limit: 2, span: 'day' }).then(chart => {
|
os.apiGet('charts/notes', { limit: 2, span: 'day' }).then(chart => {
|
||||||
notesComparedToThePrevDay = stats.originalNotesCount - chart.local.total[1];
|
notesComparedToThePrevDay = stats.originalNotesCount - chart.local.total[1];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||||
import { GetFormResultType } from '@/scripts/form';
|
|
||||||
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
||||||
import * as os from '@/os';
|
|
||||||
import MkContainer from '@/components/ui/container.vue';
|
|
||||||
import XCalendar from './activity.calendar.vue';
|
import XCalendar from './activity.calendar.vue';
|
||||||
import XChart from './activity.chart.vue';
|
import XChart from './activity.chart.vue';
|
||||||
|
import { GetFormResultType } from '@/scripts/form';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import MkContainer from '@/components/ui/container.vue';
|
||||||
import { $i } from '@/account';
|
import { $i } from '@/account';
|
||||||
|
|
||||||
const name = 'activity';
|
const name = 'activity';
|
||||||
|
@ -67,7 +67,7 @@ const toggleView = () => {
|
||||||
save();
|
save();
|
||||||
};
|
};
|
||||||
|
|
||||||
os.api('charts/user/notes', {
|
os.apiGet('charts/user/notes', {
|
||||||
userId: $i.id,
|
userId: $i.id,
|
||||||
span: 'day',
|
span: 'day',
|
||||||
limit: 7 * 21,
|
limit: 7 * 21,
|
||||||
|
@ -76,7 +76,7 @@ os.api('charts/user/notes', {
|
||||||
total: res.diffs.normal[i] + res.diffs.reply[i] + res.diffs.renote[i],
|
total: res.diffs.normal[i] + res.diffs.reply[i] + res.diffs.renote[i],
|
||||||
notes: res.diffs.normal[i],
|
notes: res.diffs.normal[i],
|
||||||
replies: res.diffs.reply[i],
|
replies: res.diffs.reply[i],
|
||||||
renotes: res.diffs.renote[i]
|
renotes: res.diffs.renote[i],
|
||||||
}));
|
}));
|
||||||
fetching.value = false;
|
fetching.value = false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, ref } from 'vue';
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
import { GetFormResultType } from '@/scripts/form';
|
|
||||||
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
||||||
|
import { GetFormResultType } from '@/scripts/form';
|
||||||
import MkContainer from '@/components/ui/container.vue';
|
import MkContainer from '@/components/ui/container.vue';
|
||||||
import MkMiniChart from '@/components/mini-chart.vue';
|
import MkMiniChart from '@/components/mini-chart.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
@ -56,9 +56,9 @@ const fetching = ref(true);
|
||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
const fetchedInstances = await os.api('federation/instances', {
|
const fetchedInstances = await os.api('federation/instances', {
|
||||||
sort: '+lastCommunicatedAt',
|
sort: '+lastCommunicatedAt',
|
||||||
limit: 5
|
limit: 5,
|
||||||
});
|
});
|
||||||
const fetchedCharts = await Promise.all(fetchedInstances.map(i => os.api('charts/instance', { host: i.host, limit: 16, span: 'hour' })));
|
const fetchedCharts = await Promise.all(fetchedInstances.map(i => os.apiGet('charts/instance', { host: i.host, limit: 16, span: 'hour' })));
|
||||||
instances.value = fetchedInstances;
|
instances.value = fetchedInstances;
|
||||||
charts.value = fetchedCharts;
|
charts.value = fetchedCharts;
|
||||||
fetching.value = false;
|
fetching.value = false;
|
||||||
|
|
Loading…
Reference in a new issue