summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-07-21 06:59:53 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-07-21 06:59:53 +0900
commited48349e39d450803af014f65d378d69fdb69f41 (patch)
treee766762dc907af8741d3a7e31591af98f84fe821 /src
parentwip (diff)
downloadsharkey-ed48349e39d450803af014f65d378d69fdb69f41.tar.gz
sharkey-ed48349e39d450803af014f65d378d69fdb69f41.tar.bz2
sharkey-ed48349e39d450803af014f65d378d69fdb69f41.zip
wip
Diffstat (limited to 'src')
-rw-r--r--src/services/note/create.ts268
1 files changed, 136 insertions, 132 deletions
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index ae3854e7a1..ab53252cf5 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -23,6 +23,7 @@ import config from '../../config';
import registerHashtag from '../register-hashtag';
import isQuote from '../../misc/is-quote';
import { TextElementMention } from '../../mfm/parse/elements/mention';
+import { TextElementHashtag } from '../../mfm/parse/elements/hashtag';
type Type = 'reply' | 'renote' | 'quote' | 'mention';
@@ -58,7 +59,7 @@ class NotificationManager {
}
}
-export default async (user: IUser, data: {
+type Option = {
createdAt?: Date;
text?: string;
reply?: INote;
@@ -72,98 +73,32 @@ export default async (user: IUser, data: {
visibleUsers?: IUser[];
uri?: string;
app?: IApp;
-}, silent = false) => new Promise<INote>(async (res, rej) => {
+};
+
+export default async (user: IUser, data: Option, silent = false) => new Promise<INote>(async (res, rej) => {
if (data.createdAt == null) data.createdAt = new Date();
if (data.visibility == null) data.visibility = 'public';
if (data.viaMobile == null) data.viaMobile = false;
- let tags: string[] = [];
-
- let tokens: any[] = null;
-
- if (data.text) {
- // Analyze
- tokens = parse(data.text);
-
- // Extract hashtags
- const hashtags = tokens
- .filter(t => t.type == 'hashtag')
- .map(t => t.hashtag);
-
- hashtags.forEach(tag => {
- if (tags.indexOf(tag) == -1) {
- tags.push(tag);
- }
- });
- }
-
- tags = tags.filter(tag => tag.length <= 100);
-
if (data.visibleUsers) {
data.visibleUsers = data.visibleUsers.filter(x => x != null);
}
- const insert: any = {
- createdAt: data.createdAt,
- mediaIds: data.media ? data.media.map(file => file._id) : [],
- replyId: data.reply ? data.reply._id : null,
- renoteId: data.renote ? data.renote._id : null,
- text: data.text,
- poll: data.poll,
- cw: data.cw == null ? null : data.cw,
- tags,
- tagsLower: tags.map(tag => tag.toLowerCase()),
- userId: user._id,
- viaMobile: data.viaMobile,
- geo: data.geo || null,
- appId: data.app ? data.app._id : null,
- visibility: data.visibility,
- visibleUserIds: data.visibility == 'specified'
- ? data.visibleUsers
- ? data.visibleUsers.map(u => u._id)
- : []
- : [],
-
- // 以下非正規化データ
- _reply: data.reply ? { userId: data.reply.userId } : null,
- _renote: data.renote ? { userId: data.renote.userId } : null,
- _user: {
- host: user.host,
- inbox: isRemoteUser(user) ? user.inbox : undefined
- }
- };
+ // Parse MFM
+ const tokens = data.text ? parse(data.text) : [];
- if (data.uri != null) insert.uri = data.uri;
+ const tags = extractHashtags(tokens);
- // メンション
const mentionedUsers = await extractMentionedUsers(tokens);
- // Append mentions data
- if (mentionedUsers.length > 0) {
- insert.mentions = mentionedUsers.map(u => u._id);
- insert.mentionedRemoteUsers = mentionedUsers.filter(u => isRemoteUser(u)).map(u => ({
- uri: (u as IRemoteUser).uri,
- username: u.username,
- host: u.host
- }));
- }
+ const note = await insertNote(user, data, tokens, tags, mentionedUsers);
- // 投稿を作成
- let note: INote;
- try {
- note = await Note.insert(insert);
- } catch (e) {
- // duplicate key error
- if (e.code === 11000) {
- return res(null);
- }
+ res(note);
- console.error(e);
- return rej('something happened');
+ if (note == null) {
+ return;
}
- res(note);
-
// ハッシュタグ登録
tags.map(tag => registerHashtag(user, tag));
@@ -200,63 +135,9 @@ export default async (user: IUser, data: {
}
if (!silent) {
- if (isLocalUser(user)) {
- if (note.visibility == 'private' || note.visibility == 'followers' || note.visibility == 'specified') {
- // Publish event to myself's stream
- stream(note.userId, 'note', await pack(note, user, {
- detail: true
- }));
- } else {
- // Publish event to myself's stream
- stream(note.userId, 'note', noteObj);
-
- // Publish note to local and hybrid timeline stream
- if (note.visibility != 'home') {
- publishLocalTimelineStream(noteObj);
- }
- if (note.visibility == 'public') {
- publishHybridTimelineStream(null, noteObj);
- }
- }
- }
-
- // Publish note to global timeline stream
- if (note.visibility == 'public' && note.replyId == null) {
- publishGlobalTimelineStream(noteObj);
- }
-
- if (note.visibility == 'specified') {
- data.visibleUsers.forEach(async u => {
- const n = await pack(note, u, {
- detail: true
- });
- stream(u._id, 'note', n);
- publishHybridTimelineStream(u._id, n);
- });
- }
-
- if (note.visibility == 'public' || note.visibility == 'home' || note.visibility == 'followers') {
- // フォロワーに配信
- publishToFollowers(note, noteObj, user, noteActivity);
- }
-
- // リストに配信
- publishToUserLists(note, noteObj);
+ publish(user, note, noteObj, data.reply, data.renote, data.visibleUsers, noteActivity);
}
- //#region リプライとAnnounceのAP配送
-
- // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
- if (data.reply && isLocalUser(user) && isRemoteUser(data.reply._user)) {
- deliver(user, noteActivity, data.reply._user.inbox);
- }
-
- // 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送
- if (data.renote && isLocalUser(user) && isRemoteUser(data.renote._user)) {
- deliver(user, noteActivity, data.renote._user.inbox);
- }
- //#endergion
-
// If has in reply to note
if (data.reply) {
// Fetch watchers
@@ -308,6 +189,129 @@ export default async (user: IUser, data: {
index(note);
});
+async function publish(user: IUser, note: INote, noteObj: any, reply: INote, renote: INote, visibleUsers: IUser[], noteActivity: any) {
+ if (isLocalUser(user)) {
+ // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
+ if (reply && isRemoteUser(reply._user)) {
+ deliver(user, noteActivity, reply._user.inbox);
+ }
+
+ // 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送
+ if (renote && isRemoteUser(renote._user)) {
+ deliver(user, noteActivity, renote._user.inbox);
+ }
+
+ if (['private', 'followers', 'specified'].includes(note.visibility)) {
+ // Publish event to myself's stream
+ stream(note.userId, 'note', await pack(note, user, {
+ detail: true
+ }));
+ } else {
+ // Publish event to myself's stream
+ stream(note.userId, 'note', noteObj);
+
+ // Publish note to local and hybrid timeline stream
+ if (note.visibility != 'home') {
+ publishLocalTimelineStream(noteObj);
+ }
+
+ if (note.visibility == 'public') {
+ publishHybridTimelineStream(null, noteObj);
+ }
+ }
+ }
+
+ // Publish note to global timeline stream
+ if (note.visibility == 'public' && note.replyId == null) {
+ publishGlobalTimelineStream(noteObj);
+ }
+
+ if (note.visibility == 'specified') {
+ visibleUsers.forEach(async (u) => {
+ const n = await pack(note, u, {
+ detail: true
+ });
+ stream(u._id, 'note', n);
+ publishHybridTimelineStream(u._id, n);
+ });
+ }
+
+ if (['public', 'home', 'followers'].includes(note.visibility)) {
+ // フォロワーに配信
+ publishToFollowers(note, noteObj, user, noteActivity);
+ }
+
+ // リストに配信
+ publishToUserLists(note, noteObj);
+}
+
+async function insertNote(user: IUser, data: Option, tokens: ReturnType<typeof parse>, tags: string[], mentionedUsers: IUser[]) {
+ const insert: any = {
+ createdAt: data.createdAt,
+ mediaIds: data.media ? data.media.map(file => file._id) : [],
+ replyId: data.reply ? data.reply._id : null,
+ renoteId: data.renote ? data.renote._id : null,
+ text: data.text,
+ poll: data.poll,
+ cw: data.cw == null ? null : data.cw,
+ tags,
+ tagsLower: tags.map(tag => tag.toLowerCase()),
+ userId: user._id,
+ viaMobile: data.viaMobile,
+ geo: data.geo || null,
+ appId: data.app ? data.app._id : null,
+ visibility: data.visibility,
+ visibleUserIds: data.visibility == 'specified'
+ ? data.visibleUsers
+ ? data.visibleUsers.map(u => u._id)
+ : []
+ : [],
+
+ // 以下非正規化データ
+ _reply: data.reply ? { userId: data.reply.userId } : null,
+ _renote: data.renote ? { userId: data.renote.userId } : null,
+ _user: {
+ host: user.host,
+ inbox: isRemoteUser(user) ? user.inbox : undefined
+ }
+ };
+
+ if (data.uri != null) insert.uri = data.uri;
+
+ // Append mentions data
+ if (mentionedUsers.length > 0) {
+ insert.mentions = mentionedUsers.map(u => u._id);
+ insert.mentionedRemoteUsers = mentionedUsers.filter(u => isRemoteUser(u)).map(u => ({
+ uri: (u as IRemoteUser).uri,
+ username: u.username,
+ host: u.host
+ }));
+ }
+
+ // 投稿を作成
+ try {
+ return await Note.insert(insert);
+ } catch (e) {
+ // duplicate key error
+ if (e.code === 11000) {
+ return null;
+ }
+
+ console.error(e);
+ throw 'something happened';
+ }
+}
+
+function extractHashtags(tokens: ReturnType<typeof parse>): string[] {
+ // Extract hashtags
+ const hashtags = tokens
+ .filter(t => t.type == 'hashtag')
+ .map(t => (t as TextElementHashtag).hashtag)
+ .filter(tag => tag.length <= 100);
+
+ return [...new Set(hashtags)];
+}
+
function index(note: INote) {
if (note.text == null || config.elasticsearch == null) return;