diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1af6016e4..2c5dcba8ba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,236 @@
+#### 1.13.3 (2020-05-08)
+
+##### Chores
+
+* incrementing version number - v1.13.3 (ee583e80)
+* bump persona (d2bd746c)
+* incrementing version number - v1.13.2 (beafd613)
+* **deps:**
+ * update dependency coveralls to v3.1.0 (5ed4a108)
+ * pin dependency @apidevtools/swagger-parser to 9.0.1 (51eccef5)
+ * update dependency husky to v4.2.5 (30a25983)
+ * update dependency husky to v4.2.4 (0a650118)
+ * update dependency lint-staged to v10.1.3 (a9e68639)
+ * update dependency nyc to v15.0.1 (#8231) (a3789e28)
+ * update dependency lint-staged to v10.1.2 (#8235) (e1919c90)
+ * update dependency lint-staged to v10.1.1 (944a6f58)
+ * update dependency lint-staged to v10.1.0 (30bd233b)
+ * update dependency eslint-config-airbnb-base to v14.1.0 (811c3aee)
+ * update dependency jsdom to v16.2.2 (c5a7242d)
+ * update dependency eslint-plugin-import to v2.20.2 (b92c1600)
+ * update dependency lint-staged to v10.0.10 (0ad4b556)
+ * update dependency coveralls to v3.0.11 (14458087)
+ * update dependency smtp-server to v3.6.0 (22681945)
+ * update dependency mocha to v7.1.1 (#8215) (c5356541)
+ * update dependency grunt to v1.1.0 (#8214) (b0864e7c)
+ * update dependency husky to v4.2.3 (#8162) (776fe9d2)
+ * update dependency lint-staged to v10.0.8 (#8180) (13d8f6f1)
+ * update dependency eslint-plugin-import to v2.20.1 (#8081) (4cdb3131)
+ * update dependency jsdom to v16.2.1 (#8165) (fbd95a50)
+ * update dependency husky to v4.2.2 (#8160) (f4ed35c9)
+ * update dependency jsdom to v16 (#8114) (1037de02)
+
+##### Documentation Changes
+
+* updated changelog (146388aa)
+
+##### New Features
+
+* allow activating additional plugins for testing via config.json (a969c5ce)
+* move plugin tests to separate file (3a23ddab)
+* remove node14 for now (a72e4429)
+* reduce infinite scroll area (3fcbd691)
+* manifest.json improvements from #8126 (#8264) (6e5ebb61)
+* show error if json is invalid (15345627)
+* moved component specs into separate files (cd506557)
+* added UserObject, UserObjectFull, Breadcrumb, Pagination component (64d79fe5)
+* added some summary and descriptions (ae3e90d6)
+* add some descriptions (442c018e)
+* common schema (eade13f9)
+* openapi component (1af5507a)
+* add page query param to docs (9987813f)
+* tag route doc (bbddaadf)
+* local redoc view on development mode only (1136a369)
+* added auto-generated, slimmed-down openapi 3.0 file for read api (7b155dab)
+* add parent cids to body class (23571224)
+* add 2 hooks for modifying privileges (d080c7b0)
+* add user ip to admin/dev/info (5e91a67e)
+* change option name (cba5b23e)
+* add no-build to ./nodebb setup (476f6717)
+* add awaitable socket.emit (4083a6e3)
+* settings sorted list (#8170) (3c9689a5)
+* guard against accidental ommision (79737c53)
+* **openapi:**
+ * merging openapi-test branch into master (8387178b)
+ * move all commonprops out for commonprops component (65c78de6)
+ * added template to commonprops (2425f453)
+
+##### Bug Fixes
+
+* #8302, send string to writeFileSync (d09bd2cf)
+* winston showing json object (7d081843)
+* sortable topics even if only 1 pinned topic (6765de3d)
+* #8298, use class name added by jQueryUI instead (dd2bc189)
+* topic search shortcut for macs (f2c725c6)
+* #8297, uids.length is different than topics.length (0431d75f)
+* #8297 guest handles shown in category.tpl (fcb81cb8)
+* only add to set if numRecentReplies>0 (16a98eaf)
+* #8293, don't show error if there are no self messages (be305410)
+* failing tests @julianlam (ecd622fd)
+* #3321, run plugin tests for installed plugins (a6bb9f43)
+* remove deprecated mocha.opts (3d0db963)
+* spec (84383d39)
+* #8290, if there are no filters go to ?reset=1 (9839346e)
+* #8283, update gdpr link again (2d076344)
+* add missing await (4f1128fd)
+* #8287, dont readd user after deletion (9d153fd3)
+* missing await (4d6b2ec3)
+* #8286, rescind notif when its resolved/rejected (0391856d)
+* #8284, parse ToS on register (0ca84bd9)
+* #8283, point to official site (17d664e0)
+* jquery xhtml violations (275e837b)
+* #8274 Don't escape HTML in manage users (#8275) (4855f1de)
+* crash in topic controller (0c7c70ed)
+* crash when res.locals.linkTags is undefined (7cab2b0f)
+* #8272 user link in digest email (e80b8101)
+* tag of /api/unread/total (9ffdab02)
+* response hook logic (5a1c6ee7)
+* remove upload picture test (avatars) (6edf02d4)
+* remove tests related to group covers, as route is gone (442fe65f)
+* #8269, return array of topics from hook (4eafe0f0)
+* remove dead picture upload code #8260 (ef52461f)
+* path.resolve to logs file (5bcaf715)
+* only trigger infinitescroll on scroll end (ba6d3fd3)
+* wrong data returned in available.groups (c7ea84a2)
+* no focus on find user modal (1b425ef1)
+* accidental fp precision on flag and acp dash graphs (bcbf98aa)
+* #8232, unresolvable session mismatch on register cancel (f2f6fbf1)
+* pin jquery to 3.4.1, #8252 (e440d617)
+* #8249, don't send move notifications for deleted posts/topics (d77036db)
+* missing descriptions for common properties (7b31fb34)
+* some definitions in read API spec (03739b6f)
+* tagged all routes in read api spec (455d42bc)
+* override ACAO header for read API spec file (240d9091)
+* throw error if topic does not exist (59cf0e80)
+* hookname (e93578b8)
+* #8230, add hook getUserDataByUserSlug (0d1b5a7f)
+* ignore case for group details route (15d6975e)
+* lint (740e598a)
+* lint (8e23dec8)
+* #8221, fix parent selection (08031730)
+* invite properly (071506eb)
+* admins not seeing invite button (8f4b99a4)
+* #8217, add missing lang key (0b5fac75)
+* #8206 first message in chat has false `newSet` (93acd139)
+* #8203, fix user invites refreshing page (2f9c7c62)
+* #8202, filter non-existing users in search by uid (f07f4f8e)
+* notification bodyShort truncated if there is a comma in topic title (266061c3)
+* hsts max-age missing translation (b67af70d)
+* call next (80f1bcad)
+* try travis fix again (05bee629)
+* try fixing psql on travis (bc9e92a1)
+* dont let regular users see other users watched categories (cf6eadb9)
+* also fix updating bookmark if sorting is newest_to_oldest (6e5de39b)
+* #8188, fix bookmark if sorting is newest_to_oldest (32ada7c4)
+* duplicate ID + label (ac241fb8)
+* #8184 global mods unable to revoke other user sessions (f0db240a)
+* return null if field does not exist (e72a29b3)
+* #8179, limit length of location/website/fullname, check grouptitle (14e78667)
+* tag key (32636755)
+* #8175 (bc93b567)
+* #8168 re-allowing slashes in homePageRoute (667608a0)
+* tweak to session validation in addHeaders (eddbd868)
+* only call clearCookie for logged in users (630f5d5b)
+* #6422, update deleted/restored messages (06703408)
+* #8163, prevent account deletion (4d0636f8)
+* register (5a0c7c14)
+* #8157, update recent tid when post is moved (e7495440)
+* tests (b73aa84d)
+* move start/stop every iteration (dd3893b1)
+* #8154, move start/stop every iteration (300c04ce)
+* #8154, respect stop (690bb69d)
+* #8156 dont allow loading members from hidden groups (f23bc347)
+* #8155, don't validate name on update if groupName didn't change (03a02e5d)
+* return correct number of suggested topics (236e1e68)
+* #8151, don't crash if taskbar doesn't have element (2e794801)
+* logic for determining dailyStats hour vars (398f0120)
+* fix daily analytics being one day off (9ecdb92f)
+* remove debug line (0b9ad416)
+* no decimal places for category analytics (14655f87)
+* #8142, broken site if no server-side session (#8148) (d6e3f3f0)
+* #8144 pluginHooks in maintenance mode middleware (0885ec68)
+* **deps:**
+ * #8298 bump persona (158d9231)
+ * update dependency nodebb-plugin-composer-default to v6.3.25 (89d17647)
+ * update dependency jquery to v3.5.1 [security] (#8281) (a69f0b29)
+ * update dependency nodebb-rewards-essentials to v0.1.3 (#8289) (919034a7)
+ * update dependency mongodb to v3.5.7 (#8279) (25d509c4)
+ * actually, swagger-parser is a dev dependency (d09c6ae0)
+ * missing @apidevtools/swagger-parser (f1720735)
+ * update dependency nodebb-theme-persona to v10.1.37 (#8258) (b0c30ceb)
+ * update dependency archiver to v4 (28777f67)
+ * update dependency mongodb to v3.5.6 (#8256) (49236067)
+ * bump dependencies (#8239) (e68156e1)
+ * update dependency jsesc to v3.0.1 (#8243) (92b55ef5)
+ * update dependency jsesc to v3 (bb70cebb)
+ * update dependency pg to v8 (#8227) (ac98775f)
+ * update dependency validator to v13 (f497ee62)
+ * update dependency sharp to v0.25.2 (#8220) (dd660c87)
+ * bump markdown (ee6cb412)
+ * update dependency mongodb to v3.5.5 (#8205) (5535c50c)
+ * update dependency sitemap to v6 (#8198) (2052f14c)
+ * update dependency nodebb-plugin-composer-default to v6.3.23 (6d98d5a1)
+ * update dependency sharp to v0.25.1 (#8199) (21e91c91)
+ * update dependency nodebb-plugin-composer-default to v6.3.22 (#8193) (e01f05e3)
+ * update dependency nodebb-theme-slick to v1.2.29 (#8177) (9daa21ff)
+ * update dependency nodebb-theme-vanilla to v11.1.16 (#8178) (7d6a983b)
+ * update dependency nodebb-theme-persona to v10.1.35 (#8176) (3acc24b0)
+ * update dependency sharp to v0.24.1 (#8164) (7cc63f7d)
+ * update dependency mongodb to v3.5.3 (#8161) (4b907137)
+ * update dependency nodebb-widget-essentials to v4.1.0 (#8159) (a5f3c2a2)
+ * update dependency request to v2.88.2 (#8158) (7fde180a)
+ * update dependency redis to v3 (#8152) (ef964b11)
+ * update dependency rimraf to v3.0.2 (#8153) (d8efc6b6)
+* **openapi:**
+ * v14 test fix (23a0b8c5)
+ * remove account and group upload routes (d342a28c)
+ * more fleshing out (058a15db)
+ * fleshed out admin routes (bae88e08)
+ * added some descriptions (ab4bd7e1)
+ * added PostsObject component (2395d2be)
+ * finished moving all category objects out (23dd2727)
+ * changed some descriptions (c939f8c6)
+ * added CategoryObject component (55d0a9ff)
+ * removed repeated breadcrumb blocks in favour of $ref (646fac1e)
+ * remove all repeated pagination blocks in favour of (ac579f9d)
+ * removed warning for category mods route (1cf62095)
+ * normalising the file for programmatic updates (3a5c6e07)
+
+##### Other Changes
+
+* #8298 (2e57d8ac)
+* post.updatePostVoteCount (b25b51bd)
+* //github.com/NodeBB/NodeBB (5e140454)
+* categories.updateRecentTid (6c59683b)
+* categories.updateRecentTid (51933c1f)
+* router.page, dep. filter variant (0053e779)
+* flags as well (5ebcdb18)
+* crash when res.locals.linkTags is undefined" (fe03effe)
+* //github.com/NodeBB/NodeBB (87a6ff0d)
+* cnpm and pnpm (#8222) (e6a1741c)
+* //github.com/NodeBB/NodeBB (7ae76477)
+* openapi component" (683e5851)
+* override ACAO header for read API spec file" (c82a2637)
+* password.change (00e299e9)
+* topic.tools.load (5aa76cdf)
+* #8154, move start/stop every iteration" (4abe5eb7)
+
+##### Refactors
+
+* match core field name pinned (478ed6c1)
+* getUsersCSV to use batch lib (1efb238a)
+* reorganized socket.io admin modules (e1c6c3b2)
+
#### 1.13.2 (2020-02-05)
##### Chores
diff --git a/install/data/defaults.json b/install/data/defaults.json
index 86fc1075c4..797347f20f 100644
--- a/install/data/defaults.json
+++ b/install/data/defaults.json
@@ -81,9 +81,11 @@
"notificationType_upvote": "notification",
"notificationType_new-topic": "notification",
"notificationType_new-reply": "notification",
+ "notificationType_post-edit": "notification",
"notificationType_follow": "notification",
"notificationType_new-chat": "notification",
"notificationType_group-invite": "notification",
+ "notificationType_group-request-membership": "notification",
"notificationType_mention": "notification",
"notificationType_new-register": "notification",
"notificationType_post-queue": "notification",
diff --git a/install/package.json b/install/package.json
index e142fa0b70..8063b62b64 100644
--- a/install/package.json
+++ b/install/package.json
@@ -79,7 +79,7 @@
"mousetrap": "^1.6.5",
"@nodebb/mubsub": "^1.6.0",
"nconf": "^0.10.0",
- "nodebb-plugin-composer-default": "6.3.25",
+ "nodebb-plugin-composer-default": "6.3.28",
"nodebb-plugin-dbsearch": "4.0.7",
"nodebb-plugin-emoji": "^3.3.0",
"nodebb-plugin-emoji-android": "2.0.0",
@@ -136,7 +136,7 @@
"@commitlint/cli": "8.3.5",
"@commitlint/config-angular": "8.3.4",
"coveralls": "3.1.0",
- "eslint": "6.8.0",
+ "eslint": "7.0.0",
"eslint-config-airbnb-base": "14.1.0",
"eslint-plugin-import": "2.20.2",
"grunt": "1.1.0",
diff --git a/public/language/ar/notifications.json b/public/language/ar/notifications.json
index 1e725aa87d..0c86cd65f8 100644
--- a/public/language/ar/notifications.json
+++ b/public/language/ar/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 أنشأ موضوعًا جديدًا: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 صار يتابعك.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "عندما يوافقك احدهم على منشورك",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/bg/notifications.json b/public/language/bg/notifications.json
index 5bde63d158..dd195e5cb2 100644
--- a/public/language/bg/notifications.json
+++ b/public/language/bg/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 и %2 публикуваха отговори на: %3",
"user_posted_to_multiple": "%1 и %2 други публикуваха отговори на: %3",
"user_posted_topic": "%1 публикува нова тема: %2",
+ "user_edited_post": "%1 редактира публикация в %2",
"user_started_following_you": "%1 започна да Ви следва.",
"user_started_following_you_dual": "%1 и %2 започнаха да Ви следват.",
"user_started_following_you_multiple": "%1 и %2 започнаха да Ви следват.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Когато някой гласува положително за Ваша публикация",
"notificationType_new-topic": "Когато някой, когото следвате, публикува тема",
"notificationType_new-reply": "Когато бъде публикуван нов отговор в тема, която следвате",
+ "notificationType_post-edit": "Когато бъде редактирана публикация в тема, която следите",
"notificationType_follow": "Когато някой започне да Ви следва",
"notificationType_new-chat": "Когато получите съобщение в разговор",
"notificationType_group-invite": "Когато получите покана за група",
diff --git a/public/language/bn/notifications.json b/public/language/bn/notifications.json
index 2aaf5b055a..a11e62bc4c 100644
--- a/public/language/bn/notifications.json
+++ b/public/language/bn/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 has posted a new topic: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 আপনাকে অনুসরন করা শুরু করেছেন।",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json
index a0db549829..277095f420 100644
--- a/public/language/cs/notifications.json
+++ b/public/language/cs/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 a %2 odpověděli na: %3",
"user_posted_to_multiple": "%1 a %2 další/ch odpověděli na %3",
"user_posted_topic": "%1 založil nové téma: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 vás začal sledovat.",
"user_started_following_you_dual": "%1 a %2 vás začali sledovat.",
"user_started_following_you_multiple": "%1 a %2 další/ch vás začali sledovat.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Vyjádří-li někdo souhlas s vaším příspěvkem",
"notificationType_new-topic": "Začne-li někdo sledovat příspěvky a téma",
"notificationType_new-reply": "Bude-li přidán nový příspěvek v tématu, které sledujete",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Začne-li vás někdo sledovat",
"notificationType_new-chat": "Obdržíte-li novou konverzační zprávu",
"notificationType_group-invite": "Obdržíte-li pozvání ke skupině",
diff --git a/public/language/da/notifications.json b/public/language/da/notifications.json
index 7544d7b047..51a44a8f0e 100644
--- a/public/language/da/notifications.json
+++ b/public/language/da/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 og %2 har skrevet svar til: %3",
"user_posted_to_multiple": "%1 og %2 andre har skrevet svar til: %3",
"user_posted_topic": "%1 har oprettet en ny tråd: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 har valgt at følge dig.",
"user_started_following_you_dual": "%1 og %2 har valgt at følge dig.",
"user_started_following_you_multiple": "%1 og %2 har valgt at følge dig.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json
index 7426284d64..b9fbf859da 100644
--- a/public/language/de/notifications.json
+++ b/public/language/de/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 und %2 haben auf %3 geantwortet.",
"user_posted_to_multiple": "%1 und %2 andere Nutzer haben auf %3 geantwortet.",
"user_posted_topic": "%1 hat ein neues Thema erstellt: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 folgt dir jetzt.",
"user_started_following_you_dual": "%1 und %2 folgen dir jetzt.",
"user_started_following_you_multiple": "%1 und %2 andere Nutzer folgen dir jetzt.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Wenn jemand deinen beitrag positiv bewertet",
"notificationType_new-topic": "Wenn jemand dem du folgst einen Beitrag erstellt",
"notificationType_new-reply": "Wenn es eine neue Antwort auf ein Thema das du beobachtest gibt",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Wenn dir jemand neues folgt",
"notificationType_new-chat": "Wenn du eine Chat Nachricht erhältst",
"notificationType_group-invite": "Wenn du eine Gruppeneinladung erhältst",
diff --git a/public/language/el/notifications.json b/public/language/el/notifications.json
index 8c07ad2261..fa538d29b6 100644
--- a/public/language/el/notifications.json
+++ b/public/language/el/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 has posted a new topic: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 started following you.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/en-GB/notifications.json b/public/language/en-GB/notifications.json
index 3716089d71..7ce5515ca0 100644
--- a/public/language/en-GB/notifications.json
+++ b/public/language/en-GB/notifications.json
@@ -39,6 +39,7 @@
"user_posted_to_dual" : "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple" : "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 has posted a new topic: %2",
+ "user_edited_post" : "%1 has edited a post in %2",
"user_started_following_you": "%1 started following you.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -59,6 +60,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/en-US/notifications.json b/public/language/en-US/notifications.json
index 04b6b94b2f..980fdbc964 100644
--- a/public/language/en-US/notifications.json
+++ b/public/language/en-US/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 has posted a new topic: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 started following you.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/en-x-pirate/notifications.json b/public/language/en-x-pirate/notifications.json
index e41dc6b9e4..0d57170235 100644
--- a/public/language/en-x-pirate/notifications.json
+++ b/public/language/en-x-pirate/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 has posted a new topic: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 started following you.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/es/notifications.json b/public/language/es/notifications.json
index a12cb1b2ba..4527ea84a3 100644
--- a/public/language/es/notifications.json
+++ b/public/language/es/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 y %2 han respondido a %3",
"user_posted_to_multiple": "%1 y otras %2 personas han respondido a: %3",
"user_posted_topic": "%1 ha publicado un nuevo tema: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 comenzó a seguirte.",
"user_started_following_you_dual": "%1 y %2 comenzaron a seguirte.",
"user_started_following_you_multiple": "%1 y otras %2 personas comenzaron a seguirte.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Cuando alguien vota positivamente en tu entrada",
"notificationType_new-topic": "Cuando alguien a quien sigues comenta en un tema",
"notificationType_new-reply": "Cuando hay una respuesta nueva en un tema que estás viendo",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Cuando alguien comienza a seguirte",
"notificationType_new-chat": "Cuando recibes un mensaje de chat",
"notificationType_group-invite": "Cuando recibes una invitación a un grupo",
diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json
index f884227d8e..a3377197d2 100644
--- a/public/language/et/notifications.json
+++ b/public/language/et/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 ja %2 on postitanud vastused: %3",
"user_posted_to_multiple": "%1 ja %2 teist on postitanud vastused: %3",
"user_posted_topic": "%1 on postitanud uue teema: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 hakkas sind jälgima.",
"user_started_following_you_dual": "%1 ja %2 hakkasid sind jälgima.",
"user_started_following_you_multiple": "%1 ja %2 hakkasid sind jälgima.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/fa-IR/notifications.json b/public/language/fa-IR/notifications.json
index 2fc82e6cf8..c61eae7314 100644
--- a/public/language/fa-IR/notifications.json
+++ b/public/language/fa-IR/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 و %2 پاسخ به پست دادند در: %3",
"user_posted_to_multiple": "%1 و %2 نفر دیگر به پست شما پاسخ ارسال کردهاند در: %3",
"user_posted_topic": "%1 یک موضوع جدید ارسال کرده: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 شروع به دنبال کردن شما کرده",
"user_started_following_you_dual": "%1 و %2 شروع به دنبال کردن شما کرده.",
"user_started_following_you_multiple": "%1 و %2 نفر دیگر شروع به دنبال کردن شما کرده.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "هنگامی که شخصی به پست شما رای مثبت می دهد",
"notificationType_new-topic": "هنگامی که شخصی که شما دنبال می کنید موضوعی ایجاد نماید",
"notificationType_new-reply": "هنگامی که پاسخ جدید در تاپیکی که شما پیگیری می کنید فرستاده می شود",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "هنگامی که کسی شما را دنبال می کند",
"notificationType_new-chat": "هنگامی که شما پیام چتی دریافت می کنید",
"notificationType_group-invite": "هنگامی که شما دعوتنامه گروه دریافت می کنید",
diff --git a/public/language/fi/notifications.json b/public/language/fi/notifications.json
index 48e6140919..0118d76edf 100644
--- a/public/language/fi/notifications.json
+++ b/public/language/fi/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 ja %2 ovat vastanneet viestiin: %3",
"user_posted_to_multiple": "%1 ja %2 muuta ovat vastanneet viestiin: %3 ",
"user_posted_topic": "%1 on kirjoittanut uuden aiheen: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 alkoi seurata sinua.",
"user_started_following_you_dual": "%1 ja %2 alkoivat seurata sinua",
"user_started_following_you_multiple": "%1 ja %2 muuta alkoivat seurata sinua",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Kun joku tykkää viestistäsi",
"notificationType_new-topic": "Kun joku seuraa viestejäsi aiheessa",
"notificationType_new-reply": "Kun uusi vastaus on lähetetty aiheeseen, jota seuraat",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Kun joku alkaa seurata sinua",
"notificationType_new-chat": "Kun saat viestin keskusteluun",
"notificationType_group-invite": "Kun saat kutsun ryhmään",
diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json
index a5be7f8c4f..ff001a7886 100644
--- a/public/language/fr/notifications.json
+++ b/public/language/fr/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 et %2 ont posté une réponse à : %3",
"user_posted_to_multiple": "%1 et %2 autres ont posté une réponse à : %3",
"user_posted_topic": "%1 a posté un nouveau sujet: %2.",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 vous suit.",
"user_started_following_you_dual": "%1 et %2 se sont abonnés à votre compte.",
"user_started_following_you_multiple": "%1 et %2 autres se sont abonnés à votre compte.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Lorsque quelqu'un a voté pour un de vos messages",
"notificationType_new-topic": "Lorsque quelqu'un que vous suivez publie un sujet",
"notificationType_new-reply": "Lorsqu'une nouvelle réponse est ajoutée dans un sujet que vous suivez",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Lorsque quelqu'un commence à vous suivre",
"notificationType_new-chat": "Lorsque vous recevez un message du chat ",
"notificationType_group-invite": "Lorsque vous recevez une invitation d'un groupe",
diff --git a/public/language/gl/notifications.json b/public/language/gl/notifications.json
index 1e5e01e984..4267d4afdb 100644
--- a/public/language/gl/notifications.json
+++ b/public/language/gl/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 e %2 responderon a %3",
"user_posted_to_multiple": "%1 e outras %2 persoas responderon a: %3",
"user_posted_topic": "%1 publicou un novo tema: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 comezou a seguirte.",
"user_started_following_you_dual": "%1 e %2 comezaron a seguirte.",
"user_started_following_you_multiple": "%1 e %2 máis comezaron a seguirte.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json
index 5baa8768b2..ee7bcb14d2 100644
--- a/public/language/he/notifications.json
+++ b/public/language/he/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 ו%2 הגיבו ל: %3",
"user_posted_to_multiple": "%1 ו%2 אחרים הגיבו ל: %3",
"user_posted_topic": "%1 העלה נושא חדש: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 התחיל לעקוב אחריך.",
"user_started_following_you_dual": "%1 ו%1 התחילו לעקוב אחריך.",
"user_started_following_you_multiple": "%1 ו%2 התחילו לעקוב אחריך.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "כאשר מישהו מצביע בעד הפוסט שלך",
"notificationType_new-topic": "כשמישהו שאתה עוקב אחריו פרסם נושא",
"notificationType_new-reply": "כשתגובה חדשה מפורסמת בנושא שאתה צופה בו",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "כשמישהו מתחיל לעקוב אחריך",
"notificationType_new-chat": "כשאתה מקבל הודעת צאט",
"notificationType_group-invite": "כשאתה מקבל הזמנה מקבוצה",
diff --git a/public/language/hr/notifications.json b/public/language/hr/notifications.json
index 85e1eb3bf1..62e5a7e026 100644
--- a/public/language/hr/notifications.json
+++ b/public/language/hr/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 i %2 ostalih su odgovorili na objavu u: %3",
"user_posted_to_multiple": "%1 i %2 drugih su odgovorili na: %3",
"user_posted_topic": "%1 je otvorio novu temu: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 Vas sada prati.",
"user_started_following_you_dual": "%1 i %2 vas sada prate.",
"user_started_following_you_multiple": "%1 i %2 ostalih vas sada prate.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/hu/notifications.json b/public/language/hu/notifications.json
index 540fa91141..78bf732d42 100644
--- a/public/language/hu/notifications.json
+++ b/public/language/hu/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 és%2 választ írt neki: %3",
"user_posted_to_multiple": "%1 és %2 másik választ írt neki: %3",
"user_posted_topic": "%1 új témakört hozott létre: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 elkezdett követni téged.",
"user_started_following_you_dual": "%1 és%2 elkezdett követni téged.",
"user_started_following_you_multiple": "%1 és %2 másik elkezdett követni téged.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Mikor valaki kedveli a hozzászólásod",
"notificationType_new-topic": "Mikor egy követett felhasználód hozzászól",
"notificationType_new-reply": "Mikor egy általad figyelt témakörre válasz érkezik",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Mikor valaki elkezd követni téged",
"notificationType_new-chat": "Mikor chat üzenetet kapsz",
"notificationType_group-invite": "Mikor csoportmeghívást kapsz",
diff --git a/public/language/id/notifications.json b/public/language/id/notifications.json
index 505b3f8cc9..27e3026ee7 100644
--- a/public/language/id/notifications.json
+++ b/public/language/id/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 telah membuat topik baru: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 mulai mengikutimu.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json
index a154f31c5d..12fdff7e5d 100644
--- a/public/language/it/notifications.json
+++ b/public/language/it/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 e %2 hanno postato una risposta su: %3",
"user_posted_to_multiple": "%1 ed altri %2 hanno postato una risposta su: %3",
"user_posted_topic": "%1 ha postato una nuova discussione: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 ha iniziato a seguirti.",
"user_started_following_you_dual": "%1 e %2 hanno iniziato a seguirti.",
"user_started_following_you_multiple": "%1 ed altri %2 hanno iniziato a seguirti.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Quando il tuo post riceve un Mi Piace",
"notificationType_new-topic": "Quando qualcuno che segui pubblica un argomento",
"notificationType_new-reply": "Quando viene pubblicata una nuova risposta in un argomento che stai seguendo",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Quando qualcuno inizia a seguirti",
"notificationType_new-chat": "Quando ricevi un messaggio in chat",
"notificationType_group-invite": "Quando ricevi un invito ad un gruppo",
diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json
index e22ac76f67..9f95ab0c31 100644
--- a/public/language/ja/notifications.json
+++ b/public/language/ja/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 と %2 は、返信しました: %3",
"user_posted_to_multiple": "%1 と %2 または他のユーザーが返信しました: %3",
"user_posted_topic": "%1 が新しいスレッドを投稿しました。: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1があなたをフォローしました。",
"user_started_following_you_dual": "%1 と %2 があなたをフォローしました。",
"user_started_following_you_multiple": "%1 と %2 または他のユーザーがあなたをフォローしました。",
@@ -53,6 +54,7 @@
"notificationType_upvote": "誰かがあなたの投稿を評価したとき",
"notificationType_new-topic": "フォロワーがスレッドを投稿したとき",
"notificationType_new-reply": "あなたが見ているトピックに新しい返信が投稿されたとき",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "誰かがあなたをフォローしたとき",
"notificationType_new-chat": "チャットメッセージを受信したとき",
"notificationType_group-invite": "グループ招待を受けたとき",
diff --git a/public/language/ko/notifications.json b/public/language/ko/notifications.json
index ebe767bddc..930d3934ec 100644
--- a/public/language/ko/notifications.json
+++ b/public/language/ko/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 님과 %2 님이 %3 에 답글을 달았습니다.",
"user_posted_to_multiple": "%1 님과 %2 명의 다른 유저들이 %3 에 답글을 달았습니다.",
"user_posted_topic": "%1님이 새 게시물을 작성했습니다: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1님이 나를 팔로우 합니다.",
"user_started_following_you_dual": "%1님과 %2님이 나를 팔로우 합니다.",
"user_started_following_you_multiple": "%1님외 %2명이 나를 팔로우 합니다.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "누군가 사용자님의 글을 추천해 줄 때",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "주시중인 글에 새로운 답글이 게시되면",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "누군가 사용자님을 팔로우 하면",
"notificationType_new-chat": "채팅 메시지를 받으면",
"notificationType_group-invite": "그룹 초대를 받으면",
diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json
index e82ca030c2..e5310eb0dd 100644
--- a/public/language/lt/notifications.json
+++ b/public/language/lt/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 paskelbė naują temą: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 pradėjo sekti tave",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/lv/notifications.json b/public/language/lv/notifications.json
index 12631ea58f..2a929402a0 100644
--- a/public/language/lv/notifications.json
+++ b/public/language/lv/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 un %2 ir atbildējuši %3",
"user_posted_to_multiple": "%1 un %2 citi ir atbildējuši %3",
"user_posted_topic": "%1 ir ievietojis jaunu tematu: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 sāka Tev sekot.",
"user_started_following_you_dual": "%1 un %2 sāka Tev sekot.",
"user_started_following_you_multiple": "%1 un %2 citi sāka Tev sekot.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Kad kāds balso \"par\" Tavu rakstu",
"notificationType_new-topic": "Kad kāds, kuru Tu seko, publicē rakstu",
"notificationType_new-reply": "Kad jauna atbilde tiek pievienota tematam, kuru novēro",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Kad kāds sāk Tev sekot",
"notificationType_new-chat": "Kad saņemi sarunu",
"notificationType_group-invite": "Kad saņemi ielūgumu pievienoties grupai",
diff --git a/public/language/ms/notifications.json b/public/language/ms/notifications.json
index 80a877b632..a6142f56b7 100644
--- a/public/language/ms/notifications.json
+++ b/public/language/ms/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 dan %2 membalas kiriman : %3",
"user_posted_to_multiple": "%1 dan %2 lagu membalas kiriman: %3",
"user_posted_topic": "%1 membuka topik baru : %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 mula mengikut anda.",
"user_started_following_you_dual": "%1 dan %2 mula mengikuti anda.",
"user_started_following_you_multiple": "%1 dan %2 lagi mula mengikuti anda.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json
index 484addbd1f..04d292395c 100644
--- a/public/language/nb/notifications.json
+++ b/public/language/nb/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 har skrevet et nytt emne: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 begynte å følge deg.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json
index a03b742f16..f0d5eb4da6 100644
--- a/public/language/nl/notifications.json
+++ b/public/language/nl/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 en %2 hebben een reactie geplaatst in: %3",
"user_posted_to_multiple": "%1 en %2 hebben een reactie geplaatst in: %3",
"user_posted_topic": "%1 heeft een nieuw onderwerp geplaatst: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 volgt jou nu.",
"user_started_following_you_dual": "%1 en %2 volgen jou nu.",
"user_started_following_you_multiple": "%1 en %2 anderen volgen jou nu.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Als iemand positief stemt voor je bericht",
"notificationType_new-topic": "Wanneer iemand die jij volgt een onderwerp post",
"notificationType_new-reply": "Als een nieuwe reactie komt op een onderwerp dat je volgt",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Als iemand begint met jou te volgen",
"notificationType_new-chat": "Als je een chat-bericht ontvangt",
"notificationType_group-invite": "Als je een uitnodiging voor een groep ontvangt",
diff --git a/public/language/pl/notifications.json b/public/language/pl/notifications.json
index f9f1043b9b..dfb52ccf78 100644
--- a/public/language/pl/notifications.json
+++ b/public/language/pl/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 oraz %2 dodali odpowiedzi do %3",
"user_posted_to_multiple": "%1 oraz %2 innych dodali odpowiedzi do %3",
"user_posted_topic": "%1 stworzył nowy temat: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 zaczął Cię obserwować.",
"user_started_following_you_dual": "%1 oraz %2 zaczęli Cię obserwować.",
"user_started_following_you_multiple": "%1 oraz %2 innych obserwują Cię.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Kiedy ktoś zagłosuje na Twój post",
"notificationType_new-topic": "Kiedy ktoś, kogo obserwujesz, utworzy temat",
"notificationType_new-reply": "Kiedy ktoś doda nową odpowiedź w temacie, który obserwujesz",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Kiedy ktoś zacznie Cię obserwować",
"notificationType_new-chat": "Kiedy otrzymasz wiadomość na czacie",
"notificationType_group-invite": "Kiedy otrzymasz grupowe zaproszenie",
diff --git a/public/language/pt-BR/notifications.json b/public/language/pt-BR/notifications.json
index fa3a8a4912..9a4df9b7b3 100644
--- a/public/language/pt-BR/notifications.json
+++ b/public/language/pt-BR/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 e %2 postaram respostas para: %3",
"user_posted_to_multiple": "%1 e %2 outros postaram respostas para: %3",
"user_posted_topic": "%1 postou um novo tópico: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 começou a seguir você.",
"user_started_following_you_dual": "%1 e %2 começaram a lhe acompanhar.",
"user_started_following_you_multiple": "%1 e %2 outros começaram a lhe acompanhar.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Quando alguém dá um voto positivo em seu post",
"notificationType_new-topic": "Quando alguém que você segue posta um tópico",
"notificationType_new-reply": "Quando uma nova resposta é postada em um tópico que você está acompanhando",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Quando alguém começar a seguir você",
"notificationType_new-chat": "Quando você receber uma mensagem de chat",
"notificationType_group-invite": "Quando você receber um convite para um grupo",
diff --git a/public/language/pt-PT/notifications.json b/public/language/pt-PT/notifications.json
index 24f72dd636..edb8369ca4 100644
--- a/public/language/pt-PT/notifications.json
+++ b/public/language/pt-PT/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 e %2 publicaram respostas a: %3",
"user_posted_to_multiple": "%1 e %2 outros utilizadores publicaram respostas a: %3",
"user_posted_topic": "%1 publicou um novo tópico: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 começou a seguir-te.",
"user_started_following_you_dual": "%1 e %2 começaram a seguir-te.",
"user_started_following_you_multiple": "%1 e %2 outros utilizadores começaram a seguir-te.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Quando alguém vota positivamente numa publicação tua",
"notificationType_new-topic": "Quando alguém que tu segues publica um tópico",
"notificationType_new-reply": "Quando uma nova resposta é publicada num tópico que tu estás a seguir",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Quando alguém começa a seguir-te",
"notificationType_new-chat": "Quando recebes uma mensagem numa conversa",
"notificationType_group-invite": "Quando recebes um convite para um grupo",
diff --git a/public/language/ro/notifications.json b/public/language/ro/notifications.json
index d331649a66..8de723abda 100644
--- a/public/language/ro/notifications.json
+++ b/public/language/ro/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 has posted a new topic: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 a început să te urmărească.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/ru/notifications.json b/public/language/ru/notifications.json
index 66aebf4d63..0da0fa4925 100644
--- a/public/language/ru/notifications.json
+++ b/public/language/ru/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "Пользователи %1 и %2 ответили на сообщение в %3",
"user_posted_to_multiple": "%1 и %2 других пользователя ответили на сообщение в %3",
"user_posted_topic": "Пользователь %1 создал новую тему: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "Пользователь %1 подписался на вас.",
"user_started_following_you_dual": "Пользователи %1 и %2 подписались на вас.",
"user_started_following_you_multiple": "%1 и %2 других пользователя подписались на вас.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Когда кто-то проголосовал за ваше сообщение",
"notificationType_new-topic": "Когда кто-то, на кого вы подписаны, создаёт новую тему",
"notificationType_new-reply": "Когда в теме, за которой вы следите, появляется новое сообщение",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Когда кто-то подписался на вас",
"notificationType_new-chat": "Когда вы получаете сообщение в чат",
"notificationType_group-invite": "Когда вы получаете приглашение в группу",
diff --git a/public/language/rw/notifications.json b/public/language/rw/notifications.json
index 9b407a2fe7..44aa3a5231 100644
--- a/public/language/rw/notifications.json
+++ b/public/language/rw/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 yatangije ikiganiro gishya: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 yatangiye kugukurikira.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/sc/notifications.json b/public/language/sc/notifications.json
index 2eb3857af0..ec509a66f6 100644
--- a/public/language/sc/notifications.json
+++ b/public/language/sc/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 and %2 have posted replies to: %3",
"user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
"user_posted_topic": "%1 has posted a new topic: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 started following you.",
"user_started_following_you_dual": "%1 and %2 started following you.",
"user_started_following_you_multiple": "%1 and %2 others started following you.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/sk/notifications.json b/public/language/sk/notifications.json
index 5e3818ca46..e4a79d54ac 100644
--- a/public/language/sk/notifications.json
+++ b/public/language/sk/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 a %2 uverejnili odpoveď na:%3",
"user_posted_to_multiple": "%1 a %2 ďalší uverejnili odpovede na:%3",
"user_posted_topic": "%1 pridal novú tému: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 Vás začal sledovať.",
"user_started_following_you_dual": "%1 a %2 Vás začali sledovať.",
"user_started_following_you_multiple": "%1 a %2 ďalší Vás začali sledovať.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Ak niekto vyjadri súhlas s vaším príspevkom",
"notificationType_new-topic": "Ak začne niekto sledovať príspevky a témy",
"notificationType_new-reply": "Ak bude pridaný nový príspevok v téme, ktorú sledujete",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Ak Vás začne niekto sledovať",
"notificationType_new-chat": "Ak obdržíte novú správu konverzácie",
"notificationType_group-invite": "Ak obdržíte pozvanie do skupiny",
diff --git a/public/language/sl/notifications.json b/public/language/sl/notifications.json
index b416d1054a..a352c5250d 100644
--- a/public/language/sl/notifications.json
+++ b/public/language/sl/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 in %2 sta objavila/-i odgovor na: %3.",
"user_posted_to_multiple": "%1 in %2 drugih je objavilo odgovor na: %3.",
"user_posted_topic": "%1 je odprl/-a novo temo: %2.",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 te je začel/-a spremljati.",
"user_started_following_you_dual": "%1 in %2 sta te začela/-i spremljati.",
"user_started_following_you_multiple": "%1 in %2 drugih te je začelo spremljati.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "When someone upvotes your post",
"notificationType_new-topic": "When someone you follow posts a topic",
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "When someone starts following you",
"notificationType_new-chat": "When you receive a chat message",
"notificationType_group-invite": "When you receive a group invite",
diff --git a/public/language/sr/notifications.json b/public/language/sr/notifications.json
index 2587d82844..3889746710 100644
--- a/public/language/sr/notifications.json
+++ b/public/language/sr/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 и %2 су одговорили на: %3",
"user_posted_to_multiple": "%1 и %2 других су одговорили на: %3",
"user_posted_topic": "%1 је поставио нову тему: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 је почео да вас прати.",
"user_started_following_you_dual": "%1 и %2 су почели да вас прате.",
"user_started_following_you_multiple": "%1 и %2 других су почели да вас прате.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Када неко гласа за вашу поруку",
"notificationType_new-topic": "Када неко кога пратите постави тему",
"notificationType_new-reply": "Када је постављен нови одговор у теми коју надгледате",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Када неко почне да вас прати",
"notificationType_new-chat": "Када примите поруку за ћаскање",
"notificationType_group-invite": "Када примите позивницу за групу",
diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json
index 8b1b549ad8..a77f77ed77 100644
--- a/public/language/sv/notifications.json
+++ b/public/language/sv/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 och %2 har svarat på: %3",
"user_posted_to_multiple": "%1 och %2 andra har svarat på: %3",
"user_posted_topic": "%1 har skapat ett nytt ämne: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 började följa dig.",
"user_started_following_you_dual": "%1 och %2 började följa dig.",
"user_started_following_you_multiple": "%1 och %2 andra började följa dig.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "När någon röstar upp ditt inlägg",
"notificationType_new-topic": "När någon du följer skapar ett ämne",
"notificationType_new-reply": "När ett nytt svar skrivs inom ett ämne du följer",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "När någon börjar följa dig",
"notificationType_new-chat": "När du får ett chattmeddelande",
"notificationType_group-invite": "När du får en gruppinbjudan",
diff --git a/public/language/th/notifications.json b/public/language/th/notifications.json
index f107a25937..0bc2009f3d 100644
--- a/public/language/th/notifications.json
+++ b/public/language/th/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1และ %2ได้โพสต์คำตอบไปยัง : %3 ",
"user_posted_to_multiple": "%1และคนอื่นๆอีก %2 ได้โพสต์คำตอบไปยัง : %3",
"user_posted_topic": "%1ได้โพสต์กระทู้ใหม่ : %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 ได้เริ่มติดตามคุณ",
"user_started_following_you_dual": "%1และ%2ได้เริ่มติดตามคุณ",
"user_started_following_you_multiple": "%1และคืนอื่นๆอีก %2 คนได้เริ่มติดตามคุณ",
@@ -53,6 +54,7 @@
"notificationType_upvote": "เมื่อมีคนโหวตอัพให้โพสต์คุณ",
"notificationType_new-topic": "เมื่อมีคนติดตามโพสต์คุณ",
"notificationType_new-reply": "เมื่อมีการตอบกลับในโพสต์ที่คุณกำลังติดตาม",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "เมื่อมีคนติดตามคุณ",
"notificationType_new-chat": "เมื่อคุณได้รับข้อความใหม่",
"notificationType_group-invite": "เมื่อคุณได้รับเชิญเข้ากลุ่ม",
diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json
index 264c08b86d..b1ec1cd9ca 100644
--- a/public/language/tr/notifications.json
+++ b/public/language/tr/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 ve %2 şu başlıktaki gönderinize cevap verdi: %3",
"user_posted_to_multiple": "%1 ve %2 kişi daha şu başlıktaki gönderinize cevap verdi: %3",
"user_posted_topic": "%1 şu yeni konuyu yarattı: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 sizi takip etmeye başladı.",
"user_started_following_you_dual": "%1 ve %2 sizi takip etmeye başladı.",
"user_started_following_you_multiple": "%1 ve %2 kişi daha sizi takip etmeye başladı.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Birisi senin iletine artı oy verdiğinde",
"notificationType_new-topic": "Takip ettiğiniz birisi bir başlık gönderdiğinde",
"notificationType_new-reply": "İzlediğiniz bir başlığa yeni bir ileti gönderildiğinde",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Birisi seni takip etmeye başlayınca",
"notificationType_new-chat": "Bir sohbet mesajı aldığınızda",
"notificationType_group-invite": "Bir grup davetiyesi aldığınızda",
diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json
index 0757fa4bff..8f0426603a 100644
--- a/public/language/tr/topic.json
+++ b/public/language/tr/topic.json
@@ -135,5 +135,5 @@
"diffs.current-revision": "mevcut revizyon",
"diffs.original-revision": "orijinal revizyon",
"timeago_later": "%1 sonra",
- "timeago_earlier": "%1 daha öncesi"
+ "timeago_earlier": "%1 önce"
}
\ No newline at end of file
diff --git a/public/language/uk/notifications.json b/public/language/uk/notifications.json
index e0c4ab4f3e..05f0a1d99f 100644
--- a/public/language/uk/notifications.json
+++ b/public/language/uk/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 та %2 запостили відповіді до: %3",
"user_posted_to_multiple": "%1 та %2 інших запостили відповіді до: %3",
"user_posted_topic": "%1 запостив нову тему: %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 почав стежити за вами.",
"user_started_following_you_dual": "%1 та %2 почали стежити за вами.",
"user_started_following_you_multiple": "%1 та %2 інших почали стежити за вами.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Коли хтось голосує за ваш пост",
"notificationType_new-topic": "Коли хтось, кого ви читаєте, публікує тему",
"notificationType_new-reply": "Коли з'являється нова відповідь у темі, за якою ви слідкуєте",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Коли хтось починає слідкувати за вами",
"notificationType_new-chat": "Коли ви отримуєте повідомлення чату",
"notificationType_group-invite": "Коли ви отримуєте запрошення до групи",
diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json
index a847465ea9..90dd6b3a4a 100644
--- a/public/language/vi/notifications.json
+++ b/public/language/vi/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 và %2 đã trả lời: %3",
"user_posted_to_multiple": "%1 và %2 người khác đã trả lời: %3",
"user_posted_topic": "%1 đã gởi chủ đề mới ở %2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1 đã theo dõi bạn.",
"user_started_following_you_dual": "%1 và %2 đã bắt đầu theo dõi bạn.",
"user_started_following_you_multiple": "%1 và %2 người khác đã bắt đầu theo dõi bạn.",
@@ -53,6 +54,7 @@
"notificationType_upvote": "Khi ai đó thích bài đăng của bạn",
"notificationType_new-topic": "Khi người bạn theo dõi đăng một chủ đề",
"notificationType_new-reply": "Khi phản hồi được đăng trong chủ đề bạn đang quan tâm",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "Khi ai đó theo dõi bạn",
"notificationType_new-chat": "Khi bạn nhận được thông điệp chat",
"notificationType_group-invite": "Khi bạn nhận được lời mời gia nhập nhóm",
diff --git a/public/language/zh-CN/notifications.json b/public/language/zh-CN/notifications.json
index 31a7161d3d..bb1568511c 100644
--- a/public/language/zh-CN/notifications.json
+++ b/public/language/zh-CN/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 和 %2 回复了: %3",
"user_posted_to_multiple": "%1 和 %2 个其他人回复了: %3",
"user_posted_topic": "%1 发表了新主题:%2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1关注了您。",
"user_started_following_you_dual": "%1 和 %2 关注了您。",
"user_started_following_you_multiple": "%1 和 %2 个其他人关注了您。",
@@ -53,6 +54,7 @@
"notificationType_upvote": "当有人顶了我的帖子时",
"notificationType_new-topic": "当有人回复我的帖子时",
"notificationType_new-reply": "当您正在查看的主题中有新回复时",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "当有人关注您时",
"notificationType_new-chat": "当您收到聊天消息时",
"notificationType_group-invite": "当您收到群组邀请时",
diff --git a/public/language/zh-TW/notifications.json b/public/language/zh-TW/notifications.json
index 1eef215d99..445acb6a63 100644
--- a/public/language/zh-TW/notifications.json
+++ b/public/language/zh-TW/notifications.json
@@ -35,6 +35,7 @@
"user_posted_to_dual": "%1 和 %2 回覆了: %3",
"user_posted_to_multiple": "%1 和 %2 個其他人回覆了: %3",
"user_posted_topic": "%1 發表了新主題:%2",
+ "user_edited_post": "%1 has edited a post in %2",
"user_started_following_you": "%1追隨了您。",
"user_started_following_you_dual": "%1 和 %2 追隨了您。",
"user_started_following_you_multiple": "%1 和 %2 個其他人追隨了您。",
@@ -53,6 +54,7 @@
"notificationType_upvote": "當有人點贊了我的貼文時",
"notificationType_new-topic": "當有人回覆我的貼文時",
"notificationType_new-reply": "當您正在查看的主題中有新回覆時",
+ "notificationType_post-edit": "When a post is edited in a topic you are watching",
"notificationType_follow": "當有人追隨您時",
"notificationType_new-chat": "當您收到聊天訊息時",
"notificationType_group-invite": "當您收到群組邀請時",
diff --git a/public/openapi/read.yaml b/public/openapi/read.yaml
index f5ab877d9d..30f81ebc3c 100644
--- a/public/openapi/read.yaml
+++ b/public/openapi/read.yaml
@@ -15,15 +15,17 @@ info:
## Authentication
+ There are a multitude of ways to authenticate with the Read API.
+
### Cookie Authentication
This default authentication behaviour of this API is via cookie jar to find a valid session. A valid login session is required for API calls that pertain to operations involving a logged-in user. For example, `/api/unread` is a route showing unread topics, and is not accessible by guest users.
- ### Bearer Authentcation
+ ### Bearer Authentication
- The Write API offers bearer authentication, as administered through the administration panel.
+ Both the Read API and Write API offers bearer authentication, as administered through the administration panel.
- * For NodeBB v1.x, this is provided by [`nodebb-plugin-write-api`](https://github.com/NodeBB/nodebb-plugin-write-api).
+ * For NodeBB v1.x, this is provided by [`nodebb-plugin-write-api`](https://github.com/NodeBB/nodebb-plugin-write-api). The Write API plugin needs to be installed before authentication via bearer token is enabled on routes provided by the Read API.
* For NodeBB v2.x+ (in development), the Write API is available in core, and bearer authentication is available out-of-the-box
### JSON Web Token (JWT)
@@ -258,14 +260,6 @@ paths:
imageClass:
type: string
- $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/admin:
- get:
- tags:
- - admin
- summary: /api/admin
- responses:
- "418":
- description: "TODO: A proper response needs to be added. It is not really a teapot | This route is identical to /api/admin/general/dashboard. When the routes are split into separate files, replace this definition with a $ref to that route"
/api/admin/general/dashboard:
get:
tags:
@@ -578,7 +572,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/general/homepage
+ summary: Get homepage settings
responses:
"200":
description: ""
@@ -631,7 +625,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/categories
+ summary: Get category management settings
responses:
"200":
description: ""
@@ -643,7 +637,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/categories/{category_id}
+ summary: Get category settings
parameters:
- name: category_id
in: path
@@ -693,7 +687,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/categories/{category_id}/analytics
+ summary: Get category anayltics
parameters:
- name: category_id
in: path
@@ -1079,7 +1073,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users
+ summary: Get users
responses:
"200":
description: ""
@@ -1115,7 +1109,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/search
+ summary: Get users via search term
responses:
"200":
description: ""
@@ -1136,7 +1130,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/latest
+ summary: Get latest users
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1144,7 +1138,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/not-validated
+ summary: Get non-verified users
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1152,7 +1146,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/no-posts
+ summary: Get users with no posts
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1160,7 +1154,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/top-posters
+ summary: Get users with the most posts
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1168,7 +1162,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/most-reputation
+ summary: Get users with the most reputation
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1176,7 +1170,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/inactive
+ summary: Get inactive users
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1184,7 +1178,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/flagged
+ summary: Get flagged users
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1192,7 +1186,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/users/banned
+ summary: Get banned users
responses:
"418":
description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest"
@@ -1348,7 +1342,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/groups
+ summary: Get user groups
responses:
"200":
description: ""
@@ -1441,7 +1435,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/manage/groups/{name}
+ summary: Get user group details
parameters:
- name: name
in: path
@@ -1636,7 +1630,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/extend/plugins
+ summary: Get system plugin settings
responses:
"200":
description: ""
@@ -1788,7 +1782,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/extend/widgets
+ summary: Get widget settings
responses:
"200":
description: ""
@@ -2162,7 +2156,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/advanced/cache
+ summary: Get system cache info
responses:
"200":
description: ""
@@ -2254,7 +2248,7 @@ paths:
get:
tags:
- admin
- summary: /api/admin/development/logger
+ summary: Get system logger settings
responses:
"200":
description: ""
@@ -2759,7 +2753,8 @@ paths:
get:
tags:
- home
- summary: /api/config
+ summary: Get forum settings
+ description: This route retrieves forum settings and user-specific settings for client-side options on the forum.
responses:
"200":
description: ""
@@ -2892,23 +2887,131 @@ paths:
type: boolean
enableQuickReply:
type: boolean
- /api/me:
+ /api/users:
get:
tags:
- - shorthand
- summary: /api/me
+ - users
+ summary: Get users
+ parameters:
+ - in: query
+ name: section
+ schema:
+ type: string
+ enum: ['joindate', 'online', 'sort-posts', 'sort-reputation', 'banned', 'flagged']
+ required: false
+ description: Allows filtering of the user list via pre-defined sections
+ example: 'joindate'
+ - in: query
+ name: term
+ schema:
+ type: string
+ required: false
+ description: Allows for searching of user list
+ example: ''
responses:
"200":
description: ""
content:
application/json:
schema:
- $ref: components/schemas/UserObject.yaml#/UserObjectFull
+ allOf:
+ - type: object
+ properties:
+ users:
+ type: array
+ items:
+ type: object
+ properties:
+ uid:
+ type: number
+ description: A user identifier
+ username:
+ type: string
+ description: A friendly name for a given user account
+ userslug:
+ type: string
+ description: An URL-safe variant of the username (i.e. lower-cased, spaces
+ removed, etc.)
+ picture:
+ nullable: true
+ type: string
+ status:
+ type: string
+ postcount:
+ type: number
+ reputation:
+ type: number
+ email:confirmed:
+ type: number
+ description: Whether the user has confirmed their email address or not
+ lastonline:
+ type: number
+ flags:
+ nullable: true
+ banned:
+ type: number
+ banned:expire:
+ type: number
+ joindate:
+ type: number
+ description: A UNIX timestamp representing the moment the user's account was
+ created
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users without an
+ avatar
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with `icon:text`
+ for the user's auto-generated icon
+ example: "#f44336"
+ joindateISO:
+ type: string
+ lastonlineISO:
+ type: string
+ banned_until:
+ type: number
+ banned_until_readable:
+ type: string
+ administrator:
+ type: boolean
+ userCount:
+ type: number
+ title:
+ type: string
+ isAdminOrGlobalMod:
+ type: boolean
+ isAdmin:
+ type: boolean
+ isGlobalMod:
+ type: boolean
+ displayUserSearch:
+ type: boolean
+ section_joindate:
+ type: boolean
+ maximumInvites:
+ type: number
+ inviteOnly:
+ type: boolean
+ adminInviteOnly:
+ type: boolean
+ invites:
+ type: number
+ showInviteButton:
+ type: boolean
+ reputation:disabled:
+ type: number
+ - $ref: components/schemas/Pagination.yaml#/Pagination
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
"/api/user/uid/{uid}":
get:
tags:
- users
- summary: /api/user/uid/{uid}
+ summary: Get user by uid
+ description: This route retrieves a user's public profile data. If the calling user is the same as the profile, then it will also return data the user elected to hide (e.g. email/fullname)
parameters:
- name: uid
in: path
@@ -2927,7 +3030,8 @@ paths:
get:
tags:
- users
- summary: /api/user/username/{username}
+ summary: Get user by username
+ description: This route retrieves a user's public profile data. If the calling user is the same as the profile, then it will also return data the user elected to hide (e.g. email/fullname)
parameters:
- name: username
in: path
@@ -2946,7 +3050,8 @@ paths:
get:
tags:
- users
- summary: /api/user/email/{email}
+ summary: Get user by email
+ description: This route retrieves a user's public profile data. If the calling user is the same as the profile, then it will also return data the user elected to hide (e.g. email/fullname)
parameters:
- name: email
in: path
@@ -2985,7 +3090,7 @@ paths:
get:
tags:
- users
- summary: /api/user/uid/{userslug}/export/uploads
+ summary: Export a user's uploads (.zip)
parameters:
- name: userslug
in: path
@@ -3005,7 +3110,7 @@ paths:
get:
tags:
- users
- summary: /api/user/uid/{userslug}/export/profile
+ summary: Export a user's profile data (.csv)
parameters:
- name: userslug
in: path
@@ -3434,456 +3539,11 @@ paths:
- 1
- 2
- 3
- "/api/recent/posts/{term?}":
- get:
- tags:
- - topics
- summary: /api/recent/posts/{term?}
- parameters:
- - name: term?
- in: path
- required: true
- schema:
- type: string
- example: day
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- $ref: components/schemas/PostsObject.yaml#/PostsObject
- /api/unread/total:
- get:
- tags:
- - topics
- summary: Get number of unread topics
- responses:
- "200":
- description: "Success"
- content:
- text/plain:
- schema:
- type: number
- "/api/topic/teaser/{topic_id}":
- get:
- tags:
- - topics
- summary: Get a topic's teaser post
- parameters:
- - name: topic_id
- in: path
- required: true
- schema:
- type: string
- example: 1
- responses:
- "200":
- description: "A JSON object containing the teaser post for a topic"
- content:
- application/json:
- schema:
- $ref: components/schemas/PostsObject.yaml#/PostsObject
- "/api/topic/pagination/{topic_id}":
- get:
- tags:
- - topics
- summary: /api/topic/pagination/{topic_id}
- parameters:
- - name: topic_id
- in: path
- required: true
- schema:
- type: string
- example: 1
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- $ref: components/schemas/Pagination.yaml#/Pagination
- /api/post/upload:
- post:
- tags:
- - posts
- summary: /api/post/upload
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- text/plain:
- schema:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- "403":
- description: ""
- content:
- application/json:
- schema:
- type: string
- example: Forbidden
- text/plain:
- schema:
- type: string
- example: Forbidden
- "500":
- description: ""
- content:
- application/json:
- schema:
- type: object
- properties:
- path:
- type: string
- error:
- type: string
- text/plain:
- schema:
- type: object
- properties:
- path:
- type: string
- error:
- type: string
- /api/topic/thumb/upload:
- post:
- tags:
- - topics
- summary: Upload topic thumb
- requestBody:
- required: true
- content:
- multipart/form-data:
- schema:
- type: object
- properties:
- files:
- type: array
- items:
- type: string
- format: binary
- required:
- - files
- responses:
- "200":
- description: "Image uploaded"
- content:
- application/json:
- schema:
- type: object
- properties:
- name:
- type: string
- description: The filename
- url:
- type: string
- description: URL of the uploaded image for use client-side
- path:
- type: string
- description: Path to the file in the local file system
- /api/login:
- get:
- tags:
- - authentication
- summary: /api/login
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- loginFormEntry:
- type: array
- items:
- type: object
- properties:
- label:
- type: string
- description: A label for the added block
- html:
- type: string
- description: HTML to render on the login page
- styleName:
- type: string
- description: Custom identifier (value is added to `input[id]` and `label[for]`)
- alternate_logins:
- type: boolean
- authentication:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- callbackURL:
- type: string
- icon:
- type: string
- scope:
- type: string
- prompt:
- type: string
- allowRegistration:
- type: boolean
- allowLoginWith:
- type: string
- title:
- type: string
- allowPasswordReset:
- type: boolean
- allowLocalLogin:
- type: boolean
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/register:
- get:
- tags:
- - authentication
- summary: /api/register
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- register_window:spansize:
- type: string
- alternate_logins:
- type: boolean
- authentication:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- callbackURL:
- type: string
- icon:
- type: string
- scope:
- type: string
- prompt:
- type: string
- minimumUsernameLength:
- type: number
- maximumUsernameLength:
- type: number
- minimumPasswordLength:
- type: number
- minimumPasswordStrength:
- type: number
- regFormEntry:
- type: array
- items:
- type: object
- properties:
- label:
- type: string
- html:
- type: string
- styleName:
- type: string
- title:
- type: string
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- # /api/register/complete:
- # get:
- # tags:
- # - authentication
- # summary: /api/register/complete
- # responses:
- # "200":
- # description: ""
- # content:
- # application/json:
- # schema:
- # allOf:
- # - type: object
- # properties:
- # title:
- # type: string
- # errors:
- # type: array
- # items: {}
- # sections:
- # type: array
- # items:
- # type: string
- # - $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/search:
- get:
- tags:
- - search
- summary: /api/search
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- posts:
- $ref: components/schemas/PostsObject.yaml#/PostsObject
- matchCount:
- type: number
- pageCount:
- type: number
- time:
- type: string
- multiplePages:
- type: boolean
- search_query:
- type: string
- term:
- type: string
- categories:
- type: array
- items:
- type: object
- properties:
- value:
- oneOf:
- - type: string
- - type: number
- text:
- type: string
- categoriesCount:
- type: number
- expandSearch:
- type: boolean
- showAsPosts:
- type: boolean
- showAsTopics:
- type: boolean
- title:
- type: string
- searchDefaultSortBy:
- type: string
- required:
- - posts
- - matchCount
- - pageCount
- - time
- - multiplePages
- - search_query
- - categories
- - categoriesCount
- - expandSearch
- - showAsPosts
- - showAsTopics
- - title
- - searchDefaultSortBy
- - $ref: components/schemas/Pagination.yaml#/Pagination
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- "/api/reset":
- get:
- tags:
- - authentication
- summary: Get user password reset (step 1)
- responses:
- "200":
- description: "A JSON object containing the 1st step of the user password reset flow"
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- code:
- type: string
- nullable: true
- title:
- type: string
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- "/api/reset/{code}":
- get:
- tags:
- - authentication
- summary: Get user password reset (step 2)
- parameters:
- - name: code
- in: path
- required: true
- schema:
- type: string
- example: testCode
- responses:
- "200":
- description: "A JSON object containing the 2nd step of the user password reset flow"
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- valid:
- type: boolean
- code:
- type: string
- minimumPasswordLength:
- type: number
- minimumPasswordStrength:
- type: number
- title:
- type: string
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- "/api/email/unsubscribe/{token}":
- # TODO: Need GET route here as well
- post:
- tags:
- - emails
- summary: /api/email/unsubscribe/{token}
- parameters:
- - name: token
- in: path
- required: true
- schema:
- type: string
- example: testToken
- responses:
- "200":
- description: "Successfully unsubscribed"
- "500":
- description: "Server-side error (likely token verification failure)"
"/api/topic/{topic_id}/{slug}/{post_index}":
get:
tags:
- topics
- summary: /api/topic/{topic_id}/{slug}/{post_index}
+ summary: Get topic data
parameters:
- name: topic_id
in: path
@@ -3892,12 +3552,14 @@ paths:
type: string
example: 1
- name: slug
+ description: This parameter is not required. If omitted, the request will be automatically redirected with the proper topic slug.
in: path
required: true
schema:
type: string
example: test-topic
- name: post_index
+ description: This parameter is not required. If omitted, the request will presume that you want the first post. The API response is largely unaffected by this parameter, it is used client-side (to send the user to the requested post), and changes the meta/link tags in the server-side generated HTML.
in: path
required: true
schema:
@@ -4280,946 +3942,11 @@ paths:
- $ref: components/schemas/Pagination.yaml#/Pagination
- $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- $ref: components/schemas/CommonProps.yaml#/CommonProps
- "/api/topic/{topic_id}/{slug}":
- get:
- tags:
- - topics
- summary: /api/topic/{topic_id}/{slug}
- parameters:
- - name: topic_id
- in: path
- required: true
- schema:
- type: string
- example: 1
- - name: slug
- in: path
- required: true
- schema:
- type: string
- example: ''
- responses:
- "418":
- description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from the route w/o post_index"
- "/api/post/{pid}":
- get:
- tags:
- - shorthand
- summary: Access a specific post
- description: This route comes in handy when all you have is the `pid`, and you want to redirect users to the canonical URL for the topic, with the appropriate topic slug and post index.
- parameters:
- - name: pid
- in: path
- required: true
- schema:
- type: string
- example: 1
- responses:
- "200":
- description: "Canonical URL of topic"
- content:
- text/plain:
- schema:
- type: string
- /api/flags:
- get:
- tags:
- - flags
- summary: /api/flags
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- flags:
- type: array
- items:
- type: object
- properties:
- state:
- type: string
- flagId:
- type: number
- type:
- type: string
- targetId:
- oneOf:
- - type: string
- - type: number
- description:
- type: string
- uid:
- type: number
- description: A user identifier
- datetime:
- type: number
- reporter:
- type: object
- properties:
- username:
- type: string
- description: A friendly name for a given user account
- picture:
- nullable: true
- type: string
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with
- `icon:text` for the user's auto-generated
- icon
- example: "#f44336"
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users without
- an avatar
- labelClass:
- type: string
- target_readable:
- type: string
- datetimeISO:
- type: string
- assignee:
- type: string
- nullable: true
- analytics:
- type: array
- items:
- type: number
- categories:
- type: object
- properties: {}
- additionalProperties:
- type: string
- description: All categories will be listed here, with the `cid` as the key, and the category name as the value
- hasFilter:
- type: boolean
- filters:
- type: object
- properties:
- page:
- type: number
- perPage:
- type: number
- title:
- type: string
- - $ref: components/schemas/Pagination.yaml#/Pagination
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- "/api/flags/{flagId}":
- get:
- tags:
- - flags
- summary: /api/flags/{flagId}
- parameters:
- - name: flagId
- in: path
- required: true
- schema:
- type: string
- example: 1
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- state:
- type: string
- flagId:
- type: number
- type:
- type: string
- targetId:
- type: number
- description:
- type: string
- uid:
- type: number
- description: A user identifier
- datetime:
- type: number
- datetimeISO:
- type: string
- target_readable:
- type: string
- target:
- type: object
- properties: {}
- additionalProperties:
- description: Properties change depending on the target type (user, post, etc.)
- assignee:
- type: number
- nullable: true
- filters:
- type: object
- properties:
- page:
- type: number
- perPage:
- type: number
- history:
- type: array
- items:
- type: object
- properties:
- uid:
- type: number
- description: A user identifier
- fields:
- type: object
- properties:
- state:
- type: string
- datetime:
- type: number
- datetimeISO:
- type: string
- user:
- type: object
- properties:
- username:
- type: string
- description: A friendly name for a given user account
- userslug:
- type: string
- description: An URL-safe variant of the username (i.e. lower-cased, spaces
- removed, etc.)
- picture:
- nullable: true
- uid:
- type: number
- description: A user identifier
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users without
- an avatar
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with
- `icon:text` for the user's auto-generated
- icon
- example: "#f44336"
- notes:
- type: array
- items:
- type: object
- properties:
- uid:
- type: number
- content:
- type: string
- datetime:
- type: number
- datetimeISO:
- type: string
- user:
- type: object
- properties:
- username:
- type: string
- description: A friendly name for a given user account
- userslug:
- type: string
- description: An URL-safe variant of the username (i.e. lower-cased, spaces
- removed, etc.)
- picture:
- type: string
- uid:
- type: number
- description: A user identifier
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users without
- an avatar
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with
- `icon:text` for the user's auto-generated
- icon
- example: "#f44336"
- reporter:
- type: object
- properties:
- username:
- type: string
- description: A friendly name for a given user account
- userslug:
- type: string
- description: An URL-safe variant of the username (i.e. lower-cased, spaces
- removed, etc.)
- picture:
- nullable: true
- reputation:
- type: number
- uid:
- type: number
- description: A user identifier
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users without an
- avatar
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with `icon:text` for
- the user's auto-generated icon
- example: "#f44336"
- type_path:
- type: string
- assignees:
- type: array
- items:
- $ref: components/schemas/UserObject.yaml#/UserObject
- type_bool:
- type: object
- properties:
- post:
- type: boolean
- user:
- type: boolean
- empty:
- type: boolean
- title:
- type: string
- categories:
- type: object
- additionalProperties:
- type: string
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/post-queue:
- get:
- tags:
- - admin
- summary: /api/post-queue
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- title:
- type: string
- posts:
- type: array
- items:
- allOf:
- - type: object
- properties:
- id:
- type: string
- uid:
- type: number
- description: A user identifier
- type:
- type: string
- data:
- type: object
- properties:
- title:
- type: string
- content:
- type: string
- thumb:
- type: string
- cid:
- oneOf:
- - type: number
- - type: string
- tags:
- type: array
- items: {}
- uid:
- type: number
- description: A user identifier
- req:
- type: object
- properties:
- uid:
- type: number
- description: A user identifier
- ip:
- type: string
- host:
- type: string
- protocol:
- type: string
- secure:
- type: boolean
- url:
- type: string
- path:
- type: string
- headers:
- type: object
- properties:
- x-real-ip:
- type: string
- x-forwarded-for:
- type: string
- x-forwarded-proto:
- type: string
- host:
- type: string
- x-nginx-proxy:
- type: string
- connection:
- type: string
- accept:
- type: string
- user-agent:
- type: string
- sec-fetch-site:
- type: string
- sec-fetch-mode:
- type: string
- referer:
- type: string
- accept-encoding:
- type: string
- accept-language:
- type: string
- cookie:
- type: string
- timestamp:
- type: number
- fromQueue:
- type: boolean
- timestampISO:
- type: string
- description: An ISO 8601 formatted date string (complementing `timestamp`)
- rawContent:
- type: string
- tid:
- type: number
- description: A topic identifier
- toPid:
- nullable: true
- user:
- type: object
- properties:
- username:
- type: string
- description: A friendly name for a given user account
- userslug:
- type: string
- description: An URL-safe variant of the username (i.e. lower-cased, spaces
- removed, etc.)
- picture:
- nullable: true
- type: string
- uid:
- type: number
- description: A user identifier
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users without
- an avatar
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with
- `icon:text` for the user's auto-generated
- icon
- example: "#f44336"
- topic:
- type: object
- properties:
- cid:
- type: number
- title:
- type: string
- titleRaw:
- type: string
- - $ref: components/schemas/CategoryObject.yaml#/CategoryObject
- - $ref: components/schemas/Pagination.yaml#/Pagination
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/ip-blacklist:
- get:
- tags:
- - admin
- summary: /api/ip-blacklist
- responses:
- "418":
- description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route"
- /api/registration-queue:
- get:
- tags:
- - admin
- summary: /api/registration-queue
- responses:
- "418":
- description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route"
- "/api/tags/{tag}":
- get:
- tags:
- - tags
- summary: /api/tags/{tag}
- description: Returns a list of topics that are tagged with {tag}
- parameters:
- - name: tag
- description: The tag used to retrieve the topics
- in: path
- required: true
- schema:
- type: string
- example: test
- - name: page
- description: Page number used in pagination
- in: query
- required: false
- schema:
- type: number
- example: ''
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- topics:
- type: array
- description: An array of topics that are all tagged with {tag}
- items:
- type: object
- properties:
- tid:
- type: number
- description: A topic identifier
- uid:
- type: number
- description: A user identifier
- cid:
- type: number
- description: A category identifier
- mainPid:
- type: number
- description: The post id of the first post in this topic (also called the
- "original post")
- title:
- type: string
- slug:
- type: string
- timestamp:
- type: number
- lastposttime:
- type: number
- postcount:
- type: number
- viewcount:
- type: number
- teaserPid:
- oneOf:
- - type: number
- - type: string
- deleted:
- type: number
- locked:
- type: number
- pinned:
- type: number
- description: Whether or not this particular topic is pinned to the top of the
- category
- upvotes:
- type: number
- downvotes:
- type: number
- titleRaw:
- type: string
- timestampISO:
- type: string
- description: An ISO 8601 formatted date string (complementing `timestamp`)
- lastposttimeISO:
- type: string
- votes:
- type: number
- category:
- type: object
- properties:
- cid:
- type: number
- description: A category identifier
- name:
- type: string
- slug:
- type: string
- icon:
- type: string
- image:
- nullable: true
- imageClass:
- nullable: true
- type: string
- bgColor:
- type: string
- color:
- type: string
- disabled:
- type: number
- user:
- type: object
- properties:
- uid:
- type: number
- description: A user identifier
- username:
- type: string
- description: A friendly name for a given user account
- userslug:
- type: string
- description: An URL-safe variant of the username (i.e. lower-cased, spaces
- removed, etc.)
- reputation:
- type: number
- postcount:
- type: number
- picture:
- nullable: true
- type: string
- signature:
- nullable: true
- type: string
- banned:
- type: number
- status:
- type: string
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users without
- an avatar
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with
- `icon:text` for the user's auto-generated
- icon
- example: "#f44336"
- banned_until_readable:
- type: string
- fullname:
- type: string
- teaser:
- type: object
- properties:
- pid:
- type: number
- uid:
- type: number
- description: A user identifier
- timestamp:
- type: number
- tid:
- type: number
- description: A topic identifier
- content:
- type: string
- timestampISO:
- type: string
- description: An ISO 8601 formatted date string (complementing `timestamp`)
- user:
- type: object
- properties:
- uid:
- type: number
- description: A user identifier
- username:
- type: string
- description: A friendly name for a given user account
- userslug:
- type: string
- description: An URL-safe variant of the username (i.e. lower-cased, spaces
- removed, etc.)
- picture:
- nullable: true
- type: string
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users
- without an avatar
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with
- `icon:text` for the user's
- auto-generated icon
- example: "#f44336"
- index:
- type: number
- tags:
- type: array
- items:
- type: object
- properties:
- value:
- type: string
- valueEscaped:
- type: string
- color:
- type: string
- bgColor:
- type: string
- score:
- type: number
- isOwner:
- type: boolean
- ignored:
- type: boolean
- unread:
- type: boolean
- bookmark:
- nullable: true
- unreplied:
- type: boolean
- icons:
- type: array
- items: {}
- index:
- type: number
- thumb:
- type: string
- isQuestion:
- nullable: true
- type: number
- isSolved:
- type: number
- tag:
- type: string
- title:
- type: string
- categories:
- type: array
- items:
- type: object
- properties:
- cid:
- type: number
- description: A category identifier
- name:
- type: string
- level:
- type: string
- icon:
- type: string
- parentCid:
- type: number
- description: The category identifier for the category that is the immediate
- ancestor of the current category
- color:
- type: string
- bgColor:
- type: string
- selected:
- type: boolean
- imageClass:
- type: string
- rssFeedUrl:
- type: string
- required:
- - topics
- - tag
- - title
- - categories
- - $ref: components/schemas/Pagination.yaml#/Pagination
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/tags:
- get:
- tags:
- - tags
- summary: /api/tags
- description: Returns a list of tags sorted by the most topics
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- tags:
- type: array
- description: An array of tags sorted by the most topics
- items:
- type: object
- properties:
- value:
- type: string
- description: The raw tag
- score:
- type: number
- description: Number of topics tagged by this tag
- valueEscaped:
- type: string
- description: This is the escaped tag value, equal to validator.escape(value)
- color:
- type: string
- bgColor:
- type: string
- displayTagSearch:
- type: boolean
- nextStart:
- type: number
- title:
- type: string
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/popular:
- get:
- tags:
- - topics
- summary: Get Popular Topics
- description: Returns a list of topics sorted by most replies. In an event of a
- tie breaker, the topic with the most views. Can be filtered by All Time,
- Day, Week, or Month.
- responses:
- "200":
- description: An array of topic objects sorted by most replies and views.
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- nextStart:
- type: number
- topicCount:
- type: number
- topics:
- type: array
- items:
- $ref: components/schemas/TopicObject.yaml#/TopicObject
- tids:
- type: array
- items:
- type: number
- canPost:
- type: boolean
- categories:
- type: array
- items:
- type: object
- properties:
- cid:
- type: number
- description: A category identifier
- name:
- type: string
- level:
- type: string
- icon:
- type: string
- parentCid:
- type: number
- description: The category identifier for the category that is the immediate
- ancestor of the current category
- color:
- type: string
- bgColor:
- type: string
- selected:
- type: boolean
- imageClass:
- type: string
- allCategoriesUrl:
- type: string
- selectedCategory:
- type: object
- properties:
- icon:
- type: string
- name:
- type: string
- bgColor:
- type: string
- nullable: true
- selectedCids:
- type: array
- items:
- type: number
- feeds:disableRSS:
- type: number
- rssFeedUrl:
- type: string
- title:
- type: string
- filters:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- filter:
- type: string
- selectedFilter:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- filter:
- type: string
- terms:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- term:
- type: string
- selectedTerm:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- term:
- type: string
- - $ref: components/schemas/Pagination.yaml#/Pagination
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
/api/recent:
get:
tags:
- topics
- summary: Recent Topics
+ summary: Get recent topics
description: Returns a list of topics sorted by timestamp.
responses:
"200":
@@ -5343,152 +4070,30 @@ paths:
- $ref: components/schemas/Pagination.yaml#/Pagination
- $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- $ref: components/schemas/CommonProps.yaml#/CommonProps
- /api/top:
+ "/api/recent/posts/{term}":
get:
tags:
- - topics
- summary: Top Topics
- description: Returns a list of topics sorted by most upvotes.
+ - posts
+ summary: Get recent posts
+ parameters:
+ - name: term
+ in: path
+ required: true
+ schema:
+ type: string
+ example: daily
responses:
"200":
- description: An array of topic objects sorted by most upvotes.
+ description: ""
content:
application/json:
schema:
- allOf:
- - type: object
- properties:
- nextStart:
- type: number
- topicCount:
- type: number
- topics:
- type: array
- items:
- $ref: components/schemas/TopicObject.yaml#/TopicObject
- tids:
- type: array
- items:
- type: number
- canPost:
- type: boolean
- categories:
- type: array
- items:
- type: object
- properties:
- cid:
- type: number
- description: A category identifier
- name:
- type: string
- level:
- type: string
- icon:
- type: string
- parentCid:
- type: number
- description: The category identifier for the category that is the immediate
- ancestor of the current category
- color:
- type: string
- bgColor:
- type: string
- selected:
- type: boolean
- imageClass:
- type: string
- allCategoriesUrl:
- type: string
- selectedCategory:
- type: object
- properties:
- cid:
- type: number
- description: A category identifier
- name:
- type: string
- level:
- type: string
- icon:
- type: string
- parentCid:
- type: number
- description: The category identifier for the category that is the immediate
- ancestor of the current category
- color:
- type: string
- bgColor:
- type: string
- selected:
- type: boolean
- nullable: true
- selectedCids:
- type: array
- items:
- type: number
- feeds:disableRSS:
- type: number
- rssFeedUrl:
- type: string
- title:
- type: string
- filters:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- filter:
- type: string
- selectedFilter:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- filter:
- type: string
- terms:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- term:
- type: string
- selectedTerm:
- type: object
- properties:
- name:
- type: string
- url:
- type: string
- selected:
- type: boolean
- term:
- type: string
- - $ref: components/schemas/Pagination.yaml#/Pagination
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ $ref: components/schemas/PostsObject.yaml#/PostsObject
/api/unread:
get:
tags:
- topics
- summary: Unread Topics
+ summary: Get unread topics
description: Returns a list of the current user's unread topics, sorted by the
last post's timestamp.
responses:
@@ -5769,11 +4374,1495 @@ paths:
- $ref: components/schemas/Pagination.yaml#/Pagination
- $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- $ref: components/schemas/CommonProps.yaml#/CommonProps
+ /api/unread/total:
+ get:
+ tags:
+ - topics
+ summary: Get number of unread topics
+ responses:
+ "200":
+ description: "Success"
+ content:
+ text/plain:
+ schema:
+ type: number
+ "/api/topic/teaser/{topic_id}":
+ get:
+ tags:
+ - topics
+ summary: Get a topic's teaser post
+ parameters:
+ - name: topic_id
+ in: path
+ required: true
+ schema:
+ type: string
+ example: 1
+ responses:
+ "200":
+ description: "A JSON object containing the teaser post for a topic"
+ content:
+ application/json:
+ schema:
+ $ref: components/schemas/PostsObject.yaml#/PostsObject
+ "/api/topic/pagination/{topic_id}":
+ get:
+ tags:
+ - topics
+ summary: Get topic pagination data
+ description: This route retrieves pagination data for a given topic. It is used mainly client-side, as it return data necessary to update a pagination block client-side.
+ parameters:
+ - name: topic_id
+ in: path
+ required: true
+ schema:
+ type: string
+ example: 1
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ $ref: components/schemas/Pagination.yaml#/Pagination
+ /api/post/upload:
+ post:
+ tags:
+ - posts
+ summary: Upload a file to a specific post
+ description: Provided by NodeBB core and used mainly by the composer, this route allows you to upload an image or file to a post.
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ text/plain:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ "403":
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: string
+ example: Forbidden
+ text/plain:
+ schema:
+ type: string
+ example: Forbidden
+ "500":
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ path:
+ type: string
+ error:
+ type: string
+ text/plain:
+ schema:
+ type: object
+ properties:
+ path:
+ type: string
+ error:
+ type: string
+ /api/topic/thumb/upload:
+ post:
+ tags:
+ - topics
+ summary: Upload topic thumb
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ files:
+ type: array
+ items:
+ type: string
+ format: binary
+ required:
+ - files
+ responses:
+ "200":
+ description: "Image uploaded"
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ name:
+ type: string
+ description: The filename
+ url:
+ type: string
+ description: URL of the uploaded image for use client-side
+ path:
+ type: string
+ description: Path to the file in the local file system
+ /api/login:
+ get:
+ tags:
+ - authentication
+ summary: /api/login
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ loginFormEntry:
+ type: array
+ items:
+ type: object
+ properties:
+ label:
+ type: string
+ description: A label for the added block
+ html:
+ type: string
+ description: HTML to render on the login page
+ styleName:
+ type: string
+ description: Custom identifier (value is added to `input[id]` and `label[for]`)
+ alternate_logins:
+ type: boolean
+ authentication:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ callbackURL:
+ type: string
+ icon:
+ type: string
+ scope:
+ type: string
+ prompt:
+ type: string
+ allowRegistration:
+ type: boolean
+ allowLoginWith:
+ type: string
+ title:
+ type: string
+ allowPasswordReset:
+ type: boolean
+ allowLocalLogin:
+ type: boolean
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ /api/register:
+ get:
+ tags:
+ - authentication
+ summary: /api/register
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ register_window:spansize:
+ type: string
+ alternate_logins:
+ type: boolean
+ authentication:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ callbackURL:
+ type: string
+ icon:
+ type: string
+ scope:
+ type: string
+ prompt:
+ type: string
+ minimumUsernameLength:
+ type: number
+ maximumUsernameLength:
+ type: number
+ minimumPasswordLength:
+ type: number
+ minimumPasswordStrength:
+ type: number
+ regFormEntry:
+ type: array
+ items:
+ type: object
+ properties:
+ label:
+ type: string
+ html:
+ type: string
+ styleName:
+ type: string
+ title:
+ type: string
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ # /api/register/complete:
+ # get:
+ # tags:
+ # - authentication
+ # summary: /api/register/complete
+ # responses:
+ # "200":
+ # description: ""
+ # content:
+ # application/json:
+ # schema:
+ # allOf:
+ # - type: object
+ # properties:
+ # title:
+ # type: string
+ # errors:
+ # type: array
+ # items: {}
+ # sections:
+ # type: array
+ # items:
+ # type: string
+ # - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ /api/search:
+ get:
+ tags:
+ - search
+ summary: Get search results
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ posts:
+ $ref: components/schemas/PostsObject.yaml#/PostsObject
+ matchCount:
+ type: number
+ pageCount:
+ type: number
+ time:
+ type: string
+ multiplePages:
+ type: boolean
+ search_query:
+ type: string
+ term:
+ type: string
+ categories:
+ type: array
+ items:
+ type: object
+ properties:
+ value:
+ oneOf:
+ - type: string
+ - type: number
+ text:
+ type: string
+ categoriesCount:
+ type: number
+ expandSearch:
+ type: boolean
+ showAsPosts:
+ type: boolean
+ showAsTopics:
+ type: boolean
+ title:
+ type: string
+ searchDefaultSortBy:
+ type: string
+ required:
+ - posts
+ - matchCount
+ - pageCount
+ - time
+ - multiplePages
+ - search_query
+ - categories
+ - categoriesCount
+ - expandSearch
+ - showAsPosts
+ - showAsTopics
+ - title
+ - searchDefaultSortBy
+ - $ref: components/schemas/Pagination.yaml#/Pagination
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ "/api/reset":
+ get:
+ tags:
+ - authentication
+ summary: Get user password reset (step 1)
+ responses:
+ "200":
+ description: "A JSON object containing the 1st step of the user password reset flow"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ code:
+ type: string
+ nullable: true
+ title:
+ type: string
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ "/api/reset/{code}":
+ get:
+ tags:
+ - authentication
+ summary: Get user password reset (step 2)
+ parameters:
+ - name: code
+ in: path
+ required: true
+ schema:
+ type: string
+ example: testCode
+ responses:
+ "200":
+ description: "A JSON object containing the 2nd step of the user password reset flow"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ valid:
+ type: boolean
+ code:
+ type: string
+ minimumPasswordLength:
+ type: number
+ minimumPasswordStrength:
+ type: number
+ title:
+ type: string
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ "/api/email/unsubscribe/{token}":
+ # TODO: Need GET route here as well
+ post:
+ tags:
+ - emails
+ summary: Unsubscribe user from email type
+ parameters:
+ - name: token
+ in: path
+ required: true
+ schema:
+ type: string
+ example: testToken
+ responses:
+ "200":
+ description: "Successfully unsubscribed"
+ "500":
+ description: "Server-side error (likely token verification failure)"
+ "/api/post/{pid}":
+ get:
+ tags:
+ - shorthand
+ summary: Access a specific post
+ description: This route comes in handy when all you have is the `pid`, and you want to redirect users to the canonical URL for the topic, with the appropriate topic slug and post index.
+ parameters:
+ - name: pid
+ in: path
+ required: true
+ schema:
+ type: string
+ example: 1
+ responses:
+ "200":
+ description: "Canonical URL of topic"
+ content:
+ text/plain:
+ schema:
+ type: string
+ /api/flags:
+ get:
+ tags:
+ - flags
+ summary: Get flags list
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ flags:
+ type: array
+ items:
+ type: object
+ properties:
+ state:
+ type: string
+ flagId:
+ type: number
+ type:
+ type: string
+ targetId:
+ oneOf:
+ - type: string
+ - type: number
+ description:
+ type: string
+ uid:
+ type: number
+ description: A user identifier
+ datetime:
+ type: number
+ reporter:
+ type: object
+ properties:
+ username:
+ type: string
+ description: A friendly name for a given user account
+ picture:
+ nullable: true
+ type: string
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with
+ `icon:text` for the user's auto-generated
+ icon
+ example: "#f44336"
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users without
+ an avatar
+ labelClass:
+ type: string
+ target_readable:
+ type: string
+ datetimeISO:
+ type: string
+ assignee:
+ type: string
+ nullable: true
+ analytics:
+ type: array
+ items:
+ type: number
+ categories:
+ type: object
+ properties: {}
+ additionalProperties:
+ type: string
+ description: All categories will be listed here, with the `cid` as the key, and the category name as the value
+ hasFilter:
+ type: boolean
+ filters:
+ type: object
+ properties:
+ page:
+ type: number
+ perPage:
+ type: number
+ title:
+ type: string
+ - $ref: components/schemas/Pagination.yaml#/Pagination
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ "/api/flags/{flagId}":
+ get:
+ tags:
+ - flags
+ summary: /api/flags/{flagId}
+ parameters:
+ - name: flagId
+ in: path
+ required: true
+ schema:
+ type: string
+ example: 1
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ state:
+ type: string
+ flagId:
+ type: number
+ type:
+ type: string
+ targetId:
+ type: number
+ description:
+ type: string
+ uid:
+ type: number
+ description: A user identifier
+ datetime:
+ type: number
+ datetimeISO:
+ type: string
+ target_readable:
+ type: string
+ target:
+ type: object
+ properties: {}
+ additionalProperties:
+ description: Properties change depending on the target type (user, post, etc.)
+ assignee:
+ type: number
+ nullable: true
+ filters:
+ type: object
+ properties:
+ page:
+ type: number
+ perPage:
+ type: number
+ history:
+ type: array
+ items:
+ type: object
+ properties:
+ uid:
+ type: number
+ description: A user identifier
+ fields:
+ type: object
+ properties:
+ state:
+ type: string
+ datetime:
+ type: number
+ datetimeISO:
+ type: string
+ user:
+ type: object
+ properties:
+ username:
+ type: string
+ description: A friendly name for a given user account
+ userslug:
+ type: string
+ description: An URL-safe variant of the username (i.e. lower-cased, spaces
+ removed, etc.)
+ picture:
+ nullable: true
+ uid:
+ type: number
+ description: A user identifier
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users without
+ an avatar
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with
+ `icon:text` for the user's auto-generated
+ icon
+ example: "#f44336"
+ notes:
+ type: array
+ items:
+ type: object
+ properties:
+ uid:
+ type: number
+ content:
+ type: string
+ datetime:
+ type: number
+ datetimeISO:
+ type: string
+ user:
+ type: object
+ properties:
+ username:
+ type: string
+ description: A friendly name for a given user account
+ userslug:
+ type: string
+ description: An URL-safe variant of the username (i.e. lower-cased, spaces
+ removed, etc.)
+ picture:
+ type: string
+ uid:
+ type: number
+ description: A user identifier
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users without
+ an avatar
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with
+ `icon:text` for the user's auto-generated
+ icon
+ example: "#f44336"
+ reporter:
+ type: object
+ properties:
+ username:
+ type: string
+ description: A friendly name for a given user account
+ userslug:
+ type: string
+ description: An URL-safe variant of the username (i.e. lower-cased, spaces
+ removed, etc.)
+ picture:
+ nullable: true
+ reputation:
+ type: number
+ uid:
+ type: number
+ description: A user identifier
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users without an
+ avatar
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with `icon:text` for
+ the user's auto-generated icon
+ example: "#f44336"
+ type_path:
+ type: string
+ assignees:
+ type: array
+ items:
+ $ref: components/schemas/UserObject.yaml#/UserObject
+ type_bool:
+ type: object
+ properties:
+ post:
+ type: boolean
+ user:
+ type: boolean
+ empty:
+ type: boolean
+ title:
+ type: string
+ categories:
+ type: object
+ additionalProperties:
+ type: string
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ /api/post-queue:
+ get:
+ tags:
+ - admin
+ summary: Get flag data
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ title:
+ type: string
+ posts:
+ type: array
+ items:
+ allOf:
+ - type: object
+ properties:
+ id:
+ type: string
+ uid:
+ type: number
+ description: A user identifier
+ type:
+ type: string
+ data:
+ type: object
+ properties:
+ title:
+ type: string
+ content:
+ type: string
+ thumb:
+ type: string
+ cid:
+ oneOf:
+ - type: number
+ - type: string
+ tags:
+ type: array
+ items: {}
+ uid:
+ type: number
+ description: A user identifier
+ req:
+ type: object
+ properties:
+ uid:
+ type: number
+ description: A user identifier
+ ip:
+ type: string
+ host:
+ type: string
+ protocol:
+ type: string
+ secure:
+ type: boolean
+ url:
+ type: string
+ path:
+ type: string
+ headers:
+ type: object
+ properties:
+ x-real-ip:
+ type: string
+ x-forwarded-for:
+ type: string
+ x-forwarded-proto:
+ type: string
+ host:
+ type: string
+ x-nginx-proxy:
+ type: string
+ connection:
+ type: string
+ accept:
+ type: string
+ user-agent:
+ type: string
+ sec-fetch-site:
+ type: string
+ sec-fetch-mode:
+ type: string
+ referer:
+ type: string
+ accept-encoding:
+ type: string
+ accept-language:
+ type: string
+ cookie:
+ type: string
+ timestamp:
+ type: number
+ fromQueue:
+ type: boolean
+ timestampISO:
+ type: string
+ description: An ISO 8601 formatted date string (complementing `timestamp`)
+ rawContent:
+ type: string
+ tid:
+ type: number
+ description: A topic identifier
+ toPid:
+ nullable: true
+ user:
+ type: object
+ properties:
+ username:
+ type: string
+ description: A friendly name for a given user account
+ userslug:
+ type: string
+ description: An URL-safe variant of the username (i.e. lower-cased, spaces
+ removed, etc.)
+ picture:
+ nullable: true
+ type: string
+ uid:
+ type: number
+ description: A user identifier
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users without
+ an avatar
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with
+ `icon:text` for the user's auto-generated
+ icon
+ example: "#f44336"
+ topic:
+ type: object
+ properties:
+ cid:
+ type: number
+ title:
+ type: string
+ titleRaw:
+ type: string
+ - $ref: components/schemas/CategoryObject.yaml#/CategoryObject
+ - $ref: components/schemas/Pagination.yaml#/Pagination
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ /api/ip-blacklist:
+ get:
+ tags:
+ - admin
+ summary: Get IP blacklist settings
+ responses:
+ "418":
+ description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route"
+ /api/registration-queue:
+ get:
+ tags:
+ - admin
+ summary: Get registration queue
+ responses:
+ "418":
+ description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route"
+ /api/tags:
+ get:
+ tags:
+ - tags
+ summary: Get tags
+ description: Returns a list of tags sorted by the most topics
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ tags:
+ type: array
+ description: An array of tags sorted by the most topics
+ items:
+ type: object
+ properties:
+ value:
+ type: string
+ description: The raw tag
+ score:
+ type: number
+ description: Number of topics tagged by this tag
+ valueEscaped:
+ type: string
+ description: This is the escaped tag value, equal to validator.escape(value)
+ color:
+ type: string
+ bgColor:
+ type: string
+ displayTagSearch:
+ type: boolean
+ nextStart:
+ type: number
+ title:
+ type: string
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ "/api/tags/{tag}":
+ get:
+ tags:
+ - tags
+ summary: Get tag data
+ description: Returns a list of topics that are tagged with {tag}
+ parameters:
+ - name: tag
+ description: The tag used to retrieve the topics
+ in: path
+ required: true
+ schema:
+ type: string
+ example: test
+ - name: page
+ description: Page number used in pagination
+ in: query
+ required: false
+ schema:
+ type: number
+ example: ''
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ topics:
+ type: array
+ description: An array of topics that are all tagged with {tag}
+ items:
+ type: object
+ properties:
+ tid:
+ type: number
+ description: A topic identifier
+ uid:
+ type: number
+ description: A user identifier
+ cid:
+ type: number
+ description: A category identifier
+ mainPid:
+ type: number
+ description: The post id of the first post in this topic (also called the
+ "original post")
+ title:
+ type: string
+ slug:
+ type: string
+ timestamp:
+ type: number
+ lastposttime:
+ type: number
+ postcount:
+ type: number
+ viewcount:
+ type: number
+ teaserPid:
+ oneOf:
+ - type: number
+ - type: string
+ deleted:
+ type: number
+ locked:
+ type: number
+ pinned:
+ type: number
+ description: Whether or not this particular topic is pinned to the top of the
+ category
+ upvotes:
+ type: number
+ downvotes:
+ type: number
+ titleRaw:
+ type: string
+ timestampISO:
+ type: string
+ description: An ISO 8601 formatted date string (complementing `timestamp`)
+ lastposttimeISO:
+ type: string
+ votes:
+ type: number
+ category:
+ type: object
+ properties:
+ cid:
+ type: number
+ description: A category identifier
+ name:
+ type: string
+ slug:
+ type: string
+ icon:
+ type: string
+ image:
+ nullable: true
+ imageClass:
+ nullable: true
+ type: string
+ bgColor:
+ type: string
+ color:
+ type: string
+ disabled:
+ type: number
+ user:
+ type: object
+ properties:
+ uid:
+ type: number
+ description: A user identifier
+ username:
+ type: string
+ description: A friendly name for a given user account
+ userslug:
+ type: string
+ description: An URL-safe variant of the username (i.e. lower-cased, spaces
+ removed, etc.)
+ reputation:
+ type: number
+ postcount:
+ type: number
+ picture:
+ nullable: true
+ type: string
+ signature:
+ nullable: true
+ type: string
+ banned:
+ type: number
+ status:
+ type: string
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users without
+ an avatar
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with
+ `icon:text` for the user's auto-generated
+ icon
+ example: "#f44336"
+ banned_until_readable:
+ type: string
+ fullname:
+ type: string
+ teaser:
+ type: object
+ properties:
+ pid:
+ type: number
+ uid:
+ type: number
+ description: A user identifier
+ timestamp:
+ type: number
+ tid:
+ type: number
+ description: A topic identifier
+ content:
+ type: string
+ timestampISO:
+ type: string
+ description: An ISO 8601 formatted date string (complementing `timestamp`)
+ user:
+ type: object
+ properties:
+ uid:
+ type: number
+ description: A user identifier
+ username:
+ type: string
+ description: A friendly name for a given user account
+ userslug:
+ type: string
+ description: An URL-safe variant of the username (i.e. lower-cased, spaces
+ removed, etc.)
+ picture:
+ nullable: true
+ type: string
+ icon:text:
+ type: string
+ description: A single-letter representation of a username. This is used in the
+ auto-generated icon given to users
+ without an avatar
+ icon:bgColor:
+ type: string
+ description: A six-character hexadecimal colour code assigned to the user. This
+ value is used in conjunction with
+ `icon:text` for the user's
+ auto-generated icon
+ example: "#f44336"
+ index:
+ type: number
+ tags:
+ type: array
+ items:
+ type: object
+ properties:
+ value:
+ type: string
+ valueEscaped:
+ type: string
+ color:
+ type: string
+ bgColor:
+ type: string
+ score:
+ type: number
+ isOwner:
+ type: boolean
+ ignored:
+ type: boolean
+ unread:
+ type: boolean
+ bookmark:
+ nullable: true
+ unreplied:
+ type: boolean
+ icons:
+ type: array
+ items: {}
+ index:
+ type: number
+ thumb:
+ type: string
+ isQuestion:
+ nullable: true
+ type: number
+ isSolved:
+ type: number
+ tag:
+ type: string
+ title:
+ type: string
+ categories:
+ type: array
+ items:
+ type: object
+ properties:
+ cid:
+ type: number
+ description: A category identifier
+ name:
+ type: string
+ level:
+ type: string
+ icon:
+ type: string
+ parentCid:
+ type: number
+ description: The category identifier for the category that is the immediate
+ ancestor of the current category
+ color:
+ type: string
+ bgColor:
+ type: string
+ selected:
+ type: boolean
+ imageClass:
+ type: string
+ rssFeedUrl:
+ type: string
+ required:
+ - topics
+ - tag
+ - title
+ - categories
+ - $ref: components/schemas/Pagination.yaml#/Pagination
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ /api/popular:
+ get:
+ tags:
+ - topics
+ summary: Get popular topics
+ description: Returns a list of topics sorted by most replies. In an event of a
+ tie breaker, the topic with the most views. Can be filtered by All Time,
+ Day, Week, or Month.
+ responses:
+ "200":
+ description: An array of topic objects sorted by most replies and views.
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ nextStart:
+ type: number
+ topicCount:
+ type: number
+ topics:
+ type: array
+ items:
+ $ref: components/schemas/TopicObject.yaml#/TopicObject
+ tids:
+ type: array
+ items:
+ type: number
+ canPost:
+ type: boolean
+ categories:
+ type: array
+ items:
+ type: object
+ properties:
+ cid:
+ type: number
+ description: A category identifier
+ name:
+ type: string
+ level:
+ type: string
+ icon:
+ type: string
+ parentCid:
+ type: number
+ description: The category identifier for the category that is the immediate
+ ancestor of the current category
+ color:
+ type: string
+ bgColor:
+ type: string
+ selected:
+ type: boolean
+ imageClass:
+ type: string
+ allCategoriesUrl:
+ type: string
+ selectedCategory:
+ type: object
+ properties:
+ icon:
+ type: string
+ name:
+ type: string
+ bgColor:
+ type: string
+ nullable: true
+ selectedCids:
+ type: array
+ items:
+ type: number
+ feeds:disableRSS:
+ type: number
+ rssFeedUrl:
+ type: string
+ title:
+ type: string
+ filters:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ filter:
+ type: string
+ selectedFilter:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ filter:
+ type: string
+ terms:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ term:
+ type: string
+ selectedTerm:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ term:
+ type: string
+ - $ref: components/schemas/Pagination.yaml#/Pagination
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
+ /api/top:
+ get:
+ tags:
+ - topics
+ summary: Get top topics
+ description: Returns a list of topics sorted by most upvotes.
+ responses:
+ "200":
+ description: An array of topic objects sorted by most upvotes.
+ content:
+ application/json:
+ schema:
+ allOf:
+ - type: object
+ properties:
+ nextStart:
+ type: number
+ topicCount:
+ type: number
+ topics:
+ type: array
+ items:
+ $ref: components/schemas/TopicObject.yaml#/TopicObject
+ tids:
+ type: array
+ items:
+ type: number
+ canPost:
+ type: boolean
+ categories:
+ type: array
+ items:
+ type: object
+ properties:
+ cid:
+ type: number
+ description: A category identifier
+ name:
+ type: string
+ level:
+ type: string
+ icon:
+ type: string
+ parentCid:
+ type: number
+ description: The category identifier for the category that is the immediate
+ ancestor of the current category
+ color:
+ type: string
+ bgColor:
+ type: string
+ selected:
+ type: boolean
+ imageClass:
+ type: string
+ allCategoriesUrl:
+ type: string
+ selectedCategory:
+ type: object
+ properties:
+ cid:
+ type: number
+ description: A category identifier
+ name:
+ type: string
+ level:
+ type: string
+ icon:
+ type: string
+ parentCid:
+ type: number
+ description: The category identifier for the category that is the immediate
+ ancestor of the current category
+ color:
+ type: string
+ bgColor:
+ type: string
+ selected:
+ type: boolean
+ nullable: true
+ selectedCids:
+ type: array
+ items:
+ type: number
+ feeds:disableRSS:
+ type: number
+ rssFeedUrl:
+ type: string
+ title:
+ type: string
+ filters:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ filter:
+ type: string
+ selectedFilter:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ filter:
+ type: string
+ terms:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ term:
+ type: string
+ selectedTerm:
+ type: object
+ properties:
+ name:
+ type: string
+ url:
+ type: string
+ selected:
+ type: boolean
+ term:
+ type: string
+ - $ref: components/schemas/Pagination.yaml#/Pagination
+ - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
+ - $ref: components/schemas/CommonProps.yaml#/CommonProps
"/api/category/{category_id}/{slug}/{topic_index}":
get:
tags:
- categories
- summary: /api/category/{category_id}/{slug}/{topic_index}
+ summary: Get a single category
+ description: This route retrieves a single category's data, along with its children and the topics created inside of the category.
parameters:
- name: category_id
in: path
@@ -5782,12 +5871,14 @@ paths:
type: string
example: 1
- name: slug
+ description: This parameter is not required. If omitted, the request will be automatically redirected with the proper category slug.
in: path
required: true
schema:
type: string
example: test
- name: topic_index
+ description: This parameter is not required. If omitted, the request will presume that you want the first post. The API response is largely unaffected by this parameter, it is used client-side (to send the user to the requested post), and changes the meta/link tags in the server-side generated HTML.
in: path
required: true
schema:
@@ -5860,32 +5951,24 @@ paths:
- $ref: components/schemas/Pagination.yaml#/Pagination
- $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- $ref: components/schemas/CommonProps.yaml#/CommonProps
- "/api/category/{category_id}/{slug?}":
+ /api/me:
get:
tags:
- - categories
- summary: /api/category/{category_id}/{slug}
- parameters:
- - name: category_id
- in: path
- required: true
- schema:
- type: string
- example: 1
- - name: slug
- in: path
- required: true
- schema:
- type: string
- example: test
+ - shorthand
+ summary: Access your profile
+ description: This shorthand is useful if you want to link to pages in your own account profile, but do not want (or have) the userslug. It is also especially useful as a means to instruct users on how to do things, as you can easily redirect them to their own profile pages.
responses:
- "418":
- description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from indexed variant"
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ $ref: components/schemas/UserObject.yaml#/UserObjectFull
/api/me/*:
get:
tags:
- shorthand
- summary: Access your own profile's pages
+ summary: Access your own profile's sub-pages
description: >-
This shorthand is useful if you want to link to pages in your own account profile, but do not want (or have) the `userslug`. It is also especially useful as a
means to instruct users on how to do things, as you can easily redirect them to their own profile pages.
@@ -6187,7 +6270,8 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/categories
+ summary: Get user's watched categories
+ description: This route retrieves the list of categories and their watch states
parameters:
- name: userslug
in: path
@@ -6248,7 +6332,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/posts
+ summary: Get a user's posts
parameters:
- name: userslug
in: path
@@ -6294,7 +6378,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/topics
+ summary: Get a user's topics
parameters:
- name: userslug
in: path
@@ -6342,7 +6426,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/best
+ summary: Get a user's best performing topics
parameters:
- name: userslug
in: path
@@ -6388,7 +6472,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/groups
+ summary: Get user's groups
parameters:
- name: userslug
in: path
@@ -6421,7 +6505,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/bookmarks
+ summary: Get user's bookmarks
parameters:
- name: userslug
in: path
@@ -6467,7 +6551,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/watched
+ summary: Get user's watched topics
parameters:
- name: userslug
in: path
@@ -6675,7 +6759,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/ignored
+ summary: Get user's ignored topics
parameters:
- name: userslug
in: path
@@ -6723,7 +6807,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/upvoted
+ summary: Get user's upvoted posts
parameters:
- name: userslug
in: path
@@ -6775,7 +6859,7 @@ paths:
get:
tags:
- users
- summary: Get user's downvotes
+ summary: Get user's downvoted posts
parameters:
- name: userslug
in: path
@@ -6827,7 +6911,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/edit
+ summary: Get user profile for editing
parameters:
- name: userslug
in: path
@@ -6894,7 +6978,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/edit/username
+ summary: Get configs for username editing
parameters:
- name: userslug
in: path
@@ -6922,7 +7006,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/edit/email
+ summary: Get configs for email editing
parameters:
- name: userslug
in: path
@@ -6950,7 +7034,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/edit/password
+ summary: Get configs for password editing
parameters:
- name: userslug
in: path
@@ -6982,7 +7066,8 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/info
+ summary: Get user moderation info
+ description: Administrators and Global Moderators get access to the `/info` page, which shows some backend data that is useful from a moderation point-of-view (such as IP addresses, recent bans, moderation history, etc).
parameters:
- name: userslug
in: path
@@ -7163,7 +7248,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/settings
+ summary: Get user's settings
parameters:
- name: userslug
in: path
@@ -7228,6 +7313,8 @@ paths:
type: string
notificationType_new-reply:
type: string
+ notificationType_post-edit:
+ type: string
sendChatNotifications:
nullable: true
sendPostNotifications:
@@ -7495,7 +7582,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/uploads
+ summary: Get user's uploads
parameters:
- name: userslug
in: path
@@ -7533,7 +7620,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/consent
+ summary: Get user's GDPR consent settings
parameters:
- name: userslug
in: path
@@ -7568,7 +7655,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/blocks
+ summary: Get user's blocks
parameters:
- name: userslug
in: path
@@ -7599,7 +7686,7 @@ paths:
get:
tags:
- users
- summary: /api/user/{userslug}/sessions
+ summary: Get user's active sessions
parameters:
- name: userslug
in: path
@@ -7667,7 +7754,7 @@ paths:
get:
tags:
- notifications
- summary: /api/notifications
+ summary: Get notifications
responses:
"200":
description: ""
@@ -8092,7 +8179,8 @@ paths:
get:
tags:
- shorthand
- summary: /api/chats/{roomid}
+ summary: Access a chat room
+ description: Redirects a request to the proper chat page URL
parameters:
- name: roomid
in: path
@@ -8108,114 +8196,11 @@ paths:
schema:
type: string
description: A relative path to the canonical URL for that chat page
- /api/users:
- get:
- tags:
- - users
- summary: /api/users
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- users:
- type: array
- items:
- type: object
- properties:
- uid:
- type: number
- description: A user identifier
- username:
- type: string
- description: A friendly name for a given user account
- userslug:
- type: string
- description: An URL-safe variant of the username (i.e. lower-cased, spaces
- removed, etc.)
- picture:
- nullable: true
- type: string
- status:
- type: string
- postcount:
- type: number
- reputation:
- type: number
- email:confirmed:
- type: number
- description: Whether the user has confirmed their email address or not
- lastonline:
- type: number
- flags:
- nullable: true
- banned:
- type: number
- banned:expire:
- type: number
- joindate:
- type: number
- description: A UNIX timestamp representing the moment the user's account was
- created
- icon:text:
- type: string
- description: A single-letter representation of a username. This is used in the
- auto-generated icon given to users without an
- avatar
- icon:bgColor:
- type: string
- description: A six-character hexadecimal colour code assigned to the user. This
- value is used in conjunction with `icon:text`
- for the user's auto-generated icon
- example: "#f44336"
- joindateISO:
- type: string
- lastonlineISO:
- type: string
- banned_until:
- type: number
- banned_until_readable:
- type: string
- administrator:
- type: boolean
- userCount:
- type: number
- title:
- type: string
- isAdminOrGlobalMod:
- type: boolean
- isAdmin:
- type: boolean
- isGlobalMod:
- type: boolean
- displayUserSearch:
- type: boolean
- section_joindate:
- type: boolean
- maximumInvites:
- type: number
- inviteOnly:
- type: boolean
- adminInviteOnly:
- type: boolean
- invites:
- type: number
- showInviteButton:
- type: boolean
- reputation:disabled:
- type: number
- - $ref: components/schemas/Pagination.yaml#/Pagination
- - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- - $ref: components/schemas/CommonProps.yaml#/CommonProps
/api/groups:
get:
tags:
- groups
- summary: /api/groups
+ summary: Get user groups
responses:
"200":
description: ""
@@ -8322,7 +8307,7 @@ paths:
get:
tags:
- groups
- summary: /api/groups/{slug}
+ summary: Get user group details
parameters:
- name: slug
in: path
diff --git a/public/src/modules/topicList.js b/public/src/modules/topicList.js
index bd486d5adb..553eb3a18b 100644
--- a/public/src/modules/topicList.js
+++ b/public/src/modules/topicList.js
@@ -199,7 +199,11 @@ define('topicList', [
});
}
var categoryEl = $(this);
- var cid = $(this).attr('data-cid');
+ var link = categoryEl.find('a').attr('href');
+ if (link && link !== '#' && link.length) {
+ return;
+ }
+ var cid = categoryEl.attr('data-cid');
if (ev.ctrlKey) {
selectChildren(cid, !categoryEl.find('[component="category/select/icon"]').hasClass('fa-check'));
}
diff --git a/src/categories/index.js b/src/categories/index.js
index 661275e6c4..371f71a579 100644
--- a/src/categories/index.js
+++ b/src/categories/index.js
@@ -175,20 +175,16 @@ function calculateTopicPostCount(category) {
return;
}
- var postCount = category.post_count;
- var topicCount = category.topic_count;
- if (!Array.isArray(category.children) || !category.children.length) {
- category.totalPostCount = postCount;
- category.totalTopicCount = topicCount;
- return;
+ let postCount = category.post_count;
+ let topicCount = category.topic_count;
+ if (Array.isArray(category.children)) {
+ category.children.forEach(function (child) {
+ calculateTopicPostCount(child);
+ postCount += parseInt(child.totalPostCount, 10) || 0;
+ topicCount += parseInt(child.totalTopicCount, 10) || 0;
+ });
}
- category.children.forEach(function (child) {
- calculateTopicPostCount(child);
- postCount += parseInt(child.totalPostCount, 10) || 0;
- topicCount += parseInt(child.totalTopicCount, 10) || 0;
- });
-
category.totalPostCount = postCount;
category.totalTopicCount = topicCount;
}
@@ -240,7 +236,7 @@ Categories.getChildrenCids = async function (rootCid) {
}
keys = childrenCids.map(cid => 'cid:' + cid + ':children');
childrenCids.forEach(cid => allCids.push(parseInt(cid, 10)));
- recursive(keys);
+ await recursive(keys);
}
const key = 'cid:' + rootCid + ':children';
const childrenCids = cache.get(key);
diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js
index 4ae423f6ac..3a7e37d383 100644
--- a/src/categories/recentreplies.js
+++ b/src/categories/recentreplies.js
@@ -62,12 +62,24 @@ module.exports = function (Categories) {
}
};
- Categories.getRecentTopicReplies = async function (categoryData, uid) {
+ Categories.getRecentTopicReplies = async function (categoryData, uid, query) {
if (!Array.isArray(categoryData) || !categoryData.length) {
return;
}
- const categoriesToLoad = categoryData.filter(category => category && category.numRecentReplies && parseInt(category.numRecentReplies, 10) > 0);
- const keys = categoriesToLoad.map(category => 'cid:' + category.cid + ':recent_tids');
+ const categoriesToLoad = categoryData.filter(c => c && c.numRecentReplies && parseInt(c.numRecentReplies, 10) > 0);
+ let keys = [];
+ if (plugins.hasListeners('filter:categories.getRecentTopicReplies')) {
+ const result = await plugins.fireHook('filter:categories.getRecentTopicReplies', {
+ categories: categoriesToLoad,
+ uid: uid,
+ query: query,
+ keys: [],
+ });
+ keys = result.keys;
+ } else {
+ keys = categoriesToLoad.map(c => 'cid:' + c.cid + ':recent_tids');
+ }
+
const results = await db.getSortedSetsMembers(keys);
let tids = _.uniq(_.flatten(results).filter(Boolean));
diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js
index 34ba4cd7cc..bb4d744333 100644
--- a/src/controllers/accounts/settings.js
+++ b/src/controllers/accounts/settings.js
@@ -108,7 +108,7 @@ settingsController.get = async function (req, res, next) {
userData.disableCustomUserSkins = meta.config.disableCustomUserSkins || 0;
- userData.allowUserHomePage = meta.config.allowUserHomePage || 1;
+ userData.allowUserHomePage = meta.config.allowUserHomePage === 1 ? 1 : 0;
userData.hideFullname = meta.config.hideFullname || 0;
userData.hideEmail = meta.config.hideEmail || 0;
diff --git a/src/controllers/categories.js b/src/controllers/categories.js
index 22f4964a74..98dae31fa5 100644
--- a/src/controllers/categories.js
+++ b/src/controllers/categories.js
@@ -19,7 +19,7 @@ categoriesController.list = async function (req, res) {
const categoryData = await categories.getCategoriesByPrivilege('categories:cid', req.uid, 'find');
const tree = categories.getTree(categoryData, 0);
- await categories.getRecentTopicReplies(categoryData, req.uid);
+ await categories.getRecentTopicReplies(categoryData, req.uid, req.query);
const data = {
title: meta.config.homePageTitle || '[[pages:home]]',
diff --git a/src/controllers/category.js b/src/controllers/category.js
index 4edc7324d6..befc2621cb 100644
--- a/src/controllers/category.js
+++ b/src/controllers/category.js
@@ -88,7 +88,7 @@ categoryController.get = async function (req, res, next) {
if (categoryData.children.length) {
const allCategories = [];
categories.flattenCategories(allCategories, categoryData.children);
- await categories.getRecentTopicReplies(allCategories, req.uid);
+ await categories.getRecentTopicReplies(allCategories, req.uid, req.query);
}
categoryData.title = translator.escape(categoryData.name);
diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js
index 11a677116d..8ce5811cf0 100644
--- a/src/controllers/helpers.js
+++ b/src/controllers/helpers.js
@@ -222,7 +222,7 @@ async function getCategoryData(cids, uid, selectedCid, states) {
if (selectedCid && !Array.isArray(selectedCid)) {
selectedCid = [selectedCid];
}
-
+ selectedCid = selectedCid && selectedCid.map(String);
states = states || [categories.watchStates.watching, categories.watchStates.notwatching];
const [allowed, watchState, categoryData, isAdmin] = await Promise.all([
@@ -286,7 +286,7 @@ function checkVisibleChildren(c, cidToAllowed, cidToWatchState, states) {
if (!c || !Array.isArray(c.children)) {
return false;
}
- return c.children.some(c => c && (
+ return c.children.some(c => c && !c.disabled && (
(cidToAllowed[c.cid] && states.includes(cidToWatchState[c.cid])) || checkVisibleChildren(c, cidToAllowed, cidToWatchState, states)
));
}
diff --git a/src/database/mongo/sorted/add.js b/src/database/mongo/sorted/add.js
index 6dc206b953..f576a27100 100644
--- a/src/database/mongo/sorted/add.js
+++ b/src/database/mongo/sorted/add.js
@@ -52,7 +52,8 @@ module.exports = function (module) {
return;
}
const isArrayOfScores = Array.isArray(scores);
- if (!isArrayOfScores && !utils.isNumber(scores)) {
+ if ((!isArrayOfScores && !utils.isNumber(scores)) ||
+ (isArrayOfScores && scores.map(s => utils.isNumber(s)).includes(false))) {
throw new Error('[[error:invalid-score, ' + scores + ']]');
}
@@ -75,6 +76,9 @@ module.exports = function (module) {
}
var bulk = module.client.collection('objects').initializeUnorderedBulkOp();
data.forEach(function (item) {
+ if (!utils.isNumber(item[1])) {
+ throw new Error('[[error:invalid-score, ' + item[1] + ']]');
+ }
bulk.find({ _key: item[0], value: String(item[2]) }).upsert().updateOne({ $set: { score: parseFloat(item[1]) } });
});
await bulk.execute();
diff --git a/src/database/postgres/sorted/add.js b/src/database/postgres/sorted/add.js
index 392482dbdd..32dc2f6325 100644
--- a/src/database/postgres/sorted/add.js
+++ b/src/database/postgres/sorted/add.js
@@ -69,7 +69,8 @@ DO UPDATE SET "score" = EXCLUDED."score"`,
return;
}
const isArrayOfScores = Array.isArray(scores);
- if (!isArrayOfScores && !utils.isNumber(scores)) {
+ if ((!isArrayOfScores && !utils.isNumber(scores)) ||
+ (isArrayOfScores && scores.map(s => utils.isNumber(s)).includes(false))) {
throw new Error('[[error:invalid-score, ' + scores + ']]');
}
@@ -108,6 +109,9 @@ INSERT INTO "legacy_zset" ("_key", "value", "score")
const values = [];
const scores = [];
data.forEach(function (item) {
+ if (!utils.isNumber(item[1])) {
+ throw new Error('[[error:invalid-score, ' + item[1] + ']]');
+ }
keys.push(item[0]);
scores.push(item[1]);
values.push(item[2]);
diff --git a/src/database/redis/sorted/add.js b/src/database/redis/sorted/add.js
index b4f28de949..f8d5c4bd8c 100644
--- a/src/database/redis/sorted/add.js
+++ b/src/database/redis/sorted/add.js
@@ -42,7 +42,8 @@ module.exports = function (module) {
return;
}
const isArrayOfScores = Array.isArray(scores);
- if (!isArrayOfScores && !utils.isNumber(scores)) {
+ if ((!isArrayOfScores && !utils.isNumber(scores)) ||
+ (isArrayOfScores && scores.map(s => utils.isNumber(s)).includes(false))) {
throw new Error('[[error:invalid-score, ' + scores + ']]');
}
@@ -65,6 +66,9 @@ module.exports = function (module) {
}
var batch = module.client.batch();
data.forEach(function (item) {
+ if (!utils.isNumber(item[1])) {
+ throw new Error('[[error:invalid-score, ' + item[1] + ']]');
+ }
batch.zadd(item[0], item[1], item[2]);
});
await helpers.execBatch(batch);
diff --git a/src/notifications.js b/src/notifications.js
index 2159a0da9d..537a23db97 100644
--- a/src/notifications.js
+++ b/src/notifications.js
@@ -21,6 +21,7 @@ Notifications.baseTypes = [
'notificationType_upvote',
'notificationType_new-topic',
'notificationType_new-reply',
+ 'notificationType_post-edit',
'notificationType_follow',
'notificationType_new-chat',
'notificationType_group-invite',
diff --git a/src/posts/edit.js b/src/posts/edit.js
index fbe3590ada..b85f54e68b 100644
--- a/src/posts/edit.js
+++ b/src/posts/edit.js
@@ -52,6 +52,13 @@ module.exports = function (Posts) {
postData.cid = topic.cid;
postData.topic = topic;
+
+ await topics.notifyFollowers(postData, data.uid, {
+ type: 'post-edit',
+ bodyShort: translator.compile('notifications:user_edited_post', editor.username, postData.topic.title),
+ nid: 'edit_post:' + postData.pid + ':uid:' + data.uid,
+ });
+
plugins.fireHook('action:post.edit', { post: _.clone(postData), data: data, uid: data.uid });
require('./cache').del(String(postData.pid));
@@ -79,6 +86,7 @@ module.exports = function (Posts) {
return {
tid: tid,
cid: topicData.cid,
+ title: validator.escape(String(topicData.title)),
isMainPost: false,
renamed: false,
};
diff --git a/src/topics/create.js b/src/topics/create.js
index 88ed0b244d..884446a549 100644
--- a/src/topics/create.js
+++ b/src/topics/create.js
@@ -13,6 +13,7 @@ var meta = require('../meta');
var posts = require('../posts');
var privileges = require('../privileges');
var categories = require('../categories');
+const translator = require('../translator');
module.exports = function (Topics) {
Topics.create = async function (data) {
@@ -180,7 +181,13 @@ module.exports = function (Topics) {
user.setUserField(uid, 'lastonline', Date.now());
}
- Topics.notifyFollowers(postData, uid);
+ Topics.notifyFollowers(postData, uid, {
+ type: 'new-reply',
+ bodyShort: translator.compile('notifications:user_posted_to', postData.user.username, postData.topic.title),
+ nid: 'new_post:tid:' + postData.topic.tid + ':pid:' + postData.pid + ':uid:' + uid,
+ mergeId: 'notifications:user_posted_to|' + postData.topic.tid,
+ });
+
analytics.increment(['posts', 'posts:byCid:' + data.cid]);
plugins.fireHook('action:topic.reply', { post: _.clone(postData), data: data });
diff --git a/src/topics/follow.js b/src/topics/follow.js
index 872cb92ce9..4faaa40419 100644
--- a/src/topics/follow.js
+++ b/src/topics/follow.js
@@ -145,47 +145,37 @@ module.exports = function (Topics) {
return tids.filter((tid, index) => tid && !scores[index]);
};
- Topics.notifyFollowers = async function (postData, exceptUid) {
- var title;
- var titleEscaped;
-
+ Topics.notifyFollowers = async function (postData, exceptUid, notifData) {
+ notifData = notifData || {};
let followers = await Topics.getFollowers(postData.topic.tid);
-
- var index = followers.indexOf(exceptUid.toString());
+ const index = followers.indexOf(String(exceptUid));
if (index !== -1) {
followers.splice(index, 1);
}
followers = await privileges.topics.filterUids('topics:read', postData.topic.tid, followers);
-
if (!followers.length) {
return;
}
- title = postData.topic.title;
+ let title = postData.topic.title;
if (title) {
title = utils.decodeHTMLEntities(title);
- titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
}
postData.content = posts.relativeToAbsolute(postData.content, posts.urlRegex);
postData.content = posts.relativeToAbsolute(postData.content, posts.imgRegex);
const notification = await notifications.create({
- type: 'new-reply',
subject: title,
- bodyShort: '[[notifications:user_posted_to, ' + postData.user.username + ', ' + titleEscaped + ']]',
bodyLong: postData.content,
pid: postData.pid,
path: '/post/' + postData.pid,
- nid: 'new_post:tid:' + postData.topic.tid + ':pid:' + postData.pid + ':uid:' + exceptUid,
tid: postData.topic.tid,
from: exceptUid,
- mergeId: 'notifications:user_posted_to|' + postData.topic.tid,
topicTitle: title,
+ ...notifData,
});
- if (notification) {
- notifications.push(notification, followers);
- }
+ notifications.push(notification, followers);
};
};
diff --git a/src/topics/index.js b/src/topics/index.js
index 30c645f458..6a63680d89 100644
--- a/src/topics/index.js
+++ b/src/topics/index.js
@@ -67,7 +67,7 @@ Topics.getTopicsByTids = async function (tids, options) {
const uids = _.uniq(topics.map(t => t && t.uid && t.uid.toString()).filter(v => utils.isNumber(v)));
const cids = _.uniq(topics.map(t => t && t.cid && t.cid.toString()).filter(v => utils.isNumber(v)));
- const guestTopics = topics.filter(t => t.uid === 0);
+ const guestTopics = topics.filter(t => t && t.uid === 0);
async function loadGuestHandles() {
return await Promise.all(guestTopics.map(topic => posts.getPostField(topic.mainPid, 'handle')));
}
diff --git a/src/topics/tags.js b/src/topics/tags.js
index 192d5e8a26..88a8f3a69b 100644
--- a/src/topics/tags.js
+++ b/src/topics/tags.js
@@ -152,12 +152,15 @@ module.exports = function (Topics) {
};
Topics.getTopicTags = async function (tid) {
- return await db.getSetMembers('topic:' + tid + ':tags');
+ const tags = await db.getSetMembers('topic:' + tid + ':tags');
+ return tags.sort();
};
Topics.getTopicsTags = async function (tids) {
const keys = tids.map(tid => 'topic:' + tid + ':tags');
- return await db.getSetsMembers(keys);
+ const tags = await db.getSetsMembers(keys);
+ tags.forEach(tags => tags.sort());
+ return tags;
};
Topics.getTopicTagsObjects = async function (tid) {
@@ -192,6 +195,31 @@ module.exports = function (Topics) {
return topicTags;
};
+ Topics.addTags = async function (tags, tids) {
+ const topicData = await Topics.getTopicsFields(tids, ['timestamp']);
+ const sets = tids.map(tid => 'topic:' + tid + ':tags');
+ for (let i = 0; i < tags.length; i++) {
+ /* eslint-disable no-await-in-loop */
+ await Promise.all([
+ db.setsAdd(sets, tags[i]),
+ db.sortedSetAdd('tag:' + tags[i] + ':topics', topicData.map(t => t.timestamp), tids),
+ ]);
+ await updateTagCount(tags[i]);
+ }
+ };
+
+ Topics.removeTags = async function (tags, tids) {
+ const sets = tids.map(tid => 'topic:' + tid + ':tags');
+ for (let i = 0; i < tags.length; i++) {
+ /* eslint-disable no-await-in-loop */
+ await Promise.all([
+ db.setsRemove(sets, tags[i]),
+ db.sortedSetRemove('tag:' + tags[i] + ':topics', tids),
+ ]);
+ await updateTagCount(tags[i]);
+ }
+ };
+
Topics.updateTopicTags = async function (tid, tags) {
await Topics.deleteTopicTags(tid);
const timestamp = await Topics.getTopicField(tid, 'timestamp');
diff --git a/src/topics/tools.js b/src/topics/tools.js
index 2fdd0d445c..269538599e 100644
--- a/src/topics/tools.js
+++ b/src/topics/tools.js
@@ -93,7 +93,8 @@ module.exports = function (Topics) {
throw new Error('[[error:no-privileges]]');
}
await Topics.setTopicField(tid, 'locked', lock ? 1 : 0);
- topicData.isLocked = lock;
+ topicData.isLocked = lock; // deprecate in v2.0
+ topicData.locked = lock;
plugins.fireHook('action:topic.lock', { topic: _.clone(topicData), uid: uid });
return topicData;
diff --git a/src/upgrades/1.13.3/fix_users_sorted_sets.js b/src/upgrades/1.13.3/fix_users_sorted_sets.js
index 3a6b947fa4..9afd97915f 100644
--- a/src/upgrades/1.13.3/fix_users_sorted_sets.js
+++ b/src/upgrades/1.13.3/fix_users_sorted_sets.js
@@ -44,9 +44,9 @@ module.exports = {
}
totalUserCount += 1;
await db.sortedSetAddBulk([
- ['users:joindate', userData.joindate, uids[index]],
- ['users:reputation', userData.reputation, uids[index]],
- ['users:postcount', userData.postcount, uids[index]],
+ ['users:joindate', userData.joindate || Date.now(), uids[index]],
+ ['users:reputation', userData.reputation || 0, uids[index]],
+ ['users:postcount', userData.postcount || 0, uids[index]],
]);
if (userData.hasOwnProperty('flags') && parseInt(userData.flags, 10) > 0) {
await db.sortedSetAdd('users:flags', userData.flags, uids[index]);
diff --git a/src/user/blocks.js b/src/user/blocks.js
index 0065fd52e4..7a8423e83e 100644
--- a/src/user/blocks.js
+++ b/src/user/blocks.js
@@ -5,6 +5,7 @@ const LRU = require('lru-cache');
const db = require('../database');
const pubsub = require('../pubsub');
+const plugins = require('../plugins');
module.exports = function (User) {
User.blocks = {
@@ -63,6 +64,7 @@ module.exports = function (User) {
await User.incrementUserFieldBy(uid, 'blocksCount', 1);
User.blocks._cache.del(parseInt(uid, 10));
pubsub.publish('user:blocks:cache:del', parseInt(uid, 10));
+ plugins.fireHook('action:user.blocks.add', { uid: uid, targetUid: targetUid });
};
User.blocks.remove = async function (targetUid, uid) {
@@ -71,6 +73,7 @@ module.exports = function (User) {
await User.decrementUserFieldBy(uid, 'blocksCount', 1);
User.blocks._cache.del(parseInt(uid, 10));
pubsub.publish('user:blocks:cache:del', parseInt(uid, 10));
+ plugins.fireHook('action:user.blocks.remove', { uid: uid, targetUid: targetUid });
};
User.blocks.applyChecks = async function (type, targetUid, uid) {
@@ -115,7 +118,8 @@ module.exports = function (User) {
set = set.filter(function (item) {
return !blockedSet.has(parseInt(isPlain ? item : item[property], 10));
});
+ const data = await plugins.fireHook('filter:user.blocks.filter', { set: set, property: property, uid: uid, blockedSet: blockedSet });
- return set;
+ return data.set;
};
};
diff --git a/test/categories.js b/test/categories.js
index a0d3f778d2..242abd9294 100644
--- a/test/categories.js
+++ b/test/categories.js
@@ -109,7 +109,7 @@ describe('Categories', function () {
uid: 0,
}, function (err, categoryData) {
assert.ifError(err);
- Categories.getRecentTopicReplies(categoryData, 0, function (err) {
+ Categories.getRecentTopicReplies(categoryData, 0, {}, function (err) {
assert.ifError(err);
done();
});
@@ -910,4 +910,18 @@ describe('Categories', function () {
});
});
});
+
+ it('should return nested children categories', async function () {
+ const rootCategory = await Categories.create({ name: 'root' });
+ const child1 = await Categories.create({ name: 'child1', parentCid: rootCategory.cid });
+ const child2 = await Categories.create({ name: 'child2', parentCid: child1.cid });
+ const data = await Categories.getCategoryById({
+ uid: 1,
+ cid: rootCategory.cid,
+ start: 0,
+ stop: 19,
+ });
+ assert.strictEqual(child1.cid, data.children[0].cid);
+ assert.strictEqual(child2.cid, data.children[0].children[0].cid);
+ });
});
diff --git a/test/database/sorted.js b/test/database/sorted.js
index 73cc7714e2..922c70a9cb 100644
--- a/test/database/sorted.js
+++ b/test/database/sorted.js
@@ -118,6 +118,18 @@ describe('Sorted Set methods', function () {
done();
});
});
+
+ it('should error if scores has null', async function () {
+ let err;
+ try {
+ await db.sortedSetsAdd(['sorted1', 'sorted2'], [1, null], 'dontadd');
+ } catch (_err) {
+ err = _err;
+ }
+ assert.equal(err.message, '[[error:invalid-score, 1,]]');
+ assert.strictEqual(await db.isSortedSetMember('sorted1', 'dontadd'), false);
+ assert.strictEqual(await db.isSortedSetMember('sorted2', 'dontadd'), false);
+ });
});
describe('sortedSetAddMulti()', function () {
@@ -146,6 +158,21 @@ describe('Sorted Set methods', function () {
done();
});
});
+
+ it('should error if score is null', async function () {
+ let err;
+ try {
+ await db.sortedSetAddBulk([
+ ['bulk4', 0, 'dontadd'],
+ ['bulk5', null, 'dontadd'],
+ ]);
+ } catch (_err) {
+ err = _err;
+ }
+ assert.equal(err.message, '[[error:invalid-score, null]]');
+ assert.strictEqual(await db.isSortedSetMember('bulk4', 'dontadd'), false);
+ assert.strictEqual(await db.isSortedSetMember('bulk5', 'dontadd'), false);
+ });
});
describe('getSortedSetRange()', function () {
diff --git a/test/topics.js b/test/topics.js
index 682ce72025..80380b5a3d 100644
--- a/test/topics.js
+++ b/test/topics.js
@@ -1753,6 +1753,19 @@ describe('Topic\'s', function () {
});
});
});
+
+ it('should add and remove tags from topics properly', async () => {
+ const result = await topics.post({ uid: adminUid, tags: ['tag4', 'tag2', 'tag1', 'tag3'], title: 'tag topic', content: 'topic 1 content', cid: topic.categoryId });
+ const tid = result.topicData.tid;
+ let tags = await topics.getTopicTags(tid);
+ assert.deepStrictEqual(tags, ['tag1', 'tag2', 'tag3', 'tag4']);
+ await topics.addTags(['tag7', 'tag6', 'tag5'], [tid]);
+ tags = await topics.getTopicTags(tid);
+ assert.deepStrictEqual(tags, ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6', 'tag7']);
+ await topics.removeTags(['tag1', 'tag3', 'tag5', 'tag7'], [tid]);
+ tags = await topics.getTopicTags(tid);
+ assert.deepStrictEqual(tags, ['tag2', 'tag4', 'tag6']);
+ });
});
describe('follow/unfollow', function () {