forked from FoundKeyGang/FoundKey
Resolve conflicts
This commit is contained in:
parent
281b388e39
commit
bfc193d8cd
308 changed files with 3045 additions and 3200 deletions
|
@ -1,4 +1,3 @@
|
||||||
``` yaml
|
|
||||||
# サーバーのメンテナ情報
|
# サーバーのメンテナ情報
|
||||||
maintainer:
|
maintainer:
|
||||||
# メンテナの名前
|
# メンテナの名前
|
||||||
|
@ -56,5 +55,3 @@ twitter:
|
||||||
|
|
||||||
# インテグレーション用アプリのコンシューマーシークレット
|
# インテグレーション用アプリのコンシューマーシークレット
|
||||||
consumer_secret:
|
consumer_secret:
|
||||||
|
|
||||||
```
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
/.config
|
/.config/*
|
||||||
|
!/.config/example.yml
|
||||||
/.vscode
|
/.vscode
|
||||||
/node_modules
|
/node_modules
|
||||||
/build
|
/build
|
||||||
|
|
532
CHANGELOG.md
532
CHANGELOG.md
|
@ -1,532 +0,0 @@
|
||||||
ChangeLog (Release Notes)
|
|
||||||
=========================
|
|
||||||
主に notable な changes を書いていきます
|
|
||||||
|
|
||||||
3493 (2018/01/01)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3460 (2017/12/23)
|
|
||||||
-----------------
|
|
||||||
* 検索で複数のユーザーを指定できるように
|
|
||||||
* 検索でユーザーを除外できるように
|
|
||||||
* など
|
|
||||||
|
|
||||||
3451 (2017/12/22)
|
|
||||||
-----------------
|
|
||||||
* ミュート機能
|
|
||||||
|
|
||||||
3430 (2017/12/21)
|
|
||||||
-----------------
|
|
||||||
* oops
|
|
||||||
|
|
||||||
3428 (2017/12/21)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3426 (2017/12/21)
|
|
||||||
-----------------
|
|
||||||
* 検索にpoll追加
|
|
||||||
|
|
||||||
3424 (2017/12/21)
|
|
||||||
-----------------
|
|
||||||
* 検索にrepost追加
|
|
||||||
* など
|
|
||||||
|
|
||||||
3422 (2017/12/21)
|
|
||||||
-----------------
|
|
||||||
* 検索にfollow追加 #1023
|
|
||||||
|
|
||||||
3420 (2017/12/21)
|
|
||||||
-----------------
|
|
||||||
* 検索機能を大幅に強化
|
|
||||||
|
|
||||||
3415 (2017/12/19)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
3404 (2017/12/17)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3400 (2017/12/17)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3392 (2017/12/17)
|
|
||||||
-----------------
|
|
||||||
* ドキュメントなど
|
|
||||||
|
|
||||||
3390 (2017/12/16)
|
|
||||||
-----------------
|
|
||||||
* ドキュメントなど
|
|
||||||
|
|
||||||
3347 (2017/12/11)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3342 (2017/12/11)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3339 (2017/12/11)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3334 (2017/12/10)
|
|
||||||
-----------------
|
|
||||||
* いい感じにした
|
|
||||||
|
|
||||||
3322 (2017/12/10)
|
|
||||||
-----------------
|
|
||||||
* :art:
|
|
||||||
|
|
||||||
3320 (2017/12/10)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3310 (2017/12/09)
|
|
||||||
-----------------
|
|
||||||
* i18nなど
|
|
||||||
|
|
||||||
3308 (2017/12/09)
|
|
||||||
-----------------
|
|
||||||
* :art:
|
|
||||||
|
|
||||||
3294 (2017/12/09)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3292 (2017/12/09)
|
|
||||||
-----------------
|
|
||||||
* ユーザビリティの向上
|
|
||||||
|
|
||||||
3281 (2017/12/08)
|
|
||||||
-----------------
|
|
||||||
* 二段階認証の実装 (#967)
|
|
||||||
|
|
||||||
3278 (2017/12/08)
|
|
||||||
-----------------
|
|
||||||
* :v:
|
|
||||||
|
|
||||||
3272 (2017/12/08)
|
|
||||||
-----------------
|
|
||||||
* Fix bug
|
|
||||||
|
|
||||||
3268 (2017/12/08)
|
|
||||||
-----------------
|
|
||||||
* :v:
|
|
||||||
|
|
||||||
3263 (2017/12/08)
|
|
||||||
-----------------
|
|
||||||
* FontAwesome5に移行
|
|
||||||
|
|
||||||
3230 (2017/11/28)
|
|
||||||
-----------------
|
|
||||||
* :v:
|
|
||||||
|
|
||||||
3219 (2017/11/28)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3212 (2017/11/27)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3201 (2017/11/23)
|
|
||||||
-----------------
|
|
||||||
* Twitterログインを実装 (#939)
|
|
||||||
|
|
||||||
3196 (2017/11/23)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3194 (2017/11/23)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3191 (2017/11/23)
|
|
||||||
-----------------
|
|
||||||
* :v:
|
|
||||||
|
|
||||||
3188 (2017/11/22)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3180 (2017/11/21)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3177 (2017/11/21)
|
|
||||||
-----------------
|
|
||||||
* ServiceWorker support
|
|
||||||
* Misskeyを開いていないときでも通知を受け取れるように(Chromeのみ)
|
|
||||||
|
|
||||||
3165 (2017/11/20)
|
|
||||||
-----------------
|
|
||||||
* デスクトップ版でも通知バッジを表示 (#918)
|
|
||||||
* デザインの調整
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3155 (2017/11/20)
|
|
||||||
-----------------
|
|
||||||
* デスクトップ版でユーザーの投稿グラフを見れるように
|
|
||||||
|
|
||||||
3142 (2017/11/18)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3140 (2017/11/18)
|
|
||||||
-----------------
|
|
||||||
* ウィジェットをスクロールに追従させるように
|
|
||||||
|
|
||||||
3136 (2017/11/17)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
* 通信の最適化
|
|
||||||
|
|
||||||
3131 (2017/11/17)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
* 通信の最適化
|
|
||||||
|
|
||||||
3124 (2017/11/16)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3121 (2017/11/16)
|
|
||||||
-----------------
|
|
||||||
* ブロードキャストウィジェットの強化
|
|
||||||
* デザインのグリッチの修正
|
|
||||||
* 通信の最適化
|
|
||||||
|
|
||||||
3113 (2017/11/15)
|
|
||||||
-----------------
|
|
||||||
* アクティビティのレンダリングの問題の修正など
|
|
||||||
|
|
||||||
3110 (2017/11/15)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整など
|
|
||||||
|
|
||||||
3107 (2017/11/14)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
3104 (2017/11/14)
|
|
||||||
-----------------
|
|
||||||
* デスクトップ版ユーザーページのデザインの改良
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3099 (2017/11/14)
|
|
||||||
-----------------
|
|
||||||
* デスクトップ版ユーザーページの強化
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3093 (2017/11/14)
|
|
||||||
-----------------
|
|
||||||
* やった
|
|
||||||
|
|
||||||
3089 (2017/11/14)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
3069 (2017/11/14)
|
|
||||||
-----------------
|
|
||||||
* ドライブウィンドウもポップアウトできるように
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
3066 (2017/11/14)
|
|
||||||
-----------------
|
|
||||||
* メッセージウィジェット追加
|
|
||||||
* アクセスログウィジェット追加
|
|
||||||
|
|
||||||
3057 (2017/11/13)
|
|
||||||
-----------------
|
|
||||||
* グリッチ修正
|
|
||||||
|
|
||||||
3055 (2017/11/13)
|
|
||||||
-----------------
|
|
||||||
* メッセージのウィンドウのポップアウト (#911)
|
|
||||||
|
|
||||||
3050 (2017/11/13)
|
|
||||||
-----------------
|
|
||||||
* 通信の最適化
|
|
||||||
* これで例えばサーバー情報ウィジェットを5000兆個設置しても利用するコネクションは一つだけになりウィジェットを1つ設置したときと(ネットワーク的な)負荷は変わらなくなる
|
|
||||||
* デザインの調整
|
|
||||||
* ユーザビリティの向上
|
|
||||||
|
|
||||||
3040 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3038 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* 投稿フォームウィジェットの追加
|
|
||||||
* タイムライン上部にもウィジェットを配置できるように
|
|
||||||
|
|
||||||
3035 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* ウィジェットの強化
|
|
||||||
|
|
||||||
3033 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
3031 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* ウィジェットの強化
|
|
||||||
|
|
||||||
3028 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* ウィジェットの表示をコンパクトにできるように
|
|
||||||
|
|
||||||
3026 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
|
|
||||||
3024 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* いい感じにするなど
|
|
||||||
|
|
||||||
3020 (2017/11/12)
|
|
||||||
-----------------
|
|
||||||
* 通信の最適化
|
|
||||||
|
|
||||||
3017 (2017/11/11)
|
|
||||||
-----------------
|
|
||||||
* 誤字修正など
|
|
||||||
|
|
||||||
3012 (2017/11/11)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
3010 (2017/11/11)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
3008 (2017/11/11)
|
|
||||||
-----------------
|
|
||||||
* カレンダー(タイムマシン)ウィジェットの追加
|
|
||||||
|
|
||||||
3006 (2017/11/11)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
* など
|
|
||||||
|
|
||||||
2996 (2017/11/10)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
* など
|
|
||||||
|
|
||||||
2991 (2017/11/09)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2988 (2017/11/09)
|
|
||||||
-----------------
|
|
||||||
* チャンネルウィジェットを追加
|
|
||||||
|
|
||||||
2984 (2017/11/09)
|
|
||||||
-----------------
|
|
||||||
* スライドショーウィジェットを追加
|
|
||||||
|
|
||||||
2974 (2017/11/08)
|
|
||||||
-----------------
|
|
||||||
* ホームのカスタマイズを実装するなど
|
|
||||||
|
|
||||||
2971 (2017/11/08)
|
|
||||||
-----------------
|
|
||||||
* バグ修正
|
|
||||||
* デザインの調整
|
|
||||||
* i18n
|
|
||||||
|
|
||||||
2944 (2017/11/07)
|
|
||||||
-----------------
|
|
||||||
* パフォーマンスの向上
|
|
||||||
* GirdFSになるなどした
|
|
||||||
* 依存関係の更新
|
|
||||||
|
|
||||||
2807 (2017/11/02)
|
|
||||||
-----------------
|
|
||||||
* いい感じに
|
|
||||||
|
|
||||||
2805 (2017/11/02)
|
|
||||||
-----------------
|
|
||||||
* いい感じに
|
|
||||||
|
|
||||||
2801 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* チャンネルのWatch実装
|
|
||||||
|
|
||||||
2799 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* いい感じに
|
|
||||||
|
|
||||||
2795 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* いい感じに
|
|
||||||
|
|
||||||
2793 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
2783 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* なんか
|
|
||||||
|
|
||||||
2777 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* 細かいブラッシュアップ
|
|
||||||
|
|
||||||
2775 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* Fix: バグ修正
|
|
||||||
|
|
||||||
2769 (2017/11/01)
|
|
||||||
-----------------
|
|
||||||
* New: チャンネルシステム
|
|
||||||
|
|
||||||
2752 (2017/10/30)
|
|
||||||
-----------------
|
|
||||||
* New: 未読の通知がある場合アイコンを表示するように
|
|
||||||
|
|
||||||
2747 (2017/10/25)
|
|
||||||
-----------------
|
|
||||||
* Fix: 非ログイン状態ですべてのページが致命的な問題を発生させる (#89)
|
|
||||||
|
|
||||||
2742 (2017/10/25)
|
|
||||||
-----------------
|
|
||||||
* New: トラブルシューティングを実装するなど
|
|
||||||
|
|
||||||
2735 (2017/10/22)
|
|
||||||
-----------------
|
|
||||||
* New: モバイル版からでもクライアントバージョンを確認できるように
|
|
||||||
|
|
||||||
2732 (2017/10/22)
|
|
||||||
-----------------
|
|
||||||
* 依存関係の更新など
|
|
||||||
|
|
||||||
2584 (2017/09/08)
|
|
||||||
-----------------
|
|
||||||
* New: ユーザーページによく使うドメインを表示 (#771)
|
|
||||||
* New: よくリプライするユーザーをユーザーページに表示 (#770)
|
|
||||||
|
|
||||||
2566 (2017/09/07)
|
|
||||||
-----------------
|
|
||||||
* New: 投稿することの多いキーワードをユーザーページに表示する (#768)
|
|
||||||
* l10n
|
|
||||||
* デザインの修正
|
|
||||||
|
|
||||||
2544 (2017/09/06)
|
|
||||||
-----------------
|
|
||||||
* 投稿のカテゴリに関する実験的な実装
|
|
||||||
* l10n
|
|
||||||
* ユーザビリティの向上
|
|
||||||
|
|
||||||
2520 (2017/08/30)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2518 (2017/08/30)
|
|
||||||
-----------------
|
|
||||||
* Fix: モバイル版のタイムラインからリアクションやメニューを開けない
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2515 (2017/08/30)
|
|
||||||
-----------------
|
|
||||||
* New: 投稿のピン留め (#746)
|
|
||||||
* New: モバイル版のユーザーページに知り合いのフォロワーを表示するように
|
|
||||||
* New: ホームストリームにメッセージを流すことでlast_used_atを更新できるようにする (#745)
|
|
||||||
* その他細かな修正
|
|
||||||
|
|
||||||
2508 (2017/08/30)
|
|
||||||
-----------------
|
|
||||||
* New: モバイル版のユーザーページのアクティビティチャートを変更
|
|
||||||
* New: モバイル版のユーザーページに最終ログイン日時を表示するように
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2503 (2017/08/30)
|
|
||||||
-----------------
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2502 (2017/08/30)
|
|
||||||
-----------------
|
|
||||||
* デザインの修正・調整
|
|
||||||
|
|
||||||
2501 (2017/08/30)
|
|
||||||
-----------------
|
|
||||||
* New: モバイルのユーザーページを刷新
|
|
||||||
|
|
||||||
2498 (2017/08/29)
|
|
||||||
-----------------
|
|
||||||
* Fix: repostのborder-radiusが効いていない (#743)
|
|
||||||
* テーマカラーを赤に戻してみた
|
|
||||||
* ユーザビリティの向上
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2493-2 (2017/08/29)
|
|
||||||
-------------------
|
|
||||||
* デザインの修正
|
|
||||||
|
|
||||||
2493 (2017/08/29)
|
|
||||||
-----------------
|
|
||||||
* デザインの変更など
|
|
||||||
|
|
||||||
2491 (2017/08/29)
|
|
||||||
-----------------
|
|
||||||
* デザインの修正と調整
|
|
||||||
|
|
||||||
2489 (2017/08/29)
|
|
||||||
-----------------
|
|
||||||
* ユーザビリティの向上
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2487 (2017/08/29)
|
|
||||||
-----------------
|
|
||||||
* New: パスワードを変更する際に新しいパスワードを二度入力させる (#739)
|
|
||||||
* New: ドナーを表示する (#738)
|
|
||||||
* Fix: 投稿のリンクが機能していない問題を修正
|
|
||||||
* Fix: アカウント作成フォームのユーザーページURLプレビューが正しく機能していなかった問題を修正
|
|
||||||
* l10n
|
|
||||||
* デザインの調整
|
|
||||||
|
|
||||||
2470 (2017/08/29)
|
|
||||||
-----------------
|
|
||||||
* New: トークンを再生成できるように (#497)
|
|
||||||
* New: パスワードを変更する機能 (#364)
|
|
||||||
|
|
||||||
2461 (2017/08/28)
|
|
||||||
-----------------
|
|
||||||
* Fix: モバイル版からアバターとバナーの設定を行えなかった問題を修正
|
|
||||||
* デザインの修正
|
|
||||||
|
|
||||||
2458 (2017/08/28)
|
|
||||||
-----------------
|
|
||||||
* New: モバイル版からプロフィールを設定できるように
|
|
||||||
* New: モバイル版からサインアウトを行えるように
|
|
||||||
* New: 投稿ページに次の投稿/前の投稿リンクを作成 (#734)
|
|
||||||
* New: タイムラインの投稿をダブルクリックすることで詳細な情報が見れるように
|
|
||||||
* Fix: モバイル版でおすすめユーザーをフォローしてもタイムラインが更新されない (#736)
|
|
||||||
* Fix: モバイル版で設定にアクセスできない
|
|
||||||
* デザインの調整
|
|
||||||
* 依存関係の更新
|
|
||||||
|
|
||||||
2380
|
|
||||||
----
|
|
||||||
アプリケーションが作れない問題を修正
|
|
||||||
|
|
||||||
2367
|
|
||||||
----
|
|
||||||
Statsのユーザー数グラフに「アカウントが作成された**回数**」(その日時点での「アカウント数」**ではなく**)グラフも併記するようにした
|
|
||||||
|
|
||||||
2364
|
|
||||||
----
|
|
||||||
デザインの微調整
|
|
||||||
|
|
||||||
2361
|
|
||||||
----
|
|
||||||
Statsを実装するなど
|
|
||||||
|
|
||||||
2357
|
|
||||||
----
|
|
||||||
Statusを実装するなど
|
|
674
LICENSE
674
LICENSE
|
@ -1,21 +1,661 @@
|
||||||
The MIT License (MIT)
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (c) 2014-2018 syuilo
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Preamble
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
copies or substantial portions of the Software.
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
The licenses for most software and other practical works are designed
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
share and change all versions of a program--to make sure it remains free
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
software for all its users.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
Developers that use our General Public Licenses protect your rights
|
||||||
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
|
you this License which gives you legal permission to copy, distribute
|
||||||
|
and/or modify the software.
|
||||||
|
|
||||||
|
A secondary benefit of defending all users' freedom is that
|
||||||
|
improvements made in alternate versions of the program, if they
|
||||||
|
receive widespread use, become available for other developers to
|
||||||
|
incorporate. Many developers of free software are heartened and
|
||||||
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
|
The GNU Affero General Public License is designed specifically to
|
||||||
|
ensure that, in such cases, the modified source code becomes available
|
||||||
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
|
An older license, called the Affero General Public License and
|
||||||
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
|
this license.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the work with which it is combined will remain governed by version
|
||||||
|
3 of the GNU General Public License.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If your software can interact with users remotely through a computer
|
||||||
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
|
interface could display a "Source" link that leads users to an archive
|
||||||
|
of the code. There are many ways you could offer source, and different
|
||||||
|
solutions will be better for different programs; see section 13 for the
|
||||||
|
specific requirements.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
661
LICENSE_AGPL-3.0
661
LICENSE_AGPL-3.0
|
@ -1,661 +0,0 @@
|
||||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 19 November 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU Affero General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works, specifically designed to ensure
|
|
||||||
cooperation with the community in the case of network server software.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
our General Public Licenses are intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
Developers that use our General Public Licenses protect your rights
|
|
||||||
with two steps: (1) assert copyright on the software, and (2) offer
|
|
||||||
you this License which gives you legal permission to copy, distribute
|
|
||||||
and/or modify the software.
|
|
||||||
|
|
||||||
A secondary benefit of defending all users' freedom is that
|
|
||||||
improvements made in alternate versions of the program, if they
|
|
||||||
receive widespread use, become available for other developers to
|
|
||||||
incorporate. Many developers of free software are heartened and
|
|
||||||
encouraged by the resulting cooperation. However, in the case of
|
|
||||||
software used on network servers, this result may fail to come about.
|
|
||||||
The GNU General Public License permits making a modified version and
|
|
||||||
letting the public access it on a server without ever releasing its
|
|
||||||
source code to the public.
|
|
||||||
|
|
||||||
The GNU Affero General Public License is designed specifically to
|
|
||||||
ensure that, in such cases, the modified source code becomes available
|
|
||||||
to the community. It requires the operator of a network server to
|
|
||||||
provide the source code of the modified version running there to the
|
|
||||||
users of that server. Therefore, public use of a modified version, on
|
|
||||||
a publicly accessible server, gives the public access to the source
|
|
||||||
code of the modified version.
|
|
||||||
|
|
||||||
An older license, called the Affero General Public License and
|
|
||||||
published by Affero, was designed to accomplish similar goals. This is
|
|
||||||
a different license, not a version of the Affero GPL, but Affero has
|
|
||||||
released a new version of the Affero GPL which permits relicensing under
|
|
||||||
this license.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, if you modify the
|
|
||||||
Program, your modified version must prominently offer all users
|
|
||||||
interacting with it remotely through a computer network (if your version
|
|
||||||
supports such interaction) an opportunity to receive the Corresponding
|
|
||||||
Source of your version by providing access to the Corresponding Source
|
|
||||||
from a network server at no charge, through some standard or customary
|
|
||||||
means of facilitating copying of software. This Corresponding Source
|
|
||||||
shall include the Corresponding Source for any work covered by version 3
|
|
||||||
of the GNU General Public License that is incorporated pursuant to the
|
|
||||||
following paragraph.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the work with which it is combined will remain governed by version
|
|
||||||
3 of the GNU General Public License.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU Affero General Public License from time to time. Such new versions
|
|
||||||
will be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU Affero General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU Affero General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU Affero General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If your software can interact with users remotely through a computer
|
|
||||||
network, you should also make sure that it provides a way for users to
|
|
||||||
get its source. For example, if your program is a web application, its
|
|
||||||
interface could display a "Source" link that leads users to an archive
|
|
||||||
of the code. There are many ways you could offer source, and different
|
|
||||||
solutions will be better for different programs; see section 13 for the
|
|
||||||
specific requirements.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
55
README.md
55
README.md
|
@ -1,4 +1,6 @@
|
||||||
![Misskey](./assets/title.png)
|
<img src="https://github.com/syuilo/misskey/blob/b3f42e62af698a67c2250533c437569559f1fdf9/src/himasaku/resources/himasaku.png?raw=true" align="right" width="320px"/>
|
||||||
|
|
||||||
|
Misskey
|
||||||
================================================================
|
================================================================
|
||||||
|
|
||||||
[![][travis-badge]][travis-link]
|
[![][travis-badge]][travis-link]
|
||||||
|
@ -7,57 +9,46 @@
|
||||||
[![][sakurako-badge]][himasaku]
|
[![][sakurako-badge]][himasaku]
|
||||||
[![][agpl-3.0-badge]][AGPL-3.0]
|
[![][agpl-3.0-badge]][AGPL-3.0]
|
||||||
|
|
||||||
[Misskey](https://misskey.xyz) is a completely open source,
|
> Lead Maintainer: [syuilo][syuilo-link]
|
||||||
|
|
||||||
|
**[Misskey](https://misskey.xyz)** is a completely open source,
|
||||||
ultimately sophisticated new type of mini-blog based SNS.
|
ultimately sophisticated new type of mini-blog based SNS.
|
||||||
|
|
||||||
![ss](./assets/ss.jpg)
|
:sparkles: Features
|
||||||
|
|
||||||
Key features
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
* Automatically updated timeline
|
* Automatically updated timeline
|
||||||
* Private messages
|
* Private messages
|
||||||
* Two-Factor Authentication support
|
* Two-Factor Authentication support
|
||||||
* ServiceWorker support
|
* ServiceWorker support
|
||||||
* Web API for third-party applications
|
* Web API for third-party applications
|
||||||
* No ads
|
* ActivityPub compatible
|
||||||
|
|
||||||
and more! You can touch with your own eyes at https://misskey.xyz/.
|
and more! You can touch with your own eyes at https://misskey.xyz/.
|
||||||
|
|
||||||
Setup and Installation
|
:package: Setup and Installation
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
If you want to run your own instance of Misskey,
|
If you want to run your own instance of Misskey,
|
||||||
please see [Setup and installation guide](./docs/setup.en.md).
|
please see [Setup and installation guide](./docs/setup.en.md).
|
||||||
|
|
||||||
Contribution
|
:yen: Donation
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Please see [Contribution guide](./CONTRIBUTING.md).
|
If you want to donate to Misskey, please see [this](./docs/donate.ja.md).
|
||||||
|
|
||||||
Release Notes
|
[List of all donors](./DONORS.md)
|
||||||
|
|
||||||
|
:mortar_board: Notable contributors
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Please see [ChangeLog](./CHANGELOG.md).
|
| ![syuilo][syuilo-icon] | ![Morisawa Aya][ayamorisawa-icon] | ![otofune][otofune-icon] | ![akihikodaki][akihikodaki-icon] | ![rinsuki][rinsuki-icon] |
|
||||||
|
|:-:|:-:|:-:|:-:|:-:|
|
||||||
Sponsors & Backers
|
| [syuilo][syuilo-link]<br>Owner | [Aya Morisawa][ayamorisawa-link]<br>Collaborator | [otofune][otofune-link]<br>Collaborator | [akihikodaki][akihikodaki-link] | [rinsuki][rinsuki-link] |
|
||||||
----------------------------------------------------------------
|
|
||||||
Misskey has no 100+ GitHub stars currently. However, a donation is always welcome!
|
|
||||||
If you want to donate to Misskey, please get in touch with [@syuilo][syuilo-link].
|
|
||||||
|
|
||||||
**Note:** When you donate to Misskey, your name will be listed in [donors](./DONORS.md).
|
|
||||||
|
|
||||||
Collaborators
|
|
||||||
----------------------------------------------------------------
|
|
||||||
| ![syuilo][syuilo-icon] | ![Morisawa Aya][ayamorisawa-icon] | ![otofune][otofune-icon] |
|
|
||||||
|------------------------|-----------------------------------|---------------------------------|
|
|
||||||
| [syuilo][syuilo-link] | [Aya Morisawa][ayamorisawa-link] | [otofune][otofune-link] |
|
|
||||||
|
|
||||||
[List of all contributors](https://github.com/syuilo/misskey/graphs/contributors)
|
[List of all contributors](https://github.com/syuilo/misskey/graphs/contributors)
|
||||||
|
|
||||||
Copyright
|
:four_leaf_clover: Copyright
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Misskey is an open-source software licensed under [The MIT License](LICENSE).
|
> Copyright (c) 2014-2018 syuilo
|
||||||
|
|
||||||
The portions of Misskey contributed by Akihiko Odaki <nekomanma@pixiv.co.jp> is
|
Misskey is an open-source software licensed under [GNU AGPLv3](LICENSE).
|
||||||
licensed under GNU Affero General Public License (only version 3.0 of the
|
|
||||||
license is applied.) See Git log to identify them.
|
|
||||||
|
|
||||||
[agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.en.html
|
[agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
[agpl-3.0-badge]: https://img.shields.io/badge/license-AGPL--3.0-444444.svg?style=flat-square
|
[agpl-3.0-badge]: https://img.shields.io/badge/license-AGPL--3.0-444444.svg?style=flat-square
|
||||||
|
@ -69,10 +60,14 @@ license is applied.) See Git log to identify them.
|
||||||
[himawari-badge]: https://img.shields.io/badge/%E5%8F%A4%E8%B0%B7-%E5%90%91%E6%97%A5%E8%91%B5-1684c5.svg?style=flat-square
|
[himawari-badge]: https://img.shields.io/badge/%E5%8F%A4%E8%B0%B7-%E5%90%91%E6%97%A5%E8%91%B5-1684c5.svg?style=flat-square
|
||||||
[sakurako-badge]: https://img.shields.io/badge/%E5%A4%A7%E5%AE%A4-%E6%AB%BB%E5%AD%90-efb02a.svg?style=flat-square
|
[sakurako-badge]: https://img.shields.io/badge/%E5%A4%A7%E5%AE%A4-%E6%AB%BB%E5%AD%90-efb02a.svg?style=flat-square
|
||||||
|
|
||||||
<!-- Collaborators Info -->
|
<!-- Contributors Info -->
|
||||||
[syuilo-link]: https://syuilo.com
|
[syuilo-link]: https://syuilo.com
|
||||||
[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70
|
[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70
|
||||||
[ayamorisawa-link]: https://github.com/ayamorisawa
|
[ayamorisawa-link]: https://github.com/ayamorisawa
|
||||||
[ayamorisawa-icon]: https://avatars0.githubusercontent.com/u/10798641?v=3&s=70
|
[ayamorisawa-icon]: https://avatars0.githubusercontent.com/u/10798641?v=3&s=70
|
||||||
[otofune-link]: https://github.com/otofune
|
[otofune-link]: https://github.com/otofune
|
||||||
[otofune-icon]: https://avatars0.githubusercontent.com/u/15062473?v=3&s=70
|
[otofune-icon]: https://avatars0.githubusercontent.com/u/15062473?v=3&s=70
|
||||||
|
[akihikodaki-link]: https://github.com/akihikodaki
|
||||||
|
[akihikodaki-icon]: https://avatars2.githubusercontent.com/u/17036990?s=70&v=4
|
||||||
|
[rinsuki-link]: https://github.com/rinsuki
|
||||||
|
[rinsuki-icon]: https://avatars0.githubusercontent.com/u/6533808?s=70&v=4
|
||||||
|
|
|
@ -14,7 +14,7 @@ RUN pacman -S --noconfirm pacman
|
||||||
RUN pacman-db-upgrade
|
RUN pacman-db-upgrade
|
||||||
RUN pacman -S --noconfirm archlinux-keyring
|
RUN pacman -S --noconfirm archlinux-keyring
|
||||||
RUN pacman -Syyu --noconfirm
|
RUN pacman -Syyu --noconfirm
|
||||||
RUN pacman -S --noconfirm git nodejs npm mongodb redis graphicsmagick
|
RUN pacman -S --noconfirm git nodejs npm mongodb redis imagemagick
|
||||||
|
|
||||||
COPY misskey.sh /root/misskey.sh
|
COPY misskey.sh /root/misskey.sh
|
||||||
RUN chmod u+x /root/misskey.sh
|
RUN chmod u+x /root/misskey.sh
|
||||||
|
|
|
@ -37,9 +37,9 @@ Please install and setup these softwares:
|
||||||
|
|
||||||
*3.* Prepare configuration
|
*3.* Prepare configuration
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
First, you need to create a `.config` directory in the directory that
|
1. Copy `example.yml` of `.config` directory
|
||||||
Misskey installed. And then you need to create a `default.yml` file in
|
2. Rename it to `default.yml`
|
||||||
the directory. The template of configuration is available [here](./config.md).
|
3. Edit it
|
||||||
|
|
||||||
*4.* Install and build Misskey
|
*4.* Install and build Misskey
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -37,9 +37,9 @@ web-push generate-vapid-keys
|
||||||
|
|
||||||
*3.* 設定ファイルを用意する
|
*3.* 設定ファイルを用意する
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Misskeyをインストールしたディレクトリに、`.config`というディレクトリを作成し、
|
1. `.config`ディレクトリ内の`example.yml`をコピー
|
||||||
その中に`default.yml`という名前で設定ファイルを作ってください。
|
2. `default.yml`にリネーム
|
||||||
設定ファイルの下書きは[ここ](./config.md)にありますので、コピペしてご利用ください。
|
3. 編集する
|
||||||
|
|
||||||
*4.* Misskeyのインストール(とビルド)
|
*4.* Misskeyのインストール(とビルド)
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -125,7 +125,6 @@ gulp.task('build:client:script', () =>
|
||||||
.pipe(replace('VERSION', JSON.stringify(version)))
|
.pipe(replace('VERSION', JSON.stringify(version)))
|
||||||
.pipe(replace('API', JSON.stringify(config.api_url)))
|
.pipe(replace('API', JSON.stringify(config.api_url)))
|
||||||
.pipe(replace('ENV', JSON.stringify(env)))
|
.pipe(replace('ENV', JSON.stringify(env)))
|
||||||
.pipe(replace('HOST', JSON.stringify(config.host)))
|
|
||||||
.pipe(isProduction ? uglify({
|
.pipe(isProduction ? uglify({
|
||||||
toplevel: true
|
toplevel: true
|
||||||
} as any) : gutil.noop())
|
} as any) : gutil.noop())
|
||||||
|
|
|
@ -147,7 +147,7 @@ common:
|
||||||
available: "利用できます"
|
available: "利用できます"
|
||||||
unavailable: "既に利用されています"
|
unavailable: "既に利用されています"
|
||||||
error: "通信エラー"
|
error: "通信エラー"
|
||||||
invalid-format: "a~z、A~Z、0~9、-(ハイフン)が使えます"
|
invalid-format: "a~z、A~Z、0~9、_が使えます"
|
||||||
too-short: "3文字以上でお願いします!"
|
too-short: "3文字以上でお願いします!"
|
||||||
too-long: "20文字以内でお願いします"
|
too-long: "20文字以内でお願いします"
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
|
|
|
@ -109,7 +109,6 @@ async function workerMain(opt) {
|
||||||
*/
|
*/
|
||||||
async function init(): Promise<Config> {
|
async function init(): Promise<Config> {
|
||||||
Logger.info('Welcome to Misskey!');
|
Logger.info('Welcome to Misskey!');
|
||||||
Logger.info(chalk.bold('Misskey <aoi>'));
|
|
||||||
Logger.info('Initializing...');
|
Logger.info('Initializing...');
|
||||||
|
|
||||||
EnvironmentInfo.show();
|
EnvironmentInfo.show();
|
||||||
|
|
|
@ -55,10 +55,10 @@ export default (req: express.Request) => new Promise<IAuthContext>(async (resolv
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = await App
|
const app = await App
|
||||||
.findOne({ _id: accessToken.app_id });
|
.findOne({ _id: accessToken.appId });
|
||||||
|
|
||||||
const user = await User
|
const user = await User
|
||||||
.findOne({ _id: accessToken.user_id });
|
.findOne({ _id: accessToken.userId });
|
||||||
|
|
||||||
return resolve({
|
return resolve({
|
||||||
app: app,
|
app: app,
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default class BotCore extends EventEmitter {
|
||||||
return await this.context.q(query);
|
return await this.context.q(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/^@[a-zA-Z0-9-]+$/.test(query)) {
|
if (/^@[a-zA-Z0-9_]+$/.test(query)) {
|
||||||
return await this.showUserCommand(query);
|
return await this.showUserCommand(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ class SigninContext extends Context {
|
||||||
if (this.temporaryUser == null) {
|
if (this.temporaryUser == null) {
|
||||||
// Fetch user
|
// Fetch user
|
||||||
const user: IUser = await User.findOne({
|
const user: IUser = await User.findOne({
|
||||||
username_lower: query.toLowerCase(),
|
usernameLower: query.toLowerCase(),
|
||||||
host: null
|
host: null
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
|
@ -297,7 +297,7 @@ class TlContext extends Context {
|
||||||
private async getTl() {
|
private async getTl() {
|
||||||
const tl = await require('../endpoints/posts/timeline')({
|
const tl = await require('../endpoints/posts/timeline')({
|
||||||
limit: 5,
|
limit: 5,
|
||||||
until_id: this.next ? this.next : undefined
|
untilId: this.next ? this.next : undefined
|
||||||
}, this.bot.user);
|
}, this.bot.user);
|
||||||
|
|
||||||
if (tl.length > 0) {
|
if (tl.length > 0) {
|
||||||
|
@ -349,7 +349,7 @@ class NotificationsContext extends Context {
|
||||||
private async getNotifications() {
|
private async getNotifications() {
|
||||||
const notifications = await require('../endpoints/i/notifications')({
|
const notifications = await require('../endpoints/i/notifications')({
|
||||||
limit: 5,
|
limit: 5,
|
||||||
until_id: this.next ? this.next : undefined
|
untilId: this.next ? this.next : undefined
|
||||||
}, this.bot.user);
|
}, this.bot.user);
|
||||||
|
|
||||||
if (notifications.length > 0) {
|
if (notifications.length > 0) {
|
||||||
|
|
|
@ -115,7 +115,7 @@ class LineBot extends BotCore {
|
||||||
actions.push({
|
actions.push({
|
||||||
type: 'uri',
|
type: 'uri',
|
||||||
label: 'Twitterアカウントを見る',
|
label: 'Twitterアカウントを見る',
|
||||||
uri: `https://twitter.com/${user.account.twitter.screen_name}`
|
uri: `https://twitter.com/${user.account.twitter.screenName}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ class LineBot extends BotCore {
|
||||||
altText: await super.showUserCommand(q),
|
altText: await super.showUserCommand(q),
|
||||||
template: {
|
template: {
|
||||||
type: 'buttons',
|
type: 'buttons',
|
||||||
thumbnailImageUrl: `${user.avatar_url}?thumbnail&size=1024`,
|
thumbnailImageUrl: `${user.avatarUrl}?thumbnail&size=1024`,
|
||||||
title: `${user.name} (@${acct})`,
|
title: `${user.name} (@${acct})`,
|
||||||
text: user.description || '(no description)',
|
text: user.description || '(no description)',
|
||||||
actions: actions
|
actions: actions
|
||||||
|
@ -142,7 +142,7 @@ class LineBot extends BotCore {
|
||||||
|
|
||||||
public async showUserTimelinePostback(userId: string) {
|
public async showUserTimelinePostback(userId: string) {
|
||||||
const tl = await require('../../endpoints/users/posts')({
|
const tl = await require('../../endpoints/users/posts')({
|
||||||
user_id: userId,
|
userId: userId,
|
||||||
limit: 5
|
limit: 5
|
||||||
}, this.user);
|
}, this.user);
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ module.exports = async (app: express.Application) => {
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
host: null,
|
host: null,
|
||||||
'account.line': {
|
'account.line': {
|
||||||
user_id: sourceId
|
userId: sourceId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ module.exports = async (app: express.Application) => {
|
||||||
User.update(user._id, {
|
User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.line': {
|
'account.line': {
|
||||||
user_id: sourceId
|
userId: sourceId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -194,7 +194,7 @@ module.exports = async (app: express.Application) => {
|
||||||
User.update(user._id, {
|
User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.line': {
|
'account.line': {
|
||||||
user_id: null
|
userId: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -100,7 +100,7 @@ const addFile = async (
|
||||||
// Check if there is a file with the same hash
|
// Check if there is a file with the same hash
|
||||||
const much = await DriveFile.findOne({
|
const much = await DriveFile.findOne({
|
||||||
md5: hash,
|
md5: hash,
|
||||||
'metadata.user_id': user._id
|
'metadata.userId': user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (much !== null) {
|
if (much !== null) {
|
||||||
|
@ -172,7 +172,7 @@ const addFile = async (
|
||||||
}
|
}
|
||||||
const driveFolder = await DriveFolder.findOne({
|
const driveFolder = await DriveFolder.findOne({
|
||||||
_id: folderId,
|
_id: folderId,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
if (!driveFolder) {
|
if (!driveFolder) {
|
||||||
throw 'folder-not-found';
|
throw 'folder-not-found';
|
||||||
|
@ -184,7 +184,7 @@ const addFile = async (
|
||||||
// Calculate drive usage
|
// Calculate drive usage
|
||||||
const usage = await DriveFile
|
const usage = await DriveFile
|
||||||
.aggregate([{
|
.aggregate([{
|
||||||
$match: { 'metadata.user_id': user._id }
|
$match: { 'metadata.userId': user._id }
|
||||||
}, {
|
}, {
|
||||||
$project: {
|
$project: {
|
||||||
length: true
|
length: true
|
||||||
|
@ -205,7 +205,7 @@ const addFile = async (
|
||||||
log(`drive usage is ${usage}`);
|
log(`drive usage is ${usage}`);
|
||||||
|
|
||||||
// If usage limit exceeded
|
// If usage limit exceeded
|
||||||
if (usage + size > user.drive_capacity) {
|
if (usage + size > user.driveCapacity) {
|
||||||
throw 'no-free-space';
|
throw 'no-free-space';
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
@ -221,12 +221,12 @@ const addFile = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (averageColor) {
|
if (averageColor) {
|
||||||
properties['average_color'] = averageColor;
|
properties['avgColor'] = averageColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return addToGridFS(detectedName, readable, mime, {
|
return addToGridFS(detectedName, readable, mime, {
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
folder_id: folder !== null ? folder._id : null,
|
folderId: folder !== null ? folder._id : null,
|
||||||
comment: comment,
|
comment: comment,
|
||||||
properties: properties
|
properties: properties
|
||||||
});
|
});
|
||||||
|
@ -297,7 +297,7 @@ export default (user: any, file: string | stream.Readable, ...args) => new Promi
|
||||||
id: file._id.toString(),
|
id: file._id.toString(),
|
||||||
body: {
|
body: {
|
||||||
name: file.name,
|
name: file.name,
|
||||||
user_id: user._id.toString()
|
userId: user._id.toString()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,17 @@ export default async (me: mongodb.ObjectID, includeMe: boolean = true) => {
|
||||||
// SELECT followee
|
// SELECT followee
|
||||||
const myfollowing = await Following
|
const myfollowing = await Following
|
||||||
.find({
|
.find({
|
||||||
follower_id: me,
|
followerId: me,
|
||||||
// 削除されたドキュメントは除く
|
// 削除されたドキュメントは除く
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
followee_id: true
|
followeeId: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ID list of other users who the I follows
|
// ID list of other users who the I follows
|
||||||
const myfollowingIds = myfollowing.map(follow => follow.followee_id);
|
const myfollowingIds = myfollowing.map(follow => follow.followeeId);
|
||||||
|
|
||||||
if (includeMe) {
|
if (includeMe) {
|
||||||
myfollowingIds.push(me);
|
myfollowingIds.push(me);
|
||||||
|
|
|
@ -16,11 +16,11 @@ export default (
|
||||||
|
|
||||||
// Create notification
|
// Create notification
|
||||||
const notification = await Notification.insert(Object.assign({
|
const notification = await Notification.insert(Object.assign({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
notifiee_id: notifiee,
|
notifieeId: notifiee,
|
||||||
notifier_id: notifier,
|
notifierId: notifier,
|
||||||
type: type,
|
type: type,
|
||||||
is_read: false
|
isRead: false
|
||||||
}, content));
|
}, content));
|
||||||
|
|
||||||
resolve(notification);
|
resolve(notification);
|
||||||
|
@ -31,14 +31,14 @@ export default (
|
||||||
|
|
||||||
// 3秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
// 3秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const fresh = await Notification.findOne({ _id: notification._id }, { is_read: true });
|
const fresh = await Notification.findOne({ _id: notification._id }, { isRead: true });
|
||||||
if (!fresh.is_read) {
|
if (!fresh.isRead) {
|
||||||
//#region ただしミュートしているユーザーからの通知なら無視
|
//#region ただしミュートしているユーザーからの通知なら無視
|
||||||
const mute = await Mute.find({
|
const mute = await Mute.find({
|
||||||
muter_id: notifiee,
|
muterId: notifiee,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
const mutedUserIds = mute.map(m => m.mutee_id.toString());
|
const mutedUserIds = mute.map(m => m.muteeId.toString());
|
||||||
if (mutedUserIds.indexOf(notifier.toString()) != -1) {
|
if (mutedUserIds.indexOf(notifier.toString()) != -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default async function(userId: mongo.ObjectID | string, type, body?) {
|
||||||
|
|
||||||
// Fetch
|
// Fetch
|
||||||
const subscriptions = await Subscription.find({
|
const subscriptions = await Subscription.find({
|
||||||
user_id: userId
|
userId: userId
|
||||||
});
|
});
|
||||||
|
|
||||||
subscriptions.forEach(subscription => {
|
subscriptions.forEach(subscription => {
|
||||||
|
@ -41,7 +41,7 @@ export default async function(userId: mongo.ObjectID | string, type, body?) {
|
||||||
|
|
||||||
if (err.statusCode == 410) {
|
if (err.statusCode == 410) {
|
||||||
Subscription.remove({
|
Subscription.remove({
|
||||||
user_id: userId,
|
userId: userId,
|
||||||
endpoint: subscription.endpoint,
|
endpoint: subscription.endpoint,
|
||||||
auth: subscription.auth,
|
auth: subscription.auth,
|
||||||
publickey: subscription.publickey
|
publickey: subscription.publickey
|
||||||
|
|
|
@ -37,12 +37,12 @@ export default (
|
||||||
// Update documents
|
// Update documents
|
||||||
await Message.update({
|
await Message.update({
|
||||||
_id: { $in: ids },
|
_id: { $in: ids },
|
||||||
user_id: otherpartyId,
|
userId: otherpartyId,
|
||||||
recipient_id: userId,
|
recipientId: userId,
|
||||||
is_read: false
|
isRead: false
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
is_read: true
|
isRead: true
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
multi: true
|
multi: true
|
||||||
|
@ -55,8 +55,8 @@ export default (
|
||||||
// Calc count of my unread messages
|
// Calc count of my unread messages
|
||||||
const count = await Message
|
const count = await Message
|
||||||
.count({
|
.count({
|
||||||
recipient_id: userId,
|
recipientId: userId,
|
||||||
is_read: false
|
isRead: false
|
||||||
});
|
});
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
|
|
|
@ -29,10 +29,10 @@ export default (
|
||||||
// Update documents
|
// Update documents
|
||||||
await Notification.update({
|
await Notification.update({
|
||||||
_id: { $in: ids },
|
_id: { $in: ids },
|
||||||
is_read: false
|
isRead: false
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
is_read: true
|
isRead: true
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
multi: true
|
multi: true
|
||||||
|
@ -41,8 +41,8 @@ export default (
|
||||||
// Calc count of my unread notifications
|
// Calc count of my unread notifications
|
||||||
const count = await Notification
|
const count = await Notification
|
||||||
.count({
|
.count({
|
||||||
notifiee_id: userId,
|
notifieeId: userId,
|
||||||
is_read: false
|
isRead: false
|
||||||
});
|
});
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
|
|
|
@ -3,15 +3,15 @@ import Watching from '../models/post-watching';
|
||||||
|
|
||||||
export default async (me: mongodb.ObjectID, post: object) => {
|
export default async (me: mongodb.ObjectID, post: object) => {
|
||||||
// 自分の投稿はwatchできない
|
// 自分の投稿はwatchできない
|
||||||
if (me.equals((post as any).user_id)) {
|
if (me.equals((post as any).userId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if watching now
|
// if watching now
|
||||||
const exist = await Watching.findOne({
|
const exist = await Watching.findOne({
|
||||||
post_id: (post as any)._id,
|
postId: (post as any)._id,
|
||||||
user_id: me,
|
userId: me,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist !== null) {
|
if (exist !== null) {
|
||||||
|
@ -19,8 +19,8 @@ export default async (me: mongodb.ObjectID, post: object) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
await Watching.insert({
|
await Watching.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
post_id: (post as any)._id,
|
postId: (post as any)._id,
|
||||||
user_id: me
|
userId: me
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -289,7 +289,7 @@ const endpoints: Endpoint[] = [
|
||||||
kind: 'notification-write'
|
kind: 'notification-write'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'notifications/mark_as_read_all',
|
name: 'notifications/markAsRead_all',
|
||||||
withCredential: true,
|
withCredential: true,
|
||||||
kind: 'notification-write'
|
kind: 'notification-write'
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,23 +18,23 @@ module.exports = params => new Promise(async (res, rej) => {
|
||||||
const datas = await Post
|
const datas = await Post
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $project: {
|
{ $project: {
|
||||||
repost_id: '$repost_id',
|
repostId: '$repostId',
|
||||||
reply_id: '$reply_id',
|
replyId: '$replyId',
|
||||||
created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
|
createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST
|
||||||
}},
|
}},
|
||||||
{ $project: {
|
{ $project: {
|
||||||
date: {
|
date: {
|
||||||
year: { $year: '$created_at' },
|
year: { $year: '$createdAt' },
|
||||||
month: { $month: '$created_at' },
|
month: { $month: '$createdAt' },
|
||||||
day: { $dayOfMonth: '$created_at' }
|
day: { $dayOfMonth: '$createdAt' }
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
$cond: {
|
$cond: {
|
||||||
if: { $ne: ['$repost_id', null] },
|
if: { $ne: ['$repostId', null] },
|
||||||
then: 'repost',
|
then: 'repost',
|
||||||
else: {
|
else: {
|
||||||
$cond: {
|
$cond: {
|
||||||
if: { $ne: ['$reply_id', null] },
|
if: { $ne: ['$replyId', null] },
|
||||||
then: 'reply',
|
then: 'reply',
|
||||||
else: 'post'
|
else: 'post'
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Reaction from '../../../models/post-reaction';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Lookup post
|
// Lookup post
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
|
@ -27,15 +27,15 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const datas = await Reaction
|
const datas = await Reaction
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $match: { post_id: post._id } },
|
{ $match: { postId: post._id } },
|
||||||
{ $project: {
|
{ $project: {
|
||||||
created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
|
createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST
|
||||||
}},
|
}},
|
||||||
{ $project: {
|
{ $project: {
|
||||||
date: {
|
date: {
|
||||||
year: { $year: '$created_at' },
|
year: { $year: '$createdAt' },
|
||||||
month: { $month: '$created_at' },
|
month: { $month: '$createdAt' },
|
||||||
day: { $dayOfMonth: '$created_at' }
|
day: { $dayOfMonth: '$createdAt' }
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
{ $group: {
|
{ $group: {
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Reaction from '../../../models/post-reaction';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Lookup post
|
// Lookup post
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
|
@ -29,10 +29,10 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const reactions = await Reaction
|
const reactions = await Reaction
|
||||||
.find({
|
.find({
|
||||||
post_id: post._id,
|
postId: post._id,
|
||||||
$or: [
|
$or: [
|
||||||
{ deleted_at: { $exists: false } },
|
{ deletedAt: { $exists: false } },
|
||||||
{ deleted_at: { $gt: startTime } }
|
{ deletedAt: { $gt: startTime } }
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
sort: {
|
sort: {
|
||||||
|
@ -40,7 +40,7 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
},
|
},
|
||||||
fields: {
|
fields: {
|
||||||
_id: false,
|
_id: false,
|
||||||
post_id: false
|
postId: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// day = day.getTime();
|
// day = day.getTime();
|
||||||
|
|
||||||
const count = reactions.filter(r =>
|
const count = reactions.filter(r =>
|
||||||
r.created_at < day && (r.deleted_at == null || r.deleted_at > day)
|
r.createdAt < day && (r.deletedAt == null || r.deletedAt > day)
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
graph.push({
|
graph.push({
|
||||||
|
|
|
@ -11,9 +11,9 @@ import Post from '../../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Lookup post
|
// Lookup post
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
|
@ -28,13 +28,13 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $match: { reply: post._id } },
|
{ $match: { reply: post._id } },
|
||||||
{ $project: {
|
{ $project: {
|
||||||
created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
|
createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST
|
||||||
}},
|
}},
|
||||||
{ $project: {
|
{ $project: {
|
||||||
date: {
|
date: {
|
||||||
year: { $year: '$created_at' },
|
year: { $year: '$createdAt' },
|
||||||
month: { $month: '$created_at' },
|
month: { $month: '$createdAt' },
|
||||||
day: { $dayOfMonth: '$created_at' }
|
day: { $dayOfMonth: '$createdAt' }
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
{ $group: {
|
{ $group: {
|
||||||
|
|
|
@ -11,9 +11,9 @@ import Post from '../../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Lookup post
|
// Lookup post
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
|
@ -26,15 +26,15 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const datas = await Post
|
const datas = await Post
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $match: { repost_id: post._id } },
|
{ $match: { repostId: post._id } },
|
||||||
{ $project: {
|
{ $project: {
|
||||||
created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
|
createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST
|
||||||
}},
|
}},
|
||||||
{ $project: {
|
{ $project: {
|
||||||
date: {
|
date: {
|
||||||
year: { $year: '$created_at' },
|
year: { $year: '$createdAt' },
|
||||||
month: { $month: '$created_at' },
|
month: { $month: '$createdAt' },
|
||||||
day: { $dayOfMonth: '$created_at' }
|
day: { $dayOfMonth: '$createdAt' }
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
{ $group: {
|
{ $group: {
|
||||||
|
|
|
@ -22,8 +22,8 @@ module.exports = params => new Promise(async (res, rej) => {
|
||||||
},
|
},
|
||||||
fields: {
|
fields: {
|
||||||
_id: false,
|
_id: false,
|
||||||
created_at: true,
|
createdAt: true,
|
||||||
deleted_at: true
|
deletedAt: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -44,11 +44,11 @@ module.exports = params => new Promise(async (res, rej) => {
|
||||||
// day = day.getTime();
|
// day = day.getTime();
|
||||||
|
|
||||||
const total = users.filter(u =>
|
const total = users.filter(u =>
|
||||||
u.created_at < dayEnd && (u.deleted_at == null || u.deleted_at > dayEnd)
|
u.createdAt < dayEnd && (u.deletedAt == null || u.deletedAt > dayEnd)
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
const created = users.filter(u =>
|
const created = users.filter(u =>
|
||||||
u.created_at < dayEnd && u.created_at > dayStart
|
u.createdAt < dayEnd && u.createdAt > dayStart
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
graph.push({
|
graph.push({
|
||||||
|
|
|
@ -18,9 +18,9 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
const [limit = 365, limitErr] = $(params.limit).optional.number().range(1, 365).$;
|
const [limit = 365, limitErr] = $(params.limit).optional.number().range(1, 365).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Lookup user
|
// Lookup user
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
|
@ -37,25 +37,25 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const datas = await Post
|
const datas = await Post
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $match: { user_id: user._id } },
|
{ $match: { userId: user._id } },
|
||||||
{ $project: {
|
{ $project: {
|
||||||
repost_id: '$repost_id',
|
repostId: '$repostId',
|
||||||
reply_id: '$reply_id',
|
replyId: '$replyId',
|
||||||
created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
|
createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST
|
||||||
}},
|
}},
|
||||||
{ $project: {
|
{ $project: {
|
||||||
date: {
|
date: {
|
||||||
year: { $year: '$created_at' },
|
year: { $year: '$createdAt' },
|
||||||
month: { $month: '$created_at' },
|
month: { $month: '$createdAt' },
|
||||||
day: { $dayOfMonth: '$created_at' }
|
day: { $dayOfMonth: '$createdAt' }
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
$cond: {
|
$cond: {
|
||||||
if: { $ne: ['$repost_id', null] },
|
if: { $ne: ['$repostId', null] },
|
||||||
then: 'repost',
|
then: 'repost',
|
||||||
else: {
|
else: {
|
||||||
$cond: {
|
$cond: {
|
||||||
if: { $ne: ['$reply_id', null] },
|
if: { $ne: ['$replyId', null] },
|
||||||
then: 'reply',
|
then: 'reply',
|
||||||
else: 'post'
|
else: 'post'
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Following from '../../../models/following';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Lookup user
|
// Lookup user
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
|
@ -33,17 +33,17 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const following = await Following
|
const following = await Following
|
||||||
.find({
|
.find({
|
||||||
followee_id: user._id,
|
followeeId: user._id,
|
||||||
$or: [
|
$or: [
|
||||||
{ deleted_at: { $exists: false } },
|
{ deletedAt: { $exists: false } },
|
||||||
{ deleted_at: { $gt: startTime } }
|
{ deletedAt: { $gt: startTime } }
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
_id: false,
|
_id: false,
|
||||||
follower_id: false,
|
followerId: false,
|
||||||
followee_id: false
|
followeeId: false
|
||||||
}, {
|
}, {
|
||||||
sort: { created_at: -1 }
|
sort: { createdAt: -1 }
|
||||||
});
|
});
|
||||||
|
|
||||||
const graph = [];
|
const graph = [];
|
||||||
|
@ -57,7 +57,7 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// day = day.getTime();
|
// day = day.getTime();
|
||||||
|
|
||||||
const count = following.filter(f =>
|
const count = following.filter(f =>
|
||||||
f.created_at < day && (f.deleted_at == null || f.deleted_at > day)
|
f.createdAt < day && (f.deletedAt == null || f.deletedAt > day)
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
graph.push({
|
graph.push({
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Following from '../../../models/following';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Lookup user
|
// Lookup user
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
|
@ -33,17 +33,17 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const following = await Following
|
const following = await Following
|
||||||
.find({
|
.find({
|
||||||
follower_id: user._id,
|
followerId: user._id,
|
||||||
$or: [
|
$or: [
|
||||||
{ deleted_at: { $exists: false } },
|
{ deletedAt: { $exists: false } },
|
||||||
{ deleted_at: { $gt: startTime } }
|
{ deletedAt: { $gt: startTime } }
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
_id: false,
|
_id: false,
|
||||||
follower_id: false,
|
followerId: false,
|
||||||
followee_id: false
|
followeeId: false
|
||||||
}, {
|
}, {
|
||||||
sort: { created_at: -1 }
|
sort: { createdAt: -1 }
|
||||||
});
|
});
|
||||||
|
|
||||||
const graph = [];
|
const graph = [];
|
||||||
|
@ -56,7 +56,7 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
day = new Date(day.setHours(23));
|
day = new Date(day.setHours(23));
|
||||||
|
|
||||||
const count = following.filter(f =>
|
const count = following.filter(f =>
|
||||||
f.created_at < day && (f.deleted_at == null || f.deleted_at > day)
|
f.createdAt < day && (f.deletedAt == null || f.deletedAt > day)
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
graph.push({
|
graph.push({
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Post from '../../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Lookup user
|
// Lookup user
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
|
@ -31,25 +31,25 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const datas = await Post
|
const datas = await Post
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $match: { user_id: user._id } },
|
{ $match: { userId: user._id } },
|
||||||
{ $project: {
|
{ $project: {
|
||||||
repost_id: '$repost_id',
|
repostId: '$repostId',
|
||||||
reply_id: '$reply_id',
|
replyId: '$replyId',
|
||||||
created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
|
createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST
|
||||||
}},
|
}},
|
||||||
{ $project: {
|
{ $project: {
|
||||||
date: {
|
date: {
|
||||||
year: { $year: '$created_at' },
|
year: { $year: '$createdAt' },
|
||||||
month: { $month: '$created_at' },
|
month: { $month: '$createdAt' },
|
||||||
day: { $dayOfMonth: '$created_at' }
|
day: { $dayOfMonth: '$createdAt' }
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
$cond: {
|
$cond: {
|
||||||
if: { $ne: ['$repost_id', null] },
|
if: { $ne: ['$repostId', null] },
|
||||||
then: 'repost',
|
then: 'repost',
|
||||||
else: {
|
else: {
|
||||||
$cond: {
|
$cond: {
|
||||||
if: { $ne: ['$reply_id', null] },
|
if: { $ne: ['$replyId', null] },
|
||||||
then: 'reply',
|
then: 'reply',
|
||||||
else: 'post'
|
else: 'post'
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Reaction from '../../../models/post-reaction';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Lookup user
|
// Lookup user
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
|
@ -31,15 +31,15 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const datas = await Reaction
|
const datas = await Reaction
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $match: { user_id: user._id } },
|
{ $match: { userId: user._id } },
|
||||||
{ $project: {
|
{ $project: {
|
||||||
created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
|
createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST
|
||||||
}},
|
}},
|
||||||
{ $project: {
|
{ $project: {
|
||||||
date: {
|
date: {
|
||||||
year: { $year: '$created_at' },
|
year: { $year: '$createdAt' },
|
||||||
month: { $month: '$created_at' },
|
month: { $month: '$createdAt' },
|
||||||
day: { $dayOfMonth: '$created_at' }
|
day: { $dayOfMonth: '$createdAt' }
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
{ $group: {
|
{ $group: {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import App, { isValidNameId, pack } from '../../models/app';
|
||||||
* parameters:
|
* parameters:
|
||||||
* - $ref: "#/parameters/AccessToken"
|
* - $ref: "#/parameters/AccessToken"
|
||||||
* -
|
* -
|
||||||
* name: name_id
|
* name: nameId
|
||||||
* description: Application unique name
|
* description: Application unique name
|
||||||
* in: formData
|
* in: formData
|
||||||
* required: true
|
* required: true
|
||||||
|
@ -40,7 +40,7 @@ import App, { isValidNameId, pack } from '../../models/app';
|
||||||
* type: string
|
* type: string
|
||||||
* collectionFormat: csv
|
* collectionFormat: csv
|
||||||
* -
|
* -
|
||||||
* name: callback_url
|
* name: callbackUrl
|
||||||
* description: URL called back after authentication
|
* description: URL called back after authentication
|
||||||
* in: formData
|
* in: formData
|
||||||
* required: false
|
* required: false
|
||||||
|
@ -66,9 +66,9 @@ import App, { isValidNameId, pack } from '../../models/app';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'name_id' parameter
|
// Get 'nameId' parameter
|
||||||
const [nameId, nameIdErr] = $(params.name_id).string().pipe(isValidNameId).$;
|
const [nameId, nameIdErr] = $(params.nameId).string().pipe(isValidNameId).$;
|
||||||
if (nameIdErr) return rej('invalid name_id param');
|
if (nameIdErr) return rej('invalid nameId param');
|
||||||
|
|
||||||
// Get 'name' parameter
|
// Get 'name' parameter
|
||||||
const [name, nameErr] = $(params.name).string().$;
|
const [name, nameErr] = $(params.name).string().$;
|
||||||
|
@ -82,24 +82,24 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
const [permission, permissionErr] = $(params.permission).array('string').unique().$;
|
const [permission, permissionErr] = $(params.permission).array('string').unique().$;
|
||||||
if (permissionErr) return rej('invalid permission param');
|
if (permissionErr) return rej('invalid permission param');
|
||||||
|
|
||||||
// Get 'callback_url' parameter
|
// Get 'callbackUrl' parameter
|
||||||
// TODO: Check it is valid url
|
// TODO: Check it is valid url
|
||||||
const [callbackUrl = null, callbackUrlErr] = $(params.callback_url).optional.nullable.string().$;
|
const [callbackUrl = null, callbackUrlErr] = $(params.callbackUrl).optional.nullable.string().$;
|
||||||
if (callbackUrlErr) return rej('invalid callback_url param');
|
if (callbackUrlErr) return rej('invalid callbackUrl param');
|
||||||
|
|
||||||
// Generate secret
|
// Generate secret
|
||||||
const secret = rndstr('a-zA-Z0-9', 32);
|
const secret = rndstr('a-zA-Z0-9', 32);
|
||||||
|
|
||||||
// Create account
|
// Create account
|
||||||
const app = await App.insert({
|
const app = await App.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
name: name,
|
name: name,
|
||||||
name_id: nameId,
|
nameId: nameId,
|
||||||
name_id_lower: nameId.toLowerCase(),
|
nameIdLower: nameId.toLowerCase(),
|
||||||
description: description,
|
description: description,
|
||||||
permission: permission,
|
permission: permission,
|
||||||
callback_url: callbackUrl,
|
callbackUrl: callbackUrl,
|
||||||
secret: secret
|
secret: secret
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,12 @@ import { isValidNameId } from '../../../models/app';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /app/name_id/available:
|
* /app/nameId/available:
|
||||||
* post:
|
* post:
|
||||||
* summary: Check available name_id on creation an application
|
* summary: Check available nameId on creation an application
|
||||||
* parameters:
|
* parameters:
|
||||||
* -
|
* -
|
||||||
* name: name_id
|
* name: nameId
|
||||||
* description: Application unique name
|
* description: Application unique name
|
||||||
* in: formData
|
* in: formData
|
||||||
* required: true
|
* required: true
|
||||||
|
@ -25,7 +25,7 @@ import { isValidNameId } from '../../../models/app';
|
||||||
* type: object
|
* type: object
|
||||||
* properties:
|
* properties:
|
||||||
* available:
|
* available:
|
||||||
* description: Whether name_id is available
|
* description: Whether nameId is available
|
||||||
* type: boolean
|
* type: boolean
|
||||||
*
|
*
|
||||||
* default:
|
* default:
|
||||||
|
@ -35,20 +35,20 @@ import { isValidNameId } from '../../../models/app';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check available name_id of app
|
* Check available nameId of app
|
||||||
*
|
*
|
||||||
* @param {any} params
|
* @param {any} params
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = async (params) => new Promise(async (res, rej) => {
|
module.exports = async (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'name_id' parameter
|
// Get 'nameId' parameter
|
||||||
const [nameId, nameIdErr] = $(params.name_id).string().pipe(isValidNameId).$;
|
const [nameId, nameIdErr] = $(params.nameId).string().pipe(isValidNameId).$;
|
||||||
if (nameIdErr) return rej('invalid name_id param');
|
if (nameIdErr) return rej('invalid nameId param');
|
||||||
|
|
||||||
// Get exist
|
// Get exist
|
||||||
const exist = await App
|
const exist = await App
|
||||||
.count({
|
.count({
|
||||||
name_id_lower: nameId.toLowerCase()
|
nameIdLower: nameId.toLowerCase()
|
||||||
}, {
|
}, {
|
||||||
limit: 1
|
limit: 1
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,15 +9,15 @@ import App, { pack } from '../../models/app';
|
||||||
* /app/show:
|
* /app/show:
|
||||||
* post:
|
* post:
|
||||||
* summary: Show an application's information
|
* summary: Show an application's information
|
||||||
* description: Require app_id or name_id
|
* description: Require appId or nameId
|
||||||
* parameters:
|
* parameters:
|
||||||
* -
|
* -
|
||||||
* name: app_id
|
* name: appId
|
||||||
* description: Application ID
|
* description: Application ID
|
||||||
* in: formData
|
* in: formData
|
||||||
* type: string
|
* type: string
|
||||||
* -
|
* -
|
||||||
* name: name_id
|
* name: nameId
|
||||||
* description: Application unique name
|
* description: Application unique name
|
||||||
* in: formData
|
* in: formData
|
||||||
* type: string
|
* type: string
|
||||||
|
@ -44,22 +44,22 @@ import App, { pack } from '../../models/app';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => {
|
module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => {
|
||||||
// Get 'app_id' parameter
|
// Get 'appId' parameter
|
||||||
const [appId, appIdErr] = $(params.app_id).optional.id().$;
|
const [appId, appIdErr] = $(params.appId).optional.id().$;
|
||||||
if (appIdErr) return rej('invalid app_id param');
|
if (appIdErr) return rej('invalid appId param');
|
||||||
|
|
||||||
// Get 'name_id' parameter
|
// Get 'nameId' parameter
|
||||||
const [nameId, nameIdErr] = $(params.name_id).optional.string().$;
|
const [nameId, nameIdErr] = $(params.nameId).optional.string().$;
|
||||||
if (nameIdErr) return rej('invalid name_id param');
|
if (nameIdErr) return rej('invalid nameId param');
|
||||||
|
|
||||||
if (appId === undefined && nameId === undefined) {
|
if (appId === undefined && nameId === undefined) {
|
||||||
return rej('app_id or name_id is required');
|
return rej('appId or nameId is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup app
|
// Lookup app
|
||||||
const app = appId !== undefined
|
const app = appId !== undefined
|
||||||
? await App.findOne({ _id: appId })
|
? await App.findOne({ _id: appId })
|
||||||
: await App.findOne({ name_id_lower: nameId.toLowerCase() });
|
: await App.findOne({ nameIdLower: nameId.toLowerCase() });
|
||||||
|
|
||||||
if (app === null) {
|
if (app === null) {
|
||||||
return rej('app not found');
|
return rej('app not found');
|
||||||
|
@ -67,6 +67,6 @@ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) =>
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
res(await pack(app, user, {
|
res(await pack(app, user, {
|
||||||
includeSecret: isSecure && app.user_id.equals(user._id)
|
includeSecret: isSecure && app.userId.equals(user._id)
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
|
@ -56,14 +56,14 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Fetch exist access token
|
// Fetch exist access token
|
||||||
const exist = await AccessToken.findOne({
|
const exist = await AccessToken.findOne({
|
||||||
app_id: session.app_id,
|
appId: session.appId,
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist === null) {
|
if (exist === null) {
|
||||||
// Lookup app
|
// Lookup app
|
||||||
const app = await App.findOne({
|
const app = await App.findOne({
|
||||||
_id: session.app_id
|
_id: session.appId
|
||||||
});
|
});
|
||||||
|
|
||||||
// Generate Hash
|
// Generate Hash
|
||||||
|
@ -73,9 +73,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Insert access token doc
|
// Insert access token doc
|
||||||
await AccessToken.insert({
|
await AccessToken.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
app_id: session.app_id,
|
appId: session.appId,
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
token: accessToken,
|
token: accessToken,
|
||||||
hash: hash
|
hash: hash
|
||||||
});
|
});
|
||||||
|
@ -84,7 +84,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Update session
|
// Update session
|
||||||
await AuthSess.update(session._id, {
|
await AuthSess.update(session._id, {
|
||||||
$set: {
|
$set: {
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import config from '../../../../../conf';
|
||||||
* summary: Generate a session
|
* summary: Generate a session
|
||||||
* parameters:
|
* parameters:
|
||||||
* -
|
* -
|
||||||
* name: app_secret
|
* name: appSecret
|
||||||
* description: App Secret
|
* description: App Secret
|
||||||
* in: formData
|
* in: formData
|
||||||
* required: true
|
* required: true
|
||||||
|
@ -45,9 +45,9 @@ import config from '../../../../../conf';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'app_secret' parameter
|
// Get 'appSecret' parameter
|
||||||
const [appSecret, appSecretErr] = $(params.app_secret).string().$;
|
const [appSecret, appSecretErr] = $(params.appSecret).string().$;
|
||||||
if (appSecretErr) return rej('invalid app_secret param');
|
if (appSecretErr) return rej('invalid appSecret param');
|
||||||
|
|
||||||
// Lookup app
|
// Lookup app
|
||||||
const app = await App.findOne({
|
const app = await App.findOne({
|
||||||
|
@ -63,8 +63,8 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create session token document
|
// Create session token document
|
||||||
const doc = await AuthSess.insert({
|
const doc = await AuthSess.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
app_id: app._id,
|
appId: app._id,
|
||||||
token: token
|
token: token
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,17 +23,17 @@ import AuthSess, { pack } from '../../../models/auth-session';
|
||||||
* schema:
|
* schema:
|
||||||
* type: object
|
* type: object
|
||||||
* properties:
|
* properties:
|
||||||
* created_at:
|
* createdAt:
|
||||||
* type: string
|
* type: string
|
||||||
* format: date-time
|
* format: date-time
|
||||||
* description: Date and time of the session creation
|
* description: Date and time of the session creation
|
||||||
* app_id:
|
* appId:
|
||||||
* type: string
|
* type: string
|
||||||
* description: Application ID
|
* description: Application ID
|
||||||
* token:
|
* token:
|
||||||
* type: string
|
* type: string
|
||||||
* description: Session Token
|
* description: Session Token
|
||||||
* user_id:
|
* userId:
|
||||||
* type: string
|
* type: string
|
||||||
* description: ID of user who create the session
|
* description: ID of user who create the session
|
||||||
* app:
|
* app:
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { pack } from '../../../models/user';
|
||||||
* summary: Get an access token(userkey)
|
* summary: Get an access token(userkey)
|
||||||
* parameters:
|
* parameters:
|
||||||
* -
|
* -
|
||||||
* name: app_secret
|
* name: appSecret
|
||||||
* description: App Secret
|
* description: App Secret
|
||||||
* in: formData
|
* in: formData
|
||||||
* required: true
|
* required: true
|
||||||
|
@ -50,9 +50,9 @@ import { pack } from '../../../models/user';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params) => new Promise(async (res, rej) => {
|
module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
// Get 'app_secret' parameter
|
// Get 'appSecret' parameter
|
||||||
const [appSecret, appSecretErr] = $(params.app_secret).string().$;
|
const [appSecret, appSecretErr] = $(params.appSecret).string().$;
|
||||||
if (appSecretErr) return rej('invalid app_secret param');
|
if (appSecretErr) return rej('invalid appSecret param');
|
||||||
|
|
||||||
// Lookup app
|
// Lookup app
|
||||||
const app = await App.findOne({
|
const app = await App.findOne({
|
||||||
|
@ -71,21 +71,21 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
const session = await AuthSess
|
const session = await AuthSess
|
||||||
.findOne({
|
.findOne({
|
||||||
token: token,
|
token: token,
|
||||||
app_id: app._id
|
appId: app._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (session === null) {
|
if (session === null) {
|
||||||
return rej('session not found');
|
return rej('session not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.user_id == null) {
|
if (session.userId == null) {
|
||||||
return rej('this session is not allowed yet');
|
return rej('this session is not allowed yet');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup access token
|
// Lookup access token
|
||||||
const accessToken = await AccessToken.findOne({
|
const accessToken = await AccessToken.findOne({
|
||||||
app_id: app._id,
|
appId: app._id,
|
||||||
user_id: session.user_id
|
userId: session.userId
|
||||||
});
|
});
|
||||||
|
|
||||||
// Delete session
|
// Delete session
|
||||||
|
@ -101,8 +101,8 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Response
|
// Response
|
||||||
res({
|
res({
|
||||||
access_token: accessToken.token,
|
accessToken: accessToken.token,
|
||||||
user: await pack(session.user_id, null, {
|
user: await pack(session.userId, null, {
|
||||||
detail: true
|
detail: true
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,17 +16,17 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct query
|
// Construct query
|
||||||
|
|
|
@ -20,11 +20,11 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create a channel
|
// Create a channel
|
||||||
const channel = await Channel.insert({
|
const channel = await Channel.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
title: title,
|
title: title,
|
||||||
index: 0,
|
index: 0,
|
||||||
watching_count: 1
|
watchingCount: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
// Response
|
// Response
|
||||||
|
@ -32,8 +32,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create Watching
|
// Create Watching
|
||||||
await Watching.insert({
|
await Watching.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
channel_id: channel._id
|
channelId: channel._id
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,22 +17,22 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [limit = 1000, limitErr] = $(params.limit).optional.number().range(1, 1000).$;
|
const [limit = 1000, limitErr] = $(params.limit).optional.number().range(1, 1000).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'channel_id' parameter
|
// Get 'channelId' parameter
|
||||||
const [channelId, channelIdErr] = $(params.channel_id).id().$;
|
const [channelId, channelIdErr] = $(params.channelId).id().$;
|
||||||
if (channelIdErr) return rej('invalid channel_id param');
|
if (channelIdErr) return rej('invalid channelId param');
|
||||||
|
|
||||||
// Fetch channel
|
// Fetch channel
|
||||||
const channel: IChannel = await Channel.findOne({
|
const channel: IChannel = await Channel.findOne({
|
||||||
|
@ -49,7 +49,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
channel_id: channel._id
|
channelId: channel._id
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Channel, { IChannel, pack } from '../../models/channel';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'channel_id' parameter
|
// Get 'channelId' parameter
|
||||||
const [channelId, channelIdErr] = $(params.channel_id).id().$;
|
const [channelId, channelIdErr] = $(params.channelId).id().$;
|
||||||
if (channelIdErr) return rej('invalid channel_id param');
|
if (channelIdErr) return rej('invalid channelId param');
|
||||||
|
|
||||||
// Fetch channel
|
// Fetch channel
|
||||||
const channel: IChannel = await Channel.findOne({
|
const channel: IChannel = await Channel.findOne({
|
||||||
|
|
|
@ -13,9 +13,9 @@ import Watching from '../../models/channel-watching';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'channel_id' parameter
|
// Get 'channelId' parameter
|
||||||
const [channelId, channelIdErr] = $(params.channel_id).id().$;
|
const [channelId, channelIdErr] = $(params.channelId).id().$;
|
||||||
if (channelIdErr) return rej('invalid channel_id param');
|
if (channelIdErr) return rej('invalid channelId param');
|
||||||
|
|
||||||
//#region Fetch channel
|
//#region Fetch channel
|
||||||
const channel = await Channel.findOne({
|
const channel = await Channel.findOne({
|
||||||
|
@ -29,9 +29,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
//#region Check whether not watching
|
//#region Check whether not watching
|
||||||
const exist = await Watching.findOne({
|
const exist = await Watching.findOne({
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
channel_id: channel._id,
|
channelId: channel._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist === null) {
|
if (exist === null) {
|
||||||
|
@ -44,7 +44,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
_id: exist._id
|
_id: exist._id
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
deleted_at: new Date()
|
deletedAt: new Date()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Decrement watching count
|
// Decrement watching count
|
||||||
Channel.update(channel._id, {
|
Channel.update(channel._id, {
|
||||||
$inc: {
|
$inc: {
|
||||||
watching_count: -1
|
watchingCount: -1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,9 +13,9 @@ import Watching from '../../models/channel-watching';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'channel_id' parameter
|
// Get 'channelId' parameter
|
||||||
const [channelId, channelIdErr] = $(params.channel_id).id().$;
|
const [channelId, channelIdErr] = $(params.channelId).id().$;
|
||||||
if (channelIdErr) return rej('invalid channel_id param');
|
if (channelIdErr) return rej('invalid channelId param');
|
||||||
|
|
||||||
//#region Fetch channel
|
//#region Fetch channel
|
||||||
const channel = await Channel.findOne({
|
const channel = await Channel.findOne({
|
||||||
|
@ -29,9 +29,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
//#region Check whether already watching
|
//#region Check whether already watching
|
||||||
const exist = await Watching.findOne({
|
const exist = await Watching.findOne({
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
channel_id: channel._id,
|
channelId: channel._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist !== null) {
|
if (exist !== null) {
|
||||||
|
@ -41,9 +41,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create Watching
|
// Create Watching
|
||||||
await Watching.insert({
|
await Watching.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
channel_id: channel._id
|
channelId: channel._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
|
@ -52,7 +52,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Increment watching count
|
// Increment watching count
|
||||||
Channel.update(channel._id, {
|
Channel.update(channel._id, {
|
||||||
$inc: {
|
$inc: {
|
||||||
watching_count: 1
|
watchingCount: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Calculate drive usage
|
// Calculate drive usage
|
||||||
const usage = ((await DriveFile
|
const usage = ((await DriveFile
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{ $match: { 'metadata.user_id': user._id } },
|
{ $match: { 'metadata.userId': user._id } },
|
||||||
{
|
{
|
||||||
$project: {
|
$project: {
|
||||||
length: true
|
length: true
|
||||||
|
@ -31,7 +31,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
}).usage;
|
}).usage;
|
||||||
|
|
||||||
res({
|
res({
|
||||||
capacity: user.drive_capacity,
|
capacity: user.driveCapacity,
|
||||||
usage: usage
|
usage: usage
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,22 +17,22 @@ module.exports = async (params, user, app) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) throw 'invalid limit param';
|
if (limitErr) throw 'invalid limit param';
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) throw 'invalid since_id param';
|
if (sinceIdErr) throw 'invalid sinceId param';
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) throw 'invalid until_id param';
|
if (untilIdErr) throw 'invalid untilId param';
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
throw 'cannot set since_id and until_id';
|
throw 'cannot set sinceId and untilId';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId = null, folderIdErr] = $(params.folder_id).optional.nullable.id().$;
|
const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
|
||||||
if (folderIdErr) throw 'invalid folder_id param';
|
if (folderIdErr) throw 'invalid folderId param';
|
||||||
|
|
||||||
// Get 'type' parameter
|
// Get 'type' parameter
|
||||||
const [type, typeErr] = $(params.type).optional.string().match(/^[a-zA-Z\/\-\*]+$/).$;
|
const [type, typeErr] = $(params.type).optional.string().match(/^[a-zA-Z\/\-\*]+$/).$;
|
||||||
|
@ -43,8 +43,8 @@ module.exports = async (params, user, app) => {
|
||||||
_id: -1
|
_id: -1
|
||||||
};
|
};
|
||||||
const query = {
|
const query = {
|
||||||
'metadata.user_id': user._id,
|
'metadata.userId': user._id,
|
||||||
'metadata.folder_id': folderId
|
'metadata.folderId': folderId
|
||||||
} as any;
|
} as any;
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
|
|
|
@ -33,9 +33,9 @@ module.exports = async (file, params, user): Promise<any> => {
|
||||||
name = null;
|
name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId = null, folderIdErr] = $(params.folder_id).optional.nullable.id().$;
|
const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
|
||||||
if (folderIdErr) throw 'invalid folder_id param';
|
if (folderIdErr) throw 'invalid folderId param';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create file
|
// Create file
|
||||||
|
|
|
@ -16,16 +16,16 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [name, nameErr] = $(params.name).string().$;
|
const [name, nameErr] = $(params.name).string().$;
|
||||||
if (nameErr) return rej('invalid name param');
|
if (nameErr) return rej('invalid name param');
|
||||||
|
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId = null, folderIdErr] = $(params.folder_id).optional.nullable.id().$;
|
const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
|
||||||
if (folderIdErr) return rej('invalid folder_id param');
|
if (folderIdErr) return rej('invalid folderId param');
|
||||||
|
|
||||||
// Issue query
|
// Issue query
|
||||||
const files = await DriveFile
|
const files = await DriveFile
|
||||||
.find({
|
.find({
|
||||||
filename: name,
|
filename: name,
|
||||||
'metadata.user_id': user._id,
|
'metadata.userId': user._id,
|
||||||
'metadata.folder_id': folderId
|
'metadata.folderId': folderId
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
|
|
|
@ -12,15 +12,15 @@ import DriveFile, { pack } from '../../../models/drive-file';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = async (params, user) => {
|
module.exports = async (params, user) => {
|
||||||
// Get 'file_id' parameter
|
// Get 'fileId' parameter
|
||||||
const [fileId, fileIdErr] = $(params.file_id).id().$;
|
const [fileId, fileIdErr] = $(params.fileId).id().$;
|
||||||
if (fileIdErr) throw 'invalid file_id param';
|
if (fileIdErr) throw 'invalid fileId param';
|
||||||
|
|
||||||
// Fetch file
|
// Fetch file
|
||||||
const file = await DriveFile
|
const file = await DriveFile
|
||||||
.findOne({
|
.findOne({
|
||||||
_id: fileId,
|
_id: fileId,
|
||||||
'metadata.user_id': user._id
|
'metadata.userId': user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (file === null) {
|
if (file === null) {
|
||||||
|
|
|
@ -14,15 +14,15 @@ import { publishDriveStream } from '../../../event';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'file_id' parameter
|
// Get 'fileId' parameter
|
||||||
const [fileId, fileIdErr] = $(params.file_id).id().$;
|
const [fileId, fileIdErr] = $(params.fileId).id().$;
|
||||||
if (fileIdErr) return rej('invalid file_id param');
|
if (fileIdErr) return rej('invalid fileId param');
|
||||||
|
|
||||||
// Fetch file
|
// Fetch file
|
||||||
const file = await DriveFile
|
const file = await DriveFile
|
||||||
.findOne({
|
.findOne({
|
||||||
_id: fileId,
|
_id: fileId,
|
||||||
'metadata.user_id': user._id
|
'metadata.userId': user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (file === null) {
|
if (file === null) {
|
||||||
|
@ -34,33 +34,33 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
if (nameErr) return rej('invalid name param');
|
if (nameErr) return rej('invalid name param');
|
||||||
if (name) file.filename = name;
|
if (name) file.filename = name;
|
||||||
|
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId, folderIdErr] = $(params.folder_id).optional.nullable.id().$;
|
const [folderId, folderIdErr] = $(params.folderId).optional.nullable.id().$;
|
||||||
if (folderIdErr) return rej('invalid folder_id param');
|
if (folderIdErr) return rej('invalid folderId param');
|
||||||
|
|
||||||
if (folderId !== undefined) {
|
if (folderId !== undefined) {
|
||||||
if (folderId === null) {
|
if (folderId === null) {
|
||||||
file.metadata.folder_id = null;
|
file.metadata.folderId = null;
|
||||||
} else {
|
} else {
|
||||||
// Fetch folder
|
// Fetch folder
|
||||||
const folder = await DriveFolder
|
const folder = await DriveFolder
|
||||||
.findOne({
|
.findOne({
|
||||||
_id: folderId,
|
_id: folderId,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (folder === null) {
|
if (folder === null) {
|
||||||
return rej('folder-not-found');
|
return rej('folder-not-found');
|
||||||
}
|
}
|
||||||
|
|
||||||
file.metadata.folder_id = folder._id;
|
file.metadata.folderId = folder._id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await DriveFile.update(file._id, {
|
await DriveFile.update(file._id, {
|
||||||
$set: {
|
$set: {
|
||||||
filename: file.filename,
|
filename: file.filename,
|
||||||
'metadata.folder_id': file.metadata.folder_id
|
'metadata.folderId': file.metadata.folderId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@ module.exports = async (params, user): Promise<any> => {
|
||||||
const [url, urlErr] = $(params.url).string().$;
|
const [url, urlErr] = $(params.url).string().$;
|
||||||
if (urlErr) throw 'invalid url param';
|
if (urlErr) throw 'invalid url param';
|
||||||
|
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId = null, folderIdErr] = $(params.folder_id).optional.nullable.id().$;
|
const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
|
||||||
if (folderIdErr) throw 'invalid folder_id param';
|
if (folderIdErr) throw 'invalid folderId param';
|
||||||
|
|
||||||
return pack(await uploadFromUrl(url, user, folderId));
|
return pack(await uploadFromUrl(url, user, folderId));
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,30 +17,30 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId = null, folderIdErr] = $(params.folder_id).optional.nullable.id().$;
|
const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
|
||||||
if (folderIdErr) return rej('invalid folder_id param');
|
if (folderIdErr) return rej('invalid folderId param');
|
||||||
|
|
||||||
// Construct query
|
// Construct query
|
||||||
const sort = {
|
const sort = {
|
||||||
_id: -1
|
_id: -1
|
||||||
};
|
};
|
||||||
const query = {
|
const query = {
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
parent_id: folderId
|
parentId: folderId
|
||||||
} as any;
|
} as any;
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
|
|
|
@ -17,9 +17,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [name = '無題のフォルダー', nameErr] = $(params.name).optional.string().pipe(isValidFolderName).$;
|
const [name = '無題のフォルダー', nameErr] = $(params.name).optional.string().pipe(isValidFolderName).$;
|
||||||
if (nameErr) return rej('invalid name param');
|
if (nameErr) return rej('invalid name param');
|
||||||
|
|
||||||
// Get 'parent_id' parameter
|
// Get 'parentId' parameter
|
||||||
const [parentId = null, parentIdErr] = $(params.parent_id).optional.nullable.id().$;
|
const [parentId = null, parentIdErr] = $(params.parentId).optional.nullable.id().$;
|
||||||
if (parentIdErr) return rej('invalid parent_id param');
|
if (parentIdErr) return rej('invalid parentId param');
|
||||||
|
|
||||||
// If the parent folder is specified
|
// If the parent folder is specified
|
||||||
let parent = null;
|
let parent = null;
|
||||||
|
@ -28,7 +28,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
parent = await DriveFolder
|
parent = await DriveFolder
|
||||||
.findOne({
|
.findOne({
|
||||||
_id: parentId,
|
_id: parentId,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (parent === null) {
|
if (parent === null) {
|
||||||
|
@ -38,10 +38,10 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create folder
|
// Create folder
|
||||||
const folder = await DriveFolder.insert({
|
const folder = await DriveFolder.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
name: name,
|
name: name,
|
||||||
parent_id: parent !== null ? parent._id : null,
|
parentId: parent !== null ? parent._id : null,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
|
|
|
@ -16,16 +16,16 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [name, nameErr] = $(params.name).string().$;
|
const [name, nameErr] = $(params.name).string().$;
|
||||||
if (nameErr) return rej('invalid name param');
|
if (nameErr) return rej('invalid name param');
|
||||||
|
|
||||||
// Get 'parent_id' parameter
|
// Get 'parentId' parameter
|
||||||
const [parentId = null, parentIdErr] = $(params.parent_id).optional.nullable.id().$;
|
const [parentId = null, parentIdErr] = $(params.parentId).optional.nullable.id().$;
|
||||||
if (parentIdErr) return rej('invalid parent_id param');
|
if (parentIdErr) return rej('invalid parentId param');
|
||||||
|
|
||||||
// Issue query
|
// Issue query
|
||||||
const folders = await DriveFolder
|
const folders = await DriveFolder
|
||||||
.find({
|
.find({
|
||||||
name: name,
|
name: name,
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
parent_id: parentId
|
parentId: parentId
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
|
|
|
@ -12,15 +12,15 @@ import DriveFolder, { pack } from '../../../models/drive-folder';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId, folderIdErr] = $(params.folder_id).id().$;
|
const [folderId, folderIdErr] = $(params.folderId).id().$;
|
||||||
if (folderIdErr) return rej('invalid folder_id param');
|
if (folderIdErr) return rej('invalid folderId param');
|
||||||
|
|
||||||
// Get folder
|
// Get folder
|
||||||
const folder = await DriveFolder
|
const folder = await DriveFolder
|
||||||
.findOne({
|
.findOne({
|
||||||
_id: folderId,
|
_id: folderId,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (folder === null) {
|
if (folder === null) {
|
||||||
|
|
|
@ -13,15 +13,15 @@ import { publishDriveStream } from '../../../event';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'folder_id' parameter
|
// Get 'folderId' parameter
|
||||||
const [folderId, folderIdErr] = $(params.folder_id).id().$;
|
const [folderId, folderIdErr] = $(params.folderId).id().$;
|
||||||
if (folderIdErr) return rej('invalid folder_id param');
|
if (folderIdErr) return rej('invalid folderId param');
|
||||||
|
|
||||||
// Fetch folder
|
// Fetch folder
|
||||||
const folder = await DriveFolder
|
const folder = await DriveFolder
|
||||||
.findOne({
|
.findOne({
|
||||||
_id: folderId,
|
_id: folderId,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (folder === null) {
|
if (folder === null) {
|
||||||
|
@ -33,18 +33,18 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
if (nameErr) return rej('invalid name param');
|
if (nameErr) return rej('invalid name param');
|
||||||
if (name) folder.name = name;
|
if (name) folder.name = name;
|
||||||
|
|
||||||
// Get 'parent_id' parameter
|
// Get 'parentId' parameter
|
||||||
const [parentId, parentIdErr] = $(params.parent_id).optional.nullable.id().$;
|
const [parentId, parentIdErr] = $(params.parentId).optional.nullable.id().$;
|
||||||
if (parentIdErr) return rej('invalid parent_id param');
|
if (parentIdErr) return rej('invalid parentId param');
|
||||||
if (parentId !== undefined) {
|
if (parentId !== undefined) {
|
||||||
if (parentId === null) {
|
if (parentId === null) {
|
||||||
folder.parent_id = null;
|
folder.parentId = null;
|
||||||
} else {
|
} else {
|
||||||
// Get parent folder
|
// Get parent folder
|
||||||
const parent = await DriveFolder
|
const parent = await DriveFolder
|
||||||
.findOne({
|
.findOne({
|
||||||
_id: parentId,
|
_id: parentId,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (parent === null) {
|
if (parent === null) {
|
||||||
|
@ -58,25 +58,25 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
_id: folderId
|
_id: folderId
|
||||||
}, {
|
}, {
|
||||||
_id: true,
|
_id: true,
|
||||||
parent_id: true
|
parentId: true
|
||||||
});
|
});
|
||||||
|
|
||||||
if (folder2._id.equals(folder._id)) {
|
if (folder2._id.equals(folder._id)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (folder2.parent_id) {
|
} else if (folder2.parentId) {
|
||||||
return await checkCircle(folder2.parent_id);
|
return await checkCircle(folder2.parentId);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent.parent_id !== null) {
|
if (parent.parentId !== null) {
|
||||||
if (await checkCircle(parent.parent_id)) {
|
if (await checkCircle(parent.parentId)) {
|
||||||
return rej('detected-circular-definition');
|
return rej('detected-circular-definition');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
folder.parent_id = parent._id;
|
folder.parentId = parent._id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
DriveFolder.update(folder._id, {
|
DriveFolder.update(folder._id, {
|
||||||
$set: {
|
$set: {
|
||||||
name: folder.name,
|
name: folder.name,
|
||||||
parent_id: folder.parent_id
|
parentId: folder.parentId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,17 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'type' parameter
|
// Get 'type' parameter
|
||||||
|
@ -38,7 +38,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
_id: -1
|
_id: -1
|
||||||
};
|
};
|
||||||
const query = {
|
const query = {
|
||||||
'metadata.user_id': user._id
|
'metadata.userId': user._id
|
||||||
} as any;
|
} as any;
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
|
|
|
@ -17,9 +17,9 @@ import event from '../../event';
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const follower = user;
|
const follower = user;
|
||||||
|
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// 自分自身
|
// 自分自身
|
||||||
if (user._id.equals(userId)) {
|
if (user._id.equals(userId)) {
|
||||||
|
@ -42,9 +42,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Check if already following
|
// Check if already following
|
||||||
const exist = await Following.findOne({
|
const exist = await Following.findOne({
|
||||||
follower_id: follower._id,
|
followerId: follower._id,
|
||||||
followee_id: followee._id,
|
followeeId: followee._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist !== null) {
|
if (exist !== null) {
|
||||||
|
@ -53,9 +53,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create following
|
// Create following
|
||||||
await Following.insert({
|
await Following.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
follower_id: follower._id,
|
followerId: follower._id,
|
||||||
followee_id: followee._id
|
followeeId: followee._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
|
@ -64,14 +64,14 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Increment following count
|
// Increment following count
|
||||||
User.update(follower._id, {
|
User.update(follower._id, {
|
||||||
$inc: {
|
$inc: {
|
||||||
following_count: 1
|
followingCount: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Increment followers count
|
// Increment followers count
|
||||||
User.update({ _id: followee._id }, {
|
User.update({ _id: followee._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
followers_count: 1
|
followersCount: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@ import event from '../../event';
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const follower = user;
|
const follower = user;
|
||||||
|
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Check if the followee is yourself
|
// Check if the followee is yourself
|
||||||
if (user._id.equals(userId)) {
|
if (user._id.equals(userId)) {
|
||||||
|
@ -41,9 +41,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Check not following
|
// Check not following
|
||||||
const exist = await Following.findOne({
|
const exist = await Following.findOne({
|
||||||
follower_id: follower._id,
|
followerId: follower._id,
|
||||||
followee_id: followee._id,
|
followeeId: followee._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist === null) {
|
if (exist === null) {
|
||||||
|
@ -55,7 +55,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
_id: exist._id
|
_id: exist._id
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
deleted_at: new Date()
|
deletedAt: new Date()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -65,14 +65,14 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Decrement following count
|
// Decrement following count
|
||||||
User.update({ _id: follower._id }, {
|
User.update({ _id: follower._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
following_count: -1
|
followingCount: -1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Decrement followers count
|
// Decrement followers count
|
||||||
User.update({ _id: followee._id }, {
|
User.update({ _id: followee._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
followers_count: -1
|
followersCount: -1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) =>
|
||||||
// Update lastUsedAt
|
// Update lastUsedAt
|
||||||
User.update({ _id: user._id }, {
|
User.update({ _id: user._id }, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.last_used_at': new Date()
|
'account.lastUsedAt': new Date()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,12 +12,12 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
const _token = token.replace(/\s/g, '');
|
const _token = token.replace(/\s/g, '');
|
||||||
|
|
||||||
if (user.two_factor_temp_secret == null) {
|
if (user.twoFactorTempSecret == null) {
|
||||||
return rej('二段階認証の設定が開始されていません');
|
return rej('二段階認証の設定が開始されていません');
|
||||||
}
|
}
|
||||||
|
|
||||||
const verified = (speakeasy as any).totp.verify({
|
const verified = (speakeasy as any).totp.verify({
|
||||||
secret: user.two_factor_temp_secret,
|
secret: user.twoFactorTempSecret,
|
||||||
encoding: 'base32',
|
encoding: 'base32',
|
||||||
token: _token
|
token: _token
|
||||||
});
|
});
|
||||||
|
@ -28,8 +28,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.two_factor_secret': user.two_factor_temp_secret,
|
'account.twoFactorSecret': user.twoFactorTempSecret,
|
||||||
'account.two_factor_enabled': true
|
'account.twoFactorEnabled': true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
two_factor_temp_secret: secret.base32
|
twoFactorTempSecret: secret.base32
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.two_factor_secret': null,
|
'account.twoFactorSecret': null,
|
||||||
'account.two_factor_enabled': false
|
'account.twoFactorEnabled': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => {
|
||||||
select[`data.${key}`] = true;
|
select[`data.${key}`] = true;
|
||||||
}
|
}
|
||||||
const appdata = await Appdata.findOne({
|
const appdata = await Appdata.findOne({
|
||||||
app_id: app._id,
|
appId: app._id,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
}, {
|
}, {
|
||||||
fields: select
|
fields: select
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,11 +43,11 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
await Appdata.update({
|
await Appdata.update({
|
||||||
app_id: app._id,
|
appId: app._id,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
}, Object.assign({
|
}, Object.assign({
|
||||||
app_id: app._id,
|
appId: app._id,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
}, {
|
}, {
|
||||||
$set: set
|
$set: set
|
||||||
}), {
|
}), {
|
||||||
|
|
|
@ -28,7 +28,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get tokens
|
// Get tokens
|
||||||
const tokens = await AccessToken
|
const tokens = await AccessToken
|
||||||
.find({
|
.find({
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
}, {
|
}, {
|
||||||
limit: limit,
|
limit: limit,
|
||||||
skip: offset,
|
skip: offset,
|
||||||
|
@ -39,5 +39,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
res(await Promise.all(tokens.map(async token =>
|
res(await Promise.all(tokens.map(async token =>
|
||||||
await pack(token.app_id))));
|
await pack(token.appId))));
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,13 +13,13 @@ import User from '../../models/user';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'current_password' parameter
|
// Get 'currentPasword' parameter
|
||||||
const [currentPassword, currentPasswordErr] = $(params.current_password).string().$;
|
const [currentPassword, currentPasswordErr] = $(params.currentPasword).string().$;
|
||||||
if (currentPasswordErr) return rej('invalid current_password param');
|
if (currentPasswordErr) return rej('invalid currentPasword param');
|
||||||
|
|
||||||
// Get 'new_password' parameter
|
// Get 'newPassword' parameter
|
||||||
const [newPassword, newPasswordErr] = $(params.new_password).string().$;
|
const [newPassword, newPasswordErr] = $(params.newPassword).string().$;
|
||||||
if (newPasswordErr) return rej('invalid new_password param');
|
if (newPasswordErr) return rej('invalid newPassword param');
|
||||||
|
|
||||||
// Compare password
|
// Compare password
|
||||||
const same = await bcrypt.compare(currentPassword, user.account.password);
|
const same = await bcrypt.compare(currentPassword, user.account.password);
|
||||||
|
|
|
@ -28,7 +28,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get favorites
|
// Get favorites
|
||||||
const favorites = await Favorite
|
const favorites = await Favorite
|
||||||
.find({
|
.find({
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
}, {
|
}, {
|
||||||
limit: limit,
|
limit: limit,
|
||||||
skip: offset,
|
skip: offset,
|
||||||
|
@ -39,6 +39,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
res(await Promise.all(favorites.map(async favorite =>
|
res(await Promise.all(favorites.map(async favorite =>
|
||||||
await pack(favorite.post)
|
await pack(favorite.postId)
|
||||||
)));
|
)));
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,9 +21,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
$(params.following).optional.boolean().$;
|
$(params.following).optional.boolean().$;
|
||||||
if (followingError) return rej('invalid following param');
|
if (followingError) return rej('invalid following param');
|
||||||
|
|
||||||
// Get 'mark_as_read' parameter
|
// Get 'markAsRead' parameter
|
||||||
const [markAsRead = true, markAsReadErr] = $(params.mark_as_read).optional.boolean().$;
|
const [markAsRead = true, markAsReadErr] = $(params.markAsRead).optional.boolean().$;
|
||||||
if (markAsReadErr) return rej('invalid mark_as_read param');
|
if (markAsReadErr) return rej('invalid markAsRead param');
|
||||||
|
|
||||||
// Get 'type' parameter
|
// Get 'type' parameter
|
||||||
const [type, typeErr] = $(params.type).optional.array('string').unique().$;
|
const [type, typeErr] = $(params.type).optional.array('string').unique().$;
|
||||||
|
@ -33,29 +33,29 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
const mute = await Mute.find({
|
const mute = await Mute.find({
|
||||||
muter_id: user._id,
|
muterId: user._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
notifiee_id: user._id,
|
notifieeId: user._id,
|
||||||
$and: [{
|
$and: [{
|
||||||
notifier_id: {
|
notifierId: {
|
||||||
$nin: mute.map(m => m.mutee_id)
|
$nin: mute.map(m => m.muteeId)
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
} as any;
|
} as any;
|
||||||
|
@ -69,7 +69,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const followingIds = await getFriends(user._id);
|
const followingIds = await getFriends(user._id);
|
||||||
|
|
||||||
query.$and.push({
|
query.$and.push({
|
||||||
notifier_id: {
|
notifierId: {
|
||||||
$in: followingIds
|
$in: followingIds
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,14 +14,14 @@ import { pack } from '../../models/user';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Fetch pinee
|
// Fetch pinee
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
_id: postId,
|
_id: postId,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (post === null) {
|
if (post === null) {
|
||||||
|
@ -30,7 +30,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
pinned_post_id: post._id
|
pinnedPostId: post._id
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,21 +16,21 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
const sort = {
|
const sort = {
|
||||||
|
|
|
@ -36,34 +36,34 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re
|
||||||
if (birthdayErr) return rej('invalid birthday param');
|
if (birthdayErr) return rej('invalid birthday param');
|
||||||
if (birthday !== undefined) user.account.profile.birthday = birthday;
|
if (birthday !== undefined) user.account.profile.birthday = birthday;
|
||||||
|
|
||||||
// Get 'avatar_id' parameter
|
// Get 'avatarId' parameter
|
||||||
const [avatarId, avatarIdErr] = $(params.avatar_id).optional.id().$;
|
const [avatarId, avatarIdErr] = $(params.avatarId).optional.id().$;
|
||||||
if (avatarIdErr) return rej('invalid avatar_id param');
|
if (avatarIdErr) return rej('invalid avatarId param');
|
||||||
if (avatarId) user.avatar_id = avatarId;
|
if (avatarId) user.avatarId = avatarId;
|
||||||
|
|
||||||
// Get 'banner_id' parameter
|
// Get 'bannerId' parameter
|
||||||
const [bannerId, bannerIdErr] = $(params.banner_id).optional.id().$;
|
const [bannerId, bannerIdErr] = $(params.bannerId).optional.id().$;
|
||||||
if (bannerIdErr) return rej('invalid banner_id param');
|
if (bannerIdErr) return rej('invalid bannerId param');
|
||||||
if (bannerId) user.banner_id = bannerId;
|
if (bannerId) user.bannerId = bannerId;
|
||||||
|
|
||||||
// Get 'is_bot' parameter
|
// Get 'isBot' parameter
|
||||||
const [isBot, isBotErr] = $(params.is_bot).optional.boolean().$;
|
const [isBot, isBotErr] = $(params.isBot).optional.boolean().$;
|
||||||
if (isBotErr) return rej('invalid is_bot param');
|
if (isBotErr) return rej('invalid isBot param');
|
||||||
if (isBot != null) user.account.is_bot = isBot;
|
if (isBot != null) user.account.isBot = isBot;
|
||||||
|
|
||||||
// Get 'auto_watch' parameter
|
// Get 'autoWatch' parameter
|
||||||
const [autoWatch, autoWatchErr] = $(params.auto_watch).optional.boolean().$;
|
const [autoWatch, autoWatchErr] = $(params.autoWatch).optional.boolean().$;
|
||||||
if (autoWatchErr) return rej('invalid auto_watch param');
|
if (autoWatchErr) return rej('invalid autoWatch param');
|
||||||
if (autoWatch != null) user.account.settings.auto_watch = autoWatch;
|
if (autoWatch != null) user.account.settings.autoWatch = autoWatch;
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
name: user.name,
|
name: user.name,
|
||||||
description: user.description,
|
description: user.description,
|
||||||
avatar_id: user.avatar_id,
|
avatarId: user.avatarId,
|
||||||
banner_id: user.banner_id,
|
bannerId: user.bannerId,
|
||||||
'account.profile': user.account.profile,
|
'account.profile': user.account.profile,
|
||||||
'account.is_bot': user.account.is_bot,
|
'account.isBot': user.account.isBot,
|
||||||
'account.settings': user.account.settings
|
'account.settings': user.account.settings
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,14 +22,14 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (valueErr) return rej('invalid value param');
|
if (valueErr) return rej('invalid value param');
|
||||||
|
|
||||||
const x = {};
|
const x = {};
|
||||||
x[`account.client_settings.${name}`] = value;
|
x[`account.clientSettings.${name}`] = value;
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: x
|
$set: x
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
user.account.client_settings[name] = value;
|
user.account.clientSettings[name] = value;
|
||||||
const iObj = await pack(user, user, {
|
const iObj = await pack(user, user, {
|
||||||
detail: true,
|
detail: true,
|
||||||
includeSecrets: true
|
includeSecrets: true
|
||||||
|
|
|
@ -26,7 +26,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (home) {
|
if (home) {
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.client_settings.home': home
|
'account.clientSettings.home': home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
} else {
|
} else {
|
||||||
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
||||||
|
|
||||||
const _home = user.account.client_settings.home;
|
const _home = user.account.clientSettings.home;
|
||||||
const widget = _home.find(w => w.id == id);
|
const widget = _home.find(w => w.id == id);
|
||||||
|
|
||||||
if (widget == null) return rej('widget not found');
|
if (widget == null) return rej('widget not found');
|
||||||
|
@ -47,7 +47,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.client_settings.home': _home
|
'account.clientSettings.home': _home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (home) {
|
if (home) {
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.client_settings.mobile_home': home
|
'account.clientSettings.mobile_home': home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
} else {
|
} else {
|
||||||
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
||||||
|
|
||||||
const _home = user.account.client_settings.mobile_home || [];
|
const _home = user.account.clientSettings.mobile_home || [];
|
||||||
const widget = _home.find(w => w.id == id);
|
const widget = _home.find(w => w.id == id);
|
||||||
|
|
||||||
if (widget == null) return rej('widget not found');
|
if (widget == null) return rej('widget not found');
|
||||||
|
@ -46,7 +46,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'account.client_settings.mobile_home': _home
|
'account.clientSettings.mobile_home': _home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,25 +19,25 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
const mute = await Mute.find({
|
const mute = await Mute.find({
|
||||||
muter_id: user._id,
|
muterId: user._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get history
|
// Get history
|
||||||
const history = await History
|
const history = await History
|
||||||
.find({
|
.find({
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
partner: {
|
partnerId: {
|
||||||
$nin: mute.map(m => m.mutee_id)
|
$nin: mute.map(m => m.muteeId)
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
limit: limit,
|
limit: limit,
|
||||||
sort: {
|
sort: {
|
||||||
updated_at: -1
|
updatedAt: -1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
res(await Promise.all(history.map(async h =>
|
res(await Promise.all(history.map(async h =>
|
||||||
await pack(h.message, user))));
|
await pack(h.messageId, user))));
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,9 +15,9 @@ import read from '../../common/read-messaging-message';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [recipientId, recipientIdErr] = $(params.user_id).id().$;
|
const [recipientId, recipientIdErr] = $(params.userId).id().$;
|
||||||
if (recipientIdErr) return rej('invalid user_id param');
|
if (recipientIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Fetch recipient
|
// Fetch recipient
|
||||||
const recipient = await User.findOne({
|
const recipient = await User.findOne({
|
||||||
|
@ -32,34 +32,34 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
return rej('user not found');
|
return rej('user not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'mark_as_read' parameter
|
// Get 'markAsRead' parameter
|
||||||
const [markAsRead = true, markAsReadErr] = $(params.mark_as_read).optional.boolean().$;
|
const [markAsRead = true, markAsReadErr] = $(params.markAsRead).optional.boolean().$;
|
||||||
if (markAsReadErr) return rej('invalid mark_as_read param');
|
if (markAsReadErr) return rej('invalid markAsRead param');
|
||||||
|
|
||||||
// Get 'limit' parameter
|
// Get 'limit' parameter
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
$or: [{
|
$or: [{
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
recipient_id: recipient._id
|
recipientId: recipient._id
|
||||||
}, {
|
}, {
|
||||||
user_id: recipient._id,
|
userId: recipient._id,
|
||||||
recipient_id: user._id
|
recipientId: user._id
|
||||||
}]
|
}]
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ import config from '../../../../../conf';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [recipientId, recipientIdErr] = $(params.user_id).id().$;
|
const [recipientId, recipientIdErr] = $(params.userId).id().$;
|
||||||
if (recipientIdErr) return rej('invalid user_id param');
|
if (recipientIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Myself
|
// Myself
|
||||||
if (recipientId.equals(user._id)) {
|
if (recipientId.equals(user._id)) {
|
||||||
|
@ -47,15 +47,15 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
|
const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
|
||||||
if (textErr) return rej('invalid text');
|
if (textErr) return rej('invalid text');
|
||||||
|
|
||||||
// Get 'file_id' parameter
|
// Get 'fileId' parameter
|
||||||
const [fileId, fileIdErr] = $(params.file_id).optional.id().$;
|
const [fileId, fileIdErr] = $(params.fileId).optional.id().$;
|
||||||
if (fileIdErr) return rej('invalid file_id param');
|
if (fileIdErr) return rej('invalid fileId param');
|
||||||
|
|
||||||
let file = null;
|
let file = null;
|
||||||
if (fileId !== undefined) {
|
if (fileId !== undefined) {
|
||||||
file = await DriveFile.findOne({
|
file = await DriveFile.findOne({
|
||||||
_id: fileId,
|
_id: fileId,
|
||||||
'metadata.user_id': user._id
|
'metadata.userId': user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (file === null) {
|
if (file === null) {
|
||||||
|
@ -70,12 +70,12 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// メッセージを作成
|
// メッセージを作成
|
||||||
const message = await Message.insert({
|
const message = await Message.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
file_id: file ? file._id : undefined,
|
fileId: file ? file._id : undefined,
|
||||||
recipient_id: recipient._id,
|
recipientId: recipient._id,
|
||||||
text: text ? text : undefined,
|
text: text ? text : undefined,
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
is_read: false
|
isRead: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
|
@ -85,32 +85,32 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
res(messageObj);
|
res(messageObj);
|
||||||
|
|
||||||
// 自分のストリーム
|
// 自分のストリーム
|
||||||
publishMessagingStream(message.user_id, message.recipient_id, 'message', messageObj);
|
publishMessagingStream(message.userId, message.recipientId, 'message', messageObj);
|
||||||
publishMessagingIndexStream(message.user_id, 'message', messageObj);
|
publishMessagingIndexStream(message.userId, 'message', messageObj);
|
||||||
publishUserStream(message.user_id, 'messaging_message', messageObj);
|
publishUserStream(message.userId, 'messaging_message', messageObj);
|
||||||
|
|
||||||
// 相手のストリーム
|
// 相手のストリーム
|
||||||
publishMessagingStream(message.recipient_id, message.user_id, 'message', messageObj);
|
publishMessagingStream(message.recipientId, message.userId, 'message', messageObj);
|
||||||
publishMessagingIndexStream(message.recipient_id, 'message', messageObj);
|
publishMessagingIndexStream(message.recipientId, 'message', messageObj);
|
||||||
publishUserStream(message.recipient_id, 'messaging_message', messageObj);
|
publishUserStream(message.recipientId, 'messaging_message', messageObj);
|
||||||
|
|
||||||
// 3秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する
|
// 3秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const freshMessage = await Message.findOne({ _id: message._id }, { is_read: true });
|
const freshMessage = await Message.findOne({ _id: message._id }, { isRead: true });
|
||||||
if (!freshMessage.is_read) {
|
if (!freshMessage.isRead) {
|
||||||
//#region ただしミュートされているなら発行しない
|
//#region ただしミュートされているなら発行しない
|
||||||
const mute = await Mute.find({
|
const mute = await Mute.find({
|
||||||
muter_id: recipient._id,
|
muterId: recipient._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
const mutedUserIds = mute.map(m => m.mutee_id.toString());
|
const mutedUserIds = mute.map(m => m.muteeId.toString());
|
||||||
if (mutedUserIds.indexOf(user._id.toString()) != -1) {
|
if (mutedUserIds.indexOf(user._id.toString()) != -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
publishUserStream(message.recipient_id, 'unread_messaging_message', messageObj);
|
publishUserStream(message.recipientId, 'unread_messaging_message', messageObj);
|
||||||
pushSw(message.recipient_id, 'unread_messaging_message', messageObj);
|
pushSw(message.recipientId, 'unread_messaging_message', messageObj);
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
|
@ -130,26 +130,26 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// 履歴作成(自分)
|
// 履歴作成(自分)
|
||||||
History.update({
|
History.update({
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
partner: recipient._id
|
partnerId: recipient._id
|
||||||
}, {
|
}, {
|
||||||
updated_at: new Date(),
|
updatedAt: new Date(),
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
partner: recipient._id,
|
partnerId: recipient._id,
|
||||||
message: message._id
|
messageId: message._id
|
||||||
}, {
|
}, {
|
||||||
upsert: true
|
upsert: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// 履歴作成(相手)
|
// 履歴作成(相手)
|
||||||
History.update({
|
History.update({
|
||||||
user_id: recipient._id,
|
userId: recipient._id,
|
||||||
partner: user._id
|
partnerId: user._id
|
||||||
}, {
|
}, {
|
||||||
updated_at: new Date(),
|
updatedAt: new Date(),
|
||||||
user_id: recipient._id,
|
userId: recipient._id,
|
||||||
partner: user._id,
|
partnerId: user._id,
|
||||||
message: message._id
|
messageId: message._id
|
||||||
}, {
|
}, {
|
||||||
upsert: true
|
upsert: true
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,18 +13,18 @@ import Mute from '../../models/mute';
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const mute = await Mute.find({
|
const mute = await Mute.find({
|
||||||
muter_id: user._id,
|
muterId: user._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
const mutedUserIds = mute.map(m => m.mutee_id);
|
const mutedUserIds = mute.map(m => m.muteeId);
|
||||||
|
|
||||||
const count = await Message
|
const count = await Message
|
||||||
.count({
|
.count({
|
||||||
user_id: {
|
userId: {
|
||||||
$nin: mutedUserIds
|
$nin: mutedUserIds
|
||||||
},
|
},
|
||||||
recipient_id: user._id,
|
recipientId: user._id,
|
||||||
is_read: false
|
isRead: false
|
||||||
});
|
});
|
||||||
|
|
||||||
res({
|
res({
|
||||||
|
|
|
@ -53,7 +53,6 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
model: os.cpus()[0].model,
|
model: os.cpus()[0].model,
|
||||||
cores: os.cpus().length
|
cores: os.cpus().length
|
||||||
},
|
},
|
||||||
top_image: meta.top_image,
|
|
||||||
broadcasts: meta.broadcasts
|
broadcasts: meta.broadcasts
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,9 +15,9 @@ import Mute from '../../models/mute';
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const muter = user;
|
const muter = user;
|
||||||
|
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// 自分自身
|
// 自分自身
|
||||||
if (user._id.equals(userId)) {
|
if (user._id.equals(userId)) {
|
||||||
|
@ -40,9 +40,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Check if already muting
|
// Check if already muting
|
||||||
const exist = await Mute.findOne({
|
const exist = await Mute.findOne({
|
||||||
muter_id: muter._id,
|
muterId: muter._id,
|
||||||
mutee_id: mutee._id,
|
muteeId: mutee._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist !== null) {
|
if (exist !== null) {
|
||||||
|
@ -51,9 +51,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create mute
|
// Create mute
|
||||||
await Mute.insert({
|
await Mute.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
muter_id: muter._id,
|
muterId: muter._id,
|
||||||
mutee_id: mutee._id,
|
muteeId: mutee._id,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
|
|
|
@ -15,9 +15,9 @@ import Mute from '../../models/mute';
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const muter = user;
|
const muter = user;
|
||||||
|
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [userId, userIdErr] = $(params.user_id).id().$;
|
const [userId, userIdErr] = $(params.userId).id().$;
|
||||||
if (userIdErr) return rej('invalid user_id param');
|
if (userIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Check if the mutee is yourself
|
// Check if the mutee is yourself
|
||||||
if (user._id.equals(userId)) {
|
if (user._id.equals(userId)) {
|
||||||
|
@ -40,9 +40,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Check not muting
|
// Check not muting
|
||||||
const exist = await Mute.findOne({
|
const exist = await Mute.findOne({
|
||||||
muter_id: muter._id,
|
muterId: muter._id,
|
||||||
mutee_id: mutee._id,
|
muteeId: mutee._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist === null) {
|
if (exist === null) {
|
||||||
|
@ -54,7 +54,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
_id: exist._id
|
_id: exist._id
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
deleted_at: new Date()
|
deletedAt: new Date()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -28,15 +28,15 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Construct query
|
// Construct query
|
||||||
const query = {
|
const query = {
|
||||||
muter_id: me._id,
|
muterId: me._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
if (iknow) {
|
if (iknow) {
|
||||||
// Get my friends
|
// Get my friends
|
||||||
const myFriends = await getFriends(me._id);
|
const myFriends = await getFriends(me._id);
|
||||||
|
|
||||||
query.mutee_id = {
|
query.muteeId = {
|
||||||
$in: myFriends
|
$in: myFriends
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
const users = await Promise.all(mutes.map(async m =>
|
const users = await Promise.all(mutes.map(async m =>
|
||||||
await pack(m.mutee_id, me, { detail: true })));
|
await pack(m.muteeId, me, { detail: true })));
|
||||||
|
|
||||||
// Response
|
// Response
|
||||||
res({
|
res({
|
||||||
|
|
|
@ -21,7 +21,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
if (offsetErr) return rej('invalid offset param');
|
if (offsetErr) return rej('invalid offset param');
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute query
|
// Execute query
|
||||||
|
|
|
@ -13,18 +13,18 @@ import Mute from '../../models/mute';
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const mute = await Mute.find({
|
const mute = await Mute.find({
|
||||||
muter_id: user._id,
|
muterId: user._id,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
const mutedUserIds = mute.map(m => m.mutee_id);
|
const mutedUserIds = mute.map(m => m.muteeId);
|
||||||
|
|
||||||
const count = await Notification
|
const count = await Notification
|
||||||
.count({
|
.count({
|
||||||
notifiee_id: user._id,
|
notifieeId: user._id,
|
||||||
notifier_id: {
|
notifierId: {
|
||||||
$nin: mutedUserIds
|
$nin: mutedUserIds
|
||||||
},
|
},
|
||||||
is_read: false
|
isRead: false
|
||||||
});
|
});
|
||||||
|
|
||||||
res({
|
res({
|
||||||
|
|
|
@ -14,11 +14,11 @@ import event from '../../event';
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Update documents
|
// Update documents
|
||||||
await Notification.update({
|
await Notification.update({
|
||||||
notifiee_id: user._id,
|
notifieeId: user._id,
|
||||||
is_read: false
|
isRead: false
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
is_read: true
|
isRead: true
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
multi: true
|
multi: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import $ from 'cafy';
|
import $ from 'cafy';
|
||||||
import Game, { pack } from '../../models/othello-game';
|
import OthelloGame, { pack } from '../../models/othello-game';
|
||||||
|
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'my' parameter
|
// Get 'my' parameter
|
||||||
|
@ -10,28 +10,28 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
const q: any = my ? {
|
const q: any = my ? {
|
||||||
is_started: true,
|
isStarted: true,
|
||||||
$or: [{
|
$or: [{
|
||||||
user1_id: user._id
|
user1Id: user._id
|
||||||
}, {
|
}, {
|
||||||
user2_id: user._id
|
user2Id: user._id
|
||||||
}]
|
}]
|
||||||
} : {
|
} : {
|
||||||
is_started: true
|
isStarted: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const sort = {
|
const sort = {
|
||||||
|
@ -50,7 +50,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch games
|
// Fetch games
|
||||||
const games = await Game.find(q, {
|
const games = await OthelloGame.find(q, {
|
||||||
sort,
|
sort,
|
||||||
limit
|
limit
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import $ from 'cafy';
|
import $ from 'cafy';
|
||||||
import Game, { pack } from '../../../models/othello-game';
|
import OthelloGame, { pack } from '../../../models/othello-game';
|
||||||
import Othello from '../../../../common/othello/core';
|
import Othello from '../../../../common/othello/core';
|
||||||
|
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'game_id' parameter
|
// Get 'gameId' parameter
|
||||||
const [gameId, gameIdErr] = $(params.game_id).id().$;
|
const [gameId, gameIdErr] = $(params.gameId).id().$;
|
||||||
if (gameIdErr) return rej('invalid game_id param');
|
if (gameIdErr) return rej('invalid gameId param');
|
||||||
|
|
||||||
const game = await Game.findOne({ _id: gameId });
|
const game = await OthelloGame.findOne({ _id: gameId });
|
||||||
|
|
||||||
if (game == null) {
|
if (game == null) {
|
||||||
return rej('game not found');
|
return rej('game not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const o = new Othello(game.settings.map, {
|
const o = new Othello(game.settings.map, {
|
||||||
isLlotheo: game.settings.is_llotheo,
|
isLlotheo: game.settings.isLlotheo,
|
||||||
canPutEverywhere: game.settings.can_put_everywhere,
|
canPutEverywhere: game.settings.canPutEverywhere,
|
||||||
loopedBoard: game.settings.looped_board
|
loopedBoard: game.settings.loopedBoard
|
||||||
});
|
});
|
||||||
|
|
||||||
game.logs.forEach(log => {
|
game.logs.forEach(log => {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Matching, { pack as packMatching } from '../../models/othello-matching';
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Find session
|
// Find session
|
||||||
const invitations = await Matching.find({
|
const invitations = await Matching.find({
|
||||||
child_id: user._id
|
childId: user._id
|
||||||
}, {
|
}, {
|
||||||
sort: {
|
sort: {
|
||||||
_id: -1
|
_id: -1
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import $ from 'cafy';
|
import $ from 'cafy';
|
||||||
import Matching, { pack as packMatching } from '../../models/othello-matching';
|
import Matching, { pack as packMatching } from '../../models/othello-matching';
|
||||||
import Game, { pack as packGame } from '../../models/othello-game';
|
import OthelloGame, { pack as packGame } from '../../models/othello-game';
|
||||||
import User from '../../models/user';
|
import User from '../../models/user';
|
||||||
import publishUserStream, { publishOthelloStream } from '../../event';
|
import publishUserStream, { publishOthelloStream } from '../../event';
|
||||||
import { eighteight } from '../../../common/othello/maps';
|
import { eighteight } from '../../../common/othello/maps';
|
||||||
|
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'user_id' parameter
|
// Get 'userId' parameter
|
||||||
const [childId, childIdErr] = $(params.user_id).id().$;
|
const [childId, childIdErr] = $(params.userId).id().$;
|
||||||
if (childIdErr) return rej('invalid user_id param');
|
if (childIdErr) return rej('invalid userId param');
|
||||||
|
|
||||||
// Myself
|
// Myself
|
||||||
if (childId.equals(user._id)) {
|
if (childId.equals(user._id)) {
|
||||||
return rej('invalid user_id param');
|
return rej('invalid userId param');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find session
|
// Find session
|
||||||
const exist = await Matching.findOne({
|
const exist = await Matching.findOne({
|
||||||
parent_id: childId,
|
parentId: childId,
|
||||||
child_id: user._id
|
childId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist) {
|
if (exist) {
|
||||||
|
@ -28,29 +28,29 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create game
|
// Create game
|
||||||
const game = await Game.insert({
|
const game = await OthelloGame.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
user1_id: exist.parent_id,
|
user1Id: exist.parentId,
|
||||||
user2_id: user._id,
|
user2Id: user._id,
|
||||||
user1_accepted: false,
|
user1Accepted: false,
|
||||||
user2_accepted: false,
|
user2Accepted: false,
|
||||||
is_started: false,
|
isStarted: false,
|
||||||
is_ended: false,
|
isEnded: false,
|
||||||
logs: [],
|
logs: [],
|
||||||
settings: {
|
settings: {
|
||||||
map: eighteight.data,
|
map: eighteight.data,
|
||||||
bw: 'random',
|
bw: 'random',
|
||||||
is_llotheo: false
|
isLlotheo: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reponse
|
// Reponse
|
||||||
res(await packGame(game, user));
|
res(await packGame(game, user));
|
||||||
|
|
||||||
publishOthelloStream(exist.parent_id, 'matched', await packGame(game, exist.parent_id));
|
publishOthelloStream(exist.parentId, 'matched', await packGame(game, exist.parentId));
|
||||||
|
|
||||||
const other = await Matching.count({
|
const other = await Matching.count({
|
||||||
child_id: user._id
|
childId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (other == 0) {
|
if (other == 0) {
|
||||||
|
@ -72,14 +72,14 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// 以前のセッションはすべて削除しておく
|
// 以前のセッションはすべて削除しておく
|
||||||
await Matching.remove({
|
await Matching.remove({
|
||||||
parent_id: user._id
|
parentId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// セッションを作成
|
// セッションを作成
|
||||||
const matching = await Matching.insert({
|
const matching = await Matching.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
parent_id: user._id,
|
parentId: user._id,
|
||||||
child_id: child._id
|
childId: child._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reponse
|
// Reponse
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Matching from '../../../models/othello-matching';
|
||||||
|
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
await Matching.remove({
|
await Matching.remove({
|
||||||
parent_id: user._id
|
parentId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
res();
|
res();
|
||||||
|
|
|
@ -35,17 +35,17 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
if (limitErr) return rej('invalid limit param');
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Get 'since_id' parameter
|
// Get 'sinceId' parameter
|
||||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
|
||||||
if (sinceIdErr) return rej('invalid since_id param');
|
if (sinceIdErr) return rej('invalid sinceId param');
|
||||||
|
|
||||||
// Get 'until_id' parameter
|
// Get 'untilId' parameter
|
||||||
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
|
const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
|
||||||
if (untilIdErr) return rej('invalid until_id param');
|
if (untilIdErr) return rej('invalid untilId param');
|
||||||
|
|
||||||
// Check if both of since_id and until_id is specified
|
// Check if both of sinceId and untilId is specified
|
||||||
if (sinceId && untilId) {
|
if (sinceId && untilId) {
|
||||||
return rej('cannot set since_id and until_id');
|
return rej('cannot set sinceId and untilId');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct query
|
// Construct query
|
||||||
|
@ -65,15 +65,15 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reply != undefined) {
|
if (reply != undefined) {
|
||||||
query.reply_id = reply ? { $exists: true, $ne: null } : null;
|
query.replyId = reply ? { $exists: true, $ne: null } : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (repost != undefined) {
|
if (repost != undefined) {
|
||||||
query.repost_id = repost ? { $exists: true, $ne: null } : null;
|
query.repostId = repost ? { $exists: true, $ne: null } : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media != undefined) {
|
if (media != undefined) {
|
||||||
query.media_ids = media ? { $exists: true, $ne: null } : null;
|
query.mediaIds = media ? { $exists: true, $ne: null } : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (poll != undefined) {
|
if (poll != undefined) {
|
||||||
|
@ -82,7 +82,7 @@ module.exports = (params) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
//if (bot != undefined) {
|
//if (bot != undefined) {
|
||||||
// query.is_bot = bot;
|
// query.isBot = bot;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Issue query
|
// Issue query
|
||||||
|
|
|
@ -12,13 +12,13 @@ import Post from '../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
if (!user.account.is_pro) {
|
if (!user.account.isPro) {
|
||||||
return rej('This endpoint is available only from a Pro account');
|
return rej('This endpoint is available only from a Pro account');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Get categorizee
|
// Get categorizee
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
|
|
|
@ -12,9 +12,9 @@ import Post, { pack } from '../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Get 'limit' parameter
|
// Get 'limit' parameter
|
||||||
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
|
||||||
|
@ -48,13 +48,13 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.reply_id) {
|
if (p.replyId) {
|
||||||
await get(p.reply_id);
|
await get(p.replyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post.reply_id) {
|
if (post.replyId) {
|
||||||
await get(post.reply_id);
|
await get(post.replyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
|
|
|
@ -33,9 +33,9 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
|
const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
|
||||||
if (textErr) return rej('invalid text');
|
if (textErr) return rej('invalid text');
|
||||||
|
|
||||||
// Get 'via_mobile' parameter
|
// Get 'viaMobile' parameter
|
||||||
const [viaMobile = false, viaMobileErr] = $(params.via_mobile).optional.boolean().$;
|
const [viaMobile = false, viaMobileErr] = $(params.viaMobile).optional.boolean().$;
|
||||||
if (viaMobileErr) return rej('invalid via_mobile');
|
if (viaMobileErr) return rej('invalid viaMobile');
|
||||||
|
|
||||||
// Get 'tags' parameter
|
// Get 'tags' parameter
|
||||||
const [tags = [], tagsErr] = $(params.tags).optional.array('string').unique().eachQ(t => t.range(1, 32)).$;
|
const [tags = [], tagsErr] = $(params.tags).optional.array('string').unique().eachQ(t => t.range(1, 32)).$;
|
||||||
|
@ -53,9 +53,9 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
.$;
|
.$;
|
||||||
if (geoErr) return rej('invalid geo');
|
if (geoErr) return rej('invalid geo');
|
||||||
|
|
||||||
// Get 'media_ids' parameter
|
// Get 'mediaIds' parameter
|
||||||
const [mediaIds, mediaIdsErr] = $(params.media_ids).optional.array('id').unique().range(1, 4).$;
|
const [mediaIds, mediaIdsErr] = $(params.mediaIds).optional.array('id').unique().range(1, 4).$;
|
||||||
if (mediaIdsErr) return rej('invalid media_ids');
|
if (mediaIdsErr) return rej('invalid mediaIds');
|
||||||
|
|
||||||
let files = [];
|
let files = [];
|
||||||
if (mediaIds !== undefined) {
|
if (mediaIds !== undefined) {
|
||||||
|
@ -67,7 +67,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
// SELECT _id
|
// SELECT _id
|
||||||
const entity = await DriveFile.findOne({
|
const entity = await DriveFile.findOne({
|
||||||
_id: mediaId,
|
_id: mediaId,
|
||||||
'metadata.user_id': user._id
|
'metadata.userId': user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (entity === null) {
|
if (entity === null) {
|
||||||
|
@ -80,9 +80,9 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
files = null;
|
files = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'repost_id' parameter
|
// Get 'repostId' parameter
|
||||||
const [repostId, repostIdErr] = $(params.repost_id).optional.id().$;
|
const [repostId, repostIdErr] = $(params.repostId).optional.id().$;
|
||||||
if (repostIdErr) return rej('invalid repost_id');
|
if (repostIdErr) return rej('invalid repostId');
|
||||||
|
|
||||||
let repost: IPost = null;
|
let repost: IPost = null;
|
||||||
let isQuote = false;
|
let isQuote = false;
|
||||||
|
@ -94,13 +94,13 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
if (repost == null) {
|
if (repost == null) {
|
||||||
return rej('repostee is not found');
|
return rej('repostee is not found');
|
||||||
} else if (repost.repost_id && !repost.text && !repost.media_ids) {
|
} else if (repost.repostId && !repost.text && !repost.mediaIds) {
|
||||||
return rej('cannot repost to repost');
|
return rej('cannot repost to repost');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch recently post
|
// Fetch recently post
|
||||||
const latestPost = await Post.findOne({
|
const latestPost = await Post.findOne({
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
}, {
|
}, {
|
||||||
sort: {
|
sort: {
|
||||||
_id: -1
|
_id: -1
|
||||||
|
@ -111,8 +111,8 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// 直近と同じRepost対象かつ引用じゃなかったらエラー
|
// 直近と同じRepost対象かつ引用じゃなかったらエラー
|
||||||
if (latestPost &&
|
if (latestPost &&
|
||||||
latestPost.repost_id &&
|
latestPost.repostId &&
|
||||||
latestPost.repost_id.equals(repost._id) &&
|
latestPost.repostId.equals(repost._id) &&
|
||||||
!isQuote) {
|
!isQuote) {
|
||||||
return rej('cannot repost same post that already reposted in your latest post');
|
return rej('cannot repost same post that already reposted in your latest post');
|
||||||
}
|
}
|
||||||
|
@ -125,9 +125,9 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'reply_id' parameter
|
// Get 'replyId' parameter
|
||||||
const [replyId, replyIdErr] = $(params.reply_id).optional.id().$;
|
const [replyId, replyIdErr] = $(params.replyId).optional.id().$;
|
||||||
if (replyIdErr) return rej('invalid reply_id');
|
if (replyIdErr) return rej('invalid replyId');
|
||||||
|
|
||||||
let reply: IPost = null;
|
let reply: IPost = null;
|
||||||
if (replyId !== undefined) {
|
if (replyId !== undefined) {
|
||||||
|
@ -141,14 +141,14 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返信対象が引用でないRepostだったらエラー
|
// 返信対象が引用でないRepostだったらエラー
|
||||||
if (reply.repost_id && !reply.text && !reply.media_ids) {
|
if (reply.repostId && !reply.text && !reply.mediaIds) {
|
||||||
return rej('cannot reply to repost');
|
return rej('cannot reply to repost');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'channel_id' parameter
|
// Get 'channelId' parameter
|
||||||
const [channelId, channelIdErr] = $(params.channel_id).optional.id().$;
|
const [channelId, channelIdErr] = $(params.channelId).optional.id().$;
|
||||||
if (channelIdErr) return rej('invalid channel_id');
|
if (channelIdErr) return rej('invalid channelId');
|
||||||
|
|
||||||
let channel: IChannel = null;
|
let channel: IChannel = null;
|
||||||
if (channelId !== undefined) {
|
if (channelId !== undefined) {
|
||||||
|
@ -162,12 +162,12 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返信対象の投稿がこのチャンネルじゃなかったらダメ
|
// 返信対象の投稿がこのチャンネルじゃなかったらダメ
|
||||||
if (reply && !channelId.equals(reply.channel_id)) {
|
if (reply && !channelId.equals(reply.channelId)) {
|
||||||
return rej('チャンネル内部からチャンネル外部の投稿に返信することはできません');
|
return rej('チャンネル内部からチャンネル外部の投稿に返信することはできません');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repost対象の投稿がこのチャンネルじゃなかったらダメ
|
// Repost対象の投稿がこのチャンネルじゃなかったらダメ
|
||||||
if (repost && !channelId.equals(repost.channel_id)) {
|
if (repost && !channelId.equals(repost.channelId)) {
|
||||||
return rej('チャンネル内部からチャンネル外部の投稿をRepostすることはできません');
|
return rej('チャンネル内部からチャンネル外部の投稿をRepostすることはできません');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,12 +177,12 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 返信対象の投稿がチャンネルへの投稿だったらダメ
|
// 返信対象の投稿がチャンネルへの投稿だったらダメ
|
||||||
if (reply && reply.channel_id != null) {
|
if (reply && reply.channelId != null) {
|
||||||
return rej('チャンネル外部からチャンネル内部の投稿に返信することはできません');
|
return rej('チャンネル外部からチャンネル内部の投稿に返信することはできません');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repost対象の投稿がチャンネルへの投稿だったらダメ
|
// Repost対象の投稿がチャンネルへの投稿だったらダメ
|
||||||
if (repost && repost.channel_id != null) {
|
if (repost && repost.channelId != null) {
|
||||||
return rej('チャンネル外部からチャンネル内部の投稿をRepostすることはできません');
|
return rej('チャンネル外部からチャンネル内部の投稿をRepostすることはできません');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,22 +206,22 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// テキストが無いかつ添付ファイルが無いかつRepostも無いかつ投票も無かったらエラー
|
// テキストが無いかつ添付ファイルが無いかつRepostも無いかつ投票も無かったらエラー
|
||||||
if (text === undefined && files === null && repost === null && poll === undefined) {
|
if (text === undefined && files === null && repost === null && poll === undefined) {
|
||||||
return rej('text, media_ids, repost_id or poll is required');
|
return rej('text, mediaIds, repostId or poll is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直近の投稿と重複してたらエラー
|
// 直近の投稿と重複してたらエラー
|
||||||
// TODO: 直近の投稿が一日前くらいなら重複とは見なさない
|
// TODO: 直近の投稿が一日前くらいなら重複とは見なさない
|
||||||
if (user.latest_post) {
|
if (user.latestPost) {
|
||||||
if (deepEqual({
|
if (deepEqual({
|
||||||
text: user.latest_post.text,
|
text: user.latestPost.text,
|
||||||
reply: user.latest_post.reply_id ? user.latest_post.reply_id.toString() : null,
|
reply: user.latestPost.replyId ? user.latestPost.replyId.toString() : null,
|
||||||
repost: user.latest_post.repost_id ? user.latest_post.repost_id.toString() : null,
|
repost: user.latestPost.repostId ? user.latestPost.repostId.toString() : null,
|
||||||
media_ids: (user.latest_post.media_ids || []).map(id => id.toString())
|
mediaIds: (user.latestPost.mediaIds || []).map(id => id.toString())
|
||||||
}, {
|
}, {
|
||||||
text: text,
|
text: text,
|
||||||
reply: reply ? reply._id.toString() : null,
|
reply: reply ? reply._id.toString() : null,
|
||||||
repost: repost ? repost._id.toString() : null,
|
repost: repost ? repost._id.toString() : null,
|
||||||
media_ids: (files || []).map(file => file._id.toString())
|
mediaIds: (files || []).map(file => file._id.toString())
|
||||||
})) {
|
})) {
|
||||||
return rej('duplicate');
|
return rej('duplicate');
|
||||||
}
|
}
|
||||||
|
@ -246,23 +246,23 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// 投稿を作成
|
// 投稿を作成
|
||||||
const post = await Post.insert({
|
const post = await Post.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
channel_id: channel ? channel._id : undefined,
|
channelId: channel ? channel._id : undefined,
|
||||||
index: channel ? channel.index + 1 : undefined,
|
index: channel ? channel.index + 1 : undefined,
|
||||||
media_ids: files ? files.map(file => file._id) : undefined,
|
mediaIds: files ? files.map(file => file._id) : undefined,
|
||||||
reply_id: reply ? reply._id : undefined,
|
replyId: reply ? reply._id : undefined,
|
||||||
repost_id: repost ? repost._id : undefined,
|
repostId: repost ? repost._id : undefined,
|
||||||
poll: poll,
|
poll: poll,
|
||||||
text: text,
|
text: text,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
app_id: app ? app._id : null,
|
appId: app ? app._id : null,
|
||||||
via_mobile: viaMobile,
|
viaMobile: viaMobile,
|
||||||
geo,
|
geo,
|
||||||
|
|
||||||
// 以下非正規化データ
|
// 以下非正規化データ
|
||||||
_reply: reply ? { user_id: reply.user_id } : undefined,
|
_reply: reply ? { userId: reply.userId } : undefined,
|
||||||
_repost: repost ? { user_id: repost.user_id } : undefined,
|
_repost: repost ? { userId: repost.userId } : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
|
@ -270,14 +270,14 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Reponse
|
// Reponse
|
||||||
res({
|
res({
|
||||||
created_post: postObj
|
createdPost: postObj
|
||||||
});
|
});
|
||||||
|
|
||||||
//#region Post processes
|
//#region Post processes
|
||||||
|
|
||||||
User.update({ _id: user._id }, {
|
User.update({ _id: user._id }, {
|
||||||
$set: {
|
$set: {
|
||||||
latest_post: post
|
latestPost: post
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -293,10 +293,10 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
// Publish event
|
// Publish event
|
||||||
if (!user._id.equals(mentionee)) {
|
if (!user._id.equals(mentionee)) {
|
||||||
const mentioneeMutes = await Mute.find({
|
const mentioneeMutes = await Mute.find({
|
||||||
muter_id: mentionee,
|
muterId: mentionee,
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
const mentioneesMutedUserIds = mentioneeMutes.map(m => m.mutee_id.toString());
|
const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId.toString());
|
||||||
if (mentioneesMutedUserIds.indexOf(user._id.toString()) == -1) {
|
if (mentioneesMutedUserIds.indexOf(user._id.toString()) == -1) {
|
||||||
event(mentionee, reason, postObj);
|
event(mentionee, reason, postObj);
|
||||||
pushSw(mentionee, reason, postObj);
|
pushSw(mentionee, reason, postObj);
|
||||||
|
@ -312,17 +312,17 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
// Fetch all followers
|
// Fetch all followers
|
||||||
const followers = await Following
|
const followers = await Following
|
||||||
.find({
|
.find({
|
||||||
followee_id: user._id,
|
followeeId: user._id,
|
||||||
// 削除されたドキュメントは除く
|
// 削除されたドキュメントは除く
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
}, {
|
}, {
|
||||||
follower_id: true,
|
followerId: true,
|
||||||
_id: false
|
_id: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publish event to followers stream
|
// Publish event to followers stream
|
||||||
followers.forEach(following =>
|
followers.forEach(following =>
|
||||||
event(following.follower_id, 'post', postObj));
|
event(following.followerId, 'post', postObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
// チャンネルへの投稿
|
// チャンネルへの投稿
|
||||||
|
@ -339,21 +339,21 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Get channel watchers
|
// Get channel watchers
|
||||||
const watches = await ChannelWatching.find({
|
const watches = await ChannelWatching.find({
|
||||||
channel_id: channel._id,
|
channelId: channel._id,
|
||||||
// 削除されたドキュメントは除く
|
// 削除されたドキュメントは除く
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
// チャンネルの視聴者(のタイムライン)に配信
|
// チャンネルの視聴者(のタイムライン)に配信
|
||||||
watches.forEach(w => {
|
watches.forEach(w => {
|
||||||
event(w.user_id, 'post', postObj);
|
event(w.userId, 'post', postObj);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment my posts count
|
// Increment my posts count
|
||||||
User.update({ _id: user._id }, {
|
User.update({ _id: user._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
posts_count: 1
|
postsCount: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -362,68 +362,68 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
// Increment replies count
|
// Increment replies count
|
||||||
Post.update({ _id: reply._id }, {
|
Post.update({ _id: reply._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
replies_count: 1
|
repliesCount: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 自分自身へのリプライでない限りは通知を作成
|
// 自分自身へのリプライでない限りは通知を作成
|
||||||
notify(reply.user_id, user._id, 'reply', {
|
notify(reply.userId, user._id, 'reply', {
|
||||||
post_id: post._id
|
postId: post._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch watchers
|
// Fetch watchers
|
||||||
Watching
|
Watching
|
||||||
.find({
|
.find({
|
||||||
post_id: reply._id,
|
postId: reply._id,
|
||||||
user_id: { $ne: user._id },
|
userId: { $ne: user._id },
|
||||||
// 削除されたドキュメントは除く
|
// 削除されたドキュメントは除く
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
user_id: true
|
userId: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(watchers => {
|
.then(watchers => {
|
||||||
watchers.forEach(watcher => {
|
watchers.forEach(watcher => {
|
||||||
notify(watcher.user_id, user._id, 'reply', {
|
notify(watcher.userId, user._id, 'reply', {
|
||||||
post_id: post._id
|
postId: post._id
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// この投稿をWatchする
|
// この投稿をWatchする
|
||||||
if ((user.account as ILocalAccount).settings.auto_watch !== false) {
|
if ((user.account as ILocalAccount).settings.autoWatch !== false) {
|
||||||
watch(user._id, reply);
|
watch(user._id, reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add mention
|
// Add mention
|
||||||
addMention(reply.user_id, 'reply');
|
addMention(reply.userId, 'reply');
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is repost
|
// If it is repost
|
||||||
if (repost) {
|
if (repost) {
|
||||||
// Notify
|
// Notify
|
||||||
const type = text ? 'quote' : 'repost';
|
const type = text ? 'quote' : 'repost';
|
||||||
notify(repost.user_id, user._id, type, {
|
notify(repost.userId, user._id, type, {
|
||||||
post_id: post._id
|
postId: post._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch watchers
|
// Fetch watchers
|
||||||
Watching
|
Watching
|
||||||
.find({
|
.find({
|
||||||
post_id: repost._id,
|
postId: repost._id,
|
||||||
user_id: { $ne: user._id },
|
userId: { $ne: user._id },
|
||||||
// 削除されたドキュメントは除く
|
// 削除されたドキュメントは除く
|
||||||
deleted_at: { $exists: false }
|
deletedAt: { $exists: false }
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
user_id: true
|
userId: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(watchers => {
|
.then(watchers => {
|
||||||
watchers.forEach(watcher => {
|
watchers.forEach(watcher => {
|
||||||
notify(watcher.user_id, user._id, type, {
|
notify(watcher.userId, user._id, type, {
|
||||||
post_id: post._id
|
postId: post._id
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -436,18 +436,18 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
// If it is quote repost
|
// If it is quote repost
|
||||||
if (text) {
|
if (text) {
|
||||||
// Add mention
|
// Add mention
|
||||||
addMention(repost.user_id, 'quote');
|
addMention(repost.userId, 'quote');
|
||||||
} else {
|
} else {
|
||||||
// Publish event
|
// Publish event
|
||||||
if (!user._id.equals(repost.user_id)) {
|
if (!user._id.equals(repost.userId)) {
|
||||||
event(repost.user_id, 'repost', postObj);
|
event(repost.userId, 'repost', postObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 今までで同じ投稿をRepostしているか
|
// 今までで同じ投稿をRepostしているか
|
||||||
const existRepost = await Post.findOne({
|
const existRepost = await Post.findOne({
|
||||||
user_id: user._id,
|
userId: user._id,
|
||||||
repost_id: repost._id,
|
repostId: repost._id,
|
||||||
_id: {
|
_id: {
|
||||||
$ne: post._id
|
$ne: post._id
|
||||||
}
|
}
|
||||||
|
@ -457,7 +457,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
// Update repostee status
|
// Update repostee status
|
||||||
Post.update({ _id: repost._id }, {
|
Post.update({ _id: repost._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
repost_count: 1
|
repostCount: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -494,15 +494,15 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
if (mentionee == null) return;
|
if (mentionee == null) return;
|
||||||
|
|
||||||
// 既に言及されたユーザーに対する返信や引用repostの場合も無視
|
// 既に言及されたユーザーに対する返信や引用repostの場合も無視
|
||||||
if (reply && reply.user_id.equals(mentionee._id)) return;
|
if (reply && reply.userId.equals(mentionee._id)) return;
|
||||||
if (repost && repost.user_id.equals(mentionee._id)) return;
|
if (repost && repost.userId.equals(mentionee._id)) return;
|
||||||
|
|
||||||
// Add mention
|
// Add mention
|
||||||
addMention(mentionee._id, 'mention');
|
addMention(mentionee._id, 'mention');
|
||||||
|
|
||||||
// Create notification
|
// Create notification
|
||||||
notify(mentionee._id, user._id, 'mention', {
|
notify(mentionee._id, user._id, 'mention', {
|
||||||
post_id: post._id
|
postId: post._id
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,9 +13,9 @@ import Post from '../../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Get favoritee
|
// Get favoritee
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
|
@ -28,8 +28,8 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// if already favorited
|
// if already favorited
|
||||||
const exist = await Favorite.findOne({
|
const exist = await Favorite.findOne({
|
||||||
post_id: post._id,
|
postId: post._id,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist !== null) {
|
if (exist !== null) {
|
||||||
|
@ -38,9 +38,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Create favorite
|
// Create favorite
|
||||||
await Favorite.insert({
|
await Favorite.insert({
|
||||||
created_at: new Date(),
|
createdAt: new Date(),
|
||||||
post_id: post._id,
|
postId: post._id,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
|
|
|
@ -13,9 +13,9 @@ import Post from '../../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
// Get 'post_id' parameter
|
// Get 'postId' parameter
|
||||||
const [postId, postIdErr] = $(params.post_id).id().$;
|
const [postId, postIdErr] = $(params.postId).id().$;
|
||||||
if (postIdErr) return rej('invalid post_id param');
|
if (postIdErr) return rej('invalid postId param');
|
||||||
|
|
||||||
// Get favoritee
|
// Get favoritee
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
|
@ -28,8 +28,8 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// if already favorited
|
// if already favorited
|
||||||
const exist = await Favorite.findOne({
|
const exist = await Favorite.findOne({
|
||||||
post_id: post._id,
|
postId: post._id,
|
||||||
user_id: user._id
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist === null) {
|
if (exist === null) {
|
||||||
|
@ -37,7 +37,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete favorite
|
// Delete favorite
|
||||||
await Favorite.deleteOne({
|
await Favorite.remove({
|
||||||
_id: exist._id
|
_id: exist._id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue