strictNullChecks (#4666)
* wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip
This commit is contained in:
@@ -21,6 +21,7 @@ import { IObject, INote } from '../type';
|
||||
import { Emoji } from '../../../models/entities/emoji';
|
||||
import { genId } from '../../../misc/gen-id';
|
||||
import fetchMeta from '../../../misc/fetch-meta';
|
||||
import { ensure } from '../../../prelude/ensure';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
@@ -29,13 +30,14 @@ const logger = apLogger;
|
||||
*
|
||||
* Misskeyに対象のNoteが登録されていればそれを返します。
|
||||
*/
|
||||
export async function fetchNote(value: string | IObject, resolver?: Resolver): Promise<Note> {
|
||||
export async function fetchNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
||||
const uri = typeof value == 'string' ? value : value.id;
|
||||
if (uri == null) throw 'missing uri';
|
||||
|
||||
// URIがこのサーバーを指しているならデータベースからフェッチ
|
||||
if (uri.startsWith(config.url + '/')) {
|
||||
const id = uri.split('/').pop();
|
||||
return await Notes.findOne(id);
|
||||
return await Notes.findOne(id).then(x => x || null);
|
||||
}
|
||||
|
||||
//#region このサーバーに既に登録されていたらそれを返す
|
||||
@@ -52,7 +54,7 @@ export async function fetchNote(value: string | IObject, resolver?: Resolver): P
|
||||
/**
|
||||
* Noteを作成します。
|
||||
*/
|
||||
export async function createNote(value: any, resolver?: Resolver, silent = false): Promise<Note> {
|
||||
export async function createNote(value: any, resolver?: Resolver, silent = false): Promise<Note | null> {
|
||||
if (resolver == null) resolver = new Resolver();
|
||||
|
||||
const object: any = await resolver.resolve(value);
|
||||
@@ -65,7 +67,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
value: value,
|
||||
object: object
|
||||
});
|
||||
return null;
|
||||
throw 'invalid note';
|
||||
}
|
||||
|
||||
const note: INote = object;
|
||||
@@ -75,11 +77,11 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
logger.info(`Creating the Note: ${note.id}`);
|
||||
|
||||
// 投稿者をフェッチ
|
||||
const actor = await resolvePerson(note.attributedTo, null, resolver) as IRemoteUser;
|
||||
const actor = await resolvePerson(note.attributedTo, resolver) as IRemoteUser;
|
||||
|
||||
// 投稿者が凍結されていたらスキップ
|
||||
if (actor.isSuspended) {
|
||||
return null;
|
||||
throw 'actor has been suspended';
|
||||
}
|
||||
|
||||
//#region Visibility
|
||||
@@ -95,9 +97,9 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
visibility = 'followers';
|
||||
} else {
|
||||
visibility = 'specified';
|
||||
visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri, null, resolver)));
|
||||
visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri, resolver)));
|
||||
}
|
||||
}
|
||||
}
|
||||
//#endergion
|
||||
|
||||
const apMentions = await extractMentionedUsers(actor, note.to, note.cc, resolver);
|
||||
@@ -118,7 +120,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
: [];
|
||||
|
||||
// リプライ
|
||||
const reply: Note = note.inReplyTo
|
||||
const reply: Note | undefined | null = note.inReplyTo
|
||||
? await resolveNote(note.inReplyTo, resolver).catch(e => {
|
||||
// 4xxの場合はリプライしてないことにする
|
||||
if (e.statusCode >= 400 && e.statusCode < 500) {
|
||||
@@ -131,7 +133,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
: null;
|
||||
|
||||
// 引用
|
||||
let quote: Note;
|
||||
let quote: Note | undefined | null;
|
||||
|
||||
if (note._misskey_quote && typeof note._misskey_quote == 'string') {
|
||||
quote = await resolveNote(note._misskey_quote).catch(e => {
|
||||
@@ -152,7 +154,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
|
||||
// vote
|
||||
if (reply && reply.hasPoll) {
|
||||
const poll = await Polls.findOne({ noteId: reply.id });
|
||||
const poll = await Polls.findOne({ noteId: reply.id }).then(ensure);
|
||||
|
||||
const tryCreateVote = async (name: string, index: number): Promise<null> => {
|
||||
if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) {
|
||||
logger.warn(`vote to expired poll from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
@@ -180,7 +183,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
}
|
||||
}
|
||||
|
||||
const emojis = await extractEmojis(note.tag, actor.host).catch(e => {
|
||||
const emojis = await extractEmojis(note.tag || [], actor.host).catch(e => {
|
||||
logger.info(`extractEmojis: ${e}`);
|
||||
return [] as Emoji[];
|
||||
});
|
||||
@@ -196,7 +199,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
}
|
||||
|
||||
return await post(actor, {
|
||||
createdAt: new Date(note.published),
|
||||
createdAt: note.published ? new Date(note.published) : null,
|
||||
files,
|
||||
reply,
|
||||
renote: quote,
|
||||
@@ -223,8 +226,9 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
* Misskeyに対象のNoteが登録されていればそれを返し、そうでなければ
|
||||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||
*/
|
||||
export async function resolveNote(value: string | IObject, resolver?: Resolver): Promise<Note> {
|
||||
export async function resolveNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
||||
const uri = typeof value == 'string' ? value : value.id;
|
||||
if (uri == null) throw 'missing uri';
|
||||
|
||||
// ブロックしてたら中断
|
||||
// TODO: いちいちデータベースにアクセスするのはコスト高そうなのでどっかにキャッシュしておく
|
||||
@@ -244,75 +248,79 @@ export async function resolveNote(value: string | IObject, resolver?: Resolver):
|
||||
// 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。
|
||||
return await createNote(uri, resolver).catch(e => {
|
||||
if (e.name === 'duplicated') {
|
||||
return fetchNote(uri);
|
||||
return fetchNote(uri).then(note => {
|
||||
if (note == null) {
|
||||
throw 'something happened';
|
||||
} else {
|
||||
return note;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function extractEmojis(tags: ITag[], host: string) {
|
||||
export async function extractEmojis(tags: ITag[], host: string): Promise<Emoji[]> {
|
||||
host = toPuny(host);
|
||||
|
||||
if (!tags) return [];
|
||||
|
||||
const eomjiTags = tags.filter(tag => tag.type === 'Emoji' && tag.icon && tag.icon.url);
|
||||
const eomjiTags = tags.filter(tag => tag.type === 'Emoji' && tag.icon && tag.icon.url && tag.name);
|
||||
|
||||
return await Promise.all(
|
||||
eomjiTags.map(async tag => {
|
||||
const name = tag.name.replace(/^:/, '').replace(/:$/, '');
|
||||
return await Promise.all(eomjiTags.map(async tag => {
|
||||
const name = tag.name!.replace(/^:/, '').replace(/:$/, '');
|
||||
|
||||
const exists = await Emojis.findOne({
|
||||
host,
|
||||
name
|
||||
});
|
||||
const exists = await Emojis.findOne({
|
||||
host,
|
||||
name
|
||||
});
|
||||
|
||||
if (exists) {
|
||||
if ((tag.updated != null && exists.updatedAt == null)
|
||||
|| (tag.id != null && exists.uri == null)
|
||||
|| (tag.updated != null && exists.updatedAt != null && new Date(tag.updated) > exists.updatedAt)
|
||||
) {
|
||||
await Emojis.update({
|
||||
host,
|
||||
name,
|
||||
}, {
|
||||
uri: tag.id,
|
||||
url: tag.icon.url,
|
||||
updatedAt: new Date(tag.updated),
|
||||
});
|
||||
if (exists) {
|
||||
if ((tag.updated != null && exists.updatedAt == null)
|
||||
|| (tag.id != null && exists.uri == null)
|
||||
|| (tag.updated != null && exists.updatedAt != null && new Date(tag.updated) > exists.updatedAt)
|
||||
) {
|
||||
await Emojis.update({
|
||||
host,
|
||||
name,
|
||||
}, {
|
||||
uri: tag.id,
|
||||
url: tag.icon!.url,
|
||||
updatedAt: new Date(tag.updated!),
|
||||
});
|
||||
|
||||
return await Emojis.findOne({
|
||||
host,
|
||||
name
|
||||
});
|
||||
}
|
||||
|
||||
return exists;
|
||||
return await Emojis.findOne({
|
||||
host,
|
||||
name
|
||||
}) as Emoji;
|
||||
}
|
||||
|
||||
logger.info(`register emoji host=${host}, name=${name}`);
|
||||
return exists;
|
||||
}
|
||||
|
||||
return await Emojis.save({
|
||||
id: genId(),
|
||||
host,
|
||||
name,
|
||||
uri: tag.id,
|
||||
url: tag.icon.url,
|
||||
updatedAt: tag.updated ? new Date(tag.updated) : undefined,
|
||||
aliases: []
|
||||
} as Emoji);
|
||||
})
|
||||
);
|
||||
logger.info(`register emoji host=${host}, name=${name}`);
|
||||
|
||||
return await Emojis.save({
|
||||
id: genId(),
|
||||
host,
|
||||
name,
|
||||
uri: tag.id,
|
||||
url: tag.icon!.url,
|
||||
updatedAt: tag.updated ? new Date(tag.updated) : undefined,
|
||||
aliases: []
|
||||
} as Partial<Emoji>);
|
||||
}));
|
||||
}
|
||||
|
||||
async function extractMentionedUsers(actor: IRemoteUser, to: string[], cc: string[], resolver: Resolver) {
|
||||
const ignoreUris = ['https://www.w3.org/ns/activitystreams#Public', `${actor.uri}/followers`];
|
||||
const uris = difference(unique(concat([to || [], cc || []])), ignoreUris);
|
||||
|
||||
const limit = promiseLimit(2);
|
||||
const limit = promiseLimit<User | null>(2);
|
||||
const users = await Promise.all(
|
||||
uris.map(uri => limit(() => resolvePerson(uri, null, resolver).catch(() => null)) as Promise<User>)
|
||||
uris.map(uri => limit(() => resolvePerson(uri, resolver).catch(() => null)) as Promise<User | null>)
|
||||
);
|
||||
|
||||
return users.filter(x => x != null);
|
||||
return users.filter(x => x != null) as User[];
|
||||
}
|
||||
|
Reference in New Issue
Block a user