Compare commits
94 Commits
11.0.0-alp
...
11.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
063f372f3c | |||
987168b863 | |||
4ee40c3345 | |||
654daff7ce | |||
64e10e9619 | |||
b89cffe98d | |||
bd76ba702f | |||
5d52e9ce6b | |||
3c29027ca3 | |||
2ff3069d23 | |||
4198246351 | |||
2b6389b4dc | |||
d7df75ae6c | |||
11c30eccb3 | |||
ab8c6515b8 | |||
d4ad36fa41 | |||
4d688be3df | |||
d2b75f3501 | |||
46b78cb4ff | |||
5d6e0d0f37 | |||
e19d0a37bb | |||
dea3e2132e | |||
91c1ceefbd | |||
5c50989970 | |||
2a7e3b9c51 | |||
ab302df0ae | |||
21e5809993 | |||
c58afc67e8 | |||
8e344f2deb | |||
c28f4ffb3f | |||
2a40240310 | |||
0e9fba9287 | |||
2e3dd2a30a | |||
dda5f6559d | |||
4152e59638 | |||
9d5a92bce6 | |||
30172b92e6 | |||
8468a9d4c7 | |||
626cfb61ac | |||
9603f3fa4f | |||
619a1b9e53 | |||
62e76ad588 | |||
236d72685d | |||
72a5f7b1e2 | |||
d1c16a90b4 | |||
33a9783ae5 | |||
4d64fd665e | |||
96443384fe | |||
69939f1edb | |||
e3c0058942 | |||
3dc2361654 | |||
ec2f709018 | |||
ea06665c51 | |||
74a4bd704c | |||
c62f3e0e45 | |||
a56a969433 | |||
1016f94bbb | |||
e98cce9aee | |||
d4bdb5d327 | |||
db4378415e | |||
9b594880c8 | |||
d44fc3db2f | |||
5133b0a0c0 | |||
815469304f | |||
c651921c79 | |||
d18c835221 | |||
e38335077e | |||
34c150cf73 | |||
24cb3ba091 | |||
c07eaef2d1 | |||
5df708ac9f | |||
38ffbe95e9 | |||
8bec4042fc | |||
ee7ef89dfb | |||
54a5246061 | |||
fa6eae2937 | |||
795be20ee1 | |||
87d3a06dcd | |||
8b5c917195 | |||
c7da0e59ff | |||
eb14acbe0c | |||
56860a6bef | |||
735687be21 | |||
fab0cc51b3 | |||
3a26acbdb2 | |||
8d0c31bcda | |||
0b99293d4c | |||
802153ff9b | |||
ec73e2d237 | |||
c32b020535 | |||
c4441804e2 | |||
6c9d80d4e8 | |||
a231f8d26c | |||
08da258b63 |
19
CHANGELOG.md
19
CHANGELOG.md
@ -8,11 +8,26 @@ If you encounter any problems with updating, please try the following:
|
|||||||
11.0.0
|
11.0.0
|
||||||
----------
|
----------
|
||||||
* データベースがMongoDBからPostgreSQLに変更されました
|
* データベースがMongoDBからPostgreSQLに変更されました
|
||||||
|
* アカウントを完全に削除できるように
|
||||||
|
* ミュート/ブロック時にそのユーザーの投稿のウォッチをすべて解除するように
|
||||||
|
* フォロー申請数が実際より1すくなくなる問題を修正
|
||||||
|
* リストからアカウント削除したユーザーを削除できない問題を修正
|
||||||
|
* リストTLでフォローしていないユーザーの非公開投稿が流れる問題を修正
|
||||||
|
* リストTLでダイレクト投稿が流れない問題を修正
|
||||||
|
* ミュートしているユーザーの投稿がタイムラインに流れてくることがある問題を修正
|
||||||
|
|
||||||
### APIの破壊的変更
|
### APIの破壊的変更
|
||||||
* v10時点で deprecated だったパラメータなどを削除
|
* v10時点で deprecated だったパラメータなどを削除
|
||||||
* notes/hybrid-timeline が notes/social-timeline にリネーム
|
* ユーザーリストの title が name に
|
||||||
* ストリームの hybridTimeline チャンネルが socialTimeline にリネーム
|
|
||||||
|
10.100.0
|
||||||
|
----------
|
||||||
|
* ユーザーリストでフォローボタンを表示するように
|
||||||
|
* ドライブのファイルのサムネイルを修正
|
||||||
|
* 投稿ウィジットでローカルのみの公開範囲で投稿できない問題を修正
|
||||||
|
* TLを遡った時に抜けがある時がある問題を修正
|
||||||
|
* ユーザータイムラインが投稿日時順ではなくなっているのを修正
|
||||||
|
* 10.99.0 でチャートのレンダリングがおかしい問題を修正
|
||||||
|
|
||||||
10.99.0
|
10.99.0
|
||||||
----------
|
----------
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<a href="https://ai.misskey.xyz/"><img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/></a>
|
<a href="https://xn--931a.moe/"><img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/></a>
|
||||||
|
|
||||||
[](https://misskey.xyz/)
|
[](https://misskey.xyz/)
|
||||||
================================================================
|
================================================================
|
||||||
|
9
binding.gyp
Normal file
9
binding.gyp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'crypto_key',
|
||||||
|
'sources': ['src/crypto_key.cc'],
|
||||||
|
'include_dirs': ['<!(node -e "require(\'nan\')")']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
const mongo = require('mongodb');
|
|
||||||
const User = require('../built/models/user').default;
|
|
||||||
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
|
|
||||||
const user = args[0];
|
|
||||||
|
|
||||||
const q = user.startsWith('@') ? {
|
|
||||||
username: user.split('@')[1],
|
|
||||||
host: user.split('@')[2] || null
|
|
||||||
} : { _id: new mongo.ObjectID(user) };
|
|
||||||
|
|
||||||
console.log(`Mark as admin ${user}...`);
|
|
||||||
|
|
||||||
User.update(q, {
|
|
||||||
$set: {
|
|
||||||
isAdmin: true
|
|
||||||
}
|
|
||||||
}).then(() => {
|
|
||||||
console.log(`Done ${user}`);
|
|
||||||
}, e => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
@ -11,7 +11,7 @@ This guide describes how to install and setup Misskey with Docker.
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone Misskey repository's master branch.
|
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone Misskey repository's master branch.
|
||||||
2. `cd misskey` Move to misskey directory.
|
2. `cd misskey` Move to misskey directory.
|
||||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag.
|
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag.
|
||||||
|
|
||||||
*2.* Configure Misskey
|
*2.* Configure Misskey
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
@ -67,7 +67,7 @@ Just `docker-compose up -d`. GLHF!
|
|||||||
### How to update your Misskey server to the latest version
|
### How to update your Misskey server to the latest version
|
||||||
1. `git fetch`
|
1. `git fetch`
|
||||||
2. `git stash`
|
2. `git stash`
|
||||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
|
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||||
4. `git stash pop`
|
4. `git stash pop`
|
||||||
5. `docker-compose build`
|
5. `docker-compose build`
|
||||||
6. Check [ChangeLog](../CHANGELOG.md) for migration information
|
6. Check [ChangeLog](../CHANGELOG.md) for migration information
|
||||||
|
@ -12,7 +12,7 @@ Ce guide explique comment installer et configurer Misskey avec Docker.
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone le dépôt de Misskey sur la branche master.
|
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone le dépôt de Misskey sur la branche master.
|
||||||
2. `cd misskey` Naviguez dans le dossier du dépôt.
|
2. `cd misskey` Naviguez dans le dossier du dépôt.
|
||||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest).
|
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest).
|
||||||
|
|
||||||
*2.* Configuration de Misskey
|
*2.* Configuration de Misskey
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
@ -40,7 +40,7 @@ Utilisez la commande `docker-compose up -d`. GLHF!
|
|||||||
### How to update your Misskey server to the latest version
|
### How to update your Misskey server to the latest version
|
||||||
1. `git fetch`
|
1. `git fetch`
|
||||||
2. `git stash`
|
2. `git stash`
|
||||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
|
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||||
4. `git stash pop`
|
4. `git stash pop`
|
||||||
5. `docker-compose build`
|
5. `docker-compose build`
|
||||||
6. Consultez le [ChangeLog](../CHANGELOG.md) pour avoir les éventuelles informations de migration
|
6. Consultez le [ChangeLog](../CHANGELOG.md) pour avoir les éventuelles informations de migration
|
||||||
|
@ -11,7 +11,7 @@ Dockerを使ったMisskey構築方法
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
1. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
||||||
2. `cd misskey` misskeyディレクトリに移動
|
2. `cd misskey` misskeyディレクトリに移動
|
||||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
||||||
|
|
||||||
*2.* 設定ファイルの作成と編集
|
*2.* 設定ファイルの作成と編集
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
@ -67,7 +67,7 @@ cp docker_example.env docker.env
|
|||||||
### Misskeyを最新バージョンにアップデートする方法:
|
### Misskeyを最新バージョンにアップデートする方法:
|
||||||
1. `git fetch`
|
1. `git fetch`
|
||||||
2. `git stash`
|
2. `git stash`
|
||||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
|
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||||
4. `git stash pop`
|
4. `git stash pop`
|
||||||
5. `docker-compose build`
|
5. `docker-compose build`
|
||||||
6. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
|
6. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
|
||||||
|
@ -40,7 +40,7 @@ Please install and setup these softwares:
|
|||||||
1. `su - misskey` Connect to misskey user.
|
1. `su - misskey` Connect to misskey user.
|
||||||
2. `git clone -b master git://github.com/syuilo/misskey.git` Clone the misskey repo from master branch.
|
2. `git clone -b master git://github.com/syuilo/misskey.git` Clone the misskey repo from master branch.
|
||||||
3. `cd misskey` Navigate to misskey directory
|
3. `cd misskey` Navigate to misskey directory
|
||||||
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
|
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
|
||||||
5. `npm install` Install misskey dependencies.
|
5. `npm install` Install misskey dependencies.
|
||||||
|
|
||||||
*5.* Configure Misskey
|
*5.* Configure Misskey
|
||||||
@ -109,7 +109,7 @@ You can check if the service is running with `systemctl status misskey`.
|
|||||||
|
|
||||||
### How to update your Misskey server to the latest version
|
### How to update your Misskey server to the latest version
|
||||||
1. `git fetch`
|
1. `git fetch`
|
||||||
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
|
2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||||
3. `npm install`
|
3. `npm install`
|
||||||
4. `NODE_ENV=production npm run build`
|
4. `NODE_ENV=production npm run build`
|
||||||
5. Check [ChangeLog](../CHANGELOG.md) for migration information
|
5. Check [ChangeLog](../CHANGELOG.md) for migration information
|
||||||
|
@ -40,7 +40,7 @@ Installez les paquets suivants :
|
|||||||
1. `su - misskey` Basculez vers l'utilisateur misskey.
|
1. `su - misskey` Basculez vers l'utilisateur misskey.
|
||||||
2. `git clone -b master git://github.com/syuilo/misskey.git` Clonez la branche master du dépôt misskey.
|
2. `git clone -b master git://github.com/syuilo/misskey.git` Clonez la branche master du dépôt misskey.
|
||||||
3. `cd misskey` Accédez au dossier misskey.
|
3. `cd misskey` Accédez au dossier misskey.
|
||||||
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
|
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
|
||||||
5. `npm install` Installez les dépendances de misskey.
|
5. `npm install` Installez les dépendances de misskey.
|
||||||
|
|
||||||
*5.* Création du fichier de configuration
|
*5.* Création du fichier de configuration
|
||||||
@ -103,7 +103,7 @@ Vous pouvez vérifier si le service a démarré en utilisant la commande `system
|
|||||||
|
|
||||||
### Méthode de mise à jour vers la plus récente version de Misskey
|
### Méthode de mise à jour vers la plus récente version de Misskey
|
||||||
1. `git fetch`
|
1. `git fetch`
|
||||||
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
|
2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||||
3. `npm install`
|
3. `npm install`
|
||||||
4. `NODE_ENV=production npm run build`
|
4. `NODE_ENV=production npm run build`
|
||||||
5. Consultez [ChangeLog](../CHANGELOG.md) pour les information de migration.
|
5. Consultez [ChangeLog](../CHANGELOG.md) pour les information de migration.
|
||||||
|
@ -47,7 +47,7 @@ adduser --disabled-password --disabled-login misskey
|
|||||||
1. `su - misskey` misskeyユーザーを使用
|
1. `su - misskey` misskeyユーザーを使用
|
||||||
2. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
2. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
||||||
3. `cd misskey` misskeyディレクトリに移動
|
3. `cd misskey` misskeyディレクトリに移動
|
||||||
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
||||||
5. `npm install` Misskeyの依存パッケージをインストール
|
5. `npm install` Misskeyの依存パッケージをインストール
|
||||||
|
|
||||||
*5.* 設定ファイルを作成する
|
*5.* 設定ファイルを作成する
|
||||||
@ -115,7 +115,7 @@ CentOSで1024以下のポートを使用してMisskeyを使用する場合は`Ex
|
|||||||
|
|
||||||
### Misskeyを最新バージョンにアップデートする方法:
|
### Misskeyを最新バージョンにアップデートする方法:
|
||||||
1. `git fetch`
|
1. `git fetch`
|
||||||
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
|
2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||||
3. `npm install`
|
3. `npm install`
|
||||||
4. `NODE_ENV=production npm run build`
|
4. `NODE_ENV=production npm run build`
|
||||||
5. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
|
5. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
|
||||||
|
@ -49,6 +49,7 @@ gulp.task('build:copy:views', () =>
|
|||||||
|
|
||||||
gulp.task('build:copy', gulp.parallel('build:copy:views', () =>
|
gulp.task('build:copy', gulp.parallel('build:copy:views', () =>
|
||||||
gulp.src([
|
gulp.src([
|
||||||
|
'./build/Release/crypto_key.node',
|
||||||
'./src/const.json',
|
'./src/const.json',
|
||||||
'./src/server/web/views/**/*',
|
'./src/server/web/views/**/*',
|
||||||
'./src/**/assets/**/*',
|
'./src/**/assets/**/*',
|
||||||
@ -119,7 +120,7 @@ gulp.task('copy:client', () =>
|
|||||||
])
|
])
|
||||||
.pipe(isProduction ? (imagemin as any)() : gutil.noop())
|
.pipe(isProduction ? (imagemin as any)() : gutil.noop())
|
||||||
.pipe(rename(path => {
|
.pipe(rename(path => {
|
||||||
path.dirname = path.dirname.replace('assets', '.');
|
path.dirname = path.dirname!.replace('assets', '.');
|
||||||
}))
|
}))
|
||||||
.pipe(gulp.dest('./built/client/assets/'))
|
.pipe(gulp.dest('./built/client/assets/'))
|
||||||
);
|
);
|
||||||
|
@ -1082,9 +1082,6 @@ desktop/views/components/settings.tags.vue:
|
|||||||
add: "追加"
|
add: "追加"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "タスクマネージャ"
|
|
||||||
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "ホーム"
|
home: "ホーム"
|
||||||
local: "ローカル"
|
local: "ローカル"
|
||||||
|
17
package.json
17
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "11.0.0-alpha.2",
|
"version": "11.0.0-beta.5",
|
||||||
"codename": "daybreak",
|
"codename": "daybreak",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -12,6 +12,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./index.js",
|
"start": "node ./index.js",
|
||||||
"init": "node ./built/init.js",
|
"init": "node ./built/init.js",
|
||||||
|
"migrate": "node ./built/migrate.js",
|
||||||
"debug": "DEBUG=misskey:* node ./index.js",
|
"debug": "DEBUG=misskey:* node ./index.js",
|
||||||
"build": "webpack && gulp build",
|
"build": "webpack && gulp build",
|
||||||
"webpack": "webpack",
|
"webpack": "webpack",
|
||||||
@ -66,6 +67,8 @@
|
|||||||
"@types/lolex": "3.1.1",
|
"@types/lolex": "3.1.1",
|
||||||
"@types/minio": "7.0.1",
|
"@types/minio": "7.0.1",
|
||||||
"@types/mocha": "5.2.6",
|
"@types/mocha": "5.2.6",
|
||||||
|
"@types/mongodb": "3.1.22",
|
||||||
|
"@types/monk": "6.0.0",
|
||||||
"@types/node": "11.10.4",
|
"@types/node": "11.10.4",
|
||||||
"@types/nodemailer": "4.6.6",
|
"@types/nodemailer": "4.6.6",
|
||||||
"@types/nprogress": "0.0.29",
|
"@types/nprogress": "0.0.29",
|
||||||
@ -96,14 +99,14 @@
|
|||||||
"@types/websocket": "0.0.40",
|
"@types/websocket": "0.0.40",
|
||||||
"@types/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
"animejs": "3.0.1",
|
"animejs": "3.0.1",
|
||||||
"apexcharts": "3.6.5",
|
"apexcharts": "3.6.6",
|
||||||
"autobind-decorator": "2.4.0",
|
"autobind-decorator": "2.4.0",
|
||||||
"autosize": "4.0.2",
|
"autosize": "4.0.2",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"bootstrap-vue": "2.0.0-rc.13",
|
"bootstrap-vue": "2.0.0-rc.13",
|
||||||
"bull": "3.7.0",
|
"bull": "3.7.0",
|
||||||
"cafy": "15.1.0",
|
"cafy": "15.1.1",
|
||||||
"chai": "4.2.0",
|
"chai": "4.2.0",
|
||||||
"chai-http": "4.2.1",
|
"chai-http": "4.2.1",
|
||||||
"chalk": "2.4.2",
|
"chalk": "2.4.2",
|
||||||
@ -168,7 +171,10 @@
|
|||||||
"mocha": "6.0.2",
|
"mocha": "6.0.2",
|
||||||
"moji": "0.5.1",
|
"moji": "0.5.1",
|
||||||
"moment": "2.24.0",
|
"moment": "2.24.0",
|
||||||
|
"mongodb": "3.2.3",
|
||||||
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
|
"nan": "2.12.1",
|
||||||
"nested-property": "0.0.7",
|
"nested-property": "0.0.7",
|
||||||
"node-fetch": "2.3.0",
|
"node-fetch": "2.3.0",
|
||||||
"nodemailer": "5.1.1",
|
"nodemailer": "5.1.1",
|
||||||
@ -234,7 +240,7 @@
|
|||||||
"video-thumbnail-generator": "1.1.3",
|
"video-thumbnail-generator": "1.1.3",
|
||||||
"vue": "2.6.10",
|
"vue": "2.6.10",
|
||||||
"vue-color": "2.7.0",
|
"vue-color": "2.7.0",
|
||||||
"vue-content-loading": "1.5.3",
|
"vue-content-loading": "1.6.0",
|
||||||
"vue-cropperjs": "3.0.0",
|
"vue-cropperjs": "3.0.0",
|
||||||
"vue-i18n": "8.10.0",
|
"vue-i18n": "8.10.0",
|
||||||
"vue-js-modal": "1.3.28",
|
"vue-js-modal": "1.3.28",
|
||||||
@ -242,7 +248,7 @@
|
|||||||
"vue-loader": "15.7.0",
|
"vue-loader": "15.7.0",
|
||||||
"vue-marquee-text-component": "1.1.1",
|
"vue-marquee-text-component": "1.1.1",
|
||||||
"vue-prism-component": "1.1.1",
|
"vue-prism-component": "1.1.1",
|
||||||
"vue-router": "3.0.2",
|
"vue-router": "3.0.3",
|
||||||
"vue-sequential-entrance": "1.1.3",
|
"vue-sequential-entrance": "1.1.3",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-svg-inline-loader": "1.2.15",
|
"vue-svg-inline-loader": "1.2.15",
|
||||||
@ -252,7 +258,6 @@
|
|||||||
"vuex": "3.1.0",
|
"vuex": "3.1.0",
|
||||||
"vuex-persistedstate": "2.5.4",
|
"vuex-persistedstate": "2.5.4",
|
||||||
"web-push": "3.3.3",
|
"web-push": "3.3.3",
|
||||||
"webfinger.js": "2.7.0",
|
|
||||||
"webpack": "4.28.4",
|
"webpack": "4.28.4",
|
||||||
"webpack-cli": "3.2.3",
|
"webpack-cli": "3.2.3",
|
||||||
"websocket": "1.0.28",
|
"websocket": "1.0.28",
|
||||||
|
65
src/@types/webfinger.js.d.ts
vendored
65
src/@types/webfinger.js.d.ts
vendored
@ -1,65 +0,0 @@
|
|||||||
declare module 'webfinger.js' {
|
|
||||||
interface IWebFingerConstructorConfig {
|
|
||||||
tls_only?: boolean;
|
|
||||||
webfist_fallback?: boolean;
|
|
||||||
uri_fallback?: boolean;
|
|
||||||
request_timeout?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
type JRDProperties = { [type: string]: string };
|
|
||||||
|
|
||||||
interface IJRDLink {
|
|
||||||
rel: string;
|
|
||||||
type?: string;
|
|
||||||
href?: string;
|
|
||||||
template?: string;
|
|
||||||
titles?: { [lang: string]: string };
|
|
||||||
properties?: JRDProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IJRD {
|
|
||||||
subject?: string;
|
|
||||||
expires?: Date;
|
|
||||||
aliases?: string[];
|
|
||||||
properties?: JRDProperties;
|
|
||||||
links?: IJRDLink[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IIDXLinks {
|
|
||||||
'avatar': IJRDLink[];
|
|
||||||
'remotestorage': IJRDLink[];
|
|
||||||
'blog': IJRDLink[];
|
|
||||||
'vcard': IJRDLink[];
|
|
||||||
'updates': IJRDLink[];
|
|
||||||
'share': IJRDLink[];
|
|
||||||
'profile': IJRDLink[];
|
|
||||||
'webfist': IJRDLink[];
|
|
||||||
'camlistore': IJRDLink[];
|
|
||||||
[type: string]: IJRDLink[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IIDXProperties {
|
|
||||||
'name': string;
|
|
||||||
[type: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IIDX {
|
|
||||||
links: IIDXLinks;
|
|
||||||
properties: IIDXProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ILookupCallbackResult {
|
|
||||||
object: IJRD;
|
|
||||||
json: string;
|
|
||||||
idx: IIDX;
|
|
||||||
}
|
|
||||||
|
|
||||||
type LookupCallback = (err: Error | string, result?: ILookupCallbackResult) => void;
|
|
||||||
|
|
||||||
export class WebFinger {
|
|
||||||
constructor(config?: IWebFingerConstructorConfig);
|
|
||||||
|
|
||||||
public lookup(address: string, cb: LookupCallback): NodeJS.Timeout;
|
|
||||||
public lookupLink(address: string, rel: string, cb: IJRDLink): void;
|
|
||||||
}
|
|
||||||
}
|
|
@ -44,7 +44,7 @@ function greet() {
|
|||||||
export async function masterMain() {
|
export async function masterMain() {
|
||||||
greet();
|
greet();
|
||||||
|
|
||||||
let config: Config;
|
let config!: Config;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// initialize app
|
// initialize app
|
||||||
|
@ -15,6 +15,6 @@ export async function workerMain() {
|
|||||||
|
|
||||||
if (cluster.isWorker) {
|
if (cluster.isWorker) {
|
||||||
// Send a 'ready' message to parent process
|
// Send a 'ready' message to parent process
|
||||||
process.send('ready');
|
process.send!('ready');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
thumbnail(file: any): any {
|
thumbnail(file: any): any {
|
||||||
return {
|
return {
|
||||||
'background-color': file.properties.avgColor && file.properties.avgColor.length == 3 ? `rgb(${file.properties.avgColor.join(',')})` : 'transparent',
|
'background-color': file.properties.avgColor || 'transparent',
|
||||||
'background-image': `url(${file.thumbnailUrl})`
|
'background-image': `url(${file.thumbnailUrl})`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -55,12 +55,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
icon(): any {
|
icon(): any {
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.avatarColor ? this.lightmode
|
backgroundColor: this.user.avatarColor,
|
||||||
? this.user.avatarColor
|
|
||||||
: this.user.avatarColor.startsWith('rgb(')
|
|
||||||
? this.user.avatarColor
|
|
||||||
: null
|
|
||||||
: null,
|
|
||||||
backgroundImage: this.lightmode ? null : `url(${this.url})`,
|
backgroundImage: this.lightmode ? null : `url(${this.url})`,
|
||||||
borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
|
borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
|
||||||
};
|
};
|
||||||
|
@ -111,9 +111,7 @@ export default Vue.extend({
|
|||||||
: false;
|
: false;
|
||||||
},
|
},
|
||||||
background(): string {
|
background(): string {
|
||||||
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3
|
return this.file.properties.avgColor || 'transparent';
|
||||||
? `rgb(${this.file.properties.avgColor.join(',')})`
|
|
||||||
: 'transparent';
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -122,10 +120,10 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onThumbnailLoaded() {
|
onThumbnailLoaded() {
|
||||||
if (this.file.properties.avgColor && this.file.properties.avgColor.length == 3) {
|
if (this.file.properties.avgColor) {
|
||||||
anime({
|
anime({
|
||||||
targets: this.$refs.thumbnail,
|
targets: this.$refs.thumbnail,
|
||||||
backgroundColor: `rgba(${this.file.properties.avgColor.join(',')}, 0)`,
|
backgroundColor: this.file.properties.avgColor.replace('255)', '0)'),
|
||||||
duration: 100,
|
duration: 100,
|
||||||
easing: 'linear'
|
easing: 'linear'
|
||||||
});
|
});
|
||||||
|
@ -52,7 +52,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'background-color': this.image.properties.avgColor && this.image.properties.avgColor.length == 3 ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
|
'background-color': this.image.properties.avgColor || 'transparent',
|
||||||
'background-image': url
|
'background-image': url
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<div class="file" v-if="message.file">
|
<div class="file" v-if="message.file">
|
||||||
<a :href="message.file.url" target="_blank" :title="message.file.name">
|
<a :href="message.file.url" target="_blank" :title="message.file.name">
|
||||||
<img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"
|
<img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"
|
||||||
:style="{ backgroundColor: message.file.properties.avgColor && message.file.properties.avgColor.length == 3 ? `rgb(${message.file.properties.avgColor.join(',')})` : 'transparent' }"/>
|
:style="{ backgroundColor: message.file.properties.avgColor || 'transparent' }"/>
|
||||||
<p v-else>{{ message.file.name }}</p>
|
<p v-else>{{ message.file.name }}</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -165,7 +165,7 @@ export default Vue.extend({
|
|||||||
bannerStyle(): any {
|
bannerStyle(): any {
|
||||||
if (this.$store.state.i.bannerUrl == null) return {};
|
if (this.$store.state.i.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.$store.state.i.bannerColor ? this.$store.state.i.bannerColor : null,
|
backgroundColor: this.$store.state.i.bannerColor,
|
||||||
backgroundImage: `url(${ this.$store.state.i.bannerUrl })`
|
backgroundImage: `url(${ this.$store.state.i.bannerUrl })`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="no-users" v-if="inited && us.length == 0">
|
<div class="no-users" v-if="inited && us.length == 0">
|
||||||
<p>{{ $t('no-users') }}</p>
|
<p>{{ $t('no-users') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="user" v-for="user in us">
|
<div class="user" v-for="user in us" :key="user.id">
|
||||||
<mk-avatar class="avatar" :user="user"/>
|
<mk-avatar class="avatar" :user="user"/>
|
||||||
<div class="body" v-if="!iconOnly">
|
<div class="body" v-if="!iconOnly">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
@ -18,6 +18,7 @@
|
|||||||
<div class="description" v-if="user.description" :title="user.description">
|
<div class="description" v-if="user.description" :title="user.description">
|
||||||
<mfm :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis" :should-break="false" :plain-text="true"/>
|
<mfm :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis" :should-break="false" :plain-text="true"/>
|
||||||
</div>
|
</div>
|
||||||
|
<mk-follow-button class="follow-button" v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" mini/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="more" :class="{ fetching: fetchingMoreUsers }" v-if="cursor != null" @click="fetchMoreUsers()" :disabled="fetchingMoreUsers">
|
<button class="more" :class="{ fetching: fetchingMoreUsers }" v-if="cursor != null" @click="fetchMoreUsers()" :disabled="fetchingMoreUsers">
|
||||||
@ -160,6 +161,12 @@ export default Vue.extend({
|
|||||||
text-overflow ellipsis
|
text-overflow ellipsis
|
||||||
opacity 0.7
|
opacity 0.7
|
||||||
font-size 14px
|
font-size 14px
|
||||||
|
padding-right 40px
|
||||||
|
|
||||||
|
> .follow-button
|
||||||
|
position absolute
|
||||||
|
top 8px
|
||||||
|
right 0px
|
||||||
|
|
||||||
> .more
|
> .more
|
||||||
display block
|
display block
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<x-notifications-column v-else-if="column.type == 'notifications'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
<x-notifications-column v-else-if="column.type == 'notifications'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||||
<x-tl-column v-else-if="column.type == 'home'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
<x-tl-column v-else-if="column.type == 'home'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||||
<x-tl-column v-else-if="column.type == 'local'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
<x-tl-column v-else-if="column.type == 'local'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||||
<x-tl-column v-else-if="column.type == 'social'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
<x-tl-column v-else-if="column.type == 'hybrid'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||||
<x-tl-column v-else-if="column.type == 'global'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
<x-tl-column v-else-if="column.type == 'global'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||||
<x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
<x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||||
<x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
<x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<fa v-if="column.type == 'home'" icon="home"/>
|
<fa v-if="column.type == 'home'" icon="home"/>
|
||||||
<fa v-if="column.type == 'local'" :icon="['far', 'comments']"/>
|
<fa v-if="column.type == 'local'" :icon="['far', 'comments']"/>
|
||||||
<fa v-if="column.type == 'social'" icon="share-alt"/>
|
<fa v-if="column.type == 'hybrid'" icon="share-alt"/>
|
||||||
<fa v-if="column.type == 'global'" icon="globe"/>
|
<fa v-if="column.type == 'global'" icon="globe"/>
|
||||||
<fa v-if="column.type == 'list'" icon="list"/>
|
<fa v-if="column.type == 'list'" icon="list"/>
|
||||||
<fa v-if="column.type == 'hashtag'" icon="hashtag"/>
|
<fa v-if="column.type == 'hashtag'" icon="hashtag"/>
|
||||||
@ -80,7 +80,7 @@ export default Vue.extend({
|
|||||||
switch (this.column.type) {
|
switch (this.column.type) {
|
||||||
case 'home': return this.$t('@deck.home');
|
case 'home': return this.$t('@deck.home');
|
||||||
case 'local': return this.$t('@deck.local');
|
case 'local': return this.$t('@deck.local');
|
||||||
case 'social': return this.$t('@deck.social');
|
case 'hybrid': return this.$t('@deck.hybrid');
|
||||||
case 'global': return this.$t('@deck.global');
|
case 'global': return this.$t('@deck.global');
|
||||||
case 'list': return this.column.list.name;
|
case 'list': return this.column.list.name;
|
||||||
case 'hashtag': return this.$store.state.settings.tagTimelines.find(x => x.id == this.column.tagTlId).title;
|
case 'hashtag': return this.$store.state.settings.tagTimelines.find(x => x.id == this.column.tagTlId).title;
|
||||||
|
@ -51,7 +51,7 @@ export default Vue.extend({
|
|||||||
switch (this.src) {
|
switch (this.src) {
|
||||||
case 'home': return this.$root.stream.useSharedConnection('homeTimeline');
|
case 'home': return this.$root.stream.useSharedConnection('homeTimeline');
|
||||||
case 'local': return this.$root.stream.useSharedConnection('localTimeline');
|
case 'local': return this.$root.stream.useSharedConnection('localTimeline');
|
||||||
case 'social': return this.$root.stream.useSharedConnection('socialTimeline');
|
case 'hybrid': return this.$root.stream.useSharedConnection('hybridTimeline');
|
||||||
case 'global': return this.$root.stream.useSharedConnection('globalTimeline');
|
case 'global': return this.$root.stream.useSharedConnection('globalTimeline');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -60,7 +60,7 @@ export default Vue.extend({
|
|||||||
switch (this.src) {
|
switch (this.src) {
|
||||||
case 'home': return 'notes/timeline';
|
case 'home': return 'notes/timeline';
|
||||||
case 'local': return 'notes/local-timeline';
|
case 'local': return 'notes/local-timeline';
|
||||||
case 'social': return 'notes/social-timeline';
|
case 'hybrid': return 'notes/hybrid-timeline';
|
||||||
case 'global': return 'notes/global-timeline';
|
case 'global': return 'notes/global-timeline';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -107,7 +107,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
this.$root.getMeta().then(meta => {
|
this.$root.getMeta().then(meta => {
|
||||||
this.disabled = !this.$store.state.i.isModerator && !this.$store.state.i.isAdmin && (
|
this.disabled = !this.$store.state.i.isModerator && !this.$store.state.i.isAdmin && (
|
||||||
meta.disableLocalTimeline && ['local', 'social'].includes(this.src) ||
|
meta.disableLocalTimeline && ['local', 'hybrid'].includes(this.src) ||
|
||||||
meta.disableGlobalTimeline && ['global'].includes(this.src));
|
meta.disableGlobalTimeline && ['global'].includes(this.src));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="is-remote" v-if="user.host != null">
|
<div class="is-remote" v-if="user.host != null">
|
||||||
<details>
|
<details>
|
||||||
<summary><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}</summary>
|
<summary><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}</summary>
|
||||||
<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a>
|
<a :href="user.url" target="_blank">{{ $t('@.view-on-remote') }}</a>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
<header :style="bannerStyle">
|
<header :style="bannerStyle">
|
||||||
@ -88,7 +88,7 @@ export default Vue.extend({
|
|||||||
if (this.user == null) return {};
|
if (this.user == null) return {};
|
||||||
if (this.user.bannerUrl == null) return {};
|
if (this.user.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
backgroundColor: this.user.bannerColor,
|
||||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -145,11 +145,11 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
icon: 'share-alt',
|
icon: 'share-alt',
|
||||||
text: this.$t('@deck.social'),
|
text: this.$t('@deck.hybrid'),
|
||||||
action: () => {
|
action: () => {
|
||||||
this.$store.commit('device/addDeckColumn', {
|
this.$store.commit('device/addDeckColumn', {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'social'
|
type: 'hybrid'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
@ -302,7 +302,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
isTlColumn(id) {
|
isTlColumn(id) {
|
||||||
const column = this.columns.find(c => c.id === id);
|
const column = this.columns.find(c => c.id === id);
|
||||||
return ['home', 'local', 'social', 'global', 'list', 'hashtag', 'mentions', 'direct'].includes(column.type);
|
return ['home', 'local', 'hybrid', 'global', 'list', 'hashtag', 'mentions', 'direct'].includes(column.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -57,7 +57,7 @@ export default Vue.extend({
|
|||||||
bannerStyle(): any {
|
bannerStyle(): any {
|
||||||
if (this.user.bannerUrl == null) return {};
|
if (this.user.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
backgroundColor: this.user.bannerColor,
|
||||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -139,10 +139,10 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onThumbnailLoaded() {
|
onThumbnailLoaded() {
|
||||||
if (this.file.properties.avgColor && this.file.properties.avgColor.length == 3) {
|
if (this.file.properties.avgColor) {
|
||||||
anime({
|
anime({
|
||||||
targets: this.$refs.thumbnail,
|
targets: this.$refs.thumbnail,
|
||||||
backgroundColor: `rgba(${this.file.properties.avgColor.join(',')}, 0)`,
|
backgroundColor: this.file.properties.avgColor.replace('255)', '0)'),
|
||||||
duration: 100,
|
duration: 100,
|
||||||
easing: 'linear'
|
easing: 'linear'
|
||||||
});
|
});
|
||||||
|
@ -77,9 +77,9 @@ export default Vue.extend({
|
|||||||
this.endpoint = 'notes/local-timeline';
|
this.endpoint = 'notes/local-timeline';
|
||||||
this.connection = this.$root.stream.useSharedConnection('localTimeline');
|
this.connection = this.$root.stream.useSharedConnection('localTimeline');
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
} else if (this.src == 'social') {
|
} else if (this.src == 'hybrid') {
|
||||||
this.endpoint = 'notes/social-timeline';
|
this.endpoint = 'notes/hybrid-timeline';
|
||||||
this.connection = this.$root.stream.useSharedConnection('socialTimeline');
|
this.connection = this.$root.stream.useSharedConnection('hybridTimeline');
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
} else if (this.src == 'global') {
|
} else if (this.src == 'global') {
|
||||||
this.endpoint = 'notes/global-timeline';
|
this.endpoint = 'notes/global-timeline';
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<header class="zahtxcqi">
|
<header class="zahtxcqi">
|
||||||
<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span>
|
<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span>
|
||||||
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span>
|
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span>
|
||||||
<span :data-active="src == 'social'" @click="src = 'social'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('social') }}</span>
|
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span>
|
||||||
<span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span>
|
<span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span>
|
||||||
<span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl"><fa icon="hashtag"/> {{ tagTl.title }}</span>
|
<span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl"><fa icon="hashtag"/> {{ tagTl.title }}</span>
|
||||||
<span :data-active="src == 'list'" @click="src = 'list'" v-if="list"><fa icon="list"/> {{ list.name }}</span>
|
<span :data-active="src == 'list'" @click="src = 'list'" v-if="list"><fa icon="list"/> {{ list.name }}</span>
|
||||||
@ -78,7 +78,7 @@ export default Vue.extend({
|
|||||||
) && this.src === 'global') this.src = 'local';
|
) && this.src === 'global') this.src = 'local';
|
||||||
if (!(
|
if (!(
|
||||||
this.enableLocalTimeline = !meta.disableLocalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin
|
this.enableLocalTimeline = !meta.disableLocalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin
|
||||||
) && ['local', 'social'].includes(this.src)) this.src = 'home';
|
) && ['local', 'hybrid'].includes(this.src)) this.src = 'home';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.$store.state.device.tl) {
|
if (this.$store.state.device.tl) {
|
||||||
@ -89,7 +89,7 @@ export default Vue.extend({
|
|||||||
this.tagTl = this.$store.state.device.tl.arg;
|
this.tagTl = this.$store.state.device.tl.arg;
|
||||||
}
|
}
|
||||||
} else if (this.$store.state.i.followingCount == 0) {
|
} else if (this.$store.state.i.followingCount == 0) {
|
||||||
this.src = 'social';
|
this.src = 'hybrid';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}
|
<fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="is-remote" v-if="user.host != null" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
|
<div class="is-remote" v-if="user.host != null" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
|
||||||
<fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a>
|
<fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url" target="_blank">{{ $t('@.view-on-remote') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<x-header class="header" :user="user"/>
|
<x-header class="header" :user="user"/>
|
||||||
|
@ -65,7 +65,7 @@ export default Vue.extend({
|
|||||||
style(): any {
|
style(): any {
|
||||||
if (this.user.bannerUrl == null) return {};
|
if (this.user.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
backgroundColor: this.user.bannerColor,
|
||||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -85,8 +85,8 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
style(): any {
|
style(): any {
|
||||||
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? {
|
return this.file.properties.avgColor ? {
|
||||||
'background-color': `rgb(${ this.file.properties.avgColor.join(',') })`
|
'background-color': this.file.properties.avgColor
|
||||||
} : {};
|
} : {};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -78,9 +78,9 @@ export default Vue.extend({
|
|||||||
this.endpoint = 'notes/local-timeline';
|
this.endpoint = 'notes/local-timeline';
|
||||||
this.connection = this.$root.stream.useSharedConnection('localTimeline');
|
this.connection = this.$root.stream.useSharedConnection('localTimeline');
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
} else if (this.src == 'social') {
|
} else if (this.src == 'hybrid') {
|
||||||
this.endpoint = 'notes/social-timeline';
|
this.endpoint = 'notes/hybrid-timeline';
|
||||||
this.connection = this.$root.stream.useSharedConnection('socialTimeline');
|
this.connection = this.$root.stream.useSharedConnection('hybridTimeline');
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
} else if (this.src == 'global') {
|
} else if (this.src == 'global') {
|
||||||
this.endpoint = 'notes/global-timeline';
|
this.endpoint = 'notes/global-timeline';
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<span :class="$style.title">
|
<span :class="$style.title">
|
||||||
<span v-if="src == 'home'"><fa icon="home"/>{{ $t('home') }}</span>
|
<span v-if="src == 'home'"><fa icon="home"/>{{ $t('home') }}</span>
|
||||||
<span v-if="src == 'local'"><fa :icon="['far', 'comments']"/>{{ $t('local') }}</span>
|
<span v-if="src == 'local'"><fa :icon="['far', 'comments']"/>{{ $t('local') }}</span>
|
||||||
<span v-if="src == 'social'"><fa icon="share-alt"/>{{ $t('social') }}</span>
|
<span v-if="src == 'hybrid'"><fa icon="share-alt"/>{{ $t('hybrid') }}</span>
|
||||||
<span v-if="src == 'global'"><fa icon="globe"/>{{ $t('global') }}</span>
|
<span v-if="src == 'global'"><fa icon="globe"/>{{ $t('global') }}</span>
|
||||||
<span v-if="src == 'mentions'"><fa icon="at"/>{{ $t('mentions') }}</span>
|
<span v-if="src == 'mentions'"><fa icon="at"/>{{ $t('mentions') }}</span>
|
||||||
<span v-if="src == 'messages'"><fa :icon="['far', 'envelope']"/>{{ $t('messages') }}</span>
|
<span v-if="src == 'messages'"><fa :icon="['far', 'envelope']"/>{{ $t('messages') }}</span>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span>
|
<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span>
|
||||||
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span>
|
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span>
|
||||||
<span :data-active="src == 'social'" @click="src = 'social'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('social') }}</span>
|
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span>
|
||||||
<span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span>
|
<span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span>
|
||||||
<div class="hr"></div>
|
<div class="hr"></div>
|
||||||
<span :data-active="src == 'mentions'" @click="src = 'mentions'"><fa icon="at"/> {{ $t('mentions') }}<i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></span>
|
<span :data-active="src == 'mentions'" @click="src = 'mentions'"><fa icon="at"/> {{ $t('mentions') }}<i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></span>
|
||||||
@ -50,7 +50,7 @@
|
|||||||
<div class="tl">
|
<div class="tl">
|
||||||
<x-tl v-if="src == 'home'" ref="tl" key="home" src="home"/>
|
<x-tl v-if="src == 'home'" ref="tl" key="home" src="home"/>
|
||||||
<x-tl v-if="src == 'local'" ref="tl" key="local" src="local"/>
|
<x-tl v-if="src == 'local'" ref="tl" key="local" src="local"/>
|
||||||
<x-tl v-if="src == 'social'" ref="tl" key="social" src="social"/>
|
<x-tl v-if="src == 'hybrid'" ref="tl" key="hybrid" src="hybrid"/>
|
||||||
<x-tl v-if="src == 'global'" ref="tl" key="global" src="global"/>
|
<x-tl v-if="src == 'global'" ref="tl" key="global" src="global"/>
|
||||||
<x-tl v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/>
|
<x-tl v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/>
|
||||||
<x-tl v-if="src == 'messages'" ref="tl" key="messages" src="messages"/>
|
<x-tl v-if="src == 'messages'" ref="tl" key="messages" src="messages"/>
|
||||||
@ -120,7 +120,7 @@ export default Vue.extend({
|
|||||||
) && this.src === 'global') this.src = 'local';
|
) && this.src === 'global') this.src = 'local';
|
||||||
if (!(
|
if (!(
|
||||||
this.enableLocalTimeline = !meta.disableLocalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin
|
this.enableLocalTimeline = !meta.disableLocalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin
|
||||||
) && ['local', 'social'].includes(this.src)) this.src = 'home';
|
) && ['local', 'hybrid'].includes(this.src)) this.src = 'home';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.$store.state.device.tl) {
|
if (this.$store.state.device.tl) {
|
||||||
@ -131,7 +131,7 @@ export default Vue.extend({
|
|||||||
this.tagTl = this.$store.state.device.tl.arg;
|
this.tagTl = this.$store.state.device.tl.arg;
|
||||||
}
|
}
|
||||||
} else if (this.$store.state.i.followingCount == 0) {
|
} else if (this.$store.state.i.followingCount == 0) {
|
||||||
this.src = 'social';
|
this.src = 'hybrid';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="stream" v-if="!fetching && images.length > 0">
|
<div class="stream" v-if="!fetching && images.length > 0">
|
||||||
<a v-for="(image, i) in images" :key="i"
|
<a v-for="(image, i) in images" :key="i"
|
||||||
class="img"
|
class="img"
|
||||||
:style="`background-image: url(${thumbnail(image.media)})`"
|
:style="`background-image: url(${thumbnail(image.file)})`"
|
||||||
:href="image.note | notePage"
|
:href="image.note | notePage"
|
||||||
></a>
|
></a>
|
||||||
</div>
|
</div>
|
||||||
@ -40,11 +40,11 @@ export default Vue.extend({
|
|||||||
untilDate: new Date().getTime() + 1000 * 86400 * 365
|
untilDate: new Date().getTime() + 1000 * 86400 * 365
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
for (const media of note.media) {
|
for (const file of note.files) {
|
||||||
if (this.images.length < 9) {
|
if (this.images.length < 9) {
|
||||||
this.images.push({
|
this.images.push({
|
||||||
note,
|
note,
|
||||||
media
|
file
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<div class="wwtwuxyh" v-if="!fetching">
|
<div class="wwtwuxyh" v-if="!fetching">
|
||||||
<div class="is-suspended" v-if="user.isSuspended"><p><fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}</p></div>
|
<div class="is-suspended" v-if="user.isSuspended"><p><fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}</p></div>
|
||||||
<div class="is-remote" v-if="user.host != null"><p><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a></p></div>
|
<div class="is-remote" v-if="user.host != null"><p><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url" target="_blank">{{ $t('@.view-on-remote') }}</a></p></div>
|
||||||
<header>
|
<header>
|
||||||
<div class="banner" :style="style"></div>
|
<div class="banner" :style="style"></div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
@ -114,7 +114,7 @@ export default Vue.extend({
|
|||||||
style(): any {
|
style(): any {
|
||||||
if (this.user.bannerUrl == null) return {};
|
if (this.user.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
backgroundColor: this.user.bannerColor,
|
||||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
kind: 'light',
|
kind: 'light',
|
||||||
|
|
||||||
vars: {
|
vars: {
|
||||||
primary: '#fb4e4e',
|
primary: '#f18570',
|
||||||
secondary: '#fff',
|
secondary: '#fff',
|
||||||
text: '#666',
|
text: '#666',
|
||||||
},
|
},
|
||||||
|
@ -25,11 +25,11 @@ export default function load() {
|
|||||||
|
|
||||||
const mixin = {} as Mixin;
|
const mixin = {} as Mixin;
|
||||||
|
|
||||||
const url = validateUrl(config.url);
|
const url = tryCreateUrl(config.url);
|
||||||
|
|
||||||
config.url = normalizeUrl(config.url);
|
config.url = url.origin;
|
||||||
|
|
||||||
config.port = config.port || parseInt(process.env.PORT, 10);
|
config.port = config.port || parseInt(process.env.PORT || '', 10);
|
||||||
|
|
||||||
mixin.host = url.host;
|
mixin.host = url.host;
|
||||||
mixin.hostname = url.hostname;
|
mixin.hostname = url.hostname;
|
||||||
@ -53,14 +53,3 @@ function tryCreateUrl(url: string) {
|
|||||||
throw `url="${url}" is not a valid URL.`;
|
throw `url="${url}" is not a valid URL.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateUrl(url: string) {
|
|
||||||
const result = tryCreateUrl(url);
|
|
||||||
if (result.pathname.replace('/', '').length) throw `url="${url}" is not a valid URL, has a pathname.`;
|
|
||||||
if (!url.includes(result.host)) throw `url="${url}" is not a valid URL, has an invalid hostname.`;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeUrl(url: string) {
|
|
||||||
return url.endsWith('/') ? url.substr(0, url.length - 1) : url;
|
|
||||||
}
|
|
||||||
|
111
src/crypto_key.cc
Normal file
111
src/crypto_key.cc
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include <nan.h>
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/buffer.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
|
||||||
|
NAN_METHOD(extractPublic)
|
||||||
|
{
|
||||||
|
const auto sourceString = info[0]->ToString(Nan::GetCurrentContext()).ToLocalChecked();
|
||||||
|
if (!sourceString->IsOneByte()) {
|
||||||
|
Nan::ThrowError("Malformed character found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sourceLength = sourceString->Length();
|
||||||
|
const auto sourceBuf = new char[sourceLength];
|
||||||
|
|
||||||
|
Nan::DecodeWrite(sourceBuf, sourceLength, sourceString);
|
||||||
|
|
||||||
|
const auto source = BIO_new_mem_buf(sourceBuf, sourceLength);
|
||||||
|
if (source == nullptr) {
|
||||||
|
Nan::ThrowError("Memory allocation failed");
|
||||||
|
delete[] sourceBuf;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto rsa = PEM_read_bio_RSAPrivateKey(source, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
BIO_free(source);
|
||||||
|
delete[] sourceBuf;
|
||||||
|
|
||||||
|
if (rsa == nullptr) {
|
||||||
|
Nan::ThrowError("Decode failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto destination = BIO_new(BIO_s_mem());
|
||||||
|
if (destination == nullptr) {
|
||||||
|
Nan::ThrowError("Memory allocation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = PEM_write_bio_RSAPublicKey(destination, rsa);
|
||||||
|
|
||||||
|
RSA_free(rsa);
|
||||||
|
|
||||||
|
if (result != 1) {
|
||||||
|
Nan::ThrowError("Public key extraction failed");
|
||||||
|
BIO_free(destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pem;
|
||||||
|
const auto pemLength = BIO_get_mem_data(destination, &pem);
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(Nan::Encode(pem, pemLength));
|
||||||
|
BIO_free(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
NAN_METHOD(generate)
|
||||||
|
{
|
||||||
|
const auto exponent = BN_new();
|
||||||
|
const auto mem = BIO_new(BIO_s_mem());
|
||||||
|
const auto rsa = RSA_new();
|
||||||
|
char *data;
|
||||||
|
long result;
|
||||||
|
|
||||||
|
if (exponent == nullptr || mem == nullptr || rsa == nullptr) {
|
||||||
|
Nan::ThrowError("Memory allocation failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = BN_set_word(exponent, 65537);
|
||||||
|
if (result != 1) {
|
||||||
|
Nan::ThrowError("Exponent setting failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = RSA_generate_key_ex(rsa, 2048, exponent, nullptr);
|
||||||
|
if (result != 1) {
|
||||||
|
Nan::ThrowError("Key generation failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = PEM_write_bio_RSAPrivateKey(mem, rsa, NULL, NULL, 0, NULL, NULL);
|
||||||
|
if (result != 1) {
|
||||||
|
Nan::ThrowError("Key export failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = BIO_get_mem_data(mem, &data);
|
||||||
|
info.GetReturnValue().Set(Nan::Encode(data, result));
|
||||||
|
|
||||||
|
done:
|
||||||
|
RSA_free(rsa);
|
||||||
|
BIO_free(mem);
|
||||||
|
BN_free(exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NAN_MODULE_INIT(InitAll)
|
||||||
|
{
|
||||||
|
Nan::Set(target, Nan::New<v8::String>("extractPublic").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(extractPublic)).ToLocalChecked());
|
||||||
|
|
||||||
|
Nan::Set(target, Nan::New<v8::String>("generate").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(generate)).ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_MODULE(crypto_key, InitAll);
|
2
src/crypto_key.d.ts
vendored
Normal file
2
src/crypto_key.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export function extractPublic(keypair: string): string;
|
||||||
|
export function generate(): string;
|
@ -19,7 +19,7 @@ initDb().then(() => {
|
|||||||
all, local
|
all, local
|
||||||
};
|
};
|
||||||
|
|
||||||
process.send(stats);
|
process.send!(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
tick();
|
tick();
|
||||||
|
@ -36,10 +36,10 @@ import { Emoji } from '../models/entities/emoji';
|
|||||||
import { ReversiGame } from '../models/entities/games/reversi/game';
|
import { ReversiGame } from '../models/entities/games/reversi/game';
|
||||||
import { ReversiMatching } from '../models/entities/games/reversi/matching';
|
import { ReversiMatching } from '../models/entities/games/reversi/matching';
|
||||||
import { UserNotePining } from '../models/entities/user-note-pinings';
|
import { UserNotePining } from '../models/entities/user-note-pinings';
|
||||||
import { UserServiceLinking } from '../models/entities/user-service-linking';
|
|
||||||
import { Poll } from '../models/entities/poll';
|
import { Poll } from '../models/entities/poll';
|
||||||
import { UserKeypair } from '../models/entities/user-keypair';
|
import { UserKeypair } from '../models/entities/user-keypair';
|
||||||
import { UserPublickey } from '../models/entities/user-publickey';
|
import { UserPublickey } from '../models/entities/user-publickey';
|
||||||
|
import { UserProfile } from '../models/entities/user-profile';
|
||||||
|
|
||||||
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
|
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ class MyCustomLogger implements Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initDb(justBorrow = false, sync = false, log = false) {
|
export function initDb(justBorrow = false, sync = false, log = false) {
|
||||||
const enableLogging = log || !['production', 'test'].includes(process.env.NODE_ENV);
|
const enableLogging = log || !['production', 'test'].includes(process.env.NODE_ENV || '');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const conn = getConnection();
|
const conn = getConnection();
|
||||||
@ -93,7 +93,7 @@ export function initDb(justBorrow = false, sync = false, log = false) {
|
|||||||
synchronize: process.env.NODE_ENV === 'test' || sync,
|
synchronize: process.env.NODE_ENV === 'test' || sync,
|
||||||
dropSchema: process.env.NODE_ENV === 'test' && !justBorrow,
|
dropSchema: process.env.NODE_ENV === 'test' && !justBorrow,
|
||||||
logging: enableLogging,
|
logging: enableLogging,
|
||||||
logger: enableLogging ? new MyCustomLogger() : null,
|
logger: enableLogging ? new MyCustomLogger() : undefined,
|
||||||
entities: [
|
entities: [
|
||||||
Meta,
|
Meta,
|
||||||
Instance,
|
Instance,
|
||||||
@ -101,12 +101,12 @@ export function initDb(justBorrow = false, sync = false, log = false) {
|
|||||||
AuthSession,
|
AuthSession,
|
||||||
AccessToken,
|
AccessToken,
|
||||||
User,
|
User,
|
||||||
|
UserProfile,
|
||||||
UserKeypair,
|
UserKeypair,
|
||||||
UserPublickey,
|
UserPublickey,
|
||||||
UserList,
|
UserList,
|
||||||
UserListJoining,
|
UserListJoining,
|
||||||
UserNotePining,
|
UserNotePining,
|
||||||
UserServiceLinking,
|
|
||||||
Following,
|
Following,
|
||||||
FollowRequest,
|
FollowRequest,
|
||||||
Muting,
|
Muting,
|
||||||
|
@ -339,7 +339,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
|
|||||||
#### `note`
|
#### `note`
|
||||||
ローカルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
|
ローカルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
|
||||||
|
|
||||||
## `socialTimeline`
|
## `hybridTimeline`
|
||||||
ソーシャルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
|
ソーシャルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
|
||||||
|
|
||||||
### 流れてくるイベント一覧
|
### 流れてくるイベント一覧
|
||||||
|
@ -37,7 +37,7 @@ export type Undo = {
|
|||||||
/**
|
/**
|
||||||
* ターン
|
* ターン
|
||||||
*/
|
*/
|
||||||
turn: Color;
|
turn: Color | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,12 +47,12 @@ export default class Reversi {
|
|||||||
public map: MapPixel[];
|
public map: MapPixel[];
|
||||||
public mapWidth: number;
|
public mapWidth: number;
|
||||||
public mapHeight: number;
|
public mapHeight: number;
|
||||||
public board: Color[];
|
public board: (Color | null | undefined)[];
|
||||||
public turn: Color = BLACK;
|
public turn: Color | null = BLACK;
|
||||||
public opts: Options;
|
public opts: Options;
|
||||||
|
|
||||||
public prevPos = -1;
|
public prevPos = -1;
|
||||||
public prevColor: Color = null;
|
public prevColor: Color | null = null;
|
||||||
|
|
||||||
private logs: Undo[] = [];
|
private logs: Undo[] = [];
|
||||||
|
|
||||||
@ -145,12 +145,12 @@ export default class Reversi {
|
|||||||
// ターン計算
|
// ターン計算
|
||||||
this.turn =
|
this.turn =
|
||||||
this.canPutSomewhere(!this.prevColor) ? !this.prevColor :
|
this.canPutSomewhere(!this.prevColor) ? !this.prevColor :
|
||||||
this.canPutSomewhere(this.prevColor) ? this.prevColor :
|
this.canPutSomewhere(this.prevColor!) ? this.prevColor :
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public undo() {
|
public undo() {
|
||||||
const undo = this.logs.pop();
|
const undo = this.logs.pop()!;
|
||||||
this.prevColor = undo.color;
|
this.prevColor = undo.color;
|
||||||
this.prevPos = undo.pos;
|
this.prevPos = undo.pos;
|
||||||
this.board[undo.pos] = null;
|
this.board[undo.pos] = null;
|
||||||
@ -254,10 +254,10 @@ export default class Reversi {
|
|||||||
/**
|
/**
|
||||||
* ゲームの勝者 (null = 引き分け)
|
* ゲームの勝者 (null = 引き分け)
|
||||||
*/
|
*/
|
||||||
public get winner(): Color {
|
public get winner(): Color | null {
|
||||||
return this.isEnded ?
|
return this.isEnded ?
|
||||||
this.blackCount == this.whiteCount ? null :
|
this.blackCount == this.whiteCount ? null :
|
||||||
this.opts.isLlotheo === this.blackCount > this.whiteCount ? WHITE : BLACK :
|
this.opts.isLlotheo === this.blackCount > this.whiteCount ? WHITE : BLACK :
|
||||||
undefined;
|
undefined as never;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
src/init.ts
18
src/init.ts
@ -1,16 +1,10 @@
|
|||||||
import { initDb } from './db/postgre';
|
import { initDb } from './db/postgre';
|
||||||
|
|
||||||
async function main() {
|
console.log('Init database...');
|
||||||
try {
|
|
||||||
console.log('Connecting database...');
|
|
||||||
await initDb(false, true, true);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Cannot connect to database', null, true);
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
initDb(false, true, true).then(() => {
|
||||||
console.log('Done :)');
|
console.log('Done :)');
|
||||||
}
|
}, e => {
|
||||||
|
console.error('Failed to init database');
|
||||||
main();
|
console.error(e);
|
||||||
|
});
|
||||||
|
@ -3,8 +3,6 @@ import { URL } from 'url';
|
|||||||
import { urlRegex } from './prelude';
|
import { urlRegex } from './prelude';
|
||||||
|
|
||||||
export function fromHtml(html: string): string {
|
export function fromHtml(html: string): string {
|
||||||
if (html == null) return null;
|
|
||||||
|
|
||||||
const dom = parseFragment(html) as DefaultTreeDocumentFragment;
|
const dom = parseFragment(html) as DefaultTreeDocumentFragment;
|
||||||
|
|
||||||
let text = '';
|
let text = '';
|
||||||
|
@ -2,7 +2,7 @@ import { mfmLanguage } from './language';
|
|||||||
import { MfmForest } from './prelude';
|
import { MfmForest } from './prelude';
|
||||||
import { normalize } from './normalize';
|
import { normalize } from './normalize';
|
||||||
|
|
||||||
export function parse(source: string): MfmForest {
|
export function parse(source: string | null): MfmForest | null {
|
||||||
if (source == null || source == '') {
|
if (source == null || source == '') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -10,7 +10,7 @@ export function parse(source: string): MfmForest {
|
|||||||
return normalize(mfmLanguage.root.tryParse(source));
|
return normalize(mfmLanguage.root.tryParse(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parsePlain(source: string): MfmForest {
|
export function parsePlain(source: string | null): MfmForest | null {
|
||||||
if (source == null || source == '') {
|
if (source == null || source == '') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { intersperse } from '../prelude/array';
|
|||||||
import { MfmForest, MfmTree } from './prelude';
|
import { MfmForest, MfmTree } from './prelude';
|
||||||
import { IMentionedRemoteUsers } from '../models/entities/note';
|
import { IMentionedRemoteUsers } from '../models/entities/note';
|
||||||
|
|
||||||
export function toHtml(tokens: MfmForest, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
|
export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
|
||||||
if (tokens == null) {
|
if (tokens == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
497
src/migrate.ts
Normal file
497
src/migrate.ts
Normal file
@ -0,0 +1,497 @@
|
|||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
|
import monk from 'monk';
|
||||||
|
import * as mongo from 'mongodb';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as uuid from 'uuid';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import config from './config';
|
||||||
|
import { initDb } from './db/postgre';
|
||||||
|
import { User } from './models/entities/user';
|
||||||
|
import { getRepository } from 'typeorm';
|
||||||
|
import generateUserToken from './server/api/common/generate-native-user-token';
|
||||||
|
import { DriveFile } from './models/entities/drive-file';
|
||||||
|
import { DriveFolder } from './models/entities/drive-folder';
|
||||||
|
import { InternalStorage } from './services/drive/internal-storage';
|
||||||
|
import { createTemp } from './misc/create-temp';
|
||||||
|
import { Note } from './models/entities/note';
|
||||||
|
import { Following } from './models/entities/following';
|
||||||
|
import { Poll } from './models/entities/poll';
|
||||||
|
import { PollVote } from './models/entities/poll-vote';
|
||||||
|
import { NoteFavorite } from './models/entities/note-favorite';
|
||||||
|
import { NoteReaction } from './models/entities/note-reaction';
|
||||||
|
import { UserPublickey } from './models/entities/user-publickey';
|
||||||
|
import { UserKeypair } from './models/entities/user-keypair';
|
||||||
|
import { extractPublic } from './crypto_key';
|
||||||
|
import { Emoji } from './models/entities/emoji';
|
||||||
|
import { toPuny } from './misc/convert-host';
|
||||||
|
import { UserProfile } from './models/entities/user-profile';
|
||||||
|
|
||||||
|
const u = (config as any).mongodb.user ? encodeURIComponent((config as any).mongodb.user) : null;
|
||||||
|
const p = (config as any).mongodb.pass ? encodeURIComponent((config as any).mongodb.pass) : null;
|
||||||
|
|
||||||
|
const uri = `mongodb://${u && p ? `${u}:${p}@` : ''}${(config as any).mongodb.host}:${(config as any).mongodb.port}/${(config as any).mongodb.db}`;
|
||||||
|
|
||||||
|
const db = monk(uri);
|
||||||
|
let mdb: mongo.Db;
|
||||||
|
|
||||||
|
const test = false;
|
||||||
|
const limit = 500;
|
||||||
|
|
||||||
|
const nativeDbConn = async (): Promise<mongo.Db> => {
|
||||||
|
if (mdb) return mdb;
|
||||||
|
|
||||||
|
const db = await ((): Promise<mongo.Db> => new Promise((resolve, reject) => {
|
||||||
|
mongo.MongoClient.connect(uri, { useNewUrlParser: true }, (e: Error, client: any) => {
|
||||||
|
if (e) return reject(e);
|
||||||
|
resolve(client.db((config as any).mongodb.db));
|
||||||
|
});
|
||||||
|
}))();
|
||||||
|
|
||||||
|
mdb = db;
|
||||||
|
|
||||||
|
return db;
|
||||||
|
};
|
||||||
|
|
||||||
|
const _User = db.get<any>('users');
|
||||||
|
const _DriveFile = db.get<any>('driveFiles.files');
|
||||||
|
const _DriveFolder = db.get<any>('driveFolders');
|
||||||
|
const _Note = db.get<any>('notes');
|
||||||
|
const _Following = db.get<any>('following');
|
||||||
|
const _PollVote = db.get<any>('pollVotes');
|
||||||
|
const _Favorite = db.get<any>('favorites');
|
||||||
|
const _NoteReaction = db.get<any>('noteReactions');
|
||||||
|
const _Emoji = db.get<any>('emoji');
|
||||||
|
const getDriveFileBucket = async (): Promise<mongo.GridFSBucket> => {
|
||||||
|
const db = await nativeDbConn();
|
||||||
|
const bucket = new mongo.GridFSBucket(db, {
|
||||||
|
bucketName: 'driveFiles'
|
||||||
|
});
|
||||||
|
return bucket;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await initDb();
|
||||||
|
const Users = getRepository(User);
|
||||||
|
const UserProfiles = getRepository(UserProfile);
|
||||||
|
const DriveFiles = getRepository(DriveFile);
|
||||||
|
const DriveFolders = getRepository(DriveFolder);
|
||||||
|
const Notes = getRepository(Note);
|
||||||
|
const Followings = getRepository(Following);
|
||||||
|
const Polls = getRepository(Poll);
|
||||||
|
const PollVotes = getRepository(PollVote);
|
||||||
|
const NoteFavorites = getRepository(NoteFavorite);
|
||||||
|
const NoteReactions = getRepository(NoteReaction);
|
||||||
|
const UserPublickeys = getRepository(UserPublickey);
|
||||||
|
const UserKeypairs = getRepository(UserKeypair);
|
||||||
|
const Emojis = getRepository(Emoji);
|
||||||
|
|
||||||
|
async function migrateUser(user: any) {
|
||||||
|
await Users.save({
|
||||||
|
id: user._id.toHexString(),
|
||||||
|
createdAt: user.createdAt || new Date(),
|
||||||
|
username: user.username,
|
||||||
|
usernameLower: user.username.toLowerCase(),
|
||||||
|
host: toPuny(user.host),
|
||||||
|
token: generateUserToken(),
|
||||||
|
isAdmin: user.isAdmin || false,
|
||||||
|
name: user.name,
|
||||||
|
followersCount: user.followersCount || 0,
|
||||||
|
followingCount: user.followingCount || 0,
|
||||||
|
notesCount: user.notesCount || 0,
|
||||||
|
isBot: user.isBot || false,
|
||||||
|
isCat: user.isCat || false,
|
||||||
|
isVerified: user.isVerified || false,
|
||||||
|
inbox: user.inbox,
|
||||||
|
sharedInbox: user.sharedInbox,
|
||||||
|
uri: user.uri,
|
||||||
|
});
|
||||||
|
await UserProfiles.save({
|
||||||
|
userId: user._id.toHexString(),
|
||||||
|
description: user.description,
|
||||||
|
userHost: toPuny(user.host),
|
||||||
|
autoAcceptFollowed: true,
|
||||||
|
autoWatch: false,
|
||||||
|
password: user.password,
|
||||||
|
location: user.profile ? user.profile.location : null,
|
||||||
|
birthday: user.profile ? user.profile.birthday : null,
|
||||||
|
});
|
||||||
|
if (user.publicKey) {
|
||||||
|
await UserPublickeys.save({
|
||||||
|
userId: user._id.toHexString(),
|
||||||
|
keyId: user.publicKey.id,
|
||||||
|
keyPem: user.publicKey.publicKeyPem
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (user.keypair) {
|
||||||
|
await UserKeypairs.save({
|
||||||
|
userId: user._id.toHexString(),
|
||||||
|
publicKey: extractPublic(user.keypair),
|
||||||
|
privateKey: user.keypair,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateFollowing(following: any) {
|
||||||
|
await Followings.save({
|
||||||
|
id: following._id.toHexString(),
|
||||||
|
createdAt: new Date(),
|
||||||
|
followerId: following.followerId.toHexString(),
|
||||||
|
followeeId: following.followeeId.toHexString(),
|
||||||
|
|
||||||
|
// 非正規化
|
||||||
|
followerHost: following._follower ? toPuny(following._follower.host) : null,
|
||||||
|
followerInbox: following._follower ? following._follower.inbox : null,
|
||||||
|
followerSharedInbox: following._follower ? following._follower.sharedInbox : null,
|
||||||
|
followeeHost: following._followee ? toPuny(following._followee.host) : null,
|
||||||
|
followeeInbox: following._followee ? following._followee.inbox : null,
|
||||||
|
followeeSharedInbox: following._followee ? following._followee.sharedInbo : null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateDriveFolder(folder: any) {
|
||||||
|
await DriveFolders.save({
|
||||||
|
id: folder._id.toHexString(),
|
||||||
|
createdAt: folder.createdAt || new Date(),
|
||||||
|
name: folder.name,
|
||||||
|
parentId: folder.parentId ? folder.parentId.toHexString() : null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateDriveFile(file: any) {
|
||||||
|
const user = await _User.findOne({
|
||||||
|
_id: file.metadata.userId
|
||||||
|
});
|
||||||
|
if (user == null) return;
|
||||||
|
if (file.metadata.storage && file.metadata.storage.key) { // when object storage
|
||||||
|
await DriveFiles.save({
|
||||||
|
id: file._id.toHexString(),
|
||||||
|
userId: user._id.toHexString(),
|
||||||
|
userHost: toPuny(user.host),
|
||||||
|
createdAt: file.uploadDate || new Date(),
|
||||||
|
md5: file.md5,
|
||||||
|
name: file.filename,
|
||||||
|
type: file.contentType,
|
||||||
|
properties: file.metadata.properties || {},
|
||||||
|
size: file.length,
|
||||||
|
url: file.metadata.url,
|
||||||
|
uri: file.metadata.uri,
|
||||||
|
accessKey: file.metadata.storage.key,
|
||||||
|
folderId: file.metadata.folderId ? file.metadata.folderId.toHexString() : null,
|
||||||
|
storedInternal: false,
|
||||||
|
isLink: false
|
||||||
|
});
|
||||||
|
} else if (!file.metadata.isLink) {
|
||||||
|
const [temp, clean] = await createTemp();
|
||||||
|
await new Promise(async (res, rej) => {
|
||||||
|
const bucket = await getDriveFileBucket();
|
||||||
|
const readable = bucket.openDownloadStream(file._id);
|
||||||
|
const dest = fs.createWriteStream(temp);
|
||||||
|
readable.pipe(dest);
|
||||||
|
readable.on('end', () => {
|
||||||
|
dest.end();
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const key = uuid.v4();
|
||||||
|
const url = InternalStorage.saveFromPath(key, temp);
|
||||||
|
await DriveFiles.save({
|
||||||
|
id: file._id.toHexString(),
|
||||||
|
userId: user._id.toHexString(),
|
||||||
|
userHost: toPuny(user.host),
|
||||||
|
createdAt: file.uploadDate || new Date(),
|
||||||
|
md5: file.md5,
|
||||||
|
name: file.filename,
|
||||||
|
type: file.contentType,
|
||||||
|
properties: file.metadata.properties,
|
||||||
|
size: file.length,
|
||||||
|
url: url,
|
||||||
|
uri: file.metadata.uri,
|
||||||
|
accessKey: key,
|
||||||
|
folderId: file.metadata.folderId ? file.metadata.folderId.toHexString() : null,
|
||||||
|
storedInternal: true,
|
||||||
|
isLink: false
|
||||||
|
});
|
||||||
|
clean();
|
||||||
|
} else {
|
||||||
|
await DriveFiles.save({
|
||||||
|
id: file._id.toHexString(),
|
||||||
|
userId: user._id.toHexString(),
|
||||||
|
userHost: toPuny(user.host),
|
||||||
|
createdAt: file.uploadDate || new Date(),
|
||||||
|
md5: file.md5,
|
||||||
|
name: file.filename,
|
||||||
|
type: file.contentType,
|
||||||
|
properties: file.metadata.properties,
|
||||||
|
size: file.length,
|
||||||
|
url: file.metadata.url,
|
||||||
|
uri: file.metadata.uri,
|
||||||
|
accessKey: null,
|
||||||
|
folderId: file.metadata.folderId ? file.metadata.folderId.toHexString() : null,
|
||||||
|
storedInternal: false,
|
||||||
|
isLink: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateNote(note: any) {
|
||||||
|
await Notes.save({
|
||||||
|
id: note._id.toHexString(),
|
||||||
|
createdAt: note.createdAt || new Date(),
|
||||||
|
text: note.text,
|
||||||
|
cw: note.cw || null,
|
||||||
|
tags: note.tags || [],
|
||||||
|
userId: note.userId.toHexString(),
|
||||||
|
viaMobile: note.viaMobile || false,
|
||||||
|
geo: note.geo,
|
||||||
|
appId: null,
|
||||||
|
visibility: note.visibility || 'public',
|
||||||
|
visibleUserIds: note.visibleUserIds ? note.visibleUserIds.map((id: any) => id.toHexString()) : [],
|
||||||
|
replyId: note.replyId ? note.replyId.toHexString() : null,
|
||||||
|
renoteId: note.renoteId ? note.renoteId.toHexString() : null,
|
||||||
|
userHost: null,
|
||||||
|
fileIds: note.fileIds ? note.fileIds.map((id: any) => id.toHexString()) : [],
|
||||||
|
localOnly: note.localOnly || false,
|
||||||
|
hasPoll: note.poll != null
|
||||||
|
});
|
||||||
|
|
||||||
|
if (note.poll) {
|
||||||
|
await Polls.save({
|
||||||
|
noteId: note._id.toHexString(),
|
||||||
|
choices: note.poll.choices.map((x: any) => x.text),
|
||||||
|
expiresAt: note.poll.expiresAt,
|
||||||
|
multiple: note.poll.multiple,
|
||||||
|
votes: note.poll.choices.map((x: any) => x.votes),
|
||||||
|
noteVisibility: note.visibility,
|
||||||
|
userId: note.userId.toHexString(),
|
||||||
|
userHost: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migratePollVote(vote: any) {
|
||||||
|
await PollVotes.save({
|
||||||
|
id: vote._id.toHexString(),
|
||||||
|
createdAt: vote.createdAt,
|
||||||
|
noteId: vote.noteId.toHexString(),
|
||||||
|
userId: vote.userId.toHexString(),
|
||||||
|
choice: vote.choice
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateNoteFavorite(favorite: any) {
|
||||||
|
await NoteFavorites.save({
|
||||||
|
id: favorite._id.toHexString(),
|
||||||
|
createdAt: favorite.createdAt,
|
||||||
|
noteId: favorite.noteId.toHexString(),
|
||||||
|
userId: favorite.userId.toHexString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateNoteReaction(reaction: any) {
|
||||||
|
await NoteReactions.save({
|
||||||
|
id: reaction._id.toHexString(),
|
||||||
|
createdAt: reaction.createdAt,
|
||||||
|
noteId: reaction.noteId.toHexString(),
|
||||||
|
userId: reaction.userId.toHexString(),
|
||||||
|
reaction: reaction.reaction
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function reMigrateUser(user: any) {
|
||||||
|
const u = await _User.findOne({
|
||||||
|
_id: new mongo.ObjectId(user.id)
|
||||||
|
});
|
||||||
|
const avatar = u.avatarId ? await DriveFiles.findOne(u.avatarId.toHexString()) : null;
|
||||||
|
const banner = u.bannerId ? await DriveFiles.findOne(u.bannerId.toHexString()) : null;
|
||||||
|
await Users.update(user.id, {
|
||||||
|
avatarId: avatar ? avatar.id : null,
|
||||||
|
bannerId: banner ? banner.id : null,
|
||||||
|
avatarUrl: avatar ? avatar.url : null,
|
||||||
|
bannerUrl: banner ? banner.url : null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateEmoji(emoji: any) {
|
||||||
|
await Emojis.save({
|
||||||
|
id: emoji._id.toHexString(),
|
||||||
|
updatedAt: emoji.createdAt,
|
||||||
|
aliases: emoji.aliases,
|
||||||
|
url: emoji.url,
|
||||||
|
uri: emoji.uri,
|
||||||
|
host: toPuny(emoji.host),
|
||||||
|
name: emoji.name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let allUsersCount = await _User.count({
|
||||||
|
deletedAt: { $exists: false }
|
||||||
|
});
|
||||||
|
if (test && allUsersCount > limit) allUsersCount = limit;
|
||||||
|
for (let i = 0; i < allUsersCount; i++) {
|
||||||
|
const user = await _User.findOne({
|
||||||
|
deletedAt: { $exists: false }
|
||||||
|
}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateUser(user);
|
||||||
|
console.log(`USER (${i + 1}/${allUsersCount}) ${user._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`USER (${i + 1}/${allUsersCount}) ${user._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allFollowingsCount = await _Following.count();
|
||||||
|
if (test && allFollowingsCount > limit) allFollowingsCount = limit;
|
||||||
|
for (let i = 0; i < allFollowingsCount; i++) {
|
||||||
|
const following = await _Following.findOne({}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateFollowing(following);
|
||||||
|
console.log(`FOLLOWING (${i + 1}/${allFollowingsCount}) ${following._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`FOLLOWING (${i + 1}/${allFollowingsCount}) ${following._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allDriveFoldersCount = await _DriveFolder.count();
|
||||||
|
if (test && allDriveFoldersCount > limit) allDriveFoldersCount = limit;
|
||||||
|
for (let i = 0; i < allDriveFoldersCount; i++) {
|
||||||
|
const folder = await _DriveFolder.findOne({}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateDriveFolder(folder);
|
||||||
|
console.log(`FOLDER (${i + 1}/${allDriveFoldersCount}) ${folder._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`FOLDER (${i + 1}/${allDriveFoldersCount}) ${folder._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allDriveFilesCount = await _DriveFile.count({
|
||||||
|
'metadata._user.host': null,
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
|
});
|
||||||
|
if (test && allDriveFilesCount > limit) allDriveFilesCount = limit;
|
||||||
|
for (let i = 0; i < allDriveFilesCount; i++) {
|
||||||
|
const file = await _DriveFile.findOne({
|
||||||
|
'metadata._user.host': null,
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
|
}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateDriveFile(file);
|
||||||
|
console.log(`FILE (${i + 1}/${allDriveFilesCount}) ${file._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`FILE (${i + 1}/${allDriveFilesCount}) ${file._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allNotesCount = await _Note.count({
|
||||||
|
'_user.host': null,
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
|
});
|
||||||
|
if (test && allNotesCount > limit) allNotesCount = limit;
|
||||||
|
for (let i = 0; i < allNotesCount; i++) {
|
||||||
|
const note = await _Note.findOne({
|
||||||
|
'_user.host': null,
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
|
}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateNote(note);
|
||||||
|
console.log(`NOTE (${i + 1}/${allNotesCount}) ${note._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`NOTE (${i + 1}/${allNotesCount}) ${note._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allPollVotesCount = await _PollVote.count();
|
||||||
|
if (test && allPollVotesCount > limit) allPollVotesCount = limit;
|
||||||
|
for (let i = 0; i < allPollVotesCount; i++) {
|
||||||
|
const vote = await _PollVote.findOne({}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migratePollVote(vote);
|
||||||
|
console.log(`VOTE (${i + 1}/${allPollVotesCount}) ${vote._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`VOTE (${i + 1}/${allPollVotesCount}) ${vote._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allNoteFavoritesCount = await _Favorite.count();
|
||||||
|
if (test && allNoteFavoritesCount > limit) allNoteFavoritesCount = limit;
|
||||||
|
for (let i = 0; i < allNoteFavoritesCount; i++) {
|
||||||
|
const favorite = await _Favorite.findOne({}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateNoteFavorite(favorite);
|
||||||
|
console.log(`FAVORITE (${i + 1}/${allNoteFavoritesCount}) ${favorite._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`FAVORITE (${i + 1}/${allNoteFavoritesCount}) ${favorite._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allNoteReactionsCount = await _NoteReaction.count();
|
||||||
|
if (test && allNoteReactionsCount > limit) allNoteReactionsCount = limit;
|
||||||
|
for (let i = 0; i < allNoteReactionsCount; i++) {
|
||||||
|
const reaction = await _NoteReaction.findOne({}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateNoteReaction(reaction);
|
||||||
|
console.log(`REACTION (${i + 1}/${allNoteReactionsCount}) ${reaction._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`REACTION (${i + 1}/${allNoteReactionsCount}) ${reaction._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allActualUsersCount = await Users.count();
|
||||||
|
if (test && allActualUsersCount > limit) allActualUsersCount = limit;
|
||||||
|
for (let i = 0; i < allActualUsersCount; i++) {
|
||||||
|
const [user] = await Users.find({
|
||||||
|
take: 1,
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await reMigrateUser(user);
|
||||||
|
console.log(`RE:USER (${i + 1}/${allActualUsersCount}) ${user.id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`RE:USER (${i + 1}/${allActualUsersCount}) ${user.id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const allEmojisCount = await _Emoji.count();
|
||||||
|
for (let i = 0; i < allEmojisCount; i++) {
|
||||||
|
const emoji = await _Emoji.findOne({}, {
|
||||||
|
skip: i
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await migrateEmoji(emoji);
|
||||||
|
console.log(`EMOJI (${i + 1}/${allEmojisCount}) ${emoji._id} ${chalk.green('DONE')}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`EMOJI (${i + 1}/${allEmojisCount}) ${emoji._id} ${chalk.red('ERR')}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('DONE :)');
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
@ -1,5 +1,5 @@
|
|||||||
import Acct from './type';
|
import Acct from './type';
|
||||||
|
|
||||||
export default (user: Acct) => {
|
export default (user: Acct) => {
|
||||||
return user.host === null ? user.username : `${user.username}@${user.host}`;
|
return user.host == null ? user.username : `${user.username}@${user.host}`;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
type Acct = {
|
type Acct = {
|
||||||
username: string;
|
username: string;
|
||||||
host: string;
|
host: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Acct;
|
export default Acct;
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { toUnicode, toASCII } from 'punycode';
|
import { toASCII } from 'punycode';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
|
|
||||||
export function getFullApAccount(username: string, host: string) {
|
export function getFullApAccount(username: string, host: string | null) {
|
||||||
return host ? `${username}@${toApHost(host)}` : `${username}@${toApHost(config.host)}`;
|
return host ? `${username}@${toPuny(host)}` : `${username}@${toPuny(config.host)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSelfHost(host: string) {
|
export function isSelfHost(host: string) {
|
||||||
if (host == null) return true;
|
if (host == null) return true;
|
||||||
return toApHost(config.host) === toApHost(host);
|
return toPuny(config.host) === toPuny(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractDbHost(uri: string) {
|
export function extractDbHost(uri: string) {
|
||||||
const url = new URL(uri);
|
const url = new URL(uri);
|
||||||
return toDbHost(url.hostname);
|
return toPuny(url.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toDbHost(host: string) {
|
export function toPuny(host: string) {
|
||||||
if (host == null) return null;
|
|
||||||
return toUnicode(host.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toApHost(host: string) {
|
|
||||||
if (host == null) return null;
|
|
||||||
return toASCII(host.toLowerCase());
|
return toASCII(host.toLowerCase());
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import fileType from 'file-type';
|
|||||||
import checkSvg from '../misc/check-svg';
|
import checkSvg from '../misc/check-svg';
|
||||||
|
|
||||||
export async function detectMine(path: string) {
|
export async function detectMine(path: string) {
|
||||||
return new Promise<[string, string]>((res, rej) => {
|
return new Promise<[string, string | null]>((res, rej) => {
|
||||||
const readable = fs.createReadStream(path);
|
const readable = fs.createReadStream(path);
|
||||||
readable
|
readable
|
||||||
.on('error', rej)
|
.on('error', rej)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as URL from 'url';
|
|
||||||
import * as request from 'request';
|
import * as request from 'request';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
@ -26,7 +25,7 @@ export async function downloadUrl(url: string, path: string) {
|
|||||||
rej(error);
|
rej(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
const requestUrl = URL.parse(url).pathname.match(/[^\u0021-\u00ff]/) ? encodeURI(url) : url;
|
const requestUrl = new URL(url).pathname.match(/[^\u0021-\u00ff]/) ? encodeURI(url) : url;
|
||||||
|
|
||||||
const req = request({
|
const req = request({
|
||||||
url: requestUrl,
|
url: requestUrl,
|
||||||
|
@ -9,7 +9,6 @@ export default async function(): Promise<Meta> {
|
|||||||
} else {
|
} else {
|
||||||
return Metas.save({
|
return Metas.save({
|
||||||
id: genId(),
|
id: genId(),
|
||||||
hiddenTags: []
|
|
||||||
} as Meta);
|
} as Meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import fetchMeta from './fetch-meta';
|
import fetchMeta from './fetch-meta';
|
||||||
import { ILocalUser } from '../models/entities/user';
|
import { ILocalUser } from '../models/entities/user';
|
||||||
import { Users } from '../models';
|
import { Users } from '../models';
|
||||||
|
import { ensure } from '../prelude/ensure';
|
||||||
|
|
||||||
export async function fetchProxyAccount(): Promise<ILocalUser> {
|
export async function fetchProxyAccount(): Promise<ILocalUser> {
|
||||||
const meta = await fetchMeta();
|
const meta = await fetchMeta();
|
||||||
return await Users.findOne({ username: meta.proxyAccount, host: null }) as ILocalUser;
|
return await Users.findOne({ username: meta.proxyAccount!, host: null }).then(ensure) as ILocalUser;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import getAcct from './acct/render';
|
|
||||||
import getUserName from './get-user-name';
|
|
||||||
import { User } from '../models/entities/user';
|
|
||||||
import { Users } from '../models';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ユーザーを表す文字列を取得します。
|
|
||||||
* @param user ユーザー
|
|
||||||
*/
|
|
||||||
export default function(user: User): string {
|
|
||||||
let string = `${getUserName(user)} (@${getAcct(user)})\n` +
|
|
||||||
`${user.notesCount}投稿、${user.followingCount}フォロー、${user.followersCount}フォロワー\n`;
|
|
||||||
|
|
||||||
if (Users.isLocalUser(user)) {
|
|
||||||
string += `場所: ${user.location}、誕生日: ${user.birthday}\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string + `「${user.description}」`;
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ export class IdentifiableError extends Error {
|
|||||||
|
|
||||||
constructor(id: string, message?: string) {
|
constructor(id: string, message?: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.message = message;
|
this.message = message || '';
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ export function nyaize(text: string): string {
|
|||||||
// ja-JP
|
// ja-JP
|
||||||
.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ')
|
.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ')
|
||||||
// ko-KR
|
// ko-KR
|
||||||
.replace(/[나-낳]/g, (match: string) => String.fromCharCode(
|
.replace(/[나-낳]/g, match => String.fromCharCode(
|
||||||
match.codePointAt(0) + '냐'.charCodeAt(0) - '나'.charCodeAt(0)
|
match.codePointAt(0)! + '냐'.charCodeAt(0) - '나'.charCodeAt(0)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ type MyType<T extends Schema> = {
|
|||||||
export type SchemaType<p extends Schema> =
|
export type SchemaType<p extends Schema> =
|
||||||
p['type'] extends 'number' ? number :
|
p['type'] extends 'number' ? number :
|
||||||
p['type'] extends 'string' ? string :
|
p['type'] extends 'string' ? string :
|
||||||
p['type'] extends 'array' ? MyType<p['items']>[] :
|
p['type'] extends 'array' ? MyType<NonNullable<p['items']>>[] :
|
||||||
p['type'] extends 'object' ? ObjType<p['properties']> :
|
p['type'] extends 'object' ? ObjType<NonNullable<p['properties']>> :
|
||||||
any;
|
any;
|
||||||
|
|
||||||
export function convertOpenApiSchema(schema: Schema) {
|
export function convertOpenApiSchema(schema: Schema) {
|
||||||
|
@ -53,7 +53,7 @@ export class App {
|
|||||||
public permission: string[];
|
public permission: string[];
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: 'The callbackUrl of the App.'
|
comment: 'The callbackUrl of the App.'
|
||||||
})
|
})
|
||||||
public callbackUrl: string | null;
|
public callbackUrl: string | null;
|
||||||
|
@ -95,9 +95,9 @@ export class DriveFile {
|
|||||||
|
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256,
|
length: 256, nullable: true,
|
||||||
})
|
})
|
||||||
public accessKey: string;
|
public accessKey: string | null;
|
||||||
|
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
@ -150,5 +150,5 @@ export class DriveFile {
|
|||||||
default: false,
|
default: false,
|
||||||
comment: 'Whether the DriveFile is direct link to remote server.'
|
comment: 'Whether the DriveFile is direct link to remote server.'
|
||||||
})
|
})
|
||||||
public isRemote: boolean;
|
public isLink: boolean;
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,12 @@ export class Emoji {
|
|||||||
public host: string | null;
|
public host: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256,
|
length: 512,
|
||||||
})
|
})
|
||||||
public url: string;
|
public url: string;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true
|
length: 512, nullable: true
|
||||||
})
|
})
|
||||||
public uri: string | null;
|
public uri: string | null;
|
||||||
|
|
||||||
|
@ -53,13 +53,13 @@ export class FollowRequest {
|
|||||||
public followerHost: string | null;
|
public followerHost: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followerInbox: string | null;
|
public followerInbox: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followerSharedInbox: string | null;
|
public followerSharedInbox: string | null;
|
||||||
@ -71,13 +71,13 @@ export class FollowRequest {
|
|||||||
public followeeHost: string | null;
|
public followeeHost: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followeeInbox: string | null;
|
public followeeInbox: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followeeSharedInbox: string | null;
|
public followeeSharedInbox: string | null;
|
||||||
|
@ -48,13 +48,13 @@ export class Following {
|
|||||||
public followerHost: string | null;
|
public followerHost: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followerInbox: string | null;
|
public followerInbox: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followerSharedInbox: string | null;
|
public followerSharedInbox: string | null;
|
||||||
@ -66,13 +66,13 @@ export class Following {
|
|||||||
public followeeHost: string | null;
|
public followeeHost: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followeeInbox: string | null;
|
public followeeInbox: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: '[Denormalized]'
|
comment: '[Denormalized]'
|
||||||
})
|
})
|
||||||
public followeeSharedInbox: string | null;
|
public followeeSharedInbox: string | null;
|
||||||
|
@ -78,27 +78,27 @@ export class Meta {
|
|||||||
public blockedHosts: string[];
|
public blockedHosts: string[];
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
default: '/assets/ai.png'
|
default: '/assets/ai.png'
|
||||||
})
|
})
|
||||||
public mascotImageUrl: string | null;
|
public mascotImageUrl: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256,
|
length: 512,
|
||||||
nullable: true
|
nullable: true
|
||||||
})
|
})
|
||||||
public bannerUrl: string | null;
|
public bannerUrl: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
default: 'https://ai.misskey.xyz/aiart/yubitun.png'
|
default: 'https://ai.misskey.xyz/aiart/yubitun.png'
|
||||||
})
|
})
|
||||||
public errorImageUrl: string | null;
|
public errorImageUrl: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256,
|
length: 512,
|
||||||
nullable: true
|
nullable: true
|
||||||
})
|
})
|
||||||
public iconUrl: string | null;
|
public iconUrl: string | null;
|
||||||
|
@ -15,13 +15,6 @@ export class Note {
|
|||||||
})
|
})
|
||||||
public createdAt: Date;
|
public createdAt: Date;
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column('timestamp with time zone', {
|
|
||||||
nullable: true,
|
|
||||||
comment: 'The updated date of the Note.'
|
|
||||||
})
|
|
||||||
public updatedAt: Date | null;
|
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column({
|
@Column({
|
||||||
...id(),
|
...id(),
|
||||||
@ -126,7 +119,7 @@ export class Note {
|
|||||||
|
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: 'The URI of a note. it will be null when the note is local.'
|
comment: 'The URI of a note. it will be null when the note is local.'
|
||||||
})
|
})
|
||||||
public uri: string | null;
|
public uri: string | null;
|
||||||
@ -183,7 +176,7 @@ export class Note {
|
|||||||
public hasPoll: boolean;
|
public hasPoll: boolean;
|
||||||
|
|
||||||
@Column('jsonb', {
|
@Column('jsonb', {
|
||||||
nullable: true, default: {}
|
nullable: true, default: null
|
||||||
})
|
})
|
||||||
public geo: any | null;
|
public geo: any | null;
|
||||||
|
|
||||||
@ -195,12 +188,6 @@ export class Note {
|
|||||||
})
|
})
|
||||||
public userHost: string | null;
|
public userHost: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
comment: '[Denormalized]'
|
|
||||||
})
|
|
||||||
public userInbox: string | null;
|
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
...id(),
|
...id(),
|
||||||
nullable: true,
|
nullable: true,
|
||||||
@ -227,6 +214,14 @@ export class Note {
|
|||||||
})
|
})
|
||||||
public renoteUserHost: string | null;
|
public renoteUserHost: string | null;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
constructor(data: Partial<Note>) {
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(data)) {
|
||||||
|
(this as any)[k] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IMentionedRemoteUsers = {
|
export type IMentionedRemoteUsers = {
|
||||||
|
@ -6,10 +6,6 @@ import { User } from './user';
|
|||||||
@Entity()
|
@Entity()
|
||||||
export class Poll {
|
export class Poll {
|
||||||
@PrimaryColumn(id())
|
@PrimaryColumn(id())
|
||||||
public id: string;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column(id())
|
|
||||||
public noteId: Note['id'];
|
public noteId: Note['id'];
|
||||||
|
|
||||||
@OneToOne(type => Note, {
|
@OneToOne(type => Note, {
|
||||||
@ -57,11 +53,19 @@ export class Poll {
|
|||||||
})
|
})
|
||||||
public userHost: string | null;
|
public userHost: string | null;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
constructor(data: Partial<Poll>) {
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(data)) {
|
||||||
|
(this as any)[k] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IPoll = {
|
export type IPoll = {
|
||||||
choices: string[];
|
choices: string[];
|
||||||
votes?: number[];
|
votes?: number[];
|
||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
expiresAt: Date;
|
expiresAt: Date | null;
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@ export class SwSubscription {
|
|||||||
public user: User | null;
|
public user: User | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256,
|
length: 512,
|
||||||
})
|
})
|
||||||
public endpoint: string;
|
public endpoint: string;
|
||||||
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm';
|
import { PrimaryColumn, Entity, JoinColumn, Column, OneToOne } from 'typeorm';
|
||||||
import { User } from './user';
|
import { User } from './user';
|
||||||
import { id } from '../id';
|
import { id } from '../id';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class UserKeypair {
|
export class UserKeypair {
|
||||||
@PrimaryColumn(id())
|
@PrimaryColumn(id())
|
||||||
public id: string;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column(id())
|
|
||||||
public userId: User['id'];
|
public userId: User['id'];
|
||||||
|
|
||||||
@OneToOne(type => User, {
|
@OneToOne(type => User, {
|
||||||
@ -26,4 +22,12 @@ export class UserKeypair {
|
|||||||
length: 4096,
|
length: 4096,
|
||||||
})
|
})
|
||||||
public privateKey: string;
|
public privateKey: string;
|
||||||
|
|
||||||
|
constructor(data: Partial<UserKeypair>) {
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(data)) {
|
||||||
|
(this as any)[k] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
209
src/models/entities/user-profile.ts
Normal file
209
src/models/entities/user-profile.ts
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
|
||||||
|
import { id } from '../id';
|
||||||
|
import { User } from './user';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class UserProfile {
|
||||||
|
@PrimaryColumn(id())
|
||||||
|
public userId: User['id'];
|
||||||
|
|
||||||
|
@OneToOne(type => User, {
|
||||||
|
onDelete: 'CASCADE'
|
||||||
|
})
|
||||||
|
@JoinColumn()
|
||||||
|
public user: User | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
comment: 'The location of the User.'
|
||||||
|
})
|
||||||
|
public location: string | null;
|
||||||
|
|
||||||
|
@Column('char', {
|
||||||
|
length: 10, nullable: true,
|
||||||
|
comment: 'The birthday (YYYY-MM-DD) of the User.'
|
||||||
|
})
|
||||||
|
public birthday: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024, nullable: true,
|
||||||
|
comment: 'The description (bio) of the User.'
|
||||||
|
})
|
||||||
|
public description: string | null;
|
||||||
|
|
||||||
|
@Column('jsonb', {
|
||||||
|
default: [],
|
||||||
|
})
|
||||||
|
public fields: {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 512, nullable: true,
|
||||||
|
comment: 'Remote URL of the user.'
|
||||||
|
})
|
||||||
|
public url: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
comment: 'The email address of the User.'
|
||||||
|
})
|
||||||
|
public email: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
})
|
||||||
|
public emailVerifyCode: string | null;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public emailVerified: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
})
|
||||||
|
public twoFactorTempSecret: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
})
|
||||||
|
public twoFactorSecret: string | null;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public twoFactorEnabled: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
comment: 'The password hash of the User. It will be null if the origin of the user is local.'
|
||||||
|
})
|
||||||
|
public password: string | null;
|
||||||
|
|
||||||
|
@Column('jsonb', {
|
||||||
|
default: {},
|
||||||
|
comment: 'The client-specific data of the User.'
|
||||||
|
})
|
||||||
|
public clientData: Record<string, any>;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public autoWatch: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public autoAcceptFollowed: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public alwaysMarkNsfw: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public carefulBot: boolean;
|
||||||
|
|
||||||
|
//#region Linking
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public twitter: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public twitterAccessToken: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public twitterAccessTokenSecret: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public twitterUserId: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public twitterScreenName: string | null;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public github: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public githubAccessToken: string | null;
|
||||||
|
|
||||||
|
@Column('integer', {
|
||||||
|
nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public githubId: number | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public githubLogin: string | null;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public discord: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public discordAccessToken: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public discordRefreshToken: string | null;
|
||||||
|
|
||||||
|
@Column('integer', {
|
||||||
|
nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public discordExpiresDate: number | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public discordId: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public discordUsername: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true, default: null,
|
||||||
|
})
|
||||||
|
public discordDiscriminator: string | null;
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region Denormalized fields
|
||||||
|
@Index()
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
comment: '[Denormalized]'
|
||||||
|
})
|
||||||
|
public userHost: string | null;
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
constructor(data: Partial<UserProfile>) {
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(data)) {
|
||||||
|
(this as any)[k] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,10 +5,6 @@ import { id } from '../id';
|
|||||||
@Entity()
|
@Entity()
|
||||||
export class UserPublickey {
|
export class UserPublickey {
|
||||||
@PrimaryColumn(id())
|
@PrimaryColumn(id())
|
||||||
public id: string;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column(id())
|
|
||||||
public userId: User['id'];
|
public userId: User['id'];
|
||||||
|
|
||||||
@OneToOne(type => User, {
|
@OneToOne(type => User, {
|
||||||
@ -27,4 +23,12 @@ export class UserPublickey {
|
|||||||
length: 4096,
|
length: 4096,
|
||||||
})
|
})
|
||||||
public keyPem: string;
|
public keyPem: string;
|
||||||
|
|
||||||
|
constructor(data: Partial<UserPublickey>) {
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(data)) {
|
||||||
|
(this as any)[k] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm';
|
|
||||||
import { User } from './user';
|
|
||||||
import { id } from '../id';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class UserServiceLinking {
|
|
||||||
@PrimaryColumn(id())
|
|
||||||
public id: string;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column(id())
|
|
||||||
public userId: User['id'];
|
|
||||||
|
|
||||||
@OneToOne(type => User, {
|
|
||||||
onDelete: 'CASCADE'
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public user: User | null;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public twitter: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public twitterAccessToken: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public twitterAccessTokenSecret: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public twitterUserId: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public twitterScreenName: string | null;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public github: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public githubAccessToken: string | null;
|
|
||||||
|
|
||||||
@Column('integer', {
|
|
||||||
nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public githubId: number | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public githubLogin: string | null;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public discord: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public discordAccessToken: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public discordRefreshToken: string | null;
|
|
||||||
|
|
||||||
@Column('integer', {
|
|
||||||
nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public discordExpiresDate: number | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public discordId: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public discordUsername: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true, default: null,
|
|
||||||
})
|
|
||||||
public discordDiscriminator: string | null;
|
|
||||||
|
|
||||||
//#region Denormalized fields
|
|
||||||
@Index()
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
comment: '[Denormalized]'
|
|
||||||
})
|
|
||||||
public userHost: string | null;
|
|
||||||
//#endregion
|
|
||||||
}
|
|
@ -45,18 +45,6 @@ export class User {
|
|||||||
})
|
})
|
||||||
public name: string | null;
|
public name: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
comment: 'The location of the User.'
|
|
||||||
})
|
|
||||||
public location: string | null;
|
|
||||||
|
|
||||||
@Column('char', {
|
|
||||||
length: 10, nullable: true,
|
|
||||||
comment: 'The birthday (YYYY-MM-DD) of the User.'
|
|
||||||
})
|
|
||||||
public birthday: string | null;
|
|
||||||
|
|
||||||
@Column('integer', {
|
@Column('integer', {
|
||||||
default: 0,
|
default: 0,
|
||||||
comment: 'The count of followers.'
|
comment: 'The count of followers.'
|
||||||
@ -101,12 +89,6 @@ export class User {
|
|||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public banner: DriveFile | null;
|
public banner: DriveFile | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 1024, nullable: true,
|
|
||||||
comment: 'The description (bio) of the User.'
|
|
||||||
})
|
|
||||||
public description: string | null;
|
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, array: true, default: '{}'
|
length: 128, array: true, default: '{}'
|
||||||
@ -114,38 +96,12 @@ export class User {
|
|||||||
public tags: string[];
|
public tags: string[];
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: 'The email address of the User.'
|
|
||||||
})
|
|
||||||
public email: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
})
|
|
||||||
public emailVerifyCode: string | null;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public emailVerified: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
})
|
|
||||||
public twoFactorTempSecret: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
})
|
|
||||||
public twoFactorSecret: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 256, nullable: true,
|
|
||||||
})
|
})
|
||||||
public avatarUrl: string | null;
|
public avatarUrl: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
})
|
})
|
||||||
public bannerUrl: string | null;
|
public bannerUrl: string | null;
|
||||||
|
|
||||||
@ -206,11 +162,6 @@ export class User {
|
|||||||
})
|
})
|
||||||
public isVerified: boolean;
|
public isVerified: boolean;
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public twoFactorEnabled: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, array: true, default: '{}'
|
length: 128, array: true, default: '{}'
|
||||||
})
|
})
|
||||||
@ -224,68 +175,44 @@ export class User {
|
|||||||
public host: string | null;
|
public host: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: 'The inbox of the User. It will be null if the origin of the user is local.'
|
comment: 'The inbox URL of the User. It will be null if the origin of the user is local.'
|
||||||
})
|
})
|
||||||
public inbox: string | null;
|
public inbox: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: 'The sharedInbox of the User. It will be null if the origin of the user is local.'
|
comment: 'The sharedInbox URL of the User. It will be null if the origin of the user is local.'
|
||||||
})
|
})
|
||||||
public sharedInbox: string | null;
|
public sharedInbox: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: 'The featured of the User. It will be null if the origin of the user is local.'
|
comment: 'The featured URL of the User. It will be null if the origin of the user is local.'
|
||||||
})
|
})
|
||||||
public featured: string | null;
|
public featured: string | null;
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 512, nullable: true,
|
||||||
comment: 'The URI of the User. It will be null if the origin of the user is local.'
|
comment: 'The URI of the User. It will be null if the origin of the user is local.'
|
||||||
})
|
})
|
||||||
public uri: string | null;
|
public uri: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
comment: 'The password hash of the User. It will be null if the origin of the user is local.'
|
|
||||||
})
|
|
||||||
public password: string | null;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column('varchar', {
|
@Column('char', {
|
||||||
length: 32, nullable: true, unique: true,
|
length: 16, nullable: true, unique: true,
|
||||||
comment: 'The native access token of the User. It will be null if the origin of the user is local.'
|
comment: 'The native access token of the User. It will be null if the origin of the user is local.'
|
||||||
})
|
})
|
||||||
public token: string | null;
|
public token: string | null;
|
||||||
|
|
||||||
@Column('jsonb', {
|
constructor(data: Partial<User>) {
|
||||||
default: {},
|
if (data == null) return;
|
||||||
comment: 'The client-specific data of the User.'
|
|
||||||
})
|
|
||||||
public clientData: Record<string, any>;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
for (const [k, v] of Object.entries(data)) {
|
||||||
default: false,
|
(this as any)[k] = v;
|
||||||
})
|
}
|
||||||
public autoWatch: boolean;
|
}
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public autoAcceptFollowed: boolean;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public alwaysMarkNsfw: boolean;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public carefulBot: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILocalUser extends User {
|
export interface ILocalUser extends User {
|
||||||
|
@ -25,7 +25,6 @@ import { FollowRequestRepository } from './repositories/follow-request';
|
|||||||
import { MutingRepository } from './repositories/muting';
|
import { MutingRepository } from './repositories/muting';
|
||||||
import { BlockingRepository } from './repositories/blocking';
|
import { BlockingRepository } from './repositories/blocking';
|
||||||
import { NoteReactionRepository } from './repositories/note-reaction';
|
import { NoteReactionRepository } from './repositories/note-reaction';
|
||||||
import { UserServiceLinking } from './entities/user-service-linking';
|
|
||||||
import { NotificationRepository } from './repositories/notification';
|
import { NotificationRepository } from './repositories/notification';
|
||||||
import { NoteFavoriteRepository } from './repositories/note-favorite';
|
import { NoteFavoriteRepository } from './repositories/note-favorite';
|
||||||
import { ReversiMatchingRepository } from './repositories/games/reversi/matching';
|
import { ReversiMatchingRepository } from './repositories/games/reversi/matching';
|
||||||
@ -35,6 +34,7 @@ import { AppRepository } from './repositories/app';
|
|||||||
import { FollowingRepository } from './repositories/following';
|
import { FollowingRepository } from './repositories/following';
|
||||||
import { AbuseUserReportRepository } from './repositories/abuse-user-report';
|
import { AbuseUserReportRepository } from './repositories/abuse-user-report';
|
||||||
import { AuthSessionRepository } from './repositories/auth-session';
|
import { AuthSessionRepository } from './repositories/auth-session';
|
||||||
|
import { UserProfile } from './entities/user-profile';
|
||||||
|
|
||||||
export const Apps = getCustomRepository(AppRepository);
|
export const Apps = getCustomRepository(AppRepository);
|
||||||
export const Notes = getCustomRepository(NoteRepository);
|
export const Notes = getCustomRepository(NoteRepository);
|
||||||
@ -45,12 +45,12 @@ export const NoteUnreads = getRepository(NoteUnread);
|
|||||||
export const Polls = getRepository(Poll);
|
export const Polls = getRepository(Poll);
|
||||||
export const PollVotes = getRepository(PollVote);
|
export const PollVotes = getRepository(PollVote);
|
||||||
export const Users = getCustomRepository(UserRepository);
|
export const Users = getCustomRepository(UserRepository);
|
||||||
|
export const UserProfiles = getRepository(UserProfile);
|
||||||
export const UserKeypairs = getRepository(UserKeypair);
|
export const UserKeypairs = getRepository(UserKeypair);
|
||||||
export const UserPublickeys = getRepository(UserPublickey);
|
export const UserPublickeys = getRepository(UserPublickey);
|
||||||
export const UserLists = getCustomRepository(UserListRepository);
|
export const UserLists = getCustomRepository(UserListRepository);
|
||||||
export const UserListJoinings = getRepository(UserListJoining);
|
export const UserListJoinings = getRepository(UserListJoining);
|
||||||
export const UserNotePinings = getRepository(UserNotePining);
|
export const UserNotePinings = getRepository(UserNotePining);
|
||||||
export const UserServiceLinkings = getRepository(UserServiceLinking);
|
|
||||||
export const Followings = getCustomRepository(FollowingRepository);
|
export const Followings = getCustomRepository(FollowingRepository);
|
||||||
export const FollowRequests = getCustomRepository(FollowRequestRepository);
|
export const FollowRequests = getCustomRepository(FollowRequestRepository);
|
||||||
export const Instances = getRepository(Instance);
|
export const Instances = getRepository(Instance);
|
||||||
|
@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import { Users } from '..';
|
import { Users } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { AbuseUserReport } from '../entities/abuse-user-report';
|
import { AbuseUserReport } from '../entities/abuse-user-report';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(AbuseUserReport)
|
@EntityRepository(AbuseUserReport)
|
||||||
export class AbuseUserReportRepository extends Repository<AbuseUserReport> {
|
export class AbuseUserReportRepository extends Repository<AbuseUserReport> {
|
||||||
@ -14,7 +15,7 @@ export class AbuseUserReportRepository extends Repository<AbuseUserReport> {
|
|||||||
public async pack(
|
public async pack(
|
||||||
src: AbuseUserReport['id'] | AbuseUserReport,
|
src: AbuseUserReport['id'] | AbuseUserReport,
|
||||||
) {
|
) {
|
||||||
const report = typeof src === 'object' ? src : await this.findOne(src);
|
const report = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: report.id,
|
id: report.id,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { App } from '../entities/app';
|
import { App } from '../entities/app';
|
||||||
import { AccessTokens } from '..';
|
import { AccessTokens } from '..';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(App)
|
@EntityRepository(App)
|
||||||
export class AppRepository extends Repository<App> {
|
export class AppRepository extends Repository<App> {
|
||||||
@ -19,7 +20,7 @@ export class AppRepository extends Repository<App> {
|
|||||||
includeProfileImageIds: false
|
includeProfileImageIds: false
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const app = typeof src === 'object' ? src : await this.findOne(src);
|
const app = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: app.id,
|
id: app.id,
|
||||||
|
@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import { Apps } from '..';
|
import { Apps } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { AuthSession } from '../entities/auth-session';
|
import { AuthSession } from '../entities/auth-session';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(AuthSession)
|
@EntityRepository(AuthSession)
|
||||||
export class AuthSessionRepository extends Repository<AuthSession> {
|
export class AuthSessionRepository extends Repository<AuthSession> {
|
||||||
@ -9,7 +10,7 @@ export class AuthSessionRepository extends Repository<AuthSession> {
|
|||||||
src: AuthSession['id'] | AuthSession,
|
src: AuthSession['id'] | AuthSession,
|
||||||
me?: any
|
me?: any
|
||||||
) {
|
) {
|
||||||
const session = typeof src === 'object' ? src : await this.findOne(src);
|
const session = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: session.id,
|
id: session.id,
|
||||||
|
@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import { Users } from '..';
|
import { Users } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { Blocking } from '../entities/blocking';
|
import { Blocking } from '../entities/blocking';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(Blocking)
|
@EntityRepository(Blocking)
|
||||||
export class BlockingRepository extends Repository<Blocking> {
|
export class BlockingRepository extends Repository<Blocking> {
|
||||||
@ -16,7 +17,7 @@ export class BlockingRepository extends Repository<Blocking> {
|
|||||||
src: Blocking['id'] | Blocking,
|
src: Blocking['id'] | Blocking,
|
||||||
me?: any
|
me?: any
|
||||||
) {
|
) {
|
||||||
const blocking = typeof src === 'object' ? src : await this.findOne(src);
|
const blocking = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: blocking.id,
|
id: blocking.id,
|
||||||
|
@ -3,6 +3,8 @@ import { DriveFile } from '../entities/drive-file';
|
|||||||
import { Users, DriveFolders } from '..';
|
import { Users, DriveFolders } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { User } from '../entities/user';
|
import { User } from '../entities/user';
|
||||||
|
import { toPuny } from '../../misc/convert-host';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(DriveFile)
|
@EntityRepository(DriveFile)
|
||||||
export class DriveFileRepository extends Repository<DriveFile> {
|
export class DriveFileRepository extends Repository<DriveFile> {
|
||||||
@ -39,7 +41,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
|
|||||||
public async clacDriveUsageOfHost(host: string): Promise<number> {
|
public async clacDriveUsageOfHost(host: string): Promise<number> {
|
||||||
const { sum } = await this
|
const { sum } = await this
|
||||||
.createQueryBuilder('file')
|
.createQueryBuilder('file')
|
||||||
.where('file.userHost = :host', { host: host })
|
.where('file.userHost = :host', { host: toPuny(host) })
|
||||||
.select('SUM(file.size)', 'sum')
|
.select('SUM(file.size)', 'sum')
|
||||||
.getRawOne();
|
.getRawOne();
|
||||||
|
|
||||||
@ -90,7 +92,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
|
|||||||
self: false
|
self: false
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const file = typeof src === 'object' ? src : await this.findOne(src);
|
const file = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: file.id,
|
id: file.id,
|
||||||
@ -107,7 +109,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
|
|||||||
folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, {
|
folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, {
|
||||||
detail: true
|
detail: true
|
||||||
}) : null,
|
}) : null,
|
||||||
user: opts.withUser ? Users.pack(file.userId) : null
|
user: opts.withUser ? Users.pack(file.userId!) : null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import { DriveFolders, DriveFiles } from '..';
|
import { DriveFolders, DriveFiles } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { DriveFolder } from '../entities/drive-folder';
|
import { DriveFolder } from '../entities/drive-folder';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(DriveFolder)
|
@EntityRepository(DriveFolder)
|
||||||
export class DriveFolderRepository extends Repository<DriveFolder> {
|
export class DriveFolderRepository extends Repository<DriveFolder> {
|
||||||
@ -22,7 +23,7 @@ export class DriveFolderRepository extends Repository<DriveFolder> {
|
|||||||
detail: false
|
detail: false
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const folder = typeof src === 'object' ? src : await this.findOne(src);
|
const folder = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: folder.id,
|
id: folder.id,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { FollowRequest } from '../entities/follow-request';
|
import { FollowRequest } from '../entities/follow-request';
|
||||||
import { Users } from '..';
|
import { Users } from '..';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(FollowRequest)
|
@EntityRepository(FollowRequest)
|
||||||
export class FollowRequestRepository extends Repository<FollowRequest> {
|
export class FollowRequestRepository extends Repository<FollowRequest> {
|
||||||
@ -8,7 +9,7 @@ export class FollowRequestRepository extends Repository<FollowRequest> {
|
|||||||
src: FollowRequest['id'] | FollowRequest,
|
src: FollowRequest['id'] | FollowRequest,
|
||||||
me?: any
|
me?: any
|
||||||
) {
|
) {
|
||||||
const request = typeof src === 'object' ? src : await this.findOne(src);
|
const request = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: request.id,
|
id: request.id,
|
||||||
|
@ -2,9 +2,50 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import { Users } from '..';
|
import { Users } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { Following } from '../entities/following';
|
import { Following } from '../entities/following';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
|
type LocalFollowerFollowing = Following & {
|
||||||
|
followerHost: null;
|
||||||
|
followerInbox: null;
|
||||||
|
followerSharedInbox: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RemoteFollowerFollowing = Following & {
|
||||||
|
followerHost: string;
|
||||||
|
followerInbox: string;
|
||||||
|
followerSharedInbox: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LocalFolloweeFollowing = Following & {
|
||||||
|
followeeHost: null;
|
||||||
|
followeeInbox: null;
|
||||||
|
followeeSharedInbox: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RemoteFolloweeFollowing = Following & {
|
||||||
|
followeeHost: string;
|
||||||
|
followeeInbox: string;
|
||||||
|
followeeSharedInbox: string;
|
||||||
|
};
|
||||||
|
|
||||||
@EntityRepository(Following)
|
@EntityRepository(Following)
|
||||||
export class FollowingRepository extends Repository<Following> {
|
export class FollowingRepository extends Repository<Following> {
|
||||||
|
public isLocalFollower(following: Following): following is LocalFollowerFollowing {
|
||||||
|
return following.followerHost == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isRemoteFollower(following: Following): following is RemoteFollowerFollowing {
|
||||||
|
return following.followerHost != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isLocalFollowee(following: Following): following is LocalFolloweeFollowing {
|
||||||
|
return following.followeeHost == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isRemoteFollowee(following: Following): following is RemoteFolloweeFollowing {
|
||||||
|
return following.followeeHost != null;
|
||||||
|
}
|
||||||
|
|
||||||
public packMany(
|
public packMany(
|
||||||
followings: any[],
|
followings: any[],
|
||||||
me?: any,
|
me?: any,
|
||||||
@ -24,7 +65,7 @@ export class FollowingRepository extends Repository<Following> {
|
|||||||
populateFollower?: boolean;
|
populateFollower?: boolean;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const following = typeof src === 'object' ? src : await this.findOne(src);
|
const following = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
if (opts == null) opts = {};
|
if (opts == null) opts = {};
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Users } from '../../..';
|
import { Users } from '../../..';
|
||||||
import { ReversiGame } from '../../../entities/games/reversi/game';
|
import { ReversiGame } from '../../../entities/games/reversi/game';
|
||||||
|
import { ensure } from '../../../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(ReversiGame)
|
@EntityRepository(ReversiGame)
|
||||||
export class ReversiGameRepository extends Repository<ReversiGame> {
|
export class ReversiGameRepository extends Repository<ReversiGame> {
|
||||||
@ -15,7 +16,7 @@ export class ReversiGameRepository extends Repository<ReversiGame> {
|
|||||||
detail: true
|
detail: true
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const game = typeof src === 'object' ? src : await this.findOne(src);
|
const game = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
const meId = me ? typeof me === 'string' ? me : me.id : null;
|
const meId = me ? typeof me === 'string' ? me : me.id : null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { ReversiMatching } from '../../../entities/games/reversi/matching';
|
import { ReversiMatching } from '../../../entities/games/reversi/matching';
|
||||||
import { Users } from '../../..';
|
import { Users } from '../../..';
|
||||||
|
import { ensure } from '../../../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(ReversiMatching)
|
@EntityRepository(ReversiMatching)
|
||||||
export class ReversiMatchingRepository extends Repository<ReversiMatching> {
|
export class ReversiMatchingRepository extends Repository<ReversiMatching> {
|
||||||
@ -9,7 +10,7 @@ export class ReversiMatchingRepository extends Repository<ReversiMatching> {
|
|||||||
src: ReversiMatching['id'] | ReversiMatching,
|
src: ReversiMatching['id'] | ReversiMatching,
|
||||||
me: any
|
me: any
|
||||||
) {
|
) {
|
||||||
const matching = typeof src === 'object' ? src : await this.findOne(src);
|
const matching = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: matching.id,
|
id: matching.id,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { MessagingMessage } from '../entities/messaging-message';
|
import { MessagingMessage } from '../entities/messaging-message';
|
||||||
import { Users, DriveFiles } from '..';
|
import { Users, DriveFiles } from '..';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(MessagingMessage)
|
@EntityRepository(MessagingMessage)
|
||||||
export class MessagingMessageRepository extends Repository<MessagingMessage> {
|
export class MessagingMessageRepository extends Repository<MessagingMessage> {
|
||||||
@ -19,7 +20,7 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> {
|
|||||||
populateRecipient: true
|
populateRecipient: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const message = typeof src === 'object' ? src : await this.findOne(src);
|
const message = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: message.id,
|
id: message.id,
|
||||||
|
@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import { Users } from '..';
|
import { Users } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { Muting } from '../entities/muting';
|
import { Muting } from '../entities/muting';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(Muting)
|
@EntityRepository(Muting)
|
||||||
export class MutingRepository extends Repository<Muting> {
|
export class MutingRepository extends Repository<Muting> {
|
||||||
@ -16,7 +17,7 @@ export class MutingRepository extends Repository<Muting> {
|
|||||||
src: Muting['id'] | Muting,
|
src: Muting['id'] | Muting,
|
||||||
me?: any
|
me?: any
|
||||||
) {
|
) {
|
||||||
const muting = typeof src === 'object' ? src : await this.findOne(src);
|
const muting = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: muting.id,
|
id: muting.id,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { NoteFavorite } from '../entities/note-favorite';
|
import { NoteFavorite } from '../entities/note-favorite';
|
||||||
import { Notes } from '..';
|
import { Notes } from '..';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(NoteFavorite)
|
@EntityRepository(NoteFavorite)
|
||||||
export class NoteFavoriteRepository extends Repository<NoteFavorite> {
|
export class NoteFavoriteRepository extends Repository<NoteFavorite> {
|
||||||
@ -15,7 +16,7 @@ export class NoteFavoriteRepository extends Repository<NoteFavorite> {
|
|||||||
src: NoteFavorite['id'] | NoteFavorite,
|
src: NoteFavorite['id'] | NoteFavorite,
|
||||||
me?: any
|
me?: any
|
||||||
) {
|
) {
|
||||||
const favorite = typeof src === 'object' ? src : await this.findOne(src);
|
const favorite = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: favorite.id,
|
id: favorite.id,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { NoteReaction } from '../entities/note-reaction';
|
import { NoteReaction } from '../entities/note-reaction';
|
||||||
import { Users } from '..';
|
import { Users } from '..';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(NoteReaction)
|
@EntityRepository(NoteReaction)
|
||||||
export class NoteReactionRepository extends Repository<NoteReaction> {
|
export class NoteReactionRepository extends Repository<NoteReaction> {
|
||||||
@ -8,7 +9,7 @@ export class NoteReactionRepository extends Repository<NoteReaction> {
|
|||||||
src: NoteReaction['id'] | NoteReaction,
|
src: NoteReaction['id'] | NoteReaction,
|
||||||
me?: any
|
me?: any
|
||||||
) {
|
) {
|
||||||
const reaction = typeof src === 'object' ? src : await this.findOne(src);
|
const reaction = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: reaction.id,
|
id: reaction.id,
|
||||||
|
@ -5,6 +5,7 @@ import { unique, concat } from '../../prelude/array';
|
|||||||
import { nyaize } from '../../misc/nyaize';
|
import { nyaize } from '../../misc/nyaize';
|
||||||
import { Emojis, Users, Apps, PollVotes, DriveFiles, NoteReactions, Followings, Polls } from '..';
|
import { Emojis, Users, Apps, PollVotes, DriveFiles, NoteReactions, Followings, Polls } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(Note)
|
@EntityRepository(Note)
|
||||||
export class NoteRepository extends Repository<Note> {
|
export class NoteRepository extends Repository<Note> {
|
||||||
@ -12,7 +13,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
return x.trim().length <= 100;
|
return x.trim().length <= 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async hideNote(packedNote: any, meId: User['id']) {
|
private async hideNote(packedNote: any, meId: User['id'] | null) {
|
||||||
let hide = false;
|
let hide = false;
|
||||||
|
|
||||||
// visibility が specified かつ自分が指定されていなかったら非表示
|
// visibility が specified かつ自分が指定されていなかったら非表示
|
||||||
@ -75,7 +76,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
|
|
||||||
public packMany(
|
public packMany(
|
||||||
notes: (Note['id'] | Note)[],
|
notes: (Note['id'] | Note)[],
|
||||||
me?: User['id'] | User,
|
me?: User['id'] | User | null | undefined,
|
||||||
options?: {
|
options?: {
|
||||||
detail?: boolean;
|
detail?: boolean;
|
||||||
skipHide?: boolean;
|
skipHide?: boolean;
|
||||||
@ -86,7 +87,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
|
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Note['id'] | Note,
|
src: Note['id'] | Note,
|
||||||
me?: User['id'] | User,
|
me?: User['id'] | User | null | undefined,
|
||||||
options?: {
|
options?: {
|
||||||
detail?: boolean;
|
detail?: boolean;
|
||||||
skipHide?: boolean;
|
skipHide?: boolean;
|
||||||
@ -98,11 +99,11 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const meId = me ? typeof me === 'string' ? me : me.id : null;
|
const meId = me ? typeof me === 'string' ? me : me.id : null;
|
||||||
const note = typeof src === 'object' ? src : await this.findOne(src);
|
const note = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
const host = note.userHost;
|
const host = note.userHost;
|
||||||
|
|
||||||
async function populatePoll() {
|
async function populatePoll() {
|
||||||
const poll = await Polls.findOne({ noteId: note.id });
|
const poll = await Polls.findOne({ noteId: note.id }).then(ensure);
|
||||||
const choices = poll.choices.map(c => ({
|
const choices = poll.choices.map(c => ({
|
||||||
text: c,
|
text: c,
|
||||||
votes: poll.votes[poll.choices.indexOf(c)],
|
votes: poll.votes[poll.choices.indexOf(c)],
|
||||||
@ -111,7 +112,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
|
|
||||||
if (poll.multiple) {
|
if (poll.multiple) {
|
||||||
const votes = await PollVotes.find({
|
const votes = await PollVotes.find({
|
||||||
userId: meId,
|
userId: meId!,
|
||||||
noteId: note.id
|
noteId: note.id
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const vote = await PollVotes.findOne({
|
const vote = await PollVotes.findOne({
|
||||||
userId: meId,
|
userId: meId!,
|
||||||
noteId: note.id
|
noteId: note.id
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -139,7 +140,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
|
|
||||||
async function populateMyReaction() {
|
async function populateMyReaction() {
|
||||||
const reaction = await NoteReactions.findOne({
|
const reaction = await NoteReactions.findOne({
|
||||||
userId: meId,
|
userId: meId!,
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -167,8 +168,11 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
text: text,
|
text: text,
|
||||||
cw: note.cw,
|
cw: note.cw,
|
||||||
visibility: note.visibility,
|
visibility: note.visibility,
|
||||||
|
localOnly: note.localOnly,
|
||||||
visibleUserIds: note.visibleUserIds,
|
visibleUserIds: note.visibleUserIds,
|
||||||
viaMobile: note.viaMobile,
|
viaMobile: note.viaMobile,
|
||||||
|
renoteCount: note.renoteCount,
|
||||||
|
repliesCount: note.repliesCount,
|
||||||
reactions: note.reactions,
|
reactions: note.reactions,
|
||||||
emojis: reactionEmojis.length > 0 ? Emojis.find({
|
emojis: reactionEmojis.length > 0 ? Emojis.find({
|
||||||
name: In(reactionEmojis),
|
name: In(reactionEmojis),
|
||||||
@ -179,6 +183,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
files: DriveFiles.packMany(note.fileIds),
|
files: DriveFiles.packMany(note.fileIds),
|
||||||
replyId: note.replyId,
|
replyId: note.replyId,
|
||||||
renoteId: note.renoteId,
|
renoteId: note.renoteId,
|
||||||
|
uri: note.uri,
|
||||||
|
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
reply: note.replyId ? this.pack(note.replyId, meId, {
|
reply: note.replyId ? this.pack(note.replyId, meId, {
|
||||||
@ -186,7 +191,7 @@ export class NoteRepository extends Repository<Note> {
|
|||||||
}) : null,
|
}) : null,
|
||||||
|
|
||||||
renote: note.renoteId ? this.pack(note.renoteId, meId, {
|
renote: note.renoteId ? this.pack(note.renoteId, meId, {
|
||||||
detail: false
|
detail: true
|
||||||
}) : null,
|
}) : null,
|
||||||
|
|
||||||
poll: note.hasPoll ? populatePoll() : null,
|
poll: note.hasPoll ? populatePoll() : null,
|
||||||
|
@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||||||
import { Users, Notes } from '..';
|
import { Users, Notes } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import { Notification } from '../entities/notification';
|
import { Notification } from '../entities/notification';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(Notification)
|
@EntityRepository(Notification)
|
||||||
export class NotificationRepository extends Repository<Notification> {
|
export class NotificationRepository extends Repository<Notification> {
|
||||||
@ -14,7 +15,7 @@ export class NotificationRepository extends Repository<Notification> {
|
|||||||
public async pack(
|
public async pack(
|
||||||
src: Notification['id'] | Notification,
|
src: Notification['id'] | Notification,
|
||||||
) {
|
) {
|
||||||
const notification = typeof src === 'object' ? src : await this.findOne(src);
|
const notification = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: notification.id,
|
id: notification.id,
|
||||||
@ -23,23 +24,23 @@ export class NotificationRepository extends Repository<Notification> {
|
|||||||
userId: notification.notifierId,
|
userId: notification.notifierId,
|
||||||
user: Users.pack(notification.notifier || notification.notifierId),
|
user: Users.pack(notification.notifier || notification.notifierId),
|
||||||
...(notification.type === 'mention' ? {
|
...(notification.type === 'mention' ? {
|
||||||
note: Notes.pack(notification.note || notification.noteId),
|
note: Notes.pack(notification.note || notification.noteId!),
|
||||||
} : {}),
|
} : {}),
|
||||||
...(notification.type === 'reply' ? {
|
...(notification.type === 'reply' ? {
|
||||||
note: Notes.pack(notification.note || notification.noteId),
|
note: Notes.pack(notification.note || notification.noteId!),
|
||||||
} : {}),
|
} : {}),
|
||||||
...(notification.type === 'renote' ? {
|
...(notification.type === 'renote' ? {
|
||||||
note: Notes.pack(notification.note || notification.noteId),
|
note: Notes.pack(notification.note || notification.noteId!),
|
||||||
} : {}),
|
} : {}),
|
||||||
...(notification.type === 'quote' ? {
|
...(notification.type === 'quote' ? {
|
||||||
note: Notes.pack(notification.note || notification.noteId),
|
note: Notes.pack(notification.note || notification.noteId!),
|
||||||
} : {}),
|
} : {}),
|
||||||
...(notification.type === 'reaction' ? {
|
...(notification.type === 'reaction' ? {
|
||||||
note: Notes.pack(notification.note || notification.noteId),
|
note: Notes.pack(notification.note || notification.noteId!),
|
||||||
reaction: notification.reaction
|
reaction: notification.reaction
|
||||||
} : {}),
|
} : {}),
|
||||||
...(notification.type === 'pollVote' ? {
|
...(notification.type === 'pollVote' ? {
|
||||||
note: Notes.pack(notification.note || notification.noteId),
|
note: Notes.pack(notification.note || notification.noteId!),
|
||||||
choice: notification.choice
|
choice: notification.choice
|
||||||
} : {})
|
} : {})
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { UserList } from '../entities/user-list';
|
import { UserList } from '../entities/user-list';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(UserList)
|
@EntityRepository(UserList)
|
||||||
export class UserListRepository extends Repository<UserList> {
|
export class UserListRepository extends Repository<UserList> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: any,
|
src: UserList['id'] | UserList,
|
||||||
) {
|
) {
|
||||||
const userList = typeof src === 'object' ? src : await this.findOne(src);
|
const userList = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: userList.id,
|
id: userList.id,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { EntityRepository, Repository, In } from 'typeorm';
|
import { EntityRepository, Repository, In } from 'typeorm';
|
||||||
import { User, ILocalUser, IRemoteUser } from '../entities/user';
|
import { User, ILocalUser, IRemoteUser } from '../entities/user';
|
||||||
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings } from '..';
|
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles } from '..';
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@EntityRepository(User)
|
@EntityRepository(User)
|
||||||
export class UserRepository extends Repository<User> {
|
export class UserRepository extends Repository<User> {
|
||||||
@ -51,7 +52,7 @@ export class UserRepository extends Repository<User> {
|
|||||||
|
|
||||||
public packMany(
|
public packMany(
|
||||||
users: (User['id'] | User)[],
|
users: (User['id'] | User)[],
|
||||||
me?: User['id'] | User,
|
me?: User['id'] | User | null | undefined,
|
||||||
options?: {
|
options?: {
|
||||||
detail?: boolean,
|
detail?: boolean,
|
||||||
includeSecrets?: boolean,
|
includeSecrets?: boolean,
|
||||||
@ -63,7 +64,7 @@ export class UserRepository extends Repository<User> {
|
|||||||
|
|
||||||
public async pack(
|
public async pack(
|
||||||
src: User['id'] | User,
|
src: User['id'] | User,
|
||||||
me?: User['id'] | User,
|
me?: User['id'] | User | null | undefined,
|
||||||
options?: {
|
options?: {
|
||||||
detail?: boolean,
|
detail?: boolean,
|
||||||
includeSecrets?: boolean,
|
includeSecrets?: boolean,
|
||||||
@ -75,11 +76,12 @@ export class UserRepository extends Repository<User> {
|
|||||||
includeSecrets: false
|
includeSecrets: false
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const user = typeof src === 'object' ? src : await this.findOne(src);
|
const user = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
const meId = me ? typeof me === 'string' ? me : me.id : null;
|
const meId = me ? typeof me === 'string' ? me : me.id : null;
|
||||||
|
|
||||||
const relation = meId && (meId !== user.id) && opts.detail ? await this.getRelation(meId, user.id) : null;
|
const relation = meId && (meId !== user.id) && opts.detail ? await this.getRelation(meId, user.id) : null;
|
||||||
const pins = opts.detail ? await UserNotePinings.find({ userId: user.id }) : [];
|
const pins = opts.detail ? await UserNotePinings.find({ userId: user.id }) : [];
|
||||||
|
const profile = opts.detail ? await UserProfiles.findOne({ userId: user.id }).then(ensure) : null;
|
||||||
|
|
||||||
return await rap({
|
return await rap({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
@ -91,6 +93,9 @@ export class UserRepository extends Repository<User> {
|
|||||||
avatarColor: user.avatarColor,
|
avatarColor: user.avatarColor,
|
||||||
bannerColor: user.bannerColor,
|
bannerColor: user.bannerColor,
|
||||||
isAdmin: user.isAdmin,
|
isAdmin: user.isAdmin,
|
||||||
|
isBot: user.isBot,
|
||||||
|
isCat: user.isCat,
|
||||||
|
isVerified: user.isVerified,
|
||||||
|
|
||||||
// カスタム絵文字添付
|
// カスタム絵文字添付
|
||||||
emojis: user.emojis.length > 0 ? Emojis.find({
|
emojis: user.emojis.length > 0 ? Emojis.find({
|
||||||
@ -113,9 +118,12 @@ export class UserRepository extends Repository<User> {
|
|||||||
} : {}),
|
} : {}),
|
||||||
|
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
description: user.description,
|
url: profile!.url,
|
||||||
location: user.location,
|
createdAt: user.createdAt,
|
||||||
birthday: user.birthday,
|
updatedAt: user.updatedAt,
|
||||||
|
description: profile!.description,
|
||||||
|
location: profile!.location,
|
||||||
|
birthday: profile!.birthday,
|
||||||
followersCount: user.followersCount,
|
followersCount: user.followersCount,
|
||||||
followingCount: user.followingCount,
|
followingCount: user.followingCount,
|
||||||
notesCount: user.notesCount,
|
notesCount: user.notesCount,
|
||||||
@ -128,9 +136,9 @@ export class UserRepository extends Repository<User> {
|
|||||||
...(opts.detail && meId === user.id ? {
|
...(opts.detail && meId === user.id ? {
|
||||||
avatarId: user.avatarId,
|
avatarId: user.avatarId,
|
||||||
bannerId: user.bannerId,
|
bannerId: user.bannerId,
|
||||||
autoWatch: user.autoWatch,
|
autoWatch: profile!.autoWatch,
|
||||||
alwaysMarkNsfw: user.alwaysMarkNsfw,
|
alwaysMarkNsfw: profile!.alwaysMarkNsfw,
|
||||||
carefulBot: user.carefulBot,
|
carefulBot: profile!.carefulBot,
|
||||||
hasUnreadMessagingMessage: MessagingMessages.count({
|
hasUnreadMessagingMessage: MessagingMessages.count({
|
||||||
where: {
|
where: {
|
||||||
recipientId: user.id,
|
recipientId: user.id,
|
||||||
@ -150,6 +158,12 @@ export class UserRepository extends Repository<User> {
|
|||||||
}),
|
}),
|
||||||
} : {}),
|
} : {}),
|
||||||
|
|
||||||
|
...(opts.includeSecrets ? {
|
||||||
|
clientData: profile!.clientData,
|
||||||
|
email: profile!.email,
|
||||||
|
emailVerified: profile!.emailVerified,
|
||||||
|
} : {}),
|
||||||
|
|
||||||
...(relation ? {
|
...(relation ? {
|
||||||
isFollowing: relation.isFollowing,
|
isFollowing: relation.isFollowing,
|
||||||
isFollowed: relation.isFollowed,
|
isFollowed: relation.isFollowed,
|
||||||
@ -163,7 +177,7 @@ export class UserRepository extends Repository<User> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isLocalUser(user: User): user is ILocalUser {
|
public isLocalUser(user: User): user is ILocalUser {
|
||||||
return user.host === null;
|
return user.host == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isRemoteUser(user: User): user is IRemoteUser {
|
public isRemoteUser(user: User): user is IRemoteUser {
|
||||||
|
7
src/prelude/ensure.ts
Normal file
7
src/prelude/ensure.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function ensure<T>(x: T): NonNullable<T> {
|
||||||
|
if (x == null) {
|
||||||
|
throw 'ぬるぽ';
|
||||||
|
} else {
|
||||||
|
return x!;
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ import { queueLogger } from './logger';
|
|||||||
import { DriveFile } from '../models/entities/drive-file';
|
import { DriveFile } from '../models/entities/drive-file';
|
||||||
|
|
||||||
function initializeQueue(name: string) {
|
function initializeQueue(name: string) {
|
||||||
return new Queue(name, config.redis != null ? {
|
return new Queue(name, {
|
||||||
redis: {
|
redis: {
|
||||||
port: config.redis.port,
|
port: config.redis.port,
|
||||||
host: config.redis.host,
|
host: config.redis.host,
|
||||||
@ -20,7 +20,7 @@ function initializeQueue(name: string) {
|
|||||||
db: config.redis.db || 0,
|
db: config.redis.db || 0,
|
||||||
},
|
},
|
||||||
prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue'
|
prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue'
|
||||||
} : null);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deliverQueue = initializeQueue('deliver');
|
export const deliverQueue = initializeQueue('deliver');
|
||||||
|
@ -10,9 +10,11 @@ const logger = queueLogger.createSubLogger('delete-drive-files');
|
|||||||
export async function deleteDriveFiles(job: Bull.Job, done: any): Promise<void> {
|
export async function deleteDriveFiles(job: Bull.Job, done: any): Promise<void> {
|
||||||
logger.info(`Deleting drive files of ${job.data.user.id} ...`);
|
logger.info(`Deleting drive files of ${job.data.user.id} ...`);
|
||||||
|
|
||||||
const user = await Users.findOne({
|
const user = await Users.findOne(job.data.user.id);
|
||||||
id: job.data.user.id
|
if (user == null) {
|
||||||
});
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let deletedCount = 0;
|
let deletedCount = 0;
|
||||||
let ended = false;
|
let ended = false;
|
||||||
|
@ -14,9 +14,11 @@ const logger = queueLogger.createSubLogger('export-blocking');
|
|||||||
export async function exportBlocking(job: Bull.Job, done: any): Promise<void> {
|
export async function exportBlocking(job: Bull.Job, done: any): Promise<void> {
|
||||||
logger.info(`Exporting blocking of ${job.data.user.id} ...`);
|
logger.info(`Exporting blocking of ${job.data.user.id} ...`);
|
||||||
|
|
||||||
const user = await Users.findOne({
|
const user = await Users.findOne(job.data.user.id);
|
||||||
id: job.data.user.id
|
if (user == null) {
|
||||||
});
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create temp file
|
// Create temp file
|
||||||
const [path, cleanup] = await new Promise<[string, any]>((res, rej) => {
|
const [path, cleanup] = await new Promise<[string, any]>((res, rej) => {
|
||||||
@ -56,6 +58,10 @@ export async function exportBlocking(job: Bull.Job, done: any): Promise<void> {
|
|||||||
|
|
||||||
for (const block of blockings) {
|
for (const block of blockings) {
|
||||||
const u = await Users.findOne({ id: block.blockeeId });
|
const u = await Users.findOne({ id: block.blockeeId });
|
||||||
|
if (u == null) {
|
||||||
|
exportedCount++; continue;
|
||||||
|
}
|
||||||
|
|
||||||
const content = getFullApAccount(u.username, u.host);
|
const content = getFullApAccount(u.username, u.host);
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
stream.write(content + '\n', err => {
|
stream.write(content + '\n', err => {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user