mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-26 08:31:22 +01:00
Merge branch 'master' of https://github.com/NodeBB/NodeBB
This commit is contained in:
84
CHANGELOG.md
84
CHANGELOG.md
@@ -1,3 +1,87 @@
|
||||
#### 1.12.2 (2019-05-15)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v1.12.2 (22db818e)
|
||||
* bump themes #7576 (d349754d)
|
||||
* bump themes (59bdc970)
|
||||
* bump themes (abcca134)
|
||||
* bump themes (551b18cd)
|
||||
* incrementing version number - v1.12.1 (dd973abe)
|
||||
* **deps:**
|
||||
* update dependency lint-staged to v8.1.7 (dc6b49ca)
|
||||
* update commitlint monorepo (9998e86b)
|
||||
* update dependency jsdom to v15.1.0 (fcd6dc88)
|
||||
* update dependency mocha to v6.1.4 (3ff8154b)
|
||||
* update node:8.16.0 docker digest to b5484d1 (6421f10f)
|
||||
* update dependency husky to v2.3.0 (c20e3313)
|
||||
* update dependency nyc to v14.1.1 (#7584) (9047210c)
|
||||
* update dependency eslint to v5.16.0 (692e2ead)
|
||||
* update dependency nyc to v14 (9210baf5)
|
||||
* update dependency husky to v2.2.0 (8a018a5f)
|
||||
* update dependency lint-staged to v8.1.6 (4e39caf8)
|
||||
* update dependency husky to v2.1.0 (65ff0bbd)
|
||||
* update dependency husky to v2 (e81a1dbb)
|
||||
* update dependency eslint-plugin-import to v2.17.2 (#7546) (c1fb17f9)
|
||||
* update dependency jsdom to v15 (#7556) (d4d8d98f)
|
||||
* update dependency jsdom to v14.1.0 (#7555) (ca694fd1)
|
||||
* update node.js to v8.16.0 (#7554) (f10708e7)
|
||||
* update dependency eslint-plugin-import to v2.17.1 (69dd8e4d)
|
||||
* update dependency mocha to v6.1.2 (b7169772)
|
||||
|
||||
##### Documentation Changes
|
||||
|
||||
* updated changelog (93b688d0)
|
||||
|
||||
##### New Features
|
||||
|
||||
* let theme know downvoting is disabled, closes https://github.com/NodeBB/NodeBB/pull/7568 (bd94fbc2)
|
||||
* closes #7583 (cf5aeace)
|
||||
* #7319 (9385c8e3)
|
||||
* add node12 to travis (1a7036a6)
|
||||
* allow file uploading on registration interstitial (ddffc904)
|
||||
* #7527 (ba5e1eaa)
|
||||
* #7515 (c38db4f7)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* #7599 image size measurement erroring out on missing path (0d86781c)
|
||||
* #7590 updated chat and post edit and delete timeout labels in ACP (4f0dc443)
|
||||
* tests (3a7e99a5)
|
||||
* #7586, switchTimeagoLanguage shouldn't discriminate against languages w/o shorthands (1703233f)
|
||||
* #7576 "Disable password changes" can be sidestepped (50260e13)
|
||||
* if editing password is disabled in ACP, prevent direct access via route/socket (related: #7576) (e114b16d)
|
||||
* #7582 (c9ca72d0)
|
||||
* #7461 (96cb29aa)
|
||||
* increase batch size (3d938e7b)
|
||||
* #7564 (bf6fc502)
|
||||
* group cover upload not working for s3 upload (#7571) (8945ebcb)
|
||||
* test (b9903120)
|
||||
* #7539 (c940a733)
|
||||
* #7565 (07e9b67e)
|
||||
* #7464 (32cf07d7)
|
||||
* #7147 (fe6d64cc)
|
||||
* #7424 (f86d74d8)
|
||||
* #7562 (09681e6c)
|
||||
* node12 tests (8775e7e6)
|
||||
* add post queue to /compose POST route (c6cd6c57)
|
||||
* remove redis object cache (4df925e7)
|
||||
* #7545 (74038849)
|
||||
* failing test from 00552d7183f0416a0caa113fe2f1e658659648f7 (9bf3517d)
|
||||
* fire filter:register.complete for users approved via registration queue (00552d71)
|
||||
* #7540 (8778f00b)
|
||||
* more graceful error handling and output for cli/reset (d3ebda73)
|
||||
* #6438 only apply whitelist when fields request empty (#7528) (808c4909)
|
||||
* **deps:**
|
||||
* update dependency nodebb-theme-vanilla to v10.1.31 (#7589) (a9f9d19b)
|
||||
* update dependency nodebb-theme-persona to v9.1.36 (#7588) (bd86e58d)
|
||||
* update dependency mongodb to v3.2.4 (#7581) (26d6d0be)
|
||||
* update dependency postcss to v7.0.16 (10a47a29)
|
||||
* update dependency nodebb-theme-persona to v9.1.33 (#7563) (7c4201f2)
|
||||
* update dependency sharp to v0.22.1 (#7561) (288a25f0)
|
||||
* update dependency nodebb-plugin-composer-default to v6.2.12 (#7538) (a54f8f00)
|
||||
* update dependency mongodb to v3.2.3 (97a7f02f)
|
||||
|
||||
#### 1.12.1 (2019-04-10)
|
||||
|
||||
##### Chores
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.12.1",
|
||||
"version": "1.12.2",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -142,7 +142,7 @@
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"husky": "2.3.0",
|
||||
"jsdom": "15.1.0",
|
||||
"lint-staged": "8.1.6",
|
||||
"lint-staged": "8.1.7",
|
||||
"mocha": "6.1.4",
|
||||
"mocha-lcov-reporter": "1.3.0",
|
||||
"nyc": "14.1.1",
|
||||
|
||||
@@ -45,7 +45,12 @@
|
||||
"privileges.search-group": "Add Group",
|
||||
"privileges.copy-to-children": "Copy to Children",
|
||||
"privileges.copy-from-category": "Copy from Category",
|
||||
"privileges.copy-privileges-to-all-categories": "Copy to All Categories",
|
||||
"privileges.copy-group-privileges-to-children": "Copy this group's privileges to the children of this category.",
|
||||
"privileges.copy-group-privileges-to-all-categories": "Copy this group's privileges to all categories.",
|
||||
"privileges.copy-group-privileges-from": "Copy this group's privileges from another category.",
|
||||
"privileges.inherit": "If the <code>registered-users</code> group is granted a specific privilege, all other groups receive an <strong>implicit privilege</strong>, even if they are not explicitly defined/checked. This implicit privilege is shown to you because all users are part of the <code>registered-users</code> user group, and so, privileges for additional groups need not be explicitly granted.",
|
||||
"privileges.copy-success": "Privileges copied!",
|
||||
|
||||
"analytics.back": "Back to Categories List",
|
||||
"analytics.title": "Analytics for \"%1\" category",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
"invitation.text1": "%1 has invited you to join %2",
|
||||
"invitation.text2": "Your invitation will expire in %1 days.",
|
||||
"invitation.ctr": "Click here to create your account.",
|
||||
"invitation.cta": "Click here to create your account.",
|
||||
|
||||
"reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.",
|
||||
"reset.text2": "To continue with the password reset, please click on the following link:",
|
||||
@@ -37,14 +37,13 @@
|
||||
"digest.subject": "Digest for %1",
|
||||
"digest.title": "Your Daily Digest",
|
||||
|
||||
"notif.chat.subject": "New chat message received from %1",
|
||||
"notif.chat.cta": "Click here to continue the conversation",
|
||||
"notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.",
|
||||
|
||||
"notif.post.cta": "Click here to read the full topic",
|
||||
"notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.",
|
||||
|
||||
"notif.cta": "Click here to go to forum",
|
||||
"notif.cta": "To the forum",
|
||||
"notif.cta-new-reply": "View Post",
|
||||
"notif.cta-new-chat": "View Chat",
|
||||
"notif.test.short": "Testing Notifications",
|
||||
"notif.test.long": "This is a test of the notifications email. Send help!",
|
||||
|
||||
"test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.",
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"online": "dostępny",
|
||||
"git": "git",
|
||||
"memory": "pamięć",
|
||||
"load": "system load",
|
||||
"cpu-usage": "cpu usage",
|
||||
"load": "obciążenie systemu",
|
||||
"cpu-usage": "użycie procesora",
|
||||
"uptime": "czas działania",
|
||||
|
||||
"registered": "Zarejestrowane",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "Nazwa grupy",
|
||||
"badge": "Badge",
|
||||
"properties": "Properties",
|
||||
"properties": "Właściwości",
|
||||
"description": "Opis grupy",
|
||||
"member-count": "Liczba użytkowników",
|
||||
"system": "System",
|
||||
"hidden": "Hidden",
|
||||
"private": "Private",
|
||||
"hidden": "Ukryty",
|
||||
"private": "Prywatny",
|
||||
"edit": "Edytuj",
|
||||
"search-placeholder": "Szukaj",
|
||||
"create": "Utwórz grupę",
|
||||
@@ -21,7 +21,7 @@
|
||||
"edit.user-title": "Tytuł członków ",
|
||||
"edit.icon": "Ikona grupy",
|
||||
"edit.label-color": "Kolor etykiety grupy",
|
||||
"edit.text-color": "Group Text Color",
|
||||
"edit.text-color": "Kolor Tekstu Grupy",
|
||||
"edit.show-badge": "Pokaż etykietę",
|
||||
"edit.private-details": "Jeśli włączone, przystępowanie do grup wymaga zatwierdzenia przez właściciela grupy",
|
||||
"edit.private-override": "Ostrzeżenie: Prywatne grupy są wyłączone w ustawieniach, co powoduje przesłonięcia opcji.",
|
||||
|
||||
@@ -18,17 +18,17 @@
|
||||
"mongo.resident-memory": "Долгосрочная память",
|
||||
"mongo.virtual-memory": "Виртуальная память",
|
||||
"mongo.mapped-memory": "Расширенная память",
|
||||
"mongo.bytes-in": "Bytes In",
|
||||
"mongo.bytes-out": "Bytes Out",
|
||||
"mongo.num-requests": "Number of Requests",
|
||||
"mongo.bytes-in": "Байт входящих",
|
||||
"mongo.bytes-out": "Байт исходящих",
|
||||
"mongo.num-requests": "Количество запросов",
|
||||
"mongo.raw-info": "Сырые данные о MongoDB",
|
||||
"mongo.unauthorized": "NodeBB was unable to query the MongoDB database for relevant statistics. Please ensure that the user in use by NodeBB contains the "clusterMonitor" role for the "admin" database.",
|
||||
"mongo.unauthorized": "NodeBB не смог создать запрос к базе данных MongoDB соответствующей статистики. Пожалуйста убедитесь, что пользователь, используемый NodeBB имеет "clusterMonitor" привилегию для "admin" базы данных. ",
|
||||
|
||||
"redis": "Redis",
|
||||
"redis.version": "Версия Redis",
|
||||
"redis.keys": "Keys",
|
||||
"redis.expires": "Expires",
|
||||
"redis.avg-ttl": "Average TTL",
|
||||
"redis.keys": "Ключей",
|
||||
"redis.expires": "Истекает",
|
||||
"redis.avg-ttl": "Средний TTL",
|
||||
"redis.connected-clients": "Подключенные клиенты",
|
||||
"redis.connected-slaves": "Подключенные устройства",
|
||||
"redis.blocked-clients": "Заблокированные клиенты",
|
||||
@@ -37,10 +37,10 @@
|
||||
"redis.total-connections-recieved": "Общее число подключений получено",
|
||||
"redis.total-commands-processed": "Команд обработано в общем",
|
||||
"redis.iops": "Мгновенные операции. в секунду",
|
||||
"redis.iinput": "Instantaneous Input Per Second",
|
||||
"redis.ioutput": "Instantaneous Output Per Second",
|
||||
"redis.total-input": "Total Input",
|
||||
"redis.total-output": "Total Ouput",
|
||||
"redis.iinput": "Текущих входящих в секунду",
|
||||
"redis.ioutput": "Текущих исходящих в секунду",
|
||||
"redis.total-input": "Всего входящих",
|
||||
"redis.total-output": "Всего исходящих",
|
||||
|
||||
"redis.keyspace-hits": "Количество ключевых просмотров",
|
||||
"redis.keyspace-misses": "Количество не ключевых просмотров",
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"online": "онлайн",
|
||||
"git": "git",
|
||||
"memory": "память",
|
||||
"load": "system load",
|
||||
"cpu-usage": "cpu usage",
|
||||
"load": "системная загрузка",
|
||||
"cpu-usage": "Использование процессора",
|
||||
"uptime": "время работы",
|
||||
|
||||
"registered": "Зарегистрированных",
|
||||
|
||||
@@ -65,9 +65,9 @@
|
||||
"high-presence-topics": "Популярные темы",
|
||||
|
||||
"graphs.page-views": "Просмотров",
|
||||
"graphs.page-views-registered": "Page Views Registered",
|
||||
"graphs.page-views-guest": "Page Views Guest",
|
||||
"graphs.page-views-bot": "Page Views Bot",
|
||||
"graphs.page-views-registered": "Зарегистрировано просмотров",
|
||||
"graphs.page-views-guest": "Просмотров гостей",
|
||||
"graphs.page-views-bot": "Просмотров ботов",
|
||||
"graphs.unique-visitors": "Уникальных пользователей",
|
||||
"graphs.registered-users": "Зарегистрированных пользователей",
|
||||
"graphs.anonymous-users": "Анонимных пользователей",
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"tooltip": "Подсказка:",
|
||||
"text": "Текст:",
|
||||
"text-class": "Класс текста: <small>опциоально</small>",
|
||||
"class": "Class: <small>optional</small>",
|
||||
"class": "Класс: <small>опционально</small>",
|
||||
"id": "ID: <small>опциоанально</small>",
|
||||
|
||||
"properties": "Свойства:",
|
||||
"groups": "Groups:",
|
||||
"groups": "Группы:",
|
||||
"open-new-window": "Открывать в новом окне",
|
||||
|
||||
"btn.delete": "Удалить",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"parent-category": "Родительская категория",
|
||||
"optional-parent-category": "(не обязательно) Родительская категория\n",
|
||||
"parent-category-none": "(Пусто)",
|
||||
"copy-parent": "Copy Parent",
|
||||
"copy-parent": "Скопировать Родительский",
|
||||
"copy-settings": "Копировать настройки из",
|
||||
"optional-clone-settings": "(не обязательно) Копировать настройки из",
|
||||
"clone-children": "Дублировать вложенные категориии настройки",
|
||||
@@ -30,13 +30,13 @@
|
||||
"select-category": "Указать категорию",
|
||||
"set-parent-category": "Указать родительскую категорию",
|
||||
|
||||
"privileges.description": "You can configure the access control privileges for portions of the site in this section. Privileges can be granted on a per-user or a per-group basis. Select the domain of effect from the dropdown below.",
|
||||
"privileges.category-selector": "Configuring privileges for ",
|
||||
"privileges.description": "В этой секции вы можете настроить права на управление доступом. Права могут быть предоставлены как на пользователя, так и на группу. Выберите применяемый домен с помощью формы поиска ниже.",
|
||||
"privileges.category-selector": "Настройка привилегий для",
|
||||
"privileges.warning": "<strong>Замечание</strong>: Настройки прав применяются немедленно. Нет необходимости сохранять категорию после изменения настроек.",
|
||||
"privileges.section-viewing": "Права на просмотр",
|
||||
"privileges.section-posting": "Права на создание поста",
|
||||
"privileges.section-moderation": "Права модераторов",
|
||||
"privileges.section-other": "Other",
|
||||
"privileges.section-other": "Другое",
|
||||
"privileges.section-user": "Пользователь",
|
||||
"privileges.search-user": "Добавить пользователя",
|
||||
"privileges.no-users": "В этой категории нет специально заданных прав пользователя.",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"upload-file": "Upload File",
|
||||
"filename": "Filename",
|
||||
"upload-file": "Загрузить Файл",
|
||||
"filename": "Имя файла",
|
||||
"usage": "Post Usage",
|
||||
"orphaned": "Orphaned",
|
||||
"size/filecount": "Size / Filecount",
|
||||
"confirm-delete": "Do you really want to delete this file?",
|
||||
"filecount": "%1 files"
|
||||
"orphaned": "Отделенный",
|
||||
"size/filecount": "Размер / Файлов",
|
||||
"confirm-delete": "Вы действительно хотите удалить этот файл?",
|
||||
"filecount": "%1 файлов"
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
"outgoing_link_message": "Вы сейчас читаете: %1",
|
||||
"continue_to": "Перейти на %1",
|
||||
"return_to": "Вернуться к %1",
|
||||
"new_notification": "You have a new notification",
|
||||
"new_notification": "У вас новое уведомление",
|
||||
"you_have_unread_notifications": "У вас есть непрочитанные уведомления.",
|
||||
"all": "Все",
|
||||
"topics": "Темы",
|
||||
|
||||
@@ -49,8 +49,29 @@ define('admin/manage/privileges', [
|
||||
|
||||
$('.privilege-table-container').on('click', '[data-action="search.user"]', Privileges.addUserToPrivilegeTable);
|
||||
$('.privilege-table-container').on('click', '[data-action="search.group"]', Privileges.addGroupToPrivilegeTable);
|
||||
$('.privilege-table-container').on('click', '[data-action="copyToChildren"]', Privileges.copyPrivilegesToChildren);
|
||||
$('.privilege-table-container').on('click', '[data-action="copyPrivilegesFrom"]', Privileges.copyPrivilegesFromCategory);
|
||||
$('.privilege-table-container').on('click', '[data-action="copyToChildren"]', function () {
|
||||
Privileges.copyPrivilegesToChildren(cid, '');
|
||||
});
|
||||
$('.privilege-table-container').on('click', '[data-action="copyToChildrenGroup"]', function () {
|
||||
var groupName = $(this).parents('[data-group-name]').attr('data-group-name');
|
||||
Privileges.copyPrivilegesToChildren(cid, groupName);
|
||||
});
|
||||
|
||||
$('.privilege-table-container').on('click', '[data-action="copyPrivilegesFrom"]', function () {
|
||||
Privileges.copyPrivilegesFromCategory(cid, '');
|
||||
});
|
||||
$('.privilege-table-container').on('click', '[data-action="copyPrivilegesFromGroup"]', function () {
|
||||
var groupName = $(this).parents('[data-group-name]').attr('data-group-name');
|
||||
Privileges.copyPrivilegesFromCategory(cid, groupName);
|
||||
});
|
||||
|
||||
$('.privilege-table-container').on('click', '[data-action="copyToAll"]', function () {
|
||||
Privileges.copyPrivilegesToAllCategories(cid, '');
|
||||
});
|
||||
$('.privilege-table-container').on('click', '[data-action="copyToAllGroup"]', function () {
|
||||
var groupName = $(this).parents('[data-group-name]').attr('data-group-name');
|
||||
Privileges.copyPrivilegesToAllCategories(cid, groupName);
|
||||
});
|
||||
|
||||
Privileges.exposeAssumedPrivileges();
|
||||
};
|
||||
@@ -168,18 +189,18 @@ define('admin/manage/privileges', [
|
||||
});
|
||||
};
|
||||
|
||||
Privileges.copyPrivilegesToChildren = function () {
|
||||
socket.emit('admin.categories.copyPrivilegesToChildren', cid, function (err) {
|
||||
Privileges.copyPrivilegesToChildren = function (cid, group) {
|
||||
socket.emit('admin.categories.copyPrivilegesToChildren', { cid: cid, group: group }, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess('Privileges copied!');
|
||||
app.alertSuccess('[[admin/manage/categories:privileges.copy-success]]');
|
||||
});
|
||||
};
|
||||
|
||||
Privileges.copyPrivilegesFromCategory = function () {
|
||||
Privileges.copyPrivilegesFromCategory = function (cid, group) {
|
||||
categorySelector.modal(ajaxify.data.categories.slice(1), function (fromCid) {
|
||||
socket.emit('admin.categories.copyPrivilegesFrom', { toCid: cid, fromCid: fromCid }, function (err) {
|
||||
socket.emit('admin.categories.copyPrivilegesFrom', { toCid: cid, fromCid: fromCid, group: group }, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
@@ -188,5 +209,14 @@ define('admin/manage/privileges', [
|
||||
});
|
||||
};
|
||||
|
||||
Privileges.copyPrivilegesToAllCategories = function (cid, group) {
|
||||
socket.emit('admin.categories.copyPrivilegesToAllCategories', { cid: cid, group: group }, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess('[[admin/manage/categories:privileges.copy-success]]');
|
||||
});
|
||||
};
|
||||
|
||||
return Privileges;
|
||||
});
|
||||
|
||||
@@ -196,7 +196,9 @@ $(document).ready(function () {
|
||||
|
||||
$('#content, #footer').removeClass('ajaxifying');
|
||||
|
||||
// Only executed on ajaxify. Otherwise these'd be in ajaxify.end()
|
||||
app.refreshTitle(data.title);
|
||||
app.updateTags();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -864,4 +864,68 @@ app.cacheBuster = null;
|
||||
|
||||
document.head.appendChild(linkEl);
|
||||
};
|
||||
|
||||
app.updateTags = function () {
|
||||
var metaWhitelist = ['title', 'description', /og:.+/, /article:.+/].map(function (val) {
|
||||
return new RegExp(val);
|
||||
});
|
||||
var linkWhitelist = ['canonical', 'alternate', 'up'];
|
||||
|
||||
// Delete the old meta tags
|
||||
Array.prototype.slice
|
||||
.call(document.querySelectorAll('head meta'))
|
||||
.filter(function (el) {
|
||||
var name = el.getAttribute('property') || el.getAttribute('name');
|
||||
return metaWhitelist.some(function (exp) {
|
||||
return !!exp.test(name);
|
||||
});
|
||||
})
|
||||
.forEach(function (el) {
|
||||
document.head.removeChild(el);
|
||||
});
|
||||
|
||||
// Add new meta tags
|
||||
ajaxify.data._header.tags.meta
|
||||
.filter(function (tagObj) {
|
||||
var name = tagObj.name || tagObj.property;
|
||||
return metaWhitelist.some(function (exp) {
|
||||
return !!exp.test(name);
|
||||
});
|
||||
})
|
||||
.forEach(function (tagObj) {
|
||||
var metaEl = document.createElement('meta');
|
||||
Object.keys(tagObj).forEach(function (prop) {
|
||||
metaEl.setAttribute(prop, tagObj[prop]);
|
||||
});
|
||||
document.head.appendChild(metaEl);
|
||||
});
|
||||
|
||||
// Delete the old link tags
|
||||
Array.prototype.slice
|
||||
.call(document.querySelectorAll('head link'))
|
||||
.filter(function (el) {
|
||||
var name = el.getAttribute('rel');
|
||||
return linkWhitelist.some(function (item) {
|
||||
return item === name;
|
||||
});
|
||||
})
|
||||
.forEach(function (el) {
|
||||
document.head.removeChild(el);
|
||||
});
|
||||
|
||||
// Add new link tags
|
||||
ajaxify.data._header.tags.link
|
||||
.filter(function (tagObj) {
|
||||
return linkWhitelist.some(function (item) {
|
||||
return item === tagObj.rel;
|
||||
});
|
||||
})
|
||||
.forEach(function (tagObj) {
|
||||
var linkEl = document.createElement('link');
|
||||
Object.keys(tagObj).forEach(function (prop) {
|
||||
linkEl.setAttribute(prop, tagObj[prop]);
|
||||
});
|
||||
document.head.appendChild(linkEl);
|
||||
});
|
||||
};
|
||||
}());
|
||||
|
||||
@@ -208,18 +208,28 @@ module.exports = function (Categories) {
|
||||
], callback);
|
||||
}
|
||||
|
||||
Categories.copyPrivilegesFrom = function (fromCid, toCid, callback) {
|
||||
Categories.copyPrivilegesFrom = function (fromCid, toCid, group, callback) {
|
||||
if (typeof group === 'function') {
|
||||
callback = group;
|
||||
group = '';
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
plugins.fireHook('filter:categories.copyPrivilegesFrom', {
|
||||
privileges: privileges.privilegeList.slice(),
|
||||
fromCid: fromCid,
|
||||
toCid: toCid,
|
||||
group: group,
|
||||
}, next);
|
||||
},
|
||||
function (data, next) {
|
||||
async.each(data.privileges, function (privilege, next) {
|
||||
copyPrivilege(privilege, data.fromCid, data.toCid, next);
|
||||
if (group) {
|
||||
copyPrivilegeByGroup(privilege, data.fromCid, data.toCid, group, next);
|
||||
} else {
|
||||
copyPrivilege(privilege, data.fromCid, data.toCid, next);
|
||||
}
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
@@ -249,4 +259,22 @@ module.exports = function (Categories) {
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
function copyPrivilegeByGroup(privilege, fromCid, toCid, group, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
groups.leave('cid:' + toCid + ':privileges:' + privilege, group, next);
|
||||
},
|
||||
function (next) {
|
||||
db.isSortedSetMember('group:cid:' + fromCid + ':privileges:' + privilege + ':members', group, next);
|
||||
},
|
||||
function (isMember, next) {
|
||||
if (!isMember) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
groups.join('cid:' + toCid + ':privileges:' + privilege, group, next);
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,7 +107,6 @@ module.exports = function (middleware) {
|
||||
});
|
||||
},
|
||||
navigation: async.apply(navigation.get, req.uid),
|
||||
tags: async.apply(meta.tags.parse, req, data, res.locals.metaTags, res.locals.linkTags),
|
||||
banned: async.apply(user.bans.isBanned, req.uid),
|
||||
banReason: async.apply(user.bans.getReason, req.uid),
|
||||
|
||||
@@ -180,8 +179,8 @@ module.exports = function (middleware) {
|
||||
templateValues.browserTitle = results.browserTitle;
|
||||
templateValues.navigation = results.navigation;
|
||||
templateValues.unreadCount = unreadCount;
|
||||
templateValues.metaTags = results.tags.meta;
|
||||
templateValues.linkTags = results.tags.link;
|
||||
templateValues.metaTags = data._header.tags.meta;
|
||||
templateValues.linkTags = data._header.tags.link;
|
||||
templateValues.isAdmin = results.user.isAdmin;
|
||||
templateValues.isGlobalMod = results.user.isGlobalMod;
|
||||
templateValues.showModMenu = results.user.isAdmin || results.user.isGlobalMod || results.user.isMod;
|
||||
|
||||
@@ -6,6 +6,7 @@ var validator = require('validator');
|
||||
var winston = require('winston');
|
||||
|
||||
var plugins = require('../plugins');
|
||||
var meta = require('../meta');
|
||||
var translator = require('../translator');
|
||||
var widgets = require('../widgets');
|
||||
var utils = require('../utils');
|
||||
@@ -49,6 +50,14 @@ module.exports = function (middleware) {
|
||||
templateToRender = data.templateData.templateToRender || template;
|
||||
plugins.fireHook('filter:middleware.render', { req: req, res: res, templateData: data.templateData }, next);
|
||||
},
|
||||
function parseTags(data, next) {
|
||||
meta.tags.parse(req, data, res.locals.metaTags, res.locals.linkTags, function (err, tags) {
|
||||
options._header = {
|
||||
tags: tags,
|
||||
};
|
||||
next(err, data);
|
||||
});
|
||||
},
|
||||
function (data, next) {
|
||||
options = data.templateData;
|
||||
|
||||
|
||||
@@ -241,6 +241,11 @@ function pushToUids(uids, notification, callback) {
|
||||
}
|
||||
|
||||
function sendEmail(uids, callback) {
|
||||
// Update CTA messaging (as not all notification types need custom text)
|
||||
if (['new-reply', 'new-chat'].includes(notification.type)) {
|
||||
notification['cta-type'] = notification.type;
|
||||
}
|
||||
|
||||
async.eachLimit(uids, 3, function (uid, next) {
|
||||
emailer.send('notification', uid, {
|
||||
path: notification.path,
|
||||
|
||||
@@ -279,8 +279,8 @@ SocketAdmin.email.test = function (socket, data, callback) {
|
||||
function (next) {
|
||||
notifications.create({
|
||||
type: 'test',
|
||||
bodyShort: '[[admin-settings-email:testing]]',
|
||||
bodyLong: '[[admin-settings-email:testing.send-help]]',
|
||||
bodyShort: '[[email:notif.test.short]]',
|
||||
bodyLong: '[[email:notif.test.long]]',
|
||||
nid: 'uid:' + socket.uid + ':test',
|
||||
path: '/',
|
||||
from: socket.uid,
|
||||
|
||||
@@ -101,25 +101,25 @@ Categories.getPrivilegeSettings = function (socket, cid, callback) {
|
||||
}
|
||||
};
|
||||
|
||||
Categories.copyPrivilegesToChildren = function (socket, cid, callback) {
|
||||
Categories.copyPrivilegesToChildren = function (socket, data, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
categories.getChildren([cid], socket.uid, next);
|
||||
categories.getChildren([data.cid], socket.uid, next);
|
||||
},
|
||||
function (children, next) {
|
||||
children = children[0];
|
||||
|
||||
async.eachSeries(children, function (child, next) {
|
||||
copyPrivilegesToChildrenRecursive(cid, child, next);
|
||||
copyPrivilegesToChildrenRecursive(data.cid, child, data.group, next);
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
function copyPrivilegesToChildrenRecursive(parentCid, category, callback) {
|
||||
function copyPrivilegesToChildrenRecursive(parentCid, category, group, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
categories.copyPrivilegesFrom(parentCid, category.cid, next);
|
||||
categories.copyPrivilegesFrom(parentCid, category.cid, group, next);
|
||||
},
|
||||
function (next) {
|
||||
async.eachSeries(category.children, function (child, next) {
|
||||
@@ -134,5 +134,19 @@ Categories.copySettingsFrom = function (socket, data, callback) {
|
||||
};
|
||||
|
||||
Categories.copyPrivilegesFrom = function (socket, data, callback) {
|
||||
categories.copyPrivilegesFrom(data.fromCid, data.toCid, callback);
|
||||
categories.copyPrivilegesFrom(data.fromCid, data.toCid, data.group, callback);
|
||||
};
|
||||
|
||||
Categories.copyPrivilegesToAllCategories = function (socket, data, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
categories.getAllCidsFromSet('categories:cid', next);
|
||||
},
|
||||
function (cids, next) {
|
||||
cids = cids.filter(cid => parseInt(cid, 10) !== parseInt(data.cid, 10));
|
||||
async.eachSeries(cids, function (toCid, next) {
|
||||
categories.copyPrivilegesFrom(data.cid, toCid, data.group, next);
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
@@ -94,7 +94,18 @@
|
||||
<!-- ENDIF privileges.groups.isPrivate -->
|
||||
{privileges.groups.name}
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fa fa-copy"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li data-action="copyToAllGroup"><a href="#">[[admin/manage/categories:privileges.copy-group-privileges-to-all-categories]]</a></li>
|
||||
<li data-action="copyToChildrenGroup"><a href="#">[[admin/manage/categories:privileges.copy-group-privileges-to-children]]</a></li>
|
||||
<li data-action="copyPrivilegesFromGroup"><a href="#">[[admin/manage/categories:privileges.copy-group-privileges-from]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
{function.spawnPrivilegeStates, privileges.groups.name, ../privileges}
|
||||
</tr>
|
||||
<!-- END privileges.groups -->
|
||||
@@ -104,11 +115,14 @@
|
||||
<button type="button" class="btn btn-primary pull-right" data-ajaxify="false" data-action="search.group">
|
||||
[[admin/manage/categories:privileges.search-group]]
|
||||
</button>
|
||||
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyPrivilegesFrom">
|
||||
[[admin/manage/categories:privileges.copy-from-category]]
|
||||
</button>
|
||||
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyToChildren">
|
||||
[[admin/manage/categories:privileges.copy-to-children]]
|
||||
</button>
|
||||
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyPrivilegesFrom">
|
||||
[[admin/manage/categories:privileges.copy-from-category]]
|
||||
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyToAll">
|
||||
[[admin/manage/categories:privileges.copy-privileges-to-all-categories]]
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{url}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:digest.cta, {site_title}]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:digest.cta, {site_title}]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{registerLink}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:invitation.ctr]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:invitation.cta]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{url}{path}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:notif.cta]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:notif.cta<!-- IF notification.cta-type -->-{notification.cta-type}<!-- END -->]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{url}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:digest.cta, {site_title}]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:digest.cta, {site_title}]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{reset_link}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:reset.cta]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:reset.cta]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{url}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:digest.cta, {site_title}]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:digest.cta, {site_title}]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{url}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:digest.cta, {site_title}]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:digest.cta, {site_title}]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{confirm_link}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:welcome.cta]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:welcome.cta]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<tr>
|
||||
<td style="border-radius: 3px; background: #222222; text-align: center;" class="button-td">
|
||||
<a href="{confirm_link}" style="background: #222222; border: 15px solid #222222; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 13px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 3px; font-weight: bold;" class="button-a">
|
||||
<span style="color:#ffffff;" class="button-link"> [[email:welcome.cta]] </span>
|
||||
<span style="color:#ffffff;" class="button-link">[[email:welcome.cta]] →</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -505,7 +505,7 @@ describe('Categories', function () {
|
||||
socketCategories.setPrivilege({ uid: adminUid }, { cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users' }, next);
|
||||
},
|
||||
function (next) {
|
||||
socketCategories.copyPrivilegesToChildren({ uid: adminUid }, parentCid, next);
|
||||
socketCategories.copyPrivilegesToChildren({ uid: adminUid }, { cid: parentCid, group: '' }, next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.categories.can('topics:delete', child2Cid, posterUid, next);
|
||||
@@ -561,7 +561,7 @@ describe('Categories', function () {
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should copy privileges from', function (done) {
|
||||
it('should copy privileges from another category', function (done) {
|
||||
var child1Cid;
|
||||
var parentCid;
|
||||
async.waterfall([
|
||||
@@ -588,6 +588,34 @@ describe('Categories', function () {
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should copy privileges from another category for a single group', function (done) {
|
||||
var child1Cid;
|
||||
var parentCid;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
Categories.create({ name: 'parent', description: 'copy me' }, next);
|
||||
},
|
||||
function (category, next) {
|
||||
parentCid = category.cid;
|
||||
Categories.create({ name: 'child1' }, next);
|
||||
},
|
||||
function (category, next) {
|
||||
child1Cid = category.cid;
|
||||
socketCategories.setPrivilege({ uid: adminUid }, { cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users' }, next);
|
||||
},
|
||||
function (next) {
|
||||
socketCategories.copyPrivilegesFrom({ uid: adminUid }, { fromCid: parentCid, toCid: child1Cid, group: 'registered-users' }, next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.categories.can('topics:delete', child1Cid, 0, next);
|
||||
},
|
||||
function (canDelete, next) {
|
||||
assert(!canDelete);
|
||||
next();
|
||||
},
|
||||
], done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should get active users', function (done) {
|
||||
|
||||
Reference in New Issue
Block a user