mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-24 09:20:32 +01:00
Compare commits
215 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
624738359a | ||
|
|
15c3abb6d5 | ||
|
|
7ead74fe9b | ||
|
|
cbbdc79357 | ||
|
|
e0d5f92b2a | ||
|
|
8228eeb468 | ||
|
|
fc09f6c4f9 | ||
|
|
7a26672872 | ||
|
|
de820ae198 | ||
|
|
961a193787 | ||
|
|
4ab31e3f79 | ||
|
|
338f89deb5 | ||
|
|
dc14d6a8d1 | ||
|
|
fb43f9ae10 | ||
|
|
638e098f30 | ||
|
|
2514aace4e | ||
|
|
9ec7ab4afc | ||
|
|
dd5ed9e507 | ||
|
|
8bc8cf1ba0 | ||
|
|
62e162cf1e | ||
|
|
a5d92da9dd | ||
|
|
2bd6eea2fa | ||
|
|
42b9fbc91c | ||
|
|
5c0bf7ccbe | ||
|
|
30b6bcfca1 | ||
|
|
de2669a2c6 | ||
|
|
21fb8590e5 | ||
|
|
c931183287 | ||
|
|
ae5afdbc66 | ||
|
|
5343d2a01b | ||
|
|
2ec81eff43 | ||
|
|
f2ca93f6c6 | ||
|
|
82f0efb14b | ||
|
|
df08b47163 | ||
|
|
c27567289f | ||
|
|
c33730530e | ||
|
|
67055006df | ||
|
|
e0b2065802 | ||
|
|
4d2d76897a | ||
|
|
7397873db3 | ||
|
|
5b7c3671c8 | ||
|
|
188ec62f9a | ||
|
|
48c1c7594d | ||
|
|
73ff25887c | ||
|
|
830f142b7a | ||
|
|
1aff9cad91 | ||
|
|
37b48b82a4 | ||
|
|
e9a8e19508 | ||
|
|
894f392bfc | ||
|
|
c2961ad4cd | ||
|
|
57f14e419f | ||
|
|
18b2150edd | ||
|
|
fb100ac731 | ||
|
|
bb725987b3 | ||
|
|
73a50d1718 | ||
|
|
93aa43f717 | ||
|
|
9ed6961af8 | ||
|
|
4b94c033c4 | ||
|
|
9e685e657a | ||
|
|
767c1d1faf | ||
|
|
a3a38e4ba3 | ||
|
|
cfd5027245 | ||
|
|
56427e4f9d | ||
|
|
b331b9423b | ||
|
|
c03d5db71e | ||
|
|
f5a59991fc | ||
|
|
e45a6de24b | ||
|
|
22fc8fe38f | ||
|
|
17d0b40efa | ||
|
|
1545223e7f | ||
|
|
f054a4f44d | ||
|
|
8c762d3228 | ||
|
|
3f8248d673 | ||
|
|
2ca38e7b95 | ||
|
|
6976925943 | ||
|
|
f4282c091b | ||
|
|
791551098c | ||
|
|
ec58700f6d | ||
|
|
8cf4a6f62e | ||
|
|
3bd9a87154 | ||
|
|
edd2fc38fc | ||
|
|
1b29dbb69d | ||
|
|
40e7b86da9 | ||
|
|
326b92687f | ||
|
|
e335d0f601 | ||
|
|
845c8013b6 | ||
|
|
7a5bcc2171 | ||
|
|
af6ce44737 | ||
|
|
f3306d038a | ||
|
|
76732140f3 | ||
|
|
c6681a1725 | ||
|
|
bf92ee0e5f | ||
|
|
8335f90ae0 | ||
|
|
202378b939 | ||
|
|
705cd13ad3 | ||
|
|
b5598a6e5d | ||
|
|
c241baf641 | ||
|
|
d68352cce5 | ||
|
|
0713482bd4 | ||
|
|
1d3c0e5a2b | ||
|
|
6d819b056e | ||
|
|
bff5ce2d79 | ||
|
|
24e58c2895 | ||
|
|
93ccf604db | ||
|
|
4821b21e81 | ||
|
|
f6c96948fe | ||
|
|
a46b2bbc45 | ||
|
|
c13f0e2128 | ||
|
|
b9553613ab | ||
|
|
ce924eca0d | ||
|
|
c3653bee60 | ||
|
|
c20b20a7aa | ||
|
|
eb2841eed3 | ||
|
|
4c46ff42f6 | ||
|
|
82eb55d77d | ||
|
|
89e059a084 | ||
|
|
fecd84d1a0 | ||
|
|
00e48803a6 | ||
|
|
a788bd1344 | ||
|
|
9f38692369 | ||
|
|
0bffd3d93c | ||
|
|
9c250b78b0 | ||
|
|
7d04e95226 | ||
|
|
f295174e07 | ||
|
|
459bc52338 | ||
|
|
39e009c05a | ||
|
|
747cb1f0a1 | ||
|
|
48c9f4470f | ||
|
|
050e43f8b4 | ||
|
|
66aa31698f | ||
|
|
1d5eff2365 | ||
|
|
9b6dad367d | ||
|
|
25ae58e8a0 | ||
|
|
727f879e5b | ||
|
|
d17d4ec09b | ||
|
|
96bdbf52b8 | ||
|
|
fe662f3a46 | ||
|
|
8a69e740a8 | ||
|
|
586eed1407 | ||
|
|
1ea9481af6 | ||
|
|
bbaf26cedc | ||
|
|
8e77673d39 | ||
|
|
a5c2edb993 | ||
|
|
7ce758d698 | ||
|
|
3f950d5162 | ||
|
|
ef500af8e6 | ||
|
|
7ab46b784a | ||
|
|
13a3faa0d1 | ||
|
|
eb6a9c474a | ||
|
|
05443dbeee | ||
|
|
485ee1301b | ||
|
|
18ff6caadd | ||
|
|
c4cc1e61df | ||
|
|
faaf09f71c | ||
|
|
cde44587c1 | ||
|
|
5dda9a5bf1 | ||
|
|
0a5adb416a | ||
|
|
de31cb1a4f | ||
|
|
9f531f957e | ||
|
|
8b209f16d1 | ||
|
|
7bcfe38e60 | ||
|
|
7b9bbef593 | ||
|
|
7b48156cc0 | ||
|
|
65ef722e82 | ||
|
|
3e8f537830 | ||
|
|
4f67fc1ad0 | ||
|
|
22493ffb4c | ||
|
|
717b36129e | ||
|
|
896493dbd6 | ||
|
|
4314b8e201 | ||
|
|
4f4b48000a | ||
|
|
2bc23a9526 | ||
|
|
33af2d9c18 | ||
|
|
06f4801e57 | ||
|
|
e213dbc3b7 | ||
|
|
96cc0617c5 | ||
|
|
4701c96d9c | ||
|
|
ccf8739344 | ||
|
|
7e52a7a574 | ||
|
|
21d9806ca9 | ||
|
|
e7fcf482f3 | ||
|
|
d80c80b618 | ||
|
|
dec0e7deac | ||
|
|
c7ff98a12d | ||
|
|
5836bf4a05 | ||
|
|
a5357812c6 | ||
|
|
c7bd7dbfe6 | ||
|
|
ec4dadabd4 | ||
|
|
3509ed9461 | ||
|
|
cb8d94563a | ||
|
|
e83260ca28 | ||
|
|
4bf1ce42e6 | ||
|
|
7e922936d0 | ||
|
|
3c8ce70c74 | ||
|
|
babcd17e6c | ||
|
|
ec6ffaad4e | ||
|
|
ce3aa95053 | ||
|
|
7aab01d87a | ||
|
|
01d276cbee | ||
|
|
9758b7af2c | ||
|
|
dd3e1a2861 | ||
|
|
2a97342035 | ||
|
|
d5525c873b | ||
|
|
e7c3634f9a | ||
|
|
9c647c6ce2 | ||
|
|
52fc05edfe | ||
|
|
3aa7b8552a | ||
|
|
36523c67b8 | ||
|
|
60cbd1480d | ||
|
|
f3e59508ae | ||
|
|
4834cde335 | ||
|
|
01da76e1dc | ||
|
|
d2425942a6 | ||
|
|
8d7475be7b | ||
|
|
046ea12022 |
10
.github/workflows/docker.yml
vendored
10
.github/workflows/docker.yml
vendored
@@ -13,13 +13,14 @@ on:
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -32,14 +33,15 @@ jobs:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: nodebb/docker
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
|
||||
293
CHANGELOG.md
293
CHANGELOG.md
@@ -1,3 +1,296 @@
|
||||
#### v2.8.11 (2023-04-11)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.10 (5b7c3671)
|
||||
* update changelog for v2.8.10 (188ec62f)
|
||||
|
||||
##### Continuous Integration
|
||||
|
||||
* publish to ghcr instead of docker hub (c2756728)
|
||||
|
||||
##### Documentation Changes
|
||||
|
||||
* update readme with new screenshot and updated copy for Harmony (67055006)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* don't crash on objects with toString property (4d2d7689)
|
||||
* fire action:user.online on user login (7397873d)
|
||||
|
||||
##### Tests
|
||||
|
||||
* update socket.io test (e0b20658)
|
||||
|
||||
#### v2.8.10 (2023-03-27)
|
||||
|
||||
##### Chores
|
||||
|
||||
* up composer-default (e9a8e195)
|
||||
* incrementing version number - v2.8.9 (57f14e41)
|
||||
* update changelog for v2.8.9 (18b2150e)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* #11403, remove loader.js crash counter logic (830f142b)
|
||||
* don't crash if event name is not a string (37b48b82)
|
||||
* closes #11173, move cache clear code (c2961ad4)
|
||||
|
||||
##### Other Changes
|
||||
|
||||
* fix arrow (1aff9cad)
|
||||
* whitespace (894f392b)
|
||||
|
||||
#### v2.8.9 (2023-03-19)
|
||||
|
||||
##### Chores
|
||||
|
||||
* up cron (73a50d17)
|
||||
* incrementing version number - v2.8.8 (b331b942)
|
||||
* update changelog for v2.8.8 (c03d5db7)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* thumb remove on windows, closes #11357 (767c1d1f)
|
||||
* #11357 clear cache on thumb remove (a3a38e4b)
|
||||
* closes #11352, try/catch rss feeds (cfd50272)
|
||||
* closes #11343, don't crash if tags array is empty (56427e4f)
|
||||
|
||||
##### Code Style Changes
|
||||
|
||||
* more fixes (93aa43f7)
|
||||
|
||||
##### Tests
|
||||
|
||||
* openapi for thumbs (9e685e65)
|
||||
|
||||
#### v2.8.8 (2023-03-09)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.7 (3f8248d6)
|
||||
* update changelog for v2.8.7 (2ca38e7b)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* stop topic navigation hotkeys from firing if in a mousetrap-enabled form element (22fc8fe3)
|
||||
* stop topic navigation hotkeys from firing if in a mousetrap-enabled form element (17d0b40e)
|
||||
* tag filtering when changing filter to watched topics (1545223e)
|
||||
* get cid from pid instead of passing in (f054a4f4)
|
||||
* closes #11331, allow 0 length content if set to 0 in acp (8c762d32)
|
||||
|
||||
#### v2.8.7 (2023-03-01)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.6 (af6ce447)
|
||||
* update changelog for v2.8.6 (f3306d03)
|
||||
|
||||
##### Documentation Changes
|
||||
|
||||
* update openapi spec to include info about passing in timestamps for topic creation, removing timestamp as valid request param for topic replying (40e7b86d)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* display 25 topics on category feed (79155109)
|
||||
* object destructuring overwriting type parameter (ec58700f)
|
||||
* alert on page load (8cf4a6f6)
|
||||
* show error alert if password change fails (3bd9a871)
|
||||
* update main post timestamp when rescheduling (edd2fc38)
|
||||
* show admins/globalmods if content is purged (326b9268)
|
||||
* email expiry timestamps (e335d0f6)
|
||||
* #11259, clean old emails when updating via admin (#11260) (845c8013)
|
||||
* #11257, onSuccessfulLogin called with improper uid (7a5bcc21)
|
||||
|
||||
##### Tests
|
||||
|
||||
* add dummy emailer hook in authentication test (1b29dbb6)
|
||||
|
||||
#### v2.8.6 (2023-02-03)
|
||||
|
||||
##### Chores
|
||||
|
||||
* **i18n:** fallback strings for new resources: nodebb.error (8335f90a)
|
||||
* incrementing version number - v2.8.5 (bff5ce2d)
|
||||
* update changelog for v2.8.5 (24e58c28)
|
||||
|
||||
##### New Features
|
||||
|
||||
* add sitemap filter hooks for categories/topic pages (bf92ee0e)
|
||||
* closes #11241, add missing error lang keys (c241baf6)
|
||||
* #11240, only show relevant users in flags assignee list (0713482b)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* #11254, return check for reroll property (202378b9)
|
||||
* closes #11249, notification uses displayname (705cd13a)
|
||||
* wrong link to topics in acp dashboard (b5598a6e)
|
||||
* https://github.com/NodeBB/NodeBB/issues/11239 (1d3c0e5a)
|
||||
* notif filter selecte field (6d819b05)
|
||||
|
||||
##### Other Changes
|
||||
|
||||
* remove unused (d68352cc)
|
||||
|
||||
#### v2.8.5 (2023-01-27)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.4 (a46b2bbc)
|
||||
* update changelog for v2.8.4 (c13f0e21)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* import resolution within plugin modules (#11219) (f6c96948)
|
||||
|
||||
#### v2.8.4 (2023-01-26)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.3 (c20b20a7)
|
||||
* update changelog for v2.8.3 (eb2841ee)
|
||||
|
||||
#### v2.8.3 (2023-01-25)
|
||||
|
||||
##### Chores
|
||||
|
||||
* remove extraneous lines from changelog (48c9f447)
|
||||
* incrementing version number - v2.8.2 (050e43f8)
|
||||
* update changelog for v2.8.2 (66aa3169)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* import resolution within plugin modules (#11200) (89e059a0)
|
||||
* #11195, allow users with admin:users privilege to delete users in acp (0bffd3d9)
|
||||
* #11194, allow access to sub dashboard pages (7d04e952)
|
||||
* #11136, tests, and returning the proper number of arrays (459bc523)
|
||||
* #11136, only show mods of active categories when getModeratorUids is called (39e009c0)
|
||||
* closes #11173, clear require cache if wrong dependency is installed (747cb1f0)
|
||||
* **deps:**
|
||||
* downgrade swagger-parser to v9 (00e48803)
|
||||
* pinning sub dependency json-schema-ref-parser to 9.0.9 (9c250b78)
|
||||
|
||||
##### Reverts
|
||||
|
||||
* a788bd1344825ad4759e39d6e98d8bf3695bd639 (fecd84d1)
|
||||
* 9c250b78b05ca2abf31a79971ed0c60ca07664ec, fix: comment out broken test for now (a788bd13)
|
||||
|
||||
##### Tests
|
||||
|
||||
* fix broken test (f295174e)
|
||||
|
||||
#### v2.8.2 (2023-01-13)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.1 (727f879e)
|
||||
* update changelog for v2.8.1 (d17d4ec0)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* move call to `filter:middleware.buildHeader` out of parallel so that req can be overridden by plugins prior to loading config (25ae58e8)
|
||||
|
||||
#### v2.8.1 (2022-12-30)
|
||||
|
||||
##### Chores
|
||||
|
||||
* fallbacks for new language string (8a69e740)
|
||||
* remove extraneous lines from changelog (bbaf26ce)
|
||||
* incrementing version number - v2.8.0 (8e77673d)
|
||||
* update changelog for v2.8.0 (a5c2edb9)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* vulnerability in socket.io nested namespaces (#11117) (586eed14)
|
||||
* lock post/reply similar to user.create (1ea9481a)
|
||||
|
||||
#### v2.8.0 (2022-12-21)
|
||||
|
||||
##### Chores
|
||||
|
||||
* **deps:**
|
||||
* update dependency jquery to v3.6.3 (#11107) (13a3faa0)
|
||||
* update dependency eslint to v8.30.0 (#11102) (485ee130)
|
||||
* update dependency mocha to v10.2.0 (#11094) (c4cc1e61)
|
||||
* up jquery (3e8f5378)
|
||||
* remove extraneous lines from changelog (e213dbc3)
|
||||
* incrementing version number - v2.7.0 (96cc0617)
|
||||
* update changelog for v2.7.0 (4701c96d)
|
||||
* **i18n:**
|
||||
* fallback strings for new resources: nodebb.admin-settings-email (717b3612)
|
||||
* fallback strings for new resources: nodebb.admin-settings-email (4f4b4800)
|
||||
|
||||
##### New Features
|
||||
|
||||
* add force flag to plugin install in cli (#11089) (de31cb1a)
|
||||
* integrating basic client-side form validity checking in settings v1 and v2 (33af2d9c)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* **deps:**
|
||||
* update dependency sharp to v0.31.3 (#11110) (ef500af8)
|
||||
* update dependency sanitize-html to v2.8.1 (#11109) (7ab46b78)
|
||||
* update dependency esbuild to v0.16.10 (#11104) (eb6a9c47)
|
||||
* update dependency mongodb to v4.13.0 (#11105) (05443dbe)
|
||||
* update dependency esbuild to v0.16.8 (#11101) (18ff6caa)
|
||||
* update dependency sanitize-html to v2.8.0 (#11098) (faaf09f7)
|
||||
* update dependency ace-builds to v1.14.0 (#11095) (cde44587)
|
||||
* update dependency nodebb-plugin-2factor to v5.1.2 (#11096) (5dda9a5b)
|
||||
* update dependency postcss to v8.4.20 (#11097) (0a5adb41)
|
||||
* update dependency compare-versions to v5.0.3 (#11092) (8b209f16)
|
||||
* update dependency html-to-text to v9.0.3 (#11093) (7bcfe38e)
|
||||
* update dependency @socket.io/redis-adapter to v8 (#11084) (7b9bbef5)
|
||||
* update dependency nodebb-widget-essentials to v6.0.1 (#11085) (7b48156c)
|
||||
* update dependency esbuild to v0.16.7 (#11086) (65ef722e)
|
||||
* update dependency esbuild to v0.16.3 (#11083) (4f67fc1a)
|
||||
* update dependency esbuild to v0.15.16 (#11069) (22493ffb)
|
||||
* change hsts-maxage back to numeric input type, change API token uid input to numeric text type (896493db)
|
||||
* replace input type number with text/pattern (2bc23a95)
|
||||
|
||||
##### Refactors
|
||||
|
||||
* flag states so that they are not hardcoded, allow plugins to add additional states, deprecated filter:flags.getFilters hook, closes #11065 (9f531f95)
|
||||
* remove debug log closes #11090 (06f4801e)
|
||||
|
||||
#### v2.7.0 (2022-12-14)
|
||||
|
||||
##### Chores
|
||||
|
||||
* added stub file in hy (9ee8502d)
|
||||
* **deps:**
|
||||
* update dependency lint-staged to v13.1.0 (#11082) (693d4783)
|
||||
* update dependency eslint to v8.29.0 (#11074) (eab5b754)
|
||||
* update dependency lint-staged to v13.0.4 (#11064) (f947ac6d)
|
||||
* **i18n:**
|
||||
* fallback strings for new resources: nodebb.admin-settings-email (0e319a58)
|
||||
* fallback strings for new resources: nodebb.admin-settings-email (9676b192)
|
||||
|
||||
##### New Features
|
||||
|
||||
* update transifex config (for use with new cli) (f11094cb)
|
||||
* integrating basic client-side form validity checking in settings v1 and v2 (dadbcd73)
|
||||
* add ./nodebb install <plugin_name> (4efc19d5)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* **deps:**
|
||||
* update dependency nodebb-theme-lavender to v6.0.1 (#11081) (df3f1c5e)
|
||||
* update dependency esbuild to v0.16.3 (#11083) (85d38158)
|
||||
* update dependency html-to-text to v9 (#11075) (d8e9738d)
|
||||
* update dependency ace-builds to v1.13.2 (#11080) (35be4594)
|
||||
* update dependency fs-extra to v11 (#11072) (aafb7f6e)
|
||||
* update dependency esbuild to v0.15.16 (#11069) (7bc4b836)
|
||||
* update dependency mongodb to v4.12.1 (#11062) (e14d4abc)
|
||||
* relax selectors for client-side form validation so that all form elements are checked (43e7c988)
|
||||
* change hsts-maxage back to numeric input type, change API token uid input to numeric text type (db8d3a94)
|
||||
* replace input type number with text/pattern (45ae31f8)
|
||||
* categories.js not showing custom privileges (#10856) (8c4d6bbe)
|
||||
* #11077, add admin uploads paths to priv mapping (07a02125)
|
||||
|
||||
##### Tests
|
||||
|
||||
* dont try to load admin upload routes (c2bb2b30)
|
||||
|
||||
#### v2.6.1 (2022-11-28)
|
||||
|
||||
##### Chores
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "2.7.0",
|
||||
"version": "2.8.20",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -30,7 +30,7 @@
|
||||
"dependencies": {
|
||||
"@adactive/bootstrap-tagsinput": "0.8.2",
|
||||
"@isaacs/ttlcache": "1.2.1",
|
||||
"ace-builds": "1.13.2",
|
||||
"ace-builds": "1.14.0",
|
||||
"archiver": "5.3.1",
|
||||
"async": "3.2.4",
|
||||
"autoprefixer": "10.4.13",
|
||||
@@ -45,7 +45,7 @@
|
||||
"clipboard": "2.0.11",
|
||||
"colors": "1.4.0",
|
||||
"commander": "9.4.1",
|
||||
"compare-versions": "5.0.1",
|
||||
"compare-versions": "5.0.3",
|
||||
"compression": "1.7.4",
|
||||
"connect-flash": "0.1.1",
|
||||
"connect-mongo": "4.6.0",
|
||||
@@ -53,12 +53,12 @@
|
||||
"connect-pg-simple": "8.0.0",
|
||||
"connect-redis": "6.1.3",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cron": "2.1.0",
|
||||
"cron": "2.3.0",
|
||||
"cropperjs": "1.5.13",
|
||||
"csurf": "1.11.0",
|
||||
"csrf-sync": "4.0.1",
|
||||
"daemon": "1.1.0",
|
||||
"diff": "5.1.0",
|
||||
"esbuild": "0.16.3",
|
||||
"esbuild": "0.16.10",
|
||||
"express": "4.18.2",
|
||||
"express-session": "1.17.3",
|
||||
"express-useragent": "1.0.15",
|
||||
@@ -66,9 +66,9 @@
|
||||
"fs-extra": "11.1.0",
|
||||
"graceful-fs": "4.2.10",
|
||||
"helmet": "5.1.1",
|
||||
"html-to-text": "9.0.2",
|
||||
"html-to-text": "9.0.3",
|
||||
"ipaddr.js": "2.0.1",
|
||||
"jquery": "3.6.1",
|
||||
"jquery": "3.6.3",
|
||||
"jquery-deserialize": "2.0.0",
|
||||
"jquery-form": "4.3.0",
|
||||
"jquery-serializeobject": "1.0.0",
|
||||
@@ -83,14 +83,14 @@
|
||||
"material-design-lite": "1.3.0",
|
||||
"mime": "3.0.0",
|
||||
"mkdirp": "1.0.4",
|
||||
"mongodb": "4.12.1",
|
||||
"mongodb": "4.13.0",
|
||||
"morgan": "1.10.0",
|
||||
"mousetrap": "1.6.5",
|
||||
"multiparty": "4.2.3",
|
||||
"@nodebb/bootswatch": "3.4.2",
|
||||
"nconf": "0.12.0",
|
||||
"nodebb-plugin-2factor": "5.1.1",
|
||||
"nodebb-plugin-composer-default": "9.2.4",
|
||||
"nodebb-plugin-2factor": "5.1.2",
|
||||
"nodebb-plugin-composer-default": "9.2.6",
|
||||
"nodebb-plugin-dbsearch": "5.1.5",
|
||||
"nodebb-plugin-emoji": "4.0.6",
|
||||
"nodebb-plugin-emoji-android": "3.0.0",
|
||||
@@ -99,10 +99,10 @@
|
||||
"nodebb-plugin-spam-be-gone": "1.0.2",
|
||||
"nodebb-rewards-essentials": "0.2.1",
|
||||
"nodebb-theme-lavender": "6.0.1",
|
||||
"nodebb-theme-persona": "12.1.12",
|
||||
"nodebb-theme-persona": "12.1.18",
|
||||
"nodebb-theme-slick": "2.0.2",
|
||||
"nodebb-theme-vanilla": "12.1.19",
|
||||
"nodebb-widget-essentials": "6.0.0",
|
||||
"nodebb-widget-essentials": "6.0.1",
|
||||
"nodemailer": "6.8.0",
|
||||
"nprogress": "0.2.0",
|
||||
"passport": "0.6.0",
|
||||
@@ -110,7 +110,7 @@
|
||||
"passport-local": "1.0.0",
|
||||
"pg": "8.8.0",
|
||||
"pg-cursor": "2.7.4",
|
||||
"postcss": "8.4.19",
|
||||
"postcss": "8.4.20",
|
||||
"postcss-clean": "1.2.0",
|
||||
"progress-webpack-plugin": "1.0.16",
|
||||
"prompt": "1.3.0",
|
||||
@@ -119,15 +119,15 @@
|
||||
"request-promise-native": "1.0.9",
|
||||
"rimraf": "3.0.2",
|
||||
"rss": "1.2.2",
|
||||
"sanitize-html": "2.7.3",
|
||||
"sanitize-html": "2.8.1",
|
||||
"semver": "7.3.8",
|
||||
"serve-favicon": "2.5.0",
|
||||
"sharp": "0.31.2",
|
||||
"sharp": "0.31.3",
|
||||
"sitemap": "7.1.1",
|
||||
"slideout": "1.0.1",
|
||||
"socket.io": "4.5.4",
|
||||
"socket.io-client": "4.5.4",
|
||||
"@socket.io/redis-adapter": "7.2.0",
|
||||
"@socket.io/redis-adapter": "8.0.0",
|
||||
"sortablejs": "1.15.0",
|
||||
"spdx-license-list": "6.6.0",
|
||||
"spider-detector": "2.0.0",
|
||||
@@ -148,11 +148,11 @@
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@apidevtools/swagger-parser": "9.0.0",
|
||||
"@commitlint/cli": "17.3.0",
|
||||
"@commitlint/config-angular": "17.3.0",
|
||||
"coveralls": "3.1.1",
|
||||
"eslint": "8.29.0",
|
||||
"eslint": "8.30.0",
|
||||
"eslint-config-nodebb": "0.2.1",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"grunt": "1.5.3",
|
||||
@@ -160,14 +160,14 @@
|
||||
"husky": "8.0.2",
|
||||
"jsdom": "20.0.3",
|
||||
"lint-staged": "13.1.0",
|
||||
"mocha": "10.1.0",
|
||||
"mocha": "10.2.0",
|
||||
"mocha-lcov-reporter": "1.3.0",
|
||||
"mockdate": "3.0.5",
|
||||
"nyc": "15.1.0",
|
||||
"smtp-server": "3.11.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"*/jquery": "3.6.1"
|
||||
"*/jquery": "3.6.3"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/NodeBB/NodeBB/issues"
|
||||
@@ -192,4 +192,4 @@
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
19
loader.js
19
loader.js
@@ -30,9 +30,7 @@ const output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compres
|
||||
const silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false;
|
||||
let numProcs;
|
||||
const workers = [];
|
||||
const Loader = {
|
||||
timesStarted: 0,
|
||||
};
|
||||
const Loader = {};
|
||||
const appPath = path.join(__dirname, 'app.js');
|
||||
|
||||
Loader.init = function () {
|
||||
@@ -57,21 +55,6 @@ Loader.displayStartupMessages = function () {
|
||||
|
||||
Loader.addWorkerEvents = function (worker) {
|
||||
worker.on('exit', (code, signal) => {
|
||||
if (code !== 0) {
|
||||
if (Loader.timesStarted < numProcs * 3) {
|
||||
Loader.timesStarted += 1;
|
||||
if (Loader.crashTimer) {
|
||||
clearTimeout(Loader.crashTimer);
|
||||
}
|
||||
Loader.crashTimer = setTimeout(() => {
|
||||
Loader.timesStarted = 0;
|
||||
}, 10000);
|
||||
} else {
|
||||
console.log(`${numProcs * 3} restarts in 10 seconds, most likely an error on startup. Halting.`);
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[cluster] Child Process (${worker.pid}) has exited (code: ${code}, signal: ${signal})`);
|
||||
if (!(worker.suicide || code === 0)) {
|
||||
console.log('[cluster] Spinning up another process...');
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "اسم مستخدم غير موجود",
|
||||
"no-teaser": "مقتطف غير موجود",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "لاتملك الصلاحيات اللازمة للقيام بهذه العملية",
|
||||
"category-disabled": "قائمة معطلة",
|
||||
"topic-locked": "الموضوع مقفول",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "يسمح لك بالنشر مرة كل %1 ثانية - يرجى الإنتظار قبل النشر مجدداً",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "لقد شاركت بالتصويت ، ألا تذكر؟",
|
||||
"reputation-system-disabled": "نظام السمعة معطل",
|
||||
"downvoting-disabled": "التصويتات السلبية معطلة",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Потребителят не съществува",
|
||||
"no-teaser": "Резюмето не съществува",
|
||||
"no-flag": "Докладът не съществува",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Нямате достатъчно права за това действие.",
|
||||
"category-disabled": "Категорията е изключена",
|
||||
"topic-locked": "Темата е заключена",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Не е избрана категория.",
|
||||
"too-many-posts": "Можете да публикувате веднъж на %1 секунда/и – моля, изчакайте малко, преди да опитате да публикувате отново",
|
||||
"too-many-posts-newbie": "Като нов потребител, Вие можете да публикувате веднъж на %1 секунда/и, докато не натрупате %2 репутация – моля, изчакайте малко, преди да опитате да публикувате отново",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Моля, въведете по-дълъг етикет. Етикетите трябва да съдържат поне %1 символ(а)",
|
||||
"tag-too-long": "Моля, въведете по-кратък етикет. Етикетите трябва да съдържат не повече от %1 символ(а)",
|
||||
"not-enough-tags": "Недостатъчно етикети. Темите трябва да имат поне %1 етикет(а)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Това съобщение вече е изтрито.",
|
||||
"chat-restored-already": "Това съобщение вече е възстановено.",
|
||||
"chat-room-does-not-exist": "Стаята за разговори не съществува.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Вече сте дали глас за тази публикация.",
|
||||
"reputation-system-disabled": "Системата за репутация е изключена.",
|
||||
"downvoting-disabled": "Отрицателното гласуване е изключено",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "এই নামে কোন সদস্য নেই",
|
||||
"no-teaser": "টিজারটি খুজে পাওয়া যায় নি",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "এই কাজটির জন্য আপনার পর্যাপ্ত অধিকার নেই",
|
||||
"category-disabled": "বিভাগটি নিষ্ক্রিয়",
|
||||
"topic-locked": "টপিক বন্ধ",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "সম্মাননা ব্যাবস্থা নিস্ক্রীয় রাখা হয়েছে",
|
||||
"downvoting-disabled": "ঋণাত্মক ভোট নিস্ক্রীয় রাখা হয়েছে।",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Uživatel neexistuje",
|
||||
"no-teaser": "Chyták neexistuje",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Na tuto akci nemáte dostatečné oprávnění.",
|
||||
"category-disabled": "Kategorie zakázána",
|
||||
"topic-locked": "Téma uzamknuto",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Nebyla vybrána kategorie.",
|
||||
"too-many-posts": "Můžete přispívat jednou za %1 sekund - vyčkejte tedy, než vytvoříte další příspěvek",
|
||||
"too-many-posts-newbie": "Jako nový uživatel, můžete přispívat jednou za %1 sekund, dokud nezískáte pověst %2 - vyčkejte tedy, než vytvoříte další příspěvek",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Zadejte delší značku. Značky by měli mít alespoň %1 znaků",
|
||||
"tag-too-long": "Zadejte kratší značku. Značky nesmí být delší než %1 znaků",
|
||||
"not-enough-tags": "Málo značek. Téma musí obsahovat alespoň %1 značek",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Tato konverzační zpráva již byla odstraněna.",
|
||||
"chat-restored-already": "Tato konverzační zpráva již byla obnovena.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Již jste v tomto příspěvku hlasoval.",
|
||||
"reputation-system-disabled": "Systém reputací je zakázán.",
|
||||
"downvoting-disabled": "Systém nesouhlasu je zakázán",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Brugeren eksisterer ikke",
|
||||
"no-teaser": "Teaser eksisterer ikke",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Du har ikke nok rettigheder til at udføre denne handling",
|
||||
"category-disabled": "Kategorien er deaktiveret",
|
||||
"topic-locked": "Tråden er låst",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "Du kan højest skrive et indlæg hver %1 sekund(er) - venligst vent et øjeblik før næste indlæg",
|
||||
"too-many-posts-newbie": "Som ny bruger kan du kun skrive et indlæg engang hvert %1. sekund() indtil du har optjent %2 omdømme point - venligst vent et øjeblik før næste indlæg.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Indtast et længere tag. Tags skal indeholde mindst %1 karakter(er).",
|
||||
"tag-too-long": "Indtast et længere tag. Tags kan ikke være længere end %1 karakter(er).",
|
||||
"not-enough-tags": "Ikke nok tags. Tråde skal have mindst %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Vurderingssystem er slået fra.",
|
||||
"downvoting-disabled": "Nedvurdering er slået fra",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Der Benutzer existiert nicht",
|
||||
"no-teaser": "Zusammenfassung existiert nicht",
|
||||
"no-flag": "Markierung existiert nicht",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Du verfügst nicht über ausreichende Berechtigungen, um die Aktion durchzuführen.",
|
||||
"category-disabled": "Kategorie ist deaktiviert",
|
||||
"topic-locked": "Thema ist gesperrt",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategorie nicht ausgewählt",
|
||||
"too-many-posts": "Du kannst nur einen Beitrag innerhalb von %1 Sekunden erstellen - Bitte warte bevor Du erneut einen Beitrag erstellst.",
|
||||
"too-many-posts-newbie": "Als neuer Benutzer kannst du nur einmal alle %1 Sekunde(n) posten, bis du %2 Reputation erworben hast - bitte warte, bevor du erneut postest",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Bitte gebe ein längeres Schlagwort ein. Schlagworte sollten mindestens %1 Zeichen enthalten.",
|
||||
"tag-too-long": "Bitte gebe ein kürzeres Schlagwort ein. Schlagworte können nicht länger als %1 Zeichen sein.",
|
||||
"not-enough-tags": "Nicht genügend Schlagworte. Themen müssen mindestens %1 Schlagwort(e) enthalten",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Diese Chatnachricht wurde bereits gelöscht.",
|
||||
"chat-restored-already": "Diese Chatnachricht wurde bereits wiederhergestellt.",
|
||||
"chat-room-does-not-exist": "Der Chatraum existiert nicht.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Du hast diesen Beitrag bereits bewertet.",
|
||||
"reputation-system-disabled": "Das Reputationssystem ist deaktiviert.",
|
||||
"downvoting-disabled": "Downvotes sind deaktiviert.",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "User does not exist",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "You do not have enough privileges for this action.",
|
||||
"category-disabled": "Η κατηγορία έχει απενεργοποιηθεί",
|
||||
"topic-locked": "Το θέμα έχει κλειδωθεί",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Το σύστημα φήμης έχει απενεργοποιηθεί.",
|
||||
"downvoting-disabled": "Η καταψήφιση έχει απενεργοποιηθεί",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"no-user": "User does not exist",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "You do not have enough privileges for this action.",
|
||||
|
||||
"category-disabled": "Category disabled",
|
||||
@@ -101,6 +102,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -181,6 +183,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Reputation system is disabled.",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "User does not exist",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "You do not have enough privileges for this action.",
|
||||
"category-disabled": "Category disabled",
|
||||
"topic-locked": "Topic Locked",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Reputation system is disabled.",
|
||||
"downvoting-disabled": "Downvoting is disabled",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "User does not exist",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "You do not have enough privileges for this action.",
|
||||
"category-disabled": "Category disabled",
|
||||
"topic-locked": "Topic Locked",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Reputation system is disabled.",
|
||||
"downvoting-disabled": "Downvoting is disabled",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "El usuario no existe",
|
||||
"no-teaser": "El resumen no existe",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "No tienes suficientes privilegios para realizar esta acción.",
|
||||
"category-disabled": "Categoría deshabilitada",
|
||||
"topic-locked": "Tema bloqueado",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Categoría no seleccionada.",
|
||||
"too-many-posts": "Solo puedes publicar una vez cada %1 segundo(s) - por favor espere antes de volver a publicar",
|
||||
"too-many-posts-newbie": "Como nuevo usuario, solo puedes publicar una vez cada %1 segundo(s) hasta hayas ganado una reputación de %2 - por favor espera antes de volver a publicar",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Por favor introduce una etiqueta más larga. Las etiquetas deben contener por lo menos %1 caractere(s)",
|
||||
"tag-too-long": "Por favor introduce una etiqueta más corta. Las etiquetas no pueden exceder los %1 caractere(s)",
|
||||
"not-enough-tags": "Etiquetas insuficientes. El tema debe tener al menos %1 etiqueta(s).",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Este mensaje de chat ya ha sido borrado.",
|
||||
"chat-restored-already": "Este mensaje de chat ya ha sido restaurado.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Ya has votado a este mensaje.",
|
||||
"reputation-system-disabled": "El sistema de reputación está deshabilitado.",
|
||||
"downvoting-disabled": "La votación negativa está deshabilitada.",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Kasutajat ei eksisteeri",
|
||||
"no-teaser": "Eelvaadet ei eksisteeri",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Sul pole piisavalt õigusi.",
|
||||
"category-disabled": "Kategooria keelatud",
|
||||
"topic-locked": "Teema lukustatud",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "Te saate postitada %1 sekundi tagant - palun oodake enne uue postituse tegemist.",
|
||||
"too-many-posts-newbie": "Uue kasutajana saadte postitada vaid iga %1 sekundi tagant, seniks kuni olete teeninud vähemalt %2 reputatsiooni - palun oodake enne uue postituse tegemist.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Palun sisestage pikem märksõna. Märksõna pikkus peab olema vähemalt %1 tähemärk(i).",
|
||||
"tag-too-long": "Palun sisestage lühem märksõna. Märksõna pikkus peab olema vähem kui %1 tähemärk(i).",
|
||||
"not-enough-tags": "Liiga vähe märksõnu. Teemadel peab olemalt vähemalt %1 märksõna",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Sa oled juba hääletanud sellel postitusel.",
|
||||
"reputation-system-disabled": "Reputatsiooni süsteem ei ole aktiveeritud",
|
||||
"downvoting-disabled": "Negatiivsete häälte andmine ei ole võimaldatud",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "کاربر وجود ندارد",
|
||||
"no-teaser": "تیزر وجود ندارد",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "شما دسترسی کافی برای این کار را ندارید",
|
||||
"category-disabled": "دسته غیرفعال شد.",
|
||||
"topic-locked": "موضوع بسته شد.",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "هیچ دستهبندی انتخاب نشده.",
|
||||
"too-many-posts": "شما می توانید هر %1 ثانیه یک پست ایجاد کنید - لطفا قبل از ارسال پست جدید صبر کنید",
|
||||
"too-many-posts-newbie": "به عنوان یک کاربر جدید ، تا زمانی که شما %2 اعتبار کسب کنید می توانید هر %1 ثانیه یک پست ایجاد کنید - لطفا قبل از ایجاد پست جدید صبر کنید .",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "لطفا برچسب بلندتری وارد کنید. برچسبها باید حداقل %1 کاراکتر داشته باشند.",
|
||||
"tag-too-long": "لطفا برچسب کوتاه تری وارد کنید . برچسب ها نباید بیشتر از %1 کاراکتر داشته باشند",
|
||||
"not-enough-tags": "تعداد برچسب ها کافی نیست. موضوع ها یابد حداقل %1 برچسب داشته باشند",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "این پیام قبلا حذف شده است",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "شما قبلا به این پست رای داده اید.",
|
||||
"reputation-system-disabled": "سیستم اعتبار غیر فعال شده است",
|
||||
"downvoting-disabled": "رأی منفی غیر فعال شده است",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Käyttäjää ei ole olemassa",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Oikeutesi eivät riitä toiminnon suorittamiseen.",
|
||||
"category-disabled": "Kategoria ei ole käytössä",
|
||||
"topic-locked": "Aihe lukittu",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Reputation system is disabled.",
|
||||
"downvoting-disabled": "Downvoting is disabled",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Cet utilisateur n'existe pas",
|
||||
"no-teaser": "L’aperçu n'existe pas",
|
||||
"no-flag": "Le signalement n'existe pas",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Vous n'avez pas les privilèges nécessaires pour effectuer cette action.",
|
||||
"category-disabled": "Catégorie désactivée",
|
||||
"topic-locked": "Sujet verrouillé",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Aucune catégorie sélectionnée",
|
||||
"too-many-posts": "Vous ne pouvez poster que toutes les %1 seconde(s) - merci de patienter avant de publier à nouveau.",
|
||||
"too-many-posts-newbie": "En tant que nouvel utilisateur, vous ne pouvez poster que toutes les %1 seconde(s) jusqu'à ce que vous obteniez une réputation de %2 - patientez avant de publier de nouveau.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Veuillez entrer un mot-clé plus long. Les mots-clés doivent contenir au moins %1 caractère(s).",
|
||||
"tag-too-long": "Veuillez entrer un mot-clé plus court. Les mot-clés ne peuvent excéder %1 caractère(s).",
|
||||
"not-enough-tags": "Pas assez de mots-clés. Les sujets doivent avoir au moins %1 mots-clé(s).",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Ce message a déjà été supprimé.",
|
||||
"chat-restored-already": "Ce message de discussion a déjà été restauré.",
|
||||
"chat-room-does-not-exist": "Le salon de discussion n'existe pas.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Vous avez déjà voté pour ce message.",
|
||||
"reputation-system-disabled": "Le système de réputation est désactivé",
|
||||
"downvoting-disabled": "Les votes négatifs ne sont pas autorisés",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "O usuario non existe",
|
||||
"no-teaser": "A vista previa do tema non existe",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Non tes privilexios dabondo para ver este tema.",
|
||||
"category-disabled": "Categoría deshabilitada",
|
||||
"topic-locked": "Tema Pechado",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Categoría non seleccionada",
|
||||
"too-many-posts": "Só podes postear unha vez cada %1 segundo(s) - por favor agarda antes de publicar de novo.",
|
||||
"too-many-posts-newbie": "Como novo usuario, só podes publicar unha vez cada %1 segundo(s) ata que acades %2 de reputación -por favor, agarda para publicar de novo.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Por favor, introduce unha etiqueta máis longa. As etiquetas deben conter %1 carácter(es) como mínimo.",
|
||||
"tag-too-long": "Por favor, introduce unha etiqueta máis curta. As etiquetas non poden conter máis de %1 carácter(es).",
|
||||
"not-enough-tags": "Non hai etiquetas dabondas. Os temas deben ter %1 etiqueta(s) como mínimo.",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Xa votache esta mensaxe.",
|
||||
"reputation-system-disabled": "O sistema de reputación está deshabilitado",
|
||||
"downvoting-disabled": "Os votos negativos están deshabilitados",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "משתמש אינו קיים",
|
||||
"no-teaser": "תקציר אינו קיים",
|
||||
"no-flag": "דיווח לא קיים",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "ההרשאות שלכם אינן מספיקות לביצוע פעולה זו.",
|
||||
"category-disabled": "קטגוריה לא פעילה",
|
||||
"topic-locked": "נושא נעול",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "לא נבחרה קטגוריה",
|
||||
"too-many-posts": "ניתן לפרסם פוסט רק פעם ב-%1 שניות - אנא המתינו לפני פרסום נוסף",
|
||||
"too-many-posts-newbie": "כמשתמשים חדשים, אתם יכולים לפרסם פוסט רק פעם ב-%1 שניות עד שיהיו לכם %2 נקודות מוניטין - אנא המתינו לפני פרסום נוסף",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "הכניסו תגית ארוכה יותר. תגיות חייבות להכיל לפחות %1 תווים",
|
||||
"tag-too-long": "הכניסו תגית קצרה יותר. תגיות יכולות להיות רק עד %1 תווים",
|
||||
"not-enough-tags": "אין מספיק תגיות. נושא חייב להכיל לפחות %1 תגיות",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "הודעת צ'אט זו כבר נמחקה.",
|
||||
"chat-restored-already": "הודעת צ'אט זו כבר שוחזרה.",
|
||||
"chat-room-does-not-exist": "חדר צ'אט אינו קיים.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "הצבעתם כבר בנושא זה.",
|
||||
"reputation-system-disabled": "מערכת המוניטין לא פעילה.",
|
||||
"downvoting-disabled": "היכולת להצביע נגד מושבתת",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Korisnik ne postoji",
|
||||
"no-teaser": "Zadirkivač ne postoji",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Nemate privilegije za ovu radnju.",
|
||||
"category-disabled": "Kategorija onemogućena",
|
||||
"topic-locked": "Tema zaključana",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategorija nije odabrana.",
|
||||
"too-many-posts": "Možete objavljivati svakih %1 skeundi, pričekajte prije ponovne objave",
|
||||
"too-many-posts-newbie": "Kao novi korisnik, možete objavljivati svakih %1 sekundi dok ne steknete reputaciju %2 - molimo pričekajte prije ponovne objave",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Unesite dužu oznaku. Oznake moraju sadržavati najmanje %1 znak(ova)",
|
||||
"tag-too-long": "Unesite kraću oznaku. Oznake me mogu imati više od %1 znak(ova)",
|
||||
"not-enough-tags": "Nema dovoljno oznaka. Teme moraju imate bar %1 oznaku",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Već ste glasali za ovu objavu",
|
||||
"reputation-system-disabled": "Sistem reputacije onemogućen.",
|
||||
"downvoting-disabled": "Oduzimanje glasova je onemogućeno",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Nem létező felhasználó",
|
||||
"no-teaser": "A bevezető nem létezik",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Nincs elég jogod ehhez a művelethez.",
|
||||
"category-disabled": "Kategória kikapcsolva",
|
||||
"topic-locked": "Téma lezárva",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "A kategória nincs kiválasztva.",
|
||||
"too-many-posts": "Csak %1 másodpercenként hozhatsz létre új bejegyzést - kérlek várj egy kicsit mielőtt új bejegyzést tennél közzé",
|
||||
"too-many-posts-newbie": "Új felhasználóként csak egyszer készíthetsz bejegyzést %1 másodpercen belül, amíg el nem éred a %2 szintet - kérlek várj egy kicsit mielőtt új bejegyzést tennél közzé",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Kérlek hosszabb címkét adj meg. A címke legalább %1 karaktert kell, hogy tartalmazzon",
|
||||
"tag-too-long": "Kérlek rövidebb címkét adj meg. A címkék nem lehetnek hosszabbak %1 karakternél",
|
||||
"not-enough-tags": "Nincs elég címke. A bejegyzésnek legalább %1 címkét kell tartalmaznia",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Ez az üzenet már törölve lett.",
|
||||
"chat-restored-already": "Ez az üzenet már vissza van állítva.",
|
||||
"chat-room-does-not-exist": "Csevegő szoba nem létezik.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Már szavaztál erre a hozzászólásra.",
|
||||
"reputation-system-disabled": "Hírnév funkció kikapcsolva.",
|
||||
"downvoting-disabled": "Leszavazás funkció kikapcsolva",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Օգտվողը գոյություն չունի",
|
||||
"no-teaser": "Թիզերը գոյություն չունի",
|
||||
"no-flag": "Դրոշ գոյություն չունի",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Դուք չունեք բավարար արտոնություններ այս գործողության համար:",
|
||||
"category-disabled": "Կատեգորիան անջատված է",
|
||||
"topic-locked": "Թեման փակված է",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Կատեգորիան ընտրված չէ:",
|
||||
"too-many-posts": "Դուք կարող եք գրառում անել միայն յուրաքանչյուր %1 վայրկյան(եր) մեկ անգամ. խնդրում ենք սպասել նորից գրառում անելուց առաջ",
|
||||
"too-many-posts-newbie": "Որպես նոր օգտատեր, դուք կարող եք հրապարակել միայն յուրաքանչյուր %1 վայրկյան(եր) մեկ անգամ, քանի դեռ չեք վաստակել %2 վարկանիշ, խնդրում ենք սպասել՝ նորից գրառում կատարելուց առաջ:",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Խնդրում ենք մուտքագրել ավելի երկար թեգ: Թեգերը պետք է պարունակեն առնվազն %1 նիշ(ներ)",
|
||||
"tag-too-long": "Խնդրում ենք մուտքագրել ավելի կարճ թեգ: Թեգերը չեն կարող ավելի երկար լինել, քան %1 նիշ(ներ)",
|
||||
"not-enough-tags": "Ոչ բավարար թեգեր: Թեմաները պետք է ունենան առնվազն %1 թեգ(ներ)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Այս զրույցի հաղորդագրությունն արդեն ջնջված է",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Այս զրուցարանը գոյություն չունի:",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Դուք արդեն քվեարկել եք այս գրառման օգտին:",
|
||||
"reputation-system-disabled": "Վարկանիշի համակարգը անջատված է:",
|
||||
"downvoting-disabled": "Դեմ քվեարկությունն անջատված է",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Pengguna tidak ditemukan",
|
||||
"no-teaser": "Teaser tidak ditemukan",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Kamu tidak punya cukup izin untuk melakukan ini",
|
||||
"category-disabled": "Kategori ditiadakan",
|
||||
"topic-locked": "Topik dikunci",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "Anda hanya dapat memposting sekali setiap %1 detik() - harap tunggu sebelum memposting lagi",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Sistem reputasi ditiadakan.",
|
||||
"downvoting-disabled": "Downvoting ditiadakan",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "L'Utente non esiste",
|
||||
"no-teaser": "Teaser non esiste",
|
||||
"no-flag": "Segnalazione non esiste",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Non hai abbastanza privilegi per questa azione.",
|
||||
"category-disabled": "Categoria disabilitata",
|
||||
"topic-locked": "Discussione Bloccata",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Categoria non selezionata.",
|
||||
"too-many-posts": "È possibile inserire un Post ogni %1 secondi - si prega di attendere prima di postare di nuovo",
|
||||
"too-many-posts-newbie": "Come nuovo utente puoi postare solamente una volta ogni %1 secondi finché non hai raggiunto un livello di reputazione %2 - per favore attendi prima di scrivere ancora",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Inserisci un tag più lungo. I tag devono contenere almeno %1 caratteri.",
|
||||
"tag-too-long": "Per favore inserisci un tag più corto. I tags non dovrebbero essere più lunghi di %1 caratteri",
|
||||
"not-enough-tags": "Tag non sufficienti. Le discussioni devono avere almeno %1 Tag",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Il messaggio è già stato eliminato.",
|
||||
"chat-restored-already": "Questo messaggio della chat è già stato ripristinato.",
|
||||
"chat-room-does-not-exist": "La stanza chat non esiste.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Hai già votato per questo post",
|
||||
"reputation-system-disabled": "Il sistema di reputazione è disabilitato.",
|
||||
"downvoting-disabled": "Votata negativamente è disabilitato",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "ユーザーは存在しません",
|
||||
"no-teaser": "ティーザーが存在しません",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "あなたがこの行為する権利がありません。",
|
||||
"category-disabled": "この板は無効された",
|
||||
"topic-locked": "スレッドがロックされた",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "カテゴリが選択されていません。",
|
||||
"too-many-posts": "あなたは%1秒間に一つの投稿しか許されます-少し待ってまた投稿してください",
|
||||
"too-many-posts-newbie": "あなたは%2評判を得ているまで、新しいユーザーとしては、一度だけごとに%1秒を投稿することができます - 再び投稿する前にお待ちください",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "%1文字(s)以上でタグを入力してください。",
|
||||
"tag-too-long": "%1文字(s)以内でタグを入力してください。",
|
||||
"not-enough-tags": "タグが足りません。スレッドはせめて%1のタグ(s)が必要です。",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "このチャットメッセージは既に削除されています",
|
||||
"chat-restored-already": "このチャットメッセージは既に削除されています",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "あなたはすでにこの投稿を評価しました。",
|
||||
"reputation-system-disabled": "Reputation system is disabled.",
|
||||
"downvoting-disabled": "Downvoting is disabled",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "존재하지 않는 사용자입니다.",
|
||||
"no-teaser": "존재하지 않는 미리보기입니다.",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "이 작업을 할 수 있는 권한이 없습니다.",
|
||||
"category-disabled": "카테고리가 비활성화 되었습니다.",
|
||||
"topic-locked": "게시물이 잠금 상태입니다.",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "선택된 카테고리가 없습니다.",
|
||||
"too-many-posts": "새 게시물 작성은 %1초마다 가능합니다. 조금 천천히 작성해주세요.",
|
||||
"too-many-posts-newbie": "신규 사용자는 %2만큼의 인지도를 얻기 전까지 %1초마다 게시물을 작성할 수 있습니다. 조금 천천히 작성해주세요.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "태그가 너무 짧습니다. 태그는 최소 %1자 이상이어야 합니다.",
|
||||
"tag-too-long": "태그가 너무 깁니다. 태그는 최대 %1자 이내로 사용 가능합니다.",
|
||||
"not-enough-tags": "태그가 없거나 부족합니다. 게시물은 %1개 이상의 태그를 사용해야 합니다.",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "이미 삭제된 채팅 메시지입니다.",
|
||||
"chat-restored-already": "이 채팅 메시지는 이미 복원되었습니다.",
|
||||
"chat-room-does-not-exist": "채팅이 존재하지 않습니다.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "이미 이 포스트에 투표하셨습니다.",
|
||||
"reputation-system-disabled": "인지도 시스템이 비활성화되어있습니다.",
|
||||
"downvoting-disabled": "비추천 기능이 비활성 상태입니다.",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Tokio vartotojo nėra",
|
||||
"no-teaser": "Anonsas neegzistuoja",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Šiam veiksmui jūs neturite pakankamų privilegijų.",
|
||||
"category-disabled": "Kategorija išjungta",
|
||||
"topic-locked": "Tema užrakinta",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Nepasirinkta kategorija.",
|
||||
"too-many-posts": "Jus galite rašyti kas %1 sekunde(s) - prašome palaukti prieš rašant dar kartą",
|
||||
"too-many-posts-newbie": "Kadangi esate naujas narys, jūs galite tik rašyti kas %1 sekunde(s) kol jūs pasieksite %2 reputacija - prašome palaukti prieš rašant dar kartą",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Prašome įvesti ilgesnę žymą. Žyma turi sudaryti mažiausiai %1 simboli(us)",
|
||||
"tag-too-long": "Prašome įvesti trumpesnę žymą. Žyma turi būti ne ilgesni negu %1 simboli(us)",
|
||||
"not-enough-tags": "Neužteka žymių. Temos turi turėti mažiausiai %1 žyme(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Ši žinutė buvo pašalinta",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Jūs jau balsavote už šį pranešimą.",
|
||||
"reputation-system-disabled": "Reputacijos sistema išjungta.",
|
||||
"downvoting-disabled": "Downvoting yra išjungtas",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Lietotājs nav atrasts",
|
||||
"no-teaser": "Ievadapraksts nav atrasts",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Tev nepietiek tiesības šai darbībai.",
|
||||
"category-disabled": "Kategorija ir atspējota",
|
||||
"topic-locked": "Temats ir slēgts",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategorija nav atlasīta.",
|
||||
"too-many-posts": "Var publicēt tikai vienu rakstu katras %1 sekundes - lūdzu, uzgaidi, pirms publicē vēlreiz",
|
||||
"too-many-posts-newbie": "Jauni lietotāji var ievietot tikai vienu rakstu katras %1 sekundes, līdz ir nopelnīti %2 ranga punkti - lūdzu, uzgaidi, pirms publicē vēlreiz",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Lūdzu, ievadi garāku birku. Birkā jāsatur vismaz %1 rakstzīmes.",
|
||||
"tag-too-long": "Lūdzu, ievadi īsāku birku. Birkā nevar būt vairāk kā %1 rakstzīmes.",
|
||||
"not-enough-tags": "Nav pietiekami daudz birku. Tematiem jābūt vismaz %1 birkām",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Saruna jau ir izdzēsta.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Tu jau balsoji par šo rakstu.",
|
||||
"reputation-system-disabled": "Ranga punktu sistēma ir atspējota.",
|
||||
"downvoting-disabled": "Balsošana \"pret\" ir atspējota",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Pengguna tidak wujud",
|
||||
"no-teaser": "Pengusik tidak wujud",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Anda tidak mempunyai cukup keistimewaan untuk perbuatan ini.",
|
||||
"category-disabled": "Kategori dilumpuhkan",
|
||||
"topic-locked": "Topik Dikunci",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "Anda hanya boleh mengirim sekali setiap %1 saat() - sila tunggu sebelum kiriman seterusnya",
|
||||
"too-many-posts-newbie": "Sebagai pengguna baru, anda hanya boleh mengirim sekali setiap %1 saat() sehinnga anda mendapat %2 reputasi - sila tunggu sebelum kiriman seterusnya",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Sila masukkan tag yang lebih panjang. Tag mesti mengandungi sekurang-kurangnya %1 aksara()",
|
||||
"tag-too-long": "Sila masukkan tag yang lebih pendek. Tag mesti mengandungi tidak lebih %1 aksara()",
|
||||
"not-enough-tags": "Tag tidak mencukupi. Topik memerlukan sekurang-kurangnya %1 tag()",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Sistem reputasi dilumpuhkan.",
|
||||
"downvoting-disabled": "Undi turun dilumpuhkan",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Bruker eksisterer ikke",
|
||||
"no-teaser": "Teaseren eksisterer ikke",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Du har ikke nok rettigheter til å utføre denne handlingen.",
|
||||
"category-disabled": "Kategori deaktivert",
|
||||
"topic-locked": "Emne låst",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategori ikke valgt",
|
||||
"too-many-posts": "Du kan bare poste en gang per %1 sekund(er) – vennligst vent før du poster igjen",
|
||||
"too-many-posts-newbie": "Som ny bruker kan du bare poste en gang per %1. sekund(er), før du har opparbeidet %2 i omdømme – vennligst vent før du poster igjen",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Vennligst skriv et lengre emneord. Disse må være på minst %1 tegn",
|
||||
"tag-too-long": "Vennligst skriv et kortere emneord. Disse kan ikke være lengre enn %1 tegn",
|
||||
"not-enough-tags": "Ikke nok emneord. Emner må ha minst %1.",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Denne meldingen har allerede blitt slettet.",
|
||||
"chat-restored-already": "Denne meldingen har allerede blitt gjenopprettet.",
|
||||
"chat-room-does-not-exist": "Dette chatterommet finnes ikke.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Du har allerede stemt på dette innlegget",
|
||||
"reputation-system-disabled": "Omdømmesystemet er deaktivert.",
|
||||
"downvoting-disabled": "Nedstemming er deaktivert",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Gebruiker bestaat niet",
|
||||
"no-teaser": "Dit voorproefje bestaat niet",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Onvoldoende rechten om deze actie uit te voeren",
|
||||
"category-disabled": "Categorie uitgeschakeld",
|
||||
"topic-locked": "Onderwerp gesloten",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Categorie niet geselecteerd ",
|
||||
"too-many-posts": "Het is slechts toegestaan iedere %1 seconde(n) een bericht te plaatsen - wacht even voordat opnieuw een bericht verzonden wordt",
|
||||
"too-many-posts-newbie": "Nieuwe gebruikersaccounts zoals deze zijn begrensd en mogen slechts iedere %1 seconde(n) berichten plaatsen, tot het moment dat %2 reputatie verdiend is - wacht daarom even met opnieuw een bericht te plaatsten",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Geef een tag op die uit meer tekens bestaat. Tags dienen uit minimaal %1 teken(s) te bestaan.",
|
||||
"tag-too-long": "Geef een kortere tag op. Tags mogen niet langer dan %1 teken(s) zijn",
|
||||
"not-enough-tags": "Niet genoeg labels. Onderwerp moeten tenminste %1 label(s) hebben",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Dit chat bericht is al verwijderd.",
|
||||
"chat-restored-already": "Dit chat bericht is al hersteld.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Je hebt al gestemd voor deze post.",
|
||||
"reputation-system-disabled": "Reputatie systeem is uitgeschakeld.",
|
||||
"downvoting-disabled": "Negatief stemmen is uitgeschakeld",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Użytkownik nie istnieje",
|
||||
"no-teaser": "Zwiastun nie istnieje",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Nie masz przywileju wykonywania tej akcji",
|
||||
"category-disabled": "Kategoria wyłączona.",
|
||||
"topic-locked": "Temat zablokowany",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Nie wybrano kategorii.",
|
||||
"too-many-posts": "Możesz publikować posty raz na %1 sekund – poczekaj, zanim dodasz kolejny post",
|
||||
"too-many-posts-newbie": "Jako nowy użytkownik możesz publikować posty raz na %1 sekund, dopóki nie zdobędziesz reputacji na poziomie %2 – poczekaj, zanim dodasz kolejny post",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Wprowadź dłuższy tag. Tagi muszą mieć przynajmniej %1 znak(-ów)",
|
||||
"tag-too-long": "Wprowadź krótszy tag. Tagi nie mogą mieć więcej niż %1 znak(-ów)",
|
||||
"not-enough-tags": "Zbyt mało tagów. Tematy muszą posiadać przynajmniej %1 tag(ów)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Ten komunikat czatu jest już skasowany",
|
||||
"chat-restored-already": "Ta wiadomość została już przywrócona",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Już zagłosowałeś na ten post",
|
||||
"reputation-system-disabled": "System reputacji jest wyłączony.",
|
||||
"downvoting-disabled": "Negatywna ocena postów jest wyłączona",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "O usuário não existe",
|
||||
"no-teaser": "O teaser não existe",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Você não possui privilégios suficientes para esta ação.",
|
||||
"category-disabled": "Categoria desativada",
|
||||
"topic-locked": "Tópico Trancado",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Categoria não escolhida.",
|
||||
"too-many-posts": "Você pode postar uma vez a cada %1 segundo(s) - por favor aguarde antes de postar novamente",
|
||||
"too-many-posts-newbie": "Como novo usuário, você só pode postar uma vez a cada %1 segundo(s) até que você tenha, pelo menos, %2 de reputação. Por favor, aguarde antes de postar novamente.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Por favor digite uma tag maior. Tags devem conter pelo menos %1 caractere(s)",
|
||||
"tag-too-long": "Por favor digite uma tag menor. Tags não podem conter mais que %1 caractere(s)",
|
||||
"not-enough-tags": "Sem tags suficientes. Tópicos devem ter no mínimo %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Essa mensagem de chat já foi deletada",
|
||||
"chat-restored-already": "Essa mensagem de chat já foi restaurada.",
|
||||
"chat-room-does-not-exist": "A sala de chat não existe.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Você já votou neste post.",
|
||||
"reputation-system-disabled": "O sistema de reputação está desabilitado.",
|
||||
"downvoting-disabled": "Negativação está desabilitada",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Utilizador não existente",
|
||||
"no-teaser": "Não existe pré-visualização",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Não possuis privilégios suficientes para esta ação.",
|
||||
"category-disabled": "Categoria desativada",
|
||||
"topic-locked": "Tópico bloqueado",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Categoria não selecionada.",
|
||||
"too-many-posts": "Só podes publicar a cada %1 segundo(s) - por favor espera até poderes publicar outra vez",
|
||||
"too-many-posts-newbie": "Como novo utilizador, só podes publicar a cada %1 segundo(s) até teres conquistado %2 de reputação - por favor espera até poderes publicar outra vez",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Por favor introduz um marcador maior. Os marcadores devem ter pelo menos %1 caracter(s)",
|
||||
"tag-too-long": "Por favor introduz um marcador mais curto. Os marcadores devem ter no máximo %1 caracter(es)",
|
||||
"not-enough-tags": "Não existem marcadores suficientes. Os tópicos devem ter pelo menos %1 marcador(es)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Esta mensagem já foi apagada.",
|
||||
"chat-restored-already": "Esta mensagem já foi restaurada.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Já votaste nesta publicação.",
|
||||
"reputation-system-disabled": "O sistema de reputação está desativado.",
|
||||
"downvoting-disabled": "Os votos negativos estão desativados",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Utilizatorul nu exista.",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "You do not have enough privileges for this action.",
|
||||
"category-disabled": "Categorie dezactivată",
|
||||
"topic-locked": "Subiect Închis",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Sistemul de reputație este dezactivat.",
|
||||
"downvoting-disabled": "Votarea negativă este dezactivată",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Такого пользователя не существует",
|
||||
"no-teaser": "Такого тизера не существует",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "У вас недостаточно прав для этого действия.",
|
||||
"category-disabled": "Категория отключена",
|
||||
"topic-locked": "Тема закрыта",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Категория не выбрана",
|
||||
"too-many-posts": "Для того, чтобы разместить новое сообщение, нужно подождать %1 сек.",
|
||||
"too-many-posts-newbie": "Для того, чтобы разместить новое сообщение, нужно подождать %1 сек. Это время уменьшится, как только ваша репутация вырастет до %2.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Слишком короткая метка. Минимум %1 символов.",
|
||||
"tag-too-long": "Слишком длинная метка. Максимум %1 символов.",
|
||||
"not-enough-tags": "Пожалуйста, добавьте метки в ваше сообщение. У темы должно быть минимум %1 меток.",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Это сообщение чата уже удалено.",
|
||||
"chat-restored-already": "Это сообщение чата уже было восстановлено.",
|
||||
"chat-room-does-not-exist": "Комната чата не существует.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Вы уже проголосовали за это сообщение.",
|
||||
"reputation-system-disabled": "Система репутации отключена.",
|
||||
"downvoting-disabled": "Понижение рейтинга отключено",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Umuntu utabaho",
|
||||
"no-teaser": "Inshamake itabaho",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Ntabwo uragira uburenganzira buhagije ngo wemererwe iki gikorwa",
|
||||
"category-disabled": "Icyiciro cyabujijwe",
|
||||
"topic-locked": "Ikiganiro Cyafungiranywe",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "Wemerewe kugira icyo ushyiraho rimwe mu masegonda (isegonda) %1. Ba utegerejeho gato kugirango wongere",
|
||||
"too-many-posts-newbie": "Nk'umuntu mushya, wemerewe gushyiraho ikintu rimwe mu masegonda (isegonda) %1 kugeza igihe ugize amanota agera kuri %2. Ba utegerejeho gato kugirango wongere",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Gerageza ukoreshe akamenyetso kagizwe n'inyuguti (cyangwa ibimenyetso) nibura zigera kuri %1",
|
||||
"tag-too-long": "Gerageza ukoreshe akamenyetso kagizwe n'inyuguti (cyangwa ibimenyetso) zitarenze %1",
|
||||
"not-enough-tags": "Nta tumenyetso turiho duhagije. Ibiganiro bigomba kugira utumenyetso (akamenyetso) nibura %1",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Ibijyanye n'itangwa ry'amanota ntibyemerewe. ",
|
||||
"downvoting-disabled": "Kwambura amanota ntibyemerewe",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "User does not exist",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "You do not have enough privileges for this action.",
|
||||
"category-disabled": "Category disabled",
|
||||
"topic-locked": "Topic Locked",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "You can only post once every %1 second(s) - please wait before posting again",
|
||||
"too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)",
|
||||
"tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)",
|
||||
"not-enough-tags": "Not enough tags. Topics must have at least %1 tag(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Reputation system is disabled.",
|
||||
"downvoting-disabled": "Downvoting is disabled",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Užívateľ neexistuje",
|
||||
"no-teaser": "Ukážka neexistuje",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Na túto akciu nemáte dostatočné oprávnenia.",
|
||||
"category-disabled": "Kategória je zablokovaná",
|
||||
"topic-locked": "Téma je uzamknutá",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategória nebola vybratá.",
|
||||
"too-many-posts": "Môžete uverejniť príspevok každých %1 sekúnd(y) - prosím počkajte pred opätovným zverejnením",
|
||||
"too-many-posts-newbie": "Ako nový užívateľ, môžete uverejniť príspevok raz za %1 sekúnd(y) pokiaľ nezískate %2 reputáciu - prosím, počkajte pred ďalším uverejnením",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Prosím, zadajte dlhšiu značku. Značky by mali obsahovať najmenej %1 znak(ov)",
|
||||
"tag-too-long": "Prosím, zadajte kratšiu značku. Značky nemôžu obsahovať viac ako %1 znak(ov)",
|
||||
"not-enough-tags": "Príliš malo značiek. Témy musia mať minimálne %1 značku(y)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Táto správa konverzácie už bola odstránená.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Za tento príspevok ste už hlasovali.",
|
||||
"reputation-system-disabled": "Systém reputácie je zablokovaný.",
|
||||
"downvoting-disabled": "Hlasovanie proti je zablokované",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Uporabnik ne obstaja.",
|
||||
"no-teaser": "Predogled ne obstaja.",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Nimate dovolj pravic za to dejanje.",
|
||||
"category-disabled": "Kategorija je onemogočena.",
|
||||
"topic-locked": "Tema je zaklenjena.",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Category not selected.",
|
||||
"too-many-posts": "Objavljate lahko na %1 s - prosimo, počakajte pred novo objavo.",
|
||||
"too-many-posts-newbie": "Kot nov uporabnik lahko objavljate le na %1 s, dokler ne dosežete ugled vsaj %2 - prosimo, počakajte pred novo objavo.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Prosimo, vnesite daljšo oznako. Obvezno število znakov: vsaj %1.",
|
||||
"tag-too-long": "Prosimo, vnesite krajšo oznako. Največje število znakov: %1.",
|
||||
"not-enough-tags": "Ni dovolj oznak. Obvezno število oznak: %1. ",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Za to objavo ste že glasovali.",
|
||||
"reputation-system-disabled": "Sistem za ugled je onemogočen.",
|
||||
"downvoting-disabled": "Negativno glasovanje je onemogočeno.",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Përdoruesi nuk ekziston",
|
||||
"no-teaser": "Përmbledhja nuk ekziston",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Nuk keni akses të mjaftueshem për këtë veprim.",
|
||||
"category-disabled": "Kategori e çaktivizuar",
|
||||
"topic-locked": "Temë e kyçur",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategoria nuk është zgjedhur.",
|
||||
"too-many-posts": "Mund të postoni vetëm një herë në %1 sekond(a) - ju lutemi prisni përpara se të postoni përsëri",
|
||||
"too-many-posts-newbie": "Si përdorues i ri, ju mund të postoni vetëm një herë në %1 sekond(a) derisa të keni fituar %2 reputacion - ju lutemi prisni përpara se të postoni përsëri",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Ju lutemi vendosni një tag më të gjatë. Tag-et duhet të përmbajnë të paktën %1 karakter(e)",
|
||||
"tag-too-long": "Ju lutemi vendosni një tag më të shkurtër. Tag-et nuk mund të jenë më të gjata se %1 karakter(e)",
|
||||
"not-enough-tags": "Numër jo i mjaftueshëm i tag-eve. Temat duhet të kenë të paktën %1 tag(-e)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Ky mesazh është fshirë tashmë.",
|
||||
"chat-restored-already": "Ky mesazh është rikthyer tashmë.",
|
||||
"chat-room-does-not-exist": "Kjo dhomë bisede nuk ekziston.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Ju keni votuar tashmë për këtë postim.",
|
||||
"reputation-system-disabled": "Sistemi i reputacionit është i çaktivizuar.",
|
||||
"downvoting-disabled": "Votimi kundër është i çaktivizuar",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Корисник не постоји",
|
||||
"no-teaser": "Исечак не постоји",
|
||||
"no-flag": "Заставица не постоји",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Немате довољне привилегије за обављање ове радње.",
|
||||
"category-disabled": "Категорија је онемогућена",
|
||||
"topic-locked": "Тема је закључана",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Није одабрана категорија",
|
||||
"too-many-posts": "Можете објављивати поруке само једном у %1 секунди - сачекајте пре него што покушате поново",
|
||||
"too-many-posts-newbie": "Као нови корисник, можете објављивати поруке само једном у %1 секунди док не достигнете %2 углед - сачекајте пре него што покушате поново",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Унесите дужу ознаку. Ознаке морају садржати најмање %1 знак(ов)а.",
|
||||
"tag-too-long": "Унесите краћу ознаку. Ознаке не смеју бити дуже од %1 знак(ов)а.",
|
||||
"not-enough-tags": "Нема довољно ознака. Теме морају имати најмање %1 ознаке/а.",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Ова порука ћаскања је већ избрисана.",
|
||||
"chat-restored-already": "Ова порука ћаскања је већ обновљена.",
|
||||
"chat-room-does-not-exist": "Соба за ћаскање не постоји.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Већ сте гласали за ову поруку.",
|
||||
"reputation-system-disabled": "Угледи су онемогућени.",
|
||||
"downvoting-disabled": "Негативно гласање је онемогућено",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Användaren finns inte",
|
||||
"no-teaser": "Förhandsvisningen finns inte",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Du har inte tillräckliga rättigheter för den här åtgärden.",
|
||||
"category-disabled": "Kategorin inaktiverad",
|
||||
"topic-locked": "Ämnet låst",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategori Ej vald.",
|
||||
"too-many-posts": "Du måste vänta minst %1 sekund(er) mellan varje inlägg",
|
||||
"too-many-posts-newbie": "Som ny användare måste du vänta %1 sekund(er) mellan varje inlägg tills dess du har %2 förtroende",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Fyll i en längre tagg. Taggar måste vara minst %1 tecken långa",
|
||||
"tag-too-long": "Fyll i en kortare tagg. Taggar kan ej vara längre än %1 tecken långa",
|
||||
"not-enough-tags": "Otillräckligt antal taggar. Ämnen måste ha minst %1 taggar",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Detta chattmeddelande har redan raderats.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Du har redan röstat på det här inlägget.",
|
||||
"reputation-system-disabled": "Ryktessystemet är inaktiverat.",
|
||||
"downvoting-disabled": "Nedröstning är inaktiverat",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "ยังไม่มีผู้ใช้งานนี้",
|
||||
"no-teaser": "ยังไม่มีทีเซอร์นี้",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "คุณมีสิทธิ์ไม่เพียงพอที่จะทำรายการนี้",
|
||||
"category-disabled": "Category นี้ถูกปิดการใช้งานแล้ว",
|
||||
"topic-locked": "กระทู้ถูกล็อก",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "ไม่มีการเลือกหมวดหมู่",
|
||||
"too-many-posts": "คุณสามารถโพสต์ได้เพียงครั้งเดียวเท่านั้นในทุกๆ %1 วินาที(s) - โปรดรอสักครู่ก่อนการโพสต์อีกครั้ง",
|
||||
"too-many-posts-newbie": "เนื่องด้วยการเป็นผู้ใช้งานใหม่ คุณสามารถโพสต์ได้เพียงครั้งเดียวเท่านั้นในทุกๆ %1 วินาที(s) จนกว่าคุณจะได้รับ %2 ชื่อเสียง - โปรดรอสักครู่ก่อนการโพสต์อีกครั้ง",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "กรุณากรอกแท็กให้ยาวขึ้น แท็กควรมีข้อความอย่างน้อย %1 ตัวอักษร(s)",
|
||||
"tag-too-long": "กรุณากรอกแท็กให้สั้นลง แท็กไม่สามารถยาวกว่า %1 ตัวอักษร(s)",
|
||||
"not-enough-tags": "จำนวนแท็กไม่พอ กระทู้ต้องมีอย่างน้อย %1 แท็ก(s)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "คุณได้โหวตโพสต์นี้แล้ว",
|
||||
"reputation-system-disabled": "ระบบชื่อเสียงถูกปิดใช้งาน",
|
||||
"downvoting-disabled": "\"การโหวตลง\" ถูกปิดใช้งาน",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Kullanıcı Yok",
|
||||
"no-teaser": "İleti Yok",
|
||||
"no-flag": "Şikayet Yok",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Bu işlemi yapmak için yeterli yetkiniz yok.",
|
||||
"category-disabled": "Kategori aktif değil",
|
||||
"topic-locked": "Başlık Kilitli",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Kategori bulunamadı. Lütfen bir kategori seçiniz. ",
|
||||
"too-many-posts": "%1 saniye içinde yalnızca bir ileti gönderebilirsiniz - lütfen tekrar ileti göndermeden önce bekleyiniz.",
|
||||
"too-many-posts-newbie": "Yeni bir kullanıcı olarak, %2 saygınlık puanı kazanana kadar %1 saniye içinde bir ileti gönderebilirsiniz - lütfen tekrar ileti göndermeden önce bekleyiniz.",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Lütfen daha uzun bir etiket girin. Etiketler en az %1 karakter içermelidir.",
|
||||
"tag-too-long": "Lütfen daha kısa bir etiket girin. Etiketler %1 karakterden uzun olamaz.",
|
||||
"not-enough-tags": "Yeterince etiket yok. Başlılar en az %1 etikete sahip olmalıdır",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Bu sohbet mesajı zaten silinmiş.",
|
||||
"chat-restored-already": "Bu sohbet mesajı zaten geri yüklendi.",
|
||||
"chat-room-does-not-exist": "Sohbet Odası Mevcut Değil",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Bu gönderi için zaten oy verdin.",
|
||||
"reputation-system-disabled": "İtibar sistemi devre dışı.",
|
||||
"downvoting-disabled": "Eksi oylama devre dışı bırakılmış. ",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Користувач не існує",
|
||||
"no-teaser": "Тизер не існує",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "У вас недостатньо повноважень для цієї дії. ",
|
||||
"category-disabled": "Категорію відключено",
|
||||
"topic-locked": "Тему заблоковано",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Категорію не вибрано.",
|
||||
"too-many-posts": "Ви не можете постити частіше %1 секунд(и) — зачекайте, будь ласка, перед повторною спробою",
|
||||
"too-many-posts-newbie": "Як новий користувач, ви не можете публікувати частіше %1 секунд(и) доки не заробите %2 репутації — зачекайте, будь ласка, перед повторною спробою",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Введіть, будь ласка, довший тег. Мінімальна довжина тегу %1 символ(ів)",
|
||||
"tag-too-long": "Введіть, будь ласка, коротший тег. Максимальна довжина тегу %1 символ(ів)",
|
||||
"not-enough-tags": "Замало тегів. Тема повинна мати щонайменше %1 тег(и)",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Це повідомлення чату вже було видалено.",
|
||||
"chat-restored-already": "Це чат повідомлення вже було відновлене",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Ви вже проголосували за цей пост.",
|
||||
"reputation-system-disabled": "Система репутацій вимкнена.",
|
||||
"downvoting-disabled": "Голосування проти вимкнено",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "Người dùng không tồn tại",
|
||||
"no-teaser": "Đoạn giới thiệu không tồn tại",
|
||||
"no-flag": "Cờ không tồn tại",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "Bạn không đủ quyền để thực thi hành động này",
|
||||
"category-disabled": "Chuyên mục bị khóa",
|
||||
"topic-locked": "Chủ đề bị khóa",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "Chưa chọn category",
|
||||
"too-many-posts": "Bạn chỉ có đăng bài mới mỗi %1 giây - vui lòng đợi để tiếp tục đăng bài.",
|
||||
"too-many-posts-newbie": "Là người dùng mới, bạn chỉ có thể đăng %1 giây một lần cho đến khi bạn đạt được %2 danh tiếng - vui lòng đợi trước khi đăng lại",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "Vui lòng nhập tag dài hơn. Tag phải có tối thiểu %1 ký tự.",
|
||||
"tag-too-long": "Vui lòng nhập tag ngắn hơn. Tag chỉ có thể có tối đa %1 ký tự.",
|
||||
"not-enough-tags": "Không đủ thẻ. Chủ đề phải có ít nhất %1 thẻ.",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "Cuộc trò chuyện này đã được xóa.",
|
||||
"chat-restored-already": "Tin nhắn trò chuyện này đã được khôi phục.",
|
||||
"chat-room-does-not-exist": "Phòng trò chuyện không tồn tại.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "Bạn đã bỏ phiếu cho bài viết này",
|
||||
"reputation-system-disabled": "Hệ thống đánh giá uy tính đã bị vô hiệu hóa.",
|
||||
"downvoting-disabled": "Phản đối đã bị tắt",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "用户不存在",
|
||||
"no-teaser": "主题预览不存在",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "您没有权限执行此操作。",
|
||||
"category-disabled": "版块已禁用",
|
||||
"topic-locked": "主题已锁定",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "未选择版块。",
|
||||
"too-many-posts": "发帖需要间隔 %1 秒以上 - 请稍候再发帖",
|
||||
"too-many-posts-newbie": "因为您是新用户,所以限制每隔 %1 秒才能发帖一次,直到您有 %2 点声望为止 —— 请稍候再发帖",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "标签太短,不能少于 %1 个字符",
|
||||
"tag-too-long": "标签太长,不能超过 %1 个字符",
|
||||
"not-enough-tags": "没有足够的标签。主题必须至少有 %1 个标签。",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "聊天消息已经被删除",
|
||||
"chat-restored-already": "此聊天消息已经恢复。\n",
|
||||
"chat-room-does-not-exist": "聊天室不存在。",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "您已为此帖回复投过票了。",
|
||||
"reputation-system-disabled": "声望系统已禁用。",
|
||||
"downvoting-disabled": "踩已被禁用",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"no-user": "使用者不存在",
|
||||
"no-teaser": "主題預覽不存在",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "您的權限不足以執行此操作。",
|
||||
"category-disabled": "版面已停用",
|
||||
"topic-locked": "主題已鎖定",
|
||||
@@ -88,6 +89,7 @@
|
||||
"category-not-selected": "未選擇版面。",
|
||||
"too-many-posts": "貼文需要間隔 %1 秒以上 - 請稍候再發文",
|
||||
"too-many-posts-newbie": "因為您是新使用者,所以限制每隔 %1 秒才能發文一次,直到您有 %2 點聲望為止 —— 請稍候再發文",
|
||||
"already-posting": "You are already posting",
|
||||
"tag-too-short": "標籤太短,不能少於 %1 個字元",
|
||||
"tag-too-long": "標籤太長,不能超過 %1 個字元",
|
||||
"not-enough-tags": "沒有足夠的主題標籤。主題必須至少有 %1 個標籤",
|
||||
@@ -155,6 +157,9 @@
|
||||
"chat-deleted-already": "聊天訊息已經被刪除",
|
||||
"chat-restored-already": "此聊天訊息已經恢復。",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
"already-voting-for-this-post": "您已讚過此貼文回覆了。",
|
||||
"reputation-system-disabled": "聲望系統已停用。",
|
||||
"downvoting-disabled": "倒讚已被停用",
|
||||
|
||||
@@ -265,6 +265,9 @@ TopicObjectSlim:
|
||||
name:
|
||||
type: string
|
||||
description: The topic thumbnail filename
|
||||
path:
|
||||
type: string
|
||||
description: Path to topic thumbnail without upload_url prefix
|
||||
url:
|
||||
type: string
|
||||
description: Relative path to the topic thumbnail
|
||||
|
||||
@@ -374,6 +374,20 @@ get:
|
||||
type: string
|
||||
postIndex:
|
||||
type: number
|
||||
author:
|
||||
type: object
|
||||
required: [username, uid]
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
userslug:
|
||||
type: string
|
||||
uid:
|
||||
type: number
|
||||
fullname:
|
||||
type: string
|
||||
displayname:
|
||||
type: string
|
||||
loggedInUser:
|
||||
$ref: ../../components/schemas/UserObject.yaml#/UserObject
|
||||
- type: object
|
||||
|
||||
@@ -19,6 +19,15 @@ post:
|
||||
content:
|
||||
type: string
|
||||
example: This is the test topic's content
|
||||
timestamp:
|
||||
type: number
|
||||
description: |
|
||||
A UNIX timestamp of the topic's creation date (i.e. when it will be posted).
|
||||
Specifically, this value can only be set to a value in the future if the calling user has the `topics:schedule` privilege for the passed-in category.
|
||||
Otherwise, the current date and time are always assumed.
|
||||
In some scenarios (e.g. forum migrations), you may want to backdate topics and posts.
|
||||
Please see [this Developer FAQ topic](https://community.nodebb.org/topic/16983/how-can-i-backdate-topics-and-posts-for-migration-purposes) for more information.
|
||||
example: 556084800000
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
|
||||
@@ -46,8 +46,6 @@ post:
|
||||
content:
|
||||
type: string
|
||||
example: This is a test reply
|
||||
timestamp:
|
||||
type: number
|
||||
toPid:
|
||||
type: number
|
||||
required:
|
||||
|
||||
@@ -31,6 +31,8 @@ get:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
description: Path to a topic thumbnail
|
||||
@@ -155,6 +157,8 @@ delete:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
description: Path to a topic thumbnail
|
||||
@@ -38,4 +38,4 @@ put:
|
||||
$ref: ../../../../components/schemas/Status.yaml#/Status
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
properties: {}
|
||||
|
||||
@@ -9,15 +9,23 @@ define('admin/settings/email', ['ace/ace', 'alerts', 'admin/settings'], function
|
||||
configureEmailTester();
|
||||
configureEmailEditor();
|
||||
handleDigestHourChange();
|
||||
handleSmtpServiceChange();
|
||||
|
||||
$(window).on('action:admin.settingsLoaded action:admin.settingsSaved', handleDigestHourChange);
|
||||
$(window).on('action:admin.settingsSaved', function () {
|
||||
socket.emit('admin.user.restartJobs');
|
||||
});
|
||||
$('[id="email:smtpTransport:service"]').change(handleSmtpServiceChange);
|
||||
$(window).off('action:admin.settingsLoaded', onSettingsLoaded)
|
||||
.on('action:admin.settingsLoaded', onSettingsLoaded);
|
||||
$(window).off('action:admin.settingsSaved', onSettingsSaved)
|
||||
.on('action:admin.settingsSaved', onSettingsSaved);
|
||||
};
|
||||
|
||||
function onSettingsLoaded() {
|
||||
handleDigestHourChange();
|
||||
handleSmtpServiceChange();
|
||||
}
|
||||
|
||||
function onSettingsSaved() {
|
||||
handleDigestHourChange();
|
||||
socket.emit('admin.user.restartJobs');
|
||||
}
|
||||
|
||||
function configureEmailTester() {
|
||||
$('button[data-action="email.test"]').off('click').on('click', function () {
|
||||
socket.emit('admin.email.test', { template: $('#test-email').val() }, function (err) {
|
||||
@@ -106,20 +114,26 @@ define('admin/settings/email', ['ace/ace', 'alerts', 'admin/settings'], function
|
||||
}
|
||||
|
||||
function handleSmtpServiceChange() {
|
||||
const isCustom = $('[id="email:smtpTransport:service"]').val() === 'nodebb-custom-smtp';
|
||||
$('[id="email:smtpTransport:custom-service"]')[isCustom ? 'slideDown' : 'slideUp'](isCustom);
|
||||
|
||||
const enabledEl = document.getElementById('email:smtpTransport:enabled');
|
||||
if (enabledEl) {
|
||||
if (!enabledEl.checked) {
|
||||
enabledEl.closest('label').classList.toggle('is-checked', true);
|
||||
enabledEl.checked = true;
|
||||
alerts.alert({
|
||||
message: '[[admin/settings/email:smtp-transport.auto-enable-toast]]',
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
function toggleCustomService() {
|
||||
const isCustom = $('[id="email:smtpTransport:service"]').val() === 'nodebb-custom-smtp';
|
||||
$('[id="email:smtpTransport:custom-service"]')[isCustom ? 'slideDown' : 'slideUp'](isCustom);
|
||||
}
|
||||
toggleCustomService();
|
||||
$('[id="email:smtpTransport:service"]').change(function () {
|
||||
toggleCustomService();
|
||||
|
||||
const enabledEl = document.getElementById('email:smtpTransport:enabled');
|
||||
if (enabledEl) {
|
||||
if (!enabledEl.checked) {
|
||||
$('label[for="email:smtpTransport:enabled"]').toggleClass('is-checked', true);
|
||||
enabledEl.checked = true;
|
||||
alerts.alert({
|
||||
message: '[[admin/settings/email:smtp-transport.auto-enable-toast]]',
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return module;
|
||||
|
||||
@@ -77,6 +77,7 @@ define('forum/account/edit/password', [
|
||||
ajaxify.go('user/' + ajaxify.data.userslug + '/edit');
|
||||
}
|
||||
})
|
||||
.catch(alerts.error)
|
||||
.finally(() => {
|
||||
btn.removeClass('disabled').find('i').addClass('hide');
|
||||
currentPassword.val('');
|
||||
|
||||
@@ -88,7 +88,11 @@ define('forum/topic', [
|
||||
});
|
||||
}
|
||||
|
||||
mousetrap.bind('j', () => {
|
||||
mousetrap.bind('j', (e) => {
|
||||
if (e.target.classList.contains('mousetrap')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = navigator.getIndex();
|
||||
const count = navigator.getCount();
|
||||
if (index === count) {
|
||||
@@ -98,7 +102,11 @@ define('forum/topic', [
|
||||
navigator.scrollToIndex(index, true, 0);
|
||||
});
|
||||
|
||||
mousetrap.bind('k', () => {
|
||||
mousetrap.bind('k', (e) => {
|
||||
if (e.target.classList.contains('mousetrap')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = navigator.getIndex();
|
||||
if (index === 1) {
|
||||
return;
|
||||
|
||||
@@ -24,7 +24,7 @@ define('forum/topic/images', [], function () {
|
||||
|
||||
if (!$this.parent().is('a')) {
|
||||
$this.wrap('<a href="' + src + '" ' +
|
||||
(!srcExt && altExt ? ' download="' + altFilename + '" ' : '') +
|
||||
(!srcExt && altExt ? ' download="' + utils.escapeHTML(altFilename) + '" ' : '') +
|
||||
' target="_blank" rel="noopener">');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ define('forum/topic/postTools', [
|
||||
const pid = postEl.attr('data-pid');
|
||||
const index = parseInt(postEl.attr('data-index'), 10);
|
||||
|
||||
socket.emit('posts.loadPostTools', { pid: pid, cid: ajaxify.data.cid }, async (err, data) => {
|
||||
socket.emit('posts.loadPostTools', { pid: pid }, async (err, data) => {
|
||||
if (err) {
|
||||
return alerts.error(err);
|
||||
}
|
||||
|
||||
@@ -518,7 +518,6 @@ define('settings', ['hooks', 'alerts'], function (hooks, alerts) {
|
||||
formEl = $(formEl);
|
||||
|
||||
const controls = formEl.get(0).elements;
|
||||
console.log(controls);
|
||||
const ok = Settings.check(controls);
|
||||
if (!ok) {
|
||||
return;
|
||||
|
||||
@@ -15,6 +15,9 @@ app = window.app || {};
|
||||
reconnectionDelay: config.reconnectionDelay,
|
||||
transports: config.socketioTransports,
|
||||
path: config.relative_path + '/socket.io',
|
||||
query: {
|
||||
_csrf: config.csrf_token,
|
||||
},
|
||||
};
|
||||
|
||||
window.socket = io(config.websocketAddress, ioParams);
|
||||
|
||||
@@ -237,23 +237,26 @@ Analytics.getDailyStatsForSet = async function (set, day, numDays) {
|
||||
set = `analytics:${set}`;
|
||||
}
|
||||
|
||||
const daysArr = [];
|
||||
day = new Date(day);
|
||||
// set the date to tomorrow, because getHourlyStatsForSet steps *backwards* 24 hours to sum up the values
|
||||
day.setDate(day.getDate() + 1);
|
||||
day.setHours(0, 0, 0, 0);
|
||||
|
||||
while (numDays > 0) {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
async function getHourlyStats(hour) {
|
||||
const dayData = await Analytics.getHourlyStatsForSet(
|
||||
set,
|
||||
day.getTime() - (1000 * 60 * 60 * 24 * (numDays - 1)),
|
||||
hour,
|
||||
24
|
||||
);
|
||||
daysArr.push(dayData.reduce((cur, next) => cur + next));
|
||||
return dayData.reduce((cur, next) => cur + next);
|
||||
}
|
||||
const hours = [];
|
||||
while (numDays > 0) {
|
||||
hours.push(day.getTime() - (1000 * 60 * 60 * 24 * (numDays - 1)));
|
||||
numDays -= 1;
|
||||
}
|
||||
return daysArr;
|
||||
|
||||
return await Promise.all(hours.map(getHourlyStats));
|
||||
};
|
||||
|
||||
Analytics.getUnwrittenPageviews = function () {
|
||||
|
||||
@@ -307,18 +307,17 @@ async function isPrivilegedOrSelfAndPasswordMatch(caller, data) {
|
||||
async function processDeletion({ uid, method, password, caller }) {
|
||||
const isTargetAdmin = await user.isAdministrator(uid);
|
||||
const isSelf = parseInt(uid, 10) === parseInt(caller.uid, 10);
|
||||
const isAdmin = await user.isAdministrator(caller.uid);
|
||||
const hasAdminPrivilege = await privileges.admin.can('admin:users', caller.uid);
|
||||
|
||||
if (isSelf && meta.config.allowAccountDelete !== 1) {
|
||||
throw new Error('[[error:account-deletion-disabled]]');
|
||||
} else if (!isSelf && !isAdmin) {
|
||||
} else if (!isSelf && !hasAdminPrivilege) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
} else if (isTargetAdmin) {
|
||||
throw new Error('[[error:cant-delete-admin]');
|
||||
}
|
||||
|
||||
// Privilege checks -- only deleteAccount is available for non-admins
|
||||
const hasAdminPrivilege = await privileges.admin.can('admin:users', caller.uid);
|
||||
if (!hasAdminPrivilege && ['delete', 'deleteContent'].includes(method)) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
@@ -444,6 +443,10 @@ usersAPI.changePicture = async (caller, data) => {
|
||||
};
|
||||
|
||||
usersAPI.generateExport = async (caller, { uid, type }) => {
|
||||
const validTypes = ['profile', 'posts', 'uploads'];
|
||||
if (!validTypes.includes(type)) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
const count = await db.incrObjectField('locks', `export:${uid}${type}`);
|
||||
if (count > 1) {
|
||||
throw new Error('[[error:already-exporting]]');
|
||||
|
||||
@@ -95,11 +95,9 @@ module.exports = function (Categories) {
|
||||
await privileges.categories.give(result.modPrivileges, category.cid, ['administrators', 'Global Moderators']);
|
||||
await privileges.categories.give(result.guestPrivileges, category.cid, ['guests', 'spiders']);
|
||||
|
||||
cache.del([
|
||||
'categories:cid',
|
||||
`cid:${parentCid}:children`,
|
||||
`cid:${parentCid}:children:all`,
|
||||
]);
|
||||
cache.del('categories:cid');
|
||||
await clearParentCategoryCache(parentCid);
|
||||
|
||||
if (data.cloneFromCid && parseInt(data.cloneFromCid, 10)) {
|
||||
category = await Categories.copySettingsFrom(data.cloneFromCid, category.cid, !data.parentCid);
|
||||
}
|
||||
@@ -112,6 +110,22 @@ module.exports = function (Categories) {
|
||||
return category;
|
||||
};
|
||||
|
||||
async function clearParentCategoryCache(parentCid) {
|
||||
while (parseInt(parentCid, 10) >= 0) {
|
||||
cache.del([
|
||||
`cid:${parentCid}:children`,
|
||||
`cid:${parentCid}:children:all`,
|
||||
]);
|
||||
|
||||
if (parseInt(parentCid, 10) === 0) {
|
||||
return;
|
||||
}
|
||||
// clear all the way to root
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
parentCid = await Categories.getCategoryField(parentCid, 'parentCid');
|
||||
}
|
||||
}
|
||||
|
||||
async function duplicateCategoriesChildren(parentCid, cid, uid) {
|
||||
let children = await Categories.getChildren([cid], uid);
|
||||
if (!children.length) {
|
||||
|
||||
@@ -5,7 +5,6 @@ const _ = require('lodash');
|
||||
|
||||
const db = require('../database');
|
||||
const user = require('../user');
|
||||
const groups = require('../groups');
|
||||
const plugins = require('../plugins');
|
||||
const privileges = require('../privileges');
|
||||
const cache = require('../cache');
|
||||
@@ -99,31 +98,7 @@ Categories.getModerators = async function (cid) {
|
||||
};
|
||||
|
||||
Categories.getModeratorUids = async function (cids) {
|
||||
const groupNames = cids.reduce((memo, cid) => {
|
||||
memo.push(`cid:${cid}:privileges:moderate`);
|
||||
memo.push(`cid:${cid}:privileges:groups:moderate`);
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
const memberSets = await groups.getMembersOfGroups(groupNames);
|
||||
// Every other set is actually a list of user groups, not uids, so convert those to members
|
||||
const sets = memberSets.reduce((memo, set, idx) => {
|
||||
if (idx % 2) {
|
||||
memo.groupNames.push(set);
|
||||
} else {
|
||||
memo.uids.push(set);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, { groupNames: [], uids: [] });
|
||||
|
||||
const uniqGroups = _.uniq(_.flatten(sets.groupNames));
|
||||
const groupUids = await groups.getMembersOfGroups(uniqGroups);
|
||||
const map = _.zipObject(uniqGroups, groupUids);
|
||||
const moderatorUids = cids.map(
|
||||
(cid, index) => _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))))
|
||||
);
|
||||
return moderatorUids;
|
||||
return await privileges.categories.getUidsWithPrivilege(cids, 'moderate');
|
||||
};
|
||||
|
||||
Categories.getCategories = async function (cids, uid) {
|
||||
|
||||
@@ -51,6 +51,16 @@ try {
|
||||
packageInstall.preserveExtraneousPlugins();
|
||||
packageInstall.installAll();
|
||||
|
||||
// delete the module from require cache so it doesn't break rest of the upgrade
|
||||
// https://github.com/NodeBB/NodeBB/issues/11173
|
||||
const packages = ['nconf', 'async', 'commander', 'chalk', 'lodash', 'lru-cache'];
|
||||
packages.forEach((packageName) => {
|
||||
const resolvedModule = require.resolve(packageName);
|
||||
if (require.cache[resolvedModule]) {
|
||||
delete require.cache[resolvedModule];
|
||||
}
|
||||
});
|
||||
|
||||
const chalk = require('chalk');
|
||||
console.log(`${chalk.green('OK')}\n`);
|
||||
} else {
|
||||
@@ -175,9 +185,10 @@ program
|
||||
program
|
||||
.command('install [plugin]')
|
||||
.description('Launch the NodeBB web installer for configuration setup or install a plugin')
|
||||
.action((plugin) => {
|
||||
.option('-f, --force', 'Force plugin installation even if it may be incompatible with currently installed NodeBB version')
|
||||
.action((plugin, options) => {
|
||||
if (plugin) {
|
||||
require('./manage').install(plugin);
|
||||
require('./manage').install(plugin, options);
|
||||
} else {
|
||||
require('./setup').webInstall();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,10 @@ const analytics = require('../analytics');
|
||||
const reset = require('./reset');
|
||||
const { pluginNamePattern, themeNamePattern, paths } = require('../constants');
|
||||
|
||||
async function install(plugin) {
|
||||
async function install(plugin, options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
try {
|
||||
await db.init();
|
||||
if (!pluginNamePattern.test(plugin)) {
|
||||
@@ -31,7 +34,11 @@ async function install(plugin) {
|
||||
const nbbVersion = require(paths.currentPackage).version;
|
||||
const suggested = await plugins.suggest(plugin, nbbVersion);
|
||||
if (!suggested.version) {
|
||||
throw new Error(suggested.message);
|
||||
if (!options.force) {
|
||||
throw new Error(suggested.message);
|
||||
}
|
||||
winston.warn(`${suggested.message} Proceeding with installation anyway due to force option being provided`);
|
||||
suggested.version = 'latest';
|
||||
}
|
||||
winston.info('Installing Plugin `%s@%s`', plugin, suggested.version);
|
||||
await plugins.toggleInstall(plugin, suggested.version);
|
||||
|
||||
@@ -45,10 +45,11 @@ notificationsController.get = async function (req, res, next) {
|
||||
{ separator: true },
|
||||
]).concat(filters.moderatorFilters);
|
||||
}
|
||||
const selectedFilter = allFilters.find((filterData) => {
|
||||
|
||||
allFilters.forEach((filterData) => {
|
||||
filterData.selected = filterData.filter === filter;
|
||||
return filterData.selected;
|
||||
});
|
||||
const selectedFilter = allFilters.find(filterData => filterData.selected);
|
||||
if (!selectedFilter) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -128,12 +128,13 @@ async function getStats() {
|
||||
}
|
||||
|
||||
let results = await Promise.all([
|
||||
getStatsForSet('ip:recent', 'uniqueIPCount'),
|
||||
getStatsFromAnalytics('uniquevisitors', 'uniqueIPCount'),
|
||||
getStatsFromAnalytics('logins', 'loginCount'),
|
||||
getStatsForSet('users:joindate', 'userCount'),
|
||||
getStatsForSet('posts:pid', 'postCount'),
|
||||
getStatsForSet('topics:tid', 'topicCount'),
|
||||
]);
|
||||
|
||||
results[0].name = '[[admin/dashboard:unique-visitors]]';
|
||||
|
||||
results[1].name = '[[admin/dashboard:logins]]';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const validator = require('validator');
|
||||
const db = require('../../database');
|
||||
const events = require('../../events');
|
||||
const pagination = require('../../pagination');
|
||||
@@ -39,6 +40,12 @@ eventsController.get = async function (req, res) {
|
||||
events: eventData,
|
||||
pagination: pagination.create(page, pageCount, req.query),
|
||||
types: types,
|
||||
query: req.query,
|
||||
query: {
|
||||
start: validator.escape(String(req.query.start)),
|
||||
end: validator.escape(String(req.query.end)),
|
||||
username: validator.escape(String(req.query.username)),
|
||||
group: validator.escape(String(req.query.group)),
|
||||
perPage: validator.escape(String(req.query.perPage)),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -119,11 +119,49 @@ uploadsController.uploadCategoryPicture = async function (req, res, next) {
|
||||
}
|
||||
|
||||
if (validateUpload(res, uploadedFile, allowedImageTypes)) {
|
||||
if (uploadedFile.path.endsWith('.svg')) {
|
||||
await sanitizeSvg(uploadedFile.path);
|
||||
}
|
||||
const filename = `category-${params.cid}${path.extname(uploadedFile.name)}`;
|
||||
await uploadImage(filename, 'category', uploadedFile, req, res, next);
|
||||
}
|
||||
};
|
||||
|
||||
async function sanitizeSvg(filePath) {
|
||||
const dirty = await fs.promises.readFile(filePath, 'utf8');
|
||||
const clean = sanitizeHtml(dirty, {
|
||||
allowedTags: [
|
||||
'svg', 'g', 'defs', 'linearGradient', 'radialGradient', 'stop',
|
||||
'circle', 'ellipse', 'polygon', 'polyline', 'path', 'rect',
|
||||
'line', 'text', 'tspan', 'use', 'symbol', 'clipPath', 'mask', 'pattern',
|
||||
'filter', 'feGaussianBlur', 'feOffset', 'feBlend', 'feColorMatrix', 'feMerge', 'feMergeNode',
|
||||
],
|
||||
allowedAttributes: {
|
||||
'*': [
|
||||
// Geometry
|
||||
'x', 'y', 'x1', 'x2', 'y1', 'y2', 'cx', 'cy', 'r', 'rx', 'ry',
|
||||
'width', 'height', 'd', 'points', 'viewBox', 'transform',
|
||||
|
||||
// Presentation
|
||||
'fill', 'stroke', 'stroke-width', 'opacity',
|
||||
'stop-color', 'stop-opacity', 'offset', 'style', 'class',
|
||||
|
||||
// Text
|
||||
'text-anchor', 'font-size', 'font-family',
|
||||
|
||||
// Misc
|
||||
'id', 'clip-path', 'mask', 'filter', 'gradientUnits', 'gradientTransform',
|
||||
'xmlns', 'preserveAspectRatio',
|
||||
],
|
||||
},
|
||||
parser: {
|
||||
lowerCaseTags: false,
|
||||
lowerCaseAttributeNames: false,
|
||||
},
|
||||
});
|
||||
await fs.promises.writeFile(filePath, clean);
|
||||
}
|
||||
|
||||
uploadsController.uploadFavicon = async function (req, res, next) {
|
||||
const uploadedFile = req.files.files[0];
|
||||
const allowedTypes = ['image/x-icon', 'image/vnd.microsoft.icon'];
|
||||
@@ -184,10 +222,6 @@ uploadsController.uploadMaskableIcon = async function (req, res, next) {
|
||||
}
|
||||
};
|
||||
|
||||
uploadsController.uploadLogo = async function (req, res, next) {
|
||||
await upload('site-logo', req, res, next);
|
||||
};
|
||||
|
||||
uploadsController.uploadFile = async function (req, res, next) {
|
||||
const uploadedFile = req.files.files[0];
|
||||
let params;
|
||||
@@ -208,6 +242,10 @@ uploadsController.uploadFile = async function (req, res, next) {
|
||||
}
|
||||
};
|
||||
|
||||
uploadsController.uploadLogo = async function (req, res, next) {
|
||||
await upload('site-logo', req, res, next);
|
||||
};
|
||||
|
||||
uploadsController.uploadDefaultAvatar = async function (req, res, next) {
|
||||
await upload('avatar-default', req, res, next);
|
||||
};
|
||||
@@ -220,6 +258,9 @@ async function upload(name, req, res, next) {
|
||||
const uploadedFile = req.files.files[0];
|
||||
|
||||
if (validateUpload(res, uploadedFile, allowedImageTypes)) {
|
||||
if (uploadedFile.path.endsWith('.svg')) {
|
||||
await sanitizeSvg(uploadedFile.path);
|
||||
}
|
||||
const filename = name + path.extname(uploadedFile.name);
|
||||
await uploadImage(filename, 'system', uploadedFile, req, res, next);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ const categories = require('../categories');
|
||||
const plugins = require('../plugins');
|
||||
const translator = require('../translator');
|
||||
const languages = require('../languages');
|
||||
const { generateToken } = require('../middleware/csrf');
|
||||
|
||||
const apiController = module.exports;
|
||||
|
||||
@@ -64,7 +65,7 @@ apiController.loadConfig = async function (req) {
|
||||
'cache-buster': meta.config['cache-buster'] || '',
|
||||
topicPostSort: meta.config.topicPostSort || 'oldest_to_newest',
|
||||
categoryTopicSort: meta.config.categoryTopicSort || 'newest_to_oldest',
|
||||
csrf_token: req.uid >= 0 && req.csrfToken && req.csrfToken(),
|
||||
csrf_token: req.uid >= 0 ? generateToken(req) : undefined,
|
||||
searchEnabled: plugins.hooks.hasListeners('filter:search.query'),
|
||||
searchDefaultInQuick: meta.config.searchDefaultInQuick || 'titles',
|
||||
bootswatchSkin: meta.config.bootswatchSkin || '',
|
||||
|
||||
@@ -339,7 +339,7 @@ authenticationController.doLogin = async function (req, uid) {
|
||||
return;
|
||||
}
|
||||
const loginAsync = util.promisify(req.login).bind(req);
|
||||
await loginAsync({ uid: uid }, { keepSessionInfo: req.res.locals !== false });
|
||||
await loginAsync({ uid: uid }, { keepSessionInfo: req.res.locals.reroll !== false });
|
||||
await authenticationController.onSuccessfulLogin(req, uid);
|
||||
};
|
||||
|
||||
@@ -383,7 +383,7 @@ authenticationController.onSuccessfulLogin = async function (req, uid) {
|
||||
}),
|
||||
user.auth.addSession(uid, req.sessionID),
|
||||
user.updateLastOnlineTime(uid),
|
||||
user.updateOnlineUsers(uid),
|
||||
user.onUserOnline(uid, Date.now()),
|
||||
analytics.increment('logins'),
|
||||
db.incrObjectFieldBy('global', 'loginCount', 1),
|
||||
]);
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const validator = require('validator');
|
||||
|
||||
const user = require('../user');
|
||||
const groups = require('../groups');
|
||||
const posts = require('../posts');
|
||||
const flags = require('../flags');
|
||||
const analytics = require('../analytics');
|
||||
@@ -38,9 +42,9 @@ modsController.flags.list = async function (req, res) {
|
||||
filters = filters.reduce((memo, cur) => {
|
||||
if (req.query.hasOwnProperty(cur)) {
|
||||
if (typeof req.query[cur] === 'string' && req.query[cur].trim() !== '') {
|
||||
memo[cur] = req.query[cur].trim();
|
||||
memo[cur] = validator.escape(String(req.query[cur].trim()));
|
||||
} else if (Array.isArray(req.query[cur]) && req.query[cur].length) {
|
||||
memo[cur] = req.query[cur];
|
||||
memo[cur] = req.query[cur].map(item => validator.escape(String(item).trim()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +114,6 @@ modsController.flags.detail = async function (req, res, next) {
|
||||
isAdminOrGlobalMod: user.isAdminOrGlobalMod(req.uid),
|
||||
moderatedCids: user.getModeratedCids(req.uid),
|
||||
flagData: flags.get(req.params.flagId),
|
||||
assignees: user.getAdminsandGlobalModsandModerators(),
|
||||
privileges: Promise.all(['global', 'admin'].map(async type => privileges[type].get(req.uid))),
|
||||
});
|
||||
results.privileges = { ...results.privileges[0], ...results.privileges[1] };
|
||||
@@ -119,6 +122,28 @@ modsController.flags.detail = async function (req, res, next) {
|
||||
return next(); // 404
|
||||
}
|
||||
|
||||
async function getAssignees(flagData) {
|
||||
let uids = [];
|
||||
const [admins, globalMods] = await Promise.all([
|
||||
groups.getMembers('administrators', 0, -1),
|
||||
groups.getMembers('Global Moderators', 0, -1),
|
||||
]);
|
||||
if (flagData.type === 'user') {
|
||||
uids = await privileges.admin.getUidsWithPrivilege('admin:users');
|
||||
uids = _.uniq(admins.concat(uids));
|
||||
} else if (flagData.type === 'post') {
|
||||
const cid = await posts.getCidByPid(flagData.targetId);
|
||||
uids = _.uniq(admins.concat(globalMods));
|
||||
if (cid) {
|
||||
const modUids = (await privileges.categories.getUidsWithPrivilege([cid], 'moderate'))[0];
|
||||
uids = _.uniq(uids.concat(modUids));
|
||||
}
|
||||
}
|
||||
const userData = await user.getUsersData(uids);
|
||||
return userData.filter(u => u && u.userslug);
|
||||
}
|
||||
|
||||
const assignees = await getAssignees(results.flagData);
|
||||
results.flagData.history = results.isAdminOrGlobalMod ? (await flags.getHistory(req.params.flagId)) : null;
|
||||
|
||||
if (results.flagData.type === 'user') {
|
||||
@@ -128,7 +153,7 @@ modsController.flags.detail = async function (req, res, next) {
|
||||
}
|
||||
|
||||
res.render('flags/detail', Object.assign(results.flagData, {
|
||||
assignees: results.assignees,
|
||||
assignees: assignees,
|
||||
type_bool: ['post', 'user', 'empty'].reduce((memo, cur) => {
|
||||
if (cur !== 'empty') {
|
||||
memo[cur] = results.flagData.type === cur && (
|
||||
@@ -141,6 +166,7 @@ modsController.flags.detail = async function (req, res, next) {
|
||||
|
||||
return memo;
|
||||
}, {}),
|
||||
states: Object.fromEntries(flags._states),
|
||||
title: `[[pages:flag-details, ${req.params.flagId}]]`,
|
||||
privileges: results.privileges,
|
||||
breadcrumbs: helpers.buildBreadcrumbs([
|
||||
|
||||
@@ -105,8 +105,8 @@ topicsController.get = async function getTopic(req, res, next) {
|
||||
|
||||
topicData.postIndex = postIndex;
|
||||
|
||||
await Promise.all([
|
||||
buildBreadcrumbs(topicData),
|
||||
const [author] = await Promise.all([
|
||||
user.getUserFields(topicData.uid, ['username', 'userslug']),
|
||||
addOldCategory(topicData, userPrivileges),
|
||||
addTags(topicData, req, res),
|
||||
incrementViewCount(req, tid),
|
||||
@@ -114,6 +114,7 @@ topicsController.get = async function getTopic(req, res, next) {
|
||||
analytics.increment([`pageviews:byCid:${topicData.category.cid}`]),
|
||||
]);
|
||||
|
||||
topicData.author = author;
|
||||
topicData.pagination = pagination.create(currentPage, pageCount, req.query);
|
||||
topicData.pagination.rel.forEach((rel) => {
|
||||
rel.href = `${url}/topic/${topicData.slug}${rel.href}`;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const validator = require('validator');
|
||||
|
||||
const db = require('../../database');
|
||||
const api = require('../../api');
|
||||
const topics = require('../../topics');
|
||||
const privileges = require('../../privileges');
|
||||
@@ -17,19 +18,39 @@ Topics.get = async (req, res) => {
|
||||
};
|
||||
|
||||
Topics.create = async (req, res) => {
|
||||
const payload = await api.topics.create(req, req.body);
|
||||
if (payload.queued) {
|
||||
helpers.formatApiResponse(202, res, payload);
|
||||
} else {
|
||||
helpers.formatApiResponse(200, res, payload);
|
||||
const id = await lockPosting(req, '[[error:already-posting]]');
|
||||
try {
|
||||
const payload = await api.topics.create(req, req.body);
|
||||
if (payload.queued) {
|
||||
helpers.formatApiResponse(202, res, payload);
|
||||
} else {
|
||||
helpers.formatApiResponse(200, res, payload);
|
||||
}
|
||||
} finally {
|
||||
await db.deleteObjectField('locks', id);
|
||||
}
|
||||
};
|
||||
|
||||
Topics.reply = async (req, res) => {
|
||||
const payload = await api.topics.reply(req, { ...req.body, tid: req.params.tid });
|
||||
helpers.formatApiResponse(200, res, payload);
|
||||
const id = await lockPosting(req, '[[error:already-posting]]');
|
||||
try {
|
||||
const payload = await api.topics.reply(req, { ...req.body, tid: req.params.tid });
|
||||
helpers.formatApiResponse(200, res, payload);
|
||||
} finally {
|
||||
await db.deleteObjectField('locks', id);
|
||||
}
|
||||
};
|
||||
|
||||
async function lockPosting(req, error) {
|
||||
const id = req.uid > 0 ? req.uid : req.sessionID;
|
||||
const value = `posting${id}`;
|
||||
const count = await db.incrObjectField('locks', value);
|
||||
if (count > 1) {
|
||||
throw new Error(error);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Topics.delete = async (req, res) => {
|
||||
await api.topics.delete(req, { tids: [req.params.tid] });
|
||||
helpers.formatApiResponse(200, res);
|
||||
|
||||
@@ -26,7 +26,7 @@ module.exports = function (module) {
|
||||
|
||||
async function getSortedSetUnion(params) {
|
||||
if (!Array.isArray(params.sets) || !params.sets.length) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
let limit = params.stop - params.start + 1;
|
||||
if (limit <= 0) {
|
||||
|
||||
@@ -629,9 +629,9 @@ SELECT z."value",
|
||||
ON o."_key" = z."_key"
|
||||
AND o."type" = z."type"
|
||||
WHERE o."_key" = $1::TEXT
|
||||
AND z."value" LIKE '${match}'
|
||||
AND z."value" LIKE $3
|
||||
LIMIT $2::INTEGER`,
|
||||
values: [params.key, params.limit],
|
||||
values: [params.key, params.limit, match],
|
||||
});
|
||||
if (!params.withScores) {
|
||||
return res.rows.map(r => r.value);
|
||||
|
||||
@@ -32,6 +32,9 @@ SELECT COUNT(DISTINCT z."value") c
|
||||
|
||||
async function getSortedSetUnion(params) {
|
||||
const { sets } = params;
|
||||
if (!sets || !sets.length) {
|
||||
return [];
|
||||
}
|
||||
const start = params.hasOwnProperty('start') ? params.start : 0;
|
||||
const stop = params.hasOwnProperty('stop') ? params.stop : -1;
|
||||
let weights = params.weights || [];
|
||||
|
||||
36
src/flags.js
36
src/flags.js
@@ -20,15 +20,24 @@ const batch = require('./batch');
|
||||
|
||||
const Flags = module.exports;
|
||||
|
||||
Flags._constants = {
|
||||
states: ['open', 'wip', 'resolved', 'rejected'],
|
||||
state_class: {
|
||||
open: 'info',
|
||||
wip: 'warning',
|
||||
resolved: 'success',
|
||||
rejected: 'danger',
|
||||
},
|
||||
};
|
||||
Flags._states = new Map([
|
||||
['open', {
|
||||
label: '[[flags:state-open]]',
|
||||
class: 'danger',
|
||||
}],
|
||||
['wip', {
|
||||
label: '[[flags:state-wip]]',
|
||||
class: 'warning',
|
||||
}],
|
||||
['resolved', {
|
||||
label: '[[flags:state-resolved]]',
|
||||
class: 'success',
|
||||
}],
|
||||
['rejected', {
|
||||
label: '[[flags:state-rejected]]',
|
||||
class: 'secondary',
|
||||
}],
|
||||
]);
|
||||
|
||||
Flags.init = async function () {
|
||||
// Query plugins for custom filter strategies and merge into core filter strategies
|
||||
@@ -78,14 +87,15 @@ Flags.init = async function () {
|
||||
}
|
||||
},
|
||||
},
|
||||
states: Flags._states,
|
||||
helpers: {
|
||||
prepareSets: prepareSets,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const data = await plugins.hooks.fire('filter:flags.getFilters', hookData);
|
||||
Flags._filters = data.filters;
|
||||
({ filters: Flags._filters } = await plugins.hooks.fire('filter:flags.getFilters', hookData));
|
||||
({ filters: Flags._filters, states: Flags._states } = await plugins.hooks.fire('filter:flags.init', hookData));
|
||||
} catch (err) {
|
||||
winston.error(`[flags/init] Could not retrieve filters\n${err.stack}`);
|
||||
Flags._filters = {};
|
||||
@@ -197,7 +207,7 @@ Flags.list = async function (data) {
|
||||
heat: reportCounts[idx],
|
||||
...flagObj,
|
||||
};
|
||||
flagObj.labelClass = Flags._constants.state_class[flagObj.state];
|
||||
flagObj.labelClass = Flags._states.get(flagObj.state).class;
|
||||
|
||||
return Object.assign(flagObj, {
|
||||
target_readable: `${flagObj.type.charAt(0).toUpperCase() + flagObj.type.slice(1)} ${flagObj.targetId}`,
|
||||
@@ -674,7 +684,7 @@ Flags.update = async function (flagId, uid, changeset) {
|
||||
if (current[prop] === changeset[prop]) {
|
||||
delete changeset[prop];
|
||||
} else if (prop === 'state') {
|
||||
if (!Flags._constants.states.includes(changeset[prop])) {
|
||||
if (!Flags._states.has(changeset[prop])) {
|
||||
delete changeset[prop];
|
||||
} else {
|
||||
tasks.push(db.sortedSetAdd(`flags:byState:${changeset[prop]}`, now, flagId));
|
||||
|
||||
@@ -40,14 +40,24 @@ async function linkModules() {
|
||||
await Promise.all(Object.keys(modules).map(async (relPath) => {
|
||||
const srcPath = path.join(__dirname, '../../', modules[relPath]);
|
||||
const destPath = path.join(__dirname, '../../build/public/src/modules', relPath);
|
||||
const destDir = path.dirname(destPath);
|
||||
|
||||
const [stats] = await Promise.all([
|
||||
fs.promises.stat(srcPath),
|
||||
mkdirp(path.dirname(destPath)),
|
||||
mkdirp(destDir),
|
||||
]);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
await file.linkDirs(srcPath, destPath, true);
|
||||
} else {
|
||||
await fs.promises.copyFile(srcPath, destPath);
|
||||
// Get the relative path to the destination directory
|
||||
const relPath = path.relative(destDir, srcPath)
|
||||
// and convert to a posix path
|
||||
.split(path.sep).join(path.posix.sep);
|
||||
|
||||
// Instead of copying file, create a new file re-exporting it
|
||||
// This way, imports in modules are resolved correctly
|
||||
await fs.promises.writeFile(destPath, `module.exports = require('${relPath}');`);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ Themes.set = async (data) => {
|
||||
await db.sortedSetAdd('plugins:active', numPlugins, data.id);
|
||||
} else if (!activePluginsConfig.includes(data.id)) {
|
||||
// This prevents changing theme when configuration doesn't include it, but allows it otherwise
|
||||
winston.error('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');
|
||||
winston.error(`When defining active plugins in configuration, changing themes requires adding the theme '${data.id}' to the list of active plugins before updating it in the ACP`);
|
||||
throw new Error('[[error:theme-not-set-in-configuration]]');
|
||||
}
|
||||
|
||||
|
||||
26
src/middleware/csrf.js
Normal file
26
src/middleware/csrf.js
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
const { csrfSync } = require('csrf-sync');
|
||||
|
||||
const {
|
||||
generateToken,
|
||||
csrfSynchronisedProtection,
|
||||
isRequestValid,
|
||||
} = csrfSync({
|
||||
getTokenFromRequest: (req) => {
|
||||
if (req.headers['x-csrf-token']) {
|
||||
return req.headers['x-csrf-token'];
|
||||
} else if (req.body && req.body.csrf_token) {
|
||||
return req.body.csrf_token;
|
||||
} else if (req.query) {
|
||||
return req.query._csrf;
|
||||
}
|
||||
},
|
||||
size: 64,
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
generateToken,
|
||||
csrfSynchronisedProtection,
|
||||
isRequestValid,
|
||||
};
|
||||
@@ -34,10 +34,11 @@ middleware.buildHeader = helpers.try(async (req, res, next) => {
|
||||
if (req.method === 'GET') {
|
||||
await require('./index').applyCSRFasync(req, res);
|
||||
}
|
||||
|
||||
({ req, locals: res.locals } = await plugins.hooks.fire('filter:middleware.buildHeader', { req: req, locals: res.locals }));
|
||||
const [config, canLoginIfBanned] = await Promise.all([
|
||||
controllers.api.loadConfig(req),
|
||||
user.bans.canLoginIfBanned(req.uid),
|
||||
plugins.hooks.fire('filter:middleware.buildHeader', { req: req, locals: res.locals }),
|
||||
]);
|
||||
|
||||
if (!canLoginIfBanned && req.loggedIn) {
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
const async = require('async');
|
||||
const path = require('path');
|
||||
const csrf = require('csurf');
|
||||
const validator = require('validator');
|
||||
const nconf = require('nconf');
|
||||
const toobusy = require('toobusy-js');
|
||||
const util = require('util');
|
||||
const { csrfSynchronisedProtection } = require('./csrf');
|
||||
|
||||
const plugins = require('../plugins');
|
||||
const meta = require('../meta');
|
||||
@@ -34,7 +34,7 @@ middleware.regexes = {
|
||||
timestampedUpload: /^\d+-.+$/,
|
||||
};
|
||||
|
||||
const csrfMiddleware = csrf();
|
||||
const csrfMiddleware = csrfSynchronisedProtection;
|
||||
|
||||
middleware.applyCSRF = function (req, res, next) {
|
||||
if (req.uid >= 0) {
|
||||
@@ -102,11 +102,20 @@ middleware.pluginHooks = helpers.try(async (req, res, next) => {
|
||||
});
|
||||
|
||||
middleware.validateFiles = function validateFiles(req, res, next) {
|
||||
if (!Array.isArray(req.files.files) || !req.files.files.length) {
|
||||
if (!req.files.files) {
|
||||
return next(new Error(['[[error:invalid-files]]']));
|
||||
}
|
||||
|
||||
next();
|
||||
if (Array.isArray(req.files.files) && req.files.files.length) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (typeof req.files.files === 'object') {
|
||||
req.files.files = [req.files.files];
|
||||
return next();
|
||||
}
|
||||
|
||||
return next(new Error(['[[error:invalid-files]]']));
|
||||
};
|
||||
|
||||
middleware.prepareAPI = function prepareAPI(req, res, next) {
|
||||
|
||||
@@ -37,7 +37,7 @@ module.exports = function (middleware) {
|
||||
const loginAsync = util.promisify(req.login).bind(req);
|
||||
await loginAsync(user, { keepSessionInfo: true });
|
||||
await controllers.authentication.onSuccessfulLogin(req, user.uid);
|
||||
req.uid = user.uid;
|
||||
req.uid = parseInt(user.uid, 10);
|
||||
req.loggedIn = req.uid > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,11 @@ Hooks._deprecated = new Map([
|
||||
since: 'v2.2.0',
|
||||
until: 'v3.0.0',
|
||||
}],
|
||||
['filter:flags.getFilters', {
|
||||
new: 'filter:flags.init',
|
||||
since: 'v2.7.0',
|
||||
until: 'v3.0.0',
|
||||
}],
|
||||
]);
|
||||
|
||||
Hooks.internals = {
|
||||
|
||||
@@ -66,6 +66,7 @@ privsAdmin.routeMap = {
|
||||
uploadDefaultAvatar: 'admin:settings',
|
||||
};
|
||||
privsAdmin.routePrefixMap = {
|
||||
'dashboard/': 'admin:dashboard',
|
||||
'manage/categories/': 'admin:categories',
|
||||
'manage/privileges/': 'admin:privileges',
|
||||
'manage/groups/': 'admin:groups',
|
||||
@@ -210,3 +211,8 @@ privsAdmin.groupPrivileges = async function (groupName) {
|
||||
const groupPrivilegeList = await privsAdmin.getGroupPrivilegeList();
|
||||
return await helpers.userOrGroupPrivileges(0, groupName, groupPrivilegeList);
|
||||
};
|
||||
|
||||
privsAdmin.getUidsWithPrivilege = async function (privilege) {
|
||||
const uidsByCid = await helpers.getUidsWithPrivilege([0], privilege);
|
||||
return uidsByCid[0];
|
||||
};
|
||||
|
||||
@@ -218,3 +218,7 @@ privsCategories.groupPrivileges = async function (cid, groupName) {
|
||||
const groupPrivilegeList = await privsCategories.getGroupPrivilegeList();
|
||||
return await helpers.userOrGroupPrivileges(cid, groupName, groupPrivilegeList);
|
||||
};
|
||||
|
||||
privsCategories.getUidsWithPrivilege = async function (cids, privilege) {
|
||||
return await helpers.getUidsWithPrivilege(cids, privilege);
|
||||
};
|
||||
|
||||
@@ -134,3 +134,8 @@ privsGlobal.groupPrivileges = async function (groupName) {
|
||||
const groupPrivilegeList = await privsGlobal.getGroupPrivilegeList();
|
||||
return await helpers.userOrGroupPrivileges(0, groupName, groupPrivilegeList);
|
||||
};
|
||||
|
||||
privsGlobal.getUidsWithPrivilege = async function (privilege) {
|
||||
const uidsByCid = await helpers.getUidsWithPrivilege([0], privilege);
|
||||
return uidsByCid[0];
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ const validator = require('validator');
|
||||
|
||||
const groups = require('../groups');
|
||||
const user = require('../user');
|
||||
const categories = require('../categories');
|
||||
const plugins = require('../plugins');
|
||||
const translator = require('../translator');
|
||||
|
||||
@@ -189,4 +190,38 @@ helpers.userOrGroupPrivileges = async function (cid, uidOrGroup, privilegeList)
|
||||
return _.zipObject(privilegeList, isMembers);
|
||||
};
|
||||
|
||||
helpers.getUidsWithPrivilege = async (cids, privilege) => {
|
||||
const disabled = (await categories.getCategoriesFields(cids, ['disabled'])).map(obj => obj.disabled);
|
||||
|
||||
const groupNames = cids.reduce((memo, cid) => {
|
||||
memo.push(`cid:${cid}:privileges:${privilege}`);
|
||||
memo.push(`cid:${cid}:privileges:groups:${privilege}`);
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
const memberSets = await groups.getMembersOfGroups(groupNames);
|
||||
// Every other set is actually a list of user groups, not uids, so convert those to members
|
||||
const sets = memberSets.reduce((memo, set, idx) => {
|
||||
if (idx % 2) {
|
||||
memo.groupNames.push(set);
|
||||
} else {
|
||||
memo.uids.push(set);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, { groupNames: [], uids: [] });
|
||||
|
||||
const uniqGroups = _.uniq(_.flatten(sets.groupNames));
|
||||
const groupUids = await groups.getMembersOfGroups(uniqGroups);
|
||||
const map = _.zipObject(uniqGroups, groupUids);
|
||||
const uidsByCid = cids.map((cid, index) => {
|
||||
if (disabled[index]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))));
|
||||
});
|
||||
return uidsByCid;
|
||||
};
|
||||
|
||||
require('../promisify')(helpers);
|
||||
|
||||
@@ -10,6 +10,7 @@ const meta = require('../meta');
|
||||
const controllers = require('../controllers');
|
||||
const helpers = require('../controllers/helpers');
|
||||
const plugins = require('../plugins');
|
||||
const { generateToken } = require('../middleware/csrf');
|
||||
|
||||
let loginStrategies = [];
|
||||
|
||||
@@ -108,7 +109,7 @@ Auth.reloadRoutes = async function (params) {
|
||||
};
|
||||
|
||||
if (strategy.checkState !== false) {
|
||||
req.session.ssoState = req.csrfToken && req.csrfToken();
|
||||
req.session.ssoState = generateToken(req, true);
|
||||
opts.state = req.session.ssoState;
|
||||
}
|
||||
|
||||
@@ -154,7 +155,7 @@ Auth.reloadRoutes = async function (params) {
|
||||
}, Auth.middleware.validateAuth, (req, res, next) => {
|
||||
async.waterfall([
|
||||
async.apply(req.login.bind(req), res.locals.user, { keepSessionInfo: true }),
|
||||
async.apply(controllers.authentication.onSuccessfulLogin, req, req.uid),
|
||||
async.apply(controllers.authentication.onSuccessfulLogin, req, res.locals.user.uid),
|
||||
], (err) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
|
||||
@@ -9,11 +9,12 @@ const topics = require('../topics');
|
||||
const user = require('../user');
|
||||
const categories = require('../categories');
|
||||
const meta = require('../meta');
|
||||
const helpers = require('../controllers/helpers');
|
||||
const controllerHelpers = require('../controllers/helpers');
|
||||
const privileges = require('../privileges');
|
||||
const db = require('../database');
|
||||
const utils = require('../utils');
|
||||
const controllers404 = require('../controllers/404');
|
||||
const routeHelpers = require('./helpers');
|
||||
|
||||
const terms = {
|
||||
daily: 'day',
|
||||
@@ -23,18 +24,18 @@ const terms = {
|
||||
};
|
||||
|
||||
module.exports = function (app, middleware) {
|
||||
app.get('/topic/:topic_id.rss', middleware.maintenanceMode, generateForTopic);
|
||||
app.get('/category/:category_id.rss', middleware.maintenanceMode, generateForCategory);
|
||||
app.get('/topics.rss', middleware.maintenanceMode, generateForTopics);
|
||||
app.get('/recent.rss', middleware.maintenanceMode, generateForRecent);
|
||||
app.get('/top.rss', middleware.maintenanceMode, generateForTop);
|
||||
app.get('/top/:term.rss', middleware.maintenanceMode, generateForTop);
|
||||
app.get('/popular.rss', middleware.maintenanceMode, generateForPopular);
|
||||
app.get('/popular/:term.rss', middleware.maintenanceMode, generateForPopular);
|
||||
app.get('/recentposts.rss', middleware.maintenanceMode, generateForRecentPosts);
|
||||
app.get('/category/:category_id/recentposts.rss', middleware.maintenanceMode, generateForCategoryRecentPosts);
|
||||
app.get('/user/:userslug/topics.rss', middleware.maintenanceMode, generateForUserTopics);
|
||||
app.get('/tags/:tag.rss', middleware.maintenanceMode, generateForTag);
|
||||
app.get('/topic/:topic_id.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTopic));
|
||||
app.get('/category/:category_id.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForCategory));
|
||||
app.get('/topics.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTopics));
|
||||
app.get('/recent.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForRecent));
|
||||
app.get('/top.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTop));
|
||||
app.get('/top/:term.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTop));
|
||||
app.get('/popular.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForPopular));
|
||||
app.get('/popular/:term.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForPopular));
|
||||
app.get('/recentposts.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForRecentPosts));
|
||||
app.get('/category/:category_id/recentposts.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForCategoryRecentPosts));
|
||||
app.get('/user/:userslug/topics.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForUserTopics));
|
||||
app.get('/tags/:tag.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTag));
|
||||
};
|
||||
|
||||
async function validateTokenIfRequiresLogin(requiresLogin, cid, req, res) {
|
||||
@@ -46,16 +47,16 @@ async function validateTokenIfRequiresLogin(requiresLogin, cid, req, res) {
|
||||
}
|
||||
|
||||
if (uid <= 0 || !token) {
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
const userToken = await db.getObjectField(`user:${uid}`, 'rss_token');
|
||||
if (userToken !== token) {
|
||||
await user.auth.logAttempt(uid, req.ip);
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
const userPrivileges = await privileges.categories.get(cid, uid);
|
||||
if (!userPrivileges.read) {
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -127,7 +128,7 @@ async function generateForCategory(req, res, next) {
|
||||
db.getSortedSetRevIntersect({
|
||||
sets: ['topics:tid', `cid:${cid}:tids:lastposttime`],
|
||||
start: 0,
|
||||
stop: 25,
|
||||
stop: 24,
|
||||
weights: [1, 0],
|
||||
}),
|
||||
]);
|
||||
@@ -230,7 +231,7 @@ async function generateSorted(options, req, res, next) {
|
||||
const { cid } = req.query;
|
||||
if (cid) {
|
||||
if (!await privileges.categories.can('topics:read', cid, uid)) {
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
params.cids = [cid];
|
||||
}
|
||||
|
||||
@@ -79,7 +79,11 @@ sitemap.getPages = async function () {
|
||||
|
||||
async function getSitemapCategories() {
|
||||
const cids = await categories.getCidsByPrivilege('categories:cid', 0, 'find');
|
||||
return await categories.getCategoriesFields(cids, ['slug']);
|
||||
const categoryData = await categories.getCategoriesFields(cids, ['slug']);
|
||||
const data = await plugins.hooks.fire('filter:sitemap.getCategories', {
|
||||
categories: categoryData,
|
||||
});
|
||||
return data.categories;
|
||||
}
|
||||
|
||||
sitemap.getCategories = async function () {
|
||||
@@ -128,7 +132,12 @@ sitemap.getTopicPage = async function (page) {
|
||||
tids = await privileges.topics.filterTids('topics:read', tids, 0);
|
||||
const topicData = await topics.getTopicsFields(tids, ['tid', 'title', 'slug', 'lastposttime']);
|
||||
|
||||
if (!topicData.length) {
|
||||
const data = await plugins.hooks.fire('filter:sitemap.getCategories', {
|
||||
page: page,
|
||||
topics: topicData,
|
||||
});
|
||||
|
||||
if (!data.topics.length) {
|
||||
sitemap.maps.topics[page - 1] = {
|
||||
sm: '',
|
||||
cacheExpireTimestamp: Date.now() + (1000 * 60 * 60 * 24),
|
||||
@@ -136,7 +145,7 @@ sitemap.getTopicPage = async function (page) {
|
||||
return sitemap.maps.topics[page - 1].sm;
|
||||
}
|
||||
|
||||
topicData.forEach((topic) => {
|
||||
data.topics.forEach((topic) => {
|
||||
if (topic) {
|
||||
topicUrls.push({
|
||||
url: `${nconf.get('relative_path')}/topic/${topic.slug}`,
|
||||
|
||||
@@ -34,13 +34,25 @@ Sockets.init = async function (server) {
|
||||
}
|
||||
}
|
||||
|
||||
io.use(authorize);
|
||||
|
||||
io.on('connection', onConnection);
|
||||
|
||||
const opts = {
|
||||
transports: nconf.get('socket.io:transports') || ['polling', 'websocket'],
|
||||
cookie: false,
|
||||
allowRequest: (req, callback) => {
|
||||
authorize(req, (err) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
const csrf = require('../middleware/csrf');
|
||||
const isValid = csrf.isRequestValid({
|
||||
session: req.session || {},
|
||||
query: req._query,
|
||||
headers: req.headers,
|
||||
});
|
||||
callback(null, isValid);
|
||||
});
|
||||
},
|
||||
};
|
||||
/*
|
||||
* Restrict socket.io listener to cookie domain. If none is set, infer based on url.
|
||||
@@ -62,7 +74,11 @@ Sockets.init = async function (server) {
|
||||
};
|
||||
|
||||
function onConnection(socket) {
|
||||
socket.ip = (socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress || '').split(',')[0];
|
||||
socket.uid = socket.request.uid;
|
||||
socket.ip = (
|
||||
socket.request.headers['x-forwarded-for'] ||
|
||||
socket.request.connection.remoteAddress || ''
|
||||
).split(',')[0];
|
||||
socket.request.ip = socket.ip;
|
||||
logger.io_one(socket, socket.uid);
|
||||
|
||||
@@ -112,43 +128,49 @@ async function onMessage(socket, payload) {
|
||||
return winston.warn('[socket.io] Empty payload');
|
||||
}
|
||||
|
||||
const eventName = payload.data[0];
|
||||
let eventName = payload.data[0];
|
||||
const params = typeof payload.data[1] === 'function' ? {} : payload.data[1];
|
||||
const callback = typeof payload.data[payload.data.length - 1] === 'function' ? payload.data[payload.data.length - 1] : function () {};
|
||||
|
||||
if (!eventName) {
|
||||
return winston.warn('[socket.io] Empty method name');
|
||||
}
|
||||
|
||||
const parts = eventName.toString().split('.');
|
||||
const namespace = parts[0];
|
||||
const methodToCall = parts.reduce((prev, cur) => {
|
||||
if (prev !== null && prev[cur]) {
|
||||
return prev[cur];
|
||||
}
|
||||
return null;
|
||||
}, Namespaces);
|
||||
|
||||
if (!methodToCall || typeof methodToCall !== 'function') {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
winston.warn(`[socket.io] Unrecognized message: ${eventName}`);
|
||||
}
|
||||
const escapedName = validator.escape(String(eventName));
|
||||
return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
|
||||
}
|
||||
|
||||
socket.previousEvents = socket.previousEvents || [];
|
||||
socket.previousEvents.push(eventName);
|
||||
if (socket.previousEvents.length > 20) {
|
||||
socket.previousEvents.shift();
|
||||
}
|
||||
|
||||
if (!eventName.startsWith('admin.') && ratelimit.isFlooding(socket)) {
|
||||
winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`);
|
||||
return socket.disconnect();
|
||||
}
|
||||
|
||||
try {
|
||||
if (!eventName) {
|
||||
return winston.warn('[socket.io] Empty method name');
|
||||
}
|
||||
|
||||
if (typeof eventName !== 'string') {
|
||||
eventName = typeof eventName;
|
||||
const escapedName = validator.escape(eventName);
|
||||
return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
|
||||
}
|
||||
|
||||
const parts = eventName.split('.');
|
||||
const namespace = parts[0];
|
||||
const methodToCall = parts.reduce((prev, cur) => {
|
||||
if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) {
|
||||
return prev[cur];
|
||||
}
|
||||
return null;
|
||||
}, Namespaces);
|
||||
|
||||
if (!methodToCall || typeof methodToCall !== 'function') {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
winston.warn(`[socket.io] Unrecognized message: ${eventName}`);
|
||||
}
|
||||
const escapedName = validator.escape(String(eventName));
|
||||
return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
|
||||
}
|
||||
|
||||
socket.previousEvents = socket.previousEvents || [];
|
||||
socket.previousEvents.push(eventName);
|
||||
if (socket.previousEvents.length > 20) {
|
||||
socket.previousEvents.shift();
|
||||
}
|
||||
|
||||
if (!eventName.startsWith('admin.') && ratelimit.isFlooding(socket)) {
|
||||
winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`);
|
||||
return socket.disconnect();
|
||||
}
|
||||
|
||||
await checkMaintenance(socket);
|
||||
await validateSession(socket, '[[error:revalidate-failure]]');
|
||||
|
||||
@@ -225,9 +247,7 @@ async function validateSession(socket, errorMsg) {
|
||||
|
||||
const cookieParserAsync = util.promisify((req, callback) => cookieParser(req, {}, err => callback(err)));
|
||||
|
||||
async function authorize(socket, callback) {
|
||||
const { request } = socket;
|
||||
|
||||
async function authorize(request, callback) {
|
||||
if (!request) {
|
||||
return callback(new Error('[[error:not-authorized]]'));
|
||||
}
|
||||
@@ -240,15 +260,13 @@ async function authorize(socket, callback) {
|
||||
});
|
||||
|
||||
const sessionData = await getSessionAsync(sessionId);
|
||||
|
||||
request.session = sessionData;
|
||||
let uid = 0;
|
||||
if (sessionData && sessionData.passport && sessionData.passport.user) {
|
||||
request.session = sessionData;
|
||||
socket.uid = parseInt(sessionData.passport.user, 10);
|
||||
} else {
|
||||
socket.uid = 0;
|
||||
uid = parseInt(sessionData.passport.user, 10);
|
||||
}
|
||||
request.uid = socket.uid;
|
||||
callback();
|
||||
request.uid = uid;
|
||||
callback(null, uid);
|
||||
}
|
||||
|
||||
Sockets.in = function (room) {
|
||||
|
||||
@@ -14,15 +14,15 @@ const utils = require('../../utils');
|
||||
|
||||
module.exports = function (SocketPosts) {
|
||||
SocketPosts.loadPostTools = async function (socket, data) {
|
||||
if (!data || !data.pid || !data.cid) {
|
||||
if (!data || !data.pid) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
const cid = await posts.getCidByPid(data.pid);
|
||||
const results = await utils.promiseParallel({
|
||||
posts: posts.getPostFields(data.pid, ['deleted', 'bookmarks', 'uid', 'ip', 'flagId']),
|
||||
isAdmin: user.isAdministrator(socket.uid),
|
||||
isGlobalMod: user.isGlobalModerator(socket.uid),
|
||||
isModerator: user.isModerator(socket.uid, data.cid),
|
||||
isModerator: user.isModerator(socket.uid, cid),
|
||||
canEdit: privileges.posts.canEdit(data.pid, socket.uid),
|
||||
canDelete: privileges.posts.canDelete(data.pid, socket.uid),
|
||||
canPurge: privileges.posts.canPurge(data.pid, socket.uid),
|
||||
|
||||
@@ -74,6 +74,6 @@ module.exports = function (SocketUser) {
|
||||
|
||||
await user.isAdminOrSelf(socket.uid, data.uid);
|
||||
|
||||
api.users.generateExport(socket, { type, ...data });
|
||||
api.users.generateExport(socket, { type, uid: data.uid });
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user