mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-07 08:02:50 +01:00
Compare commits
119 Commits
v1.14.1-be
...
v1.14.3-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55b3e376c6 | ||
|
|
4c90fac412 | ||
|
|
bc26883aed | ||
|
|
8769e28b28 | ||
|
|
b9cff5775c | ||
|
|
a6ae69737b | ||
|
|
10e4ae629c | ||
|
|
53f6139b8c | ||
|
|
2c83278f97 | ||
|
|
42af4b572b | ||
|
|
844f2b4ed0 | ||
|
|
7260646d6c | ||
|
|
4658121a7d | ||
|
|
5a5abf3c4e | ||
|
|
fefe994af5 | ||
|
|
ff3c343532 | ||
|
|
ac257a6586 | ||
|
|
bbab183fec | ||
|
|
ec05783507 | ||
|
|
a3c8d45626 | ||
|
|
6f889c9c83 | ||
|
|
a46adb3fd5 | ||
|
|
65395ae59d | ||
|
|
72c60d19c2 | ||
|
|
67ca5e3256 | ||
|
|
2a5f8ab27e | ||
|
|
23a9a334cd | ||
|
|
2c06f6ace1 | ||
|
|
2485a55092 | ||
|
|
8ddc8dd10f | ||
|
|
764969ab29 | ||
|
|
1e7397b1b8 | ||
|
|
f06b1cecba | ||
|
|
320008cd49 | ||
|
|
b5df576646 | ||
|
|
649c64e4d4 | ||
|
|
06143ca7d7 | ||
|
|
91bdc12a16 | ||
|
|
9e2c3ce005 | ||
|
|
3653151143 | ||
|
|
1e14af4503 | ||
|
|
0e13fd0fc1 | ||
|
|
3f87d5f9d0 | ||
|
|
9fb9185fa7 | ||
|
|
d52d7bdb10 | ||
|
|
e3e55f25d0 | ||
|
|
cd94c24a86 | ||
|
|
e085c8463c | ||
|
|
1e4d683f4e | ||
|
|
488e69fd80 | ||
|
|
c54287fe9c | ||
|
|
65240a178e | ||
|
|
1441720962 | ||
|
|
f85a45c722 | ||
|
|
63fb2ad7d9 | ||
|
|
9d1465d0da | ||
|
|
5e984d10f0 | ||
|
|
0ca7e28ad0 | ||
|
|
2286ee2a61 | ||
|
|
7730e7da23 | ||
|
|
3379d65f36 | ||
|
|
00d39fb32c | ||
|
|
15aabfd3a5 | ||
|
|
2fba0a1405 | ||
|
|
b3a88331bf | ||
|
|
393f19b461 | ||
|
|
3dcf538773 | ||
|
|
4e9743abb3 | ||
|
|
599c5015c8 | ||
|
|
6235b31c2b | ||
|
|
46a6686300 | ||
|
|
73ddf1cb98 | ||
|
|
c513b88dff | ||
|
|
fca4ee312e | ||
|
|
4adbf87c6c | ||
|
|
ab244ca6cc | ||
|
|
60bf488f54 | ||
|
|
26c744090e | ||
|
|
31203b162f | ||
|
|
d4c16086a3 | ||
|
|
658dd03b03 | ||
|
|
14eafcb6b8 | ||
|
|
e8ecef6bff | ||
|
|
943a344aaa | ||
|
|
0d9461b185 | ||
|
|
9f06f12cb9 | ||
|
|
c2ca02dfc7 | ||
|
|
8853cd1aa5 | ||
|
|
9458d90b5e | ||
|
|
4f51838df8 | ||
|
|
7b04d8970d | ||
|
|
ace312e068 | ||
|
|
bdc4d9e75b | ||
|
|
b8d9b6b1e1 | ||
|
|
8461a1796d | ||
|
|
857900f17c | ||
|
|
9a6b87d261 | ||
|
|
d6c619cf1a | ||
|
|
eb51cfd419 | ||
|
|
b60e1cbf50 | ||
|
|
87dd6c83eb | ||
|
|
746222d6c6 | ||
|
|
ee38e05daa | ||
|
|
9eb748b985 | ||
|
|
519e035dd1 | ||
|
|
5f1865c0b7 | ||
|
|
65c0adc720 | ||
|
|
ac6b571ed5 | ||
|
|
fef04fcf6b | ||
|
|
02ac44cc5a | ||
|
|
057b783df7 | ||
|
|
412ca4ae71 | ||
|
|
c468942f14 | ||
|
|
f3441fce4f | ||
|
|
89062d8e70 | ||
|
|
da29b947bf | ||
|
|
e95cd28f6f | ||
|
|
be85123ad5 | ||
|
|
723fe8e8e0 |
115
CHANGELOG.md
115
CHANGELOG.md
@@ -1,3 +1,118 @@
|
||||
#### 1.14.2 (2020-07-15)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v1.14.2 (1e4d683f)
|
||||
* update changelog for v1.14.2 (488e69fd)
|
||||
* up theme (63fb2ad7)
|
||||
* incrementing version number - v1.14.2-beta.1 (9d1465d0)
|
||||
* up theme (15aabfd3)
|
||||
* up theme (599c5015)
|
||||
* incrementing version number - v1.14.2-beta.0 (fca4ee31)
|
||||
* incrementing version number - v1.14.1 (31203b16)
|
||||
* update changelog for v1.14.1 (d4c16086)
|
||||
* **deps:** update commitlint monorepo to v9.1.1 (0ca7e28a)
|
||||
|
||||
##### New Features
|
||||
|
||||
* logic for flag note editing, #8499 (14417209)
|
||||
* logic for flag note deletion, #8499 (f85a45c7)
|
||||
* #8460, export groups members as csv (00d39fb3)
|
||||
* pass connection options to socket.io-adapter-mongo (393f19b4)
|
||||
* #8023, allow wildcard search for uid/email (3dcf5387)
|
||||
* up composer (6235b31c)
|
||||
* #8427, daily downvote limits (c513b88d)
|
||||
* warn user if whitelisted tags are less than minTags (4adbf87c)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* **deps:**
|
||||
* update dependency nodebb-plugin-mentions to v2.9.1 (c54287fe)
|
||||
* update dependency nodebb-plugin-mentions to v2.9.0 (7730e7da)
|
||||
* update dependency nodebb-theme-persona to v10.1.62 (#8485) (4e9743ab)
|
||||
* update dependency nodebb-plugin-composer-default to v6.3.49 (#8479) (ab244ca6)
|
||||
* #8499 (65240a17)
|
||||
* #8500 (5e984d10)
|
||||
* invalid session error modal during logout (2286ee2a)
|
||||
* #8488 (b3a88331)
|
||||
* category search in selector (46a66863)
|
||||
* groups.updateCover (73ddf1cb)
|
||||
* **docs:** bad changelog (60bf488f)
|
||||
|
||||
##### Other Changes
|
||||
|
||||
* update changelog for v1.14.2" (e085c846)
|
||||
* flag.showModal on flag modal appearance (3379d65f)
|
||||
* NodeBB/NodeBB (2fba0a14)
|
||||
* update changelog for v1.14.1" (26c74409)
|
||||
|
||||
#### 1.14.1 (2020-07-08)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v1.14.1 (31203b16)
|
||||
* update changelog for v1.14.1 (d4c16086)
|
||||
* incrementing version number - v1.14.1-beta.3 (e8ecef6b)
|
||||
* incrementing version number - v1.14.1-beta.2 (b8d9b6b1)
|
||||
* incrementing version number - v1.14.1-beta.1 (be85123a)
|
||||
* incrementing version number - v1.14.1-beta.0 (c279875a)
|
||||
* incrementing version number - v1.14.0 (bb73d6a4)
|
||||
* update changelog for v1.14.0 (cffae0f1)
|
||||
|
||||
##### New Features
|
||||
|
||||
* add tools to recent/unread (#8477) (658dd03b)
|
||||
* fire new hooks on chat message editing (4f51838d)
|
||||
* add back redis tests (bdc4d9e7)
|
||||
* remove redis test (8461a179)
|
||||
* use covered query (057b783d)
|
||||
* add js-enabled.css to list of preloaded css files (da29b947)
|
||||
* zscan (#8457) (723fe8e8)
|
||||
* fix blocksCount not being returned on user profile (bd228d5e)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* **deps:**
|
||||
* update dependency nodebb-theme-persona to v10.1.60 (#8478) (14eafcb6)
|
||||
* bump nodebb-plugin-composer-default to 6.3.48 (943a344a)
|
||||
* update dependency nodebb-plugin-dbsearch to v4.1.1 (#8476) (9f06f12c)
|
||||
* update dependency nodebb-plugin-composer-default to v6.3.47 (#8473) (857900f1)
|
||||
* update dependency nodebb-plugin-dbsearch to v4.1.0 (#8471) (eb51cfd4)
|
||||
* update dependency nodebb-theme-persona to v10.1.59 (#8468) (ee38e05d)
|
||||
* update dependency nodebb-widget-essentials to v4.1.1 (#8466) (519e035d)
|
||||
* update dependency @nodebb/socket.io-adapter-mongo to v3.0.1 (#8464) (412ca4ae)
|
||||
* #8474 (c2ca02df)
|
||||
* show stack properly (7b04d897)
|
||||
* editing chat messages does not go through content sanity checks (9a6b87d2)
|
||||
* don't show blocked users under nested replies (d6c619cf)
|
||||
* tests (87dd6c83)
|
||||
* handle scan/zscan returning duplicate elements on redis (746222d6)
|
||||
* #8467, fix url to merged topic in subfolder installs (9eb748b9)
|
||||
* openapi (5f1865c0)
|
||||
* openapi (65c0adc7)
|
||||
* dont allow searching by email/ip if not privileged (ac6b571e)
|
||||
* missing backgroundImage #8386 (fef04fcf)
|
||||
* dont allow searching by ip/banned/flagged for regular users (02ac44cc)
|
||||
* admin privileges client-side regression (f3441fce)
|
||||
* only add blocksCount for self and admins (59a2ace6)
|
||||
* tests (fd20e5c6)
|
||||
* better changelog (f992af05)
|
||||
* **tests:**
|
||||
* another shot in the dark (8853cd1a)
|
||||
* shot in the dark (9458d90b)
|
||||
* **openapi:** tests (c468942f)
|
||||
|
||||
##### Other Changes
|
||||
|
||||
* update changelog for v1.14.1" (26c74409)
|
||||
* //github.com/NodeBB/NodeBB (0d9461b1)
|
||||
* //github.com/NodeBB/NodeBB (ace312e0)
|
||||
* post.changeOwner (b60e1cbf)
|
||||
|
||||
##### Reverts
|
||||
|
||||
* bad changelog (a761e31f)
|
||||
|
||||
#### 1.14.0 (2020-07-02)
|
||||
|
||||
##### Chores
|
||||
|
||||
@@ -70,6 +70,8 @@
|
||||
"reputation:disabled": 0,
|
||||
"downvote:disabled": 0,
|
||||
"disableSignatures": 0,
|
||||
"downvotesPerDay": 10,
|
||||
"downvotesPerUserPerDay": 3,
|
||||
"min:rep:downvote": 0,
|
||||
"min:rep:flag": 0,
|
||||
"min:rep:profile-picture": 0,
|
||||
@@ -77,6 +79,7 @@
|
||||
"min:rep:website": 0,
|
||||
"min:rep:aboutme": 0,
|
||||
"min:rep:signature": 0,
|
||||
"flags:limitPerTarget": 0,
|
||||
"notificationType_upvote": "notification",
|
||||
"notificationType_new-topic": "notification",
|
||||
"notificationType_new-reply": "notification",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.14.1-beta.0",
|
||||
"version": "1.14.3-beta.4",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -11,9 +11,9 @@
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"start": "node loader.js",
|
||||
"lint": "eslint --cache ./nodebb .",
|
||||
"lint": "npx eslint --cache ./nodebb .",
|
||||
"pretest": "npm run lint",
|
||||
"test": "nyc --reporter=html --reporter=text-summary mocha",
|
||||
"test": "npx nyc --reporter=html --reporter=text-summary npx mocha",
|
||||
"coveralls": "nyc report --reporter=text-lcov | coveralls && rm -r coverage"
|
||||
},
|
||||
"husky": {
|
||||
@@ -78,22 +78,22 @@
|
||||
"morgan": "^1.10.0",
|
||||
"mousetrap": "^1.6.5",
|
||||
"@nodebb/mubsub": "^1.6.0",
|
||||
"@nodebb/socket.io-adapter-mongo": "3.0.0",
|
||||
"@nodebb/socket.io-adapter-mongo": "3.0.1",
|
||||
"nconf": "^0.10.0",
|
||||
"nodebb-plugin-composer-default": "6.3.46",
|
||||
"nodebb-plugin-dbsearch": "4.0.7",
|
||||
"nodebb-plugin-composer-default": "6.3.52",
|
||||
"nodebb-plugin-dbsearch": "4.1.2",
|
||||
"nodebb-plugin-emoji": "^3.3.0",
|
||||
"nodebb-plugin-emoji-android": "2.0.0",
|
||||
"nodebb-plugin-markdown": "8.11.2",
|
||||
"nodebb-plugin-mentions": "2.8.3",
|
||||
"nodebb-plugin-mentions": "2.9.3",
|
||||
"nodebb-plugin-soundpack-default": "1.0.0",
|
||||
"nodebb-plugin-spam-be-gone": "0.7.2",
|
||||
"nodebb-rewards-essentials": "0.1.3",
|
||||
"nodebb-theme-lavender": "5.0.11",
|
||||
"nodebb-theme-persona": "10.1.58",
|
||||
"nodebb-theme-persona": "10.1.68",
|
||||
"nodebb-theme-slick": "1.2.29",
|
||||
"nodebb-theme-vanilla": "11.1.32",
|
||||
"nodebb-widget-essentials": "4.1.0",
|
||||
"nodebb-theme-vanilla": "11.1.35",
|
||||
"nodebb-widget-essentials": "4.1.1",
|
||||
"nodemailer": "^6.4.6",
|
||||
"passport": "^0.4.1",
|
||||
"passport-local": "1.0.0",
|
||||
@@ -132,9 +132,9 @@
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apidevtools/swagger-parser": "9.0.1",
|
||||
"@commitlint/cli": "9.0.1",
|
||||
"@commitlint/config-angular": "9.0.1",
|
||||
"@apidevtools/swagger-parser": "10.0.0",
|
||||
"@commitlint/cli": "9.1.1",
|
||||
"@commitlint/config-angular": "9.1.1",
|
||||
"coveralls": "3.1.0",
|
||||
"eslint": "7.3.1",
|
||||
"eslint-config-airbnb-base": "14.1.0",
|
||||
|
||||
@@ -223,12 +223,15 @@ function launch(req, res) {
|
||||
}
|
||||
|
||||
function compileLess(callback) {
|
||||
fs.readFile(path.join(__dirname, '../public/less/install.less'), function (err, style) {
|
||||
var installSrc = path.join(__dirname, '../public/less/install.less');
|
||||
fs.readFile(installSrc, function (err, style) {
|
||||
if (err) {
|
||||
return winston.error('Unable to read LESS install file: ', err.stack);
|
||||
}
|
||||
|
||||
less.render(style.toString(), function (err, css) {
|
||||
less.render(style.toString(), {
|
||||
filename: path.resolve(installSrc),
|
||||
}, function (err, css) {
|
||||
if (err) {
|
||||
return winston.error('Unable to compile LESS: ', err.stack);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"es6": false
|
||||
},
|
||||
"rules": {
|
||||
"block-scoped-var": "off",
|
||||
"no-dupe-class-members": "off",
|
||||
"no-var": "off",
|
||||
"object-shorthand": "off",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
/*
|
||||
The following stylesheet is only included on pages that can execute javascript
|
||||
*/
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "إلغاء",
|
||||
"bootbox.confirm": "تأكيد",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Качване на файл",
|
||||
"composer.zen_mode": "Режим Дзен",
|
||||
"composer.select_category": "Изберете категория",
|
||||
"composer.textarea.placeholder": "Въведете съдържанието на публикацията си тук. Можете също да влачите и пускате снимки.",
|
||||
"bootbox.ok": "Добре",
|
||||
"bootbox.cancel": "Отказ",
|
||||
"bootbox.confirm": "Потвърждаване",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Nahrát soubor",
|
||||
"composer.zen_mode": "Režim Zem",
|
||||
"composer.select_category": "Vyberte kategorii",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Zrušit",
|
||||
"bootbox.confirm": "Potvrdit",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Annuller",
|
||||
"bootbox.confirm": "Bekræft",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Datei hochladen",
|
||||
"composer.zen_mode": "Zen Modus",
|
||||
"composer.select_category": "Wähle eine Kategorie",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Abbrechen",
|
||||
"bootbox.confirm": "Bestätigen",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"ip": "IP <strong>%1</strong>",
|
||||
"nodes-responded": "%1 nodes responded within %2ms!",
|
||||
"host": "host",
|
||||
"primary": "primary / run jobs",
|
||||
"pid": "pid",
|
||||
"nodejs": "nodejs",
|
||||
"online": "online",
|
||||
|
||||
@@ -76,7 +76,9 @@
|
||||
"alert.user-search": "Search for a user here...",
|
||||
"alert.find-group": "Find a Group",
|
||||
"alert.group-search": "Search for a group here...",
|
||||
"alert.not-enough-whitelisted-tags": "Whitelisted tags are less than minimum tags, you need to create more whitelisted tags!",
|
||||
"collapse-all": "Collapse All",
|
||||
"expand-all": "Expand All",
|
||||
"disable-on-create": "Disable on create"
|
||||
"disable-on-create": "Disable on create",
|
||||
"no-matches": "No matches"
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
"hidden": "Hidden",
|
||||
"private": "Private",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"download-csv": "Download CSV",
|
||||
"search-placeholder": "Search",
|
||||
"create": "Create Group",
|
||||
"description-placeholder": "A short description about your group",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"admin": "Admin",
|
||||
"group-privileges": "Group Privileges",
|
||||
"user-privileges": "User Privileges",
|
||||
"edit-privileges": "Edit Privileges",
|
||||
"chat": "Chat",
|
||||
"upload-images": "Upload Images",
|
||||
"upload-files": "Upload Files",
|
||||
@@ -33,7 +34,6 @@
|
||||
"delete-topics": "Delete Topics",
|
||||
"purge": "Purge",
|
||||
"moderate": "Moderate",
|
||||
|
||||
"admin-dashboard": "Dashboard",
|
||||
"admin-categories": "Categories",
|
||||
"admin-privileges": "Privileges",
|
||||
|
||||
@@ -108,5 +108,5 @@
|
||||
|
||||
"alerts.prompt-email": "Emails: ",
|
||||
"alerts.email-sent-to": "An invitation email has been sent to %1",
|
||||
"alerts.x-users-found": "%1 user(s) found! Search took %2 ms."
|
||||
"alerts.x-users-found": "%1 user(s) found, (%2 seconds)"
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
"settings/general": "General",
|
||||
"settings/homepage": "Home Page",
|
||||
"settings/navigation": "Navigation",
|
||||
"settings/reputation": "Reputation",
|
||||
"settings/reputation": "Reputation & Flags",
|
||||
"settings/email": "Email",
|
||||
"settings/user": "Users",
|
||||
"settings/group": "Groups",
|
||||
|
||||
@@ -5,10 +5,16 @@
|
||||
"votes-are-public": "All Votes Are Public",
|
||||
"thresholds": "Activity Thresholds",
|
||||
"min-rep-downvote": "Minimum reputation to downvote posts",
|
||||
"downvotes-per-day": "Downvotes per day (set to 0 for unlimited downvotes)",
|
||||
"downvotes-per-user-per-day": "Downvotes per user per day (set to 0 for unlimited downvotes)",
|
||||
"min-rep-flag": "Minimum reputation to flag posts",
|
||||
"min-rep-website": "Minimum reputation to add \"Website\" to user profile",
|
||||
"min-rep-aboutme": "Minimum reputation to add \"About me\" to user profile",
|
||||
"min-rep-signature": "Minimum reputation to add \"Signature\" to user profile",
|
||||
"min-rep-profile-picture": "Minimum reputation to add \"Profile Picture\" to user profile",
|
||||
"min-rep-cover-picture": "Minimum reputation to add \"Cover Picture\" to user profile"
|
||||
"min-rep-cover-picture": "Minimum reputation to add \"Cover Picture\" to user profile",
|
||||
|
||||
"flags": "Flag Settings",
|
||||
"flags.limit-per-target": "Maximum number of times something can be flagged",
|
||||
"flags.limit-per-target-placeholder": "Default: 0"
|
||||
}
|
||||
@@ -163,8 +163,13 @@
|
||||
"not-enough-reputation-min-rep-signature": "You do not have enough reputation to add a signature",
|
||||
"not-enough-reputation-min-rep-profile-picture": "You do not have enough reputation to add a profile picture",
|
||||
"not-enough-reputation-min-rep-cover-picture": "You do not have enough reputation to add a cover picture",
|
||||
"already-flagged": "You have already flagged this post",
|
||||
"post-already-flagged": "You have already flagged this post",
|
||||
"user-already-flagged": "You have already flagged this user",
|
||||
"post-flagged-too-many-times": "This post has been flagged by others already",
|
||||
"user-flagged-too-many-times": "This user has been flagged by others already",
|
||||
"self-vote": "You cannot vote on your own post",
|
||||
"too-many-downvotes-today": "You can only downvote %1 times a day",
|
||||
"too-many-downvotes-today-user": "You can only downvote a user %1 times a day",
|
||||
|
||||
"reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.",
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"filter-quick-mine": "Assigned to me",
|
||||
"filter-cid-all": "All categories",
|
||||
"apply-filters": "Apply Filters",
|
||||
"more-filters": "More Filters",
|
||||
|
||||
"quick-actions": "Quick Actions",
|
||||
"flagged-user": "Flagged User",
|
||||
@@ -43,6 +44,9 @@
|
||||
"notes": "Flag Notes",
|
||||
"add-note": "Add Note",
|
||||
"no-notes": "No shared notes.",
|
||||
"delete-note-confirm": "Are you sure you want to delete this flag note?",
|
||||
"note-added": "Note Added",
|
||||
"note-deleted": "Note Deleted",
|
||||
|
||||
"history": "Account & Flag History",
|
||||
"no-history": "No flag history.",
|
||||
@@ -53,7 +57,6 @@
|
||||
"state-resolved": "Resolved",
|
||||
"state-rejected": "Rejected",
|
||||
"no-assignee": "Not Assigned",
|
||||
"note-added": "Note Added",
|
||||
|
||||
"modal-title": "Report Inappropriate Content",
|
||||
"modal-body": "Please specify your reason for flagging %1 %2 for review. Alternatively, use one of the quick report buttons if applicable.",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"chat.chatting_with": "Chat with",
|
||||
"chat.placeholder": "Type chat message here, press enter to send",
|
||||
"chat.scroll-up-alert": "You are looking at older messages, click here to go to most recent message.",
|
||||
"chat.send": "Send",
|
||||
"chat.no_active": "You have no active chats.",
|
||||
"chat.user_typing": "%1 is typing ...",
|
||||
@@ -60,6 +61,8 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
|
||||
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"flag_post": "Flag this post",
|
||||
"flag_user": "Flag this user",
|
||||
|
||||
"merged_message": "This topic has been merged into <a href=\"/topic/%1\">%2</a>",
|
||||
"merged_message": "This topic has been merged into <a href=\"%1\">%2</a>",
|
||||
"deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.",
|
||||
|
||||
"following_topic.message": "You will now be receiving notifications when somebody posts to this topic.",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Subir archivo",
|
||||
"composer.zen_mode": "Modo Zen",
|
||||
"composer.select_category": "Selecciona una categoría",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancelar",
|
||||
"bootbox.confirm": "Confirmar",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Lae fail üles",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "Olgu",
|
||||
"bootbox.cancel": "Katkesta",
|
||||
"bootbox.confirm": "Kinnita",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "بارگذاری فایل",
|
||||
"composer.zen_mode": "حالت ذن",
|
||||
"composer.select_category": "یک دستهبندی انتخاب کنید",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "باشه",
|
||||
"bootbox.cancel": "انصراف",
|
||||
"bootbox.confirm": "تایید",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Envoyer un fichier",
|
||||
"composer.zen_mode": "Mode Zen",
|
||||
"composer.select_category": "Sélectionnez une catégorie",
|
||||
"composer.textarea.placeholder": "Saisissez le contenu de votre message ici, faites glisser et déposez les images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Annuler",
|
||||
"bootbox.confirm": "Confirmer",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Subir arquivo",
|
||||
"composer.zen_mode": "Modo Zen",
|
||||
"composer.select_category": "Selecciona unha categoría",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "De acordo",
|
||||
"bootbox.cancel": "Cancelar",
|
||||
"bootbox.confirm": "Confirmar",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "העלה קובץ",
|
||||
"composer.zen_mode": "מצב זן",
|
||||
"composer.select_category": "בחר קטגוריה",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "אוקיי",
|
||||
"bootbox.cancel": "בטל",
|
||||
"bootbox.confirm": "אשר",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Učitaj datoteku",
|
||||
"composer.zen_mode": "Zen",
|
||||
"composer.select_category": "Odaberi kategoriju",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Odbaci",
|
||||
"bootbox.confirm": "Potvrdi",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Fájl feltöltése",
|
||||
"composer.zen_mode": "Zen mód",
|
||||
"composer.select_category": "Kategória választása",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Mégse",
|
||||
"bootbox.confirm": "Megerősítés",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Carica file",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Seleziona una categoria",
|
||||
"composer.textarea.placeholder": "Inserisci qui il contenuto del tuo post, trascina e rilascia le immagini",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Annulla",
|
||||
"bootbox.confirm": "Conferma",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "ファイルをアップロード",
|
||||
"composer.zen_mode": "Zen モード",
|
||||
"composer.select_category": "カテゴリを選択",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "キャンセル",
|
||||
"bootbox.confirm": "確認",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "파일 업로드",
|
||||
"composer.zen_mode": "전체화면",
|
||||
"composer.select_category": "카테고리 선택",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "확인",
|
||||
"bootbox.cancel": "취소",
|
||||
"bootbox.confirm": "확인",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Augšupielādēt failu",
|
||||
"composer.zen_mode": "Zen režīms",
|
||||
"composer.select_category": "Izvēlēties kategoriju",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "Labi",
|
||||
"bootbox.cancel": "Atcelt",
|
||||
"bootbox.confirm": "Apstiprināt",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "Ok",
|
||||
"bootbox.cancel": "Batal",
|
||||
"bootbox.confirm": "Pasti",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Avbryt",
|
||||
"bootbox.confirm": "Bekreft",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload bestand",
|
||||
"composer.zen_mode": "Zen-modus",
|
||||
"composer.select_category": "Selecteer een categorie",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Annuleren",
|
||||
"bootbox.confirm": "Bevestig",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Wyślij plik",
|
||||
"composer.zen_mode": "Tryb Zen",
|
||||
"composer.select_category": "Wybierz kategorię",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Anuluj",
|
||||
"bootbox.confirm": "Potwierdź",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Fazer upload de Arquivo",
|
||||
"composer.zen_mode": "Modo Zen",
|
||||
"composer.select_category": "Escolha uma categoria",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancelar",
|
||||
"bootbox.confirm": "Confirmar",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Enviar um ficheiro",
|
||||
"composer.zen_mode": "Modo Zen",
|
||||
"composer.select_category": "Selecionar uma categoria",
|
||||
"composer.textarea.placeholder": "Escreve aqui o conteúdo da tua publicação, arrasta e solta imagens",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancelar",
|
||||
"bootbox.confirm": "Confirmar",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Загрузить файл",
|
||||
"composer.zen_mode": "Полноэкранный режим",
|
||||
"composer.select_category": "Выберите категорию",
|
||||
"composer.textarea.placeholder": "Введите содержание вашего сообщения здесь, перетащите изображения",
|
||||
"bootbox.ok": "ОК",
|
||||
"bootbox.cancel": "Отмена",
|
||||
"bootbox.confirm": "Подтвердить",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "Sawa",
|
||||
"bootbox.cancel": "Isubire",
|
||||
"bootbox.confirm": "Emeza",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Upload File",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Cancel",
|
||||
"bootbox.confirm": "Confirm",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Nahrať súbor",
|
||||
"composer.zen_mode": "Režim Zen",
|
||||
"composer.select_category": "Vyberte kategóriu",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Zrušiť",
|
||||
"bootbox.confirm": "Potvrdiť",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Prenesi datoteko",
|
||||
"composer.zen_mode": "Zen način",
|
||||
"composer.select_category": "Select a category",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "V redu",
|
||||
"bootbox.cancel": "Prekliči",
|
||||
"bootbox.confirm": "Potrdi",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Отпреми датотеку",
|
||||
"composer.zen_mode": "Цео екран",
|
||||
"composer.select_category": "Изаберите категорију",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "ОК",
|
||||
"bootbox.cancel": "Откажи",
|
||||
"bootbox.confirm": "Потврди",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Ladda upp fil",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Välj en kategori",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Avbryt",
|
||||
"bootbox.confirm": "Bekräfta",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "อัพโหลดไฟล์",
|
||||
"composer.zen_mode": "เซ็นโหมด",
|
||||
"composer.select_category": "เลือกหมวดหมู่",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "ตกลง",
|
||||
"bootbox.cancel": "ยกเลิก",
|
||||
"bootbox.confirm": "ยืนยัน",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Dosya Yükle",
|
||||
"composer.zen_mode": "Tam ekran modu",
|
||||
"composer.select_category": "Bir kategori seç",
|
||||
"composer.textarea.placeholder": "İletinizi buraya giriniz, görselleri sürükleyip bırakabilirsiniz",
|
||||
"bootbox.ok": "Kabul",
|
||||
"bootbox.cancel": "İptal",
|
||||
"bootbox.confirm": "Onayla",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Завантажити файл",
|
||||
"composer.zen_mode": "Режим Дзен",
|
||||
"composer.select_category": "Обрати категорію",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "ОК",
|
||||
"bootbox.cancel": "Скасувати",
|
||||
"bootbox.confirm": "Підтвердити",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "Tải file lên",
|
||||
"composer.zen_mode": "Zen Mode",
|
||||
"composer.select_category": "Chọn một chuyên mục",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "OK",
|
||||
"bootbox.cancel": "Huỷ bỏ",
|
||||
"bootbox.confirm": "Xác nhận",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "上传文件",
|
||||
"composer.zen_mode": "无干扰模式",
|
||||
"composer.select_category": "选择一个版块",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "确认",
|
||||
"bootbox.cancel": "取消",
|
||||
"bootbox.confirm": "确认",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"composer.upload-file": "上傳檔案",
|
||||
"composer.zen_mode": "無干擾模式",
|
||||
"composer.select_category": "選擇一個版面",
|
||||
"composer.textarea.placeholder": "Enter your post content here, drag and drop images",
|
||||
"bootbox.ok": "確認",
|
||||
"bootbox.cancel": "取消",
|
||||
"bootbox.confirm": "確認",
|
||||
|
||||
@@ -27,3 +27,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-admin-groups {
|
||||
[component="category/list"] li {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,18 @@
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.page-admin-privileges {
|
||||
@keyframes fadeOut {
|
||||
0% {background-color: @brand-primary;}
|
||||
100% {background-color: white;}
|
||||
}
|
||||
|
||||
[data-group-name].selected {
|
||||
animation-name: fadeOut;
|
||||
animation-duration: 5s;
|
||||
animation-fill-mode: both;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,8 @@ CommonProps:
|
||||
type: string
|
||||
sizes:
|
||||
type: string
|
||||
as:
|
||||
type: string
|
||||
required:
|
||||
- rel
|
||||
- href
|
||||
|
||||
@@ -106,7 +106,7 @@ PostsObject:
|
||||
type: string
|
||||
color:
|
||||
type: string
|
||||
image:
|
||||
backgroundImage:
|
||||
nullable: true
|
||||
imageClass:
|
||||
nullable: true
|
||||
|
||||
@@ -66,7 +66,7 @@ TopicObject:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
image:
|
||||
backgroundImage:
|
||||
nullable: true
|
||||
type: string
|
||||
imageClass:
|
||||
|
||||
@@ -954,11 +954,30 @@ paths:
|
||||
properties:
|
||||
search_display:
|
||||
type: string
|
||||
matchCount:
|
||||
type: number
|
||||
query:
|
||||
type: string
|
||||
uidQuery:
|
||||
type: string
|
||||
usernameQuery:
|
||||
type: string
|
||||
emailQuery:
|
||||
type: string
|
||||
ipQuery:
|
||||
type: string
|
||||
pageCount:
|
||||
type: number
|
||||
resultsPerPage:
|
||||
type: number
|
||||
timing:
|
||||
type: number
|
||||
users:
|
||||
type: array
|
||||
items:
|
||||
$ref: components/schemas/UserObject.yaml#/UserObjectACP
|
||||
- $ref: components/schemas/CommonProps.yaml#/CommonProps
|
||||
- $ref: components/schemas/Pagination.yaml#/Pagination
|
||||
/api/admin/manage/users/latest:
|
||||
get:
|
||||
tags:
|
||||
@@ -1298,6 +1317,36 @@ paths:
|
||||
type: string
|
||||
selected:
|
||||
type: boolean
|
||||
categories:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
cid:
|
||||
type: number
|
||||
description: A category identifier
|
||||
name:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
selected:
|
||||
type: boolean
|
||||
level:
|
||||
type: string
|
||||
parentCid:
|
||||
type: number
|
||||
description: The category identifier for the category that is the immediate
|
||||
ancestor of the current category
|
||||
color:
|
||||
type: string
|
||||
bgColor:
|
||||
type: string
|
||||
imageClass:
|
||||
type: string
|
||||
required:
|
||||
- cid
|
||||
- name
|
||||
- icon
|
||||
allowPrivateGroups:
|
||||
type: number
|
||||
maximumGroupNameLength:
|
||||
@@ -2176,11 +2225,24 @@ paths:
|
||||
load:
|
||||
type: string
|
||||
description: CPU load
|
||||
nodebb:
|
||||
type: object
|
||||
properties:
|
||||
isPrimary:
|
||||
type: boolean
|
||||
isCluster:
|
||||
type: boolean
|
||||
runJobs:
|
||||
type: boolean
|
||||
jobsDisabled:
|
||||
type: boolean
|
||||
git:
|
||||
type: object
|
||||
properties:
|
||||
hash:
|
||||
type: string
|
||||
hashShort:
|
||||
type: string
|
||||
branch:
|
||||
type: string
|
||||
stats:
|
||||
@@ -2257,6 +2319,26 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
/api/admin/groups/{groupname}/csv:
|
||||
get:
|
||||
tags:
|
||||
- admin
|
||||
summary: Get members of a group (.csv)
|
||||
parameters:
|
||||
- in: header
|
||||
name: referer
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
example: /admin/manage/groups
|
||||
responses:
|
||||
"200":
|
||||
description: "A CSV file containing all users in the group"
|
||||
content:
|
||||
text/csv:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
/api/admin/analytics:
|
||||
get:
|
||||
tags:
|
||||
@@ -3810,6 +3892,10 @@ paths:
|
||||
type: number
|
||||
canPost:
|
||||
type: boolean
|
||||
showSelect:
|
||||
type: boolean
|
||||
showTopicTools:
|
||||
type: boolean
|
||||
categories:
|
||||
type: array
|
||||
items:
|
||||
@@ -3871,6 +3957,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
selectedFilter:
|
||||
type: object
|
||||
properties:
|
||||
@@ -3882,6 +3970,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
terms:
|
||||
type: array
|
||||
items:
|
||||
@@ -3946,6 +4036,8 @@ paths:
|
||||
properties:
|
||||
showSelect:
|
||||
type: boolean
|
||||
showTopicTools:
|
||||
type: boolean
|
||||
nextStart:
|
||||
type: number
|
||||
topics:
|
||||
@@ -4199,6 +4291,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
selectedFilter:
|
||||
type: object
|
||||
properties:
|
||||
@@ -4210,6 +4304,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
- $ref: components/schemas/Pagination.yaml#/Pagination
|
||||
- $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs
|
||||
- $ref: components/schemas/CommonProps.yaml#/CommonProps
|
||||
@@ -4990,6 +5086,35 @@ paths:
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
allCategories:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
bgColor:
|
||||
type: string
|
||||
cid:
|
||||
type: number
|
||||
color:
|
||||
type: string
|
||||
disabled:
|
||||
type: number
|
||||
disabledClass:
|
||||
type: boolean
|
||||
icon:
|
||||
type: string
|
||||
imageClass:
|
||||
type: string
|
||||
level:
|
||||
type: string
|
||||
link:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
parentCid:
|
||||
type: number
|
||||
slug:
|
||||
type: string
|
||||
posts:
|
||||
type: array
|
||||
items:
|
||||
@@ -5492,6 +5617,10 @@ paths:
|
||||
type: number
|
||||
canPost:
|
||||
type: boolean
|
||||
showSelect:
|
||||
type: boolean
|
||||
showTopicTools:
|
||||
type: boolean
|
||||
categories:
|
||||
type: array
|
||||
items:
|
||||
@@ -5553,6 +5682,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
selectedFilter:
|
||||
type: object
|
||||
properties:
|
||||
@@ -5564,6 +5695,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
terms:
|
||||
type: array
|
||||
items:
|
||||
@@ -5620,6 +5753,10 @@ paths:
|
||||
type: number
|
||||
canPost:
|
||||
type: boolean
|
||||
showSelect:
|
||||
type: boolean
|
||||
showTopicTools:
|
||||
type: boolean
|
||||
categories:
|
||||
type: array
|
||||
items:
|
||||
@@ -5694,6 +5831,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
selectedFilter:
|
||||
type: object
|
||||
properties:
|
||||
@@ -5705,6 +5844,8 @@ paths:
|
||||
type: boolean
|
||||
filter:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
terms:
|
||||
type: array
|
||||
items:
|
||||
@@ -5817,6 +5958,8 @@ paths:
|
||||
type: boolean
|
||||
showSelect:
|
||||
type: boolean
|
||||
showTopicTools:
|
||||
type: boolean
|
||||
rssFeedUrl:
|
||||
type: string
|
||||
feeds:disableRSS:
|
||||
|
||||
@@ -11,9 +11,9 @@ define('admin/manage/categories', [
|
||||
var sortables;
|
||||
|
||||
Categories.init = function () {
|
||||
socket.emit('admin.categories.getAll', function (error, payload) {
|
||||
if (error) {
|
||||
return app.alertError(error.message);
|
||||
socket.emit('admin.categories.getAll', function (err, payload) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
Categories.render(payload);
|
||||
@@ -63,8 +63,55 @@ define('admin/manage/categories', [
|
||||
el.find('i').toggleClass('fa-minus', expand).toggleClass('fa-plus', !expand);
|
||||
el.closest('[data-cid]').find('> ul[data-cid]').toggleClass('hidden', !expand);
|
||||
}
|
||||
|
||||
$('#category-search').on('keyup', function () {
|
||||
searchCategory();
|
||||
});
|
||||
};
|
||||
|
||||
function searchCategory() {
|
||||
var container = $('#content .categories');
|
||||
function revealParents(cid) {
|
||||
var parentCid = container.find('li[data-cid="' + cid + '"]').attr('data-parent-cid');
|
||||
if (parentCid) {
|
||||
container.find('li[data-cid="' + parentCid + '"]').removeClass('hidden');
|
||||
revealParents(parentCid);
|
||||
}
|
||||
}
|
||||
|
||||
function revealChildren(cid) {
|
||||
var els = container.find('li[data-parent-cid="' + cid + '"]');
|
||||
els.each(function (index, el) {
|
||||
var $el = $(el);
|
||||
$el.removeClass('hidden');
|
||||
revealChildren($el.attr('data-cid'));
|
||||
});
|
||||
}
|
||||
|
||||
var categoryEls = container.find('li[data-cid]');
|
||||
var val = $('#category-search').val().toLowerCase();
|
||||
var noMatch = true;
|
||||
var cids = [];
|
||||
categoryEls.each(function () {
|
||||
var liEl = $(this);
|
||||
var isMatch = liEl.attr('data-name').toLowerCase().indexOf(val) !== -1;
|
||||
if (noMatch && isMatch) {
|
||||
noMatch = false;
|
||||
}
|
||||
if (isMatch && val) {
|
||||
cids.push(liEl.attr('data-cid'));
|
||||
}
|
||||
liEl.toggleClass('hidden', !isMatch);
|
||||
});
|
||||
|
||||
cids.forEach(function (cid) {
|
||||
revealParents(cid);
|
||||
revealChildren(cid);
|
||||
});
|
||||
|
||||
$('[component="category/no-matches"]').toggleClass('hidden', !noMatch);
|
||||
}
|
||||
|
||||
Categories.throwCreateModal = function () {
|
||||
socket.emit('categories.getSelectCategories', {}, function (err, categories) {
|
||||
if (err) {
|
||||
|
||||
@@ -48,6 +48,11 @@ define('admin/manage/category', [
|
||||
$('[data-name="bgColor"], [data-name="color"]').each(enableColorPicker);
|
||||
|
||||
$('#save').on('click', function () {
|
||||
var tags = $('#tag-whitelist').val() ? $('#tag-whitelist').val().split(',') : [];
|
||||
if (tags.length && tags.length < parseInt($('#cid-min-tags').val(), 10)) {
|
||||
return app.alertError('[[admin/manage/categories:alert.not-enough-whitelisted-tags]]');
|
||||
}
|
||||
|
||||
if (Object.keys(modified_categories).length) {
|
||||
socket.emit('admin.categories.update', modified_categories, function (err, result) {
|
||||
if (err) {
|
||||
|
||||
@@ -5,7 +5,8 @@ define('admin/manage/group', [
|
||||
'forum/groups/memberlist',
|
||||
'iconSelect',
|
||||
'admin/modules/colorpicker',
|
||||
], function (memberList, iconSelect, colorpicker) {
|
||||
'translator',
|
||||
], function (memberList, iconSelect, colorpicker, translator) {
|
||||
var Groups = {};
|
||||
|
||||
Groups.init = function () {
|
||||
@@ -36,6 +37,68 @@ define('admin/manage/group', [
|
||||
groupLabelPreview.css('color', changeGroupTextColor.val() || '#ffffff');
|
||||
});
|
||||
|
||||
setupGroupMembersMenu(groupName);
|
||||
|
||||
$('#group-icon, #group-icon-label').on('click', function () {
|
||||
iconSelect.init(groupIcon, function () {
|
||||
var newIcon = groupIcon.attr('value');
|
||||
if (newIcon === 'fa-nbb-none') {
|
||||
newIcon = 'hidden';
|
||||
}
|
||||
$('#group-icon-preview').attr('class', 'fa fa-fw ' + (newIcon || 'hidden'));
|
||||
});
|
||||
});
|
||||
|
||||
$('[component="category/list"] [data-cid]').on('click', navigateToCategory);
|
||||
|
||||
colorpicker.enable(changeGroupLabelColor, function (hsb, hex) {
|
||||
groupLabelPreview.css('background-color', '#' + hex);
|
||||
});
|
||||
|
||||
colorpicker.enable(changeGroupTextColor, function (hsb, hex) {
|
||||
groupLabelPreview.css('color', '#' + hex);
|
||||
});
|
||||
|
||||
$('form').on('change', 'input, select, textarea', function () {
|
||||
app.flags = app.flags || {};
|
||||
app.flags._unsaved = true;
|
||||
});
|
||||
|
||||
$('#save').on('click', function () {
|
||||
socket.emit('admin.groups.update', {
|
||||
groupName: groupName,
|
||||
values: {
|
||||
name: $('#change-group-name').val(),
|
||||
userTitle: changeGroupUserTitle.val(),
|
||||
description: $('#change-group-desc').val(),
|
||||
icon: groupIcon.attr('value'),
|
||||
labelColor: changeGroupLabelColor.val(),
|
||||
textColor: changeGroupTextColor.val(),
|
||||
userTitleEnabled: $('#group-userTitleEnabled').is(':checked'),
|
||||
private: $('#group-private').is(':checked'),
|
||||
hidden: $('#group-hidden').is(':checked'),
|
||||
disableJoinRequests: $('#group-disableJoinRequests').is(':checked'),
|
||||
disableLeave: $('#group-disableLeave').is(':checked'),
|
||||
},
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
var newName = $('#change-group-name').val();
|
||||
|
||||
// If the group name changed, change url
|
||||
if (groupName !== newName) {
|
||||
ajaxify.go('admin/manage/groups/' + encodeURIComponent(newName), undefined, true);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[admin/manage/groups:edit.save-success]]');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
function setupGroupMembersMenu(groupName) {
|
||||
$('[component="groups/members"]').on('click', '[data-action]', function () {
|
||||
var btnEl = $(this);
|
||||
var userRow = btnEl.parents('[data-uid]');
|
||||
@@ -77,58 +140,27 @@ define('admin/manage/group', [
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#group-icon, #group-icon-label').on('click', function () {
|
||||
iconSelect.init(groupIcon, function () {
|
||||
var newIcon = groupIcon.attr('value');
|
||||
if (newIcon === 'fa-nbb-none') {
|
||||
newIcon = 'hidden';
|
||||
}
|
||||
$('#group-icon-preview').attr('class', 'fa fa-fw ' + (newIcon || 'hidden'));
|
||||
});
|
||||
});
|
||||
function navigateToCategory() {
|
||||
var cid = $(this).attr('data-cid');
|
||||
|
||||
colorpicker.enable(changeGroupLabelColor, function (hsb, hex) {
|
||||
groupLabelPreview.css('background-color', '#' + hex);
|
||||
});
|
||||
|
||||
colorpicker.enable(changeGroupTextColor, function (hsb, hex) {
|
||||
groupLabelPreview.css('color', '#' + hex);
|
||||
});
|
||||
|
||||
$('#save').on('click', function () {
|
||||
socket.emit('admin.groups.update', {
|
||||
groupName: groupName,
|
||||
values: {
|
||||
name: $('#change-group-name').val(),
|
||||
userTitle: changeGroupUserTitle.val(),
|
||||
description: $('#change-group-desc').val(),
|
||||
icon: groupIcon.attr('value'),
|
||||
labelColor: changeGroupLabelColor.val(),
|
||||
textColor: changeGroupTextColor.val(),
|
||||
userTitleEnabled: $('#group-userTitleEnabled').is(':checked'),
|
||||
private: $('#group-private').is(':checked'),
|
||||
hidden: $('#group-hidden').is(':checked'),
|
||||
disableJoinRequests: $('#group-disableJoinRequests').is(':checked'),
|
||||
disableLeave: $('#group-disableLeave').is(':checked'),
|
||||
},
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
var newName = $('#change-group-name').val();
|
||||
|
||||
// If the group name changed, change url
|
||||
if (groupName !== newName) {
|
||||
ajaxify.go('admin/manage/groups/' + encodeURIComponent(newName), undefined, true);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[admin/manage/groups:edit.save-success]]');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
||||
if (cid) {
|
||||
var url = 'admin/manage/privileges/' + cid + '?group=' + ajaxify.data.group.name;
|
||||
if (app.flags && app.flags._unsaved === true) {
|
||||
translator.translate('[[global:unsaved-changes]]', function (text) {
|
||||
bootbox.confirm(text, function (navigate) {
|
||||
if (navigate) {
|
||||
app.flags._unsaved = false;
|
||||
ajaxify.go(url);
|
||||
}
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
ajaxify.go(url);
|
||||
}
|
||||
}
|
||||
|
||||
return Groups;
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@ define('admin/manage/groups', ['translator', 'benchpress'], function (translator
|
||||
});
|
||||
});
|
||||
|
||||
$('.groups-list').on('click', 'button[data-action]', function () {
|
||||
$('.groups-list').on('click', '[data-action]', function () {
|
||||
var el = $(this);
|
||||
var action = el.attr('data-action');
|
||||
var groupName = el.parents('tr[data-groupname]').attr('data-groupname');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
define('admin/manage/post-queue', function () {
|
||||
define('admin/manage/post-queue', ['categorySelector'], function (categorySelector) {
|
||||
var PostQueue = {};
|
||||
|
||||
PostQueue.init = function () {
|
||||
@@ -22,31 +22,64 @@ define('admin/manage/post-queue', function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.posts-list').on('click', '.post-content', function () {
|
||||
handleContentEdit('.post-content', '.post-content-editable', 'textarea');
|
||||
handleContentEdit('.topic-title', '.topic-title-editable', 'input');
|
||||
|
||||
$('.posts-list').on('click', '.topic-category[data-editable]', function () {
|
||||
var $this = $(this);
|
||||
var id = $this.parents('[data-id]').attr('data-id');
|
||||
categorySelector.modal(ajaxify.data.allCategories, function (cid) {
|
||||
var category = ajaxify.data.allCategories.find(function (c) {
|
||||
return parseInt(c.cid, 10) === parseInt(cid, 10);
|
||||
});
|
||||
socket.emit('posts.editQueuedContent', {
|
||||
id: id,
|
||||
cid: cid,
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.parseAndTranslate('admin/manage/post-queue', 'posts', {
|
||||
posts: [{
|
||||
category: category,
|
||||
}],
|
||||
}, function (html) {
|
||||
$this.replaceWith(html.find('.topic-category'));
|
||||
});
|
||||
});
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
function handleContentEdit(displayClass, editableClass, inputSelector) {
|
||||
$('.posts-list').on('click', displayClass, function () {
|
||||
var el = $(this);
|
||||
el.addClass('hidden');
|
||||
var textareaParent = el.parent().find('.post-content-editable');
|
||||
textareaParent.removeClass('hidden').find('textarea').focus();
|
||||
var inputEl = el.parent().find(editableClass);
|
||||
inputEl.removeClass('hidden').find(inputSelector).focus();
|
||||
});
|
||||
|
||||
$('.posts-list').on('blur', '.post-content-editable textarea', function () {
|
||||
$('.posts-list').on('blur', editableClass + ' ' + inputSelector, function () {
|
||||
var textarea = $(this);
|
||||
var preview = textarea.parent().parent().find('.post-content');
|
||||
var preview = textarea.parent().parent().find(displayClass);
|
||||
var id = textarea.parents('[data-id]').attr('data-id');
|
||||
var titleEdit = displayClass === '.topic-title';
|
||||
|
||||
socket.emit('posts.editQueuedContent', {
|
||||
id: id,
|
||||
content: textarea.val(),
|
||||
title: titleEdit ? textarea.val() : undefined,
|
||||
content: titleEdit ? undefined : textarea.val(),
|
||||
}, function (err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err);
|
||||
}
|
||||
preview.html(data.postData.content);
|
||||
preview.html(titleEdit ? data.postData.title : data.postData.content);
|
||||
textarea.parent().addClass('hidden');
|
||||
preview.removeClass('hidden');
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return PostQueue;
|
||||
});
|
||||
|
||||
@@ -6,12 +6,12 @@ define('admin/manage/privileges', [
|
||||
'benchpress',
|
||||
'categorySelector',
|
||||
], function (autocomplete, translator, Benchpress, categorySelector) {
|
||||
var Privileges = {};
|
||||
var Privileges = {};
|
||||
|
||||
var cid;
|
||||
|
||||
Privileges.init = function () {
|
||||
cid = isNaN(parseInt(ajaxify.data.cid, 10)) ? 'admin' : ajaxify.data.cid;
|
||||
cid = isNaN(parseInt(ajaxify.data.selectedCategory.cid, 10)) ? 'admin' : ajaxify.data.selectedCategory.cid;
|
||||
|
||||
categorySelector.init($('[component="category-selector"]'), function (category) {
|
||||
cid = parseInt(category.cid, 10);
|
||||
@@ -21,6 +21,8 @@ define('admin/manage/privileges', [
|
||||
});
|
||||
|
||||
Privileges.setupPrivilegeTable();
|
||||
|
||||
highlightRow();
|
||||
};
|
||||
|
||||
Privileges.setupPrivilegeTable = function () {
|
||||
@@ -79,7 +81,7 @@ define('admin/manage/privileges', [
|
||||
Privileges.exposeAssumedPrivileges();
|
||||
};
|
||||
|
||||
Privileges.refreshPrivilegeTable = function () {
|
||||
Privileges.refreshPrivilegeTable = function (groupToHighlight) {
|
||||
socket.emit('admin.categories.getPrivilegeSettings', cid, function (err, privileges) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
@@ -92,6 +94,10 @@ define('admin/manage/privileges', [
|
||||
translator.translate(html, function (html) {
|
||||
$('.privilege-table-container').html(html);
|
||||
Privileges.exposeAssumedPrivileges();
|
||||
|
||||
if (groupToHighlight) {
|
||||
$('[data-group-name="' + groupToHighlight + '"]').addClass('selected');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -182,24 +188,7 @@ define('admin/manage/privileges', [
|
||||
inputEl.focus();
|
||||
|
||||
autocomplete.group(inputEl, function (ev, ui) {
|
||||
var defaultPrivileges;
|
||||
if (ajaxify.data.url === '/admin/manage/privileges/admin') {
|
||||
defaultPrivileges = ['groups:admin:dashboard'];
|
||||
} else {
|
||||
defaultPrivileges = cid ? ['groups:find', 'groups:read', 'groups:topics:read'] : ['groups:chat'];
|
||||
}
|
||||
|
||||
socket.emit('admin.categories.setPrivilege', {
|
||||
cid: isNaN(cid) ? 0 : cid,
|
||||
privilege: defaultPrivileges,
|
||||
set: true,
|
||||
member: ui.item.group.name,
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
Privileges.refreshPrivilegeTable();
|
||||
addGroupToCategory(ui.item.group.name, function () {
|
||||
modal.modal('hide');
|
||||
});
|
||||
});
|
||||
@@ -235,5 +224,42 @@ define('admin/manage/privileges', [
|
||||
});
|
||||
};
|
||||
|
||||
function highlightRow() {
|
||||
var params = utils.params();
|
||||
if (params.group) {
|
||||
var el = $('[data-group-name="' + params.group + '"]');
|
||||
if (el.length) {
|
||||
return el.addClass('selected');
|
||||
}
|
||||
|
||||
addGroupToCategory(params.group);
|
||||
}
|
||||
}
|
||||
|
||||
function addGroupToCategory(group, cb) {
|
||||
var defaultPrivileges;
|
||||
if (ajaxify.data.url === '/admin/manage/privileges/admin') {
|
||||
defaultPrivileges = ['groups:admin:dashboard'];
|
||||
} else {
|
||||
defaultPrivileges = cid ? ['groups:find', 'groups:read', 'groups:topics:read'] : ['groups:chat'];
|
||||
}
|
||||
|
||||
socket.emit('admin.categories.setPrivilege', {
|
||||
cid: isNaN(cid) ? 0 : cid,
|
||||
privilege: defaultPrivileges,
|
||||
set: true,
|
||||
member: group,
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
Privileges.refreshPrivilegeTable(group);
|
||||
if (typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Privileges;
|
||||
});
|
||||
|
||||
@@ -376,33 +376,10 @@ define('admin/manage/users', ['translator', 'benchpress', 'autocomplete'], funct
|
||||
|
||||
timeoutId = setTimeout(function () {
|
||||
$('.fa-spinner').removeClass('hidden');
|
||||
|
||||
socket.emit('admin.user.search', { searchBy: type, query: $this.val() }, function (err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
Benchpress.parse('admin/manage/users', 'users', data, function (html) {
|
||||
translator.translate(html, function (html) {
|
||||
html = $(html);
|
||||
$('.users-table tbody tr').remove();
|
||||
$('.users-table tbody').append(html);
|
||||
html.find('.timeago').timeago();
|
||||
$('.fa-spinner').addClass('hidden');
|
||||
|
||||
if (data && data.users.length === 0) {
|
||||
$('#user-notfound-notify').translateHtml('[[admin/manage/users:search.not-found]]')
|
||||
.removeClass('hide')
|
||||
.addClass('label-danger')
|
||||
.removeClass('label-success');
|
||||
} else {
|
||||
$('#user-notfound-notify').translateHtml(translator.compile('admin/manage/users:alerts.x-users-found', data.users.length, data.timing))
|
||||
.removeClass('hide')
|
||||
.addClass('label-success')
|
||||
.removeClass('label-danger');
|
||||
}
|
||||
});
|
||||
});
|
||||
loadSearchPage({
|
||||
searchBy: type,
|
||||
query: $this.val(),
|
||||
page: 1,
|
||||
});
|
||||
}, 250);
|
||||
});
|
||||
@@ -412,6 +389,38 @@ define('admin/manage/users', ['translator', 'benchpress', 'autocomplete'], funct
|
||||
handleInvite();
|
||||
};
|
||||
|
||||
function loadSearchPage(query) {
|
||||
var qs = decodeURIComponent($.param(query));
|
||||
$.get(config.relative_path + '/api/admin/manage/users/search?' + qs, renderSearchResults).fail(function (xhrErr) {
|
||||
if (xhrErr && xhrErr.responseJSON && xhrErr.responseJSON.error) {
|
||||
app.alertError(xhrErr.responseJSON.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderSearchResults(data) {
|
||||
Benchpress.parse('partials/paginator', { pagination: data.pagination }, function (html) {
|
||||
$('.pagination-container').replaceWith(html);
|
||||
});
|
||||
|
||||
app.parseAndTranslate('admin/manage/users', 'users', data, function (html) {
|
||||
$('.users-table tbody tr').remove();
|
||||
$('.users-table tbody').append(html);
|
||||
html.find('.timeago').timeago();
|
||||
$('.fa-spinner').addClass('hidden');
|
||||
|
||||
if (data && data.users.length === 0) {
|
||||
$('#user-notfound-notify').translateHtml('[[admin/manage/users:search.not-found]]')
|
||||
.removeClass('hidden');
|
||||
$('#user-found-notify').addClass('hidden');
|
||||
} else {
|
||||
$('#user-found-notify').translateHtml(translator.compile('admin/manage/users:alerts.x-users-found', data.matchCount, data.timing))
|
||||
.removeClass('hidden');
|
||||
$('#user-notfound-notify').addClass('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleInvite() {
|
||||
$('[component="user/invite"]').on('click', function () {
|
||||
bootbox.prompt('[[admin/manage/users:alerts.prompt-email]]', function (email) {
|
||||
|
||||
@@ -6,6 +6,7 @@ app = window.app || {};
|
||||
app.isFocused = true;
|
||||
app.currentRoom = null;
|
||||
app.widgets = {};
|
||||
app.flags = {};
|
||||
app.cacheBuster = null;
|
||||
|
||||
(function () {
|
||||
@@ -37,8 +38,6 @@ app.cacheBuster = null;
|
||||
});
|
||||
|
||||
app.load = function () {
|
||||
app.loadProgressiveStylesheet();
|
||||
|
||||
overrides.overrideTimeago();
|
||||
|
||||
var url = ajaxify.start(window.location.pathname.slice(1) + window.location.search + window.location.hash);
|
||||
@@ -117,6 +116,9 @@ app.cacheBuster = null;
|
||||
headers: {
|
||||
'x-csrf-token': config.csrf_token,
|
||||
},
|
||||
beforeSend: function () {
|
||||
app.flags._logout = true;
|
||||
},
|
||||
success: function (data) {
|
||||
$(window).trigger('action:app.loggedOut', data);
|
||||
if (redirect) {
|
||||
@@ -169,6 +171,10 @@ app.cacheBuster = null;
|
||||
};
|
||||
|
||||
app.handleInvalidSession = function () {
|
||||
if (app.flags._logout) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.disconnect();
|
||||
bootbox.alert({
|
||||
title: '[[error:invalid-session]]',
|
||||
@@ -743,14 +749,6 @@ app.cacheBuster = null;
|
||||
});
|
||||
};
|
||||
|
||||
app.loadProgressiveStylesheet = function () {
|
||||
var linkEl = document.createElement('link');
|
||||
linkEl.rel = 'stylesheet';
|
||||
linkEl.href = config.relative_path + '/assets/js-enabled.css?' + app.cacheBuster;
|
||||
|
||||
document.head.appendChild(linkEl);
|
||||
};
|
||||
|
||||
app.showCookieWarning = function () {
|
||||
require(['translator', 'storage'], function (translator, storage) {
|
||||
if (!config.cookies.enabled || !navigator.cookieEnabled) {
|
||||
|
||||
@@ -4,25 +4,17 @@ define('forum/category', [
|
||||
'forum/infinitescroll',
|
||||
'share',
|
||||
'navigator',
|
||||
'forum/category/tools',
|
||||
'topicList',
|
||||
'sort',
|
||||
], function (infinitescroll, share, navigator, categoryTools, topicList, sort) {
|
||||
], function (infinitescroll, share, navigator, topicList, sort) {
|
||||
var Category = {};
|
||||
|
||||
$(window).on('action:ajaxify.start', function (ev, data) {
|
||||
if (!String(data.url).startsWith('category/')) {
|
||||
navigator.disable();
|
||||
|
||||
removeListeners();
|
||||
}
|
||||
});
|
||||
|
||||
function removeListeners() {
|
||||
categoryTools.removeListeners();
|
||||
topicList.removeListeners();
|
||||
}
|
||||
|
||||
Category.init = function () {
|
||||
var cid = ajaxify.data.cid;
|
||||
|
||||
@@ -30,8 +22,6 @@ define('forum/category', [
|
||||
|
||||
share.addShareHandlers(ajaxify.data.name);
|
||||
|
||||
categoryTools.init(cid);
|
||||
|
||||
topicList.init('category', loadTopicsAfter);
|
||||
|
||||
sort.handleSort('categoryTopicSort', 'user.setCategorySort', 'category/' + ajaxify.data.slug);
|
||||
|
||||
@@ -9,9 +9,7 @@ define('forum/category/tools', [
|
||||
], function (topicSelect, components, translator) {
|
||||
var CategoryTools = {};
|
||||
|
||||
CategoryTools.init = function (cid) {
|
||||
CategoryTools.cid = cid;
|
||||
|
||||
CategoryTools.init = function () {
|
||||
topicSelect.init(updateDropdownOptions);
|
||||
|
||||
handlePinnedTopicSort();
|
||||
@@ -36,7 +34,7 @@ define('forum/category/tools', [
|
||||
if (!tids.length) {
|
||||
return app.alertError('[[error:no-topics-selected]]');
|
||||
}
|
||||
socket.emit('topics.lock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete);
|
||||
socket.emit('topics.lock', { tids: tids }, onCommandComplete);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -45,7 +43,7 @@ define('forum/category/tools', [
|
||||
if (!tids.length) {
|
||||
return app.alertError('[[error:no-topics-selected]]');
|
||||
}
|
||||
socket.emit('topics.unlock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete);
|
||||
socket.emit('topics.unlock', { tids: tids }, onCommandComplete);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -54,7 +52,7 @@ define('forum/category/tools', [
|
||||
if (!tids.length) {
|
||||
return app.alertError('[[error:no-topics-selected]]');
|
||||
}
|
||||
socket.emit('topics.pin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete);
|
||||
socket.emit('topics.pin', { tids: tids }, onCommandComplete);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -63,7 +61,7 @@ define('forum/category/tools', [
|
||||
if (!tids.length) {
|
||||
return app.alertError('[[error:no-topics-selected]]');
|
||||
}
|
||||
socket.emit('topics.unpin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete);
|
||||
socket.emit('topics.unpin', { tids: tids }, onCommandComplete);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -92,13 +90,17 @@ define('forum/category/tools', [
|
||||
if (!tids.length) {
|
||||
return app.alertError('[[error:no-topics-selected]]');
|
||||
}
|
||||
move.init(tids, cid, onCommandComplete);
|
||||
move.init(tids, null, onCommandComplete);
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
components.get('topic/move-all').on('click', function () {
|
||||
var cid = ajaxify.data.cid;
|
||||
if (!ajaxify.data.template.category) {
|
||||
return app.alertError('[[error:invalid-data]]');
|
||||
}
|
||||
require(['forum/topic/move'], function (move) {
|
||||
move.init(null, cid, function (err) {
|
||||
if (err) {
|
||||
@@ -110,7 +112,7 @@ define('forum/category/tools', [
|
||||
});
|
||||
});
|
||||
|
||||
$('.category').on('click', '[component="topic/merge"]', function () {
|
||||
components.get('topic/merge').on('click', function () {
|
||||
require(['forum/topic/merge'], function (merge) {
|
||||
merge.init();
|
||||
});
|
||||
@@ -138,7 +140,7 @@ define('forum/category/tools', [
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('topics.' + command, { tids: tids, cid: CategoryTools.cid }, onDeletePurgeComplete);
|
||||
socket.emit('topics.' + command, { tids: tids }, onDeletePurgeComplete);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -259,7 +261,7 @@ define('forum/category/tools', [
|
||||
return memo;
|
||||
}, 0);
|
||||
|
||||
if (!ajaxify.data.privileges.isAdminOrMod || numPinned < 2) {
|
||||
if ((!app.user.isAdmin && !app.user.isMod) || numPinned < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ define('forum/chats', [
|
||||
Chats.addRenameHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="rename"]'));
|
||||
Chats.addLeaveHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="leave"]'));
|
||||
Chats.addScrollHandler(ajaxify.data.roomId, ajaxify.data.uid, $('.chat-content'));
|
||||
Chats.addScrollBottomHandler($('.chat-content'));
|
||||
Chats.addCharactersLeftHandler($('[component="chat/main-wrapper"]'));
|
||||
Chats.addIPHandler($('[component="chat/main-wrapper"]'));
|
||||
Chats.createAutoComplete($('[component="chat/input"]'));
|
||||
@@ -101,6 +102,7 @@ define('forum/chats', [
|
||||
Chats.addScrollHandler = function (roomId, uid, el) {
|
||||
var loading = false;
|
||||
el.off('scroll').on('scroll', function () {
|
||||
messages.toggleScrollUpAlert(el);
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
@@ -144,6 +146,14 @@ define('forum/chats', [
|
||||
});
|
||||
};
|
||||
|
||||
Chats.addScrollBottomHandler = function (chatContent) {
|
||||
chatContent.parent()
|
||||
.find('[component="chat/messages/scroll-up-alert"]')
|
||||
.off('click').on('click', function () {
|
||||
messages.scrollToBottom(chatContent);
|
||||
});
|
||||
};
|
||||
|
||||
Chats.addCharactersLeftHandler = function (parent) {
|
||||
var element = parent.find('[component="chat/input"]');
|
||||
element.on('change keyup paste', function () {
|
||||
|
||||
@@ -84,11 +84,13 @@ define('forum/chats/messages', ['components', 'sounds', 'translator', 'benchpres
|
||||
|
||||
function onMessagesParsed(chatContentEl, html) {
|
||||
var newMessage = $(html);
|
||||
|
||||
var isAtBottom = messages.isAtBottom(chatContentEl);
|
||||
newMessage.appendTo(chatContentEl);
|
||||
newMessage.find('.timeago').timeago();
|
||||
newMessage.find('img:not(.not-responsive)').addClass('img-responsive');
|
||||
messages.scrollToBottom(chatContentEl);
|
||||
if (isAtBottom) {
|
||||
messages.scrollToBottom(chatContentEl);
|
||||
}
|
||||
|
||||
$(window).trigger('action:chat.received', {
|
||||
messageEl: newMessage,
|
||||
@@ -112,13 +114,31 @@ define('forum/chats/messages', ['components', 'sounds', 'translator', 'benchpres
|
||||
}
|
||||
};
|
||||
|
||||
messages.isAtBottom = function (containerEl, threshold) {
|
||||
if (containerEl.length) {
|
||||
var distanceToBottom = containerEl[0].scrollHeight - (
|
||||
containerEl.outerHeight() + containerEl.scrollTop()
|
||||
);
|
||||
return distanceToBottom < (threshold || 100);
|
||||
}
|
||||
};
|
||||
|
||||
messages.scrollToBottom = function (containerEl) {
|
||||
if (containerEl.length) {
|
||||
if (containerEl && containerEl.length) {
|
||||
containerEl.scrollTop(containerEl[0].scrollHeight - containerEl.height());
|
||||
containerEl.parent()
|
||||
.find('[component="chat/messages/scroll-up-alert"]')
|
||||
.addClass('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
messages.toggleScrollUpAlert = function (containerEl) {
|
||||
var isAtBottom = messages.isAtBottom(containerEl, 300);
|
||||
containerEl.parent()
|
||||
.find('[component="chat/messages/scroll-up-alert"]')
|
||||
.toggleClass('hidden', isAtBottom);
|
||||
};
|
||||
|
||||
messages.prepEdit = function (inputEl, messageId, roomId) {
|
||||
socket.emit('modules.chats.getRaw', { mid: messageId, roomId: roomId }, function (err, raw) {
|
||||
if (err) {
|
||||
@@ -130,6 +150,12 @@ define('forum/chats/messages', ['components', 'sounds', 'translator', 'benchpres
|
||||
// message, instead of posting a new one.
|
||||
inputEl.attr('data-mid', messageId).addClass('editing');
|
||||
inputEl.val(raw).focus();
|
||||
|
||||
$(window).trigger('action:chat.prepEdit', {
|
||||
inputEl: inputEl,
|
||||
messageId: messageId,
|
||||
roomId: roomId,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ define('forum/chats/search', ['components'], function (components) {
|
||||
socket.emit('user.search', {
|
||||
query: username,
|
||||
searchBy: 'username',
|
||||
paginate: false,
|
||||
}, function (err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
|
||||
@@ -8,9 +8,10 @@ define('forum/flags/detail', ['forum/flags/list', 'components', 'translator', 'b
|
||||
$('#state').val(ajaxify.data.state).removeAttr('disabled');
|
||||
$('#assignee').val(ajaxify.data.assignee).removeAttr('disabled');
|
||||
|
||||
$('[data-action]').on('click', function () {
|
||||
$('#content > div').on('click', '[data-action]', function () {
|
||||
var action = this.getAttribute('data-action');
|
||||
var uid = $(this).parents('[data-uid]').attr('data-uid');
|
||||
var noteEl = document.getElementById('note');
|
||||
|
||||
switch (action) {
|
||||
case 'assign':
|
||||
@@ -33,7 +34,8 @@ define('forum/flags/detail', ['forum/flags/list', 'components', 'translator', 'b
|
||||
case 'appendNote':
|
||||
socket.emit('flags.appendNote', {
|
||||
flagId: ajaxify.data.flagId,
|
||||
note: document.getElementById('note').value,
|
||||
note: noteEl.value,
|
||||
datetime: noteEl.getAttribute('data-datetime'),
|
||||
}, function (err, payload) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
@@ -41,6 +43,9 @@ define('forum/flags/detail', ['forum/flags/list', 'components', 'translator', 'b
|
||||
app.alertSuccess('[[flags:note-added]]');
|
||||
Detail.reloadNotes(payload.notes);
|
||||
Detail.reloadHistory(payload.history);
|
||||
|
||||
noteEl.setAttribute('data-action', 'appendNote');
|
||||
noteEl.removeAttribute('data-datetime');
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -75,6 +80,43 @@ define('forum/flags/detail', ['forum/flags/list', 'components', 'translator', 'b
|
||||
case 'restore-post':
|
||||
postAction('restore', ajaxify.data.target.pid, ajaxify.data.target.tid);
|
||||
break;
|
||||
|
||||
case 'delete-note':
|
||||
var datetime = this.closest('[data-datetime]').getAttribute('data-datetime');
|
||||
bootbox.confirm('[[flags:delete-note-confirm]]', function (ok) {
|
||||
if (ok) {
|
||||
socket.emit('flags.deleteNote', {
|
||||
flagId: ajaxify.data.flagId,
|
||||
datetime: datetime,
|
||||
}, function (err, payload) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[flags:note-deleted]]');
|
||||
Detail.reloadNotes(payload.notes);
|
||||
Detail.reloadHistory(payload.history);
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'prepare-edit':
|
||||
var selectedNoteEl = this.closest('[data-index]');
|
||||
var index = selectedNoteEl.getAttribute('data-index');
|
||||
var textareaEl = document.getElementById('note');
|
||||
textareaEl.value = ajaxify.data.notes[index].content;
|
||||
textareaEl.setAttribute('data-datetime', ajaxify.data.notes[index].datetime);
|
||||
|
||||
var siblings = selectedNoteEl.parentElement.children;
|
||||
for (var el in siblings) {
|
||||
if (siblings.hasOwnProperty(el)) {
|
||||
siblings[el].classList.remove('editing');
|
||||
}
|
||||
}
|
||||
selectedNoteEl.classList.add('editing');
|
||||
textareaEl.focus();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -103,6 +145,7 @@ define('forum/flags/detail', ['forum/flags/list', 'components', 'translator', 'b
|
||||
}
|
||||
|
||||
Detail.reloadNotes = function (notes) {
|
||||
ajaxify.data.notes = notes;
|
||||
Benchpress.parse('flags/detail', 'notes', {
|
||||
notes: notes,
|
||||
}, function (html) {
|
||||
|
||||
@@ -5,7 +5,13 @@ define('forum/flags/list', ['components', 'Chart'], function (components, Chart)
|
||||
|
||||
Flags.init = function () {
|
||||
Flags.enableFilterForm();
|
||||
Flags.handleGraphs();
|
||||
|
||||
var graphWrapper = $('#flags-daily-wrapper');
|
||||
var graphFooter = graphWrapper.siblings('.panel-footer');
|
||||
$('#flags-daily-wrapper').one('shown.bs.collapse', function () {
|
||||
Flags.handleGraphs();
|
||||
});
|
||||
graphFooter.on('click', graphWrapper.collapse.bind(graphWrapper, 'toggle'));
|
||||
};
|
||||
|
||||
Flags.enableFilterForm = function () {
|
||||
@@ -18,7 +24,7 @@ define('forum/flags/list', ['components', 'Chart'], function (components, Chart)
|
||||
}
|
||||
}
|
||||
|
||||
filtersEl.find('button').on('click', function () {
|
||||
document.getElementById('apply-filters').addEventListener('click', function () {
|
||||
var payload = filtersEl.serializeArray().filter(function (item) {
|
||||
return !!item.value;
|
||||
});
|
||||
|
||||
@@ -14,7 +14,6 @@ define('forum/unread', ['topicSelect', 'components', 'topicList'], function (top
|
||||
app.enterRoom('unread_topics');
|
||||
|
||||
topicList.init('unread');
|
||||
topicSelect.init();
|
||||
|
||||
updateUnreadTopicCount('/' + ajaxify.data.selectedFilter.url, ajaxify.data.topicCount);
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ define('categorySearch', function () {
|
||||
if (!searchEl.length) {
|
||||
return;
|
||||
}
|
||||
var toggleVisibility = searchEl.parent('[component="category/dropdown"]').length > 0;
|
||||
var toggleVisibility = searchEl.parent('[component="category/dropdown"]').length > 0 ||
|
||||
searchEl.parent('[component="category-selector"]').length > 0;
|
||||
|
||||
var categoryEls = el.find('[component="category/list"] [data-cid]');
|
||||
el.on('show.bs.dropdown', function () {
|
||||
function revealParents(cid) {
|
||||
|
||||
@@ -91,7 +91,9 @@ define('chat', [
|
||||
|
||||
if (modal.is(':visible')) {
|
||||
taskbar.updateActive(modal.attr('data-uuid'));
|
||||
ChatsMessages.scrollToBottom(modal.find('.chat-content'));
|
||||
if (ChatsMessages.isAtBottom(modal.find('.chat-content'))) {
|
||||
ChatsMessages.scrollToBottom(modal.find('.chat-content'));
|
||||
}
|
||||
} else if (!ajaxify.data.template.chats) {
|
||||
module.toggleNew(modal.attr('data-uuid'), true, true);
|
||||
}
|
||||
@@ -239,6 +241,7 @@ define('chat', [
|
||||
Chats.createAutoComplete(chatModal.find('[component="chat/input"]'));
|
||||
|
||||
Chats.addScrollHandler(chatModal.attr('data-roomid'), data.uid, chatModal.find('.chat-content'));
|
||||
Chats.addScrollBottomHandler(chatModal.find('.chat-content'));
|
||||
|
||||
Chats.addCharactersLeftHandler(chatModal);
|
||||
Chats.addIPHandler(chatModal);
|
||||
|
||||
@@ -49,6 +49,11 @@ define('flags', function () {
|
||||
});
|
||||
|
||||
flagModal.modal('show');
|
||||
$(window).trigger('action:flag.showModal', {
|
||||
modalEl: flagModal,
|
||||
type: data.type,
|
||||
id: data.id,
|
||||
});
|
||||
|
||||
flagModal.find('#flag-reason-custom').on('keyup blur change', checkFlagButtonEnable);
|
||||
});
|
||||
|
||||
@@ -70,12 +70,13 @@
|
||||
function buildLinkTag(tag) {
|
||||
var link = tag.link ? 'link="' + tag.link + '" ' : '';
|
||||
var rel = tag.rel ? 'rel="' + tag.rel + '" ' : '';
|
||||
var as = tag.as ? 'as="' + tag.as + '" ' : '';
|
||||
var type = tag.type ? 'type="' + tag.type + '" ' : '';
|
||||
var href = tag.href ? 'href="' + tag.href + '" ' : '';
|
||||
var sizes = tag.sizes ? 'sizes="' + tag.sizes + '" ' : '';
|
||||
var title = tag.title ? 'title="' + tag.title + '" ' : '';
|
||||
|
||||
return '<link ' + link + rel + type + sizes + title + href + '/>\n\t';
|
||||
return '<link ' + link + rel + as + type + sizes + title + href + '/>\n\t';
|
||||
}
|
||||
|
||||
function stringify(obj) {
|
||||
|
||||
@@ -5,7 +5,8 @@ define('topicList', [
|
||||
'handleBack',
|
||||
'topicSelect',
|
||||
'categorySearch',
|
||||
], function (infinitescroll, handleBack, topicSelect, categorySearch) {
|
||||
'forum/category/tools',
|
||||
], function (infinitescroll, handleBack, topicSelect, categorySearch, categoryTools) {
|
||||
var TopicList = {};
|
||||
var templateName = '';
|
||||
|
||||
@@ -24,6 +25,7 @@ define('topicList', [
|
||||
|
||||
$(window).on('action:ajaxify.start', function () {
|
||||
TopicList.removeListeners();
|
||||
categoryTools.removeListeners();
|
||||
});
|
||||
|
||||
TopicList.init = function (template, cb) {
|
||||
@@ -32,6 +34,8 @@ define('topicList', [
|
||||
templateName = template;
|
||||
loadTopicsCallback = cb || loadTopicsAfter;
|
||||
|
||||
categoryTools.init();
|
||||
|
||||
TopicList.watchForNewPosts();
|
||||
|
||||
TopicList.handleCategorySelection();
|
||||
|
||||
@@ -278,7 +278,7 @@
|
||||
}
|
||||
|
||||
if (namespace && !key) {
|
||||
warn('Missing key in translation token "' + name + '"');
|
||||
warn('Missing key in translation token "' + name + '" for language "' + self.lang + '"');
|
||||
return Promise.resolve('[[' + namespace + ']]');
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
return translation.then(function (translated) {
|
||||
// check if the translation is missing first
|
||||
if (!translated) {
|
||||
warn('Missing translation "' + name + '"');
|
||||
warn('Missing translation "' + name + '" for language "' + self.lang + '"');
|
||||
return backup || key;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ module.exports = function (Categories) {
|
||||
'cid:' + cid + ':tids',
|
||||
'cid:' + cid + ':tids:pinned',
|
||||
'cid:' + cid + ':tids:posts',
|
||||
'cid:' + cid + ':tids:votes',
|
||||
'cid:' + cid + ':tids:lastposttime',
|
||||
'cid:' + cid + ':recent_tids',
|
||||
'cid:' + cid + ':pids',
|
||||
'cid:' + cid + ':read_by_uid',
|
||||
'cid:' + cid + ':uid:watch:state',
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
const nconf = require('nconf');
|
||||
const validator = require('validator');
|
||||
|
||||
const db = require('../../database');
|
||||
const user = require('../../user');
|
||||
const categories = require('../../categories');
|
||||
const groups = require('../../groups');
|
||||
const meta = require('../../meta');
|
||||
const pagination = require('../../pagination');
|
||||
const events = require('../../events');
|
||||
|
||||
const groupsController = module.exports;
|
||||
|
||||
@@ -47,12 +51,15 @@ groupsController.get = async function (req, res, next) {
|
||||
};
|
||||
});
|
||||
|
||||
const allCategories = await categories.buildForSelectAll();
|
||||
|
||||
res.render('admin/manage/group', {
|
||||
group: group,
|
||||
groupNames: groupNameData,
|
||||
allowPrivateGroups: meta.config.allowPrivateGroups,
|
||||
maximumGroupNameLength: meta.config.maximumGroupNameLength,
|
||||
maximumGroupTitleLength: meta.config.maximumGroupTitleLength,
|
||||
categories: allCategories,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -60,3 +67,29 @@ async function getGroupNames() {
|
||||
const groupNames = await db.getSortedSetRange('groups:createtime', 0, -1);
|
||||
return groupNames.filter(name => name !== 'registered-users' && !groups.isPrivilegeGroup(name));
|
||||
}
|
||||
|
||||
groupsController.getCSV = async function (req, res) {
|
||||
const referer = req.headers.referer;
|
||||
|
||||
if (!referer || !referer.replace(nconf.get('url'), '').startsWith('/admin/manage/groups')) {
|
||||
return res.status(403).send('[[error:invalid-origin]]');
|
||||
}
|
||||
await events.log({
|
||||
type: 'getGroupCSV',
|
||||
uid: req.uid,
|
||||
ip: req.ip,
|
||||
});
|
||||
const groupName = req.params.groupname;
|
||||
const members = (await groups.getMembersOfGroups([groupName]))[0];
|
||||
const fields = ['email', 'username', 'uid'];
|
||||
const userData = await user.getUsersFields(members, fields);
|
||||
let csvContent = fields.join(',') + '\n';
|
||||
csvContent += userData.reduce((memo, user) => {
|
||||
memo += user.email + ',' + user.username + ',' + user.uid + '\n';
|
||||
return memo;
|
||||
}, '');
|
||||
|
||||
res.attachment(validator.escape(groupName) + '_members.csv');
|
||||
res.setHeader('Content-Type', 'text/csv');
|
||||
res.end(csvContent);
|
||||
};
|
||||
|
||||
@@ -79,6 +79,12 @@ async function getNodeInfo() {
|
||||
release: os.release(),
|
||||
load: os.loadavg().map(function (load) { return load.toFixed(2); }).join(', '),
|
||||
},
|
||||
nodebb: {
|
||||
isCluster: nconf.get('isCluster'),
|
||||
isPrimary: nconf.get('isPrimary'),
|
||||
runJobs: nconf.get('runJobs'),
|
||||
jobsDisabled: nconf.get('jobsDisabled'),
|
||||
},
|
||||
};
|
||||
data.process.cpuUsage.user /= 1000000;
|
||||
data.process.cpuUsage.user = data.process.cpuUsage.user.toFixed(2);
|
||||
@@ -109,5 +115,5 @@ async function getGitInfo() {
|
||||
getAsync('git rev-parse HEAD'),
|
||||
getAsync('git rev-parse --abbrev-ref HEAD'),
|
||||
]);
|
||||
return { hash: hash, branch: branch };
|
||||
return { hash: hash, hashShort: hash.substr(0, 6), branch: branch };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const nconf = require('nconf');
|
||||
const validator = require('validator');
|
||||
|
||||
const user = require('../../user');
|
||||
const meta = require('../../meta');
|
||||
@@ -15,11 +16,56 @@ const usersController = module.exports;
|
||||
const userFields = ['uid', 'username', 'userslug', 'email', 'postcount', 'joindate', 'banned',
|
||||
'reputation', 'picture', 'flags', 'lastonline', 'email:confirmed'];
|
||||
|
||||
usersController.search = function (req, res) {
|
||||
res.render('admin/manage/users', {
|
||||
search_display: '',
|
||||
users: [],
|
||||
usersController.search = async function (req, res) {
|
||||
const page = parseInt(req.query.page, 10) || 1;
|
||||
let resultsPerPage = parseInt(req.query.resultsPerPage, 10) || 50;
|
||||
if (![50, 100, 250, 500].includes(resultsPerPage)) {
|
||||
resultsPerPage = 50;
|
||||
}
|
||||
const searchData = await user.search({
|
||||
uid: req.uid,
|
||||
query: req.query.query,
|
||||
searchBy: req.query.searchBy,
|
||||
page: page,
|
||||
resultsPerPage: resultsPerPage,
|
||||
findUids: async function (query, searchBy, hardCap) {
|
||||
if (!query || query.length < 2) {
|
||||
return [];
|
||||
}
|
||||
hardCap = hardCap || resultsPerPage * 10;
|
||||
if (!query.endsWith('*')) {
|
||||
query += '*';
|
||||
}
|
||||
|
||||
const data = await db.getSortedSetScan({
|
||||
key: searchBy + ':sorted',
|
||||
match: query,
|
||||
limit: hardCap,
|
||||
});
|
||||
return data.map(data => data.split(':')[1]);
|
||||
},
|
||||
});
|
||||
|
||||
const uids = searchData.users.map(user => user && user.uid);
|
||||
const userInfo = await user.getUsersFields(uids, ['email', 'flags', 'lastonline', 'joindate']);
|
||||
|
||||
searchData.users.forEach(function (user, index) {
|
||||
if (user && userInfo[index]) {
|
||||
user.email = userInfo[index].email;
|
||||
user.flags = userInfo[index].flags || 0;
|
||||
user.lastonlineISO = userInfo[index].lastonlineISO;
|
||||
user.joindateISO = userInfo[index].joindateISO;
|
||||
}
|
||||
});
|
||||
searchData.query = validator.escape(String(req.query.query || ''));
|
||||
searchData.uidQuery = req.query.searchBy === 'uid' ? searchData.query : '';
|
||||
searchData.usernameQuery = req.query.searchBy === 'username' ? searchData.query : '';
|
||||
searchData.emailQuery = req.query.searchBy === 'email' ? searchData.query : '';
|
||||
searchData.ipQuery = req.query.searchBy === 'uid' ? searchData.query : '';
|
||||
searchData.resultsPerPage = resultsPerPage;
|
||||
searchData.pagination = pagination.create(page, searchData.pageCount, req.query);
|
||||
searchData.search_display = '';
|
||||
res.render('admin/manage/users', searchData);
|
||||
};
|
||||
|
||||
usersController.sortByJoinDate = async function (req, res) {
|
||||
|
||||
@@ -95,6 +95,7 @@ categoryController.get = async function (req, res, next) {
|
||||
categoryData.description = translator.escape(categoryData.description);
|
||||
categoryData.privileges = userPrivileges;
|
||||
categoryData.showSelect = userPrivileges.editable;
|
||||
categoryData.showTopicTools = userPrivileges.editable;
|
||||
categoryData.rssFeedUrl = nconf.get('url') + '/category/' + categoryData.cid + '.rss';
|
||||
if (parseInt(req.uid, 10)) {
|
||||
categories.markAsRead([cid], req.uid);
|
||||
|
||||
@@ -72,21 +72,25 @@ helpers.buildFilters = function (url, filter, query) {
|
||||
url: url + helpers.buildQueryString(query.cid, '', query.term),
|
||||
selected: filter === '',
|
||||
filter: '',
|
||||
icon: 'fa-book',
|
||||
}, {
|
||||
name: '[[unread:new-topics]]',
|
||||
url: url + helpers.buildQueryString(query.cid, 'new', query.term),
|
||||
selected: filter === 'new',
|
||||
filter: 'new',
|
||||
icon: 'fa-clock-o',
|
||||
}, {
|
||||
name: '[[unread:watched-topics]]',
|
||||
url: url + helpers.buildQueryString(query.cid, 'watched', query.term),
|
||||
selected: filter === 'watched',
|
||||
filter: 'watched',
|
||||
icon: 'fa-bell-o',
|
||||
}, {
|
||||
name: '[[unread:unreplied-topics]]',
|
||||
url: url + helpers.buildQueryString(query.cid, 'unreplied', query.term),
|
||||
selected: filter === 'unreplied',
|
||||
filter: 'unreplied',
|
||||
icon: 'fa-reply',
|
||||
}];
|
||||
};
|
||||
|
||||
|
||||
@@ -181,12 +181,17 @@ modsController.postQueue = async function (req, res, next) {
|
||||
const page = parseInt(req.query.page, 10) || 1;
|
||||
const postsPerPage = 20;
|
||||
|
||||
const [ids, isAdminOrGlobalMod, moderatedCids] = await Promise.all([
|
||||
const [ids, isAdminOrGlobalMod, moderatedCids, allCategories] = await Promise.all([
|
||||
db.getSortedSetRange('post:queue', 0, -1),
|
||||
user.isAdminOrGlobalMod(req.uid),
|
||||
user.getModeratedCids(req.uid),
|
||||
categories.buildForSelect(req.uid, 'find', ['disabled', 'link', 'slug']),
|
||||
]);
|
||||
|
||||
allCategories.forEach((c) => {
|
||||
c.disabledClass = !isAdminOrGlobalMod && !moderatedCids.includes(String(c.cid));
|
||||
});
|
||||
|
||||
let postData = await getQueuedPosts(ids);
|
||||
postData = postData.filter(p => p && (isAdminOrGlobalMod || moderatedCids.includes(String(p.category.cid))));
|
||||
|
||||
@@ -198,6 +203,7 @@ modsController.postQueue = async function (req, res, next) {
|
||||
res.render('admin/manage/post-queue', {
|
||||
title: '[[pages:post-queue]]',
|
||||
posts: postData,
|
||||
allCategories: allCategories,
|
||||
pagination: pagination.create(page, pageCount),
|
||||
breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[pages:post-queue]]' }]),
|
||||
});
|
||||
|
||||
@@ -37,11 +37,12 @@ recentController.getData = async function (req, url, sort) {
|
||||
states.push(categories.watchStates.ignoring);
|
||||
}
|
||||
|
||||
const [settings, categoryData, rssToken, canPost] = await Promise.all([
|
||||
const [settings, categoryData, rssToken, canPost, isPrivileged] = await Promise.all([
|
||||
user.getSettings(req.uid),
|
||||
helpers.getCategoriesByStates(req.uid, cid, states),
|
||||
user.auth.getFeedToken(req.uid),
|
||||
canPostTopic(req.uid),
|
||||
user.isPrivileged(req.uid),
|
||||
]);
|
||||
|
||||
const start = Math.max(0, (page - 1) * settings.topicsPerPage);
|
||||
@@ -60,6 +61,8 @@ recentController.getData = async function (req, url, sort) {
|
||||
});
|
||||
|
||||
data.canPost = canPost;
|
||||
data.showSelect = isPrivileged;
|
||||
data.showTopicTools = isPrivileged;
|
||||
data.categories = categoryData.categories;
|
||||
data.allCategoriesUrl = url + helpers.buildQueryString('', filter, '');
|
||||
data.selectedCategory = categoryData.selectedCategory || null;
|
||||
|
||||
@@ -22,9 +22,10 @@ unreadController.get = async function (req, res, next) {
|
||||
if (!filterData.filters[filter]) {
|
||||
return next();
|
||||
}
|
||||
const [watchedCategories, userSettings] = await Promise.all([
|
||||
const [watchedCategories, userSettings, isPrivileged] = await Promise.all([
|
||||
getWatchedCategories(req.uid, cid, filter),
|
||||
user.getSettings(req.uid),
|
||||
user.isPrivileged(req.uid),
|
||||
]);
|
||||
|
||||
const page = parseInt(req.query.page, 10) || 1;
|
||||
@@ -48,7 +49,8 @@ unreadController.get = async function (req, res, next) {
|
||||
req.query.page = Math.max(1, Math.min(data.pageCount, page));
|
||||
return helpers.redirect(res, '/unread?' + querystring.stringify(req.query));
|
||||
}
|
||||
|
||||
data.showSelect = true;
|
||||
data.showTopicTools = isPrivileged;
|
||||
data.categories = watchedCategories.categories;
|
||||
data.allCategoriesUrl = 'unread' + helpers.buildQueryString('', filter, '');
|
||||
data.selectedCategory = watchedCategories.selectedCategory;
|
||||
|
||||
@@ -30,10 +30,14 @@ usersController.index = async function (req, res, next) {
|
||||
}
|
||||
};
|
||||
|
||||
usersController.search = async function (req, res, next) {
|
||||
const allowed = await privileges.global.can('search:users', req.uid);
|
||||
if (!allowed) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
usersController.search = async function (req, res) {
|
||||
const [allowed, isPrivileged] = await Promise.all([
|
||||
privileges.global.can('search:users', req.uid),
|
||||
user.isPrivileged(req.uid),
|
||||
]);
|
||||
|
||||
if (!allowed || ((req.query.searchBy === 'ip' || req.query.searchBy === 'email' || req.query.bannedOnly === 'true' || req.query.flaggedOnly === 'true') && !isPrivileged)) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
const [searchData, isAdminOrGlobalMod] = await Promise.all([
|
||||
user.search({
|
||||
|
||||
@@ -168,7 +168,7 @@ mongoModule.close = function (callback) {
|
||||
|
||||
mongoModule.socketAdapter = function () {
|
||||
const mongoAdapter = require('@nodebb/socket.io-adapter-mongo');
|
||||
return mongoAdapter(connection.getConnectionString());
|
||||
return mongoAdapter(connection.getConnectionString(), connection.getConnectionOptions());
|
||||
};
|
||||
|
||||
require('./mongo/main')(mongoModule);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user