Compare commits

..

89 Commits

Author SHA1 Message Date
Misty Release Bot
82f0efb14b chore: incrementing version number - v2.8.11 2023-04-11 01:49:11 +00:00
Opliko
c27567289f ci: publish to ghcr instead of docker hub 2023-04-05 14:38:47 -04:00
Julian Lam
c33730530e Revert "docs: update readme with new screenshot and updated copy for Harmony"
This reverts commit 67055006df.
2023-03-29 10:32:05 -04:00
Julian Lam
67055006df docs: update readme with new screenshot and updated copy for Harmony 2023-03-29 10:31:39 -04:00
Barış Soner Uşaklı
e0b2065802 test: update socket.io test 2023-03-28 08:15:42 -04:00
Barış Soner Uşaklı
4d2d76897a fix: don't crash on objects with toString property 2023-03-28 08:08:59 -04:00
Barış Soner Uşaklı
7397873db3 fix: fire action:user.online on user login 2023-03-27 22:16:41 -04:00
Misty Release Bot
188ec62f9a chore: update changelog for v2.8.10 2023-03-27 18:10:57 +00:00
Misty Release Bot
48c1c7594d chore: incrementing version number - v2.8.10 2023-03-27 18:10:57 +00:00
Julian Lam
830f142b7a fix: #11403, remove loader.js crash counter logic 2023-03-27 10:55:44 -04:00
Barış Soner Uşaklı
1aff9cad91 lint: fix arrow 2023-03-27 10:47:15 -04:00
Barış Soner Uşaklı
37b48b82a4 fix: don't crash if event name is not a string 2023-03-27 10:38:53 -04:00
Barış Soner Uşaklı
e9a8e19508 chore: up composer-default 2023-03-21 10:13:21 -04:00
Barış Soner Uşaklı
894f392bfc lint: whitespace 2023-03-20 11:17:05 -04:00
Barış Soner Uşaklı
c2961ad4cd fix: closes #11173, move cache clear code
if 2 deps were updated only one of them was cleared from require.cache. ie commander & lru-cache both has major version bump then only commander would be cleared from cache since it throws first
2023-03-20 11:05:48 -04:00
Misty Release Bot
18b2150edd chore: update changelog for v2.8.9 2023-03-19 16:31:26 +00:00
Misty Release Bot
fb100ac731 chore: incrementing version number - v2.8.9 2023-03-19 16:31:26 +00:00
Barış Soner Uşaklı
73a50d1718 chore: up cron 2023-03-19 12:21:06 -04:00
Julian Lam
93aa43f717 style: more fixes 2023-03-17 15:48:44 -04:00
Phạm Tấn Minh Tiến
9ed6961af8 fix lint 2023-03-17 15:48:44 -04:00
Phạm Tấn Minh Tiến
4b94c033c4 wrap quotes to prevent stripping leading 0 2023-03-17 15:48:44 -04:00
Barış Soner Uşaklı
9e685e657a test: openapi for thumbs 2023-03-15 15:18:05 -04:00
Barış Soner Uşaklı
767c1d1faf fix: thumb remove on windows, closes #11357 2023-03-14 15:09:12 -04:00
Barış Soner Uşaklı
a3a38e4ba3 fix: #11357 clear cache on thumb remove 2023-03-14 14:30:46 -04:00
Barış Soner Uşaklı
cfd5027245 fix: closes #11352, try/catch rss feeds 2023-03-11 16:07:02 -05:00
Barış Soner Uşaklı
56427e4f9d fix: closes #11343, don't crash if tags array is empty 2023-03-10 11:40:02 -05:00
Misty Release Bot
c03d5db71e chore: update changelog for v2.8.8 2023-03-09 14:58:28 +00:00
Misty Release Bot
f5a59991fc chore: incrementing version number - v2.8.8 2023-03-09 14:58:28 +00:00
Julian Lam
22fc8fe38f fix: stop topic navigation hotkeys from firing if in a mousetrap-enabled form element 2023-03-09 09:55:32 -05:00
Julian Lam
17d0b40efa fix: stop topic navigation hotkeys from firing if in a mousetrap-enabled form element 2023-03-09 09:44:06 -05:00
Barış Soner Uşaklı
1545223e7f fix: tag filtering when changing filter to watched topics
or changing popular time limit to month
2023-03-08 18:28:55 -05:00
Barış Soner Uşaklı
f054a4f44d fix: get cid from pid instead of passing in 2023-03-06 09:44:21 -05:00
Barış Soner Uşaklı
8c762d3228 fix: closes #11331, allow 0 length content if set to 0 in acp 2023-03-03 09:30:51 -05:00
Misty Release Bot
2ca38e7b95 chore: update changelog for v2.8.7 2023-03-01 15:51:30 +00:00
Misty Release Bot
6976925943 chore: incrementing version number - v2.8.7 2023-03-01 15:51:30 +00:00
Barış Soner Uşaklı
791551098c fix: display 25 topics on category feed 2023-02-27 09:47:28 -05:00
Barış Soner Uşaklı
ec58700f6d fix: object destructuring overwriting type parameter
also check for valid types in generateExport
2023-02-27 09:10:53 -05:00
Barış Soner Uşaklı
8cf4a6f62e fix: alert on page load 2023-02-24 13:40:37 -05:00
Eldor
3bd9a87154 fix: show error alert if password change fails 2023-02-22 09:06:51 -05:00
gasoved
edd2fc38fc fix: update main post timestamp when rescheduling 2023-02-16 14:10:07 -05:00
Julian Lam
1b29dbb69d test: add dummy emailer hook in authentication test 2023-02-13 12:15:45 -05:00
Julian Lam
40e7b86da9 docs: update openapi spec to include info about passing in timestamps for topic creation, removing timestamp as valid request param for topic replying 2023-02-13 11:44:54 -05:00
Barış Soner Uşaklı
326b92687f fix: show admins/globalmods if content is purged 2023-02-08 17:35:38 -05:00
Barış Soner Uşaklı
e335d0f601 fix: email expiry timestamps
emailConfirmExpiry is hours and default is 24
2023-02-08 13:22:16 -05:00
Barış Soner Uşaklı
845c8013b6 fix: #11259, clean old emails when updating via admin (#11260)
when admin is changing users emails check if its avaiable and remove old email of user first
upgrade script to cleanup email:uid, email:sorted, will remove entries if user doesn't exist or doesn't have email or if entry in user hash doesn't match entry in email:uid
fix missing ! in email interstitial
fix missing await in canSendValidation,
fix broken tests
dont pass sessionId to email.remove if admin is changing/removing email
2023-02-06 10:45:01 -05:00
Julian Lam
7a5bcc2171 fix: #11257, onSuccessfulLogin called with improper uid 2023-02-03 16:01:31 -05:00
Misty Release Bot
f3306d038a chore: update changelog for v2.8.6 2023-02-03 16:39:40 +00:00
Misty Release Bot
76732140f3 chore: incrementing version number - v2.8.6 2023-02-03 16:39:40 +00:00
Barış Soner Uşaklı
bf92ee0e5f feat: add sitemap filter hooks for categories/topic pages 2023-02-03 09:46:02 -05:00
Misty Release Bot
8335f90ae0 chore(i18n): fallback strings for new resources: nodebb.error 2023-02-02 13:37:19 -05:00
nesro
202378b939 fix: #11254, return check for reroll property 2023-02-02 09:15:04 -05:00
Barış Soner Uşaklı
705cd13ad3 fix: closes #11249, notification uses displayname 2023-01-31 17:27:25 -05:00
Julian Lam
b5598a6e5d fix: wrong link to topics in acp dashboard 2023-01-30 15:05:57 -05:00
Barış Soner Uşaklı
c241baf641 feat: closes #11241, add missing error lang keys 2023-01-30 12:40:24 -05:00
Barış Soner Uşaklı
d68352cce5 lint: remove unused 2023-01-30 12:35:08 -05:00
Barış Soner Uşaklı
0713482bd4 feat: #11240, only show relevant users in flags assignee list
for user flags-> admins + all users who have `admin:users` privilege
for post flags -> admins + global mods + moderators of the category the post is in
refactor getModeratorUids function so it can be used for different privileges
2023-01-30 12:26:08 -05:00
Barış Soner Uşaklı
1d3c0e5a2b fix: https://github.com/NodeBB/NodeBB/issues/11239
parseInt uid received from req.body._uid or req.query._uid
2023-01-30 11:48:10 -05:00
Barış Soner Uşaklı
6d819b056e fix: notif filter selecte field 2023-01-30 10:43:02 -05:00
Misty Release Bot
24e58c2895 chore: update changelog for v2.8.5 2023-01-27 14:35:25 +00:00
Misty Release Bot
93ccf604db chore: incrementing version number - v2.8.5 2023-01-27 14:35:24 +00:00
Peter Jaszkowiak
f6c96948fe fix: import resolution within plugin modules (#11219)
use module.exports = require('..')
export * from '..' didn't work in some cases
2023-01-27 09:17:38 -05:00
Misty Release Bot
c13f0e2128 chore: update changelog for v2.8.4 2023-01-26 14:38:07 +00:00
Misty Release Bot
b9553613ab chore: incrementing version number - v2.8.4 2023-01-26 14:38:06 +00:00
Barış Soner Uşaklı
c3653bee60 Revert "fix: import resolution within plugin modules (#11200)"
This reverts commit 89e059a084.
2023-01-26 09:27:16 -05:00
Misty Release Bot
eb2841eed3 chore: update changelog for v2.8.3 2023-01-25 19:37:34 +00:00
Misty Release Bot
4c46ff42f6 chore: incrementing version number - v2.8.3 2023-01-25 19:37:33 +00:00
Peter Jaszkowiak
89e059a084 fix: import resolution within plugin modules (#11200) 2023-01-24 19:59:06 -05:00
Julian Lam
fecd84d1a0 revert: a788bd1344 2023-01-23 15:19:47 -05:00
Julian Lam
00e48803a6 fix(deps): downgrade swagger-parser to v9 2023-01-23 15:19:40 -05:00
Julian Lam
a788bd1344 revert: 9c250b78b0, fix: comment out broken test for now 2023-01-23 12:51:42 -05:00
Barış Soner Uşaklı
9f38692369 Merge branch 'master' of https://github.com/NodeBB/NodeBB 2023-01-23 11:40:22 -05:00
Barış Soner Uşaklı
0bffd3d93c fix: #11195, allow users with admin:users privilege to delete users in acp 2023-01-23 11:40:17 -05:00
Julian Lam
9c250b78b0 fix(deps): pinning sub dependency json-schema-ref-parser to 9.0.9
ref: https://github.com/APIDevTools/json-schema-ref-parser/issues/298
2023-01-23 11:28:03 -05:00
Barış Soner Uşaklı
7d04e95226 fix: #11194, allow access to sub dashboard pages 2023-01-23 11:09:19 -05:00
Julian Lam
f295174e07 test: fix broken test 2023-01-23 09:58:51 -05:00
Julian Lam
459bc52338 fix: #11136, tests, and returning the proper number of arrays 2023-01-18 15:08:35 -05:00
Julian Lam
39e009c05a fix: #11136, only show mods of active categories when getModeratorUids is called 2023-01-18 14:47:10 -05:00
Barış Soner Uşaklı
747cb1f0a1 fix: closes #11173, clear require cache if wrong dependency is installed 2023-01-18 09:40:00 -05:00
Julian Lam
48c9f4470f chore: remove extraneous lines from changelog 2023-01-13 13:38:45 -05:00
Misty Release Bot
66aa31698f chore: update changelog for v2.8.2 2023-01-13 18:38:13 +00:00
Misty Release Bot
1d5eff2365 chore: incrementing version number - v2.8.2 2023-01-13 18:38:12 +00:00
Julian Lam
25ae58e8a0 fix: move call to filter:middleware.buildHeader out of parallel so that req can be overridden by plugins prior to loading config 2023-01-13 09:53:14 -05:00
Misty Release Bot
d17d4ec09b chore: update changelog for v2.8.1 2022-12-30 20:48:48 +00:00
Misty Release Bot
96bdbf52b8 chore: incrementing version number - v2.8.1 2022-12-30 20:48:47 +00:00
Julian Lam
8a69e740a8 chore: fallbacks for new language string 2022-12-30 15:35:01 -05:00
Barış Soner Uşaklı
586eed1407 fix: vulnerability in socket.io nested namespaces (#11117) 2022-12-30 09:49:22 -05:00
Barış Soner Uşaklı
1ea9481af6 fix: lock post/reply similar to user.create 2022-12-25 15:05:15 -05:00
Julian Lam
bbaf26cedc chore: remove extraneous lines from changelog 2022-12-21 17:11:53 -05:00
Misty Release Bot
a5c2edb993 chore: update changelog for v2.8.0 2022-12-21 22:10:49 +00:00
102 changed files with 1165 additions and 204 deletions

View File

@@ -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}}

View File

@@ -1,3 +1,437 @@
#### 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)
* incrementing version number - v2.8.8 (b331b942)
* incrementing version number - v2.8.7 (3f8248d6)
* incrementing version number - v2.8.6 (af6ce447)
* incrementing version number - v2.8.5 (bff5ce2d)
* incrementing version number - v2.8.4 (a46b2bbc)
* incrementing version number - v2.8.3 (c20b20a7)
* incrementing version number - v2.8.2 (050e43f8)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
##### 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)
* incrementing version number - v2.8.7 (3f8248d6)
* incrementing version number - v2.8.6 (af6ce447)
* incrementing version number - v2.8.5 (bff5ce2d)
* incrementing version number - v2.8.4 (a46b2bbc)
* incrementing version number - v2.8.3 (c20b20a7)
* incrementing version number - v2.8.2 (050e43f8)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
##### 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)
* incrementing version number - v2.8.6 (af6ce447)
* incrementing version number - v2.8.5 (bff5ce2d)
* incrementing version number - v2.8.4 (a46b2bbc)
* incrementing version number - v2.8.3 (c20b20a7)
* incrementing version number - v2.8.2 (050e43f8)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
##### 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)
* incrementing version number - v2.8.5 (bff5ce2d)
* incrementing version number - v2.8.4 (a46b2bbc)
* incrementing version number - v2.8.3 (c20b20a7)
* incrementing version number - v2.8.2 (050e43f8)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
##### 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)
* incrementing version number - v2.8.4 (a46b2bbc)
* incrementing version number - v2.8.3 (c20b20a7)
* incrementing version number - v2.8.2 (050e43f8)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
##### 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)
* incrementing version number - v2.8.3 (c20b20a7)
* incrementing version number - v2.8.2 (050e43f8)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
##### 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)
* incrementing version number - v2.8.2 (050e43f8)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
#### 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)
* incrementing version number - v2.8.1 (727f879e)
* incrementing version number - v2.8.0 (8e77673d)
* incrementing version number - v2.7.0 (96cc0617)
* incrementing version number - v2.6.1 (7e52a7a5)
* incrementing version number - v2.6.0 (e7fcf482)
* incrementing version number - v2.5.8 (dec0e7de)
* incrementing version number - v2.5.7 (5836bf4a)
* incrementing version number - v2.5.6 (c7bd7dbf)
* incrementing version number - v2.5.5 (3509ed94)
* incrementing version number - v2.5.4 (e83260ca)
* incrementing version number - v2.5.3 (7e922936)
* incrementing version number - v2.5.2 (babcd17e)
* incrementing version number - v2.5.1 (ce3aa950)
* incrementing version number - v2.5.0 (01d276cb)
* incrementing version number - v2.4.5 (dd3e1a28)
* incrementing version number - v2.4.4 (d5525c87)
* incrementing version number - v2.4.3 (9c647c6c)
* incrementing version number - v2.4.2 (3aa7b855)
* incrementing version number - v2.4.1 (60cbd148)
* incrementing version number - v2.4.0 (4834cde3)
* incrementing version number - v2.3.1 (d2425942)
* incrementing version number - v2.3.0 (046ea120)
##### 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

View File

@@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPL-3.0",
"description": "NodeBB Forum",
"version": "2.8.0",
"version": "2.8.11",
"homepage": "http://www.nodebb.org",
"repository": {
"type": "git",
@@ -53,7 +53,7 @@
"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",
"daemon": "1.1.0",
@@ -90,7 +90,7 @@
"@nodebb/bootswatch": "3.4.2",
"nconf": "0.12.0",
"nodebb-plugin-2factor": "5.1.2",
"nodebb-plugin-composer-default": "9.2.4",
"nodebb-plugin-composer-default": "9.2.5",
"nodebb-plugin-dbsearch": "5.1.5",
"nodebb-plugin-emoji": "4.0.6",
"nodebb-plugin-emoji-android": "3.0.0",
@@ -148,7 +148,7 @@
"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",

View File

@@ -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...');

View File

@@ -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": "التصويتات السلبية معطلة",

View File

@@ -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": "Отрицателното гласуване е изключено",

View File

@@ -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": "ঋণাত্মক ভোট নিস্ক্রীয় রাখা হয়েছে।",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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.",

View File

@@ -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": "Η καταψήφιση έχει απενεργοποιηθεί",

View File

@@ -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.",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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.",

View File

@@ -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",

View File

@@ -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": "رأی منفی غیر فعال شده است",

View File

@@ -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",

View File

@@ -62,6 +62,7 @@
"no-user": "Cet utilisateur n'existe pas",
"no-teaser": "Laperç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",

View File

@@ -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",

View File

@@ -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": "היכולת להצביע נגד מושבתת",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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": "Դեմ քվեարկությունն անջատված է",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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": "비추천 기능이 비활성 상태입니다.",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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ă",

View File

@@ -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": "Понижение рейтинга отключено",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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é",

View File

@@ -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.",

View File

@@ -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",

View File

@@ -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": "Негативно гласање је онемогућено",

View File

@@ -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",

View File

@@ -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": "\"การโหวตลง\" ถูกปิดใช้งาน",

View File

@@ -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ış. ",

View File

@@ -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": "Голосування проти вимкнено",

View File

@@ -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",

View File

@@ -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": "踩已被禁用",

View File

@@ -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": "倒讚已被停用",

View File

@@ -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

View File

@@ -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:

View File

@@ -46,8 +46,6 @@ post:
content:
type: string
example: This is a test reply
timestamp:
type: number
toPid:
type: number
required:

View File

@@ -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

View File

@@ -38,4 +38,4 @@ put:
$ref: ../../../../components/schemas/Status.yaml#/Status
response:
type: object
properties: {}
properties: {}

View File

@@ -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;

View File

@@ -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('');

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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]]');

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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();
}

