From 264c8db143c4c13cee2f327a8532ffbd873ac5de Mon Sep 17 00:00:00 2001 From: "Misty (Bot)" Date: Wed, 24 Jan 2018 21:14:43 +0000 Subject: [PATCH 01/15] Incremented version number - v1.7.4 --- install/package.json | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/install/package.json b/install/package.json index 148b70c443..e57eefeb4e 100644 --- a/install/package.json +++ b/install/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "1.7.3", + "version": "1.7.4", "homepage": "http://www.nodebb.org", "repository": { "type": "git", @@ -69,9 +69,6 @@ "nodebb-plugin-spam-be-gone": "0.5.1", "nodebb-rewards-essentials": "0.0.11", "nodebb-theme-lavender": "5.0.1", - "nodebb-theme-persona": "7.2.18", - "nodebb-theme-slick": "1.1.4", - "nodebb-theme-vanilla": "8.1.8", "nodebb-theme-persona": "7.2.16", "nodebb-theme-slick": "1.1.4", "nodebb-theme-vanilla": "8.1.7", @@ -105,17 +102,17 @@ "zxcvbn": "^4.4.2" }, "devDependencies": { - "coveralls": "^3.0.0", - "eslint": "^4.14.0", - "eslint-config-airbnb-base": "^12.1.0", - "eslint-plugin-import": "^2.8.0", - "grunt": "^1.0.1", - "grunt-contrib-watch": "^1.0.0", - "jsdom": "^11.5.1", - "mocha": "^4.1.0", - "mocha-lcov-reporter": "^1.3.0", - "nyc": "^11.4.1", - "smtp-server": "^3.4.1" + "coveralls": "^3.0.0", + "eslint": "^4.14.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-import": "^2.8.0", + "grunt": "^1.0.1", + "grunt-contrib-watch": "^1.0.0", + "jsdom": "^11.5.1", + "mocha": "^4.1.0", + "mocha-lcov-reporter": "^1.3.0", + "nyc": "^11.4.1", + "smtp-server": "^3.4.1" }, "bugs": { "url": "https://github.com/NodeBB/NodeBB/issues" From 3b3a28dc1511619767c1183aab7ecbf031490e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 24 Jan 2018 21:05:08 -0500 Subject: [PATCH 02/15] add ping routes to webinstaller --- install/web.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/install/web.js b/install/web.js index 8bfd416785..8dbbeec278 100644 --- a/install/web.js +++ b/install/web.js @@ -76,6 +76,12 @@ function setupRoutes() { app.get('/', welcome); app.post('/', install); app.post('/launch', launch); + app.get('/ping', ping); + app.get('/sping', ping); +} + +function ping(req, res) { + res.status(200).send(req.path === '/sping' ? 'healthy' : '200'); } function welcome(req, res) { From b3a021a3afadeb927bd23782ee5fc0db6e1e00cb Mon Sep 17 00:00:00 2001 From: "Misty (Bot)" Date: Thu, 25 Jan 2018 09:25:09 +0000 Subject: [PATCH 03/15] Latest translations and fallbacks --- .../language/fr/admin/advanced/database.json | 8 +-- .../fr/admin/appearance/customise.json | 6 +- public/language/fr/admin/manage/tags.json | 4 +- public/language/fr/admin/manage/users.json | 2 +- .../fr/admin/settings/reputation.json | 6 +- public/language/fr/error.json | 56 +++++++++---------- public/language/fr/pages.json | 2 +- public/language/nl/error.json | 6 +- public/language/nl/flags.json | 6 +- public/language/nl/pages.json | 2 +- 10 files changed, 49 insertions(+), 49 deletions(-) diff --git a/public/language/fr/admin/advanced/database.json b/public/language/fr/admin/advanced/database.json index 38f97bbd33..46742ca044 100644 --- a/public/language/fr/admin/advanced/database.json +++ b/public/language/fr/admin/advanced/database.json @@ -1,7 +1,7 @@ { - "x-b": "%1 octets", - "x-mb": "%1 Mo", - "x-gb": "%1 Go", + "x-b": "%1 b", + "x-mb": "%1 Mb", + "x-gb": "%1 Gb", "uptime-seconds": "Disponibilité en secondes", "uptime-days": "Disponibilité en jours", @@ -29,7 +29,7 @@ "redis.memory-frag-ratio": "Ratio de fragmentation de la mémoire", "redis.total-connections-recieved": "Connexions totales reçues", "redis.total-commands-processed": "Commandes totales exécutées", - "redis.iops": "Opérations par seconde", + "redis.iops": "Opérations instantanées par seconde", "redis.keyspace-hits": "Keyspace Hits", "redis.keyspace-misses": "Keyspace Misses", "redis.raw-info": "Informations brutes Redis" diff --git a/public/language/fr/admin/appearance/customise.json b/public/language/fr/admin/appearance/customise.json index d218fdbf1d..2e1521c0a2 100644 --- a/public/language/fr/admin/appearance/customise.json +++ b/public/language/fr/admin/appearance/customise.json @@ -1,7 +1,7 @@ { - "custom-css": "Custom CSS/LESS", - "custom-css.description": "Enter your own CSS/LESS declarations here, which will be applied after all other styles.", - "custom-css.enable": "Enable Custom CSS/LESS", + "custom-css": "CSS/LESS personnalisé", + "custom-css.description": "Entrez vos propres déclarations CSS/LESS ici, qui seront appliquées après tous les autres styles.", + "custom-css.enable": "Activer le CSS/LESS personnalisé", "custom-js": "Javascript personnalisé", "custom-js.description": "Entrez votre Javascript ici. Celui-ci sera exécute après le chargement complet de la page.", diff --git a/public/language/fr/admin/manage/tags.json b/public/language/fr/admin/manage/tags.json index 1d644a4c7d..226c154249 100644 --- a/public/language/fr/admin/manage/tags.json +++ b/public/language/fr/admin/manage/tags.json @@ -5,8 +5,8 @@ "create-modify": "Créer et modifier les mots-clés", "description": "Sélectionnez les mot-clés par clic ou glisser-déposer, maintenez shift pour en sélectionner plusieurs.", "create": "Créer le mot-clés", - "modify": "Modifier le mot-clés", - "rename": "Rename Tags", + "modify": "Modifier les mots-clés", + "rename": "Renommer les mots-clés", "delete": "Supprimer les mots-clés sélectionnés", "search": "Chercher des mots-clés...", "settings": "Cliquez ici pour visiter la page de paramètres des mots clés.", diff --git a/public/language/fr/admin/manage/users.json b/public/language/fr/admin/manage/users.json index 2e798d184d..047c796146 100644 --- a/public/language/fr/admin/manage/users.json +++ b/public/language/fr/admin/manage/users.json @@ -76,7 +76,7 @@ "alerts.remove-admin-success": "L'utilisateur n'est plus administrateur", "alerts.make-global-mod-success": "L'utilisateur est maintenant modérateur global", "alerts.confirm-remove-global-mod": "Voulez-vous vraiment supprimer ce modérateur global?", - "alerts.remove-global-mod-success": "User is no longer global moderator.", + "alerts.remove-global-mod-success": "L'utilisateur n'est plus un modérateur global.", "alerts.make-moderator-success": "L'utilisateur est maintenant modérateur", "alerts.confirm-remove-moderator": "Voulez-vous vraiment supprimer ce modérateur?", "alerts.remove-moderator-success": "L'utilisateur n'est plus modérateur", diff --git a/public/language/fr/admin/settings/reputation.json b/public/language/fr/admin/settings/reputation.json index af1f293f50..9206382add 100644 --- a/public/language/fr/admin/settings/reputation.json +++ b/public/language/fr/admin/settings/reputation.json @@ -6,7 +6,7 @@ "thresholds": "Seuils d'activité", "min-rep-downvote": "Réputation minimum pour les votes négatifs", "min-rep-flag": "Réputation minimum pour signaler un message", - "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-website": "Réputation minimum pour ajouter \"Site internet\" au profil utilisateur", + "min-rep-aboutme": "Réputation minimum pour ajouter \"À propos\" au profil utilisateur", + "min-rep-signature": "Réputation minimum pour ajouter \"Signature\" au profil utilisateur" } \ No newline at end of file diff --git a/public/language/fr/error.json b/public/language/fr/error.json index 1141fc7a88..bb61a8a95b 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -8,7 +8,7 @@ "invalid-cid": "ID de catégorie invalide", "invalid-tid": "ID de sujet invalide", "invalid-pid": "ID de message invalide", - "invalid-uid": "ID utilisateur invalide", + "invalid-uid": "ID d'utilisateur invalide", "invalid-username": "Nom d'utilisateur invalide", "invalid-email": "Email invalide", "invalid-title": "Titre invalide", @@ -18,23 +18,23 @@ "invalid-username-or-password": "Veuillez entrer un nom d'utilisateur et un mot de passe", "invalid-search-term": "Données de recherche invalides", "invalid-url": "URL invalide", - "csrf-invalid": "Nous ne pouvons pas vous connectez, possiblement car votre session a expiré. Merci de réessayer.", + "csrf-invalid": "Nous ne pouvons pas vous connectez, probablement car votre session a expiré. Merci de réessayer.", "invalid-pagination-value": "Valeur de pagination invalide. Celle-ci doit être comprise entre %1 et %2.", "username-taken": "Nom d’utilisateur déjà utilisé", "email-taken": "Email déjà utilisé", "email-not-confirmed": "Votre adresse email n'est pas confirmée, cliquez ici pour la valider.", "email-not-confirmed-chat": "Il ne vous est pas possible d'utiliser le chat tant que votre adresse email n'a pas été vérifiée. Veuillez cliquer ici pour confirmer votre adresse email.", - "email-not-confirmed-email-sent": "Votre adresse email n'a pas encore été confirmée. Merci de vérifier l'email de confirmation dans votre boîte de reception.", + "email-not-confirmed-email-sent": "Votre adresse email n'a pas encore été confirmée. Merci de vérifier l'email de confirmation dans votre boîte de réception.", "no-email-to-confirm": "Ce forum requiert une vérification de votre adresse email. Veuillez cliquer ici pour entrer une adresse.", "email-confirm-failed": "Votre adresse email n'a pas pu être vérifiée. Veuillez ré-essayer plus tard.", "confirm-email-already-sent": "L'email de confirmation a déjà été envoyé. Veuillez attendre %1 minute(s) avant de redemander un nouvel envoi.", - "sendmail-not-found": "L'application d'envoi de mail est introuvable, assurez-vous qu'elle est installée et que l'utilisateur servant à démarrer NodeBB ait des droits suffisants.", + "sendmail-not-found": "L'application d'envoi de mail est introuvable, assurez-vous qu'elle est installée et que l'utilisateur ayant démarré NodeBB ait des droits suffisants.", "username-too-short": "Nom d'utilisateur trop court", "username-too-long": "Nom d'utilisateur trop long", "password-too-long": "Mot de passe trop long", "user-banned": "Utilisateur banni", "user-banned-reason": "Désolé, ce compte a été banni (Raison : %1)", - "user-banned-reason-until": "Désolé, ce compte a été banni jusque %1 (Raison : %2).", + "user-banned-reason-until": "Désolé, ce compte a été banni jusqu'au %1 (Raison : %2).", "user-too-new": "Désolé, vous devez attendre encore %1 seconde(s) avant d'envoyer votre premier message", "blacklisted-ip": "Désolé, votre adresse IP a été bannie de cette communauté. Si vous pensez que c'est une erreur, veuillez contacter un administrateur.", "ban-expiry-missing": "Veuillez entrer une date de fin de banissement.", @@ -63,24 +63,24 @@ "post-delete-duration-expired-days-hours": "Vous ne pouvez supprimer un message que pendant %1 jour(s) et %2 heure(s) après l'avoir posté.", "cant-delete-topic-has-reply": "Vous ne pouvez pas supprimer votre sujet s'il a au moins une réponse.", "cant-delete-topic-has-replies": "Vous ne pouvez pas supprimer votre sujet s'il a au moins %1 réponses.", - "content-too-short": "Veuillez entrer un message plus long. %1 caractère(s) minimum.", - "content-too-long": "Veuillez poster un message plus cours. Les messages ne peuvent être plus long que %1 caractère(s).", - "title-too-short": "Veuillez entrer un titre plus long. %1 caractère(s) minimum.", + "content-too-short": "Veuillez entrer un message plus long. Les messages doivent contenir au moins %1 caractère(s).", + "content-too-long": "Veuillez poster un message plus court. Les messages ne peuvent être plus long que %1 caractère(s).", + "title-too-short": "Veuillez entrer un titre plus long. Les titres doivent contenir au moins %1 caractère(s).", "title-too-long": "Veuillez entrer un titre plus court. Les titres ne peuvent excéder %1 caractère(s).", "category-not-selected": "Aucune catégorie sélectionnée", - "too-many-posts": "Vous ne pouvez poster que toutes les %1 seconde(s).", + "too-many-posts": "Vous ne pouvez poster que toutes les %1 seconde(s) - merci de patienter avant de publier à nouveau.", "too-many-posts-newbie": "En tant que nouvel utilisateur, vous ne pouvez poster que toutes les %1 seconde(s) jusqu'à ce que vous obteniez une réputation de %2 - patientez avant de publier de nouveau.", "tag-too-short": "Veuillez entrer un mot-clé plus long. Les mots-clés doivent contenir au moins %1 caractère(s).", - "tag-too-long": "Veuillez entrer un mot-clé plus court. Les mot-clés ne peuvent faire plus de %1 caractère(s).", + "tag-too-long": "Veuillez entrer un mot-clé plus court. Les mot-clés ne peuvent excéder %1 caractère(s).", "not-enough-tags": "Pas assez de mots-clés. Les sujets doivent avoir au moins %1 mots-clé(s).", "too-many-tags": "Trop de mots-clés. Les sujets ne peuvent avoir au plus que %1 mots-clé(s).", - "still-uploading": "Veuillez patienter pendant le téléchargement.", - "file-too-big": "La taille maximale autorisée pour un fichier est de %1 kb. Veuillez envoyer un fichier plus petit.", - "guest-upload-disabled": "Le téléversement est désactivé pour les Invités.", + "still-uploading": "Veuillez patienter pendant l'envoi des fichiers.", + "file-too-big": "La taille maximale autorisée pour un fichier est de %1 ko. Veuillez envoyer un fichier plus petit.", + "guest-upload-disabled": "L'envoi de fichiers a été désactivé pour les invités", "already-bookmarked": "Vous avez déjà mis un marque-page", "already-unbookmarked": "Vous avez déjà retiré un marque-page", "cant-ban-other-admins": "Vous ne pouvez pas bannir les autres administrateurs !", - "cant-remove-last-admin": "Vous seul êtes administrateur. Ajouter un autre utilisateur en tant qu'administrateur avant de vous en retirer.", + "cant-remove-last-admin": "Vous êtes le seul administrateur. Ajoutez un autre utilisateur en tant qu'administrateur avant de vous retirer.", "cant-delete-admin": "Veuillez retirer les droits d'administration de ce compte avant de tenter de le supprimer.", "invalid-image": "Image invalide", "invalid-image-type": "Type d'image invalide. Les types autorisés sont: %1", @@ -105,41 +105,41 @@ "uploads-are-disabled": "Les envois sont désactivés", "signature-too-long": "La signature ne peut dépasser %1 caractère(s).", "about-me-too-long": "Votre texte \"à propos de moi\" ne peut dépasser %1 caractère(s).", - "cant-chat-with-yourself": "Vous ne pouvez chatter avec vous même !", - "chat-restricted": "Cet utilisateur a restreint les ses messages de chat. Il doit d'abord s'abonner à votre compte avant que vous puissiez discuter avec lui.", + "cant-chat-with-yourself": "Vous ne pouvez discuter avec vous-même !", + "chat-restricted": "Cet utilisateur a restreint ses messages de chat. Il doit d'abord s'abonner à votre compte avant que vous puissiez discuter avec lui.", "chat-disabled": "Système de chat désactivé", "too-many-messages": "Vous avez envoyé trop de messages, veuillez patienter un instant.", - "invalid-chat-message": "Message de Chat invalide", + "invalid-chat-message": "Message de chat invalide", "chat-message-too-long": "Les messages de discussion ne peuvent pas être plus longs que %1 caractères.", "cant-edit-chat-message": "Vous n'avez pas l'autorisation de modifier ce message", "cant-remove-last-user": "Vous ne pouvez pas supprimer le dernier utilisateur", "cant-delete-chat-message": "Vous n'avez pas l'autorisation de supprimer ce message", - "chat-edit-duration-expired": "Vous n'êtes autorisé à modifier des messages qu'après %1 seconde(s) de les avoir postés", - "chat-delete-duration-expired": "Vous n'êtes autorisé à supprimer des messages qu'après %1 seconde(s) de les avoir postés", + "chat-edit-duration-expired": "Vous n'êtes autorisé à modifier des messages que pendant %1 seconde(s) après les avoir postés", + "chat-delete-duration-expired": "Vous n'êtes autorisé à supprimer des messages que pendant %1 seconde(s) après les avoir postés", "already-voting-for-this-post": "Vous avez déjà voté pour ce message.", "reputation-system-disabled": "Le système de réputation est désactivé", "downvoting-disabled": "Les votes négatifs ne sont pas autorisés", "not-enough-reputation-to-downvote": "Vous n'avez pas une réputation assez élevée pour noter négativement ce message", "not-enough-reputation-to-flag": "Vous n'avez pas une réputation assez élevée pour signaler ce message", - "not-enough-reputation-min-rep-website": "You do not have enough reputation to add a website", - "not-enough-reputation-min-rep-aboutme": "You do not have enough reputation to add an about me", - "not-enough-reputation-min-rep-signature": "You do not have enough reputation to add a signature", + "not-enough-reputation-min-rep-website": "Vous n'avez pas une réputation assez élevée pour ajouter un site internet", + "not-enough-reputation-min-rep-aboutme": "Vous n'avez pas une réputation assez élevée pour ajouter un à propos", + "not-enough-reputation-min-rep-signature": "Vous n'avez pas une réputation assez élevée pour ajouter une signature", "already-flagged": "Vous avez déjà signalé ce message", "self-vote": "Vous ne pouvez pas voter sur votre propre message", - "reload-failed": "NodeBB a rencontré un problème lors du rechargement : \"% 1\" . NodeBB continuera de fonctionner côté client, même si vous devez annuler ce que vous avez fait juste avant de recharger .", + "reload-failed": "NodeBB a rencontré un problème lors du rechargement : \"%1\" . NodeBB continuera de fonctionner côté client, même si vous devriez annuler ce que vous avez fait juste avant de recharger.", "registration-error": "Erreur d'enregistrement", "parse-error": "Une erreur est survenue en analysant la réponse du serveur", "wrong-login-type-email": "Veuillez utiliser votre adresse email pour vous connecter", "wrong-login-type-username": "Veuillez utiliser votre identifiant pour vous connecter", - "sso-registration-disabled": "L'enregistrement a été désactivé pour les comptes %1, s'il vous plaît, enregistrez vous avec un adresse mail en premier", - "invite-maximum-met": "Vous avez invité la quantité maximale de personnes (%1 de %2).", - "no-session-found": "Pas de session de connexion trouvé!", + "sso-registration-disabled": "L'enregistrement a été désactivé pour les comptes %1, merci de vous enregistrer avec une adresse mail avant", + "invite-maximum-met": "Vous avez invité la quantité maximale de personnes (%1 sur %2).", + "no-session-found": "Pas de session de connexion trouvée !", "not-in-room": "L'utilisateur n'est pas dans cette salle", "no-users-in-room": "Aucun utilisateur dans cette salle", "cant-kick-self": "Vous ne pouvez pas vous exclure vous-même du groupe", "no-users-selected": "Aucun utilisateur sélectionné", - "invalid-home-page-route": "Route de page d'accueil invalide", - "invalid-session": "Session Interrompue", + "invalid-home-page-route": "Chemin vers la page d'accueil invalide", + "invalid-session": "Session interrompue", "invalid-session-text": "Il semble que votre session ne soit plus active, ou que le serveur ne la reconnaisse plus. Merci de rafraichir cette page.", "no-topics-selected": "Aucun sujet sélectionné !" } \ No newline at end of file diff --git a/public/language/fr/pages.json b/public/language/fr/pages.json index 98abe48bd2..5609a93d49 100644 --- a/public/language/fr/pages.json +++ b/public/language/fr/pages.json @@ -20,7 +20,7 @@ "users/search": "Rechercher des utilisateurs", "notifications": "Notifications", "tags": "Mots-clés", - "tag": "Topics tagged under "%1"", + "tag": "Sujets marqués comme \"%1\"", "register": "Créer un compte", "registration-complete": "Inscription terminée", "login": "Connectez-vous à votre compte", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index a35e67fa8a..9606aebb8c 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -121,9 +121,9 @@ "downvoting-disabled": "Negatief stemmen is uitgeschakeld", "not-enough-reputation-to-downvote": "Je hebt onvoldoende reputatie om een negatieve stem uit te mogen brengen", "not-enough-reputation-to-flag": "Je hebt onvoldoende reputatie om dit bericht aan de beheerders te mogen melden", - "not-enough-reputation-min-rep-website": "You do not have enough reputation to add a website", - "not-enough-reputation-min-rep-aboutme": "You do not have enough reputation to add an about me", - "not-enough-reputation-min-rep-signature": "You do not have enough reputation to add a signature", + "not-enough-reputation-min-rep-website": "Je hebt onvoldoende reputatie om een website toe te mogen voegen", + "not-enough-reputation-min-rep-aboutme": "Je hebt onvoldoende reputatie om een \"Over mij\" toe te mogen voegen", + "not-enough-reputation-min-rep-signature": "Je hebt onvoldoende reputatie om een handtekening toe te mogen voegen", "already-flagged": "Je hebt deze post al gerapporteerd", "self-vote": "Het is niet mogelijk om op je eigen bericht te stemmen", "reload-failed": "Tijdens het herladen van \"%1\" is NodeBB een fout of probleem tegengekomen. NodeBB blijft operationeel. Echter het is verstandig om de oorzaak te onderzoeken en wellicht de vorige actie, voor het herladen, ongedaan te maken.", diff --git a/public/language/nl/flags.json b/public/language/nl/flags.json index af87085366..2a02015440 100644 --- a/public/language/nl/flags.json +++ b/public/language/nl/flags.json @@ -9,7 +9,7 @@ "updated": "Bijgewerkt", "target-purged": "The content this flag referred to has been purged and is no longer available.", - "quick-filters": "Quick Filters", + "quick-filters": "Snelfilters", "filter-active": "Er zijn een of meer filters actief in deze lijst van markeringen", "filter-reset": "Filters verwijderen", "filters": "Filter opties", @@ -19,13 +19,13 @@ "filter-type-all": "Alle inhoud", "filter-type-post": "Bericht", "filter-state": "Status", - "filter-assignee": "Assignee UID", + "filter-assignee": "UID van toewijzer", "filter-cid": "Categorie", "filter-quick-mine": "Toegewezen aan mij", "filter-cid-all": "Alle categorieën", "apply-filters": "Filters toepassen", - "quick-links": "Quick Links", + "quick-links": "Snelkoppelingen", "flagged-user": "Flagged User", "view-profile": "Profiel bekijken", "start-new-chat": "Begin een nieuwe chat", diff --git a/public/language/nl/pages.json b/public/language/nl/pages.json index e4b8d02d44..10e31e47de 100644 --- a/public/language/nl/pages.json +++ b/public/language/nl/pages.json @@ -20,7 +20,7 @@ "users/search": "Zoek Gebruiker", "notifications": "Notificaties", "tags": "Tags", - "tag": "Topics tagged under "%1"", + "tag": "Onderwerpen getagd onder "%1"", "register": "Registeer een gebruikersaccount", "registration-complete": "Registratie compleet", "login": "Login met u gebruikersaccount in", From f7aa32cd05be4f4564dd67bda70723d0ec62790d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 25 Jan 2018 09:16:02 -0500 Subject: [PATCH 04/15] dont crash if res.session.meta is not set --- src/middleware/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middleware/user.js b/src/middleware/user.js index e3123e6942..c61e5144b3 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -177,7 +177,7 @@ module.exports = function (middleware) { var disabled = parseInt(meta.config.adminReloginDuration, 10) === 0; if (disabled || (loginTime && parseInt(loginTime, 10) > Date.now() - adminReloginDuration)) { var timeLeft = parseInt(loginTime, 10) - (Date.now() - adminReloginDuration); - if (timeLeft < Math.min(300000, adminReloginDuration)) { + if (req.session.meta && timeLeft < Math.min(300000, adminReloginDuration) ) { req.session.meta.datetime += Math.min(300000, adminReloginDuration); } From a4939d78fecb6a047787e0b4f0fbf1efee60eeb6 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 25 Jan 2018 11:50:33 -0500 Subject: [PATCH 05/15] Moved ping to its own controller re: #6281 --- config.json.bk | 11 +++++++++++ src/controllers/index.js | 1 + src/controllers/ping.js | 15 +++++++++++++++ src/webserver.js | 16 +++------------- 4 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 config.json.bk create mode 100644 src/controllers/ping.js diff --git a/config.json.bk b/config.json.bk new file mode 100644 index 0000000000..05adb022c6 --- /dev/null +++ b/config.json.bk @@ -0,0 +1,11 @@ +{ + "url": "http://127.0.0.1:4567", + "secret": "catsRkool", + "database": "redis", + "port": 4567, + "redis": { + "host": "127.0.0.1", + "port": "6379", + "database": "0" + } +} diff --git a/src/controllers/index.js b/src/controllers/index.js index bddab21a11..6e82dbf4a2 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -11,6 +11,7 @@ var helpers = require('./helpers'); var Controllers = module.exports; +Controllers.ping = require('./ping'); Controllers.home = require('./home'); Controllers.topics = require('./topics'); Controllers.posts = require('./posts'); diff --git a/src/controllers/ping.js b/src/controllers/ping.js new file mode 100644 index 0000000000..d43beca298 --- /dev/null +++ b/src/controllers/ping.js @@ -0,0 +1,15 @@ +'use strict'; + +var async = require('async'); +var db = require('../database'); + +module.exports.ping = function (req, res, next) { + async.waterfall([ + function (next) { + db.getObject('config', next); + }, + function () { + res.status(200).send(req.path === '/sping' ? 'healthy' : '200'); + }, + ], next); +}; diff --git a/src/webserver.js b/src/webserver.js index dc7c70770c..57904f8dd0 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -116,6 +116,7 @@ function initializeNodeBB(callback) { function setupExpressApp(app, callback) { var middleware = require('./middleware'); + var pingController = require('./controllers/ping'); var relativePath = nconf.get('relative_path'); var viewsDir = nconf.get('views_dir'); @@ -147,8 +148,8 @@ function setupExpressApp(app, callback) { app.use(compression()); - app.get(relativePath + '/ping', ping); - app.get(relativePath + '/sping', ping); + app.get(relativePath + '/ping', pingController.ping); + app.get(relativePath + '/sping', pingController.ping); setupFavicon(app); @@ -179,17 +180,6 @@ function setupExpressApp(app, callback) { setupAutoLocale(app, callback); } -function ping(req, res, next) { - async.waterfall([ - function (next) { - db.getObject('config', next); - }, - function () { - res.status(200).send(req.path === '/sping' ? 'healthy' : '200'); - }, - ], next); -} - function setupFavicon(app) { var faviconPath = meta.config['brand:favicon'] || 'favicon.ico'; faviconPath = path.join(nconf.get('base_dir'), 'public', faviconPath.replace(/assets\/uploads/, 'uploads')); From 08da1b262b886aa2b32850539b9625bceaf1f036 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 25 Jan 2018 12:26:57 -0500 Subject: [PATCH 06/15] gg --- config.json.bk | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 config.json.bk diff --git a/config.json.bk b/config.json.bk deleted file mode 100644 index 05adb022c6..0000000000 --- a/config.json.bk +++ /dev/null @@ -1,11 +0,0 @@ -{ - "url": "http://127.0.0.1:4567", - "secret": "catsRkool", - "database": "redis", - "port": 4567, - "redis": { - "host": "127.0.0.1", - "port": "6379", - "database": "0" - } -} From 14fbc0dc2f732fd64f00da833f0e355c072502ec Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Thu, 25 Jan 2018 12:29:54 -0500 Subject: [PATCH 07/15] remove dupe method --- public/src/client/categories.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/public/src/client/categories.js b/public/src/client/categories.js index 8357ff8a29..779710fcbb 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -36,7 +36,8 @@ define('forum/categories', ['components', 'translator', 'benchpress'], function var recentPosts = category.find('[component="category/posts"]'); - parseAndTranslate([post], function (html) { + app.parseAndTranslate('partials/categories/lastpost', 'posts', { posts: [post] }, function (html) { + html.find('.post-content img:not(.not-responsive)').addClass('img-responsive'); html.hide(); if (recentPosts.length === 0) { html.appendTo(category); @@ -57,16 +58,5 @@ define('forum/categories', ['components', 'translator', 'benchpress'], function }); } - function parseAndTranslate(posts, callback) { - Benchpress.parse('partials/categories/lastpost', 'posts', { posts: posts }, function (html) { - translator.translate(html, function (translatedHTML) { - translatedHTML = $(translatedHTML); - translatedHTML.find('.post-content img:not(.not-responsive)').addClass('img-responsive'); - - callback(translatedHTML); - }); - }); - } - return categories; }); From c090ec301b7ca6d57392e94926da48ef65530135 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Thu, 25 Jan 2018 12:31:43 -0500 Subject: [PATCH 08/15] fix lint --- src/middleware/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middleware/user.js b/src/middleware/user.js index c61e5144b3..2b29aa5ca1 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -177,7 +177,7 @@ module.exports = function (middleware) { var disabled = parseInt(meta.config.adminReloginDuration, 10) === 0; if (disabled || (loginTime && parseInt(loginTime, 10) > Date.now() - adminReloginDuration)) { var timeLeft = parseInt(loginTime, 10) - (Date.now() - adminReloginDuration); - if (req.session.meta && timeLeft < Math.min(300000, adminReloginDuration) ) { + if (req.session.meta && timeLeft < Math.min(300000, adminReloginDuration)) { req.session.meta.datetime += Math.min(300000, adminReloginDuration); } From 7aae16718807bb695817dcabd61bfa53b1414403 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Thu, 25 Jan 2018 12:52:51 -0500 Subject: [PATCH 09/15] remove unused deps --- public/src/client/categories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/categories.js b/public/src/client/categories.js index 779710fcbb..72b1ff2bcb 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -1,7 +1,7 @@ 'use strict'; -define('forum/categories', ['components', 'translator', 'benchpress'], function (components, translator, Benchpress) { +define('forum/categories', ['components'], function (components) { var categories = {}; $(window).on('action:ajaxify.start', function (ev, data) { From c37be3b58f633f40b0c7f4c0a297ab93e83411c3 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Thu, 25 Jan 2018 13:40:08 -0500 Subject: [PATCH 10/15] remove my stupid code --- src/controllers/accounts/helpers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 0a99d83af1..64170ce39d 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -106,7 +106,6 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { userData.moderationNote = undefined; } - userData.uid = userData.uid; userData.yourid = callerUID; userData.theirid = userData.uid; userData.isTargetAdmin = results.isTargetAdmin; From 2e2b97033e63d0fa977f98dbe2188e96a77964f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 26 Jan 2018 12:25:59 -0500 Subject: [PATCH 11/15] closes #6248 , closes #6282 --- install/package.json | 2 +- public/language/en-GB/topic.json | 1 + src/topics.js | 25 +++++++++++++++++++++++++ src/topics/merge.js | 7 +++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index e57eefeb4e..58a22e7821 100644 --- a/install/package.json +++ b/install/package.json @@ -69,7 +69,7 @@ "nodebb-plugin-spam-be-gone": "0.5.1", "nodebb-rewards-essentials": "0.0.11", "nodebb-theme-lavender": "5.0.1", - "nodebb-theme-persona": "7.2.16", + "nodebb-theme-persona": "7.2.19", "nodebb-theme-slick": "1.1.4", "nodebb-theme-vanilla": "8.1.7", "nodebb-widget-essentials": "4.0.1", diff --git a/public/language/en-GB/topic.json b/public/language/en-GB/topic.json index 657880296c..a4892868b3 100644 --- a/public/language/en-GB/topic.json +++ b/public/language/en-GB/topic.json @@ -38,6 +38,7 @@ "flag_title": "Flag this post for moderation", + "merged_message": "This topic has been merged into %2", "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.", diff --git a/src/topics.js b/src/topics.js index 2ac14e4264..c3475995bd 100644 --- a/src/topics.js +++ b/src/topics.js @@ -198,6 +198,7 @@ Topics.getTopicWithPosts = function (topicData, set, uid, start, stop, reverse, bookmark: async.apply(Topics.getUserBookmark, topicData.tid, uid), postSharing: async.apply(social.getActivePostSharing), deleter: async.apply(getDeleter, topicData), + merger: async.apply(getMerger, topicData), related: function (next) { async.waterfall([ function (next) { @@ -223,6 +224,8 @@ Topics.getTopicWithPosts = function (topicData, set, uid, start, stop, reverse, topicData.postSharing = results.postSharing; topicData.deleter = results.deleter; topicData.deletedTimestampISO = utils.toISOString(topicData.deletedTimestamp); + topicData.merger = results.merger; + topicData.mergedTimestampISO = utils.toISOString(topicData.mergedTimestamp); topicData.related = results.related || []; topicData.unreplied = parseInt(topicData.postcount, 10) === 1; @@ -290,6 +293,28 @@ function getDeleter(topicData, callback) { user.getUserFields(topicData.deleterUid, ['username', 'userslug', 'picture'], callback); } +function getMerger(topicData, callback) { + if (!topicData.mergerUid) { + return setImmediate(callback, null, null); + } + async.waterfall([ + function (next) { + async.parallel({ + merger: function (next) { + user.getUserFields(topicData.mergerUid, ['username', 'userslug', 'picture'], next); + }, + mergedIntoTitle: function (next) { + Topics.getTopicField(topicData.mergeIntoTid, 'title', next); + }, + }, next); + }, + function (results, next) { + results.merger.mergedIntoTitle = results.mergedIntoTitle; + next(null, results.merger); + }, + ], callback); +} + Topics.getMainPost = function (tid, uid, callback) { Topics.getMainPosts([tid], uid, function (err, mainPosts) { callback(err, Array.isArray(mainPosts) && mainPosts.length ? mainPosts[0] : null); diff --git a/src/topics/merge.js b/src/topics/merge.js index 9fd97f60eb..0477de3b41 100644 --- a/src/topics/merge.js +++ b/src/topics/merge.js @@ -26,6 +26,13 @@ module.exports = function (Topics) { function (next) { Topics.delete(tid, uid, next); }, + function (next) { + Topics.setTopicFields(tid, { + mergeIntoTid: mergeIntoTid, + mergerUid: uid, + mergedTimestamp: Date.now(), + }, next); + }, ], next); }, callback); }; From 5302e79b564f057105be467f885e0018b0605c58 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 26 Jan 2018 13:22:28 -0500 Subject: [PATCH 12/15] fixing accidental usage of .includes @benlubar --- public/src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/utils.js b/public/src/utils.js index 2fcdfa8157..d921573f7a 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -550,7 +550,7 @@ value = value ? value.split(' ') : []; ['noopener', 'noreferrer'].forEach(function (property) { - if (!value.includes(property)) { + if (value.indexOf(property) === -1) { value.push(property); } }); From 5e89c520410b3c7d0dbd12d87ab885125fbfae11 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 26 Jan 2018 15:00:13 -0500 Subject: [PATCH 13/15] bump markdown --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 58a22e7821..68cffdcd36 100644 --- a/install/package.json +++ b/install/package.json @@ -63,7 +63,7 @@ "nodebb-plugin-dbsearch": "2.0.9", "nodebb-plugin-emoji": "2.0.9", "nodebb-plugin-emoji-android": "2.0.0", - "nodebb-plugin-markdown": "8.2.2", + "nodebb-plugin-markdown": "8.3.0", "nodebb-plugin-mentions": "2.2.2", "nodebb-plugin-soundpack-default": "1.0.0", "nodebb-plugin-spam-be-gone": "0.5.1", From 0a5d16d1cd8cc0adc65aad33c5bbbd391ad2e364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 26 Jan 2018 15:50:26 -0500 Subject: [PATCH 14/15] closes #6284 --- .gitignore | 1 + test/mocks/databasemock.js | 17 ++++++++++++++++- test/user.js | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 76eb6aa59c..2ae33250b3 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ pidfile /public/sounds /public/uploads +/test/uploads # compiled files /public/stylesheet.css diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 5314894543..0bef41c466 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -17,7 +17,7 @@ nconf.file({ file: path.join(__dirname, '../../config.json') }); nconf.defaults({ base_dir: path.join(__dirname, '../..'), themes_path: path.join(__dirname, '../../node_modules'), - upload_path: 'public/uploads', + upload_path: 'test/uploads', views_dir: path.join(__dirname, '../../build/public/templates'), relative_path: '', }); @@ -173,6 +173,21 @@ function setupMockDefaults(callback) { id: 'nodebb-theme-persona', }, next); }, + function (next) { + var rimraf = require('rimraf'); + rimraf('test/uploads', next); + }, + function (next) { + var mkdirp = require('mkdirp'); + async.eachSeries([ + 'test/uploads', + 'test/uploads/category', + 'test/uploads/files', + 'test/uploads/system', + 'test/uploads/sounds', + 'test/uploads/profile', + ], mkdirp, next); + }, ], callback); } db.setupMockDefaults = setupMockDefaults; diff --git a/test/user.js b/test/user.js index 8de7491761..897bb71a78 100644 --- a/test/user.js +++ b/test/user.js @@ -816,7 +816,7 @@ describe('User', function () { }, function (err, uploadedPicture) { assert.ifError(err); assert.equal(uploadedPicture.url, '/assets/uploads/profile/' + uid + '-profileavatar.png'); - assert.equal(uploadedPicture.path, path.join(nconf.get('base_dir'), 'public', 'uploads', 'profile', uid + '-profileavatar.png')); + assert.equal(uploadedPicture.path, path.join(nconf.get('upload_path'), 'profile', uid + '-profileavatar.png')); done(); }); } From c7506d77b07c24d0d232828b7a3739d8b27d4268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 26 Jan 2018 18:56:17 -0500 Subject: [PATCH 15/15] closes #6247 --- .../language/en-GB/admin/manage/uploads.json | 7 ++ public/language/en-GB/admin/menu.json | 1 + public/src/admin/manage/uploads.js | 35 ++++++ src/controllers/admin/uploads.js | 113 ++++++++++++++++++ src/file.js | 2 +- src/pagination.js | 5 +- src/routes/admin.js | 3 + src/socket.io/admin.js | 13 ++ src/views/admin/manage/uploads.tpl | 39 ++++++ src/views/admin/partials/menu.tpl | 2 + 10 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 public/language/en-GB/admin/manage/uploads.json create mode 100644 public/src/admin/manage/uploads.js create mode 100644 src/views/admin/manage/uploads.tpl diff --git a/public/language/en-GB/admin/manage/uploads.json b/public/language/en-GB/admin/manage/uploads.json new file mode 100644 index 0000000000..13e69cafa7 --- /dev/null +++ b/public/language/en-GB/admin/manage/uploads.json @@ -0,0 +1,7 @@ +{ + "upload-file": "Upload File", + "filename": "Filename", + "size/filecount": "Size / Filecount", + "confirm-delete": "Do you really want to delete this file?", + "filecount": "%1 files" +} \ No newline at end of file diff --git a/public/language/en-GB/admin/menu.json b/public/language/en-GB/admin/menu.json index 8f44bcd304..51099e9af4 100644 --- a/public/language/en-GB/admin/menu.json +++ b/public/language/en-GB/admin/menu.json @@ -17,6 +17,7 @@ "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", + "manage/uploads": "Uploads", "section-settings": "Settings", "settings/general": "General", diff --git a/public/src/admin/manage/uploads.js b/public/src/admin/manage/uploads.js new file mode 100644 index 0000000000..98da2ef557 --- /dev/null +++ b/public/src/admin/manage/uploads.js @@ -0,0 +1,35 @@ +'use strict'; + + +define('admin/manage/uploads', ['uploader'], function (uploader) { + var Uploads = {}; + + Uploads.init = function () { + $('#upload').on('click', function () { + uploader.show({ + title: '[[admin/manage/uploads:upload-file]]', + route: config.relative_path + '/api/admin/upload/file', + params: { folder: ajaxify.data.currentFolder }, + }, function () { + ajaxify.refresh(); + }); + }); + + $('.delete').on('click', function () { + var file = $(this).parents('[data-path]'); + bootbox.confirm('[[admin/manage/uploads:confirm-delete]]', function (ok) { + if (!ok) { + return; + } + socket.emit('admin.uploads.delete', file.attr('data-path'), function (err) { + if (err) { + return app.alertError(err.message); + } + file.remove(); + }); + }); + }); + }; + + return Uploads; +}); diff --git a/src/controllers/admin/uploads.js b/src/controllers/admin/uploads.js index dc5bd7ce37..db26284205 100644 --- a/src/controllers/admin/uploads.js +++ b/src/controllers/admin/uploads.js @@ -4,16 +4,109 @@ var path = require('path'); var async = require('async'); var nconf = require('nconf'); var mime = require('mime'); +var fs = require('fs'); var meta = require('../../meta'); var file = require('../../file'); var image = require('../../image'); var plugins = require('../../plugins'); +var pagination = require('../../pagination'); var allowedImageTypes = ['image/png', 'image/jpeg', 'image/pjpeg', 'image/jpg', 'image/gif', 'image/svg+xml']; var uploadsController = module.exports; +uploadsController.get = function (req, res, next) { + var currentFolder = path.join(nconf.get('upload_path'), req.query.dir || ''); + if (!currentFolder.startsWith(nconf.get('upload_path'))) { + return next(new Error('[[error:invalid-path]]')); + } + var itemsPerPage = 20; + var itemCount = 0; + var page = parseInt(req.query.page, 10) || 1; + async.waterfall([ + function (next) { + fs.readdir(currentFolder, next); + }, + function (files, next) { + files = files.filter(function (filename) { + return filename !== '.gitignore'; + }); + + itemCount = files.length; + var start = Math.max(0, (page - 1) * itemsPerPage); + var stop = start + itemsPerPage; + files = files.slice(start, stop); + + filesToData(currentFolder, files, next); + }, + function (files) { + files.sort(function (a, b) { + if (a.isDirectory && !b.isDirectory) { + return -1; + } else if (!a.isDirectory && b.isDirectory) { + return 1; + } + return 0; + }); + res.render('admin/manage/uploads', { + currentFolder: currentFolder.replace(nconf.get('upload_path'), ''), + files: files, + breadcrumbs: buildBreadcrumbs(currentFolder), + pagination: pagination.create(page, Math.ceil(itemCount / itemsPerPage), req.query), + }); + }, + ], next); +}; + +function buildBreadcrumbs(currentFolder) { + var crumbs = []; + var parts = currentFolder.replace(nconf.get('upload_path'), '').split(path.sep); + var currentPath = ''; + parts.forEach(function (part) { + var dir = path.join(currentPath, part); + crumbs.push({ + text: part || 'Uploads', + url: part ? '/admin/manage/uploads?dir=' + dir : '/admin/manage/uploads', + }); + currentPath = dir; + }); + + return crumbs; +} + +function filesToData(currentDir, files, callback) { + async.map(files, function (file, next) { + var stat; + async.waterfall([ + function (next) { + fs.stat(path.join(currentDir, file), next); + }, + function (_stat, next) { + stat = _stat; + if (stat.isDirectory()) { + fs.readdir(path.join(currentDir, file), next); + } else { + next(null, []); + } + }, + function (filesInDir, next) { + var url = nconf.get('upload_url') + currentDir.replace(nconf.get('upload_path'), '') + '/' + file; + next(null, { + name: file, + path: path.join(currentDir, file).replace(nconf.get('upload_path'), ''), + url: url, + fileCount: filesInDir.length - 1, // ignore .gitignore + size: stat.size, + sizeHumanReadable: (stat.size / 1024).toFixed(1) + 'KiB', + isDirectory: stat.isDirectory(), + isFile: stat.isFile(), + }); + }, + ], next); + }, callback); +} + uploadsController.uploadCategoryPicture = function (req, res, next) { var uploadedFile = req.files.files[0]; var params = null; @@ -110,6 +203,25 @@ uploadsController.uploadSound = function (req, res, next) { }); }; +uploadsController.uploadFile = function (req, res, next) { + var uploadedFile = req.files.files[0]; + var params; + try { + params = JSON.parse(req.body.params); + } catch (e) { + file.delete(uploadedFile.path); + return next(new Error('[[error:invalid-json]]')); + } + + file.saveFileToLocal(uploadedFile.name, params.folder, uploadedFile.path, function (err, data) { + file.delete(uploadedFile.path); + if (err) { + return next(err); + } + res.json([{ url: data.url }]); + }); +}; + uploadsController.uploadDefaultAvatar = function (req, res, next) { upload('avatar-default', req, res, next); }; @@ -173,3 +285,4 @@ function uploadImage(filename, folder, uploadedFile, req, res, next) { res.json([{ name: uploadedFile.name, url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url }]); }); } + diff --git a/src/file.js b/src/file.js index 8027f7ad77..e31ae18399 100644 --- a/src/file.js +++ b/src/file.js @@ -81,7 +81,7 @@ file.saveFileToLocal = function (filename, folder, tempPath, callback) { } callback(null, { - url: '/assets/uploads/' + folder + '/' + filename, + url: '/assets/uploads/' + (folder ? folder + '/' : '') + filename, path: uploadPath, }); }); diff --git a/src/pagination.js b/src/pagination.js index 8405fafd50..5789573b92 100644 --- a/src/pagination.js +++ b/src/pagination.js @@ -3,7 +3,7 @@ var qs = require('querystring'); var _ = require('lodash'); -var pagination = {}; +var pagination = module.exports; pagination.create = function (currentPage, pageCount, queryObj) { if (pageCount <= 1) { @@ -76,6 +76,3 @@ pagination.create = function (currentPage, pageCount, queryObj) { } return data; }; - - -module.exports = pagination; diff --git a/src/routes/admin.js b/src/routes/admin.js index db0ce7798c..98008cfeec 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -17,6 +17,7 @@ function apiRoutes(router, middleware, controllers) { router.post('/uploadlogo', middlewares, controllers.admin.uploads.uploadLogo); router.post('/uploadOgImage', middlewares, controllers.admin.uploads.uploadOgImage); router.post('/upload/sound', middlewares, controllers.admin.uploads.uploadSound); + router.post('/upload/file', middlewares, controllers.admin.uploads.uploadFile); router.post('/uploadDefaultAvatar', middlewares, controllers.admin.uploads.uploadDefaultAvatar); } @@ -77,6 +78,8 @@ function addRoutes(router, middleware, controllers) { router.get('/manage/groups', middlewares, controllers.admin.groups.list); router.get('/manage/groups/:name', middlewares, controllers.admin.groups.get); + router.get('/manage/uploads', middlewares, controllers.admin.uploads.get); + router.get('/settings/:term?', middlewares, controllers.admin.settings.get); router.get('/appearance/:term?', middlewares, controllers.admin.appearance.get); diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 628bbd97da..668dea0dbc 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -2,6 +2,9 @@ var async = require('async'); var winston = require('winston'); +var fs = require('fs'); +var path = require('path'); +var nconf = require('nconf'); var meta = require('../meta'); var plugins = require('../plugins'); @@ -37,6 +40,7 @@ var SocketAdmin = { analytics: {}, logs: {}, errors: {}, + uploads: {}, }; SocketAdmin.before = function (socket, method, data, next) { @@ -336,4 +340,13 @@ SocketAdmin.reloadAllSessions = function (socket, data, callback) { callback(); }; +SocketAdmin.uploads.delete = function (socket, pathToFile, callback) { + pathToFile = path.join(nconf.get('upload_path'), pathToFile); + if (!pathToFile.startsWith(nconf.get('upload_path'))) { + return callback(new Error('[[error:invalid-path]]')); + } + + fs.unlink(pathToFile, callback); +}; + module.exports = SocketAdmin; diff --git a/src/views/admin/manage/uploads.tpl b/src/views/admin/manage/uploads.tpl new file mode 100644 index 0000000000..0af5bd43c8 --- /dev/null +++ b/src/views/admin/manage/uploads.tpl @@ -0,0 +1,39 @@ + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
[[admin/manage/uploads:filename]][[admin/manage/uploads:size/filecount]]
+ {files.name} + + {files.name} + {files.sizeHumanReadable}[[admin/manage/uploads:filecount, {files.fileCount}]]
+
+ + \ No newline at end of file diff --git a/src/views/admin/partials/menu.tpl b/src/views/admin/partials/menu.tpl index 87d9bfeecb..24fe0becb4 100644 --- a/src/views/admin/partials/menu.tpl +++ b/src/views/admin/partials/menu.tpl @@ -23,6 +23,7 @@
  • [[admin/menu:manage/registration]]
  • [[admin/menu:manage/post-queue]]
  • [[admin/menu:manage/ip-blacklist]]
  • +
  • [[admin/menu:manage/uploads]]
  • @@ -198,6 +199,7 @@
  • [[admin/menu:manage/registration]]
  • [[admin/menu:manage/post-queue]]
  • [[admin/menu:manage/ip-blacklist]]
  • +
  • [[admin/menu:manage/uploads]]