diff --git a/src/client/app/mobile/views/pages/drive.vue b/src/client/app/mobile/views/pages/drive.vue
index 200379f22..2cf3f510a 100644
--- a/src/client/app/mobile/views/pages/drive.vue
+++ b/src/client/app/mobile/views/pages/drive.vue
@@ -3,7 +3,7 @@
%fa:R folder-open%{{ folder.name }}
{{ file.name }}
- %fa:cloud%%i18n:mobile.tags.mk-drive-page.drive%
+ %fa:cloud%%i18n:@drive%
- {{ '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', name) }}
+ {{ '%i18n:@followers-of%'.replace('{}', name) }}
- %i18n:mobile.tags.mk-user-followers.no-users%
+ %i18n:@no-users%
@@ -52,7 +52,7 @@ export default Vue.extend({
this.user = user;
this.fetching = false;
- document.title = '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', this.name) + ' | Misskey';
+ document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
});
},
onLoaded() {
diff --git a/src/client/app/mobile/views/pages/following.vue b/src/client/app/mobile/views/pages/following.vue
index d0dcc117c..8dbdd5dba 100644
--- a/src/client/app/mobile/views/pages/following.vue
+++ b/src/client/app/mobile/views/pages/following.vue
@@ -2,7 +2,7 @@
- {{ '%i18n:mobile.tags.mk-user-following-page.following-of%'.replace('{}', name) }}
+ {{ '%i18n:@following-of%'.replace('{}', name) }}
- %i18n:mobile.tags.mk-user-following.no-users%
+ %i18n:@no-users%
@@ -51,7 +51,7 @@ export default Vue.extend({
this.user = user;
this.fetching = false;
- document.title = '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', this.name) + ' | Misskey';
+ document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
});
},
onLoaded() {
diff --git a/src/client/app/mobile/views/pages/home.vue b/src/client/app/mobile/views/pages/home.vue
index 3de2ba1c3..3d94dd7ce 100644
--- a/src/client/app/mobile/views/pages/home.vue
+++ b/src/client/app/mobile/views/pages/home.vue
@@ -1,7 +1,7 @@
- %fa:home%タイムライン
+ %fa:home%%i18n:@timeline%
%fa:home%ウィジェット
%fa:angle-down%
diff --git a/src/client/app/mobile/views/pages/messaging-room.vue b/src/client/app/mobile/views/pages/messaging-room.vue
index 3b6fb11db..c26a9b735 100644
--- a/src/client/app/mobile/views/pages/messaging-room.vue
+++ b/src/client/app/mobile/views/pages/messaging-room.vue
@@ -33,7 +33,7 @@ export default Vue.extend({
this.user = user;
this.fetching = false;
- document.title = `%i18n:mobile.tags.mk-messaging-room-page.message%: ${Vue.filter('userName')(this.user)} | Misskey`;
+ document.title = `%i18n:@messaging%: ${Vue.filter('userName')(this.user)} | Misskey`;
});
}
}
diff --git a/src/client/app/mobile/views/pages/messaging.vue b/src/client/app/mobile/views/pages/messaging.vue
index fa735a253..cc328e5a1 100644
--- a/src/client/app/mobile/views/pages/messaging.vue
+++ b/src/client/app/mobile/views/pages/messaging.vue
@@ -1,6 +1,6 @@
- %fa:R comments%%i18n:mobile.tags.mk-messaging-page.message%
+ %fa:R comments%%i18n:@messaging%
@@ -11,7 +11,7 @@ import getAcct from '../../../../../acct/render';
export default Vue.extend({
mounted() {
- document.title = 'Misskey %i18n:mobile.tags.mk-messaging-page.message%';
+ document.title = 'Misskey %i18n:@messaging%';
document.documentElement.style.background = '#fff';
},
methods: {
diff --git a/src/client/app/mobile/views/pages/note.vue b/src/client/app/mobile/views/pages/note.vue
index 89b8c776f..c866be8a1 100644
--- a/src/client/app/mobile/views/pages/note.vue
+++ b/src/client/app/mobile/views/pages/note.vue
@@ -1,12 +1,12 @@
- %fa:R sticky-note%%i18n:mobile.tags.mk-note-page.title%
+ %fa:R sticky-note%%i18n:@title%
- %fa:angle-up%%i18n:mobile.tags.mk-note-page.next%
+ %fa:angle-up%%i18n:@next%
- %fa:angle-down%%i18n:mobile.tags.mk-note-page.prev%
+ %fa:angle-down%%i18n:@prev%
diff --git a/src/client/app/mobile/views/pages/notifications.vue b/src/client/app/mobile/views/pages/notifications.vue
index 6d45e22a9..5ae94590c 100644
--- a/src/client/app/mobile/views/pages/notifications.vue
+++ b/src/client/app/mobile/views/pages/notifications.vue
@@ -1,6 +1,6 @@
- %fa:R bell%%i18n:mobile.tags.mk-notifications-page.notifications%
+ %fa:R bell%%i18n:@notifications%
@@ -12,14 +12,14 @@ import Progress from '../../../common/scripts/loading';
export default Vue.extend({
mounted() {
- document.title = 'Misskey | %i18n:mobile.tags.mk-notifications-page.notifications%';
+ document.title = 'Misskey | %i18n:@notifications%';
document.documentElement.style.background = '#313a42';
Progress.start();
},
methods: {
fn() {
- const ok = window.confirm('%i18n:mobile.tags.mk-notifications-page.read-all%');
+ const ok = window.confirm('%i18n:@read-all%');
if (!ok) return;
(this as any).api('notifications/markAsRead_all');
diff --git a/src/client/app/mobile/views/pages/profile-setting.vue b/src/client/app/mobile/views/pages/profile-setting.vue
index 7f0ff5aad..846be5995 100644
--- a/src/client/app/mobile/views/pages/profile-setting.vue
+++ b/src/client/app/mobile/views/pages/profile-setting.vue
@@ -1,38 +1,38 @@
- %fa:user%%i18n:mobile.tags.mk-profile-setting-page.title%
+ %fa:user%%i18n:@title%
-
%fa:info-circle%%i18n:mobile.tags.mk-profile-setting.will-be-published%
+
%fa:info-circle%%i18n:@will-be-published%
-
+
@@ -58,7 +58,7 @@ export default Vue.extend({
this.birthday = (this as any).os.i.profile.birthday;
},
mounted() {
- document.title = 'Misskey | %i18n:mobile.tags.mk-profile-setting-page.title%';
+ document.title = 'Misskey | %i18n:@title%';
document.documentElement.style.background = '#313a42';
},
methods: {
@@ -72,7 +72,7 @@ export default Vue.extend({
avatarId: file.id
}).then(() => {
this.avatarSaving = false;
- alert('%i18n:mobile.tags.mk-profile-setting.avatar-saved%');
+ alert('%i18n:@avatar-saved%');
});
});
},
@@ -86,7 +86,7 @@ export default Vue.extend({
bannerId: file.id
}).then(() => {
this.bannerSaving = false;
- alert('%i18n:mobile.tags.mk-profile-setting.banner-saved%');
+ alert('%i18n:@banner-saved%');
});
});
},
@@ -100,7 +100,7 @@ export default Vue.extend({
birthday: this.birthday || null
}).then(() => {
this.saving = false;
- alert('%i18n:mobile.tags.mk-profile-setting.saved%');
+ alert('%i18n:@saved%');
});
}
}
diff --git a/src/client/app/mobile/views/pages/search.vue b/src/client/app/mobile/views/pages/search.vue
index a96832bee..2ea2c7338 100644
--- a/src/client/app/mobile/views/pages/search.vue
+++ b/src/client/app/mobile/views/pages/search.vue
@@ -3,9 +3,9 @@
%fa:search% {{ q }}
- {{ '%i18n:mobile.tags.mk-search-notes.empty%'.replace('{}', q) }}
+ {{ '%i18n:@empty%'.replace('{}', q) }}
@@ -38,7 +38,7 @@ export default Vue.extend({
}
},
mounted() {
- document.title = `%i18n:mobile.tags.mk-search-page.search%: ${this.q} | Misskey`;
+ document.title = `%i18n:@search%: ${this.q} | Misskey`;
document.documentElement.style.background = '#313a42';
this.fetch();
diff --git a/src/client/app/mobile/views/pages/selectdrive.vue b/src/client/app/mobile/views/pages/selectdrive.vue
index 3480a0d10..e8e256cae 100644
--- a/src/client/app/mobile/views/pages/selectdrive.vue
+++ b/src/client/app/mobile/views/pages/selectdrive.vue
@@ -1,7 +1,7 @@
- %i18n:mobile.tags.mk-selectdrive-page.select-file%({{ files.length }})
+ %i18n:@select-file%({{ files.length }})
@@ -25,7 +25,7 @@ export default Vue.extend({
}
},
mounted() {
- document.title = '%i18n:desktop.tags.mk-selectdrive-page.title%';
+ document.title = '%i18n:@title%';
},
methods: {
onSelected(file) {
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index 8d248f5cb..36f7f09b8 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -1,16 +1,15 @@
- %fa:cog%%i18n:mobile.tags.mk-settings-page.settings%
+ %fa:cog%%i18n:@settings%
-
+
- - %fa:user%%i18n:mobile.tags.mk-settings-page.profile%%fa:angle-right%
- - %fa:puzzle-piece%%i18n:mobile.tags.mk-settings-page.applications%%fa:angle-right%
- - %fa:B twitter%%i18n:mobile.tags.mk-settings-page.twitter-integration%%fa:angle-right%
- - %fa:sign-in-alt%%i18n:mobile.tags.mk-settings-page.signin-history%%fa:angle-right%
+ - %fa:user%%i18n:@profile%%fa:angle-right%
+ - %fa:B twitter%%i18n:@twitter%%fa:angle-right%
+ - %fa:sign-in-alt%%i18n:@signin-history%%fa:angle-right%
ver {{ version }} ({{ codename }})
@@ -34,7 +33,7 @@ export default Vue.extend({
}
},
mounted() {
- document.title = 'Misskey | %i18n:mobile.tags.mk-settings-page.settings%';
+ document.title = 'Misskey | %i18n:@settings%';
document.documentElement.style.background = '#313a42';
},
methods: {
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index 3d9fbda94..ea384308e 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -14,7 +14,7 @@
{{ user | userName }}
@{{ user | acct }}
- %i18n:mobile.tags.mk-user.follows-you%
+ %i18n:@follows-you%
{{ user.description }}
diff --git a/src/client/app/mobile/views/pages/user/home.followers-you-know.vue b/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
index 2841c0d63..6f809d889 100644
--- a/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
+++ b/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
@@ -1,12 +1,12 @@
-
%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-followers-you-know.loading%
+
%fa:spinner .pulse .fw%%i18n:@loading%
-
%i18n:mobile.tags.mk-user-overview-followers-you-know.no-users%
+
%i18n:@no-users%
diff --git a/src/client/app/mobile/views/pages/user/home.friends.vue b/src/client/app/mobile/views/pages/user/home.friends.vue
index 469781abb..cf257b124 100644
--- a/src/client/app/mobile/views/pages/user/home.friends.vue
+++ b/src/client/app/mobile/views/pages/user/home.friends.vue
@@ -1,10 +1,10 @@
-
%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-frequently-replied-users.loading%
+
%fa:spinner .pulse .fw%%i18n:@loading%
-
%i18n:mobile.tags.mk-user-overview-frequently-replied-users.no-users%
+
%i18n:@no-users%
diff --git a/src/client/app/mobile/views/pages/user/home.notes.vue b/src/client/app/mobile/views/pages/user/home.notes.vue
index 02afed9b8..6483402a5 100644
--- a/src/client/app/mobile/views/pages/user/home.notes.vue
+++ b/src/client/app/mobile/views/pages/user/home.notes.vue
@@ -1,10 +1,10 @@
-
%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-notes.loading%
+
%fa:spinner .pulse .fw%%i18n:@loading%
-
%i18n:mobile.tags.mk-user-overview-notes.no-notes%
+
%i18n:@no-notes%
diff --git a/src/client/app/mobile/views/pages/user/home.photos.vue b/src/client/app/mobile/views/pages/user/home.photos.vue
index 0e0d6926a..bfd2aa833 100644
--- a/src/client/app/mobile/views/pages/user/home.photos.vue
+++ b/src/client/app/mobile/views/pages/user/home.photos.vue
@@ -1,6 +1,6 @@
-
%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-photos.loading%
+
%fa:spinner .pulse .fw%%i18n:@loading%
-
%i18n:mobile.tags.mk-user-overview-photos.no-photos%
+
%i18n:@no-photos%
diff --git a/src/client/app/mobile/views/pages/user/home.vue b/src/client/app/mobile/views/pages/user/home.vue
index c0cd9b8da..4ba2ffd1d 100644
--- a/src/client/app/mobile/views/pages/user/home.vue
+++ b/src/client/app/mobile/views/pages/user/home.vue
@@ -2,36 +2,36 @@
- %fa:R comments%%i18n:mobile.tags.mk-user-overview.recent-notes%
+ %fa:R comments%%i18n:@recent-notes%
- %fa:image%%i18n:mobile.tags.mk-user-overview.images%
+ %fa:image%%i18n:@images%
- %fa:chart-bar%%i18n:mobile.tags.mk-user-overview.activity%
+ %fa:chart-bar%%i18n:@activity%
- %fa:users%%i18n:mobile.tags.mk-user-overview.frequently-replied-users%
+ %fa:users%%i18n:@frequently-replied-users%
- %fa:users%%i18n:mobile.tags.mk-user-overview.followers-you-know%
+ %fa:users%%i18n:@followers-you-know%
-
%i18n:mobile.tags.mk-user-overview.last-used-at%:
+
%i18n:@last-used-at%:
diff --git a/src/client/docs/api/gulpfile.ts b/src/client/docs/api/gulpfile.ts
index 9980ede23..31027c0be 100644
--- a/src/client/docs/api/gulpfile.ts
+++ b/src/client/docs/api/gulpfile.ts
@@ -127,7 +127,7 @@ gulp.task('doc:api:endpoints', async () => {
return;
}
const i18n = new I18nReplacer(lang);
- html = html.replace(i18n.pattern, i18n.replacement);
+ html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
html = fa(html);
const htmlPath = `./built/client/docs/${lang}/api/endpoints/${ep.endpoint}.html`;
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
@@ -171,7 +171,7 @@ gulp.task('doc:api:entities', async () => {
return;
}
const i18n = new I18nReplacer(lang);
- html = html.replace(i18n.pattern, i18n.replacement);
+ html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
html = fa(html);
const htmlPath = `./built/client/docs/${lang}/api/entities/${kebab(entity.name)}.html`;
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
diff --git a/src/client/docs/gulpfile.ts b/src/client/docs/gulpfile.ts
index 56bf6188c..5e81d6d3b 100644
--- a/src/client/docs/gulpfile.ts
+++ b/src/client/docs/gulpfile.ts
@@ -53,7 +53,7 @@ gulp.task('doc:docs', async () => {
return;
}
const i18n = new I18nReplacer(lang);
- html = html.replace(i18n.pattern, i18n.replacement);
+ html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
html = fa(html);
const htmlPath = `./built/client/docs/${lang}/${name}.html`;
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts
index 80fe8e030..fc9c15072 100644
--- a/src/models/drive-file.ts
+++ b/src/models/drive-file.ts
@@ -84,14 +84,19 @@ export async function deleteDriveFile(driveFile: string | mongo.ObjectID | IDriv
// このDriveFileがアバターやバナーに使われていたらそれらのプロパティをnullにする
const u = await User.findOne({ _id: d.metadata.userId });
if (u) {
- if (u.avatarId.equals(d._id)) {
+ if (u.avatarId && u.avatarId.equals(d._id)) {
await User.update({ _id: u._id }, { $set: { avatarId: null } });
}
- if (u.bannerId.equals(d._id)) {
+ if (u.bannerId && u.bannerId.equals(d._id)) {
await User.update({ _id: u._id }, { $set: { bannerId: null } });
}
}
+ // このDriveFileのチャンクをすべて削除
+ await monkDb.get('driveFiles.chunks').remove({
+ files_id: d._id
+ });
+
// このDriveFileを削除
await DriveFile.remove({
_id: d._id
diff --git a/src/models/note.ts b/src/models/note.ts
index 3c1c2e18e..305959354 100644
--- a/src/models/note.ts
+++ b/src/models/note.ts
@@ -5,13 +5,13 @@ import db from '../db/mongodb';
import { IUser, pack as packUser } from './user';
import { pack as packApp } from './app';
import { pack as packChannel } from './channel';
-import Vote, { deletePollVote } from './poll-vote';
+import PollVote, { deletePollVote } from './poll-vote';
import Reaction, { deleteNoteReaction } from './note-reaction';
import { pack as packFile } from './drive-file';
import NoteWatching, { deleteNoteWatching } from './note-watching';
import NoteReaction from './note-reaction';
import Favorite, { deleteFavorite } from './favorite';
-import PollVote from './poll-vote';
+import Notification, { deleteNotification } from './notification';
const Note = db.get
('notes');
@@ -66,7 +66,6 @@ export type INote = {
};
_user: {
host: string;
- hostLower: string;
account: {
inbox?: string;
};
@@ -92,6 +91,8 @@ export async function deleteNote(note: string | mongo.ObjectID | INote) {
n = note as INote;
}
+ console.log(n == null ? `Note: delete skipped ${note}` : `Note: deleting ${n._id}`);
+
if (n == null) return;
// このNoteへの返信をすべて削除
@@ -124,10 +125,17 @@ export async function deleteNote(note: string | mongo.ObjectID | INote) {
await Favorite.find({ noteId: n._id })
).map(x => deleteFavorite(x)));
+ // この投稿に対するNotificationをすべて削除
+ await Promise.all((
+ await Notification.find({ noteId: n._id })
+ ).map(x => deleteNotification(x)));
+
// このNoteを削除
await Note.remove({
_id: n._id
});
+
+ console.log(`Note: deleted ${n._id}`);
}
/**
@@ -259,7 +267,7 @@ export const pack = async (
// Poll
if (meId && _note.poll) {
_note.poll = (async (poll) => {
- const vote = await Vote
+ const vote = await PollVote
.findOne({
userId: meId,
noteId: id
diff --git a/src/models/notification.ts b/src/models/notification.ts
index d5ca7135b..76871166a 100644
--- a/src/models/notification.ts
+++ b/src/models/notification.ts
@@ -49,6 +49,33 @@ export interface INotification {
isRead: Boolean;
}
+/**
+ * Notificationを物理削除します
+ */
+export async function deleteNotification(notification: string | mongo.ObjectID | INotification) {
+ let n: INotification;
+
+ // Populate
+ if (mongo.ObjectID.prototype.isPrototypeOf(notification)) {
+ n = await Notification.findOne({
+ _id: notification
+ });
+ } else if (typeof notification === 'string') {
+ n = await Notification.findOne({
+ _id: new mongo.ObjectID(notification)
+ });
+ } else {
+ n = notification as INotification;
+ }
+
+ if (n == null) return;
+
+ // このNotificationを削除
+ await Notification.remove({
+ _id: n._id
+ });
+}
+
/**
* Pack a notification for API response
*/
diff --git a/src/models/user.ts b/src/models/user.ts
index c121790c3..1d23c21db 100644
--- a/src/models/user.ts
+++ b/src/models/user.ts
@@ -19,12 +19,15 @@ import PollVote, { deletePollVote } from './poll-vote';
import FollowingLog, { deleteFollowingLog } from './following-log';
import FollowedLog, { deleteFollowedLog } from './followed-log';
import SwSubscription, { deleteSwSubscription } from './sw-subscription';
+import Notification, { deleteNotification } from './notification';
const User = db.get('users');
User.createIndex('username');
User.createIndex('usernameLower');
-User.createIndex('token');
+User.createIndex(['username', 'host'], { unique: true });
+User.createIndex(['usernameLower', 'host'], { unique: true });
+User.createIndex('token', { sparse: true, unique: true });
User.createIndex('uri', { sparse: true, unique: true });
export default User;
@@ -49,7 +52,6 @@ type IUserBase = {
isSuspended: boolean;
keywords: string[];
host: string;
- hostLower: string;
};
export interface ILocalUser extends IUserBase {
@@ -153,6 +155,8 @@ export async function deleteUser(user: string | mongo.ObjectID | IUser) {
u = user as IUser;
}
+ console.log(u == null ? `User: delete skipped ${user}` : `User: deleting ${u._id}`);
+
if (u == null) return;
// このユーザーのAccessTokenをすべて削除
@@ -245,7 +249,22 @@ export async function deleteUser(user: string | mongo.ObjectID | IUser) {
await SwSubscription.find({ userId: u._id })
).map(x => deleteSwSubscription(x)));
+ // このユーザーのNotificationをすべて削除
+ await Promise.all((
+ await Notification.find({ notifieeId: u._id })
+ ).map(x => deleteNotification(x)));
+
+ // このユーザーが原因となったNotificationをすべて削除
+ await Promise.all((
+ await Notification.find({ notifierId: u._id })
+ ).map(x => deleteNotification(x)));
+
// このユーザーを削除
+ await User.remove({
+ _id: u._id
+ });
+
+ console.log(`User: deleted ${u._id}`);
}
/**
diff --git a/src/queue/index.ts b/src/queue/index.ts
index 4aa1dc032..94efb3634 100644
--- a/src/queue/index.ts
+++ b/src/queue/index.ts
@@ -19,12 +19,12 @@ export function createHttp(data) {
}
export function deliver(user, content, to) {
- return createHttp({
+ createHttp({
type: 'deliver',
user,
content,
to
- });
+ }).save();
}
export default function() {
diff --git a/src/queue/processors/http/process-inbox.ts b/src/queue/processors/http/process-inbox.ts
index ce5b7d5a8..2c49a67b6 100644
--- a/src/queue/processors/http/process-inbox.ts
+++ b/src/queue/processors/http/process-inbox.ts
@@ -1,7 +1,7 @@
import * as kue from 'kue';
import * as debug from 'debug';
-import { verifySignature } from 'http-signature';
+const httpSignature = require('http-signature');
import parseAcct from '../../../acct/parse';
import User, { IRemoteUser } from '../../../models/user';
import perform from '../../../remote/activitypub/perform';
@@ -32,7 +32,7 @@ export default async (job: kue.Job, done): Promise => {
return;
}
- user = await User.findOne({ usernameLower: username, hostLower: host }) as IRemoteUser;
+ user = await User.findOne({ usernameLower: username, host: host.toLowerCase() }) as IRemoteUser;
} else {
user = await User.findOne({
host: { $ne: null },
@@ -50,7 +50,7 @@ export default async (job: kue.Job, done): Promise => {
return;
}
- if (!verifySignature(signature, user.publicKey.publicKeyPem)) {
+ if (!httpSignature.verifySignature(signature, user.publicKey.publicKeyPem)) {
console.warn('signature verification failed');
done();
return;
diff --git a/src/remote/activitypub/objects/person.ts b/src/remote/activitypub/objects/person.ts
index f7ec064cd..6c060f879 100644
--- a/src/remote/activitypub/objects/person.ts
+++ b/src/remote/activitypub/objects/person.ts
@@ -74,8 +74,7 @@ export async function createPerson(value: any, resolver?: Resolver): Promise matched.toLowerCase());
+ const host = toUnicode(finger.subject.replace(/^.*?@/, '')).toLowerCase();
const summaryDOM = JSDOM.fragment(person.summary);
// Create user
@@ -92,7 +91,6 @@ export async function createPerson(value: any, resolver?: Resolver): Promise {
+export default async (username, _host, option) => {
const usernameLower = username.toLowerCase();
- const hostLowerAscii = toASCII(host).toLowerCase();
- const hostLower = toUnicode(hostLowerAscii);
+ const hostAscii = toASCII(_host).toLowerCase();
+ const host = toUnicode(hostAscii);
- if (config.host == hostLower) {
+ if (config.host == host) {
return await User.findOne({ usernameLower });
}
- let user = await User.findOne({ usernameLower, hostLower }, option);
+ let user = await User.findOne({ usernameLower, host }, option);
if (user === null) {
- const acctLower = `${usernameLower}@${hostLowerAscii}`;
+ const acctLower = `${usernameLower}@${hostAscii}`;
const finger = await webFinger(acctLower);
const self = finger.links.find(link => link.rel && link.rel.toLowerCase() === 'self');
diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index 2a99bccfc..e27e2552f 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -1,5 +1,6 @@
import * as Router from 'koa-router';
-import { parseRequest } from 'http-signature';
+const json = require('koa-json-body');
+const httpSignature = require('http-signature');
import { createHttp } from '../queue';
import pack from '../remote/activitypub/renderer';
@@ -18,13 +19,13 @@ const router = new Router();
//#region Routing
// inbox
-router.post('/users/:user/inbox', ctx => {
+router.post('/users/:user/inbox', json(), ctx => {
let signature;
ctx.req.headers.authorization = 'Signature ' + ctx.req.headers.signature;
try {
- signature = parseRequest(ctx.req);
+ signature = httpSignature.parseRequest(ctx.req);
} catch (e) {
ctx.status = 401;
return;
diff --git a/src/server/api/common/get-host-lower.ts b/src/server/api/common/get-host-lower.ts
index fc4b30439..550c23300 100644
--- a/src/server/api/common/get-host-lower.ts
+++ b/src/server/api/common/get-host-lower.ts
@@ -1,5 +1,5 @@
import { toUnicode } from 'punycode';
export default host => {
- return toUnicode(host).replace(/[A-Z]+/, match => match.toLowerCase());
+ return toUnicode(host).toLowerCase();
};
diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts
index e91b75e1d..bd4247c79 100644
--- a/src/server/api/endpoints/users/notes.ts
+++ b/src/server/api/endpoints/users/notes.ts
@@ -65,7 +65,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
const q = userId !== undefined
? { _id: userId }
- : { usernameLower: username.toLowerCase(), hostLower: getHostLower(host) } ;
+ : { usernameLower: username.toLowerCase(), host: getHostLower(host) } ;
// Lookup user
const user = await User.findOne(q, {
diff --git a/src/server/api/endpoints/users/recommendation.ts b/src/server/api/endpoints/users/recommendation.ts
index 2de22da13..e367e65a6 100644
--- a/src/server/api/endpoints/users/recommendation.ts
+++ b/src/server/api/endpoints/users/recommendation.ts
@@ -30,15 +30,13 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
_id: {
$nin: followingIds
},
- $or: [
- {
- 'lastUsedAt': {
- $gte: new Date(Date.now() - ms('7days'))
- }
- }, {
- host: { $ne: null }
+ $or: [{
+ 'lastUsedAt': {
+ $gte: new Date(Date.now() - ms('7days'))
}
- ]
+ }, {
+ host: null
+ }]
}, {
limit: limit,
skip: offset,
diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts
index 15257b869..cf51dec4d 100644
--- a/src/server/api/private/signup.ts
+++ b/src/server/api/private/signup.ts
@@ -118,7 +118,6 @@ export default async (ctx: Koa.Context) => {
username: username,
usernameLower: username.toLowerCase(),
host: null,
- hostLower: null,
keypair: generateKeypair(),
token: secret,
email: null,
diff --git a/src/server/api/service/twitter.ts b/src/server/api/service/twitter.ts
index 9fb01b44e..284ae7ee2 100644
--- a/src/server/api/service/twitter.ts
+++ b/src/server/api/service/twitter.ts
@@ -107,7 +107,7 @@ if (config.twitter == null) {
ctx.redirect(twCtx.url);
});
- router.get('/tw/cb', ctx => {
+ router.get('/tw/cb', async ctx => {
const userToken = getUserToken(ctx);
if (userToken == null) {
@@ -118,21 +118,27 @@ if (config.twitter == null) {
return;
}
- redis.get(sessid, async (_, twCtx) => {
- const result = await twAuth.done(JSON.parse(twCtx), ctx.query.oauth_verifier);
-
- const user = await User.findOne({
- host: null,
- 'twitter.userId': result.userId
- }) as ILocalUser;
-
- if (user == null) {
- ctx.throw(404, `@${result.screenName}と連携しているMisskeyアカウントはありませんでした...`);
- return;
- }
-
- signin(ctx, user, true);
+ const get = new Promise((res, rej) => {
+ redis.get(sessid, async (_, twCtx) => {
+ res(twCtx);
+ });
});
+
+ const twCtx = await get;
+
+ const result = await twAuth.done(JSON.parse(twCtx), ctx.query.oauth_verifier);
+
+ const user = await User.findOne({
+ host: null,
+ 'twitter.userId': result.userId
+ }) as ILocalUser;
+
+ if (user == null) {
+ ctx.throw(404, `@${result.screenName}と連携しているMisskeyアカウントはありませんでした...`);
+ return;
+ }
+
+ signin(ctx, user, true);
} else {
const verifier = ctx.query.oauth_verifier;
@@ -141,31 +147,37 @@ if (config.twitter == null) {
return;
}
- redis.get(userToken, async (_, twCtx) => {
- const result = await twAuth.done(JSON.parse(twCtx), verifier);
-
- const user = await User.findOneAndUpdate({
- host: null,
- token: userToken
- }, {
- $set: {
- twitter: {
- accessToken: result.accessToken,
- accessTokenSecret: result.accessTokenSecret,
- userId: result.userId,
- screenName: result.screenName
- }
- }
+ const get = new Promise((res, rej) => {
+ redis.get(userToken, async (_, twCtx) => {
+ res(twCtx);
});
-
- ctx.body = `Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`;
-
- // Publish i updated event
- event(user._id, 'i_updated', await pack(user, user, {
- detail: true,
- includeSecrets: true
- }));
});
+
+ const twCtx = await get;
+
+ const result = await twAuth.done(JSON.parse(twCtx), verifier);
+
+ const user = await User.findOneAndUpdate({
+ host: null,
+ token: userToken
+ }, {
+ $set: {
+ twitter: {
+ accessToken: result.accessToken,
+ accessTokenSecret: result.accessTokenSecret,
+ userId: result.userId,
+ screenName: result.screenName
+ }
+ }
+ });
+
+ ctx.body = `Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`;
+
+ // Publish i updated event
+ event(user._id, 'i_updated', await pack(user, user, {
+ detail: true,
+ includeSecrets: true
+ }));
}
});
}
diff --git a/src/server/file/index.ts b/src/server/file/index.ts
index d305286d1..29056c63e 100644
--- a/src/server/file/index.ts
+++ b/src/server/file/index.ts
@@ -14,6 +14,7 @@ const app = new Koa();
app.use(cors());
app.use(async (ctx, next) => {
+ // Cache 365days
ctx.set('Cache-Control', 'max-age=31536000, immutable');
await next();
});
diff --git a/src/server/index.ts b/src/server/index.ts
index db41a1dcb..5db3da2b9 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -53,6 +53,7 @@ function createServer() {
Object.keys(config.https).forEach(k => {
certs[k] = fs.readFileSync(config.https[k]);
});
+ certs['allowHTTP1'] = true;
return http2.createSecureServer(certs, app.callback());
} else {
return http.createServer(app.callback());
@@ -62,13 +63,9 @@ function createServer() {
export default () => new Promise(resolve => {
const server = createServer();
- /**
- * Steaming
- */
+ // Init stream server
require('./api/streaming')(server);
- /**
- * Server listen
- */
+ // Listen
server.listen(config.port, resolve);
});
diff --git a/src/server/web/url-preview.ts b/src/server/web/url-preview.ts
index 4b3f44a5d..d5464d0cd 100644
--- a/src/server/web/url-preview.ts
+++ b/src/server/web/url-preview.ts
@@ -5,6 +5,10 @@ module.exports = async (ctx: Koa.Context) => {
const summary = await summaly(ctx.query.url);
summary.icon = wrap(summary.icon);
summary.thumbnail = wrap(summary.thumbnail);
+
+ // Cache 7days
+ ctx.set('Cache-Control', 'max-age=604800, immutable');
+
ctx.body = summary;
};
diff --git a/src/services/following/create.ts b/src/services/following/create.ts
index 3289e3129..375b02891 100644
--- a/src/services/following/create.ts
+++ b/src/services/following/create.ts
@@ -58,11 +58,11 @@ export default async function(follower: IUser, followee: IUser, activity?) {
if (isLocalUser(follower) && isRemoteUser(followee)) {
const content = pack(renderFollow(follower, followee));
- deliver(follower, content, followee.inbox).save();
+ deliver(follower, content, followee.inbox);
}
if (isRemoteUser(follower) && isLocalUser(followee)) {
const content = pack(renderAccept(activity));
- deliver(followee, content, follower.inbox).save();
+ deliver(followee, content, follower.inbox);
}
}
diff --git a/src/services/following/delete.ts b/src/services/following/delete.ts
index 8b6c56816..c0c99fbed 100644
--- a/src/services/following/delete.ts
+++ b/src/services/following/delete.ts
@@ -57,6 +57,6 @@ export default async function(follower: IUser, followee: IUser, activity?) {
if (isLocalUser(follower) && isRemoteUser(followee)) {
const content = pack(renderUndo(renderFollow(follower, followee)));
- deliver(follower, content, followee.inbox).save();
+ deliver(follower, content, followee.inbox);
}
}
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index b238cd560..781337daf 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -78,7 +78,6 @@ export default async (user: IUser, data: {
_renote: data.renote ? { userId: data.renote.userId } : null,
_user: {
host: user.host,
- hostLower: user.hostLower,
inbox: isRemoteUser(user) ? user.inbox : undefined
}
};
@@ -137,12 +136,12 @@ export default async (user: IUser, data: {
// 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
if (data.reply && isLocalUser(user) && isRemoteUser(data.reply._user)) {
- deliver(user, await render(), data.reply._user.inbox).save();
+ deliver(user, await render(), data.reply._user.inbox);
}
// 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送
if (data.renote && isLocalUser(user) && isRemoteUser(data.renote._user)) {
- deliver(user, await render(), data.renote._user.inbox).save();
+ deliver(user, await render(), data.renote._user.inbox);
}
Promise.all(followers.map(async follower => {
@@ -154,7 +153,7 @@ export default async (user: IUser, data: {
} else {
// フォロワーがリモートユーザーかつ投稿者がローカルユーザーなら投稿を配信
if (isLocalUser(user)) {
- deliver(user, await render(), follower.inbox).save();
+ deliver(user, await render(), follower.inbox);
}
}
}));
diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts
index 69a14248d..dd3d4be8b 100644
--- a/src/services/note/reaction/create.ts
+++ b/src/services/note/reaction/create.ts
@@ -9,6 +9,7 @@ import watch from '../watch';
import renderLike from '../../../remote/activitypub/renderer/like';
import { deliver } from '../../../queue';
import pack from '../../../remote/activitypub/renderer';
+import { MongoError } from 'mongodb';
export default async (user: IUser, note: INote, reaction: string) => new Promise(async (res, rej) => {
// Myself
@@ -16,23 +17,23 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise
return rej('cannot react to my note');
}
- // if already reacted
- const exist = await NoteReaction.findOne({
- noteId: note._id,
- userId: user._id
- });
-
- if (exist !== null) {
- return rej('already reacted');
- }
-
// Create reaction
- await NoteReaction.insert({
- createdAt: new Date(),
- noteId: note._id,
- userId: user._id,
- reaction
- });
+ try {
+ await NoteReaction.insert({
+ createdAt: new Date(),
+ noteId: note._id,
+ userId: user._id,
+ reaction
+ });
+ } catch (e) {
+ // duplicate key error
+ if (e instanceof MongoError && e.code === 11000) {
+ return rej('already reacted');
+ }
+
+ console.error(e);
+ return rej('something happened');
+ }
res();
@@ -86,7 +87,7 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise
// リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送
if (isLocalUser(user) && isRemoteUser(note._user)) {
const content = pack(renderLike(user, note));
- deliver(user, content, note._user.inbox).save();
+ deliver(user, content, note._user.inbox);
}
//#endregion
});
diff --git a/tools/migration/nighthike/10.js b/tools/migration/nighthike/10.js
deleted file mode 100644
index 3c57b8d48..000000000
--- a/tools/migration/nighthike/10.js
+++ /dev/null
@@ -1,3 +0,0 @@
-db.following.remove({
- deletedAt: { $exists: true }
-});
diff --git a/tools/migration/nighthike/11.js b/tools/migration/nighthike/11.js
deleted file mode 100644
index 2a4e8630d..000000000
--- a/tools/migration/nighthike/11.js
+++ /dev/null
@@ -1,36 +0,0 @@
-db.pollVotes.update({}, {
- $rename: {
- postId: 'noteId',
- }
-}, false, true);
-
-db.postReactions.renameCollection('noteReactions');
-db.noteReactions.update({}, {
- $rename: {
- postId: 'noteId',
- }
-}, false, true);
-
-db.postWatching.renameCollection('noteWatching');
-db.noteWatching.update({}, {
- $rename: {
- postId: 'noteId',
- }
-}, false, true);
-
-db.posts.renameCollection('notes');
-db.notes.update({}, {
- $rename: {
- _repost: '_renote',
- repostId: 'renoteId',
- repostCount: 'renoteCount'
- }
-}, false, true);
-
-db.users.update({}, {
- $rename: {
- postsCount: 'notesCount',
- pinnedPostId: 'pinnedNoteId',
- latestPost: 'latestNote'
- }
-}, false, true);
diff --git a/tools/migration/nighthike/12.js b/tools/migration/nighthike/12.js
deleted file mode 100644
index f4b61e2ee..000000000
--- a/tools/migration/nighthike/12.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// for Node.js interpret
-
-const { default: User } = require('../../../built/models/user');
-const { generate } = require('../../../built/crypto_key');
-const { default: zip } = require('@prezzemolo/zip')
-
-const migrate = async (user) => {
- const result = await User.update(user._id, {
- $unset: {
- account: ''
- },
- $set: {
- host: null,
- hostLower: null,
- email: user.account.email,
- links: user.account.links,
- password: user.account.password,
- token: user.account.token,
- twitter: user.account.twitter,
- line: user.account.line,
- profile: user.account.profile,
- lastUsedAt: user.account.lastUsedAt,
- isBot: user.account.isBot,
- isPro: user.account.isPro,
- twoFactorSecret: user.account.twoFactorSecret,
- twoFactorEnabled: user.account.twoFactorEnabled,
- clientSettings: user.account.clientSettings,
- settings: user.account.settings,
- keypair: user.account.keypair
- }
- });
- return result.ok === 1;
-}
-
-async function main() {
- const count = await User.count({});
-
- const dop = Number.parseInt(process.argv[2]) || 5
- const idop = ((count - (count % dop)) / dop) + 1
-
- return zip(
- 1,
- async (time) => {
- console.log(`${time} / ${idop}`)
- const doc = await User.find({}, {
- limit: dop, skip: time * dop
- })
- return Promise.all(doc.map(migrate))
- },
- idop
- ).then(a => {
- const rv = []
- a.forEach(e => rv.push(...e))
- return rv
- })
-}
-
-main().then(console.dir).catch(console.error)
diff --git a/tools/migration/nighthike/2.js b/tools/migration/nighthike/2.js
deleted file mode 100644
index bb516db5b..000000000
--- a/tools/migration/nighthike/2.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// for Node.js interpret
-
-const { default: App } = require('../../../built/models/app');
-const { default: zip } = require('@prezzemolo/zip')
-
-const migrate = async (app) => {
- const result = await App.update(app._id, {
- $set: {
- 'name_id': app.name_id.replace(/\-/g, '_'),
- 'name_id_lower': app.name_id_lower.replace(/\-/g, '_')
- }
- });
- return result.ok === 1;
-}
-
-async function main() {
- const count = await App.count({});
-
- const dop = Number.parseInt(process.argv[2]) || 5
- const idop = ((count - (count % dop)) / dop) + 1
-
- return zip(
- 1,
- async (time) => {
- console.log(`${time} / ${idop}`)
- const doc = await App.find({}, {
- limit: dop, skip: time * dop
- })
- return Promise.all(doc.map(migrate))
- },
- idop
- ).then(a => {
- const rv = []
- a.forEach(e => rv.push(...e))
- return rv
- })
-}
-
-main().then(console.dir).catch(console.error)
diff --git a/tools/migration/nighthike/3.js b/tools/migration/nighthike/3.js
deleted file mode 100644
index bde4f773d..000000000
--- a/tools/migration/nighthike/3.js
+++ /dev/null
@@ -1,73 +0,0 @@
-// for Node.js interpret
-
-const { default: User } = require('../../../built/models/user');
-const { generate } = require('../../../built/crypto_key');
-const { default: zip } = require('@prezzemolo/zip')
-
-const migrate = async (user) => {
- const result = await User.update(user._id, {
- $unset: {
- email: '',
- links: '',
- password: '',
- token: '',
- twitter: '',
- line: '',
- profile: '',
- last_used_at: '',
- is_bot: '',
- is_pro: '',
- two_factor_secret: '',
- two_factor_enabled: '',
- client_settings: '',
- settings: ''
- },
- $set: {
- host: null,
- host_lower: null,
- account: {
- email: user.email,
- links: user.links,
- password: user.password,
- token: user.token,
- twitter: user.twitter,
- line: user.line,
- profile: user.profile,
- last_used_at: user.last_used_at,
- is_bot: user.is_bot,
- is_pro: user.is_pro,
- two_factor_secret: user.two_factor_secret,
- two_factor_enabled: user.two_factor_enabled,
- client_settings: user.client_settings,
- settings: user.settings,
- keypair: generate()
- }
- }
- });
- return result.ok === 1;
-}
-
-async function main() {
- const count = await User.count({});
-
- const dop = Number.parseInt(process.argv[2]) || 5
- const idop = ((count - (count % dop)) / dop) + 1
-
- return zip(
- 1,
- async (time) => {
- console.log(`${time} / ${idop}`)
- const doc = await User.find({}, {
- limit: dop, skip: time * dop
- })
- return Promise.all(doc.map(migrate))
- },
- idop
- ).then(a => {
- const rv = []
- a.forEach(e => rv.push(...e))
- return rv
- })
-}
-
-main().then(console.dir).catch(console.error)
diff --git a/tools/migration/nighthike/4.js b/tools/migration/nighthike/4.js
deleted file mode 100644
index 5e12e6405..000000000
--- a/tools/migration/nighthike/4.js
+++ /dev/null
@@ -1,262 +0,0 @@
-// このスクリプトを走らせる前か後に notifications コレクションはdropしてください
-
-db.access_tokens.renameCollection('accessTokens');
-db.accessTokens.update({}, {
- $rename: {
- created_at: 'createdAt',
- app_id: 'appId',
- user_id: 'userId',
- }
-}, false, true);
-
-db.apps.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- name_id: 'nameId',
- name_id_lower: 'nameIdLower',
- callback_url: 'callbackUrl',
- }
-}, false, true);
-
-db.auth_sessions.renameCollection('authSessions');
-db.authSessions.update({}, {
- $rename: {
- created_at: 'createdAt',
- app_id: 'appId',
- user_id: 'userId',
- }
-}, false, true);
-
-db.channel_watching.renameCollection('channelWatching');
-db.channelWatching.update({}, {
- $rename: {
- created_at: 'createdAt',
- deleted_at: 'deletedAt',
- channel_id: 'channelId',
- user_id: 'userId',
- }
-}, false, true);
-
-db.channels.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- watching_count: 'watchingCount'
- }
-}, false, true);
-
-db.drive_files.files.renameCollection('driveFiles.files');
-db.drive_files.chunks.renameCollection('driveFiles.chunks');
-db.driveFiles.files.update({}, {
- $rename: {
- 'metadata.user_id': 'metadata.userId'
- }
-}, false, true);
-db.driveFiles.files.update({
- 'metadata.folder_id': { $ne: null }
-}, {
- $rename: {
- 'metadata.folder_id': 'metadata.folderId',
- }
-}, false, true);
-db.driveFiles.files.update({
- 'metadata.properties.average_color': { $ne: null }
-}, {
- $rename: {
- 'metadata.properties.average_color': 'metadata.properties.avgColor'
- }
-}, false, true);
-
-db.drive_folders.renameCollection('driveFolders');
-db.driveFolders.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- parent_id: 'parentId',
- }
-}, false, true);
-
-db.favorites.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- post_id: 'postId',
- }
-}, false, true);
-
-db.following.update({}, {
- $rename: {
- created_at: 'createdAt',
- deleted_at: 'deletedAt',
- followee_id: 'followeeId',
- follower_id: 'followerId',
- }
-}, false, true);
-
-db.messaging_histories.renameCollection('messagingHistories');
-db.messagingHistories.update({}, {
- $rename: {
- updated_at: 'updatedAt',
- user_id: 'userId',
- partner: 'partnerId',
- message: 'messageId',
- }
-}, false, true);
-
-db.messaging_messages.renameCollection('messagingMessages');
-db.messagingMessages.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- recipient_id: 'recipientId',
- file_id: 'fileId',
- is_read: 'isRead'
- }
-}, false, true);
-
-db.mute.update({}, {
- $rename: {
- created_at: 'createdAt',
- deleted_at: 'deletedAt',
- mutee_id: 'muteeId',
- muter_id: 'muterId',
- }
-}, false, true);
-
-db.othello_games.renameCollection('othelloGames');
-db.othelloGames.update({}, {
- $rename: {
- created_at: 'createdAt',
- started_at: 'startedAt',
- is_started: 'isStarted',
- is_ended: 'isEnded',
- user1_id: 'user1Id',
- user2_id: 'user2Id',
- user1_accepted: 'user1Accepted',
- user2_accepted: 'user2Accepted',
- winner_id: 'winnerId',
- 'settings.is_llotheo': 'settings.isLlotheo',
- 'settings.can_put_everywhere': 'settings.canPutEverywhere',
- 'settings.looped_board': 'settings.loopedBoard',
- }
-}, false, true);
-
-db.othello_matchings.renameCollection('othelloMatchings');
-db.othelloMatchings.update({}, {
- $rename: {
- created_at: 'createdAt',
- parent_id: 'parentId',
- child_id: 'childId'
- }
-}, false, true);
-
-db.poll_votes.renameCollection('pollVotes');
-db.pollVotes.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- post_id: 'postId'
- }
-}, false, true);
-
-db.post_reactions.renameCollection('postReactions');
-db.postReactions.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- post_id: 'postId'
- }
-}, false, true);
-
-db.post_watching.renameCollection('postWatching');
-db.postWatching.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- post_id: 'postId'
- }
-}, false, true);
-
-db.posts.update({}, {
- $rename: {
- created_at: 'createdAt',
- channel_id: 'channelId',
- user_id: 'userId',
- app_id: 'appId',
- media_ids: 'mediaIds',
- reply_id: 'replyId',
- repost_id: 'repostId',
- via_mobile: 'viaMobile',
- reaction_counts: 'reactionCounts',
- replies_count: 'repliesCount',
- repost_count: 'repostCount'
- }
-}, false, true);
-
-db.posts.update({
- _reply: { $ne: null }
-}, {
- $rename: {
- '_reply.user_id': '_reply.userId',
- }
-}, false, true);
-
-db.posts.update({
- _repost: { $ne: null }
-}, {
- $rename: {
- '_repost.user_id': '_repost.userId',
- }
-}, false, true);
-
-db.signin.update({}, {
- $rename: {
- created_at: 'createdAt',
- user_id: 'userId',
- }
-}, false, true);
-
-db.sw_subscriptions.renameCollection('swSubscriptions');
-db.swSubscriptions.update({}, {
- $rename: {
- user_id: 'userId',
- }
-}, false, true);
-
-db.users.update({}, {
- $unset: {
- likes_count: '',
- liked_count: '',
- latest_post: '',
- 'account.twitter.access_token': '',
- 'account.twitter.access_token_secret': '',
- 'account.twitter.user_id': '',
- 'account.twitter.screen_name': '',
- 'account.line.user_id': '',
- 'account.client_settings.mobile_home': ''
- }
-}, false, true);
-
-db.users.update({}, {
- $rename: {
- created_at: 'createdAt',
- deleted_at: 'deletedAt',
- followers_count: 'followersCount',
- following_count: 'followingCount',
- posts_count: 'postsCount',
- drive_capacity: 'driveCapacity',
- username_lower: 'usernameLower',
- avatar_id: 'avatarId',
- banner_id: 'bannerId',
- pinned_post_id: 'pinnedPostId',
- is_suspended: 'isSuspended',
- host_lower: 'hostLower',
- 'account.last_used_at': 'account.lastUsedAt',
- 'account.is_bot': 'account.isBot',
- 'account.is_pro': 'account.isPro',
- 'account.two_factor_secret': 'account.twoFactorSecret',
- 'account.two_factor_enabled': 'account.twoFactorEnabled',
- 'account.client_settings': 'account.clientSettings'
- }
-}, false, true);
diff --git a/tools/migration/nighthike/5.js b/tools/migration/nighthike/5.js
deleted file mode 100644
index 3989ea630..000000000
--- a/tools/migration/nighthike/5.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// for Node.js interpret
-
-const mongodb = require("../../../built/db/mongodb");
-const Post = mongodb.default.get('posts');
-
-const { default: zip } = require('@prezzemolo/zip')
-
-const migrate = async (post) => {
- const result = await Post.update(post._id, {
- $set: {
- 'geo.type': 'Point',
- 'geo.coordinates': [post.geo.longitude, post.geo.latitude]
- },
- $unset: {
- 'geo.longitude': '',
- 'geo.latitude': '',
- }
- });
- return result.ok === 1;
-}
-
-async function main() {
- const count = await Post.count({
- 'geo': { $ne: null }
- });
-
- const dop = Number.parseInt(process.argv[2]) || 5
- const idop = ((count - (count % dop)) / dop) + 1
-
- return zip(
- 1,
- async (time) => {
- console.log(`${time} / ${idop}`)
- const doc = await Post.find({
- 'geo': { $ne: null }
- }, {
- limit: dop, skip: time * dop
- })
- return Promise.all(doc.map(migrate))
- },
- idop
- ).then(a => {
- const rv = []
- a.forEach(e => rv.push(...e))
- return rv
- })
-}
-
-main().then(console.dir).catch(console.error)
diff --git a/tools/migration/nighthike/6.js b/tools/migration/nighthike/6.js
deleted file mode 100644
index 27fff2ec1..000000000
--- a/tools/migration/nighthike/6.js
+++ /dev/null
@@ -1,13 +0,0 @@
-db.posts.update({
- $or: [{
- mediaIds: null
- }, {
- mediaIds: {
- $exists: false
- }
- }]
-}, {
- $set: {
- mediaIds: []
- }
-}, false, true);
diff --git a/tools/migration/nighthike/7.js b/tools/migration/nighthike/7.js
deleted file mode 100644
index ed5f1e6b9..000000000
--- a/tools/migration/nighthike/7.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// for Node.js interpret
-
-const mongodb = require("../../../built/db/mongodb");
-const Post = mongodb.default.get('posts');
-const { default: zip } = require('@prezzemolo/zip')
-const html = require('../../../built/text/html').default;
-const parse = require('../../../built/text/parse').default;
-
-const migrate = async (post) => {
- const result = await Post.update(post._id, {
- $set: {
- textHtml: post.text ? html(parse(post.text)) : null
- }
- });
- return result.ok === 1;
-}
-
-async function main() {
- const count = await Post.count({});
-
- const dop = Number.parseInt(process.argv[2]) || 5
- const idop = ((count - (count % dop)) / dop) + 1
-
- return zip(
- 1,
- async (time) => {
- console.log(`${time} / ${idop}`)
- const doc = await Post.find({}, {
- limit: dop, skip: time * dop
- })
- return Promise.all(doc.map(migrate))
- },
- idop
- ).then(a => {
- const rv = []
- a.forEach(e => rv.push(...e))
- return rv
- })
-}
-
-main().then(console.dir).catch(console.error)
diff --git a/tools/migration/nighthike/8.js b/tools/migration/nighthike/8.js
deleted file mode 100644
index e4f4482db..000000000
--- a/tools/migration/nighthike/8.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// for Node.js interpret
-
-const { default: Message } = require('../../../built/models/messaging-message');
-const { default: zip } = require('@prezzemolo/zip')
-const html = require('../../../built/text/html').default;
-const parse = require('../../../built/text/parse').default;
-
-const migrate = async (message) => {
- const result = await Message.update(message._id, {
- $set: {
- textHtml: message.text ? html(parse(message.text)) : null
- }
- });
- return result.ok === 1;
-}
-
-async function main() {
- const count = await Message.count({});
-
- const dop = Number.parseInt(process.argv[2]) || 5
- const idop = ((count - (count % dop)) / dop) + 1
-
- return zip(
- 1,
- async (time) => {
- console.log(`${time} / ${idop}`)
- const doc = await Message.find({}, {
- limit: dop, skip: time * dop
- })
- return Promise.all(doc.map(migrate))
- },
- idop
- ).then(a => {
- const rv = []
- a.forEach(e => rv.push(...e))
- return rv
- })
-}
-
-main().then(console.dir).catch(console.error)
diff --git a/tools/migration/nighthike/9.js b/tools/migration/nighthike/9.js
deleted file mode 100644
index f4e1ab341..000000000
--- a/tools/migration/nighthike/9.js
+++ /dev/null
@@ -1,93 +0,0 @@
-// for Node.js interpret
-
-const { default: Following } = require('../../../built/models/following');
-const { default: FollowingLog } = require('../../../built/models/following-log');
-const { default: FollowedLog } = require('../../../built/models/followed-log');
-const { default: zip } = require('@prezzemolo/zip')
-
-const migrate = async (following) => {
- const followingCount = await Following.count({
- followerId: following.followerId,
- createdAt: { $lt: following.createdAt },
- $or: [
- { deletedAt: { $exists: false } },
- { deletedAt: { $gt: following.createdAt } }
- ]
- });
- await FollowingLog.insert({
- createdAt: following.createdAt,
- userId: following.followerId,
- count: followingCount + 1
- });
-
- const followersCount = await Following.count({
- followeeId: following.followeeId,
- createdAt: { $lt: following.createdAt },
- $or: [
- { deletedAt: { $exists: false } },
- { deletedAt: { $gt: following.createdAt } }
- ]
- });
- await FollowedLog.insert({
- createdAt: following.createdAt,
- userId: following.followeeId,
- count: followersCount + 1
- });
-
- if (following.deletedAt) {
- const followingCount2 = await Following.count({
- followerId: following.followerId,
- createdAt: { $lt: following.deletedAt },
- $or: [
- { deletedAt: { $exists: false } },
- { deletedAt: { $gt: following.createdAt } }
- ]
- });
- await FollowingLog.insert({
- createdAt: following.deletedAt,
- userId: following.followerId,
- count: followingCount2 - 1
- });
-
- const followersCount2 = await Following.count({
- followeeId: following.followeeId,
- createdAt: { $lt: following.deletedAt },
- $or: [
- { deletedAt: { $exists: false } },
- { deletedAt: { $gt: following.createdAt } }
- ]
- });
- await FollowedLog.insert({
- createdAt: following.deletedAt,
- userId: following.followeeId,
- count: followersCount2 - 1
- });
- }
-
- return true;
-}
-
-async function main() {
- const count = await Following.count({});
-
- const dop = Number.parseInt(process.argv[2]) || 5
- const idop = ((count - (count % dop)) / dop) + 1
-
- return zip(
- 1,
- async (time) => {
- console.log(`${time} / ${idop}`)
- const doc = await Following.find({}, {
- limit: dop, skip: time * dop, sort: { _id: 1 }
- })
- return Promise.all(doc.map(migrate))
- },
- idop
- ).then(a => {
- const rv = []
- a.forEach(e => rv.push(...e))
- return rv
- })
-}
-
-main().then(console.dir).catch(console.error)
diff --git a/webpack.config.ts b/webpack.config.ts
index 60dbfd2ff..bc876e067 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -42,7 +42,7 @@ const langs = Object.keys(locales);
const entries = process.env.NODE_ENV == 'production'
? langs.map(l => [l, false]).concat(langs.map(l => [l, true]))
- : [['ja', false]];
+ : langs.map(l => [l, false]);
module.exports = entries.map(x => {
const [lang, isProduction] = x;
@@ -143,7 +143,9 @@ module.exports = entries.map(x => {
loader: 'replace',
query: {
search: i18nReplacer.pattern.toString(),
- replace: 'i18nReplacement'
+ replace: 'i18nReplacement',
+ i18n: true,
+ lang
}
}, {
loader: 'replace',
@@ -214,7 +216,9 @@ module.exports = entries.map(x => {
loader: 'replace',
query: {
search: i18nReplacer.pattern.toString(),
- replace: 'i18nReplacement'
+ replace: 'i18nReplacement',
+ i18n: true,
+ lang
}
}, {
loader: 'replace',
diff --git a/webpack/loaders/replace.js b/webpack/loaders/replace.js
index 03cf1fcd7..0326dcdab 100644
--- a/webpack/loaders/replace.js
+++ b/webpack/loaders/replace.js
@@ -9,7 +9,11 @@ module.exports = function(src) {
const options = loaderUtils.getOptions(this);
const search = options.search;
const g = search[search.length - 1] == 'g';
- const replace = global[options.replace];
+ const file = this.resourcePath.replace(/\\/g, '/');
+ const replace = options.i18n ? global[options.replace].bind(null, {
+ src: file,
+ lang: options.lang
+ }) : global[options.replace];
if (typeof search != 'string' || search.length == 0) console.error('invalid search');
if (typeof replace != 'function') console.error('invalid replacer:', replace, this.request);
src = src.replace(new RegExp(trim(search, g), g ? 'g' : ''), replace);