mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-04 03:21:18 +01:00
Merge remote-tracking branch 'origin/master' into develop
This commit is contained in:
2
app.js
2
app.js
@@ -37,7 +37,7 @@ var winston = require('winston');
|
||||
var path = require('path');
|
||||
var pkg = require('./package.json');
|
||||
var file = require('./src/file');
|
||||
var debug = require('./src/meta/debugParams')().execArgv.length;
|
||||
var debug = require('./src/meta/debugFork').debugging;
|
||||
|
||||
global.env = process.env.NODE_ENV || 'production';
|
||||
|
||||
|
||||
10
package.json
10
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.6.0",
|
||||
"version": "1.6.1",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -65,11 +65,11 @@
|
||||
"nodebb-plugin-soundpack-default": "1.0.0",
|
||||
"nodebb-plugin-spam-be-gone": "0.5.1",
|
||||
"nodebb-rewards-essentials": "0.0.9",
|
||||
"nodebb-theme-lavender": "4.1.0",
|
||||
"nodebb-theme-persona": "6.1.1",
|
||||
"nodebb-theme-lavender": "4.1.1",
|
||||
"nodebb-theme-persona": "6.1.3",
|
||||
"nodebb-theme-slick": "1.1.1",
|
||||
"nodebb-theme-vanilla": "7.1.0",
|
||||
"nodebb-widget-essentials": "3.0.6",
|
||||
"nodebb-theme-vanilla": "7.1.2",
|
||||
"nodebb-widget-essentials": "3.0.7",
|
||||
"nodemailer": "4.1.1",
|
||||
"passport": "^0.4.0",
|
||||
"passport-local": "1.0.0",
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
"smtp-transport.gmail-warning2": "Další informace o tomto řešení, <a href=\"https://nodemailer.com/usage/using-gmail/\">konzultujte s NodeMailer.</a>Alternativou je použití e-mailového rozšíření třetích stran jako je SendGrid, Mailgun atd.<a href=\"{config.relative_path}/admin/extend/plugins\">Dostupné rozšíření zde</a>.",
|
||||
"smtp-transport.host": "Hostitel SMTP",
|
||||
"smtp-transport.port": "Port SMTP",
|
||||
"smtp-transport.security": "Connection security",
|
||||
"smtp-transport.security-encrypted": "Encrypted",
|
||||
"smtp-transport.security": "Zabezpečení připojení",
|
||||
"smtp-transport.security-encrypted": "Šifrované",
|
||||
"smtp-transport.security-starttls": "StartTLS",
|
||||
"smtp-transport.security-none": "None",
|
||||
"smtp-transport.security-none": "Nic",
|
||||
"smtp-transport.username": "Uživatelské jméno",
|
||||
"smtp-transport.username-help": "<b>Pro službu Gmail,</b> zadejte plnou e-mailovou adresu, zvláště, používáte-li spravovanou doménu Google Apps.",
|
||||
"smtp-transport.password": "Heslo",
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
"enable": "Paginate topics and posts instead of using infinite scroll.",
|
||||
"topics": "Topic Pagination",
|
||||
"posts-per-page": "Posts per Page",
|
||||
"max-posts-per-page": "Maximum posts per page",
|
||||
"categories": "Category Pagination",
|
||||
"topics-per-page": "Topics per Page",
|
||||
"max-topics-per-page": "Maximum topics per page",
|
||||
"initial-num-load": "Initial Number of Topics to Load on Unread, Recent, and Popular"
|
||||
}
|
||||
@@ -102,6 +102,7 @@
|
||||
"paginate_description" : "Paginate topics and posts instead of using infinite scroll",
|
||||
"topics_per_page": "Topics per Page",
|
||||
"posts_per_page": "Posts per Page",
|
||||
"max_items_per_page": "Maximum %1",
|
||||
|
||||
"notification_sounds" : "Play a sound when you receive a notification",
|
||||
"notifications_and_sounds": "Notifications & Sounds",
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
"from": "Nom de l’expéditeur",
|
||||
"from-help": "Le nom de l’expéditeur à afficher dans l'e-mail",
|
||||
|
||||
"smtp-transport": "SMTP Transport",
|
||||
"smtp-transport": "Protocole SMTP",
|
||||
"smtp-transport.enabled": "Utiliser un server extérieur pour envoyer les emails",
|
||||
"smtp-transport-help": "Vous pouvez sélectionner depuis une liste de services ou entrer un service personnalisé.",
|
||||
"smtp-transport.service": "Sélectionner un service",
|
||||
"smtp-transport.service-custom": "Service personnalisé",
|
||||
"smtp-transport.service-help": "S",
|
||||
"smtp-transport.gmail-warning1": "There have been reports of the Gmail service not working on accounts with heightened security. In those scenarios, you will have to <a href=\"https://www.google.com/settings/security/lesssecureapps\">configure your GMail account to allow less secure apps</a>.",
|
||||
"smtp-transport.gmail-warning2": "For more information about this workaround, <a href=\"https://nodemailer.com/usage/using-gmail/\">please consult this NodeMailer article on the issue.</a> An alternative would be to utilise a third-party emailer plugin such as SendGrid, Mailgun, etc. <a href=\"{config.relative_path}/admin/extend/plugins\">Browse available plugins here</a>.",
|
||||
"smtp-transport.service-help": "Sélectionner un service ci-dessus afin de renseigner les champs. Sinon, sélectionner \"Service Personnalisé\" et ajouter les informations ci-dessous.",
|
||||
"smtp-transport.gmail-warning1": "Vous pouvez rencontrer des difficultés avec le service Gmail pour les comptes ayant une sécurité élevée. Dans ce cas, vous devez configurer <a href=\"https://www.google.com/settings/security/lesssecureapps\">votre compte Gmail pour qu'il autorise les applications moins sécurisées</a>.",
|
||||
"smtp-transport.gmail-warning2": "Pour plus d'informations à propos de cette solution, <a href=\"https://nodemailer.com/usage/using-gmail/\">consulter l'article sur le NodeMailer sur ce sujet.</a> Une alternative est d'utiliser un service tiers d'envoi d'email tels que SendGrid, Mailgun, etc. <a href=\"{config.relative_path}/admin/extend/plugins\">Consulter les plugins disponibles ici</a>.",
|
||||
"smtp-transport.host": "Host SMTP",
|
||||
"smtp-transport.port": "Port SMTP",
|
||||
"smtp-transport.security": "Connection security",
|
||||
"smtp-transport.security-encrypted": "Encrypted",
|
||||
"smtp-transport.security": "Accès sécurisé",
|
||||
"smtp-transport.security-encrypted": "Cryptage",
|
||||
"smtp-transport.security-starttls": "StartTLS",
|
||||
"smtp-transport.security-none": "None",
|
||||
"smtp-transport.security-none": "Aucun",
|
||||
"smtp-transport.username": "Nom d'utilisateur",
|
||||
"smtp-transport.username-help": "<b>Pour Gmail,</b> entrer l’adresse e-mail complète ici, surtout si vous utilisez un domaine géré par Google Apps.",
|
||||
"smtp-transport.password": "Mot de passe",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"site-settings": "Réglages du site",
|
||||
"title": "Titre du site",
|
||||
"title.url": "URL",
|
||||
"title.url-placeholder": "The URL of the site title",
|
||||
"title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index.",
|
||||
"title.url-placeholder": "URL du titre du site",
|
||||
"title.url-help": "Adresse à laquelle l'utilisateur est renvoyé lors du clic sur le titre. Si ce champ est vide, l'adresse est celle de l'index du forum.",
|
||||
"title.name": "Nom de votre communauté",
|
||||
"title.show-in-header": "Afficher le titre du site dans l'en-tête",
|
||||
"browser-title": "Titre dans le navigateur",
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"sorting.most-votes": "Avec le plus de votes",
|
||||
"sorting.topic-default": "Tri des sujets par défaut",
|
||||
"restrictions": "Restrictions d'envoi",
|
||||
"restrictions.post-queue": "Enable post queue",
|
||||
"restrictions.post-queue-help": "Enabling post queue will put the posts of new users in a queue for approval.",
|
||||
"restrictions.post-queue": "Activer la file d'attente des messages",
|
||||
"restrictions.post-queue-help": "Activer la file d'attente des messages mettra automatiquement les messages des nouveaux utilisateurs dans la liste pour approbation.",
|
||||
"restrictions.seconds-between": "Nombre de secondes entre chaque message",
|
||||
"restrictions.seconds-between-new": "Nombre de secondes entre chaque message pour les nouveaux utilisateurs",
|
||||
"restrictions.rep-threshold": "Seuil de réputation avant que cette restriction soit levée",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"not-logged-in": "Vous ne semblez pas être connecté.",
|
||||
"account-locked": "Votre compte a été temporairement suspendu",
|
||||
"search-requires-login": "Rechercher nécessite d'avoir un compte. Veuillez vous identifier ou vous enregistrer.",
|
||||
"goback": "Press back to return to the previous page",
|
||||
"goback": "Appuyez sur retour pour revenir à la page précédente",
|
||||
"invalid-cid": "ID de catégorie invalide",
|
||||
"invalid-tid": "ID de sujet invalide",
|
||||
"invalid-pid": "ID de message invalide",
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"new_register": "<strong>%1</strong> a envoyé une demande d'incription.",
|
||||
"new_register_multiple": "<strong>%1</strong> inscription(s) est en attente de validation.",
|
||||
"flag_assigned_to_you": "<strong>Drapeau %1</strong> vous a été assigné",
|
||||
"post_awaiting_review": "Post awaiting review",
|
||||
"post_awaiting_review": "Message en attente de validation",
|
||||
"email-confirmed": "Email vérifié",
|
||||
"email-confirmed-message": "Merci pour la validation de votre adresse email. Votre compte est désormais activé.",
|
||||
"email-confirm-error-message": "Il y a un un problème dans la vérification de votre adresse email. Le code est peut être invalide ou a expiré.",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"moderator-tools": "Outils de modération",
|
||||
"flagged-content": "Contenu signalé",
|
||||
"ip-blacklist": "Liste noire d'adresses IP",
|
||||
"post-queue": "Post Queue",
|
||||
"post-queue": "File d'attente des messages",
|
||||
"users/online": "Utilisateurs en ligne",
|
||||
"users/latest": "Derniers inscrits",
|
||||
"users/sort-posts": "Utilisateurs avec le plus de messages",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"success": "Terminé",
|
||||
"topic-post": "Le message a bien été envoyé.",
|
||||
"post-queued": "Your post is queued for approval.",
|
||||
"post-queued": "Votre message est en attente d'approbation.",
|
||||
"authentication-successful": "Authentification réussie",
|
||||
"settings-saved": "Paramètres enregistrés !"
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"not-logged-in": "נראה שאינך מחובר למערכת.",
|
||||
"account-locked": "חשבונך נחסם באופן זמני",
|
||||
"search-requires-login": "פעולת החיפוש דורשת חשבון - בבקשה התחבר או הרשם.",
|
||||
"goback": "Press back to return to the previous page",
|
||||
"goback": "לחץ back לחזרה לעמוד הקודם",
|
||||
"invalid-cid": "זהוי קטגוריה שגוי",
|
||||
"invalid-tid": "זהוי נושא שגוי",
|
||||
"invalid-pid": "זהוי פוסט שגוי",
|
||||
@@ -59,7 +59,7 @@
|
||||
"post-delete-duration-expired-hours": "You are only allowed to delete posts for %1 hour(s) after posting",
|
||||
"post-delete-duration-expired-hours-minutes": "You are only allowed to delete posts for %1 hour(s) %2 minute(s) after posting",
|
||||
"post-delete-duration-expired-days": "You are only allowed to delete posts for %1 day(s) after posting",
|
||||
"post-delete-duration-expired-days-hours": "You are only allowed to delete posts for %1 day(s) %2 hour(s) after posting",
|
||||
"post-delete-duration-expired-days-hours": "אתה מורשה למחוק פוסט רק %1 ימים ו %2 שעות אחרי פרסומו",
|
||||
"cant-delete-topic-has-reply": "אינך יכול למחוק נושא אחרי שכבר הגיבו בו.",
|
||||
"cant-delete-topic-has-replies": "לא ניתן למחוק את הנושא לאחר שקיבל %1 תגובות",
|
||||
"content-too-short": "אנא הכנס פוסט ארוך יותר. פוסטים חייבים להכיל לפחות %1 תווים.",
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"new_register": "<strong>%1</strong> שלח בקשת הרשמה.",
|
||||
"new_register_multiple": "ישנן <strong>%1</strong> בקשות הרשמה שמחכות לבדיקה.",
|
||||
"flag_assigned_to_you": "<strong>דיווח %1</strong> הוקצה עבורך",
|
||||
"post_awaiting_review": "Post awaiting review",
|
||||
"post_awaiting_review": "הפוסט ממתין לאישור",
|
||||
"email-confirmed": "כתובת המייל אושרה",
|
||||
"email-confirmed-message": "תודה שאישרת את כתובת המייל שלך. החשבון שלך פעיל כעת.",
|
||||
"email-confirm-error-message": "אירעה שגיאה בעת אישור המייל שלך. ייתכן כי הקוד היה שגוי או פג תוקף.",
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
"popular-month": "נושאים חמים החודש",
|
||||
"popular-alltime": "הנושאים החמים בכל הזמנים",
|
||||
"recent": "נושאים אחרונים",
|
||||
"moderator-tools": "Moderator Tools",
|
||||
"moderator-tools": "כלי מודרטור",
|
||||
"flagged-content": "תוכן מדווח",
|
||||
"ip-blacklist": "רשימת IP שחורה",
|
||||
"post-queue": "Post Queue",
|
||||
"post-queue": "פוסטים ממתינים",
|
||||
"users/online": "משתמשים מחוברים",
|
||||
"users/latest": "משתמשים אחרונים",
|
||||
"users/sort-posts": "משתמשים עם המונה הגבוה ביותר",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"success": "הצלחה",
|
||||
"topic-post": "העלת פוסט בהצלחה.",
|
||||
"post-queued": "Your post is queued for approval.",
|
||||
"post-queued": "הפוסט שלך ממתין לאישור.",
|
||||
"authentication-successful": "הנתונים אומתו בהצלחה",
|
||||
"settings-saved": "הנתונים נשמרו!"
|
||||
}
|
||||
@@ -59,7 +59,7 @@
|
||||
"thread_tools.unlock": "הסר נעילה",
|
||||
"thread_tools.move": "הזז נושא",
|
||||
"thread_tools.move_all": "הזז הכל",
|
||||
"thread_tools.select_category": "Select Category",
|
||||
"thread_tools.select_category": "בחר קטגוריה",
|
||||
"thread_tools.fork": "שכפל נושא",
|
||||
"thread_tools.delete": "מחק נושא",
|
||||
"thread_tools.delete-posts": "מחק פוסטים",
|
||||
@@ -75,9 +75,9 @@
|
||||
"load_categories": "טוען קטגוריות",
|
||||
"confirm_move": "הזז",
|
||||
"confirm_fork": "שכפל",
|
||||
"bookmark": "Bookmark",
|
||||
"bookmarks": "Bookmarks",
|
||||
"bookmarks.has_no_bookmarks": "You haven't bookmarked any posts yet.",
|
||||
"bookmark": "הוסף למועדפים",
|
||||
"bookmarks": "מועדפים",
|
||||
"bookmarks.has_no_bookmarks": "לא צירפת אף פוסט למועדפים עדיין",
|
||||
"loading_more_posts": "טוען פוסטים נוספים",
|
||||
"move_topic": "הזז נושא",
|
||||
"move_topics": "הזז נושאים",
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
"smtp-transport.gmail-warning2": "Para mais informação sobre este workaround, <a href=\"https://nodemailer.com/usage/using-gmail/\">por gentileza consulte este artigo no NodeMailer sobre o assunto..</a> Uma alternativa seria utilizar um plugin de email terceirizado como o SendGrid, Maigun etc. . <a href=\"{config.relative_path}/admin/extend/plugins\">Explore pelos plugins disponíveis aqui</a>.",
|
||||
"smtp-transport.host": "Host SMTP",
|
||||
"smtp-transport.port": "Porta SMTP",
|
||||
"smtp-transport.security": "Connection security",
|
||||
"smtp-transport.security-encrypted": "Encrypted",
|
||||
"smtp-transport.security": "Segurança da conexão",
|
||||
"smtp-transport.security-encrypted": "Encriptada",
|
||||
"smtp-transport.security-starttls": "StartTLS",
|
||||
"smtp-transport.security-none": "None",
|
||||
"smtp-transport.security-none": "Nenhuma",
|
||||
"smtp-transport.username": "Nome de usuário",
|
||||
"smtp-transport.username-help": "<b>Para o serviço do Gmail,</b> entre com o endereço de email completo aqui, especiamente se você estiver usando um domínio administrado pelo Google Apps.",
|
||||
"smtp-transport.password": "Senha",
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"from-help": "用于邮件中显示的发送者",
|
||||
|
||||
"smtp-transport": "SMTP 通信",
|
||||
"smtp-transport.enabled": "使用一个外部邮箱系统来发送邮件",
|
||||
"smtp-transport-help": "你可以从列表中选取一个已知的服务或自定义。",
|
||||
"smtp-transport.enabled": "使用一个外部电子邮箱系统来发送邮件",
|
||||
"smtp-transport-help": "您可以从列表中选取一个已知的服务或自定义。",
|
||||
"smtp-transport.service": "选择服务",
|
||||
"smtp-transport.service-custom": "自定义",
|
||||
"smtp-transport.service-help": "选取一个上方服务以便使用已知的信息。此外,还可以选取 “自定义”并在下方输入配置细节。",
|
||||
@@ -20,7 +20,7 @@
|
||||
"smtp-transport.security-starttls": "StartTLS",
|
||||
"smtp-transport.security-none": "None",
|
||||
"smtp-transport.username": "用户名",
|
||||
"smtp-transport.username-help": "<b>对于Gmail服务,</b>请在这里输入完整的电子邮件地址,尤其是如果你使用的是 Google Apps 托管的域名。",
|
||||
"smtp-transport.username-help": "<b>对于Gmail服务,</b>请在这里输入完整的电子邮箱地址,尤其是如果您使用的是 Google Apps 托管的域名。",
|
||||
"smtp-transport.password": "密码",
|
||||
|
||||
"template": "编辑电子邮件模板",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (translator, cropper, Benchpress) {
|
||||
define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (translator, Cropper, Benchpress) {
|
||||
var module = {};
|
||||
|
||||
module.show = function (data, callback) {
|
||||
@@ -46,7 +46,7 @@ define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (tran
|
||||
var img = document.getElementById('cropped-image');
|
||||
$(img).css('max-height', cropBoxHeight);
|
||||
|
||||
var cropperTool = new cropper.default(img, {
|
||||
var cropperTool = new Cropper(img, {
|
||||
aspectRatio: data.aspectRatio,
|
||||
autoCropArea: 1,
|
||||
viewMode: 1,
|
||||
@@ -122,7 +122,7 @@ define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (tran
|
||||
$(this).addClass('disabled');
|
||||
cropperTool.destroy();
|
||||
|
||||
cropperTool = new cropper.default(img, {
|
||||
cropperTool = new Cropper(img, {
|
||||
viewMode: 1,
|
||||
autoCropArea: 1,
|
||||
ready: function () {
|
||||
|
||||
@@ -12,9 +12,7 @@ var db = require('../../database');
|
||||
var helpers = require('../helpers');
|
||||
var accountHelpers = require('./helpers');
|
||||
|
||||
|
||||
var settingsController = {};
|
||||
|
||||
var settingsController = module.exports;
|
||||
|
||||
settingsController.get = function (req, res, callback) {
|
||||
var userData;
|
||||
@@ -91,67 +89,64 @@ settingsController.get = function (req, res, callback) {
|
||||
next(err, data);
|
||||
});
|
||||
},
|
||||
function (data, next) {
|
||||
function (data) {
|
||||
userData.customSettings = data.customSettings;
|
||||
userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1;
|
||||
next();
|
||||
|
||||
userData.dailyDigestFreqOptions = [
|
||||
{ value: 'off', name: '[[user:digest_off]]', selected: userData.settings.dailyDigestFreq === 'off' },
|
||||
{ value: 'day', name: '[[user:digest_daily]]', selected: userData.settings.dailyDigestFreq === 'day' },
|
||||
{ value: 'week', name: '[[user:digest_weekly]]', selected: userData.settings.dailyDigestFreq === 'week' },
|
||||
{ value: 'month', name: '[[user:digest_monthly]]', selected: userData.settings.dailyDigestFreq === 'month' },
|
||||
];
|
||||
|
||||
userData.bootswatchSkinOptions = [
|
||||
{ name: 'No skin', value: 'noskin' },
|
||||
{ name: 'Default', value: 'default' },
|
||||
{ name: 'Cerulean', value: 'cerulean' },
|
||||
{ name: 'Cosmo', value: 'cosmo' },
|
||||
{ name: 'Cyborg', value: 'cyborg' },
|
||||
{ name: 'Darkly', value: 'darkly' },
|
||||
{ name: 'Flatly', value: 'flatly' },
|
||||
{ name: 'Journal', value: 'journal' },
|
||||
{ name: 'Lumen', value: 'lumen' },
|
||||
{ name: 'Paper', value: 'paper' },
|
||||
{ name: 'Readable', value: 'readable' },
|
||||
{ name: 'Sandstone', value: 'sandstone' },
|
||||
{ name: 'Simplex', value: 'simplex' },
|
||||
{ name: 'Slate', value: 'slate' },
|
||||
{ name: 'Spacelab', value: 'spacelab' },
|
||||
{ name: 'Superhero', value: 'superhero' },
|
||||
{ name: 'United', value: 'united' },
|
||||
{ name: 'Yeti', value: 'yeti' },
|
||||
];
|
||||
|
||||
userData.bootswatchSkinOptions.forEach(function (skin) {
|
||||
skin.selected = skin.value === userData.settings.bootswatchSkin;
|
||||
});
|
||||
|
||||
userData.languages.forEach(function (language) {
|
||||
language.selected = language.code === userData.settings.userLang;
|
||||
});
|
||||
|
||||
userData.disableCustomUserSkins = parseInt(meta.config.disableCustomUserSkins, 10) === 1;
|
||||
|
||||
userData.allowUserHomePage = parseInt(meta.config.allowUserHomePage, 10) === 1;
|
||||
|
||||
userData.hideFullname = parseInt(meta.config.hideFullname, 10) === 1;
|
||||
userData.hideEmail = parseInt(meta.config.hideEmail, 10) === 1;
|
||||
|
||||
userData.inTopicSearchAvailable = plugins.hasListeners('filter:topic.search');
|
||||
|
||||
userData.maxTopicsPerPage = parseInt(meta.config.maxTopicsPerPage, 10) || 20;
|
||||
userData.maxPostsPerPage = parseInt(meta.config.maxPostsPerPage, 10) || 20;
|
||||
|
||||
userData.title = '[[pages:account/settings]]';
|
||||
userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[user:settings]]' }]);
|
||||
|
||||
res.render('account/settings', userData);
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
userData.dailyDigestFreqOptions = [
|
||||
{ value: 'off', name: '[[user:digest_off]]', selected: userData.settings.dailyDigestFreq === 'off' },
|
||||
{ value: 'day', name: '[[user:digest_daily]]', selected: userData.settings.dailyDigestFreq === 'day' },
|
||||
{ value: 'week', name: '[[user:digest_weekly]]', selected: userData.settings.dailyDigestFreq === 'week' },
|
||||
{ value: 'month', name: '[[user:digest_monthly]]', selected: userData.settings.dailyDigestFreq === 'month' },
|
||||
];
|
||||
|
||||
|
||||
userData.bootswatchSkinOptions = [
|
||||
{ name: 'No skin', value: 'noskin' },
|
||||
{ name: 'Default', value: 'default' },
|
||||
{ name: 'Cerulean', value: 'cerulean' },
|
||||
{ name: 'Cosmo', value: 'cosmo' },
|
||||
{ name: 'Cyborg', value: 'cyborg' },
|
||||
{ name: 'Darkly', value: 'darkly' },
|
||||
{ name: 'Flatly', value: 'flatly' },
|
||||
{ name: 'Journal', value: 'journal' },
|
||||
{ name: 'Lumen', value: 'lumen' },
|
||||
{ name: 'Paper', value: 'paper' },
|
||||
{ name: 'Readable', value: 'readable' },
|
||||
{ name: 'Sandstone', value: 'sandstone' },
|
||||
{ name: 'Simplex', value: 'simplex' },
|
||||
{ name: 'Slate', value: 'slate' },
|
||||
{ name: 'Spacelab', value: 'spacelab' },
|
||||
{ name: 'Superhero', value: 'superhero' },
|
||||
{ name: 'United', value: 'united' },
|
||||
{ name: 'Yeti', value: 'yeti' },
|
||||
];
|
||||
|
||||
userData.bootswatchSkinOptions.forEach(function (skin) {
|
||||
skin.selected = skin.value === userData.settings.bootswatchSkin;
|
||||
});
|
||||
|
||||
userData.languages.forEach(function (language) {
|
||||
language.selected = language.code === userData.settings.userLang;
|
||||
});
|
||||
|
||||
userData.disableCustomUserSkins = parseInt(meta.config.disableCustomUserSkins, 10) === 1;
|
||||
|
||||
userData.allowUserHomePage = parseInt(meta.config.allowUserHomePage, 10) === 1;
|
||||
|
||||
userData.hideFullname = parseInt(meta.config.hideFullname, 10) === 1;
|
||||
userData.hideEmail = parseInt(meta.config.hideEmail, 10) === 1;
|
||||
|
||||
userData.inTopicSearchAvailable = plugins.hasListeners('filter:topic.search');
|
||||
|
||||
userData.title = '[[pages:account/settings]]';
|
||||
userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[user:settings]]' }]);
|
||||
|
||||
res.render('account/settings', userData);
|
||||
});
|
||||
], callback);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -187,8 +187,11 @@ function addTags(categoryData, res) {
|
||||
];
|
||||
|
||||
if (categoryData.backgroundImage) {
|
||||
if (!categoryData.backgroundImage.startsWith('http')) {
|
||||
categoryData.backgroundImage = nconf.get('url') + categoryData.backgroundImage;
|
||||
}
|
||||
res.locals.metaTags.push({
|
||||
name: 'og:image',
|
||||
property: 'og:image',
|
||||
content: categoryData.backgroundImage,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -390,8 +390,10 @@ Controllers.manifest = function (req, res) {
|
||||
|
||||
Controllers.outgoing = function (req, res, next) {
|
||||
var url = req.query.url || '';
|
||||
var allowedProtocols = ['http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal'];
|
||||
var parsed = require('url').parse(url);
|
||||
|
||||
if (!url) {
|
||||
if (!url || !allowedProtocols.includes(parsed.protocol.slice(0, -1))) {
|
||||
return next();
|
||||
}
|
||||
|
||||
|
||||
@@ -227,6 +227,8 @@ function addTags(topicData, req, res) {
|
||||
var ogImageUrl = '';
|
||||
if (topicData.thumb) {
|
||||
ogImageUrl = topicData.thumb;
|
||||
} else if (topicData.category.backgroundImage && (!postAtIndex || !postAtIndex.index)) {
|
||||
ogImageUrl = topicData.category.backgroundImage;
|
||||
} else if (postAtIndex && postAtIndex.user && postAtIndex.user.picture) {
|
||||
ogImageUrl = postAtIndex.user.picture;
|
||||
} else if (meta.config['og:image']) {
|
||||
|
||||
41
src/meta/debugFork.js
Normal file
41
src/meta/debugFork.js
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
var fork = require('child_process').fork;
|
||||
|
||||
var debugArg = process.execArgv.find(function (arg) {
|
||||
return /^--(debug|inspect)/.test(arg);
|
||||
});
|
||||
var debugging = !!debugArg;
|
||||
|
||||
debugArg = debugArg ? debugArg.replace('-brk', '').split('=') : ['--debug', 5859];
|
||||
var lastAddress = parseInt(debugArg[1], 10);
|
||||
|
||||
/**
|
||||
* child-process.fork, but safe for use in debuggers
|
||||
* @param {string} modulePath
|
||||
* @param {string[]} [args]
|
||||
* @param {any} [options]
|
||||
*/
|
||||
function debugFork(modulePath, args, options) {
|
||||
var execArgv = [];
|
||||
if (global.v8debug || debugging) {
|
||||
lastAddress += 1;
|
||||
|
||||
execArgv = [debugArg[0] + '=' + lastAddress, '--nolazy'];
|
||||
}
|
||||
|
||||
if (!Array.isArray(args)) {
|
||||
options = args;
|
||||
args = [];
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
options = Object.assign({}, options, {
|
||||
execArgv: execArgv,
|
||||
});
|
||||
|
||||
return fork(modulePath, args, options);
|
||||
}
|
||||
debugFork.debugging = debugging;
|
||||
|
||||
module.exports = debugFork;
|
||||
@@ -1,16 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (execArgv) {
|
||||
execArgv = execArgv || process.execArgv;
|
||||
var debugArg = execArgv.find(function (arg) {
|
||||
return /^--(debug|inspect)/.test(arg);
|
||||
});
|
||||
if (global.v8debug || debugArg) {
|
||||
debugArg = debugArg ? debugArg.split('=') : ['--debug', 5859];
|
||||
var num = parseInt(debugArg[1], 10) + 1;
|
||||
|
||||
return { execArgv: [debugArg[0] + '=' + num, '--nolazy'] };
|
||||
}
|
||||
|
||||
return { execArgv: [] };
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var childProcess = require('child_process');
|
||||
var os = require('os');
|
||||
var uglifyjs = require('uglify-js');
|
||||
var async = require('async');
|
||||
@@ -11,7 +10,7 @@ var postcss = require('postcss');
|
||||
var autoprefixer = require('autoprefixer');
|
||||
var clean = require('postcss-clean');
|
||||
|
||||
var debugParams = require('./debugParams');
|
||||
var fork = require('./debugFork');
|
||||
|
||||
var Minifier = module.exports;
|
||||
|
||||
@@ -47,13 +46,12 @@ function getChild() {
|
||||
return free.shift();
|
||||
}
|
||||
|
||||
var forkProcessParams = debugParams();
|
||||
var proc = childProcess.fork(__filename, [], Object.assign({}, forkProcessParams, {
|
||||
var proc = fork(__filename, [], {
|
||||
cwd: __dirname,
|
||||
env: {
|
||||
minifier_child: true,
|
||||
},
|
||||
}));
|
||||
});
|
||||
pool.push(proc);
|
||||
|
||||
return proc;
|
||||
|
||||
@@ -79,6 +79,7 @@ module.exports = function (middleware) {
|
||||
uid: 0,
|
||||
username: '[[global:guest]]',
|
||||
userslug: '',
|
||||
fullname: '[[global:guest]]',
|
||||
email: '',
|
||||
picture: user.getDefaultAvatar(),
|
||||
status: 'offline',
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var fork = require('child_process').fork;
|
||||
var path = require('path');
|
||||
|
||||
var debugParams = require('./meta/debugParams');
|
||||
var fork = require('./meta/debugFork');
|
||||
|
||||
exports.hash = function (rounds, password, callback) {
|
||||
forkChild({ type: 'hash', rounds: rounds, password: password }, callback);
|
||||
@@ -17,7 +16,7 @@ exports.compare = function (password, hash, callback) {
|
||||
};
|
||||
|
||||
function forkChild(message, callback) {
|
||||
var child = fork(path.join(__dirname, 'bcrypt'), [], debugParams());
|
||||
var child = fork(path.join(__dirname, 'bcrypt'));
|
||||
|
||||
child.on('message', function (msg) {
|
||||
if (msg.err) {
|
||||
|
||||
@@ -12,12 +12,21 @@ module.exports = function (Posts) {
|
||||
Posts.getUserInfoForPosts = function (uids, uid, callback) {
|
||||
var groupsMap = {};
|
||||
var userData;
|
||||
var userSettings;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status', 'lastonline', 'groupTitle'], next);
|
||||
async.parallel({
|
||||
userData: function (next) {
|
||||
user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status', 'lastonline', 'groupTitle'], next);
|
||||
},
|
||||
userSettings: function (next) {
|
||||
user.getMultipleUserSettings(uids, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (_userData, next) {
|
||||
userData = _userData;
|
||||
function (results, next) {
|
||||
userData = results.userData;
|
||||
userSettings = results.userSettings;
|
||||
var groupTitles = userData.map(function (userData) {
|
||||
return userData && userData.groupTitle;
|
||||
}).filter(function (groupTitle, index, array) {
|
||||
@@ -38,7 +47,7 @@ module.exports = function (Posts) {
|
||||
}
|
||||
});
|
||||
|
||||
userData.forEach(function (userData) {
|
||||
userData.forEach(function (userData, index) {
|
||||
userData.uid = userData.uid || 0;
|
||||
userData.username = userData.username || '[[global:guest]]';
|
||||
userData.userslug = userData.userslug || '';
|
||||
@@ -48,7 +57,7 @@ module.exports = function (Posts) {
|
||||
userData.picture = userData.picture || '';
|
||||
userData.status = user.getStatus(userData);
|
||||
userData.signature = validator.escape(String(userData.signature || ''));
|
||||
userData.fullname = validator.escape(String(userData.fullname || ''));
|
||||
userData.fullname = userSettings[index].showfullname ? validator.escape(String(userData.fullname || '')) : undefined;
|
||||
if (parseInt(meta.config.hideFullname, 10) === 1) {
|
||||
userData.fullname = undefined;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,9 @@ Topics.getTopicsByTids = function (tids, uid, callback) {
|
||||
users: function (next) {
|
||||
user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status'], next);
|
||||
},
|
||||
userSettings: function (next) {
|
||||
user.getMultipleUserSettings(uids, next);
|
||||
},
|
||||
categories: function (next) {
|
||||
categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'image', 'bgColor', 'color', 'disabled'], next);
|
||||
},
|
||||
@@ -136,11 +139,11 @@ Topics.getTopicsByTids = function (tids, uid, callback) {
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (parseInt(meta.config.hideFullname, 10) === 1) {
|
||||
results.users.forEach(function (user) {
|
||||
results.users.forEach(function (user, index) {
|
||||
if (parseInt(meta.config.hideFullname, 10) === 1 || !results.userSettings[index].showfullname) {
|
||||
user.fullname = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var users = _.zipObject(uids, results.users);
|
||||
var categories = _.zipObject(cids, results.categories);
|
||||
|
||||
@@ -45,7 +45,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
meta.configs.setMultiple({
|
||||
'brand:logo': path.join(nconf.get('upload_path'), 'system', path.basename(meta.config['brand:logo'])),
|
||||
'brand:logo': path.join('/assets/uploads/system', path.basename(meta.config['brand:logo'])),
|
||||
'brand:emailLogo': '/assets/uploads/system/site-logo-x50.png',
|
||||
}, next);
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@ var pubsub = require('../pubsub');
|
||||
var LRU = require('lru-cache');
|
||||
|
||||
var cache = LRU({
|
||||
max: 1000,
|
||||
max: 2000,
|
||||
length: function () { return 1; },
|
||||
maxAge: 1000 * 60 * 60,
|
||||
});
|
||||
@@ -135,12 +135,14 @@ module.exports = function (User) {
|
||||
}
|
||||
|
||||
User.saveSettings = function (uid, data, callback) {
|
||||
if (!data.postsPerPage || parseInt(data.postsPerPage, 10) <= 1 || parseInt(data.postsPerPage, 10) > meta.config.postsPerPage) {
|
||||
return callback(new Error('[[error:invalid-pagination-value, 2, ' + meta.config.postsPerPage + ']]'));
|
||||
var maxPostsPerPage = meta.config.maxPostsPerPage || 20;
|
||||
if (!data.postsPerPage || parseInt(data.postsPerPage, 10) <= 1 || parseInt(data.postsPerPage, 10) > maxPostsPerPage) {
|
||||
return callback(new Error('[[error:invalid-pagination-value, 2, ' + maxPostsPerPage + ']]'));
|
||||
}
|
||||
|
||||
if (!data.topicsPerPage || parseInt(data.topicsPerPage, 10) <= 1 || parseInt(data.topicsPerPage, 10) > meta.config.topicsPerPage) {
|
||||
return callback(new Error('[[error:invalid-pagination-value, 2, ' + meta.config.topicsPerPage + ']]'));
|
||||
var maxTopicsPerPage = meta.config.maxTopicsPerPage || 20;
|
||||
if (!data.topicsPerPage || parseInt(data.topicsPerPage, 10) <= 1 || parseInt(data.topicsPerPage, 10) > maxTopicsPerPage) {
|
||||
return callback(new Error('[[error:invalid-pagination-value, 2, ' + maxTopicsPerPage + ']]'));
|
||||
}
|
||||
|
||||
data.userLang = data.userLang || meta.config.defaultLang;
|
||||
@@ -153,8 +155,8 @@ module.exports = function (User) {
|
||||
openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab,
|
||||
dailyDigestFreq: data.dailyDigestFreq || 'off',
|
||||
usePagination: data.usePagination,
|
||||
topicsPerPage: Math.min(data.topicsPerPage, parseInt(meta.config.topicsPerPage, 10) || 20),
|
||||
postsPerPage: Math.min(data.postsPerPage, parseInt(meta.config.postsPerPage, 10) || 20),
|
||||
topicsPerPage: Math.min(data.topicsPerPage, parseInt(maxTopicsPerPage, 10) || 20),
|
||||
postsPerPage: Math.min(data.postsPerPage, parseInt(maxPostsPerPage, 10) || 20),
|
||||
userLang: data.userLang || meta.config.defaultLang,
|
||||
followTopicsOnCreate: data.followTopicsOnCreate,
|
||||
followTopicsOnReply: data.followTopicsOnReply,
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/pagination:topics]]</div>
|
||||
<div class="col-sm-10 col-xs-12">
|
||||
<form>
|
||||
<strong>[[admin/settings/pagination:posts-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="postsPerPage">
|
||||
<strong>[[admin/settings/pagination:posts-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="postsPerPage"><br/>
|
||||
<strong>[[admin/settings/pagination:max-posts-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="maxPostsPerPage"><br/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -28,6 +29,7 @@
|
||||
<div class="col-sm-10 col-xs-12">
|
||||
<form>
|
||||
<strong>[[admin/settings/pagination:topics-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="topicsPerPage"><br />
|
||||
<strong>[[admin/settings/pagination:max-topics-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="maxTopicsPerPage"><br/>
|
||||
<strong>[[admin/settings/pagination:initial-num-load]]</strong><br /> <input type="text" class="form-control" value="20" data-field="topicsPerList">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -92,18 +92,19 @@ function renderWidget(widget, uid, options, callback) {
|
||||
}
|
||||
|
||||
if (widget.data.container && widget.data.container.match('{body}')) {
|
||||
translator.translate(widget.data.title, function (title) {
|
||||
Benchpress.compileParse(widget.data.container, {
|
||||
title: title,
|
||||
body: html,
|
||||
}, function (err, html) {
|
||||
next(err, { html: html });
|
||||
});
|
||||
});
|
||||
Benchpress.compileParse(widget.data.container, {
|
||||
title: widget.data.title,
|
||||
body: html,
|
||||
}, next);
|
||||
} else {
|
||||
next(null, { html: html });
|
||||
next(null, html);
|
||||
}
|
||||
},
|
||||
function (html, next) {
|
||||
translator.translate(html, function (translatedHtml) {
|
||||
next(null, { html: translatedHtml });
|
||||
});
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ describe('Controllers', function () {
|
||||
});
|
||||
|
||||
it('should load /outgoing?url=<url>', function (done) {
|
||||
request(nconf.get('url') + '/outgoing?url=http//youtube.com', function (err, res, body) {
|
||||
request(nconf.get('url') + '/outgoing?url=http://youtube.com', function (err, res, body) {
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert(body);
|
||||
@@ -233,6 +233,15 @@ describe('Controllers', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should 404 on /outgoing with javascript: protocol', function (done) {
|
||||
request(nconf.get('url') + '/outgoing?url=javascript:alert(1);', function (err, res, body) {
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 404);
|
||||
assert(body);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should load /tos', function (done) {
|
||||
meta.config.termsOfUse = 'please accept our tos';
|
||||
request(nconf.get('url') + '/tos', function (err, res, body) {
|
||||
|
||||
27
test/meta.js
27
test/meta.js
@@ -276,13 +276,28 @@ describe('meta', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('debug params', function () {
|
||||
it('should return fork arguments for debug', function (done) {
|
||||
var debugParams = require('../src/meta/debugParams');
|
||||
var data = debugParams(['--debug=5858', '--foo=1']);
|
||||
assert.equal(data.execArgv[0], '--debug=5859');
|
||||
assert.equal(data.execArgv[1], '--nolazy');
|
||||
describe('debugFork', function () {
|
||||
var oldArgv;
|
||||
before(function () {
|
||||
oldArgv = process.execArgv;
|
||||
process.execArgv = ['--debug=5858', '--foo=1'];
|
||||
});
|
||||
|
||||
it('should detect debugging', function (done) {
|
||||
var debugFork = require('../src/meta/debugFork');
|
||||
assert(!debugFork.debugging);
|
||||
|
||||
var debugForkPath = require.resolve('../src/meta/debugFork');
|
||||
delete require.cache[debugForkPath];
|
||||
|
||||
debugFork = require('../src/meta/debugFork');
|
||||
assert(debugFork.debugging);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
process.execArgv = oldArgv;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user