mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-24 09:20:32 +01:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
129474f268 | ||
|
|
40170f8133 | ||
|
|
d4452ba25c | ||
|
|
5c6a631fc6 | ||
|
|
dc1cd3feaa | ||
|
|
841b856e27 | ||
|
|
abf81ec57d | ||
|
|
b89502ce0b | ||
|
|
381e64e657 | ||
|
|
110b867ed5 | ||
|
|
4b006b37cc | ||
|
|
e51c8de9cb | ||
|
|
918008fffd | ||
|
|
2e2b1e9d6c | ||
|
|
ca42094f3f | ||
|
|
3d07f14859 | ||
|
|
32175666d5 | ||
|
|
1501a9303c | ||
|
|
db75571923 |
525
CHANGELOG.md
525
CHANGELOG.md
@@ -1,528 +1,3 @@
|
||||
#### v3.6.6 (2024-02-14)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v3.6.5 (6c653625)
|
||||
* update changelog for v3.6.5 (04039f76)
|
||||
* incrementing version number - v3.6.4 (83d131b4)
|
||||
* incrementing version number - v3.6.3 (fc7d2bfd)
|
||||
* incrementing version number - v3.6.2 (0f577a57)
|
||||
* incrementing version number - v3.6.1 (f1a69468)
|
||||
* incrementing version number - v3.6.0 (4cdf85f8)
|
||||
* incrementing version number - v3.5.3 (ed0e8783)
|
||||
* incrementing version number - v3.5.2 (52fbb2da)
|
||||
* incrementing version number - v3.5.1 (4c543488)
|
||||
* incrementing version number - v3.5.0 (d06fb4f0)
|
||||
* incrementing version number - v3.4.3 (5c984250)
|
||||
* incrementing version number - v3.4.2 (3f0dac38)
|
||||
* incrementing version number - v3.4.1 (01e69574)
|
||||
* incrementing version number - v3.4.0 (fd9247c5)
|
||||
* incrementing version number - v3.3.9 (5805e770)
|
||||
* incrementing version number - v3.3.8 (a5603565)
|
||||
* incrementing version number - v3.3.7 (b26f1744)
|
||||
* incrementing version number - v3.3.6 (7fb38792)
|
||||
* incrementing version number - v3.3.4 (a67f84ea)
|
||||
* incrementing version number - v3.3.3 (f94d239b)
|
||||
* incrementing version number - v3.3.2 (ec9dac97)
|
||||
* incrementing version number - v3.3.1 (151cc68f)
|
||||
* incrementing version number - v3.3.0 (fc1ad70f)
|
||||
* incrementing version number - v3.2.3 (b06d3e63)
|
||||
* incrementing version number - v3.2.2 (758ecfcd)
|
||||
* incrementing version number - v3.2.1 (20145074)
|
||||
* incrementing version number - v3.2.0 (9ecac38e)
|
||||
* incrementing version number - v3.1.7 (0b4e81ab)
|
||||
* incrementing version number - v3.1.6 (b3a3b130)
|
||||
* incrementing version number - v3.1.5 (ec19343a)
|
||||
* incrementing version number - v3.1.4 (2452783c)
|
||||
* incrementing version number - v3.1.3 (3b4e9d3f)
|
||||
* incrementing version number - v3.1.2 (40fa3489)
|
||||
* incrementing version number - v3.1.1 (40250733)
|
||||
* incrementing version number - v3.1.0 (0cb386bd)
|
||||
* incrementing version number - v3.0.1 (26f6ea49)
|
||||
* incrementing version number - v3.0.0 (224e08cd)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* closes #12329, fix default value of categoryWatchState (88e9fa37)
|
||||
|
||||
##### Tests
|
||||
|
||||
* fix spec (5fec8b23)
|
||||
|
||||
#### v3.6.5 (2024-01-31)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v3.6.4 (83d131b4)
|
||||
* update changelog for v3.6.4 (6e6c3974)
|
||||
* incrementing version number - v3.6.3 (fc7d2bfd)
|
||||
* incrementing version number - v3.6.2 (0f577a57)
|
||||
* incrementing version number - v3.6.1 (f1a69468)
|
||||
* incrementing version number - v3.6.0 (4cdf85f8)
|
||||
* incrementing version number - v3.5.3 (ed0e8783)
|
||||
* incrementing version number - v3.5.2 (52fbb2da)
|
||||
* incrementing version number - v3.5.1 (4c543488)
|
||||
* incrementing version number - v3.5.0 (d06fb4f0)
|
||||
* incrementing version number - v3.4.3 (5c984250)
|
||||
* incrementing version number - v3.4.2 (3f0dac38)
|
||||
* incrementing version number - v3.4.1 (01e69574)
|
||||
* incrementing version number - v3.4.0 (fd9247c5)
|
||||
* incrementing version number - v3.3.9 (5805e770)
|
||||
* incrementing version number - v3.3.8 (a5603565)
|
||||
* incrementing version number - v3.3.7 (b26f1744)
|
||||
* incrementing version number - v3.3.6 (7fb38792)
|
||||
* incrementing version number - v3.3.4 (a67f84ea)
|
||||
* incrementing version number - v3.3.3 (f94d239b)
|
||||
* incrementing version number - v3.3.2 (ec9dac97)
|
||||
* incrementing version number - v3.3.1 (151cc68f)
|
||||
* incrementing version number - v3.3.0 (fc1ad70f)
|
||||
* incrementing version number - v3.2.3 (b06d3e63)
|
||||
* incrementing version number - v3.2.2 (758ecfcd)
|
||||
* incrementing version number - v3.2.1 (20145074)
|
||||
* incrementing version number - v3.2.0 (9ecac38e)
|
||||
* incrementing version number - v3.1.7 (0b4e81ab)
|
||||
* incrementing version number - v3.1.6 (b3a3b130)
|
||||
* incrementing version number - v3.1.5 (ec19343a)
|
||||
* incrementing version number - v3.1.4 (2452783c)
|
||||
* incrementing version number - v3.1.3 (3b4e9d3f)
|
||||
* incrementing version number - v3.1.2 (40fa3489)
|
||||
* incrementing version number - v3.1.1 (40250733)
|
||||
* incrementing version number - v3.1.0 (0cb386bd)
|
||||
* incrementing version number - v3.0.1 (26f6ea49)
|
||||
* incrementing version number - v3.0.0 (224e08cd)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* #12320, .text() gets \n\t characters (67c8bd99)
|
||||
|
||||
#### v3.6.4 (2024-01-24)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v3.6.3 (fc7d2bfd)
|
||||
* update changelog for v3.6.3 (92ffc57c)
|
||||
* incrementing version number - v3.6.2 (0f577a57)
|
||||
* incrementing version number - v3.6.1 (f1a69468)
|
||||
* incrementing version number - v3.6.0 (4cdf85f8)
|
||||
* incrementing version number - v3.5.3 (ed0e8783)
|
||||
* incrementing version number - v3.5.2 (52fbb2da)
|
||||
* incrementing version number - v3.5.1 (4c543488)
|
||||
* incrementing version number - v3.5.0 (d06fb4f0)
|
||||
* incrementing version number - v3.4.3 (5c984250)
|
||||
* incrementing version number - v3.4.2 (3f0dac38)
|
||||
* incrementing version number - v3.4.1 (01e69574)
|
||||
* incrementing version number - v3.4.0 (fd9247c5)
|
||||
* incrementing version number - v3.3.9 (5805e770)
|
||||
* incrementing version number - v3.3.8 (a5603565)
|
||||
* incrementing version number - v3.3.7 (b26f1744)
|
||||
* incrementing version number - v3.3.6 (7fb38792)
|
||||
* incrementing version number - v3.3.4 (a67f84ea)
|
||||
* incrementing version number - v3.3.3 (f94d239b)
|
||||
* incrementing version number - v3.3.2 (ec9dac97)
|
||||
* incrementing version number - v3.3.1 (151cc68f)
|
||||
* incrementing version number - v3.3.0 (fc1ad70f)
|
||||
* incrementing version number - v3.2.3 (b06d3e63)
|
||||
* incrementing version number - v3.2.2 (758ecfcd)
|
||||
* incrementing version number - v3.2.1 (20145074)
|
||||
* incrementing version number - v3.2.0 (9ecac38e)
|
||||
* incrementing version number - v3.1.7 (0b4e81ab)
|
||||
* incrementing version number - v3.1.6 (b3a3b130)
|
||||
* incrementing version number - v3.1.5 (ec19343a)
|
||||
* incrementing version number - v3.1.4 (2452783c)
|
||||
* incrementing version number - v3.1.3 (3b4e9d3f)
|
||||
* incrementing version number - v3.1.2 (40fa3489)
|
||||
* incrementing version number - v3.1.1 (40250733)
|
||||
* incrementing version number - v3.1.0 (0cb386bd)
|
||||
* incrementing version number - v3.0.1 (26f6ea49)
|
||||
* incrementing version number - v3.0.0 (224e08cd)
|
||||
|
||||
##### New Features
|
||||
|
||||
* add success hook to quick reply (cb21f28b)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* if there is no bookmarkThreshold dont init unread indicator (cf40d681)
|
||||
* remove leftover code from 2.x, closes #12301 (d5f445f1)
|
||||
* copy single line code blocks, closes #12297 (06269cdf)
|
||||
* validate plugin id in toggleActive (76f3efff)
|
||||
|
||||
##### Tests
|
||||
|
||||
* add plugin id tests (e8befbcc)
|
||||
|
||||
#### v3.6.3 (2024-01-12)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v3.6.2 (0f577a57)
|
||||
* update changelog for v3.6.2 (82a936c3)
|
||||
* incrementing version number - v3.6.1 (f1a69468)
|
||||
* incrementing version number - v3.6.0 (4cdf85f8)
|
||||
* incrementing version number - v3.5.3 (ed0e8783)
|
||||
* incrementing version number - v3.5.2 (52fbb2da)
|
||||
* incrementing version number - v3.5.1 (4c543488)
|
||||
* incrementing version number - v3.5.0 (d06fb4f0)
|
||||
* incrementing version number - v3.4.3 (5c984250)
|
||||
* incrementing version number - v3.4.2 (3f0dac38)
|
||||
* incrementing version number - v3.4.1 (01e69574)
|
||||
* incrementing version number - v3.4.0 (fd9247c5)
|
||||
* incrementing version number - v3.3.9 (5805e770)
|
||||
* incrementing version number - v3.3.8 (a5603565)
|
||||
* incrementing version number - v3.3.7 (b26f1744)
|
||||
* incrementing version number - v3.3.6 (7fb38792)
|
||||
* incrementing version number - v3.3.4 (a67f84ea)
|
||||
* incrementing version number - v3.3.3 (f94d239b)
|
||||
* incrementing version number - v3.3.2 (ec9dac97)
|
||||
* incrementing version number - v3.3.1 (151cc68f)
|
||||
* incrementing version number - v3.3.0 (fc1ad70f)
|
||||
* incrementing version number - v3.2.3 (b06d3e63)
|
||||
* incrementing version number - v3.2.2 (758ecfcd)
|
||||
* incrementing version number - v3.2.1 (20145074)
|
||||
* incrementing version number - v3.2.0 (9ecac38e)
|
||||
* incrementing version number - v3.1.7 (0b4e81ab)
|
||||
* incrementing version number - v3.1.6 (b3a3b130)
|
||||
* incrementing version number - v3.1.5 (ec19343a)
|
||||
* incrementing version number - v3.1.4 (2452783c)
|
||||
* incrementing version number - v3.1.3 (3b4e9d3f)
|
||||
* incrementing version number - v3.1.2 (40fa3489)
|
||||
* incrementing version number - v3.1.1 (40250733)
|
||||
* incrementing version number - v3.1.0 (0cb386bd)
|
||||
* incrementing version number - v3.0.1 (26f6ea49)
|
||||
* incrementing version number - v3.0.0 (224e08cd)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* #12275, pin sharp to 0.32.6 (f3927ce7)
|
||||
* topic event translations closes #12273 (5f91cc83)
|
||||
|
||||
#### v3.6.2 (2024-01-10)
|
||||
|
||||
##### Chores
|
||||
|
||||
* up composer (ef8f8db7)
|
||||
* up harmony (2bed405c)
|
||||
* up harmony (b6dbe1a6)
|
||||
* up lavender (16f0affa)
|
||||
* up themes (980bfee8)
|
||||
* incrementing version number - v3.6.1 (f1a69468)
|
||||
* update changelog for v3.6.1 (1e4abdbf)
|
||||
* incrementing version number - v3.6.0 (4cdf85f8)
|
||||
* incrementing version number - v3.5.3 (ed0e8783)
|
||||
* incrementing version number - v3.5.2 (52fbb2da)
|
||||
* incrementing version number - v3.5.1 (4c543488)
|
||||
* incrementing version number - v3.5.0 (d06fb4f0)
|
||||
* incrementing version number - v3.4.3 (5c984250)
|
||||
* incrementing version number - v3.4.2 (3f0dac38)
|
||||
* incrementing version number - v3.4.1 (01e69574)
|
||||
* incrementing version number - v3.4.0 (fd9247c5)
|
||||
* incrementing version number - v3.3.9 (5805e770)
|
||||
* incrementing version number - v3.3.8 (a5603565)
|
||||
* incrementing version number - v3.3.7 (b26f1744)
|
||||
* incrementing version number - v3.3.6 (7fb38792)
|
||||
* incrementing version number - v3.3.4 (a67f84ea)
|
||||
* incrementing version number - v3.3.3 (f94d239b)
|
||||
* incrementing version number - v3.3.2 (ec9dac97)
|
||||
* incrementing version number - v3.3.1 (151cc68f)
|
||||
* incrementing version number - v3.3.0 (fc1ad70f)
|
||||
* incrementing version number - v3.2.3 (b06d3e63)
|
||||
* incrementing version number - v3.2.2 (758ecfcd)
|
||||
* incrementing version number - v3.2.1 (20145074)
|
||||
* incrementing version number - v3.2.0 (9ecac38e)
|
||||
* incrementing version number - v3.1.7 (0b4e81ab)
|
||||
* incrementing version number - v3.1.6 (b3a3b130)
|
||||
* incrementing version number - v3.1.5 (ec19343a)
|
||||
* incrementing version number - v3.1.4 (2452783c)
|
||||
* incrementing version number - v3.1.3 (3b4e9d3f)
|
||||
* incrementing version number - v3.1.2 (40fa3489)
|
||||
* incrementing version number - v3.1.1 (40250733)
|
||||
* incrementing version number - v3.1.0 (0cb386bd)
|
||||
* incrementing version number - v3.0.1 (26f6ea49)
|
||||
* incrementing version number - v3.0.0 (224e08cd)
|
||||
|
||||
##### New Features
|
||||
|
||||
* #12247 (0af19afd)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* recent loading (d3d6d77d)
|
||||
* closes #12246, direction is passed in as string as query param with new api call (8867f243)
|
||||
* stricter selector for sort (a74b5141)
|
||||
|
||||
##### Performance Improvements
|
||||
|
||||
* dont load all followed tids on unread/recent?filter=watched (563e03b6)
|
||||
|
||||
#### v3.6.1 (2023-12-22)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v3.6.0 (4cdf85f8)
|
||||
* update changelog for v3.6.0 (eb92cee6)
|
||||
* incrementing version number - v3.5.3 (ed0e8783)
|
||||
* incrementing version number - v3.5.2 (52fbb2da)
|
||||
* incrementing version number - v3.5.1 (4c543488)
|
||||
* incrementing version number - v3.5.0 (d06fb4f0)
|
||||
* incrementing version number - v3.4.3 (5c984250)
|
||||
* incrementing version number - v3.4.2 (3f0dac38)
|
||||
* incrementing version number - v3.4.1 (01e69574)
|
||||
* incrementing version number - v3.4.0 (fd9247c5)
|
||||
* incrementing version number - v3.3.9 (5805e770)
|
||||
* incrementing version number - v3.3.8 (a5603565)
|
||||
* incrementing version number - v3.3.7 (b26f1744)
|
||||
* incrementing version number - v3.3.6 (7fb38792)
|
||||
* incrementing version number - v3.3.4 (a67f84ea)
|
||||
* incrementing version number - v3.3.3 (f94d239b)
|
||||
* incrementing version number - v3.3.2 (ec9dac97)
|
||||
* incrementing version number - v3.3.1 (151cc68f)
|
||||
* incrementing version number - v3.3.0 (fc1ad70f)
|
||||
* incrementing version number - v3.2.3 (b06d3e63)
|
||||
* incrementing version number - v3.2.2 (758ecfcd)
|
||||
* incrementing version number - v3.2.1 (20145074)
|
||||
* incrementing version number - v3.2.0 (9ecac38e)
|
||||
* incrementing version number - v3.1.7 (0b4e81ab)
|
||||
* incrementing version number - v3.1.6 (b3a3b130)
|
||||
* incrementing version number - v3.1.5 (ec19343a)
|
||||
* incrementing version number - v3.1.4 (2452783c)
|
||||
* incrementing version number - v3.1.3 (3b4e9d3f)
|
||||
* incrementing version number - v3.1.2 (40fa3489)
|
||||
* incrementing version number - v3.1.1 (40250733)
|
||||
* incrementing version number - v3.1.0 (0cb386bd)
|
||||
* incrementing version number - v3.0.1 (26f6ea49)
|
||||
* incrementing version number - v3.0.0 (224e08cd)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* #12243, don' set process.env.config if it doesnt exist (788404c1)
|
||||
* lang key for move notification closes #12241 (48a2b5f7)
|
||||
* dont send topic notification to poster (e72b26f5)
|
||||
|
||||
#### v3.6.0 (2023-12-20)
|
||||
|
||||
##### Chores
|
||||
|
||||
* **i18n:**
|
||||
* fallback strings for new resources: nodebb.error (d3cfa1b7)
|
||||
* fallback strings for new resources: nodebb.post-queue (64fe1278)
|
||||
* fallback strings for new resources: nodebb.post-queue (f98205c1)
|
||||
* fallback strings for new resources: nodebb.social (081352b6)
|
||||
* fallback strings for new resources: nodebb.modules (4fe84ae8)
|
||||
* fallback strings for new resources: nodebb.admin-settings-chat, nodebb.admin-settings-post, nodebb.admin-settings-user (94777927)
|
||||
* fallback strings for new resources: nodebb.admin-settings-user, nodebb.category, nodebb.notifications (29b3a403)
|
||||
* fallback strings for new resources: nodebb.error (7d8f700f)
|
||||
* fallback strings for new resources: nodebb.modules (83931138)
|
||||
* make error:email-taken slightly more descriptive (dd0743d3)
|
||||
* up harmony (250cc771)
|
||||
* up harmony (9324a75c)
|
||||
* incrementing version number - v3.5.3 (ed0e8783)
|
||||
* update changelog for v3.5.3 (e49ddaf8)
|
||||
* up harmony (dbbf3a2c)
|
||||
* up harmony (e4656bd4)
|
||||
* incrementing version number - v3.5.2 (52fbb2da)
|
||||
* up themes (0ec9d4c3)
|
||||
* added missing deprecation warning for .getTopics (9079ad0b)
|
||||
* update note at top of file (2de534fa)
|
||||
* up dbsearch (b6981693)
|
||||
* up themes (9a1f8e9b)
|
||||
* incrementing version number - v3.5.1 (4c543488)
|
||||
* up themes (ed10dda2)
|
||||
* up composer (22d7e92f)
|
||||
* up themes (fcdd3737)
|
||||
* v4 note for deprecations (f4c36b84)
|
||||
* minor re-order of routes/controllers in admin api v3 router/controller (181a9399)
|
||||
* add in note at top of files ready for deletion in v4 (54a08087)
|
||||
* up harmony (1b8dcbc2)
|
||||
* incrementing version number - v3.5.0 (d06fb4f0)
|
||||
* incrementing version number - v3.4.3 (5c984250)
|
||||
* incrementing version number - v3.4.2 (3f0dac38)
|
||||
* incrementing version number - v3.4.1 (01e69574)
|
||||
* incrementing version number - v3.4.0 (fd9247c5)
|
||||
* incrementing version number - v3.3.9 (5805e770)
|
||||
* incrementing version number - v3.3.8 (a5603565)
|
||||
* incrementing version number - v3.3.7 (b26f1744)
|
||||
* incrementing version number - v3.3.6 (7fb38792)
|
||||
* incrementing version number - v3.3.4 (a67f84ea)
|
||||
* incrementing version number - v3.3.3 (f94d239b)
|
||||
* incrementing version number - v3.3.2 (ec9dac97)
|
||||
* incrementing version number - v3.3.1 (151cc68f)
|
||||
* incrementing version number - v3.3.0 (fc1ad70f)
|
||||
* incrementing version number - v3.2.3 (b06d3e63)
|
||||
* incrementing version number - v3.2.2 (758ecfcd)
|
||||
* incrementing version number - v3.2.1 (20145074)
|
||||
* incrementing version number - v3.2.0 (9ecac38e)
|
||||
* incrementing version number - v3.1.7 (0b4e81ab)
|
||||
* incrementing version number - v3.1.6 (b3a3b130)
|
||||
* incrementing version number - v3.1.5 (ec19343a)
|
||||
* incrementing version number - v3.1.4 (2452783c)
|
||||
* incrementing version number - v3.1.3 (3b4e9d3f)
|
||||
* incrementing version number - v3.1.2 (40fa3489)
|
||||
* incrementing version number - v3.1.1 (40250733)
|
||||
* incrementing version number - v3.1.0 (0cb386bd)
|
||||
* incrementing version number - v3.0.1 (26f6ea49)
|
||||
* incrementing version number - v3.0.0 (224e08cd)
|
||||
* **deps:**
|
||||
* update dependency eslint-plugin-import to v2.29.1 (#12229) (055b7597)
|
||||
* update dependency eslint to v8.56.0 (#12231) (a7dd0f92)
|
||||
* update dependency eslint to v8.55.0 (#12203) (32a403b2)
|
||||
* update dependency lint-staged to v15.2.0 (#12210) (9763e97f)
|
||||
* update dependency jsdom to v23.0.1 (#12196) (a50b141f)
|
||||
* update dependency jsdom to v23 (#12186) (8c0472a0)
|
||||
* update commitlint monorepo to v18.4.3 (#12177) (fd5d7b65)
|
||||
* update dependency eslint to v8.54.0 (#12172) (b6275453)
|
||||
* update commitlint monorepo to v18.4.2 (#12169) (d6a92d4c)
|
||||
* update postgres docker tag to v16.1 (#12167) (616ff573)
|
||||
* update mongo docker tag to v7 (#12166) (5f8a4f3a)
|
||||
* update redis docker tag to v7.2.3 (#12165) (c41f9a75)
|
||||
* update dependency lint-staged to v15.1.0 (#12161) (1796ed2b)
|
||||
* update dependency @commitlint/cli to v18.4.1 (#12162) (be3d3393)
|
||||
* update commitlint monorepo to v18.4.0 (#12159) (128c24f2)
|
||||
* update dependency eslint to v8.53.0 (#12151) (d1a7ba35)
|
||||
* update redis docker tag to v7.2.3 (#12152) (2eff6912)
|
||||
* update commitlint monorepo to v18 (#12105) (97016f47)
|
||||
* update dependency sass-embedded to v1.69.5 (#12127) (9e8a2116)
|
||||
* **socket.io:** deprecate categories.(isModerator|ignore|watch|getSelectCategories|getMoveCategories|getCategoriesByPrivilege) (f1dbfaa2)
|
||||
|
||||
##### Documentation Changes
|
||||
|
||||
* fix improper verbiage in category watch schema (f8cc8548)
|
||||
* openapi schema for api.search.categories (4ffe0417)
|
||||
* **socket.io:**
|
||||
* openapi schema for remaining added routes (5399e86a)
|
||||
* added schema for new routes (f279bca0)
|
||||
|
||||
##### New Features
|
||||
|
||||
* add 500 page for missing tpls, closes #12230 (06221a0d)
|
||||
* remove gif exif stripping exception (f8219aa6)
|
||||
* update groups.leave to allow global mods to kick users out of groups (2c6024e0)
|
||||
* better layout for manage chat room modal (f4faa0b7)
|
||||
* update Messaging.toggleOwner to optionally take a third `state` argument (932bd292)
|
||||
* new language strings for post-queue page (5d03321e)
|
||||
* add some new social share buttons (ace171a6)
|
||||
* docker improvements (#12031) (7f3a9968)
|
||||
* closes #12158, add sortable rewards (5ea7dec9)
|
||||
* add copy text (4b2491be)
|
||||
* closes #12154, add exempt groups (fdff165e)
|
||||
* update moved keys (119c3362)
|
||||
* move new user restrrictions (3d505c5c)
|
||||
* add tracking categories and make watching send notifications (#12147) (84fed97b)
|
||||
* add new lang string for minutes (d8d26c9f)
|
||||
* add direct message link (#12138) (4c4f3ac9)
|
||||
* closes #5584, setup winston to output to file (87a859aa)
|
||||
* batch.processSortedSet min/max (#12129) (6c7e6144)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* fix display post history (dc975838)
|
||||
* update isJSON test in request lib (506d7be5)
|
||||
* 503 rendering on ajaxify (f7e0fd0b)
|
||||
* #12227, fix crash in redirect (2dc1def5)
|
||||
* deprecated emailer hook (565ca3cc)
|
||||
* extract all pages when stripping metadata (0b3eb6c0)
|
||||
* incorrect call to load additional group members (78835ebb)
|
||||
* closes #12185, fix cli user password reset (b9050139)
|
||||
* don't require login for listing categories (50a90f8e)
|
||||
* #12183, remove ensureLoggedIn middleware (0a4f3c8a)
|
||||
* remove unused requires (b5940a5d)
|
||||
* remove lodash require (f9c471a0)
|
||||
* #12171, bump harmony (89a1134c)
|
||||
* update design of post-queue (41bdc9e8)
|
||||
* update post-queue template for #12171 (63ba4986)
|
||||
* language key (4c7c46f3)
|
||||
* another missing state (f4bbc5bd)
|
||||
* add missing tracking (3b91e8e2)
|
||||
* bump harmony (a5e3754b)
|
||||
* #12133 dropdown menus on mobile stay open during ajaxify (4601a6f7)
|
||||
* update ajaxifyTimer logic to only drop the request if the URL is the same as the one it's already processing (b4297cd8)
|
||||
* #12141, use apiv3 for category search module (cefd4061)
|
||||
* made parentCid optional in api.search.categories (581516c8)
|
||||
* don't count internal links towards link count when restricting new users from posting links (022fa0e7)
|
||||
* closes #12126, fix language keys (075cd598)
|
||||
* param (e5a60dc8)
|
||||
* handle public chat rooms too (6a696c43)
|
||||
* suppress chat message notifications for users who are known to be in the chat room (uid is present in the corresponding socket.io room) (18c27d1a)
|
||||
* **deps:**
|
||||
* update dependency workerpool to v9 (#12234) (2cccbcf6)
|
||||
* update dependency sharp to v0.33.1 (#12233) (45143000)
|
||||
* update dependency csrf-sync to v4.0.3 (#12232) (9e2a6f86)
|
||||
* update dependency ace-builds to v1.32.2 (#12228) (b6ca117a)
|
||||
* update dependency ace-builds to v1.32.1 (#12226) (6036d144)
|
||||
* update dependency esbuild to v0.19.9 (#12224) (d96d4d09)
|
||||
* update dependency @fontsource/inter to v5.0.16 (#12219) (e32eb8b3)
|
||||
* update dependency chart.js to v4.4.1 (#12217) (b6b569c0)
|
||||
* update dependency nodebb-theme-persona to v13.2.49 (#12218) (6dab99fd)
|
||||
* update dependency postcss to v8.4.32 (#12204) (da879704)
|
||||
* update dependency @fortawesome/fontawesome-free to v6.5.1 (#12198) (b41c7f2a)
|
||||
* update dependency nodebb-theme-harmony to v1.1.101 (#12199) (72d6a4b1)
|
||||
* update dependency sortablejs to v1.15.1 (#12200) (cd625705)
|
||||
* update dependency ace-builds to v1.32.0 (#12197) (75f063ba)
|
||||
* update dependency @fortawesome/fontawesome-free to v6.5.0 (#12193) (a94f4a48)
|
||||
* update dependency sharp to v0.33.0 (#12194) (1f287c74)
|
||||
* update dependency fs-extra to v11.2.0 (#12191) (4eaf2320)
|
||||
* update dependency passport to v0.7.0 (#12190) (bbf7c5e1)
|
||||
* update dependency esbuild to v0.19.8 (#12187) (bc59856e)
|
||||
* update dependency lru-cache to v10.1.0 (#12181) (22932bdb)
|
||||
* update dependency esbuild to v0.19.7 (#12176) (00cb5839)
|
||||
* update dependency lru-cache to v10.0.3 (#12175) (c404ef73)
|
||||
* update dependency ace-builds to v1.31.2 (#12168) (b4a41af9)
|
||||
* update dependency mongodb to v6.3.0 (#12170) (85936a59)
|
||||
* update dependency lru-cache to v10.0.2 (#12160) (9d18d3c7)
|
||||
* update dependency helmet to v7.1.0 (#12155) (50aa1a7c)
|
||||
* update dependency async to v3.2.5 (#12150) (0e9eafa1)
|
||||
* update dependency nodebb-theme-persona to v13.2.44 (#12149) (b489af06)
|
||||
* update dependency nodebb-theme-harmony to v1.1.95 (#12148) (77b0baea)
|
||||
* update dependency connect-pg-simple to v9.0.1 (#12144) (4e23d0d1)
|
||||
* update dependency nodebb-theme-persona to v13.2.43 (#12140) (91e45fa2)
|
||||
* update dependency nodebb-theme-harmony to v1.1.92 (#12131) (a3452c8f)
|
||||
* update dependency nodebb-theme-peace to v2.1.24 (#12139) (29a59b90)
|
||||
* update dependency spdx-license-list to v6.8.0 (2337d641)
|
||||
* update dependency nodebb-plugin-composer-default to v10.2.25 (#12136) (cdb40719)
|
||||
* update dependency cron to v3.1.6 (#12132) (2fb3af3c)
|
||||
* update dependency ace-builds to v1.31.1 (#12135) (6b28f1dc)
|
||||
* update dependency workerpool to v8 (#12121) (9bed7646)
|
||||
* update dependency sass to v1.69.5 (#12128) (b351c00a)
|
||||
* **socket.io:** update getPosts controller to return object containing posts instead of straight array (54000aab)
|
||||
|
||||
##### Other Changes
|
||||
|
||||
* **socket.io:** deprecate socketGroups.getChatGroups in favour of api.admin.listGroups (dc4cc74f)
|
||||
|
||||
##### Refactors
|
||||
|
||||
* line breaks good (4e560ade)
|
||||
* replace deprecated call with api call (f91b823e)
|
||||
* move async call to parallel (dabc282d)
|
||||
* **socket.io:**
|
||||
* deprecate SocketModules.chats.typing in favour of api.chats.toggleTyping (c1e6be77)
|
||||
* deprecate SocketModules.chats.loadPinnedMessages in favour of api.chats.getPinnedMessages" (401e8636)
|
||||
* deprecate SocketModules.chats.searchMessages in favour of api.search.roomMessages (f9dc3502)
|
||||
* deprecate SocketModules.chats.setNotificationSetting in favour of api.chats.watch (75c8cda1)
|
||||
* deprecated SocketModules.chats.toggleOwner in favour of api.chats.toggleOwner (b13c6ee4)
|
||||
* deprecated SocketModules.chats.searchMembers in favour of api.search.roomUsers (6e952263)
|
||||
* deprecate SocketModules.sortPublicRooms in favour of api.chats.sortPublicRooms (62b7dfd4)
|
||||
* deprecate SocketModules.chat.getUnreadCount in favour of api.chats.getUnread (5eaffb42)
|
||||
* deprecate SocketModules.chats.getIP in favour of api.chats.getIpAddress (214989a8)
|
||||
* deprecate SocketModules.chats.hasPrivateChat in favour of api.users.getPrivateRoomId (0d3c94e6)
|
||||
* deprecate SocketModules.chats.canMessage and .markAllRead with no alternative. deprecate .getRecentChats in favour of api.chats.list (a4133500)
|
||||
* deprecate SocketModules.chats.isDnD in favour of api.users.getStatus (eebea4df)
|
||||
* deprecate SocketModules.chats.getRaw in favour of api.chats.getRawMessage (c4b4e79b)
|
||||
* deprecate socketGroups.loadMoreMembers in favour of api.groups.listMembers (807d778c)
|
||||
* deprecate socketGroups.searchMembers in favour of api.groups.listMembers (d2f3333a)
|
||||
* deprecate socketGroups.loadMore in favour of api.groups.list (b61e8147)
|
||||
* deprecate categories.categorySearch in favour of api.search.categories (00de9d5b)
|
||||
* deprecate categories.loadMore in favour of api.categories.getTopics (1ce4ca54)
|
||||
* deprecate categories.loadMoreSubCategories in favour of api.categories.getChildren (010727f5)
|
||||
* deprecate categories.setWatchState in favour of api.categories.setWatchState (d7c6b3d6)
|
||||
* deprecate categories.getTopicCount in favour of api.categories.getTopicCount (c442b6e6)
|
||||
* deprecate categories.get in favour of api.categories.list (96046373)
|
||||
* deprecate categories.getRecentReplies in favour of api.categories.getPosts (52b78e83)
|
||||
|
||||
##### Tests
|
||||
|
||||
* migrate socket modules tests to v3 api (445b70de)
|
||||
* migrate socket.io groups tests to use api v3 (2c1c4dfe)
|
||||
|
||||
#### v3.5.3 (2023-12-13)
|
||||
|
||||
##### Chores
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
"onlineCutoff": 30,
|
||||
"timeagoCutoff": 30,
|
||||
"necroThreshold": 7,
|
||||
"categoryWatchState": "tracking",
|
||||
"categoryWatchState": "watching",
|
||||
"submitPluginUsage": 1,
|
||||
"showAverageApprovalTime": 1,
|
||||
"autoApproveTime": 0,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "3.6.7",
|
||||
"version": "3.5.3",
|
||||
"homepage": "https://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -38,6 +38,8 @@
|
||||
"archiver": "6.0.1",
|
||||
"async": "3.2.5",
|
||||
"autoprefixer": "10.4.16",
|
||||
"axios": "1.6.2",
|
||||
"axios-cookiejar-support": "4.0.7",
|
||||
"bcryptjs": "2.4.3",
|
||||
"benchpressjs": "2.5.1",
|
||||
"body-parser": "1.20.2",
|
||||
@@ -67,8 +69,8 @@
|
||||
"express": "4.18.2",
|
||||
"express-session": "1.17.3",
|
||||
"express-useragent": "1.0.15",
|
||||
"fetch-cookie": "2.1.0",
|
||||
"file-loader": "6.2.0",
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "11.2.0",
|
||||
"graceful-fs": "4.2.11",
|
||||
"helmet": "7.1.0",
|
||||
@@ -94,7 +96,7 @@
|
||||
"multiparty": "4.2.3",
|
||||
"nconf": "0.12.1",
|
||||
"nodebb-plugin-2factor": "7.4.0",
|
||||
"nodebb-plugin-composer-default": "10.2.31",
|
||||
"nodebb-plugin-composer-default": "10.2.29",
|
||||
"nodebb-plugin-dbsearch": "6.2.3",
|
||||
"nodebb-plugin-emoji": "5.1.13",
|
||||
"nodebb-plugin-emoji-android": "4.0.0",
|
||||
@@ -103,10 +105,10 @@
|
||||
"nodebb-plugin-ntfy": "1.7.3",
|
||||
"nodebb-plugin-spam-be-gone": "2.2.0",
|
||||
"nodebb-rewards-essentials": "1.0.0",
|
||||
"nodebb-theme-harmony": "1.1.108",
|
||||
"nodebb-theme-lavender": "7.1.7",
|
||||
"nodebb-theme-peace": "2.1.26",
|
||||
"nodebb-theme-persona": "13.2.50",
|
||||
"nodebb-theme-harmony": "1.1.103",
|
||||
"nodebb-theme-lavender": "7.1.5",
|
||||
"nodebb-theme-peace": "2.1.25",
|
||||
"nodebb-theme-persona": "13.2.49",
|
||||
"nodebb-widget-essentials": "7.0.14",
|
||||
"nodemailer": "6.9.7",
|
||||
"nprogress": "0.2.0",
|
||||
@@ -127,7 +129,7 @@
|
||||
"sass": "1.69.5",
|
||||
"semver": "7.5.4",
|
||||
"serve-favicon": "2.5.0",
|
||||
"sharp": "0.32.6",
|
||||
"sharp": "0.33.0",
|
||||
"sitemap": "7.1.1",
|
||||
"socket.io": "4.7.2",
|
||||
"socket.io-client": "4.7.2",
|
||||
@@ -146,7 +148,7 @@
|
||||
"webpack": "5.89.0",
|
||||
"webpack-merge": "5.10.0",
|
||||
"winston": "3.11.0",
|
||||
"workerpool": "9.0.1",
|
||||
"workerpool": "8.0.0",
|
||||
"xml": "1.0.1",
|
||||
"xregexp": "5.1.1",
|
||||
"yargs": "17.7.2",
|
||||
@@ -157,9 +159,9 @@
|
||||
"@commitlint/cli": "18.4.3",
|
||||
"@commitlint/config-angular": "18.4.3",
|
||||
"coveralls": "3.1.1",
|
||||
"eslint": "8.56.0",
|
||||
"eslint": "8.55.0",
|
||||
"eslint-config-nodebb": "0.2.1",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-import": "2.29.0",
|
||||
"grunt": "1.6.1",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"husky": "8.0.3",
|
||||
@@ -181,7 +183,7 @@
|
||||
"url": "https://github.com/NodeBB/NodeBB/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=16"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
@@ -195,4 +197,4 @@
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Internal Server Error</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/assets/5xx.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
let count = 0;
|
||||
const bounce = document.getElementById('click-me');
|
||||
bounce.onclick = function() {
|
||||
count++;
|
||||
bounce.className = '';
|
||||
setTimeout(function() {
|
||||
bounce.className = 'animated bounce';
|
||||
}, 50);
|
||||
|
||||
if (count > 5) {
|
||||
document.getElementById('hide').className = '';
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="center">
|
||||
<h1 id="click-me" class="animated bounce">500</h1>
|
||||
<p>
|
||||
<strong>Internal server error. </strong>
|
||||
</p>
|
||||
<p>
|
||||
{message}
|
||||
</p>
|
||||
<p>
|
||||
<small id="hide" class="hide">Alright. You can stop clicking... it's not going to make the site come back sooner!</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
141
public/503.html
141
public/503.html
@@ -2,12 +2,147 @@
|
||||
<head>
|
||||
<title>Excessive Load Warning</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/assets/5xx.css" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background: #00A9EA;
|
||||
color: white;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
text-align: center;
|
||||
-webkit-transform-style: preserve-3d;
|
||||
-moz-transform-style: preserve-3d;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 250px;
|
||||
color: #fff;
|
||||
opacity: 0.5;
|
||||
margin: 10px;
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
p strong {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
h1 {
|
||||
font-size: 125px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p strong {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(50%);
|
||||
-ms-transform: translateY(50%);
|
||||
transform: translateY(50%);
|
||||
}
|
||||
|
||||
@-webkit-keyframes bounce {
|
||||
0%, 20%, 53%, 80%, 100% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
40%, 43% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -30px, 0);
|
||||
transform: translate3d(0, -30px, 0);
|
||||
}
|
||||
|
||||
70% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -15px, 0);
|
||||
transform: translate3d(0, -15px, 0);
|
||||
}
|
||||
|
||||
90% {
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 20%, 53%, 80%, 100% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
40%, 43% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -30px, 0);
|
||||
transform: translate3d(0, -30px, 0);
|
||||
}
|
||||
|
||||
70% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -15px, 0);
|
||||
transform: translate3d(0, -15px, 0);
|
||||
}
|
||||
|
||||
90% {
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
|
||||
.bounce {
|
||||
-webkit-animation-name: bounce;
|
||||
animation-name: bounce;
|
||||
-webkit-transform-origin: center bottom;
|
||||
-ms-transform-origin: center bottom;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
|
||||
.animated {
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animated.infinite {
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.animated.hinge {
|
||||
-webkit-animation-duration: 2s;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
let count = 0;
|
||||
const bounce = document.getElementById('click-me');
|
||||
var count = 0,
|
||||
bounce = document.getElementById('click-me');
|
||||
bounce.onclick = function() {
|
||||
count++;
|
||||
bounce.className = '';
|
||||
|
||||
135
public/5xx.css
135
public/5xx.css
@@ -1,135 +0,0 @@
|
||||
body {
|
||||
background: #00A9EA;
|
||||
color: white;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
text-align: center;
|
||||
-webkit-transform-style: preserve-3d;
|
||||
-moz-transform-style: preserve-3d;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 250px;
|
||||
color: #fff;
|
||||
opacity: 0.5;
|
||||
margin: 10px;
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
p strong {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
h1 {
|
||||
font-size: 125px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p strong {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(50%);
|
||||
-ms-transform: translateY(50%);
|
||||
transform: translateY(50%);
|
||||
}
|
||||
|
||||
@-webkit-keyframes bounce {
|
||||
0%, 20%, 53%, 80%, 100% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
40%, 43% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -30px, 0);
|
||||
transform: translate3d(0, -30px, 0);
|
||||
}
|
||||
|
||||
70% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -15px, 0);
|
||||
transform: translate3d(0, -15px, 0);
|
||||
}
|
||||
|
||||
90% {
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 20%, 53%, 80%, 100% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
40%, 43% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -30px, 0);
|
||||
transform: translate3d(0, -30px, 0);
|
||||
}
|
||||
|
||||
70% {
|
||||
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
-webkit-transform: translate3d(0, -15px, 0);
|
||||
transform: translate3d(0, -15px, 0);
|
||||
}
|
||||
|
||||
90% {
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
|
||||
.bounce {
|
||||
-webkit-animation-name: bounce;
|
||||
animation-name: bounce;
|
||||
-webkit-transform-origin: center bottom;
|
||||
-ms-transform-origin: center bottom;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
|
||||
.animated {
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animated.infinite {
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.animated.hinge {
|
||||
-webkit-animation-duration: 2s;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "رقم الصفحة غير صحيح ، يجب أن يكون بين %1 و %2 .",
|
||||
"username-taken": "اسم المستخدم مأخوذ",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "البريد الالكتروني مأخوذ",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Вече има папка с това име",
|
||||
"invalid-pagination-value": "Грешен номер на странициране, трябва да бъде между %1 и %2",
|
||||
"username-taken": "Потребителското име е заето",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Е-пощата е заета",
|
||||
"email-nochange": "Въведената е-поща е същата като съществуващата.",
|
||||
"email-invited": "На тази е-поща вече е била изпратена покана",
|
||||
"email-not-confirmed": "Публикуването в някои категории и теми ще бъде възможно едва след като е-пощата Ви бъде потвърдена. Щръкнете тук, за да Ви изпратим е-писмо за потвърждение.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "ইউজারনেম আগেই ব্যবহৃত",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "ইমেইল আগেই ব্যবহৃত",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Neplatná hodnota stránkování, musí být alespoň %1 a nejvýše %2",
|
||||
"username-taken": "Uživatelské jméno je již použito",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Tento e-mail je již použit",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Ugyldig side værdi, skal mindst være %1 og maks. %2",
|
||||
"username-taken": "Brugernavn optaget",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Emailadresse allerede i brug",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Ordner existiert",
|
||||
"invalid-pagination-value": "Ungültige Seitennummerierung, muss mindestens %1 und maximal %2 sein",
|
||||
"username-taken": "Der Benutzername ist bereits vergeben",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-Mail-Adresse vergeben",
|
||||
"email-nochange": "Die eingegebene E-Mail ist die gleiche wie die bereits hinterlegte E-Mail.",
|
||||
"email-invited": "E-Mail wurde bereits eingeladen",
|
||||
"email-not-confirmed": "Das Schreiben von Beiträgen in einigen Kategorien oder Themen ist erst möglich, wenn Ihre E-Mail bestätigt wurde. Bitte klicken Sie hier, um eine Bestätigungs-E-Mail zu senden.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "Το όνομα χρήστη είναι πιασμένο",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Το email είναι πιασμένο",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
|
||||
"username-taken": "Username taken",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email taken",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
@@ -255,7 +255,6 @@
|
||||
"no-connection": "There seems to be a problem with your internet connection",
|
||||
"socket-reconnect-failed": "Unable to reach the server at this time. Click here to try again, or try again later",
|
||||
|
||||
"invalid-plugin-id": "Invalid plugin ID",
|
||||
"plugin-not-whitelisted": "Unable to install plugin – only plugins whitelisted by the NodeBB Package Manager can be installed via the ACP",
|
||||
"plugins-set-in-configuration": "You are not allowed to change plugin state as they are defined at runtime (config.json, environmental variables or terminal arguments), please modify the configuration instead.",
|
||||
"theme-not-set-in-configuration": "When defining active plugins in configuration, changing themes requires adding the new theme to the list of active plugins before updating it in the ACP",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "Username taken",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email taken",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "Username taken",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email taken",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Número de página inválido, debe estar entre %1 y %2",
|
||||
"username-taken": "Nombre de usuario ocupado",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Correo electrónico ocupado",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Väär lehekülje numeratsioon, peab olema vähemalt %1 ja kõige rohkem %2",
|
||||
"username-taken": "Kasutajanimi on juba võetud",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email on võetud",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "ارزش گذاری صفحه نامعتبر است، کمترین مقدار <strong>%1</strong> و بیشترین مقدار <strong>%2</strong> باید باشد",
|
||||
"username-taken": "این نام کاربری گرفته شده است.",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "این ایمیل گرفته شده است.",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "ایمیل قبلا دعوت شدهاست",
|
||||
"email-not-confirmed": "پس از تایید ایمیل شما، ارسال در برخی دسته ها یا موضوعات فعال می شود، لطفاً برای ارسال ایمیل تایید اینجا را کلیک کنید.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "Käyttäjänimi varattu",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Sähköpostiosoite varattu",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Le dossier existe",
|
||||
"invalid-pagination-value": "Valeur de pagination invalide. Celle-ci doit être comprise entre %1 et %2.",
|
||||
"username-taken": "Ce nom d'utilisateur est déjà pris",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-mail déjà utilisé",
|
||||
"email-nochange": "Le mail saisi est déjà enregistré.",
|
||||
"email-invited": "Cet utilisateur a déjà été invité.",
|
||||
"email-not-confirmed": "La publication dans certaines catégories ou sujets sera activée après confirmation de l'e-mail, veuillez cliquer ici pour envoyer un e-mail de confirmation.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Valor de paxinación incorreto, ten que estar entre %1 e %2",
|
||||
"username-taken": "Nome de usuario en uso",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Enderezo electrónico en uso",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "התיקיה קיימת",
|
||||
"invalid-pagination-value": "ערך דף לא חוקי, חייב להיות לפחות %1 ולא מעל %2",
|
||||
"username-taken": "שם משתמש תפוס",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "כתובת דוא\"ל תפוסה",
|
||||
"email-nochange": "כתובת דוא\"ל שהוזן זהה לדוא\"ל שנמצא כבר",
|
||||
"email-invited": "נשלחה כבר הזמנה לדוא\"ל זה",
|
||||
"email-not-confirmed": "פרסום בקטגוריות או בנושאים מסוימים מופעל רק לאחר אישור הדוא\"ל שלכם, אנא לחצו כאן כדי לשלוח אימות לדוא\"ל שלכם.",
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"user-flagged-user-multiple": "<strong>%1</strong>, <strong>%2</strong> ו-%3 אחרים דיווחו על פרופיל משתמש (%4)",
|
||||
"user-posted-to": "<strong>%1</strong> פרסם תגובה ל: <strong>%2</strong>",
|
||||
"user-posted-to-dual": "<strong>%1</strong> ו<strong>%2</strong> הגיבו ל: <strong>%3</strong>",
|
||||
"user-posted-to-triple": "<strong>%1</strong>, <strong>%2</strong> ו<strong>%3</strong> הגיבו ל: <strong>%4</strong>",
|
||||
"user-posted-to-triple": "<strong>%1</strong>, <strong>%2</strong> ו<strong>3%</strong> הגיבו ל: <strong>%4</strong>",
|
||||
"user-posted-to-multiple": "<strong>%1</strong>, <strong>%2</strong> ו-%3 אחרים הגיבו ל: <strong>%4</strong>",
|
||||
"user-posted-topic": "<strong>%1</strong> העלה נושא חדש: <strong>%2</strong>",
|
||||
"user-edited-post": "<strong>%1</strong> ערך פוסט ב: <strong>%2</strong>",
|
||||
@@ -59,7 +59,7 @@
|
||||
"user-posted-topic-in-category": "<strong>%1</strong> פרסם נושא חדש ב<strong>%2</strong>",
|
||||
"user-started-following-you": "<strong>%1</strong> התחיל לעקוב אחריך.",
|
||||
"user-started-following-you-dual": "<strong>%1</strong> ו-<strong>%2</strong> התחילו לעקוב אחריך.",
|
||||
"user-started-following-you-triple": "<strong>%1</strong>, <strong>%2</strong> ו<strong>%3</strong> התחילו לעקוב אחריך.",
|
||||
"user-started-following-you-triple": "<strong>%1</strong>, <strong>%2</strong> ו<strong>3%</strong> התחילו לעקוב אחריך.",
|
||||
"user-started-following-you-multiple": "<strong>%1</strong>, <strong>%2</strong> ו-%3 אחרים התחילו לעקוב אחריך.",
|
||||
"new-register": "<strong>%1</strong> שלח בקשת הרשמה.",
|
||||
"new-register-multiple": "ישנן <strong>%1</strong> בקשות הרשמה שמחכות לבדיקה.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Netočno numeriranje stranica, mora biti %1 ili %2",
|
||||
"username-taken": "Korisničko ime je zauzeto",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email je zauzet",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Mappa létezik",
|
||||
"invalid-pagination-value": "Érvénytelen lapozási érték, legalább %1 kell lennie és legfeljebb %2 -nak/nek",
|
||||
"username-taken": "Foglalt felhasználónév",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Foglalt e-mail",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Ez az email cím már meg lett hívva",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"edit-privileges": "Խմբագրել արտոնությունները",
|
||||
"select-clear-all": "Ընտրել/Մաքրել բոլորը",
|
||||
"chat": "Զրույց",
|
||||
"chat-with-privileged": "Խոսել առավելություն ունեցողի հետ",
|
||||
"chat-with-privileged": "Chat with Privileged",
|
||||
"upload-images": "Վերբեռնեք պատկերներ",
|
||||
"upload-files": "Վերբեռնել Ֆայլեր",
|
||||
"signature": "Ստորագրություն",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Թղթապանակ գոյություն ունի",
|
||||
"invalid-pagination-value": "Էջավորման անվավեր արժեքը, պետք է լինի առնվազն %1 և առավելագույնը %2",
|
||||
"username-taken": "Օգտագործողի անունը վերցված է",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Էլփոստը վերցված է",
|
||||
"email-nochange": "Մուտքագրված էլփոստը նույնն է, ինչ ֆայլում արդեն առկա էլ.",
|
||||
"email-invited": "Էլփոստն արդեն հրավիրված էր",
|
||||
"email-not-confirmed": "Որոշ կատեգորիաներում կամ թեմաներում հրապարակելը միացված կլինի, երբ ձեր էլփոստը հաստատվի, խնդրում ենք սեղմել այստեղ՝ հաստատող էլփոստը ուղարկելու համար:",
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
"sessions.description": "Այս էջը թույլ է տալիս դիտել ցանկացած ակտիվ սեանս այս ֆորումում և անհրաժեշտության դեպքում չեղարկել դրանք: Դուք կարող եք չեղարկել ձեր սեփական սեանսը՝ դուրս գալով ձեր հաշվից:",
|
||||
"revoke-session": "Չեղյալ համարել նիստը",
|
||||
"browser-version-on-platform": "%1 %2 %3-ում",
|
||||
"consent.title": "Ձեր Իրավունքները և Համաձայնությունը",
|
||||
"consent.title": "Your Rights & Consent",
|
||||
"consent.lead": "Այս համայնքի ֆորումը հավաքում և մշակում է ձեր անձնական տվյալները:",
|
||||
"consent.intro": "Մենք օգտագործում ենք այս տեղեկատվությունը խստորեն այս համայնքում ձեր փորձառությունն անհատականացնելու, ինչպես նաև ձեր կատարած գրառումները ձեր օգտատիրոջ հաշվին կապելու համար: Գրանցման քայլի ընթացքում ձեզանից պահանջվել է տրամադրել օգտատիրոջ անուն և էլ.փոստի հասցե, դուք կարող եք նաև լրացուցիչ տեղեկություններ տրամադրել այս կայքում ձեր օգտատիրոջ պրոֆիլը լրացնելու համար: Մենք պահպանում ենք այս տեղեկատվությունը ձեր օգտատիրոջ հաշվի ողջ կյանքի ընթացքում, և դուք կարող եք հետ վերցնել համաձայնությունը: ցանկացած պահի ջնջելով ձեր հաշիվը: Ցանկացած ժամանակ դուք կարող եք պահանջել ձեր ներդրման պատճենը այս կայքում՝ ձեր իրավունքների և amp; Համաձայնության էջ: Եթե ունեք հարցեր կամ մտահոգություններ, խորհուրդ ենք տալիս դիմել այս ֆորումի ադմինիստրատիվ թիմին:",
|
||||
"consent.email-intro": "Երբեմն, մենք կարող ենք նամակներ ուղարկել ձեր գրանցված էլ․ հասցեին՝ թարմացումներ տրամադրելու և/կամ ձեզ ծանուցելու նոր գործունեության մասին, որը վերաբերում է ձեզ: Դուք կարող եք հարմարեցնել համայնքի ամփոփման հաճախականությունը (ներառյալ այն ուղղակիորեն անջատելը), ինչպես նաև ընտրել, թե ինչ տեսակի ծանուցումներ պետք է ստանալ էլփոստի միջոցով՝ ձեր օգտվողի կարգավորումների էջի միջոցով:",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Nomor pagination tidak valid, minimal %1 dan maksimal %2",
|
||||
"username-taken": "Username sudah terdaftar",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email sudah terdaftar",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "La cartella esiste",
|
||||
"invalid-pagination-value": "Valore di impaginazione non valido, deve essere almeno %1 ed al massimo %2",
|
||||
"username-taken": "Nome utente già esistente",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email già esistente",
|
||||
"email-nochange": "L'email inserita è la stessa dell'email già presente in archivio.",
|
||||
"email-invited": "L'email è già stata invitata",
|
||||
"email-not-confirmed": "Sarai abilitato a postare in alcune categorie o discussioni una volta che la tua email sarà confermata, per favore clicca qui per inviare una email di conferma.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "無効なページネーション値です。%1 から%2の値でなければありません。",
|
||||
"username-taken": "ユーザー名は既に使われています",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "メールアドレスは既に使われています",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "폴더가 이미 존재합니다.",
|
||||
"invalid-pagination-value": "올바르지 않은 페이지 값입니다. 최소 %1에서 최대 2% 사이로 설정해야 합니다.",
|
||||
"username-taken": "이미 사용 중인 사용자명입니다.",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "이미 사용 중인 이메일입니다.",
|
||||
"email-nochange": "입력한 전자 메일이 이미 등록되어 있는 전자 메일과 동일합니다.",
|
||||
"email-invited": "해당 이메일의 사용자는 이미 초대되었습니다.",
|
||||
"email-not-confirmed": "이메일 인증이 완료된 후 카테고리나 화제에 새로운 포스트를 작성할 수 있습니다. 여기를 눌러 인증 메일을 다시 발송할 수 있습니다.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Bloga puslapių išdėstymo reikšmė. Ji turėtų būti ne mažesnė nei %1 ir ne didesnė nei %2",
|
||||
"username-taken": "Vartotojo vardas jau užimtas",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "El. pašto adresas jau užimtas",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Nederīgs vienību skaits, ir jābūt vismaz %1 un ne vairāk kā %2",
|
||||
"username-taken": "Lietotājvārds jau izmantots",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-pasta adrese jau izmantota",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Nombor halaman tidak sah, mesti tidak kurang dari %1 dan tidak lebih dari %2",
|
||||
"username-taken": "Nama pengguna telah digunakan",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Emel telah digunakan",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Mappen eksisterer",
|
||||
"invalid-pagination-value": "Ugyldig sidetall, må være minst %1 og maks %2",
|
||||
"username-taken": "Brukernavn opptatt",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-post opptatt",
|
||||
"email-nochange": "E-posten som er angitt er den samme e-posten som allerede er lagret.",
|
||||
"email-invited": "E-post har allerede fått invitasjon",
|
||||
"email-not-confirmed": "Posting i enkelte kategorier eller emner blir aktivert når e-posten din er bekreftet. Klikk her for å sende en bekreftelses-e-post.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Ongeldig paginering waarde. De waarde moet op z'n minst %1 zijn en niet hoger dan %2 zijn.",
|
||||
"username-taken": "Gebruikersnaam is al in gebruik",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-mailadres is al in gebruik",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "E-mail was reeds uitgenodigd",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder istnieje",
|
||||
"invalid-pagination-value": "Błędna wartość paginacji, zakres od %1 do %2",
|
||||
"username-taken": "Login zajęty",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email zajęty",
|
||||
"email-nochange": "Podany email jest taki sam jak ten już zapisany.",
|
||||
"email-invited": "Ten adres email otrzymał już zaproszenie",
|
||||
"email-not-confirmed": "Pisanie w niektórych kategoriach albo tematach jest dozwolone wtedy gdy Twój adres email został zweryfikowany, proszę kliknij tutaj aby wysłać potwierdzający email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Valor de paginação inválido, precisa ser no mínimo %1 e no máximo %2",
|
||||
"username-taken": "Nome de usuário já existe",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email já cadastrado",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "O email já foi convidado",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Valor de paginação errado, deve ser no mínimo %1 e no máximo %2",
|
||||
"username-taken": "Nome de utilizar já utilizado",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-mail já utilizado",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "Numele de utilizator este deja folosit",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Adresa de email este deja folostă",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Папка существует",
|
||||
"invalid-pagination-value": "Неправильно указан номер страницы. Значение должно быть в диапазоне от %1 до %2",
|
||||
"username-taken": "Это имя пользователя уже занято",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Пользователь с таким адресом электронной почты уже зарегистрирован",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Электронная почта уже была приглашена",
|
||||
"email-not-confirmed": "Вы не сможете отправлять сообщения, пока ваш адрес электронной почты не подтверждён. Пожалуйста, нажмите здесь, чтобы подтвердить его.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "Izina ryarafashwe mbere",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email yarafashwe mbere",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"username-taken": "Username taken",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email taken",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Neplatná stránkovania hodnota, musí byť najmenej %1 a najviac %2",
|
||||
"username-taken": "Užívateľské meno je už obsadené",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Tento e-mail je už obsadený",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Napačna vrednost za številčenje strani. Vrednost mora biti najmanj %1 in največ %2.",
|
||||
"username-taken": "Uporabniško ime je že zasedeno.",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-poštni naslov je že zaseden.",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Ky dokument ekziston",
|
||||
"invalid-pagination-value": "Vlera e pasaktë e faqes, duhet të jetë së paku %1 dhe maksimumi %2",
|
||||
"username-taken": "Username është i zënë",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email-i është i zënë",
|
||||
"email-nochange": "Email-i i futur është i njëjtë me emailin ekzistues në sistem.",
|
||||
"email-invited": "Email-i është ftuar më herët",
|
||||
"email-not-confirmed": "Postimi në disa kategori ose tema aktivizohet pasi emaili juaj të konfirmohet, ju lutemi klikoni këtu për të dërguar një email konfirmimi.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Фасцикла постоји",
|
||||
"invalid-pagination-value": "Неважећа вредност приликом нумерисања страница, мора бити најмање %1 а највише %2",
|
||||
"username-taken": "Корисничко име је заузето",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Адреса е-поште је заузета",
|
||||
"email-nochange": "Унета е-пошта је иста као е-пошта која је већ у евиденцији.",
|
||||
"email-invited": "Е-пошта је већ позвана",
|
||||
"email-not-confirmed": "Објављивање у неким категоријама или темама је омогућено када потврдите вашу е-пошту, кликните овде да бисте послали е-поруку за потврду.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Ogiltigt värde för siduppdelning. Värdet måste vara mellan %1 och %2",
|
||||
"username-taken": "Användarnamn upptaget",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Epostadress upptagen",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "หมายเลขหน้าไม่ถูกต้อง จำเป็นต้องเป็นตัวเลขอย่างน้อย %1 และอย่างมาก %2",
|
||||
"username-taken": "ชื่อผู้ใช้นี้มีการใช้แล้ว",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "อีเมลนี้มีการใช้แล้ว",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Dosya mevcut",
|
||||
"invalid-pagination-value": "Geçersiz sayfa numarası girdiniz, en az %1 ve en fazla %2 olabilir",
|
||||
"username-taken": "Kullanıcı İsmi Alınmış",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "E-posta Alınmış",
|
||||
"email-nochange": "Girdiğiniz e-posta var olan e-posta ile aynı",
|
||||
"email-invited": "E-posta halihazırda davet edilmiş",
|
||||
"email-not-confirmed": "Ancak e-postanız onaylandıktan sonra bazı kategorilere veya konulara ileti gönderebilirsiniz; lütfen bir onay e-postası almak için buraya tıklayın.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "Невірне значення сторінки, має бути щонайменше %1 та щонайбільше %2",
|
||||
"username-taken": "Це ім'я зайняте",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Ця електронна пошта зайнята",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Thư mục tồn tại",
|
||||
"invalid-pagination-value": "Giá trị phân trang không hợp lệ, tối thiểu phải là %1 và tối đa là %2",
|
||||
"username-taken": "Tên đăng nhập đã tồn tại",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "Email đã được đăng kí",
|
||||
"email-nochange": "Email đã nhập giống với email đã có trong tệp.",
|
||||
"email-invited": "Email đã được mời",
|
||||
"email-not-confirmed": "Đăng trong một số danh mục hoặc chủ đề được bật sau khi email của bạn được xác nhận, vui lòng nhấp vào đây để gửi email xác nhận.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "文件夹已存在",
|
||||
"invalid-pagination-value": "无效的分页数值,必须介于 %1 和 %2 之间",
|
||||
"username-taken": "此用户名已被占用",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "此电子邮箱已被占用",
|
||||
"email-nochange": "输入的邮件地址和已存档的邮件地址相同。",
|
||||
"email-invited": "已通过电子邮件进行邀请",
|
||||
"email-not-confirmed": "您需要验证您的邮箱后才能在版块或主题中发布帖子,请点击此处以发送验证邮件。",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
"invalid-pagination-value": "無效的分頁數,必須介於 %1 和 %2 之間",
|
||||
"username-taken": "此使用者名已被使用",
|
||||
"email-taken": "Email address is already taken.",
|
||||
"email-taken": "此電子信箱已被使用",
|
||||
"email-nochange": "The email entered is the same as the email already on file.",
|
||||
"email-invited": "Email was already invited",
|
||||
"email-not-confirmed": "Posting in some categories or topics is enabled once your email is confirmed, please click here to send a confirmation email.",
|
||||
|
||||
@@ -117,7 +117,7 @@ get:
|
||||
categoryWatchState:
|
||||
type: object
|
||||
properties:
|
||||
tracking:
|
||||
watching:
|
||||
type: boolean
|
||||
disableCustomUserSkins:
|
||||
type: number
|
||||
|
||||
@@ -195,7 +195,7 @@ define('admin/extend/plugins', [
|
||||
let html = '';
|
||||
activePlugins.forEach(function (plugin) {
|
||||
html += `
|
||||
<li class="d-flex justify-content-between gap-1 pointer border-bottom pb-2" data-plugin="${plugin}">
|
||||
<li class="d-flex justify-content-between gap-1 pointer border-bottom pb-2">
|
||||
${plugin}
|
||||
<div class="d-flex gap-1">
|
||||
<div class="btn-ghost-sm move-up">
|
||||
@@ -233,7 +233,7 @@ define('admin/extend/plugins', [
|
||||
const plugins = $('#order-active-plugins-modal .plugin-list').children();
|
||||
const data = [];
|
||||
plugins.each(function (index, el) {
|
||||
data.push({ name: $(el).attr('data-plugin'), order: index });
|
||||
data.push({ name: $(el).text(), order: index });
|
||||
});
|
||||
|
||||
socket.emit('admin.plugins.orderActivePlugins', data, function (err) {
|
||||
|
||||
@@ -5,7 +5,7 @@ define('admin/manage/digest', ['bootbox', 'alerts'], function (bootbox, alerts)
|
||||
const Digest = {};
|
||||
|
||||
Digest.init = function () {
|
||||
$('.digest').on('click', '[data-action]', function () {
|
||||
$('table').on('click', '[data-action]', function () {
|
||||
const action = this.getAttribute('data-action');
|
||||
const uid = this.getAttribute('data-uid');
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ define('admin/settings/navigation', [
|
||||
translator.translate(li, function (li) {
|
||||
li = $(translator.unescape(li));
|
||||
$('#enabled').append(li);
|
||||
componentHandler.upgradeDom();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -150,7 +150,7 @@ ajaxify.widgets = { render: render };
|
||||
|
||||
if (data) {
|
||||
let status = parseInt(data.status, 10);
|
||||
if ([400, 403, 404, 500, 502, 503].includes(status)) {
|
||||
if ([400, 403, 404, 500, 502, 504].includes(status)) {
|
||||
if (status === 502 && retry) {
|
||||
retry = false;
|
||||
ajaxifyTimer = undefined;
|
||||
|
||||
@@ -127,6 +127,7 @@ define('forum/category', [
|
||||
hooks.fire('action:topics.loading');
|
||||
const params = utils.params();
|
||||
infinitescroll.loadMore(`/categories/${ajaxify.data.cid}/topics`, {
|
||||
cid: ajaxify.data.cid,
|
||||
after: after,
|
||||
direction: direction,
|
||||
query: params,
|
||||
|
||||
@@ -35,7 +35,7 @@ define('forum/chats/recent', ['alerts', 'api', 'chat'], function (alerts, api, c
|
||||
return;
|
||||
}
|
||||
recentChats.attr('loading', 1);
|
||||
api.get(`/chats`, {
|
||||
app.get(`/chats`, {
|
||||
uid: ajaxify.data.uid,
|
||||
after: recentChats.attr('data-nextstart'),
|
||||
}).then(({ rooms, nextStart }) => {
|
||||
|
||||
@@ -92,7 +92,7 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b
|
||||
const searchEl = $('[component="groups/members/search"]');
|
||||
searchEl.on('keyup', utils.debounce(function () {
|
||||
const query = searchEl.val();
|
||||
api.get(`/groups/${ajaxify.data.group.slug}/members`, { query }, function (err, results) {
|
||||
api.get(`/groups/${groupName}/members`, { query }, function (err, results) {
|
||||
if (err) {
|
||||
return alerts.error(err);
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ define('forum/topic', [
|
||||
btn.find('i').removeClass('fa-copy').addClass('fa-check');
|
||||
setTimeout(() => btn.find('i').removeClass('fa-check').addClass('fa-copy'), 2000);
|
||||
const codeEl = btn.parent().find('code');
|
||||
if (codeEl.attr('data-lines') && codeEl.find('.hljs-ln-code[data-line-number]').length) {
|
||||
if (codeEl.attr('data-lines')) {
|
||||
return codeEl.find('.hljs-ln-code[data-line-number]')
|
||||
.map((i, e) => e.textContent).get().join('\n');
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ define('forum/topic/events', [
|
||||
'components',
|
||||
'translator',
|
||||
'hooks',
|
||||
'helpers',
|
||||
], function (postTools, threadTools, posts, images, components, translator, hooks, helpers) {
|
||||
], function (postTools, threadTools, posts, images, components, translator, hooks) {
|
||||
const Events = {};
|
||||
|
||||
const events = {
|
||||
@@ -153,7 +152,7 @@ define('forum/topic/events', [
|
||||
editorEl.replaceWith(html);
|
||||
postContainer.find('[component="post/edit-indicator"]')
|
||||
.removeClass('hidden')
|
||||
.translateAttr('title', `[[global:edited-timestamp, ${helpers.isoTimeToLocaleString(editData.editedISO, config.userLang)}]]`);
|
||||
.translateAttr('title', `[[global:edited-timestamp, ${editData.editedISO}]]`);
|
||||
postContainer.find('[component="post/editor"] .timeago').timeago();
|
||||
hooks.fire('action:posts.edited', data);
|
||||
});
|
||||
|
||||
@@ -149,7 +149,7 @@ define('forum/topic/move-post', [
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
if (data.pids.length && ajaxify.data.template.topic &&
|
||||
if (data.pids.length === 1 && ajaxify.data.template.topic &&
|
||||
parseInt(data.tid, 10) === parseInt(ajaxify.data.tid, 10)) {
|
||||
ajaxify.go(`/post/${data.pids[0]}`);
|
||||
}
|
||||
|
||||
@@ -353,8 +353,7 @@ define('navigator', [
|
||||
}
|
||||
|
||||
async function updateUnreadIndicator(index) {
|
||||
const { bookmarkThreshold } = ajaxify.data;
|
||||
if (!paginationBlockUnreadEl.length || ajaxify.data.postcount <= bookmarkThreshold || !bookmarkThreshold) {
|
||||
if (!paginationBlockUnreadEl.length || ajaxify.data.postcount <= ajaxify.data.bookmarkThreshold) {
|
||||
return;
|
||||
}
|
||||
const currentBookmark = ajaxify.data.bookmark || storage.getItem('topic:' + ajaxify.data.tid + ':bookmark');
|
||||
@@ -459,9 +458,11 @@ define('navigator', [
|
||||
};
|
||||
|
||||
function toggle(flag) {
|
||||
if (flag && (!ajaxify.data.template.topic && !ajaxify.data.template.category)) {
|
||||
const path = ajaxify.removeRelativePath(window.location.pathname.slice(1));
|
||||
if (flag && (!path.startsWith('topic') && !path.startsWith('category'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
paginationBlockEl.toggleClass('ready', flag);
|
||||
paginationBlockEl.toggleClass('noreplies', count <= 1);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
define('quickreply', [
|
||||
'components', 'composer', 'composer/autocomplete', 'api',
|
||||
'alerts', 'uploadHelpers', 'mousetrap', 'storage', 'hooks',
|
||||
'alerts', 'uploadHelpers', 'mousetrap', 'storage',
|
||||
], function (
|
||||
components, composer, autocomplete, api,
|
||||
alerts, uploadHelpers, mousetrap, storage, hooks
|
||||
alerts, uploadHelpers, mousetrap, storage
|
||||
) {
|
||||
const QuickReply = {};
|
||||
|
||||
@@ -91,7 +91,6 @@ define('quickreply', [
|
||||
components.get('topic/quickreply/text').val('');
|
||||
storage.removeItem(qrDraftId);
|
||||
autocomplete._active.core_qr.hide();
|
||||
hooks.fire('action:quickreply.success', { data });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ define('sort', ['components'], function (components) {
|
||||
currentSetting.find('i').addClass('fa-check');
|
||||
|
||||
$('body')
|
||||
.off('click', '[component="thread/sort"] a[data-sort]')
|
||||
.on('click', '[component="thread/sort"] a[data-sort]', function () {
|
||||
.off('click', '[component="thread/sort"] a')
|
||||
.on('click', '[component="thread/sort"] a', function () {
|
||||
const newSetting = $(this).attr('data-sort');
|
||||
const urlParams = utils.params();
|
||||
urlParams.sort = newSetting;
|
||||
|
||||
@@ -10,6 +10,7 @@ const isPrerelease = /^v?\d+\.\d+\.\d+-.+$/;
|
||||
const latestReleaseUrl = 'https://api.github.com/repos/NodeBB/NodeBB/releases/latest';
|
||||
|
||||
async function getLatestVersion() {
|
||||
return '';
|
||||
const headers = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
'User-Agent': encodeURIComponent(`NodeBB Admin Control Panel/${meta.config.title}`),
|
||||
@@ -18,24 +19,25 @@ async function getLatestVersion() {
|
||||
if (versionCacheLastModified) {
|
||||
headers['If-Modified-Since'] = versionCacheLastModified;
|
||||
}
|
||||
try {
|
||||
const { body: latestRelease, response } = await request.get(latestReleaseUrl, {
|
||||
headers: headers,
|
||||
timeout: 2000,
|
||||
});
|
||||
|
||||
const { body: latestRelease, response } = await request.get(latestReleaseUrl, {
|
||||
headers: headers,
|
||||
timeout: 2000,
|
||||
});
|
||||
if (response.statusCode === 304) {
|
||||
if (!latestRelease || !latestRelease.tag_name) {
|
||||
throw new Error('[[error:cant-get-latest-release]]');
|
||||
}
|
||||
const tagName = latestRelease.tag_name.replace(/^v/, '');
|
||||
versionCache = tagName;
|
||||
versionCacheLastModified = response.headers['last-modified'];
|
||||
return versionCache;
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status === 304) {
|
||||
return versionCache;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
if (response.statusCode !== 200) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
if (!latestRelease || !latestRelease.tag_name) {
|
||||
throw new Error('[[error:cant-get-latest-release]]');
|
||||
}
|
||||
const tagName = latestRelease.tag_name.replace(/^v/, '');
|
||||
versionCache = tagName;
|
||||
versionCacheLastModified = response.headers['last-modified'];
|
||||
return versionCache;
|
||||
}
|
||||
|
||||
exports.getLatestVersion = getLatestVersion;
|
||||
|
||||
@@ -128,7 +128,7 @@ categoriesAPI.getTopics = async (caller, data) => {
|
||||
|
||||
let start = Math.max(0, parseInt(data.after || 0, 10));
|
||||
|
||||
if (parseInt(data.direction, 10) === -1) {
|
||||
if (data.direction === -1) {
|
||||
start -= infScrollTopicsPerPage;
|
||||
}
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ postsAPI.move = async function (caller, data) {
|
||||
]);
|
||||
|
||||
if (!postDeleted && !topicDeleted) {
|
||||
socketHelpers.sendNotificationToPostOwner(data.pid, caller.uid, 'move', 'notifications:moved-your-post');
|
||||
socketHelpers.sendNotificationToPostOwner(data.pid, caller.uid, 'move', 'notifications:moved_your_post');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -219,10 +219,7 @@ module.exports = function (Categories) {
|
||||
min: Categories.watchStates.watching,
|
||||
max: Categories.watchStates.watching,
|
||||
});
|
||||
const index = followers.indexOf(String(exceptUid));
|
||||
if (index !== -1) {
|
||||
followers.splice(index, 1);
|
||||
}
|
||||
|
||||
if (!followers.length) {
|
||||
return;
|
||||
}
|
||||
@@ -236,6 +233,7 @@ module.exports = function (Categories) {
|
||||
const notification = await notifications.create({
|
||||
type: 'new-topic-in-category',
|
||||
nid: `new_topic:tid:${postData.topic.tid}:uid:${exceptUid}`,
|
||||
subject: bodyShort,
|
||||
bodyShort: bodyShort,
|
||||
bodyLong: postData.content,
|
||||
pid: postData.pid,
|
||||
|
||||
@@ -114,9 +114,7 @@ if (!configExists && process.argv[2] !== 'setup') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (configExists) {
|
||||
process.env.CONFIG = configFile;
|
||||
}
|
||||
process.env.CONFIG = configFile;
|
||||
|
||||
// running commands
|
||||
program
|
||||
|
||||
@@ -7,7 +7,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
|
||||
|
||||
const request = require('../request');
|
||||
const { paths, pluginNamePattern } = require('../constants');
|
||||
const pkgInstall = require('./package-install');
|
||||
|
||||
@@ -74,11 +74,7 @@ async function getCurrentVersion() {
|
||||
}
|
||||
|
||||
async function getSuggestedModules(nbbVersion, toCheck) {
|
||||
const request = require('../request');
|
||||
let { response, body } = await request.get(`https://packages.nodebb.org/api/v1/suggest?version=${nbbVersion}&package[]=${toCheck.join('&package[]=')}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Unable to get suggested module for NodeBB(${nbbVersion}) ${toCheck.join(',')}`);
|
||||
}
|
||||
let { body } = await request.get(`https://packages.nodebb.org/api/v1/suggest?version=${nbbVersion}&package[]=${toCheck.join('&package[]=')}`);
|
||||
if (!Array.isArray(body) && toCheck.length === 1) {
|
||||
body = [body];
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ groupsController.get = async function (req, res, next) {
|
||||
if (!group || groupName === groups.BANNED_USERS) {
|
||||
return next();
|
||||
}
|
||||
group.isOwner = true;
|
||||
|
||||
const groupNameData = groupNames.map(name => ({
|
||||
encodedName: encodeURIComponent(name),
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const nconf = require('nconf');
|
||||
const winston = require('winston');
|
||||
const validator = require('validator');
|
||||
const path = require('path');
|
||||
const translator = require('../translator');
|
||||
const plugins = require('../plugins');
|
||||
const middleware = require('../middleware');
|
||||
@@ -56,12 +54,6 @@ exports.handleErrors = async function handleErrors(err, req, res, next) { // esl
|
||||
controllers['404'].handle404(req, res);
|
||||
};
|
||||
|
||||
const notBuiltHandler = async () => {
|
||||
let file = await fs.promises.readFile(path.join(__dirname, '../../public/500.html'), { encoding: 'utf-8' });
|
||||
file = file.replace('{message}', 'Failed to lookup view! Did you run `./nodebb build`?');
|
||||
return res.type('text/html').send(file);
|
||||
};
|
||||
|
||||
const defaultHandler = async function () {
|
||||
if (res.headersSent) {
|
||||
return;
|
||||
@@ -103,8 +95,6 @@ exports.handleErrors = async function handleErrors(err, req, res, next) { // esl
|
||||
data.cases[err.code](err, req, res, defaultHandler);
|
||||
} else if (err.message.startsWith('[[error:no-') && err.message !== '[[error:no-privileges]]') {
|
||||
notFoundHandler();
|
||||
} else if (err.message.startsWith('Failed to lookup view')) {
|
||||
notBuiltHandler();
|
||||
} else {
|
||||
await defaultHandler();
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ groupsController.details = async function (req, res, next) {
|
||||
if (!groupData) {
|
||||
return next();
|
||||
}
|
||||
groupData.isOwner = groupData.isOwner || isAdmin || (isGlobalMod && !groupData.system);
|
||||
|
||||
res.render('groups/details', {
|
||||
title: `[[pages:group, ${groupData.displayName}]]`,
|
||||
|
||||
@@ -13,25 +13,17 @@ module.exports = function (module) {
|
||||
}
|
||||
value = value.map(v => helpers.valueToString(v));
|
||||
|
||||
try {
|
||||
await module.client.collection('objects').updateOne({
|
||||
_key: key,
|
||||
}, {
|
||||
$addToSet: {
|
||||
members: {
|
||||
$each: value,
|
||||
},
|
||||
await module.client.collection('objects').updateOne({
|
||||
_key: key,
|
||||
}, {
|
||||
$addToSet: {
|
||||
members: {
|
||||
$each: value,
|
||||
},
|
||||
}, {
|
||||
upsert: true,
|
||||
});
|
||||
} catch (err) {
|
||||
if (err && err.message.includes('E11000 duplicate key error')) {
|
||||
console.log(new Error('e11000').stack, key, value);
|
||||
return await module.setAdd(key, value);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
}, {
|
||||
upsert: true,
|
||||
});
|
||||
};
|
||||
|
||||
module.setsAdd = async function (keys, value) {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
const user = require('../user');
|
||||
const db = require('../database');
|
||||
const plugins = require('../plugins');
|
||||
const privileges = require('../privileges');
|
||||
const slugify = require('../slugify');
|
||||
|
||||
const Groups = module.exports;
|
||||
@@ -131,37 +130,30 @@ Groups.get = async function (groupName, options) {
|
||||
stop = (parseInt(options.userListCount, 10) || 4) - 1;
|
||||
}
|
||||
|
||||
const [groupData, members, isMember, isPending, isInvited, isOwner, isAdmin, isGlobalMod] = await Promise.all([
|
||||
const [groupData, members, pending, invited, isMember, isPending, isInvited, isOwner] = await Promise.all([
|
||||
Groups.getGroupData(groupName),
|
||||
Groups.getOwnersAndMembers(groupName, options.uid, 0, stop),
|
||||
Groups.getPending(groupName),
|
||||
Groups.getInvites(groupName),
|
||||
Groups.isMember(options.uid, groupName),
|
||||
Groups.isPending(options.uid, groupName),
|
||||
Groups.isInvited(options.uid, groupName),
|
||||
Groups.ownership.isOwner(options.uid, groupName),
|
||||
privileges.admin.can('admin:groups', options.uid),
|
||||
user.isGlobalModerator(options.uid),
|
||||
]);
|
||||
|
||||
if (!groupData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
groupData.isOwner = isOwner || isAdmin || (isGlobalMod && !groupData.system);
|
||||
if (groupData.isOwner) {
|
||||
([groupData.pending, groupData.invited] = await Promise.all([
|
||||
Groups.getPending(groupName),
|
||||
Groups.getInvites(groupName),
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
const descriptionParsed = await plugins.hooks.fire('filter:parse.raw', String(groupData.description || ''));
|
||||
groupData.descriptionParsed = descriptionParsed;
|
||||
groupData.members = members;
|
||||
groupData.membersNextStart = stop + 1;
|
||||
groupData.pending = pending.filter(Boolean);
|
||||
groupData.invited = invited.filter(Boolean);
|
||||
groupData.isMember = isMember;
|
||||
groupData.isPending = isPending;
|
||||
groupData.isInvited = isInvited;
|
||||
groupData.isOwner = isOwner;
|
||||
const results = await plugins.hooks.fire('filter:group.get', { group: groupData });
|
||||
return results.group;
|
||||
};
|
||||
|
||||
@@ -4,10 +4,13 @@ const db = require('../database');
|
||||
const user = require('../user');
|
||||
|
||||
module.exports = function (Groups) {
|
||||
Groups.getUsersFromSet = async function (set, fields = []) {
|
||||
Groups.getUsersFromSet = async function (set, fields) {
|
||||
const uids = await db.getSetMembers(set);
|
||||
const userData = await user.getUsersFields(uids, fields);
|
||||
return userData.filter(u => u && u.uid);
|
||||
|
||||
if (fields) {
|
||||
return await user.getUsersFields(uids, fields);
|
||||
}
|
||||
return await user.getUsersData(uids);
|
||||
};
|
||||
|
||||
Groups.getUserGroups = async function (uids) {
|
||||
|
||||
@@ -39,7 +39,7 @@ module.exports = function (middleware) {
|
||||
|
||||
const data = {
|
||||
site_title: meta.config.title || 'NodeBB',
|
||||
message: meta.config.maintenanceModeMessage,
|
||||
message: meta.config.maintenanceModeMessage || '',
|
||||
};
|
||||
|
||||
if (res.locals.isAPI) {
|
||||
|
||||
@@ -207,38 +207,6 @@ Hooks.hasListeners = function (hook) {
|
||||
return !!(plugins.loadedHooks[hook] && plugins.loadedHooks[hook].length > 0);
|
||||
};
|
||||
|
||||
function hookHandlerPromise(hook, hookObj, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let resolved = false;
|
||||
function _resolve(result) {
|
||||
if (resolved) {
|
||||
winston.warn(`[plugins] ${hook} already resolved in plugin ${hookObj.id}`);
|
||||
return;
|
||||
}
|
||||
resolved = true;
|
||||
resolve(result);
|
||||
}
|
||||
const returned = hookObj.method(params, (err, result) => {
|
||||
if (err) reject(err); else _resolve(result);
|
||||
});
|
||||
|
||||
if (utils.isPromise(returned)) {
|
||||
returned.then(
|
||||
payload => _resolve(payload),
|
||||
err => reject(err)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hook.startsWith('filter:') && returned !== undefined) {
|
||||
_resolve(returned);
|
||||
} else if (hook.startsWith('static:') && hookObj.method.length <= 1) {
|
||||
// make sure it is resolved if static hook doesn't return anything and doesn't use callback
|
||||
_resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fireFilterHook(hook, hookList, params) {
|
||||
if (!Array.isArray(hookList) || !hookList.length) {
|
||||
return params;
|
||||
@@ -255,7 +223,31 @@ async function fireFilterHook(hook, hookList, params) {
|
||||
if (hookObj.method.constructor && hookObj.method.constructor.name === 'AsyncFunction') {
|
||||
return await hookObj.method(params);
|
||||
}
|
||||
return hookHandlerPromise(hook, hookObj, params);
|
||||
return new Promise((resolve, reject) => {
|
||||
let resolved = false;
|
||||
function _resolve(result) {
|
||||
if (resolved) {
|
||||
winston.warn(`[plugins] ${hook} already resolved in plugin ${hookObj.id}`);
|
||||
return;
|
||||
}
|
||||
resolved = true;
|
||||
resolve(result);
|
||||
}
|
||||
const returned = hookObj.method(params, (err, result) => {
|
||||
if (err) reject(err); else _resolve(result);
|
||||
});
|
||||
|
||||
if (utils.isPromise(returned)) {
|
||||
returned.then(
|
||||
payload => _resolve(payload),
|
||||
err => reject(err)
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (returned) {
|
||||
_resolve(returned);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const hookObj of hookList) {
|
||||
@@ -311,7 +303,28 @@ async function fireStaticHook(hook, hookList, params) {
|
||||
return timeout(hookObj.method(params), 10000, 'timeout');
|
||||
}
|
||||
|
||||
return hookHandlerPromise(hook, hookObj, params);
|
||||
return new Promise((resolve, reject) => {
|
||||
let resolved = false;
|
||||
function _resolve(result) {
|
||||
if (resolved) {
|
||||
return;
|
||||
}
|
||||
resolved = true;
|
||||
resolve(result);
|
||||
}
|
||||
const returned = hookObj.method(params, (err, result) => {
|
||||
if (err) reject(err); else _resolve(result);
|
||||
});
|
||||
|
||||
if (utils.isPromise(returned)) {
|
||||
returned.then(
|
||||
payload => _resolve(payload),
|
||||
err => reject(err)
|
||||
);
|
||||
return;
|
||||
}
|
||||
_resolve();
|
||||
});
|
||||
}
|
||||
|
||||
for (const hookObj of hookList) {
|
||||
|
||||
@@ -153,10 +153,8 @@ Plugins.reloadRoutes = async function (params) {
|
||||
|
||||
Plugins.get = async function (id) {
|
||||
const url = `${nconf.get('registry') || 'https://packages.nodebb.org'}/api/v1/plugins/${id}`;
|
||||
const { response, body } = await request.get(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`[[error:unable-to-load-plugin, ${id}]]`);
|
||||
}
|
||||
const { body } = await request.get(url);
|
||||
|
||||
let normalised = await Plugins.normalise([body ? body.payload : {}]);
|
||||
normalised = normalised.filter(plugin => plugin.id === id);
|
||||
return normalised.length ? normalised[0] : undefined;
|
||||
@@ -169,10 +167,7 @@ Plugins.list = async function (matching) {
|
||||
const { version } = require(paths.currentPackage);
|
||||
const url = `${nconf.get('registry') || 'https://packages.nodebb.org'}/api/v1/plugins${matching !== false ? `?version=${version}` : ''}`;
|
||||
try {
|
||||
const { response, body } = await request.get(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`[[error:unable-to-load-plugins-from-nbbpm]]`);
|
||||
}
|
||||
const { body } = await request.get(url);
|
||||
return await Plugins.normalise(body);
|
||||
} catch (err) {
|
||||
winston.error(`Error loading ${url}`, err);
|
||||
@@ -182,10 +177,7 @@ Plugins.list = async function (matching) {
|
||||
|
||||
Plugins.listTrending = async () => {
|
||||
const url = `${nconf.get('registry') || 'https://packages.nodebb.org'}/api/v1/analytics/top/week`;
|
||||
const { response, body } = await request.get(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`[[error:unable-to-load-trending-plugins]]`);
|
||||
}
|
||||
const { body } = await request.get(url);
|
||||
return body;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ const request = require('../request');
|
||||
const db = require('../database');
|
||||
const meta = require('../meta');
|
||||
const pubsub = require('../pubsub');
|
||||
const { paths, pluginNamePattern } = require('../constants');
|
||||
const { paths } = require('../constants');
|
||||
const pkgInstall = require('../cli/package-install');
|
||||
|
||||
const packageManager = pkgInstall.getPackageManager();
|
||||
@@ -60,9 +60,6 @@ module.exports = function (Plugins) {
|
||||
winston.error('Cannot activate plugins while plugin state is set in the configuration (config.json, environmental variables or terminal arguments), please modify the configuration instead');
|
||||
throw new Error('[[error:plugins-set-in-configuration]]');
|
||||
}
|
||||
if (!pluginNamePattern.test(id)) {
|
||||
throw new Error('[[error:invalid-plugin-id]]');
|
||||
}
|
||||
const isActive = await Plugins.isActive(id);
|
||||
if (isActive) {
|
||||
await db.sortedSetRemove('plugins:active', id);
|
||||
@@ -77,10 +74,8 @@ module.exports = function (Plugins) {
|
||||
};
|
||||
|
||||
Plugins.checkWhitelist = async function (id, version) {
|
||||
const { response, body } = await request.get(`https://packages.nodebb.org/api/v1/plugins/${encodeURIComponent(id)}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`[[error:cant-connect-to-nbbpm]]`);
|
||||
}
|
||||
const { body } = await request.get(`https://packages.nodebb.org/api/v1/plugins/${encodeURIComponent(id)}`);
|
||||
|
||||
if (body && body.code === 'ok' && (version === 'latest' || body.payload.valid.includes(version))) {
|
||||
return;
|
||||
}
|
||||
@@ -89,10 +84,7 @@ module.exports = function (Plugins) {
|
||||
};
|
||||
|
||||
Plugins.suggest = async function (pluginId, nbbVersion) {
|
||||
const { response, body } = await request.get(`https://packages.nodebb.org/api/v1/suggest?package=${encodeURIComponent(pluginId)}&version=${encodeURIComponent(nbbVersion)}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`[[error:cant-connect-to-nbbpm]]`);
|
||||
}
|
||||
const { body } = await request.get(`https://packages.nodebb.org/api/v1/suggest?package=${encodeURIComponent(pluginId)}&version=${encodeURIComponent(nbbVersion)}`);
|
||||
return body;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ module.exports = function (Plugins) {
|
||||
const url = `${nconf.get('registry') || 'https://packages.nodebb.org'}/api/v1/plugin/usage`;
|
||||
try {
|
||||
const { response, body } = await request.post(url, {
|
||||
body: {
|
||||
data: {
|
||||
id: hash.digest('hex'),
|
||||
version: pkg.version,
|
||||
plugins: Plugins.loadedPlugins,
|
||||
@@ -35,7 +35,7 @@ module.exports = function (Plugins) {
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status !== 200) {
|
||||
winston.error(`[plugins.submitUsageData] received ${response.status} ${body}`);
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,80 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
const axios = require('axios').default;
|
||||
const { CookieJar } = require('tough-cookie');
|
||||
const fetchCookie = require('fetch-cookie');
|
||||
const { wrapper } = require('axios-cookiejar-support');
|
||||
|
||||
wrapper(axios);
|
||||
|
||||
exports.jar = function () {
|
||||
return new CookieJar();
|
||||
};
|
||||
|
||||
async function call(url, method, { body, timeout, jar, ...config } = {}) {
|
||||
let fetchImpl = fetch;
|
||||
if (jar) {
|
||||
fetchImpl = fetchCookie(fetch, jar);
|
||||
}
|
||||
|
||||
const opts = {
|
||||
async function call(url, method, config = {}) {
|
||||
const result = await axios({
|
||||
...config,
|
||||
method,
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
...config.headers,
|
||||
},
|
||||
};
|
||||
if (timeout > 0) {
|
||||
opts.signal = AbortSignal.timeout(timeout);
|
||||
}
|
||||
|
||||
if (body && ['POST', 'PUT', 'PATCH', 'DEL', 'DELETE'].includes(method)) {
|
||||
if (opts.headers['content-type'] && opts.headers['content-type'].startsWith('application/json')) {
|
||||
opts.body = JSON.stringify(body);
|
||||
} else {
|
||||
opts.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetchImpl(url, opts);
|
||||
|
||||
const { headers } = response;
|
||||
const contentType = headers.get('content-type');
|
||||
const jsonTest = /application\/([a-z]+\+)?json/;
|
||||
const isJSON = contentType && jsonTest.test(contentType);
|
||||
let respBody = await response.text();
|
||||
if (isJSON && respBody) {
|
||||
try {
|
||||
respBody = JSON.parse(respBody);
|
||||
} catch (err) {
|
||||
throw new Error('invalid json in response body', url);
|
||||
}
|
||||
}
|
||||
url: url,
|
||||
});
|
||||
|
||||
return {
|
||||
body: respBody,
|
||||
body: result.data,
|
||||
response: {
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusCode: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
status: result.status,
|
||||
statusCode: result.status,
|
||||
statusText: result.statusText,
|
||||
headers: result.headers,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
const { body, response } = await request.get('someurl?foo=1&baz=2')
|
||||
or
|
||||
const { body, response } = await request.get('someurl', { params: { foo:1, baz: 2 } })
|
||||
*/
|
||||
exports.get = async (url, config) => call(url, 'GET', config);
|
||||
exports.get = async (url, config) => call(url, 'get', config);
|
||||
|
||||
exports.head = async (url, config) => call(url, 'HEAD', config);
|
||||
exports.del = async (url, config) => call(url, 'DELETE', config);
|
||||
exports.head = async (url, config) => call(url, 'head', config);
|
||||
exports.del = async (url, config) => call(url, 'delete', config);
|
||||
exports.delete = exports.del;
|
||||
exports.options = async (url, config) => call(url, 'OPTIONS', config);
|
||||
exports.options = async (url, config) => call(url, 'delete', config);
|
||||
|
||||
/*
|
||||
const { body, response } = await request.post('someurl', { body: { foo: 1, baz: 2}})
|
||||
const { body, response } = await request.post('someurl', { data: { foo: 1, baz: 2}})
|
||||
*/
|
||||
exports.post = async (url, config) => call(url, 'POST', config);
|
||||
exports.put = async (url, config) => call(url, 'PUT', config);
|
||||
exports.patch = async (url, config) => call(url, 'PATCH', config);
|
||||
exports.post = async (url, config) => call(url, 'post', config);
|
||||
exports.put = async (url, config) => call(url, 'put', config);
|
||||
exports.patch = async (url, config) => call(url, 'patch', config);
|
||||
|
||||
|
||||
|
||||
@@ -13,9 +13,6 @@ module.exports = function (app, middleware, controllers) {
|
||||
app.get('/css/previews/:theme', controllers.admin.themes.get);
|
||||
app.get('/osd.xml', controllers.osd.handle);
|
||||
app.get('/service-worker.js', (req, res) => {
|
||||
res.status(200)
|
||||
.type('application/javascript')
|
||||
.set('Service-Worker-Allowed', `${nconf.get('relative_path')}/`)
|
||||
.sendFile(path.join(__dirname, '../../build/public/src/service-worker.js'));
|
||||
res.status(200).type('application/javascript').set('Service-Worker-Allowed', `${nconf.get('relative_path')}/`).sendFile(path.join(__dirname, '../../public/src/service-worker.js'));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@ const nconf = require('nconf');
|
||||
const plugins = require('../../plugins');
|
||||
const events = require('../../events');
|
||||
const db = require('../../database');
|
||||
const { pluginNamePattern } = require('../../constants');
|
||||
|
||||
const Plugins = module.exports;
|
||||
|
||||
@@ -42,14 +41,7 @@ Plugins.orderActivePlugins = async function (socket, data) {
|
||||
throw new Error('[[error:plugins-set-in-configuration]]');
|
||||
}
|
||||
data = data.filter(plugin => plugin && plugin.name);
|
||||
|
||||
data.forEach((plugin) => {
|
||||
if (!pluginNamePattern.test(plugin.name)) {
|
||||
throw new Error('[[error:invalid-plugin-id]]');
|
||||
}
|
||||
});
|
||||
|
||||
await db.sortedSetAdd('plugins:active', data.map(p => p.order || 0), data.map(p => p.name));
|
||||
await Promise.all(data.map(plugin => db.sortedSetAdd('plugins:active', plugin.order || 0, plugin.name)));
|
||||
};
|
||||
|
||||
Plugins.upgrade = async function (socket, data) {
|
||||
|
||||
@@ -27,7 +27,6 @@ module.exports = function (SocketPosts) {
|
||||
canDelete: privileges.posts.canDelete(data.pid, socket.uid),
|
||||
canPurge: privileges.posts.canPurge(data.pid, socket.uid),
|
||||
canFlag: privileges.posts.canFlag(data.pid, socket.uid),
|
||||
canViewHistory: privileges.posts.can('posts:history', data.pid, socket.uid),
|
||||
flagged: flags.exists('post', data.pid, socket.uid), // specifically, whether THIS calling user flagged
|
||||
bookmarked: posts.hasBookmarked(data.pid, socket.uid),
|
||||
postSharing: social.getActivePostSharing(),
|
||||
@@ -47,7 +46,7 @@ module.exports = function (SocketPosts) {
|
||||
postData.display_move_tools = results.isAdmin || results.isModerator;
|
||||
postData.display_change_owner_tools = results.isAdmin || results.isModerator;
|
||||
postData.display_ip_ban = (results.isAdmin || results.isGlobalMod) && !postData.selfPost;
|
||||
postData.display_history = results.history && results.canViewHistory;
|
||||
postData.display_history = results.history;
|
||||
postData.flags = {
|
||||
flagId: parseInt(results.posts.flagId, 10) || null,
|
||||
can: results.canFlag.flag,
|
||||
|
||||
@@ -30,7 +30,7 @@ module.exports = function (SocketTopics) {
|
||||
parseInt(data.count, 10) || meta.config.postsPerPage || 20
|
||||
));
|
||||
|
||||
if (parseInt(data.direction, 10) === -1) {
|
||||
if (data.direction === -1) {
|
||||
start -= infScrollPostsPerPage;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ module.exports = function (SocketTopics) {
|
||||
const notifyUids = await privileges.categories.filterUids('topics:read', topicData.cid, uids);
|
||||
socketHelpers.emitToUids('event:topic_moved', topicData, notifyUids);
|
||||
if (!topicData.deleted) {
|
||||
socketHelpers.sendNotificationToTopicOwner(tid, socket.uid, 'move', 'notifications:moved-your-topic');
|
||||
socketHelpers.sendNotificationToTopicOwner(tid, socket.uid, 'move', 'notifications:moved_your_topic');
|
||||
}
|
||||
|
||||
await events.log({
|
||||
|
||||
@@ -30,43 +30,43 @@ const Events = module.exports;
|
||||
Events._types = {
|
||||
pin: {
|
||||
icon: 'fa-thumb-tack',
|
||||
translation: async (event, language) => translateSimple(event, language, 'topic:user-pinned-topic'),
|
||||
translation: async event => translateSimple(event, 'topic:user-pinned-topic'),
|
||||
},
|
||||
unpin: {
|
||||
icon: 'fa-thumb-tack fa-rotate-90',
|
||||
translation: async (event, language) => translateSimple(event, language, 'topic:user-unpinned-topic'),
|
||||
translation: async event => translateSimple(event, 'topic:user-unpinned-topic'),
|
||||
},
|
||||
lock: {
|
||||
icon: 'fa-lock',
|
||||
translation: async (event, language) => translateSimple(event, language, 'topic:user-locked-topic'),
|
||||
translation: async event => translateSimple(event, 'topic:user-locked-topic'),
|
||||
},
|
||||
unlock: {
|
||||
icon: 'fa-unlock',
|
||||
translation: async (event, language) => translateSimple(event, language, 'topic:user-unlocked-topic'),
|
||||
translation: async event => translateSimple(event, 'topic:user-unlocked-topic'),
|
||||
},
|
||||
delete: {
|
||||
icon: 'fa-trash',
|
||||
translation: async (event, language) => translateSimple(event, language, 'topic:user-deleted-topic'),
|
||||
translation: async event => translateSimple(event, 'topic:user-deleted-topic'),
|
||||
},
|
||||
restore: {
|
||||
icon: 'fa-trash-o',
|
||||
translation: async (event, language) => translateSimple(event, language, 'topic:user-restored-topic'),
|
||||
translation: async event => translateSimple(event, 'topic:user-restored-topic'),
|
||||
},
|
||||
move: {
|
||||
icon: 'fa-arrow-circle-right',
|
||||
translation: async (event, language) => translateEventArgs(event, language, 'topic:user-moved-topic-from', renderUser(event), `${event.fromCategory.name}`, renderTimeago(event)),
|
||||
translation: async event => translateEventArgs(event, 'topic:user-moved-topic-from', renderUser(event), `${event.fromCategory.name}`, renderTimeago(event)),
|
||||
},
|
||||
'post-queue': {
|
||||
icon: 'fa-history',
|
||||
translation: async (event, language) => translateEventArgs(event, language, 'topic:user-queued-post', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
|
||||
translation: async event => translateEventArgs(event, 'topic:user-queued-post', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
|
||||
},
|
||||
backlink: {
|
||||
icon: 'fa-link',
|
||||
translation: async (event, language) => translateEventArgs(event, language, 'topic:user-referenced-topic', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
|
||||
translation: async event => translateEventArgs(event, 'topic:user-referenced-topic', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
|
||||
},
|
||||
fork: {
|
||||
icon: 'fa-code-fork',
|
||||
translation: async (event, language) => translateEventArgs(event, language, 'topic:user-forked-topic', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
|
||||
translation: async event => translateEventArgs(event, 'topic:user-forked-topic', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -76,14 +76,14 @@ Events.init = async () => {
|
||||
Events._types = types;
|
||||
};
|
||||
|
||||
async function translateEventArgs(event, language, prefix, ...args) {
|
||||
async function translateEventArgs(event, prefix, ...args) {
|
||||
const key = getTranslationKey(event, prefix);
|
||||
const compiled = translator.compile.apply(null, [key, ...args]);
|
||||
return utils.decodeHTMLEntities(await translator.translate(compiled, language));
|
||||
return utils.decodeHTMLEntities(await translator.translate(compiled));
|
||||
}
|
||||
|
||||
async function translateSimple(event, language, prefix) {
|
||||
return await translateEventArgs(event, language, prefix, renderUser(event), renderTimeago(event));
|
||||
async function translateSimple(event, prefix) {
|
||||
return await translateEventArgs(event, prefix, renderUser(event), renderTimeago(event));
|
||||
}
|
||||
|
||||
Events.translateSimple = translateSimple; // so plugins can perform translate
|
||||
@@ -162,10 +162,9 @@ async function modifyEvent({ tid, uid, eventIds, timestamps, events }) {
|
||||
});
|
||||
}
|
||||
|
||||
const [users, fromCategories, userSettings] = await Promise.all([
|
||||
const [users, fromCategories] = await Promise.all([
|
||||
getUserInfo(events.map(event => event.uid).filter(Boolean)),
|
||||
getCategoryInfo(events.map(event => event.fromCid).filter(Boolean)),
|
||||
user.getSettings(uid),
|
||||
]);
|
||||
|
||||
// Remove backlink events if backlinks are disabled
|
||||
@@ -201,7 +200,7 @@ async function modifyEvent({ tid, uid, eventIds, timestamps, events }) {
|
||||
|
||||
await Promise.all(events.map(async (event) => {
|
||||
if (Events._types[event.type].translation) {
|
||||
event.text = await Events._types[event.type].translation(event, userSettings.userLang);
|
||||
event.text = await Events._types[event.type].translation(event);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ module.exports = function (Topics) {
|
||||
tids = await Topics.filterWatchedTids(tids, params.uid);
|
||||
}
|
||||
} else if (params.filter === 'watched') {
|
||||
tids = await getWatchedTopics(params);
|
||||
tids = await db.getSortedSetRevRange(`uid:${params.uid}:followed_tids`, 0, -1);
|
||||
} else if (params.cids) {
|
||||
tids = await getCidTids(params);
|
||||
} else if (params.tags.length) {
|
||||
@@ -63,17 +63,6 @@ module.exports = function (Topics) {
|
||||
return tids;
|
||||
}
|
||||
|
||||
async function getWatchedTopics(params) {
|
||||
const sortSet = ['recent', 'old'].includes(params.sort) ? 'topics:recent' : `topics:${params.sort}`;
|
||||
const method = params.sort === 'old' ? 'getSortedSetIntersect' : 'getSortedSetRevIntersect';
|
||||
return await db[method]({
|
||||
sets: [sortSet, `uid:${params.uid}:followed_tids`],
|
||||
weights: [1, 0],
|
||||
start: 0,
|
||||
stop: meta.config.recentMaxTopics - 1,
|
||||
});
|
||||
}
|
||||
|
||||
async function getTagTids(params) {
|
||||
const sets = [
|
||||
params.sort === 'old' ?
|
||||
|
||||
@@ -620,6 +620,7 @@ module.exports = function (Topics) {
|
||||
const notification = await notifications.create({
|
||||
type: 'new-topic-with-tag',
|
||||
nid: `new_topic:tid:${postData.topic.tid}:uid:${exceptUid}`,
|
||||
subject: bodyShort,
|
||||
bodyShort: bodyShort,
|
||||
bodyLong: postData.content,
|
||||
pid: postData.pid,
|
||||
|
||||
@@ -210,13 +210,15 @@ module.exports = function (Topics) {
|
||||
}
|
||||
|
||||
async function getFollowedTids(params) {
|
||||
const keys = params.cid ?
|
||||
params.cid.map(cid => `cid:${cid}:tids:lastposttime`) :
|
||||
'topics:recent';
|
||||
|
||||
const recentTopicData = await db.getSortedSetRevRangeByScoreWithScores(keys, 0, -1, '+inf', params.cutoff);
|
||||
const isFollowed = await db.isSortedSetMembers(`uid:${params.uid}:followed_tids`, recentTopicData.map(t => t.tid));
|
||||
return recentTopicData.filter((t, i) => isFollowed[i]);
|
||||
let tids = await db.getSortedSetMembers(`uid:${params.uid}:followed_tids`);
|
||||
const filterCids = params.cid && params.cid.map(cid => parseInt(cid, 10));
|
||||
if (filterCids) {
|
||||
const topicData = await Topics.getTopicsFields(tids, ['tid', 'cid']);
|
||||
tids = topicData.filter(t => filterCids.includes(t.cid)).map(t => t.tid);
|
||||
}
|
||||
const scores = await db.sortedSetScores('topics:recent', tids);
|
||||
const data = tids.map((tid, index) => ({ value: String(tid), score: scores[index] }));
|
||||
return data.filter(item => item.score > params.cutoff);
|
||||
}
|
||||
|
||||
async function filterTidsThatHaveBlockedPosts(params) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="px-lg-4 digest">
|
||||
<div class="px-lg-4">
|
||||
<p class="lead">[[admin/manage/digest:lead]]</p>
|
||||
<p>[[admin/manage/digest:disclaimer]]</p>
|
||||
<p>[[admin/manage/digest:disclaimer-continued]]</p>
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-2"><em>[[admin/manage/digest:default-help, {default}]]</em></div>
|
||||
<div class="d-flex gap-1 align-items-center">
|
||||
<div class="d-flex gap-1">
|
||||
<div>[[admin/manage/digest:manual-run]]</div>
|
||||
<button class="btn btn-sm btn-outline-secondary" data-action="resend-day">[[admin/settings/user:digest-freq.daily]]</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" data-action="resend-week">[[admin/settings/user:digest-freq.weekly]]</button>
|
||||
|
||||
@@ -1 +1 @@
|
||||
data-index="{posts.index}" data-pid="{posts.pid}" data-uid="{posts.uid}" data-timestamp="{posts.timestamp}" data-username="{posts.user.username}" data-userslug="{posts.user.userslug}"{{{ if posts.allowDupe }}} data-allow-dupe="1"{{{ end }}}{{{ if posts.navigatorIgnore }}} data-navigator-ignore="1"{{{ end }}} itemprop="comment" itemtype="http://schema.org/Comment" itemscope
|
||||
data-index="{posts.index}" data-pid="{posts.pid}" data-uid="{posts.uid}" data-timestamp="{posts.timestamp}" data-username="{posts.user.username}" data-userslug="{posts.user.userslug}"{{{ if posts.allowDupe }}} data-allow-dupe="1"{{{ end }}}{{{ if posts.navigatorIgnore }}} data-navigator-ignore="1"{{{ end }}} itemscope itemtype="http://schema.org/Comment"
|
||||
10
test/api.js
10
test/api.js
@@ -493,13 +493,13 @@ describe('API', async () => {
|
||||
|
||||
try {
|
||||
if (type === 'json') {
|
||||
const searchParams = new URLSearchParams(qs);
|
||||
result = await request[method](`${url}?${searchParams}`, {
|
||||
result = await request[method](url, {
|
||||
jar: !unauthenticatedRoutes.includes(path) ? jar : undefined,
|
||||
maxRedirect: 0,
|
||||
redirect: 'manual',
|
||||
maxRedirects: 0,
|
||||
validateStatus: null, // don't throw on non-200 (e.g. 302)
|
||||
headers: headers,
|
||||
body: body,
|
||||
params: qs,
|
||||
data: body,
|
||||
});
|
||||
} else if (type === 'form') {
|
||||
result = await helpers.uploadFile(url, pathLib.join(__dirname, './files/test.png'), {}, jar, csrfToken);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user