View File

@@ -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),
]);

View File

@@ -1,6 +1,9 @@
'use strict';
const _ = require('lodash');
const user = require('../user');
const groups = require('../groups');
const posts = require('../posts');
const flags = require('../flags');
const analytics = require('../analytics');
@@ -110,7 +113,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 +121,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 +152,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 && (

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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 || [];

View File

@@ -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}');`);
}
}));
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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];
};

View File

@@ -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);
};

View File

@@ -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];
};

View File

@@ -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);

View File

@@ -154,7 +154,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);

View File

@@ -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];
}

View File

@@ -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}`,

View File

@@ -112,43 +112,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]]');

View File

@@ -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),

View File

@@ -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 });
}
};

View File

@@ -82,9 +82,8 @@ module.exports = function (Topics) {
data.title = String(data.title).trim();
data.tags = data.tags || [];
if (data.content) {
data.content = utils.rtrim(data.content);
}
data.content = String(data.content || '').trimEnd();
Topics.checkTitle(data.title);
await Topics.validateTags(data.tags, data.cid, uid);
data.tags = await Topics.filterTags(data.tags, data.cid);
@@ -167,9 +166,8 @@ module.exports = function (Topics) {
data.cid = topicData.cid;
await guestHandleValid(data);
if (data.content) {
data.content = utils.rtrim(data.content);
}
data.content = String(data.content || '').trimEnd();
if (!data.fromQueue) {
await user.isReadyToPost(uid, data.cid);
Topics.checkContent(data.content);

View File

@@ -60,6 +60,7 @@ Scheduled.pin = async function (tid, topicData) {
};
Scheduled.reschedule = async function ({ cid, tid, timestamp, uid }) {
const mainPid = await topics.getTopicField(tid, 'mainPid');
await Promise.all([
db.sortedSetsAdd([
'topics:scheduled',
@@ -67,6 +68,7 @@ Scheduled.reschedule = async function ({ cid, tid, timestamp, uid }) {
'topics:tid',
`cid:${cid}:uid:${uid}:tids`,
], timestamp, tid),
posts.setPostField(mainPid, 'timestamp', timestamp),
shiftPostTimes(tid, timestamp),
]);
return topics.updateLastPostTimeFromLastPid(tid);
@@ -87,14 +89,15 @@ function unpin(tid, topicData) {
}
async function sendNotifications(uids, topicsData) {
const usernames = await Promise.all(uids.map(uid => user.getUserField(uid, 'username')));
const uidToUsername = Object.fromEntries(uids.map((uid, idx) => [uid, usernames[idx]]));
const userData = await user.getUsersData(uids);
const uidToUserData = Object.fromEntries(uids.map((uid, idx) => [uid, userData[idx]]));
const postsData = await posts.getPostsData(topicsData.map(({ mainPid }) => mainPid));
const postsData = await posts.getPostsData(topicsData.map(t => t && t.mainPid));
postsData.forEach((postData, idx) => {
postData.user = {};
postData.user.username = uidToUsername[postData.uid];
postData.topic = topicsData[idx];
if (postData) {
postData.user = uidToUserData[topicsData[idx].uid];
postData.topic = topicsData[idx];
}
});
return Promise.all(topicsData.map(

View File

@@ -174,7 +174,7 @@ module.exports = function (Topics) {
}
tids = await privileges.topics.filterTids('topics:read', tids, uid);
let topicData = await Topics.getTopicsFields(tids, ['uid', 'tid', 'cid']);
let topicData = await Topics.getTopicsFields(tids, ['uid', 'tid', 'cid', 'tags']);
const topicCids = _.uniq(topicData.map(topic => topic.cid)).filter(Boolean);
async function getIgnoredCids() {
@@ -192,11 +192,13 @@ module.exports = function (Topics) {
topicData = filtered;
const cids = params.cids && params.cids.map(String);
const { tags } = params;
tids = topicData.filter(t => (
t &&
t.cid &&
!isCidIgnored[t.cid] &&
(!cids || cids.includes(String(t.cid)))
(!cids || cids.includes(String(t.cid))) &&
(!tags.length || tags.every(tag => t.tags.find(topicTag => topicTag.value === tag)))
)).map(t => t.tid);
const result = await plugins.hooks.fire('filter:topics.filterSortedTids', { tids: tids, params: params });

View File

@@ -287,7 +287,7 @@ module.exports = function (Topics) {
}
Topics.getTagData = async function (tags) {
if (!tags.length) {
if (!tags || !tags.length) {
return [];
}
tags.forEach((tag) => {

View File

@@ -52,6 +52,7 @@ Thumbs.get = async function (tids) {
const name = path.basename(thumb);
return hasTimestampPrefix.test(name) ? name.slice(14) : name;
})(),
path: thumb,
url: thumb.startsWith('http') ? thumb : path.posix.join(upload_url, thumb),
})));
@@ -151,6 +152,9 @@ Thumbs.delete = async function (id, relativePaths) {
Promise.all(toRemove.map(async relativePath => posts.uploads.dissociate(mainPid, relativePath.slice(1)))),
]);
}
if (toRemove.length) {
cache.del(set);
}
};
Thumbs.deleteAll = async (id) => {

View File

@@ -0,0 +1,46 @@
'use strict';
const db = require('../../database');
const batch = require('../../batch');
module.exports = {
name: 'Fix user email sorted sets',
timestamp: Date.UTC(2023, 1, 4),
method: async function () {
const { progress } = this;
const bulkRemove = [];
await batch.processSortedSet('email:uid', async (data) => {
progress.incr(data.length);
const usersData = await db.getObjects(data.map(d => `user:${d.score}`));
data.forEach((emailData, index) => {
const { score: uid, value: email } = emailData;
const userData = usersData[index];
// user no longer exists or doesn't have email set in user hash
// remove the email/uid pair from email:uid, email:sorted
if (!userData || !userData.email) {
bulkRemove.push(['email:uid', email]);
bulkRemove.push(['email:sorted', `${email.toLowerCase()}:${uid}`]);
return;
}
// user has email but doesn't match whats stored in user hash, gh#11259
if (userData.email && userData.email.toLowerCase() !== email.toLowerCase()) {
bulkRemove.push(['email:uid', email]);
bulkRemove.push(['email:sorted', `${email.toLowerCase()}:${uid}`]);
}
});
}, {
batch: 500,
withScores: true,
progress: progress,
});
await batch.processArray(bulkRemove, async (bulk) => {
await db.sortedSetRemoveBulk(bulk);
}, {
batch: 500,
});
},
};

View File

@@ -70,7 +70,9 @@ module.exports = function (User) {
let line = '';
usersData.forEach((user, index) => {
line += `${fields.map(field => user[field]).join(',')}`;
line += `${fields
.map(field => (isFinite(user[field]) ? `'${user[field]}'` : user[field]))
.join(',')}`;
if (showIps) {
userIPs = ips[index] ? ips[index].join(',') : '';
line += `,"${userIPs}"\n`;

View File

@@ -39,7 +39,7 @@ UserEmail.remove = async function (uid, sessionId) {
db.sortedSetRemove('email:uid', email.toLowerCase()),
db.sortedSetRemove('email:sorted', `${email.toLowerCase()}:${uid}`),
user.email.expireValidation(uid),
user.auth.revokeAllSessions(uid, sessionId),
sessionId ? user.auth.revokeAllSessions(uid, sessionId) : Promise.resolve(),
events.log({ type: 'email-change', email, newEmail: '' }),
]);
};
@@ -69,7 +69,7 @@ UserEmail.expireValidation = async (uid) => {
};
UserEmail.canSendValidation = async (uid, email) => {
const pending = UserEmail.isValidationPending(uid, email);
const pending = await UserEmail.isValidationPending(uid, email);
if (!pending) {
return true;
}
@@ -134,13 +134,13 @@ UserEmail.sendValidationEmail = async function (uid, options) {
await UserEmail.expireValidation(uid);
await db.set(`confirm:byUid:${uid}`, confirm_code);
await db.pexpire(`confirm:byUid:${uid}`, emailConfirmExpiry * 24 * 60 * 60 * 1000);
await db.pexpire(`confirm:byUid:${uid}`, emailConfirmExpiry * 60 * 60 * 1000);
await db.setObject(`confirm:${confirm_code}`, {
email: options.email.toLowerCase(),
uid: uid,
});
await db.pexpire(`confirm:${confirm_code}`, emailConfirmExpiry * 24 * 60 * 60 * 1000);
await db.pexpire(`confirm:${confirm_code}`, emailConfirmExpiry * 60 * 60 * 1000);
winston.verbose(`[user/email] Validation email for uid ${uid} sent to ${options.email}`);
events.log({
@@ -196,6 +196,20 @@ UserEmail.confirmByUid = async function (uid) {
throw new Error('[[error:invalid-email]]');
}
// If another uid has the same email throw error
const oldUid = await db.sortedSetScore('email:uid', currentEmail.toLowerCase());
if (oldUid && oldUid !== parseInt(uid, 10)) {
throw new Error('[[error:email-taken]]');
}
const confirmedEmails = await db.getSortedSetRangeByScore(`email:uid`, 0, -1, uid, uid);
if (confirmedEmails.length) {
// remove old email of user by uid
await db.sortedSetsRemoveRangeByScore([`email:uid`], uid, uid);
await db.sortedSetRemoveBulk(
confirmedEmails.map(email => [`email:sorted`, `${email.toLowerCase()}:${uid}`])
);
}
await Promise.all([
db.sortedSetAddBulk([
['email:uid', uid, currentEmail.toLowerCase()],

View File

@@ -42,6 +42,7 @@ Interstitials.email = async (data) => {
callback: async (userData, formData) => {
// Validate and send email confirmation
if (userData.uid) {
const isSelf = parseInt(userData.uid, 10) === parseInt(data.req.uid, 10);
const [isPasswordCorrect, canEdit, { email: current, 'email:confirmed': confirmed }, { allowed, error }] = await Promise.all([
user.isPasswordCorrect(userData.uid, formData.password, data.req.ip),
privileges.users.canEdit(data.req.uid, userData.uid),
@@ -68,13 +69,17 @@ Interstitials.email = async (data) => {
if (formData.email === current) {
if (confirmed) {
throw new Error('[[error:email-nochange]]');
} else if (await user.email.canSendValidation(userData.uid, current)) {
} else if (!await user.email.canSendValidation(userData.uid, current)) {
throw new Error(`[[error:confirm-email-already-sent, ${meta.config.emailConfirmInterval}]]`);
}
}
// Admins editing will auto-confirm, unless editing their own email
if (isAdminOrGlobalMod && userData.uid !== data.req.uid) {
if (!await user.email.available(formData.email)) {
throw new Error('[[error:email-taken]]');
}
await user.email.remove(userData.uid);
await user.setUserField(userData.uid, 'email', formData.email);
await user.email.confirmByUid(userData.uid);
} else if (canEdit) {
@@ -99,8 +104,8 @@ Interstitials.email = async (data) => {
}
if (current.length && (!hasPassword || (hasPassword && isPasswordCorrect) || isAdminOrGlobalMod)) {
// User explicitly clearing their email
await user.email.remove(userData.uid, data.req.session.id);
// User or admin explicitly clearing their email
await user.email.remove(userData.uid, isSelf ? data.req.session.id : null);
}
}
} else {

View File

@@ -27,9 +27,13 @@ module.exports = function (User) {
if (now - parseInt(userOnlineTime, 10) < 300000) {
return;
}
await db.sortedSetAdd('users:online', now, uid);
await User.onUserOnline(uid, now);
topics.pushUnreadCount(uid);
plugins.hooks.fire('action:user.online', { uid: uid, timestamp: now });
};
User.onUserOnline = async (uid, timestamp) => {
await db.sortedSetAdd('users:online', timestamp, uid);
plugins.hooks.fire('action:user.online', { uid, timestamp });
};
User.isOnline = async function (uid) {

View File

@@ -17,7 +17,7 @@
{{{ end }}}
{{{ each topics }}}
<tr>
<td><a href="{config.relative_path}/topics/{../slug}">{../title}</a></td>
<td><a href="{config.relative_path}/topic/{../slug}">{../title}</a></td>
<td>[[topic:posted_by, {../user.username}]]</td>
<td><span class="timeago" data-title="{../timestampISO}"></span></td>
</tr>

View File

@@ -150,7 +150,7 @@
[[admin/settings/email:smtp-transport.gmail-warning2]]
</p>
</div>
<div class="form-group well" id="email:smtpTransport:custom-service" style="display: none">
<div class="form-group well" id="email:smtpTransport:custom-service">
<h5>Custom Service</h5>
<label for="email:smtpTransport:host">[[admin/settings/email:smtp-transport.host]]</label>

View File

@@ -3,7 +3,7 @@
<div class="alert alert-info">[[modules:thumbs.modal.no-thumbs]]</div>
{{{ end }}}
{{{ each thumbs }}}
<div class="media" data-id="{./id}" data-path="{./url}">
<div class="media" data-id="{./id}" data-path="{./path}">
<div class="media-left">
<img class="media-object" src="{./url}" alt="" />
</div>

View File

@@ -12,13 +12,22 @@ const db = require('./mocks/databasemock');
const user = require('../src/user');
const utils = require('../src/utils');
const meta = require('../src/meta');
const plugins = require('../src/plugins');
const privileges = require('../src/privileges');
const helpers = require('./helpers');
describe('authentication', () => {
const jar = request.jar();
let regularUid;
const dummyEmailerHook = async (data) => {};
before((done) => {
// Attach an emailer hook so related requests do not error
plugins.hooks.register('authentication-test', {
hook: 'filter:email.send',
method: dummyEmailerHook,
});
user.create({ username: 'regular', password: 'regularpwd', email: 'regular@nodebb.org' }, (err, uid) => {
assert.ifError(err);
regularUid = uid;
@@ -27,6 +36,10 @@ describe('authentication', () => {
});
});
after(() => {
plugins.hooks.unregister('authentication-test', 'filter:email.send');
});
it('should allow login with email for uid 1', async () => {
const oldValue = meta.config.allowLoginWith;
meta.config.allowLoginWith = 'username-email';

View File

@@ -827,16 +827,17 @@ describe('Categories', () => {
});
describe('Categories.getModeratorUids', () => {
before((done) => {
async.series([
async.apply(groups.create, { name: 'testGroup' }),
async.apply(groups.join, 'cid:1:privileges:groups:moderate', 'testGroup'),
async.apply(groups.join, 'testGroup', 1),
], done);
let cid;
before(async () => {
({ cid } = await Categories.create({ name: 'foobar' }));
await groups.create({ name: 'testGroup' });
await groups.join(`cid:${cid}:privileges:groups:moderate`, 'testGroup');
await groups.join('testGroup', 1);
});
it('should retrieve all users with moderator bit in category privilege', (done) => {
Categories.getModeratorUids([1, 2], (err, uids) => {
Categories.getModeratorUids([cid, 2], (err, uids) => {
assert.ifError(err);
assert.strictEqual(uids.length, 2);
assert(uids[0].includes('1'));
@@ -851,7 +852,7 @@ describe('Categories', () => {
async.apply(groups.join, 'cid:1:privileges:groups:moderate', 'testGroup2'),
async.apply(groups.join, 'testGroup2', 1),
function (next) {
Categories.getModeratorUids([1, 2], (err, uids) => {
Categories.getModeratorUids([cid, 2], (err, uids) => {
assert.ifError(err);
assert(uids[0].includes('1'));
next();
@@ -860,10 +861,18 @@ describe('Categories', () => {
], done);
});
it('should not return moderators of disabled categories', async () => {
const payload = {};
payload[cid] = { disabled: 1 };
await Categories.update(payload);
const uids = await Categories.getModeratorUids([cid, 2]);
assert(!uids[0].includes('1'));
});
after((done) => {
async.series([
async.apply(groups.leave, 'cid:1:privileges:groups:moderate', 'testGroup'),
async.apply(groups.leave, 'cid:1:privileges:groups:moderate', 'testGroup2'),
async.apply(groups.leave, `cid:${cid}:privileges:groups:moderate`, 'testGroup'),
async.apply(groups.leave, `cid:${cid}:privileges:groups:moderate`, 'testGroup2'),
async.apply(groups.destroy, 'testGroup'),
async.apply(groups.destroy, 'testGroup2'),
], done);

View File

@@ -996,6 +996,11 @@ describe('Sorted Set methods', () => {
done();
});
});
it('should return empty array if sets is empty', async () => {
const result = await db.getSortedSetRevUnion({ sets: [], start: 0, stop: -1 });
assert.deepStrictEqual(result, []);
});
});
describe('sortedSetIncrBy()', () => {

View File

@@ -91,6 +91,30 @@ describe('socket.io', () => {
});
});
it('should return error for unknown event', (done) => {
io.emit('user.gdpr.__proto__.constructor.toString', (err) => {
assert(err);
assert.equal(err.message, '[[error:invalid-event, user.gdpr.__proto__.constructor.toString]]');
done();
});
});
it('should return error for unknown event', (done) => {
io.emit('constructor.toString', (err) => {
assert(err);
assert.equal(err.message, '[[error:invalid-event, constructor.toString]]');
done();
});
});
it('should return error for invalid eventName type', (done) => {
const eventName = ['topics.loadMoreTags'];
io.emit(eventName, (err) => {
assert.strictEqual(err.message, `[[error:invalid-event, object]]`);
done();
});
});
it('should get installed themes', (done) => {
const themes = ['nodebb-theme-lavender', 'nodebb-theme-persona', 'nodebb-theme-vanilla'];
io.emit('admin.themes.getInstalled', (err, data) => {

View File

@@ -82,6 +82,7 @@ describe('Topic thumbs', () => {
assert.deepStrictEqual(thumbs, [{
id: topicObj.topicData.tid,
name: 'test.png',
path: `${relativeThumbPaths[0]}`,
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[0]}`,
}]);
});
@@ -92,6 +93,7 @@ describe('Topic thumbs', () => {
[{
id: topicObj.topicData.tid,
name: 'test.png',
path: `${relativeThumbPaths[0]}`,
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[0]}`,
}],
[],
@@ -200,16 +202,19 @@ describe('Topic thumbs', () => {
{
id: tid,
name: 'test.png',
path: relativeThumbPaths[0],
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[0]}`,
},
{
id: tid,
name: 'example.org',
path: 'https://example.org',
url: 'https://example.org',
},
{
id: tid,
name: 'test2.png',
path: relativeThumbPaths[1],
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[1]}`,
},
]);

Some files were not shown because too many files have changed in this diff Show More