This commit is contained in:
2022-02-03 01:42:58 +00:00
63 changed files with 1196 additions and 591 deletions

View File

@ -1,3 +1,3 @@
export function isDuplicateKeyValueError(e: Error): boolean {
return e.message.startsWith('duplicate key value');
export function isDuplicateKeyValueError(e: unknown | Error): boolean {
return (e as any).message && (e as Error).message.startsWith('duplicate key value');
}

View File

@ -32,7 +32,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => {
// Authentication
authenticate(body['i']).then(([user, app]) => {
// API invoking
call(endpoint.name, user, app, body, (ctx as any).file).then((res: any) => {
call(endpoint.name, user, app, body, ctx).then((res: any) => {
reply(res);
}).catch((e: ApiError) => {
reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e);

View File

@ -1,3 +1,4 @@
import * as Koa from 'koa';
import { performance } from 'perf_hooks';
import { limiter } from './limiter';
import { User } from '@/models/entities/user';
@ -12,7 +13,7 @@ const accessDenied = {
id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e',
};
export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, file?: any) => {
export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, ctx?: Koa.Context) => {
const isSecure = user != null && token == null;
const ep = endpoints.find(e => e.name === endpoint);
@ -76,9 +77,20 @@ export default async (endpoint: string, user: User | null | undefined, token: Ac
});
}
// Cast non JSON input
if (ep.meta.requireFile && ep.meta.params) {
const body = (ctx!.request as any).body;
for (const k of Object.keys(ep.meta.params)) {
const param = ep.meta.params[k];
if (['Boolean', 'Number'].includes(param.validator.name) && typeof body[k] === 'string') {
body[k] = JSON.parse(body[k]);
}
}
}
// API invoking
const before = performance.now();
return await ep.exec(data, user, token, file).catch((e: Error) => {
return await ep.exec(data, user, token, ctx?.file).catch((e: Error) => {
if (e instanceof ApiError) {
throw e;
} else {

View File

@ -39,15 +39,13 @@ export const meta = {
},
isSensitive: {
validator: $.optional.either($.bool, $.str),
validator: $.optional.bool,
default: false,
transform: (v: any): boolean => v === true || v === 'true',
},
force: {
validator: $.optional.either($.bool, $.str),
validator: $.optional.bool,
default: false,
transform: (v: any): boolean => v === true || v === 'true',
},
},

View File

@ -105,7 +105,10 @@ export interface NoteStreamTypes {
};
reacted: {
reaction: string;
emoji?: Emoji;
emoji?: {
name: string;
url: string;
} | null;
userId: User['id'];
};
unreacted: {

View File

@ -21,6 +21,7 @@ html
meta(name='referrer' content='origin')
meta(name='theme-color' content='#a7dc4e')
meta(name='theme-color-orig' content='#a7dc4e')
meta(property='twitter:card' content='summary')
meta(property='og:site_name' content= instanceName || 'Misskey')
meta(name='viewport' content='width=device-width, initial-scale=1')
link(rel='icon' href= icon || '/favicon.ico')
@ -42,7 +43,9 @@ html
block meta
block og
meta(property='og:image' content=img)
meta(property='og:title' content= title || 'Misskey')
meta(property='og:description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨')
meta(property='og:image' content= img)
style
include ../style.css

View File

@ -16,6 +16,3 @@ block og
meta(property='og:description' content= channel.description)
meta(property='og:url' content= url)
meta(property='og:image' content= channel.bannerUrl)
block meta
meta(name='twitter:card' content='summary')

View File

@ -26,8 +26,6 @@ block meta
meta(name='misskey:user-id' content=user.id)
meta(name='misskey:clip-id' content=clip.id)
meta(name='twitter:card' content='summary')
// todo
if user.twitter
meta(name='twitter:creator' content=`@${user.twitter.screenName}`)

View File

@ -25,8 +25,6 @@ block meta
meta(name='misskey:user-username' content=user.username)
meta(name='misskey:user-id' content=user.id)
meta(name='twitter:card' content='summary')
// todo
if user.twitter
meta(name='twitter:creator' content=`@${user.twitter.screenName}`)

View File

@ -26,9 +26,7 @@ block meta
meta(name='misskey:user-username' content=user.username)
meta(name='misskey:user-id' content=user.id)
meta(name='misskey:note-id' content=note.id)
meta(name='twitter:card' content='summary')
// todo
if user.twitter
meta(name='twitter:creator' content=`@${user.twitter.screenName}`)

View File

@ -26,8 +26,6 @@ block meta
meta(name='misskey:user-id' content=user.id)
meta(name='misskey:page-id' content=page.id)
meta(name='twitter:card' content='summary')
// todo
if user.twitter
meta(name='twitter:creator' content=`@${user.twitter.screenName}`)

View File

@ -25,8 +25,6 @@ block meta
meta(name='misskey:user-username' content=user.username)
meta(name='misskey:user-id' content=user.id)
meta(name='twitter:card' content='summary')
if profile.twitter
meta(name='twitter:creator' content=`@${profile.twitter.screenName}`)

View File

@ -59,7 +59,7 @@ class NotificationManager {
if (exist) {
// 「メンションされているかつ返信されている」場合は、メンションとしての通知ではなく返信としての通知にする
if (reason != 'mention') {
if (reason !== 'mention') {
exist.reason = reason;
}
} else {
@ -201,7 +201,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
mentionedUsers.push(await Users.findOneOrFail(data.reply.userId));
}
if (data.visibility == 'specified') {
if (data.visibility === 'specified') {
if (data.visibleUsers == null) throw new Error('invalid param');
for (const u of data.visibleUsers) {
@ -301,7 +301,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
if (Users.isRemoteUser(user)) activeUsersChart.update(user);
// 未読通知を作成
if (data.visibility == 'specified') {
if (data.visibility === 'specified') {
if (data.visibleUsers == null) throw new Error('invalid param');
for (const u of data.visibleUsers) {
@ -439,7 +439,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
async function renderNoteOrRenoteActivity(data: Option, note: Note) {
if (data.localOnly) return null;
const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length == 0)
const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0)
? renderAnnounce(data.renote.uri ? data.renote.uri : `${config.url}/notes/${data.renote.id}`, note)
: renderCreate(await renderNote(note, false), note);
@ -478,7 +478,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O
userId: user.id,
localOnly: data.localOnly!,
visibility: data.visibility as any,
visibleUserIds: data.visibility == 'specified'
visibleUserIds: data.visibility === 'specified'
? data.visibleUsers
? data.visibleUsers.map(u => u.id)
: []
@ -502,7 +502,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O
insert.mentions = mentionedUsers.map(u => u.id);
const profiles = await UserProfiles.find({ userId: In(insert.mentions) });
insert.mentionedRemoteUsers = JSON.stringify(mentionedUsers.filter(u => Users.isRemoteUser(u)).map(u => {
const profile = profiles.find(p => p.userId == u.id);
const profile = profiles.find(p => p.userId === u.id);
const url = profile != null ? profile.url : null;
return {
uri: u.uri,

View File

@ -39,7 +39,7 @@ export default async function(user: User, note: Note, quiet = false) {
let renote: Note | undefined;
// if deletd note is renote
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length == 0)) {
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) {
renote = await Notes.findOne({
id: note.renoteId,
});

View File

@ -76,7 +76,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note,
// カスタム絵文字リアクションだったら絵文字情報も送る
const decodedReaction = decodeReaction(reaction);
let emoji = await Emojis.findOne({
const emoji = await Emojis.findOne({
where: {
name: decodedReaction.name,
host: decodedReaction.host,

View File

@ -52,7 +52,7 @@ export default async function(
if (note.user != null) { // たぶんnullになることは無いはずだけど一応
for (const antenna of myAntennas) {
if (await checkHitAntenna(antenna, note, note.user as any, undefined, Array.from(following))) {
if (await checkHitAntenna(antenna, note, note.user, undefined, Array.from(following))) {
readAntennaNotes.push(note);
}
}

View File

@ -114,9 +114,9 @@ export async function sendEmail(to: string, subject: string, html: string, text:
</html>`,
});
logger.info('Message sent: %s', info.messageId);
} catch (e) {
logger.error(e);
throw e;
logger.info(`Message sent: ${info.messageId}`);
} catch (err) {
logger.error(err as Error);
throw err;
}
}