mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-06 15:42:52 +01:00
Merge remote-tracking branch 'origin/master' into develop
This commit is contained in:
@@ -38,5 +38,11 @@
|
||||
"bookmarkThreshold": 5,
|
||||
"topicsPerList": 20,
|
||||
"autoDetectLang": 1,
|
||||
"min:rep:flag": 0
|
||||
"min:rep:flag": 0,
|
||||
"notificationType_upvote": "notification",
|
||||
"notificationType_new-topic": "notification",
|
||||
"notificationType_new-reply": "notification",
|
||||
"notificationType_follow": "notification",
|
||||
"notificationType_new-chat": "notification",
|
||||
"notificationType_group-invite": "notification"
|
||||
}
|
||||
|
||||
@@ -70,16 +70,5 @@
|
||||
"targetBlank": false,
|
||||
"adminOnly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"route": "/search",
|
||||
"title": "[[global:header.search]]",
|
||||
"enabled": true,
|
||||
"iconClass": "fa-search",
|
||||
"textClass": "visible-xs-inline",
|
||||
"text": "[[global:header.search]]",
|
||||
"properties": {
|
||||
"searchInstalled": true
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.7.4",
|
||||
"version": "1.7.5",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -25,6 +25,7 @@
|
||||
"body-parser": "^1.18.2",
|
||||
"bootstrap": "^3.3.7",
|
||||
"chart.js": "^2.7.1",
|
||||
"clipboard": "1.7.1",
|
||||
"colors": "^1.1.2",
|
||||
"compression": "^1.7.1",
|
||||
"commander": "^2.12.2",
|
||||
@@ -60,19 +61,19 @@
|
||||
"mousetrap": "^1.6.1",
|
||||
"mubsub": "^1.4.0",
|
||||
"nconf": "^0.9.1",
|
||||
"nodebb-plugin-composer-default": "6.0.12",
|
||||
"nodebb-plugin-composer-default": "6.0.13",
|
||||
"nodebb-plugin-dbsearch": "2.0.9",
|
||||
"nodebb-plugin-emoji": "^2.1.0",
|
||||
"nodebb-plugin-emoji-android": "2.0.0",
|
||||
"nodebb-plugin-markdown": "8.3.0",
|
||||
"nodebb-plugin-mentions": "2.2.3",
|
||||
"nodebb-plugin-soundpack-default": "1.0.0",
|
||||
"nodebb-plugin-spam-be-gone": "0.5.1",
|
||||
"nodebb-plugin-spam-be-gone": "0.5.2",
|
||||
"nodebb-rewards-essentials": "0.0.11",
|
||||
"nodebb-theme-lavender": "5.0.1",
|
||||
"nodebb-theme-persona": "7.2.20",
|
||||
"nodebb-theme-lavender": "5.0.3",
|
||||
"nodebb-theme-persona": "7.2.23",
|
||||
"nodebb-theme-slick": "1.1.4",
|
||||
"nodebb-theme-vanilla": "8.1.9",
|
||||
"nodebb-theme-vanilla": "8.1.10",
|
||||
"nodebb-widget-essentials": "4.0.2",
|
||||
"nodemailer": "4.4.1",
|
||||
"passport": "^0.4.0",
|
||||
|
||||
@@ -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": "Uživatelský CSS/LESS",
|
||||
"custom-css.description": "Zadejte vlastní definici CSS/LESS, která bude nadřazená ostatním stylům.",
|
||||
"custom-css.enable": "Povolit uživatelský CSS/LESS",
|
||||
|
||||
"custom-js": "Uživatelský Javascript",
|
||||
"custom-js.description": "Zadejte zde váš javascriptový kód. Bude spuštěn, jakmile se stránka plně načte.",
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"home-page-route": "Cesta k domovské stránce",
|
||||
"custom-route": "Upravit cestu",
|
||||
"allow-user-home-pages": "Povolit uživatelům domovské stránky",
|
||||
"home-page-title": "Title of the home page (default \"Home\")"
|
||||
"home-page-title": "Titulka domovské stránky (výchozí „Domů”)"
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"description": "Vyberte značky pomocí kliknutí a/nebo přetažením, pro vícenásobný výběr, použijte klávesu Shift.",
|
||||
"create": "Vytvořit značku",
|
||||
"modify": "Upravit značky",
|
||||
"rename": "Rename Tags",
|
||||
"rename": "Přejmenovat značky",
|
||||
"delete": "Odstranit vybrané značky",
|
||||
"search": "Hledat značky...",
|
||||
"settings": "Pro přejití na stránku s nastavením značek, klikněte <a href=\"%1\">zde</a>.",
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
"remove-admin": "Odebrat správce",
|
||||
"validate-email": "Ověřit e-mail",
|
||||
"send-validation-email": "Poslat ověřovací e-mail",
|
||||
"password-reset-email": "Poslat e-mail pro resetování hesla",
|
||||
"password-reset-email": "Poslat e-mail pro resetování hesla",
|
||||
"ban": "Zakázat uživatele",
|
||||
"temp-ban": "Dočasně zakázat uživatele",
|
||||
"unban": "Zrušit zákaz uživatele",
|
||||
"reset-lockout": "Obnovit uzamčení",
|
||||
"reset-flags": "Obnovit označení",
|
||||
"delete": "Odstranit uživatele",
|
||||
"purge": "Odstranit uživatele a obsah",
|
||||
"purge": "Odstranit uživatele a obsah",
|
||||
"download-csv": "Stáhnout jako CSV",
|
||||
"invite": "Pozvat",
|
||||
"new": "Nový uživatel",
|
||||
@@ -27,19 +27,19 @@
|
||||
"pills.banned": "Zakázán",
|
||||
"pills.search": "Hledat uživatele",
|
||||
|
||||
"search.uid": "By User ID",
|
||||
"search.uid-placeholder": "Enter a user ID to search",
|
||||
"search.uid": "Dle ID uživatele",
|
||||
"search.uid-placeholder": "Pro hledání, zadejte ID uživatele",
|
||||
"search.username": "Dle jména uživatele",
|
||||
"search.username-placeholder": "Zadejte hledané uživatelské jméno",
|
||||
"search.email": "Podle e-mailu",
|
||||
"search.email-placeholder": "Zadejte hledaný e-mail",
|
||||
"search.ip": "Podle IP adresy",
|
||||
"search.ip-placeholder": "Zadejte hledanou IP adresu",
|
||||
"search.ip": "Podle IP adresy",
|
||||
"search.ip-placeholder": "Zadejte hledanou IP adresu",
|
||||
"search.not-found": "Uživatel nebyl nalezen.",
|
||||
|
||||
"inactive.3-months": "3 měsíce",
|
||||
"inactive.6-months": "6 měsíců",
|
||||
"inactive.12-months": "12 měsíců",
|
||||
"inactive.3-months": "3 měsíce",
|
||||
"inactive.6-months": "6 měsíců",
|
||||
"inactive.12-months": "12 měsíců",
|
||||
|
||||
"users.uid": "uid",
|
||||
"users.username": "jméno",
|
||||
@@ -71,15 +71,15 @@
|
||||
"alerts.lockout-reset-success": "Uzamčení bylo obnoveno.",
|
||||
"alerts.flag-reset-success": "Označení bylo obnoveno.",
|
||||
"alerts.no-remove-yourself-admin": "Sebe jako správce nemůžete vyjmout.",
|
||||
"alerts.make-admin-success": "User is now administrator.",
|
||||
"alerts.confirm-remove-admin": "Do you really want to remove this administrator?",
|
||||
"alerts.remove-admin-success": "User is no longer administrator.",
|
||||
"alerts.make-global-mod-success": "User is now global moderator.",
|
||||
"alerts.confirm-remove-global-mod": "Do you really want to remove this global moderator?",
|
||||
"alerts.remove-global-mod-success": "User is no longer global moderator.",
|
||||
"alerts.make-moderator-success": "User is now moderator.",
|
||||
"alerts.confirm-remove-moderator": "Do you really want to remove this moderator?",
|
||||
"alerts.remove-moderator-success": "User is no longer moderator.",
|
||||
"alerts.make-admin-success": "Uživatel je nyní správcem",
|
||||
"alerts.confirm-remove-admin": "Opravdu chcete vyjmout tohoto správce?",
|
||||
"alerts.remove-admin-success": "Uživatel již není správcem.",
|
||||
"alerts.make-global-mod-success": "Uživatel je nyní globálním moderátorem.",
|
||||
"alerts.confirm-remove-global-mod": "Opravdu chcete vyjmout tohoto globálního moderátora?",
|
||||
"alerts.remove-global-mod-success": "Uživatel již není globálním moderátorem.",
|
||||
"alerts.make-moderator-success": "Uživatel je nyní moderátorem.",
|
||||
"alerts.confirm-remove-moderator": "Opravdu chcete vyjmout tohoto moderátora?",
|
||||
"alerts.remove-moderator-success": "Uživatel není již moderátorem.",
|
||||
"alerts.confirm-validate-email": "Chcete schválit e-mailové adresy těchto uživatelů?",
|
||||
"alerts.validate-email-success": "E-maily byly ověřeny",
|
||||
"alerts.password-reset-confirm": "Chcete poslat těmto uživatelům e-mail pro resetování hesla?",
|
||||
@@ -95,5 +95,5 @@
|
||||
|
||||
"alerts.prompt-email": "E-mail:",
|
||||
"alerts.email-sent-to": "E-mail s pozvánkou byl odeslán na %1",
|
||||
"alerts.x-users-found": "Počet nalezených uživatelů: %1 (hledání trvalo %2 ms)"
|
||||
"alerts.x-users-found": "Počet nalezených uživatelů: %1 (hledání trvalo %2 ms)"
|
||||
}
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
"section-manage": "Spravovat",
|
||||
"manage/categories": "Kategorie",
|
||||
"manage/privileges": "Privileges",
|
||||
"manage/privileges": "Oprávnění",
|
||||
"manage/tags": "Značky",
|
||||
"manage/users": "Uživatelé",
|
||||
"manage/admins-mods": "Admins & Mods",
|
||||
"manage/admins-mods": "Správci a moderátoři",
|
||||
"manage/registration": "Registrační fronta",
|
||||
"manage/post-queue": "Fronta příspěvků",
|
||||
"manage/groups": "Skupiny",
|
||||
@@ -70,8 +70,8 @@
|
||||
"search.placeholder": "Hledat nastavení",
|
||||
"search.no-results": "Žádné výsledky…",
|
||||
"search.search-forum": "Prohledat fórum pro <strong></strong>",
|
||||
"search.keep-typing": "Pište dále pro zobrazení výsledků…",
|
||||
"search.start-typing": "Začněte psát pro zobrazení výsledků…",
|
||||
"search.keep-typing": "Pište dále pro zobrazení výsledků…",
|
||||
"search.start-typing": "Začněte psát pro zobrazení výsledků…",
|
||||
|
||||
"connection-lost": "Připojení k %1 bylo ztraceno, snaha o opětovné připojení…"
|
||||
"connection-lost": "Připojení k %1 bylo ztraceno, snaha o opětovné připojení…"
|
||||
}
|
||||
@@ -6,6 +6,6 @@
|
||||
"max-length": "Maximální délka konverzační zprávy",
|
||||
"max-room-size": "Maximální počet uživatelů v konverzační místnosti",
|
||||
"delay": "Čas mezi konverzačními zprávami v milisekundách",
|
||||
"restrictions.seconds-edit-after": "Number of seconds before users are allowed to edit chat messages after posting. (0 disabled)",
|
||||
"restrictions.seconds-delete-after": "Number of seconds before users are allowed to delete chat messages after posting. (0 disabled)"
|
||||
"restrictions.seconds-edit-after": "Počet sekund než je uživateli umožněno upravit zprávy konverzace po jejich odeslání. (0 zákaz)",
|
||||
"restrictions.seconds-delete-after": "Počet sekund než je uživateli umožněno smazat zprávy konverzace po jejich odeslání. (0 zákaz)"
|
||||
}
|
||||
@@ -6,25 +6,25 @@
|
||||
"sorting.most-votes": "Dle počtu hlasů",
|
||||
"sorting.most-posts": "Dle počtu příspěvků",
|
||||
"sorting.topic-default": "Výchozí třídění tématu",
|
||||
"length": "Post Length",
|
||||
"length": "Délka příspěvku",
|
||||
"restrictions": "Omezení příspěvků",
|
||||
"restrictions-new": "New User Restrictions",
|
||||
"restrictions-new": "Omezení nového uživatele",
|
||||
"restrictions.post-queue": "Povolit frontu pro příspěvky",
|
||||
"restrictions-new.post-queue": "Enable new user restrictions",
|
||||
"restrictions-new.post-queue": "Povolit omezení nových uživatelů",
|
||||
"restrictions.post-queue-help": "Povolení fronty příspěvků bude přidávat příspěvky nových uživatelů do fronty na schválení.",
|
||||
"restrictions-new.post-queue-help": "Enabling new user restrictions will set restrictions on posts created by new users.",
|
||||
"restrictions.seconds-between": "Seconds between posts",
|
||||
"restrictions.seconds-between-new": "Seconds between posts for new users",
|
||||
"restrictions.rep-threshold": "Reputation threshold before these restrictions are lifted",
|
||||
"restrictions-new.post-queue-help": "Povolení omezení nových uživatelů uvede v činnost omezení na vytvořené příspěvky nových uživatelů.",
|
||||
"restrictions.seconds-between": "Sekund mezi příspěvky",
|
||||
"restrictions.seconds-between-new": "Sekund mezi příspěvky pro nové uživatele",
|
||||
"restrictions.rep-threshold": "Ohraničení reputace než začnou platit tato omezení",
|
||||
"restrictions.seconds-defore-new": "Sekundy předtím, než uživatel může přidat příspěvek",
|
||||
"restrictions.seconds-edit-after": "Number of seconds before users are allowed to edit posts after posting. (0 disabled)",
|
||||
"restrictions.seconds-delete-after": "Number of seconds before users are allowed to delete posts after posting. (0 disabled)",
|
||||
"restrictions.seconds-edit-after": "Počet sekund než bude moci uživatel upravit příspěvek před jeho odesláním. (0 zákaz)",
|
||||
"restrictions.seconds-delete-after": "Počet sekund než bude moci uživatel smazat příspěvek před jeho odesláním. (0 zákaz)",
|
||||
"restrictions.replies-no-delete": "Počet odpovědí, kdy je uživatelům zakázáno odstranit jejich vlastní příspěvek. (0 zakázáno)",
|
||||
"restrictions.min-title-length": "Minimální délka názvu",
|
||||
"restrictions.max-title-length": "Maximální délka názvu",
|
||||
"restrictions.min-post-length": "Minimální délka příspěvku",
|
||||
"restrictions.max-post-length": "Maximální délka příspěvku",
|
||||
"restrictions.days-until-stale": "Days until topic is considered stale",
|
||||
"restrictions.days-until-stale": "Počet dnů, než je téma považováno za neaktuální",
|
||||
"restrictions.stale-help": "Je-li téma považováno za „staré”, uživateli se zobrazí oznámení při pokusu o přidání odpovědi.",
|
||||
"timestamp": "Časový otisk",
|
||||
"timestamp.cut-off": "Datum ukončení (ve dnech)",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"thresholds": "Omezení aktivity",
|
||||
"min-rep-downvote": "Minimální reputace pro vyjádření nesouhlasu s příspěvkem",
|
||||
"min-rep-flag": "Minimální reputace pro označení příspěvků",
|
||||
"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": "Minimální reputace pro přidání „Webové stránky” do uživatelského profilu",
|
||||
"min-rep-aboutme": "Minimální reputace pro přidání „O mně” do uživatelského profilu",
|
||||
"min-rep-signature": "Minimální reputace pro přidání „Podpisu” do uživatelského profilu"
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
"invalid-login-credentials": "Neplatné přihlašovací údaje",
|
||||
"invalid-username-or-password": "Zadejte prosím uživatelské jméno a i heslo",
|
||||
"invalid-search-term": "Neplatný výraz pro vyhledávání",
|
||||
"invalid-url": "Invalid URL",
|
||||
"invalid-url": "Neplatné URL",
|
||||
"csrf-invalid": "Není možné vás přihlásit, díky vypršení relace. Zkuste to prosím znovu.",
|
||||
"invalid-pagination-value": "Neplatná hodnota stránkování, musí být alespoň %1 a nejvýše %2",
|
||||
"username-taken": "Uživatelské jméno je již použito",
|
||||
@@ -114,16 +114,16 @@
|
||||
"cant-edit-chat-message": "Tuto zprávu nemůžete upravit",
|
||||
"cant-remove-last-user": "Posledního uživatele nemůžete vyjmout",
|
||||
"cant-delete-chat-message": "Tuto zprávu nemůžete odstranit",
|
||||
"chat-edit-duration-expired": "You are only allowed to edit chat messages for %1 second(s) after posting",
|
||||
"chat-delete-duration-expired": "You are only allowed to delete chat messages for %1 second(s) after posting",
|
||||
"chat-edit-duration-expired": "Je vám umožněno upravit konverzační zprávy pod dobu %1 sekund/y po jejich odeslání",
|
||||
"chat-delete-duration-expired": "Je vám umožněno odstranit konverzační zprávy pod dobu %1 sekund/y po jejich odeslání",
|
||||
"already-voting-for-this-post": "Již jste v tomto příspěvku hlasoval.",
|
||||
"reputation-system-disabled": "Systém reputací je zakázán.",
|
||||
"downvoting-disabled": "Systém nesouhlasu je zakázán",
|
||||
"not-enough-reputation-to-downvote": "Nemáte dostatečnou reputaci pro vyjádření nesouhlasu u tohoto příspěvku",
|
||||
"not-enough-reputation-to-flag": "Pro označení tohoto příspěvku nemáte dostatečnou reputaci",
|
||||
"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": "Pro přidání webové stránky nemáte dostatek reputace",
|
||||
"not-enough-reputation-min-rep-aboutme": "Pro přidání „O mně” nemáte dostatek reputace",
|
||||
"not-enough-reputation-min-rep-signature": "Pro přidání podpisu nemáte dostatek reputace",
|
||||
"already-flagged": "Tento příspěvek jste již označil",
|
||||
"self-vote": "U svého vlastního příspěvku nemůžete hlasovat",
|
||||
"reload-failed": "Vyskytla se chyba v NodeBB při znovu načtení: \"%1\". NodeBB bude pokračovat v běhu na straně klienta, nicméně byste měl/a přenastavit zpět to, co jste udělal/a před opětovným načtením.",
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"topics": "Témata",
|
||||
"posts": "Příspěvky",
|
||||
"best": "Nejlepší",
|
||||
"votes": "Votes",
|
||||
"votes": "Počet hlasů",
|
||||
"upvoters": "Souhlasník",
|
||||
"upvoted": "Souhlasů",
|
||||
"downvoters": "Nesouhlasník",
|
||||
@@ -85,7 +85,7 @@
|
||||
"language": "Jazyk",
|
||||
"guest": "Host",
|
||||
"guests": "Hosté",
|
||||
"updated.title": "Fórum zaktualizováno",
|
||||
"updated.title": "Fórum bylo zaktualizováno",
|
||||
"updated.message": "Toto fórum bylo právě aktualizováno na poslední verzi. Klikněte zde a obnovte tuto stránku.",
|
||||
"privacy": "Soukromí",
|
||||
"follow": "Sledovat",
|
||||
@@ -101,7 +101,7 @@
|
||||
"unsaved-changes": "Některé změny nebyly uloženy. Jste si jist, že chcete jít jinam?",
|
||||
"reconnecting-message": "Vypadá to, že vaše připojení k %1 bylo ukončeno. Vyčkejte prosím, než obnovíme připojení.",
|
||||
"play": "Přehrát",
|
||||
"cookies.message": "Tato webová stránka používá \"cookies\", aby jste mohl plně zažít její funkčnost.",
|
||||
"cookies.message": "Pro využití plné funkčnosti stránek, jsou použity „cookies”.",
|
||||
"cookies.accept": "Rozumím.",
|
||||
"cookies.learn_more": "Zjistit více",
|
||||
"edited": "Upraveno",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"popular-month": "Oblíbená témata pro tento měsíc",
|
||||
"popular-alltime": "Oblíbená témata za celou dobu",
|
||||
"recent": "Aktuální témata",
|
||||
"top": "Top Voted Topics",
|
||||
"top": "Témata s nejvíce hlasy",
|
||||
"moderator-tools": "Nástroje moderátora",
|
||||
"flagged-content": "Nahlášený obsah",
|
||||
"ip-blacklist": "Černá listina IP adres",
|
||||
@@ -20,7 +20,7 @@
|
||||
"users/search": "Hledat uživatele",
|
||||
"notifications": "Upozornění",
|
||||
"tags": "Značky",
|
||||
"tag": "Topics tagged under "%1"",
|
||||
"tag": "Témata označená "%1"",
|
||||
"register": "Zaregistrovat účet",
|
||||
"registration-complete": "Registrace dokončena",
|
||||
"login": "Přihlásit se ke svému účtu",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"flag_title": "Označit tento příspěvek k moderování",
|
||||
"deleted_message": "Toto téma bylo odstraněno. Jen uživatelé s oprávněním správy témat ho mohou vidět.",
|
||||
"following_topic.message": "Nyní budete dostávat upozornění, jakmile někdo přidá příspěvek do tohoto tématu.",
|
||||
"not_following_topic.message": "Uvidíte toto téma v seznamu nepřečtených témat, ale neobdržíte upozornění. pokud sem někdo přidá příspěvek.",
|
||||
"not_following_topic.message": " Toto téma uvidíte v seznamu nepřečtených témat, ale neobdržíte upozornění, přidá-li někdo nový příspěvek.",
|
||||
"ignoring_topic.message": "Již nadále neuvidíte toto téma v seznamu nepřečtených témat. Budete upozorněn, jakmile se někdo o vás zmíní nebo bude vyjádřen souhlas s příspěvkem.",
|
||||
"login_to_subscribe": "Pro sledování tohoto tématu se prosím přihlaste nebo zaregistrujte.",
|
||||
"markAsUnreadForAll.success": "Téma označeno jako nepřečtené pro všechny.",
|
||||
@@ -52,7 +52,7 @@
|
||||
"not-watching.description": "Neupozorňovat na nové odpovědi. <br/>Zobrazit téma v nepřečtených, není-li tato kategorie ignorována",
|
||||
"ignoring.description": "Neupozorňovat na nové odpovědi.<br/>Nezobrazovat téma v nepřečtených.",
|
||||
"thread_tools.title": "Nástroje tématu",
|
||||
"thread_tools.markAsUnreadForAll": "Mark Unread For All",
|
||||
"thread_tools.markAsUnreadForAll": "Označit nepřečtené pro všechny",
|
||||
"thread_tools.pin": "Připnout téma",
|
||||
"thread_tools.unpin": "Odepnout téma",
|
||||
"thread_tools.lock": "Zamknout téma",
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
"only-guest": "Only display to guests",
|
||||
"open-new-window": "Open in a new window",
|
||||
|
||||
"installed-plugins-required": "Installed Plugins Required:",
|
||||
"search-plugin": "Search plugin",
|
||||
|
||||
"btn.delete": "Delete",
|
||||
"btn.disable": "Disable",
|
||||
"btn.enable": "Enable",
|
||||
|
||||
@@ -65,5 +65,7 @@
|
||||
"alert.find-user": "Find a User",
|
||||
"alert.user-search": "Search for a user here...",
|
||||
"alert.find-group": "Find a Group",
|
||||
"alert.group-search": "Search for a group here..."
|
||||
"alert.group-search": "Search for a group here...",
|
||||
"collapse-all": "Collapse All",
|
||||
"expand-all": "Expand All"
|
||||
}
|
||||
@@ -14,5 +14,6 @@
|
||||
"alerts.applied-success": "Blacklist Applied",
|
||||
|
||||
"analytics.blacklist-hourly": "<strong>Figure 1</strong> – Blacklist hits per hour",
|
||||
"analytics.blacklist-daily": "<strong>Figure 2</strong> – Blacklist hits per day"
|
||||
"analytics.blacklist-daily": "<strong>Figure 2</strong> – Blacklist hits per day",
|
||||
"ip-banned": "IP banned"
|
||||
}
|
||||
@@ -62,5 +62,6 @@
|
||||
"email-chat-notifs": "Send an email if a new chat message arrives and I am not online",
|
||||
"email-post-notif": "Send an email when replies are made to topics I am subscribed to",
|
||||
"follow-created-topics": "Follow topics you create",
|
||||
"follow-replied-topics": "Follow topics that you reply to"
|
||||
"follow-replied-topics": "Follow topics that you reply to",
|
||||
"default-notification-settings": "Default notification settings"
|
||||
}
|
||||
@@ -161,6 +161,7 @@
|
||||
"wrong-login-type-email": "Please use your email to login",
|
||||
"wrong-login-type-username": "Please use your username to login",
|
||||
"sso-registration-disabled": "Registration has been disabled for %1 accounts, please register with an email address first",
|
||||
"sso-multiple-association": "You cannot associate multiple accounts from this service to your NodeBB account. Please dissociate your existing account and try again.",
|
||||
|
||||
"invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).",
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
"locked": "Locked",
|
||||
"pinned": "Pinned",
|
||||
"moved": "Moved",
|
||||
"copy-ip": "Copy IP",
|
||||
"ban-ip": "Ban IP",
|
||||
|
||||
"bookmark_instructions" : "Click here to return to the last read post in this thread.",
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
"topics_per_page": "Topics per Page",
|
||||
"posts_per_page": "Posts per Page",
|
||||
"max_items_per_page": "Maximum %1",
|
||||
|
||||
"acp_language": "Admin Page Language",
|
||||
"notification_sounds" : "Play a sound when you receive a notification",
|
||||
"notifications_and_sounds": "Notifications & Sounds",
|
||||
"incoming-message-sound": "Incoming message sound",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"figure-x": "Figure %1",
|
||||
"error-events-per-day": "<code>%1</code> events per day",
|
||||
"error.404": "404 Not Found",
|
||||
"error.503": "503 Service Unavailable",
|
||||
"manage-error-log": "Manage Error Log",
|
||||
"error.404": "ارور 404 یافت نشد",
|
||||
"error.503": "ارور 503 سرویس دردسترس نیست",
|
||||
"manage-error-log": "مدیریت Error Log",
|
||||
"export-error-log": "Export Error Log (CSV)",
|
||||
"clear-error-log": "Clear Error Log",
|
||||
"route": "Route",
|
||||
"count": "Count",
|
||||
"no-routes-not-found": "Hooray! No 404 errors!",
|
||||
"clear404-confirm": "Are you sure you wish to clear the 404 error logs?",
|
||||
"clear404-success": "\"404 Not Found\" errors cleared"
|
||||
"clear-error-log": "پاک کردن Error Log",
|
||||
"route": "مسیر",
|
||||
"count": "شمارش",
|
||||
"no-routes-not-found": "ایول! بدون ارور 404 !",
|
||||
"clear404-confirm": "آیا از پاک کردن ارور های 404 اطمینان دارید؟",
|
||||
"clear404-success": "ارور های 404 پاک شدند"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"events": "Events",
|
||||
"no-events": "There are no events",
|
||||
"control-panel": "Events Control Panel",
|
||||
"delete-events": "Delete Events"
|
||||
"events": "رویداد ها",
|
||||
"no-events": "رویدادی موجود نیست",
|
||||
"control-panel": "کنترل پنل رویداد ها",
|
||||
"delete-events": "پاک کردن رویداد ها"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"logs": "Logs",
|
||||
"control-panel": "Logs Control Panel",
|
||||
"reload": "Reload Logs",
|
||||
"clear": "Clear Logs",
|
||||
"clear-success": "Logs Cleared!"
|
||||
"logs": "گزارشات",
|
||||
"control-panel": "کنترل پنل گزارشات",
|
||||
"reload": "بارگزاری مجدد گزارش ها",
|
||||
"clear": "حذف گزارشات",
|
||||
"clear-success": "گزارش ها پاک شدند"
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"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",
|
||||
"custom-css.description": "کد های CSS/LESS خود را در این قسمت وارد کنید . بعد از همه ی استایل های دیگر اعمال میشود",
|
||||
"custom-css.enable": "به کار گرفتن CSS/LESS سفارشی",
|
||||
|
||||
"custom-js": "Custom Javascript",
|
||||
"custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.",
|
||||
"custom-js.enable": "Enable Custom Javascript",
|
||||
"custom-js": "جائا اسکریپت سفارشی",
|
||||
"custom-js.description": "کد های جاوا اسکریپت خود را در این قسمت وارد کنید بعد از لود شدن تمام صفحه اجرا خواهند شد",
|
||||
"custom-js.enable": "به کارگیری جاوا اسکریپت سفارشی ",
|
||||
|
||||
"custom-header": "Custom Header",
|
||||
"custom-header": "هدر سفارشی",
|
||||
"custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <code><head></code> section of your forum's markup. Script tags are allowed, but are discouraged, as the <a href=\"#custom-header\" data-toggle=\"tab\">Custom Javascript</a> tab is available.",
|
||||
"custom-header.enable": "Enable Custom Header",
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"email_only": "فقط ایمیل",
|
||||
"notification_and_email": "اعلان و ایمیل",
|
||||
"notificationType_upvote": "هنگامی که شخصی به پست شما رای مثبت می دهد",
|
||||
"notificationType_new-topic": "هنگامی که شخصی که شما فالو می کنید موضوعی ایجاد نماید",
|
||||
"notificationType_new-topic": "هنگامی که شخصی که شما دنبال می کنید موضوعی ایجاد نماید",
|
||||
"notificationType_new-reply": "هنگامی که پاسخ جدید در تاپیکی که شما پیگیری می کنید فرستاده می شود",
|
||||
"notificationType_follow": "هنگامی که کسی شما را دنبال می کند",
|
||||
"notificationType_new-chat": "هنگامی که شما پیام چتی دریافت می کنید",
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"topics": "Темы",
|
||||
"posts": "Записи",
|
||||
"best": "Лучшие",
|
||||
"votes": "Votes",
|
||||
"votes": "Голоса",
|
||||
"upvoters": "Кому понравилось",
|
||||
"upvoted": "Понравилось",
|
||||
"downvoters": "Кому не понравилось",
|
||||
@@ -105,6 +105,6 @@
|
||||
"cookies.accept": "Понял",
|
||||
"cookies.learn_more": "Подробнее",
|
||||
"edited": "Отредактированный",
|
||||
"disabled": "Disabled",
|
||||
"select": "Select"
|
||||
"disabled": "Отключено",
|
||||
"select": "Выбрать"
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
"chat.three_months": "3 месяца",
|
||||
"chat.delete_message_confirm": "Вы уверены, что хотите удалить это сообщение?",
|
||||
"chat.add-users-to-room": "Добавить участников в комнату",
|
||||
"chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?",
|
||||
"chat.confirm-chat-with-dnd-user": "Этот пользователь установил статус \"Не беспокоить\". Вы все еще хотите написать ему?",
|
||||
"composer.compose": "Редактор сообщений",
|
||||
"composer.show_preview": "Показать предпросмотр сообщения",
|
||||
"composer.hide_preview": "Скрыть предпросмотр",
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"popular-month": "Популярные темы этого месяца",
|
||||
"popular-alltime": "Популярные темы за всё время",
|
||||
"recent": "Последние темы",
|
||||
"top": "Top Voted Topics",
|
||||
"moderator-tools": "Moderator Tools",
|
||||
"flagged-content": "Flagged Content",
|
||||
"top": "Самые популярные темы",
|
||||
"moderator-tools": "Инструменты модератора",
|
||||
"flagged-content": "Выбранное содержимое",
|
||||
"ip-blacklist": "Чёрный список IP",
|
||||
"post-queue": "Post Queue",
|
||||
"post-queue": "Очередь публикации",
|
||||
"users/online": "В сети",
|
||||
"users/latest": "Новые участники",
|
||||
"users/sort-posts": "Участники по количеству сообщений",
|
||||
@@ -20,7 +20,7 @@
|
||||
"users/search": "Поиск участников",
|
||||
"notifications": "Уведомления",
|
||||
"tags": "Метки",
|
||||
"tag": "Topics tagged under "%1"",
|
||||
"tag": "Темы помеченные как "%1"",
|
||||
"register": "Зарегистрироваться",
|
||||
"registration-complete": "Регистрация завершена",
|
||||
"login": "Войти",
|
||||
@@ -30,8 +30,8 @@
|
||||
"group": "Группа %1",
|
||||
"chats": "Чаты",
|
||||
"chat": "Чат с участником %1",
|
||||
"flags": "Flags",
|
||||
"flag-details": "Flag %1 Details",
|
||||
"flags": "Отметки",
|
||||
"flag-details": "Отметка %1 детали",
|
||||
"account/edit": "Редактирование \"%1\"",
|
||||
"account/edit/password": "Сменить пароль \"%1\"",
|
||||
"account/edit/username": "Изменить имя пользователя \"%1\"",
|
||||
@@ -45,7 +45,7 @@
|
||||
"account/bookmarks": "%1 сообщений в закладках",
|
||||
"account/settings": "Настройки учётной записи",
|
||||
"account/watched": "Тему просмотрели %1",
|
||||
"account/ignored": "Topics ignored by %1",
|
||||
"account/ignored": "Игнорируемые темы %1",
|
||||
"account/upvoted": "Рейтинг записей поднят %1",
|
||||
"account/downvoted": "Рейтинг записей снижен %1",
|
||||
"account/best": "Лучшие записи участника %1",
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"not-watching.description": "Не уведомлять меня о новых ответах.<br/>Показать тему в непрочитанных, если категория мной не игнорируется.",
|
||||
"ignoring.description": "Не уведомлять меня о новых ответах.<br/>Не отображать тему в непрочитанных.",
|
||||
"thread_tools.title": "Настройки темы",
|
||||
"thread_tools.markAsUnreadForAll": "Mark Unread For All",
|
||||
"thread_tools.markAsUnreadForAll": "Выделить непрочитанные для всех",
|
||||
"thread_tools.pin": "Прикрепить тему",
|
||||
"thread_tools.unpin": "Открепить тему",
|
||||
"thread_tools.lock": "Закрыть тему",
|
||||
@@ -68,8 +68,8 @@
|
||||
"thread_tools.restore_confirm": "Вы уверены, что хотите восстановить тему?",
|
||||
"thread_tools.purge": "Стереть тему",
|
||||
"thread_tools.purge_confirm": "Вы уверены, что хотите стереть эту тему?",
|
||||
"thread_tools.merge_topics": "Merge Topics",
|
||||
"thread_tools.merge": "Merge",
|
||||
"thread_tools.merge_topics": "Объединить темы",
|
||||
"thread_tools.merge": "Объединить",
|
||||
"topic_move_success": "Эта тема успешно перемещена в %1",
|
||||
"post_delete_confirm": "Вы уверены, что хотите удалить эту запись?",
|
||||
"post_restore_confirm": "Вы уверены, что хотите восстановить эту запись?",
|
||||
@@ -91,7 +91,7 @@
|
||||
"fork_pid_count": "Отмечено %1 сообщений",
|
||||
"fork_success": "Готово! Просмотр отделённой темы.",
|
||||
"delete_posts_instruction": "Отметьте записи, которые вы хотите удалить",
|
||||
"merge_topics_instruction": "Click the topics you want to merge",
|
||||
"merge_topics_instruction": "Выберите темы которые вы хотите объединить",
|
||||
"composer.title_placeholder": "Введите название темы...",
|
||||
"composer.handle_placeholder": "Название",
|
||||
"composer.discard": "Отменить",
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
"all-topics": "Все темы",
|
||||
"new-topics": "Новые темы",
|
||||
"watched-topics": "Подписанные темы",
|
||||
"unreplied-topics": "Unreplied Topics",
|
||||
"multiple-categories-selected": "Multiple Selected"
|
||||
"unreplied-topics": "Неотвеченные темы",
|
||||
"multiple-categories-selected": "Выбрано несколько"
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
"reputation": "Репутация",
|
||||
"bookmarks": "Закладки",
|
||||
"watched": "Подписка",
|
||||
"ignored": "Ignored",
|
||||
"ignored": "Игнорировать",
|
||||
"followers": "Подписчиков",
|
||||
"following": "Подписок",
|
||||
"aboutme": "Обо мне",
|
||||
@@ -34,7 +34,7 @@
|
||||
"chat": "Чат",
|
||||
"chat_with": "Продолжить чат с %1",
|
||||
"new_chat_with": "Начать новый чат с %1",
|
||||
"flag-profile": "Flag Profile",
|
||||
"flag-profile": "Идентификатор профиля",
|
||||
"follow": "Подписаться",
|
||||
"unfollow": "Отписаться",
|
||||
"more": "Больше",
|
||||
@@ -85,7 +85,7 @@
|
||||
"has_no_posts": "Участник пока не создал ни одной записи",
|
||||
"has_no_topics": "Участник пока не создал ни одной темы",
|
||||
"has_no_watched_topics": "Участник пока не посмотрел ни одной темы",
|
||||
"has_no_ignored_topics": "This user hasn't ignored any topics yet.",
|
||||
"has_no_ignored_topics": "Этот пользователь еще не игнорировал ни одной темы.",
|
||||
"has_no_upvoted_posts": "Участник пока не голосовал положительно ни за одну запись",
|
||||
"has_no_downvoted_posts": "Участник пока не голосовал против ни одной записи",
|
||||
"has_no_voted_posts": "Участник пока не голосовал ни за одну запись",
|
||||
@@ -94,18 +94,18 @@
|
||||
"paginate_description": "Разбить на страницы, а не выводить бесконечным списком",
|
||||
"topics_per_page": "Тем на странице",
|
||||
"posts_per_page": "Записей на странице",
|
||||
"max_items_per_page": "Maximum %1",
|
||||
"max_items_per_page": "Максимум %1",
|
||||
"notification_sounds": "Воспроизводить звук во время получения уведомления",
|
||||
"notifications_and_sounds": "Уведомления и звуки",
|
||||
"incoming-message-sound": "Звук входящего сообщения",
|
||||
"outgoing-message-sound": "Звук исходящего сообщения",
|
||||
"notification-sound": "Звук уведомления",
|
||||
"no-sound": "Без звука",
|
||||
"upvote-notif-freq": "Upvote Notification Frequency",
|
||||
"upvote-notif-freq.all": "All Upvotes",
|
||||
"upvote-notif-freq.everyTen": "Every Ten Upvotes",
|
||||
"upvote-notif-freq.logarithmic": "On 10, 100, 1000...",
|
||||
"upvote-notif-freq.disabled": "Disabled",
|
||||
"upvote-notif-freq": "Частота уведомлений о понравившемся отзыве",
|
||||
"upvote-notif-freq.all": "Все положительные отзывы",
|
||||
"upvote-notif-freq.everyTen": "Каждые десять понравившихся отзывов",
|
||||
"upvote-notif-freq.logarithmic": "На 10, 100, 1000...",
|
||||
"upvote-notif-freq.disabled": "Выключено",
|
||||
"browsing": "Настройки просмотра",
|
||||
"open_links_in_new_tab": "Открывать внешние ссылки в новом окне",
|
||||
"enable_topic_searching": "Поиск во всех записях темы",
|
||||
@@ -126,9 +126,9 @@
|
||||
"sso.title": "Для вашего удобства вы можете связать ваши учётные записи на других социальных сервисах с учётной записью на нашем сайте",
|
||||
"sso.associated": "Связан с",
|
||||
"sso.not-associated": "Нажмите здесь, что бы связать учётную запись с",
|
||||
"sso.dissociate": "Dissociate",
|
||||
"sso.dissociate-confirm-title": "Confirm Dissociation",
|
||||
"sso.dissociate-confirm": "Are you sure you wish to dissociate your account from %1?",
|
||||
"sso.dissociate": "Открепить",
|
||||
"sso.dissociate-confirm-title": "Подтверждение открепления",
|
||||
"sso.dissociate-confirm": "Вы уверены, что хотите открепить свой аккаунт от %1?",
|
||||
"info.latest-flags": "Новые отмеченные сообщения",
|
||||
"info.no-flags": "Отмеченных сообщений не найдено",
|
||||
"info.ban-history": "Недавно заблокированы",
|
||||
|
||||
@@ -37,6 +37,20 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
|
||||
el.find('i').toggleClass('fa-minus').toggleClass('fa-plus');
|
||||
el.closest('[data-cid]').find('> ul[data-cid]').toggleClass('hidden');
|
||||
});
|
||||
|
||||
$('#collapse-all').on('click', function () {
|
||||
toggleAll(false);
|
||||
});
|
||||
|
||||
$('#expand-all').on('click', function () {
|
||||
toggleAll(true);
|
||||
});
|
||||
|
||||
function toggleAll(expand) {
|
||||
var el = $('.categories .toggle');
|
||||
el.find('i').toggleClass('fa-minus', expand).toggleClass('fa-plus', !expand);
|
||||
el.closest('[data-cid]').find('> ul[data-cid]').toggleClass('hidden', !expand);
|
||||
}
|
||||
};
|
||||
|
||||
Categories.throwCreateModal = function () {
|
||||
|
||||
@@ -89,7 +89,7 @@ define('admin/settings', ['uploader'], function (uploader) {
|
||||
alert_id: 'config_status',
|
||||
timeout: 2500,
|
||||
title: 'Changes Not Saved',
|
||||
message: 'NodeBB encountered a problem saving your changes',
|
||||
message: 'NodeBB encountered a problem saving your changes. (' + err.message + ')',
|
||||
type: 'danger',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds'
|
||||
if (skinName === 'default') {
|
||||
skinName = config.defaultBootswatchSkin;
|
||||
}
|
||||
var cssSource = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + skinName + '/bootstrap.min.css';
|
||||
var cssSource = '//maxcdn.bootstrapcdn.com/bootswatch/3.3.7/' + skinName + '/bootstrap.min.css';
|
||||
if (css.length) {
|
||||
css.attr('href', cssSource);
|
||||
} else {
|
||||
|
||||
@@ -231,7 +231,7 @@ define('forum/topic', [
|
||||
var bookmarkKey = 'topic:' + ajaxify.data.tid + ':bookmark';
|
||||
var currentBookmark = ajaxify.data.bookmark || storage.getItem(bookmarkKey);
|
||||
|
||||
if (ajaxify.data.postcount > ajaxify.data.bookmarkThreshold && (!currentBookmark || parseInt(index, 10) > parseInt(currentBookmark, 10))) {
|
||||
if (ajaxify.data.postcount > ajaxify.data.bookmarkThreshold && (!currentBookmark || parseInt(index, 10) > parseInt(currentBookmark, 10) || ajaxify.data.postcount < parseInt(currentBookmark, 10))) {
|
||||
if (app.user.uid) {
|
||||
socket.emit('topics.bookmark', {
|
||||
tid: ajaxify.data.tid,
|
||||
|
||||
@@ -10,9 +10,6 @@ define('forum/topic/merge', function () {
|
||||
|
||||
Merge.init = function () {
|
||||
$('.category').on('click', '[component="topic/merge"]', onMergeTopicsClicked);
|
||||
if (modal) {
|
||||
$('[component="category/topic"]').on('click', 'a', onTopicClicked);
|
||||
}
|
||||
};
|
||||
|
||||
function onMergeTopicsClicked() {
|
||||
@@ -28,7 +25,7 @@ define('forum/topic/merge', function () {
|
||||
|
||||
modal.find('.close,#merge_topics_cancel').on('click', closeModal);
|
||||
|
||||
$('[component="category/topic"]').on('click', 'a', onTopicClicked);
|
||||
$('[component="category"]').on('click', '[component="category/topic"] a', onTopicClicked);
|
||||
|
||||
showTopicsSelected();
|
||||
|
||||
@@ -40,15 +37,19 @@ define('forum/topic/merge', function () {
|
||||
|
||||
function onTopicClicked(ev) {
|
||||
var tid = $(this).parents('[component="category/topic"]').attr('data-tid');
|
||||
var index = $(this).parents('[component="category/topic"]').attr('data-index');
|
||||
var title = ajaxify.data.topics[index] ? ajaxify.data.topics[index].title : 'No title';
|
||||
if (selectedTids[tid]) {
|
||||
delete selectedTids[tid];
|
||||
} else {
|
||||
selectedTids[tid] = title;
|
||||
}
|
||||
checkButtonEnable();
|
||||
showTopicsSelected();
|
||||
socket.emit('topics.getTopic', tid, function (err, topicData) {
|
||||
if (err) {
|
||||
return app.alertError(err);
|
||||
}
|
||||
var title = topicData ? topicData.title : 'No title';
|
||||
if (selectedTids[tid]) {
|
||||
delete selectedTids[tid];
|
||||
} else {
|
||||
selectedTids[tid] = title;
|
||||
}
|
||||
checkButtonEnable();
|
||||
showTopicsSelected();
|
||||
});
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
return false;
|
||||
|
||||
@@ -8,8 +8,7 @@ define('forum/topic/postTools', [
|
||||
'translator',
|
||||
'forum/topic/votes',
|
||||
'forum/topic/move-post',
|
||||
'benchpress',
|
||||
], function (share, navigator, components, translator, votes, movePost, Benchpress) {
|
||||
], function (share, navigator, components, translator, votes, movePost) {
|
||||
var PostTools = {};
|
||||
|
||||
var staleReplyAnyway = false;
|
||||
@@ -45,11 +44,12 @@ define('forum/topic/postTools', [
|
||||
}
|
||||
data.posts.display_move_tools = data.posts.display_move_tools && index !== 0;
|
||||
|
||||
Benchpress.parse('partials/topic/post-menu-list', data, function (html) {
|
||||
translator.translate(html, function (html) {
|
||||
dropdownMenu.html(html);
|
||||
$(window).trigger('action:post.tools.load');
|
||||
app.parseAndTranslate('partials/topic/post-menu-list', data, function (html) {
|
||||
dropdownMenu.html(html);
|
||||
require(['clipboard'], function (clipboard) {
|
||||
new clipboard('[data-clipboard-text]');
|
||||
});
|
||||
$(window).trigger('action:post.tools.load');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -192,6 +192,16 @@ define('forum/topic/postTools', [
|
||||
movePost.openMovePostModal($(this));
|
||||
});
|
||||
|
||||
postContainer.on('click', '[component="post/ban-ip"]', function () {
|
||||
var ip = $(this).attr('data-ip');
|
||||
socket.emit('blacklist.addRule', ip, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess('[[admin/manage/blacklist:ban-ip]]');
|
||||
});
|
||||
});
|
||||
|
||||
postContainer.on('click', '[component="post/chat"]', function () {
|
||||
openChat($(this));
|
||||
});
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
if ((properties.loggedIn && !loggedIn) ||
|
||||
(properties.guestOnly && loggedIn) ||
|
||||
(properties.globalMod && !data.isGlobalMod && !data.isAdmin) ||
|
||||
(properties.adminOnly && !data.isAdmin) ||
|
||||
(properties.searchInstalled && !data.searchEnabled)) {
|
||||
(properties.adminOnly && !data.isAdmin)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ define('notifications', ['sounds', 'translator', 'components', 'navigator', 'ben
|
||||
payload.message = notifData.bodyShort;
|
||||
payload.type = 'info';
|
||||
payload.clickfn = function () {
|
||||
if (notifData.path.startsWith('http') && notifData.path.startsWith('https')) {
|
||||
if (notifData.path.startsWith('http') || notifData.path.startsWith('https')) {
|
||||
window.location.href = notifData.path;
|
||||
} else {
|
||||
window.location.href = window.location.protocol + '//' + window.location.host + config.relative_path + notifData.path;
|
||||
|
||||
@@ -518,7 +518,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
tags: ['a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b', 'base', 'basefont', 'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'small', 'source', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'],
|
||||
tags: ['a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b', 'base', 'basefont',
|
||||
'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup',
|
||||
'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed',
|
||||
'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
||||
'head', 'header', 'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link',
|
||||
'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option',
|
||||
'output', 'p', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select',
|
||||
'small', 'source', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot',
|
||||
'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'],
|
||||
|
||||
stripTags: ['abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'base', 'basefont',
|
||||
'bdi', 'bdo', 'big', 'blink', 'body', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup',
|
||||
|
||||
@@ -41,7 +41,7 @@ module.exports = function (Categories) {
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
plugins.fireHook('filter:category.update', { category: modifiedFields }, next);
|
||||
plugins.fireHook('filter:category.update', { cid: cid, category: modifiedFields }, next);
|
||||
},
|
||||
function (categoryData, next) {
|
||||
category = categoryData.category;
|
||||
|
||||
@@ -41,11 +41,18 @@ function installAll() {
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
cproc.execSync(command + (prod ? ' --production' : ''), {
|
||||
cwd: path.join(__dirname, '../../'),
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
try {
|
||||
cproc.execSync(command + (prod ? ' --production' : ''), {
|
||||
cwd: path.join(__dirname, '../../'),
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
} catch (e) {
|
||||
console.log('Error installing dependencies!');
|
||||
console.log('message: ' + e.message);
|
||||
console.log('stdout: ' + e.stdout);
|
||||
console.log('stderr: ' + e.stderr);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
exports.installAll = installAll;
|
||||
|
||||
@@ -65,7 +65,7 @@ function runSteps(tasks) {
|
||||
|
||||
async.series(tasks, function (err) {
|
||||
if (err) {
|
||||
console.error('Error occurred during upgrade');
|
||||
console.error('Error occurred during upgrade: ' + err.stack);
|
||||
throw err;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
|
||||
var user = require('../../user');
|
||||
var languages = require('../../languages');
|
||||
@@ -40,6 +41,9 @@ settingsController.get = function (req, res, callback) {
|
||||
function (results, next) {
|
||||
userData.settings = results.settings;
|
||||
userData.languages = results.languages;
|
||||
if (userData.isAdmin && userData.isSelf) {
|
||||
userData.acpLanguages = _.cloneDeep(results.languages);
|
||||
}
|
||||
|
||||
var types = [
|
||||
'notification',
|
||||
@@ -135,6 +139,12 @@ settingsController.get = function (req, res, callback) {
|
||||
language.selected = language.code === userData.settings.userLang;
|
||||
});
|
||||
|
||||
if (userData.isAdmin && userData.isSelf) {
|
||||
userData.acpLanguages.forEach(function (language) {
|
||||
language.selected = language.code === userData.settings.acpLang;
|
||||
});
|
||||
}
|
||||
|
||||
var notifFreqOptions = [
|
||||
'all',
|
||||
'everyTen',
|
||||
@@ -203,7 +213,7 @@ function getNotificationSettings(userData, callback) {
|
||||
},
|
||||
function (results, next) {
|
||||
function modifyType(type) {
|
||||
var setting = userData.settings[type] || 'notification';
|
||||
var setting = userData.settings[type];
|
||||
|
||||
return {
|
||||
name: type,
|
||||
|
||||
@@ -7,7 +7,6 @@ var analytics = require('../../analytics');
|
||||
var blacklistController = module.exports;
|
||||
|
||||
blacklistController.get = function (req, res, next) {
|
||||
// Analytics.getBlacklistAnalytics
|
||||
async.parallel({
|
||||
rules: async.apply(meta.blacklist.get),
|
||||
analytics: async.apply(analytics.getBlacklistAnalytics),
|
||||
|
||||
@@ -88,6 +88,7 @@ apiController.loadConfig = function (req, callback) {
|
||||
config.topicsPerPage = settings.topicsPerPage;
|
||||
config.postsPerPage = settings.postsPerPage;
|
||||
config.userLang = (req.query.lang ? validator.escape(String(req.query.lang)) : null) || settings.userLang || config.defaultLang;
|
||||
config.acpLang = (req.query.lang ? validator.escape(String(req.query.lang)) : null) || settings.acpLang;
|
||||
config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab;
|
||||
config.topicPostSort = settings.topicPostSort || config.topicPostSort;
|
||||
config.categoryTopicSort = settings.categoryTopicSort || config.categoryTopicSort;
|
||||
|
||||
@@ -233,6 +233,7 @@ Controllers.robots = function (req, res) {
|
||||
} else {
|
||||
res.send('User-agent: *\n' +
|
||||
'Disallow: ' + nconf.get('relative_path') + '/admin/\n' +
|
||||
'Disallow: ' + nconf.get('relative_path') + '/reset/\n' +
|
||||
'Sitemap: ' + nconf.get('url') + '/sitemap.xml');
|
||||
}
|
||||
};
|
||||
|
||||
12
src/flags.js
12
src/flags.js
@@ -645,10 +645,18 @@ Flags.notify = function (flagObj, uid, callback) {
|
||||
admins: async.apply(groups.getMembers, 'administrators', 0, -1),
|
||||
globalMods: async.apply(groups.getMembers, 'Global Moderators', 0, -1),
|
||||
moderators: function (next) {
|
||||
var cid;
|
||||
async.waterfall([
|
||||
async.apply(posts.getCidByPid, flagObj.targetId),
|
||||
function (cid, next) {
|
||||
groups.getMembers('cid:' + cid + ':privileges:moderate', 0, -1, next);
|
||||
function (_cid, next) {
|
||||
cid = _cid;
|
||||
groups.getMembers('cid:' + cid + ':privileges:groups:moderate', 0, -1, next);
|
||||
},
|
||||
function (moderatorGroups, next) {
|
||||
groups.getMembersOfGroups(moderatorGroups.concat(['cid:' + cid + ':privileges:moderate']), next);
|
||||
},
|
||||
function (members, next) {
|
||||
next(null, _.flatten(members));
|
||||
},
|
||||
], next);
|
||||
},
|
||||
|
||||
@@ -8,13 +8,14 @@ var db = require('../database');
|
||||
|
||||
module.exports = function (Groups) {
|
||||
Groups.create = function (data, callback) {
|
||||
var system = isSystemGroup(data);
|
||||
var isSystem = isSystemGroup(data);
|
||||
var groupData;
|
||||
var timestamp = data.timestamp || Date.now();
|
||||
var disableJoinRequests = parseInt(data.disableJoinRequests, 10) === 1 ? 1 : 0;
|
||||
if (data.name === 'administrators') {
|
||||
disableJoinRequests = 1;
|
||||
}
|
||||
var isHidden = parseInt(data.hidden, 10) === 1;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
validateGroupName(data.name, next);
|
||||
@@ -38,8 +39,8 @@ module.exports = function (Groups) {
|
||||
description: data.description || '',
|
||||
memberCount: memberCount,
|
||||
deleted: 0,
|
||||
hidden: parseInt(data.hidden, 10) === 1 ? 1 : 0,
|
||||
system: system ? 1 : 0,
|
||||
hidden: isHidden ? 1 : 0,
|
||||
system: isSystem ? 1 : 0,
|
||||
private: isPrivate,
|
||||
disableJoinRequests: disableJoinRequests,
|
||||
};
|
||||
@@ -58,7 +59,7 @@ module.exports = function (Groups) {
|
||||
groupData.ownerUid = data.ownerUid;
|
||||
}
|
||||
|
||||
if (!data.hidden && !system) {
|
||||
if (!isHidden && !isSystem) {
|
||||
tasks.push(async.apply(db.sortedSetAdd, 'groups:visible:createtime', timestamp, groupData.name));
|
||||
tasks.push(async.apply(db.sortedSetAdd, 'groups:visible:memberCount', groupData.memberCount, groupData.name));
|
||||
tasks.push(async.apply(db.sortedSetAdd, 'groups:visible:name', 0, groupData.name.toLowerCase() + ':' + groupData.name));
|
||||
|
||||
@@ -71,12 +71,13 @@ Languages.list = function (callback) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
var lang;
|
||||
try {
|
||||
var lang = JSON.parse(file);
|
||||
next(null, lang);
|
||||
lang = JSON.parse(file);
|
||||
} catch (e) {
|
||||
next(e);
|
||||
return next(e);
|
||||
}
|
||||
next(null, lang);
|
||||
});
|
||||
}, function (err, languages) {
|
||||
if (err) {
|
||||
|
||||
@@ -177,9 +177,44 @@ module.exports = function (Messaging) {
|
||||
}));
|
||||
db.sortedSetsRemove(keys, roomId, next);
|
||||
},
|
||||
function (next) {
|
||||
updateOwner(roomId, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
Messaging.leaveRooms = function (uid, roomIds, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
var roomKeys = roomIds.map(function (roomId) {
|
||||
return 'chat:room:' + roomId + ':uids';
|
||||
});
|
||||
db.sortedSetsRemove(roomKeys, uid, next);
|
||||
},
|
||||
function (next) {
|
||||
db.sortedSetRemove('uid:' + uid + ':chat:rooms', roomIds, next);
|
||||
},
|
||||
function (next) {
|
||||
db.sortedSetRemove('uid:' + uid + ':chat:rooms:unread', roomIds, next);
|
||||
},
|
||||
function (next) {
|
||||
async.eachSeries(roomIds, updateOwner, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
function updateOwner(roomId, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getSortedSetRange('chat:room:' + roomId + ':uids', 0, 0, next);
|
||||
},
|
||||
function (uids, next) {
|
||||
var newOwner = uids[0] || 0;
|
||||
db.setObjectField('chat:room:' + roomId, 'owner', newOwner, next);
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
Messaging.getUidsInRoom = function (roomId, start, stop, callback) {
|
||||
db.getSortedSetRevRange('chat:room:' + roomId + ':uids', start, stop, callback);
|
||||
};
|
||||
|
||||
@@ -9,9 +9,8 @@ var pubsub = require('../pubsub');
|
||||
var plugins = require('../plugins');
|
||||
var analytics = require('../analytics');
|
||||
|
||||
var Blacklist = {
|
||||
_rules: [],
|
||||
};
|
||||
var Blacklist = module.exports;
|
||||
Blacklist._rules = [];
|
||||
|
||||
Blacklist.load = function (callback) {
|
||||
callback = callback || function () {};
|
||||
@@ -182,4 +181,22 @@ Blacklist.validate = function (rules, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Blacklist;
|
||||
Blacklist.addRule = function (rule, callback) {
|
||||
var valid;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
Blacklist.validate(rule, next);
|
||||
},
|
||||
function (result, next) {
|
||||
valid = result.valid;
|
||||
if (!valid.length) {
|
||||
return next(new Error('[[error:invalid-rule]]'));
|
||||
}
|
||||
Blacklist.get(next);
|
||||
},
|
||||
function (rules, next) {
|
||||
rules = rules + '\n' + valid[0];
|
||||
Blacklist.save(rules, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
var async = require('async');
|
||||
var nconf = require('nconf');
|
||||
var path = require('path');
|
||||
var winston = require('winston');
|
||||
|
||||
var db = require('../database');
|
||||
var pubsub = require('../pubsub');
|
||||
@@ -83,9 +84,17 @@ function processConfig(data, callback) {
|
||||
var image = require('../image');
|
||||
if (data['brand:logo']) {
|
||||
image.size(path.join(nconf.get('upload_path'), 'system', 'site-logo-x50.png'), function (err, size) {
|
||||
if (err) {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
// For whatever reason the x50 logo wasn't generated, gracefully error out
|
||||
winston.warn('[logo] The email-safe logo doesn\'t seem to have been created, please re-upload your site logo.');
|
||||
size = {
|
||||
height: 0,
|
||||
width: 0,
|
||||
};
|
||||
} else if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
data['brand:emailLogo:height'] = size.height;
|
||||
data['brand:emailLogo:width'] = size.width;
|
||||
next();
|
||||
|
||||
@@ -98,6 +98,7 @@ JS.scripts = {
|
||||
'jqueryui.js': 'public/vendor/jquery/js/jquery-ui.js',
|
||||
'zxcvbn.js': 'node_modules/zxcvbn/dist/zxcvbn.js',
|
||||
ace: 'node_modules/ace-builds/src-min',
|
||||
'clipboard.js': 'node_modules/clipboard/dist/clipboard.min.js',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ module.exports = function (middleware) {
|
||||
plugins: [],
|
||||
authentication: [],
|
||||
};
|
||||
|
||||
res.locals.config = res.locals.config || {};
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
@@ -51,9 +51,6 @@ module.exports = function (middleware) {
|
||||
custom_header: function (next) {
|
||||
plugins.fireHook('filter:admin.header.build', custom_header, next);
|
||||
},
|
||||
config: function (next) {
|
||||
controllers.api.getConfig(req, res, next);
|
||||
},
|
||||
configs: function (next) {
|
||||
meta.configs.list(next);
|
||||
},
|
||||
@@ -64,8 +61,6 @@ module.exports = function (middleware) {
|
||||
userData.uid = req.uid;
|
||||
userData['email:confirmed'] = parseInt(userData['email:confirmed'], 10) === 1;
|
||||
|
||||
res.locals.config = results.config;
|
||||
|
||||
var acpPath = req.path.slice(1).split('/');
|
||||
acpPath.forEach(function (path, i) {
|
||||
acpPath[i] = path.charAt(0).toUpperCase() + path.slice(1);
|
||||
@@ -73,9 +68,9 @@ module.exports = function (middleware) {
|
||||
acpPath = acpPath.join(' > ');
|
||||
|
||||
var templateValues = {
|
||||
config: results.config,
|
||||
configJSON: jsesc(JSON.stringify(results.config), { isScriptContext: true }),
|
||||
relative_path: results.config.relative_path,
|
||||
config: res.locals.config,
|
||||
configJSON: jsesc(JSON.stringify(res.locals.config), { isScriptContext: true }),
|
||||
relative_path: res.locals.config.relative_path,
|
||||
adminConfigJSON: encodeURIComponent(JSON.stringify(results.configs)),
|
||||
user: userData,
|
||||
userJSON: jsesc(JSON.stringify(userData), { isScriptContext: true }),
|
||||
|
||||
@@ -283,7 +283,7 @@ module.exports = function (middleware) {
|
||||
}
|
||||
|
||||
if (skinToUse) {
|
||||
obj.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + skinToUse + '/bootstrap.min.css';
|
||||
obj.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/3.3.7/' + skinToUse + '/bootstrap.min.css';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,12 +237,18 @@ middleware.templatesOnDemand = function (req, res, next) {
|
||||
fs.readFile(filePath.replace(/\.js$/, '.tpl'), 'utf8', cb);
|
||||
},
|
||||
function (source, cb) {
|
||||
if (!source) {
|
||||
return cb(new Error('[[error:templatesOnDemand.source-template-empty]]'));
|
||||
}
|
||||
Benchpress.precompile({
|
||||
source: source,
|
||||
minify: global.env !== 'development',
|
||||
}, cb);
|
||||
},
|
||||
function (compiled, cb) {
|
||||
if (!compiled) {
|
||||
return cb(new Error('[[error:templatesOnDemand.compiled-template-empty]]'));
|
||||
}
|
||||
fs.writeFile(filePath, compiled, cb);
|
||||
},
|
||||
], function (err) {
|
||||
|
||||
@@ -41,8 +41,7 @@ module.exports = function (middleware) {
|
||||
options.template = { name: template };
|
||||
options.template[template] = true;
|
||||
options.url = (req.baseUrl + req.path.replace(/^\/api/, ''));
|
||||
options.bodyClass = buildBodyClass(req, options);
|
||||
|
||||
options.bodyClass = buildBodyClass(req, res, options);
|
||||
plugins.fireHook('filter:' + template + '.build', { req: req, res: res, templateData: options }, next);
|
||||
},
|
||||
function (data, next) {
|
||||
@@ -120,13 +119,16 @@ module.exports = function (middleware) {
|
||||
|
||||
function translate(str, req, res, next) {
|
||||
var language = (res.locals.config && res.locals.config.userLang) || 'en-GB';
|
||||
if (res.locals.renderAdminHeader) {
|
||||
language = (res.locals.config && res.locals.config.acpLang) || 'en-GB';
|
||||
}
|
||||
language = req.query.lang ? validator.escape(String(req.query.lang)) : language;
|
||||
translator.translate(str, language, function (translated) {
|
||||
next(null, translator.unescape(translated));
|
||||
});
|
||||
}
|
||||
|
||||
function buildBodyClass(req, templateData) {
|
||||
function buildBodyClass(req, res, templateData) {
|
||||
var clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, '');
|
||||
var parts = clean.split('/').slice(0, 3);
|
||||
parts.forEach(function (p, index) {
|
||||
@@ -145,6 +147,7 @@ module.exports = function (middleware) {
|
||||
parts.push('page-topic-category-' + utils.slugify(templateData.category.name));
|
||||
}
|
||||
|
||||
parts.push('page-status-' + res.statusCode);
|
||||
return parts.join(' ');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -82,23 +82,20 @@ module.exports = function (Plugins) {
|
||||
|
||||
var hookList = Plugins.loadedHooks[hook];
|
||||
var hookType = hook.split(':')[0];
|
||||
try {
|
||||
switch (hookType) {
|
||||
case 'filter':
|
||||
fireFilterHook(hook, hookList, params, callback);
|
||||
break;
|
||||
case 'action':
|
||||
fireActionHook(hook, hookList, params, callback);
|
||||
break;
|
||||
case 'static':
|
||||
fireStaticHook(hook, hookList, params, callback);
|
||||
break;
|
||||
default:
|
||||
winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook);
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
switch (hookType) {
|
||||
case 'filter':
|
||||
fireFilterHook(hook, hookList, params, callback);
|
||||
break;
|
||||
case 'action':
|
||||
fireActionHook(hook, hookList, params, callback);
|
||||
break;
|
||||
case 'static':
|
||||
fireStaticHook(hook, hookList, params, callback);
|
||||
break;
|
||||
default:
|
||||
winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook);
|
||||
callback();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ function generateForTopic(req, res, callback) {
|
||||
var author = topicData.posts.length ? topicData.posts[0].username : '';
|
||||
|
||||
var feed = new rss({
|
||||
title: utils.stripHTMLTags(topicData.title, utils.stripTags),
|
||||
title: utils.stripHTMLTags(topicData.title, utils.tags),
|
||||
description: description,
|
||||
feed_url: nconf.get('url') + '/topic/' + tid + '.rss',
|
||||
site_url: nconf.get('url') + '/topic/' + topicData.slug,
|
||||
@@ -125,7 +125,7 @@ function generateForTopic(req, res, callback) {
|
||||
dateStamp = new Date(parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)).toUTCString();
|
||||
|
||||
feed.item({
|
||||
title: 'Reply to ' + utils.stripHTMLTags(topicData.title, utils.stripTags) + ' on ' + dateStamp,
|
||||
title: 'Reply to ' + utils.stripHTMLTags(topicData.title, utils.tags) + ' on ' + dateStamp,
|
||||
description: postData.content,
|
||||
url: nconf.get('url') + '/post/' + postData.pid,
|
||||
author: postData.user ? postData.user.username : '',
|
||||
@@ -301,7 +301,7 @@ function generateTopicsFeed(feedOptions, feedTopics, callback) {
|
||||
|
||||
async.each(feedTopics, function (topicData, next) {
|
||||
var feedItem = {
|
||||
title: utils.stripHTMLTags(topicData.title, utils.stripTags),
|
||||
title: utils.stripHTMLTags(topicData.title, utils.tags),
|
||||
url: nconf.get('url') + '/topic/' + topicData.slug,
|
||||
date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString(),
|
||||
};
|
||||
|
||||
@@ -26,3 +26,18 @@ SocketBlacklist.save = function (socket, rules, callback) {
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
SocketBlacklist.addRule = function (socket, rule, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.isAdminOrGlobalMod(socket.uid, next);
|
||||
},
|
||||
function (isAdminOrGlobalMod, next) {
|
||||
if (!isAdminOrGlobalMod) {
|
||||
return callback(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
|
||||
meta.blacklist.addRule(rule, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
@@ -113,6 +113,7 @@ SocketHelpers.sendNotificationToPostOwner = function (pid, fromuid, command, not
|
||||
bodyShort: '[[' + notification + ', ' + results.username + ', ' + titleEscaped + ']]',
|
||||
bodyLong: results.postObj.content,
|
||||
pid: pid,
|
||||
tid: postData.tid,
|
||||
path: '/post/' + pid,
|
||||
nid: command + ':post:' + pid + ':uid:' + fromuid,
|
||||
from: fromuid,
|
||||
|
||||
@@ -10,6 +10,8 @@ var socketTopics = require('../topics');
|
||||
var privileges = require('../../privileges');
|
||||
var plugins = require('../../plugins');
|
||||
var social = require('../../social');
|
||||
var user = require('../../user');
|
||||
|
||||
|
||||
module.exports = function (SocketPosts) {
|
||||
SocketPosts.loadPostTools = function (socket, data, callback) {
|
||||
@@ -20,10 +22,16 @@ module.exports = function (SocketPosts) {
|
||||
function (next) {
|
||||
async.parallel({
|
||||
posts: function (next) {
|
||||
posts.getPostFields(data.pid, ['deleted', 'bookmarks', 'uid'], next);
|
||||
posts.getPostFields(data.pid, ['deleted', 'bookmarks', 'uid', 'ip'], next);
|
||||
},
|
||||
isAdminOrMod: function (next) {
|
||||
privileges.categories.isAdminOrMod(data.cid, socket.uid, next);
|
||||
isAdmin: function (next) {
|
||||
user.isAdministrator(socket.uid, next);
|
||||
},
|
||||
isGlobalMod: function (next) {
|
||||
user.isGlobalModerator(socket.uid, next);
|
||||
},
|
||||
isModerator: function (next) {
|
||||
user.isModerator(socket.uid, data.cid, next);
|
||||
},
|
||||
canEdit: function (next) {
|
||||
privileges.posts.canEdit(data.pid, socket.uid, next);
|
||||
@@ -54,7 +62,12 @@ module.exports = function (SocketPosts) {
|
||||
results.posts.display_delete_tools = results.canDelete.flag;
|
||||
results.posts.display_flag_tools = socket.uid && !results.posts.selfPost && results.canFlag.flag;
|
||||
results.posts.display_moderator_tools = results.posts.display_edit_tools || results.posts.display_delete_tools;
|
||||
results.posts.display_move_tools = results.isAdminOrMod;
|
||||
results.posts.display_move_tools = results.isAdmin || results.isModerator;
|
||||
results.posts.display_ip_ban = (results.isAdmin || results.isGlobalMod) && !results.posts.selfPost;
|
||||
|
||||
if (!results.isAdmin && !results.isGlobalMod && !results.isModerator) {
|
||||
results.posts.ip = undefined;
|
||||
}
|
||||
next(null, results);
|
||||
},
|
||||
], callback);
|
||||
|
||||
@@ -39,6 +39,13 @@ module.exports = function (SocketUser) {
|
||||
function (next) {
|
||||
user.setUserFields(socket.uid, data, next);
|
||||
},
|
||||
function (next) {
|
||||
if (status !== 'offline') {
|
||||
user.updateOnlineUsers(socket.uid, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
var data = {
|
||||
uid: socket.uid,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
var async = require('async');
|
||||
|
||||
var db = require('../database');
|
||||
var posts = require('../posts');
|
||||
var user = require('../user');
|
||||
|
||||
module.exports = function (Topics) {
|
||||
Topics.getUserBookmark = function (tid, uid, callback) {
|
||||
@@ -34,7 +34,9 @@ module.exports = function (Topics) {
|
||||
};
|
||||
|
||||
Topics.updateTopicBookmarks = function (tid, pids, callback) {
|
||||
var minIndex;
|
||||
var maxIndex;
|
||||
var postIndices;
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
@@ -42,38 +44,54 @@ module.exports = function (Topics) {
|
||||
},
|
||||
function (postcount, next) {
|
||||
maxIndex = postcount;
|
||||
|
||||
db.sortedSetRanks('tid:' + tid + ':posts', pids, next);
|
||||
},
|
||||
function (indices, next) {
|
||||
postIndices = indices.map(function (i) {
|
||||
return i === null ? 0 : i + 1;
|
||||
});
|
||||
minIndex = Math.min.apply(Math, postIndices);
|
||||
|
||||
Topics.getTopicBookmarks(tid, next);
|
||||
},
|
||||
function (bookmarks, next) {
|
||||
var forkedPosts = pids.map(function (pid) {
|
||||
return { pid: pid, tid: tid };
|
||||
});
|
||||
|
||||
var uidData = bookmarks.map(function (bookmark) {
|
||||
return {
|
||||
uid: bookmark.value,
|
||||
bookmark: bookmark.score,
|
||||
bookmark: parseInt(bookmark.score, 10),
|
||||
};
|
||||
}).filter(function (data) {
|
||||
return data.bookmark >= minIndex;
|
||||
});
|
||||
|
||||
async.eachLimit(uidData, 50, function (data, next) {
|
||||
posts.getPostIndices(forkedPosts, data.uid, function (err, postIndices) {
|
||||
var bookmark = data.bookmark;
|
||||
bookmark = Math.min(bookmark, maxIndex);
|
||||
|
||||
postIndices.forEach(function (i) {
|
||||
if (i < data.bookmark) {
|
||||
bookmark -= 1;
|
||||
}
|
||||
});
|
||||
|
||||
// make sure the bookmark is valid if we removed the last post
|
||||
bookmark = Math.min(bookmark, maxIndex - pids.length);
|
||||
|
||||
if (bookmark === data.bookmark) {
|
||||
return next();
|
||||
}
|
||||
|
||||
user.getSettings(data.uid, function (err, settings) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var bookmark = data.bookmark;
|
||||
bookmark = bookmark < maxIndex ? bookmark : maxIndex;
|
||||
|
||||
for (var i = 0; i < postIndices.length && postIndices[i] < data.bookmark; i += 1) {
|
||||
bookmark -= 1;
|
||||
if (settings.topicPostSort === 'most_votes') {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (parseInt(bookmark, 10) !== parseInt(data.bookmark, 10)) {
|
||||
Topics.setUserBookmark(tid, data.uid, bookmark, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
Topics.setUserBookmark(tid, data.uid, bookmark, next);
|
||||
});
|
||||
}, next);
|
||||
},
|
||||
|
||||
@@ -209,18 +209,17 @@ module.exports = function (Topics) {
|
||||
var uid = data.uid;
|
||||
var content = data.content;
|
||||
var postData;
|
||||
var cid;
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
Topics.getTopicField(tid, 'cid', next);
|
||||
},
|
||||
function (_cid, next) {
|
||||
cid = _cid;
|
||||
function (cid, next) {
|
||||
data.cid = cid;
|
||||
async.parallel({
|
||||
topicData: async.apply(Topics.getTopicData, tid),
|
||||
canReply: async.apply(privileges.topics.can, 'topics:reply', tid, uid),
|
||||
isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, cid, uid),
|
||||
isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, data.cid, uid),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
@@ -243,7 +242,7 @@ module.exports = function (Topics) {
|
||||
guestHandleValid(data, next);
|
||||
},
|
||||
function (next) {
|
||||
user.isReadyToPost(uid, cid, next);
|
||||
user.isReadyToPost(uid, data.cid, next);
|
||||
},
|
||||
function (next) {
|
||||
plugins.fireHook('filter:topic.reply', data, next);
|
||||
@@ -284,7 +283,7 @@ module.exports = function (Topics) {
|
||||
}
|
||||
|
||||
Topics.notifyFollowers(postData, uid);
|
||||
analytics.increment(['posts', 'posts:byCid:' + cid]);
|
||||
analytics.increment(['posts', 'posts:byCid:' + data.cid]);
|
||||
plugins.fireHook('action:topic.reply', { post: _.clone(postData) });
|
||||
|
||||
next(null, postData);
|
||||
|
||||
@@ -33,7 +33,13 @@ Upgrade.getAll = function (callback) {
|
||||
versionA = path.dirname(a).split('/').pop();
|
||||
versionB = path.dirname(b).split('/').pop();
|
||||
|
||||
return semver.compare(versionA, versionB);
|
||||
var semverCompare = semver.compare(versionA, versionB);
|
||||
if (semverCompare) {
|
||||
return semverCompare;
|
||||
}
|
||||
var timestampA = require(a).timestamp;
|
||||
var timestampB = require(b).timestamp;
|
||||
return timestampA - timestampB;
|
||||
}));
|
||||
},
|
||||
async.apply(Upgrade.appendPluginScripts),
|
||||
|
||||
26
src/upgrades/1.7.6/notification_types.js
Normal file
26
src/upgrades/1.7.6/notification_types.js
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var db = require('../../database');
|
||||
|
||||
module.exports = {
|
||||
name: 'Add default settings for notification delivery types',
|
||||
timestamp: Date.UTC(2018, 1, 14),
|
||||
method: function (callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getObject('config', next);
|
||||
},
|
||||
function (config, next) {
|
||||
db.setObject('config', {
|
||||
notificationType_upvote: config.notificationType_upvote || 'notification',
|
||||
'notificationType_new-topic': config['notificationType_new-topic'] || 'notification',
|
||||
'notificationType_new-reply': config['notificationType_new-reply'] || config.sendPostNotifications || 'notification',
|
||||
notificationType_follow: config.notificationType_follow || 'notification',
|
||||
'notificationType_new-chat': config['notificationType_new-chat'] || config.sendChatNotifications || 'notification',
|
||||
'notificationType_group-invite': config['notificationType_group-invite'] || 'notification',
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
},
|
||||
};
|
||||
@@ -7,6 +7,7 @@ var db = require('../database');
|
||||
var posts = require('../posts');
|
||||
var topics = require('../topics');
|
||||
var groups = require('../groups');
|
||||
var messaging = require('../messaging');
|
||||
var plugins = require('../plugins');
|
||||
var batch = require('../batch');
|
||||
|
||||
@@ -173,12 +174,9 @@ module.exports = function (User) {
|
||||
var userKeys = roomIds.map(function (roomId) {
|
||||
return 'uid:' + uid + ':chat:room:' + roomId + ':mids';
|
||||
});
|
||||
var roomKeys = roomIds.map(function (roomId) {
|
||||
return 'chat:room:' + roomId + ':uids';
|
||||
});
|
||||
|
||||
async.parallel([
|
||||
async.apply(db.sortedSetsRemove, roomKeys, uid),
|
||||
async.apply(messaging.leaveRooms, uid, roomIds),
|
||||
async.apply(db.deleteAll, userKeys),
|
||||
], next);
|
||||
},
|
||||
|
||||
@@ -126,14 +126,24 @@ UserEmail.sendValidationEmail = function (uid, options, callback) {
|
||||
};
|
||||
|
||||
UserEmail.confirm = function (code, callback) {
|
||||
var confirmObj;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getObject('confirm:' + code, next);
|
||||
},
|
||||
function (confirmObj, next) {
|
||||
function (_confirmObj, next) {
|
||||
confirmObj = _confirmObj;
|
||||
if (!confirmObj || !confirmObj.uid || !confirmObj.email) {
|
||||
return next(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
user.getUserField(confirmObj.uid, 'email', next);
|
||||
},
|
||||
function (currentEmail, next) {
|
||||
if (!currentEmail || currentEmail.toLowerCase() !== confirmObj.email) {
|
||||
return next(new Error('[[error:invalid-email]]'));
|
||||
}
|
||||
|
||||
async.series([
|
||||
async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1),
|
||||
async.apply(db.delete, 'confirm:' + code),
|
||||
|
||||
@@ -70,6 +70,7 @@ module.exports = function (User) {
|
||||
settings.topicsPerPage = Math.min(settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : defaultTopicsPerPage, defaultTopicsPerPage);
|
||||
settings.postsPerPage = Math.min(settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : defaultPostsPerPage, defaultPostsPerPage);
|
||||
settings.userLang = settings.userLang || meta.config.defaultLang || 'en-GB';
|
||||
settings.acpLang = settings.acpLang || settings.userLang;
|
||||
settings.topicPostSort = getSetting(settings, 'topicPostSort', 'oldest_to_newest');
|
||||
settings.categoryTopicSort = getSetting(settings, 'categoryTopicSort', 'newest_to_oldest');
|
||||
settings.followTopicsOnCreate = parseInt(getSetting(settings, 'followTopicsOnCreate', 1), 10) === 1;
|
||||
@@ -80,6 +81,12 @@ module.exports = function (User) {
|
||||
settings.delayImageLoading = parseInt(getSetting(settings, 'delayImageLoading', 1), 10) === 1;
|
||||
settings.bootswatchSkin = settings.bootswatchSkin || meta.config.bootswatchSkin || 'default';
|
||||
settings.scrollToMyPost = parseInt(getSetting(settings, 'scrollToMyPost', 1), 10) === 1;
|
||||
settings.notificationType_upvote = getSetting(settings, 'notificationType_upvote', 'notification');
|
||||
settings['notificationType_new-topic'] = getSetting(settings, 'notificationType_new-topic', 'notification');
|
||||
settings['notificationType_new-reply'] = getSetting(settings, 'notificationType_new-reply', 'notification');
|
||||
settings.notificationType_follow = getSetting(settings, 'notificationType_follow', 'notification');
|
||||
settings['notificationType_new-chat'] = getSetting(settings, 'notificationType_new-chat', 'notification');
|
||||
settings['notificationType_group-invite'] = getSetting(settings, 'notificationType_group-invite', 'notification');
|
||||
next(null, settings);
|
||||
},
|
||||
], callback);
|
||||
@@ -118,6 +125,7 @@ module.exports = function (User) {
|
||||
topicsPerPage: Math.min(data.topicsPerPage, parseInt(maxTopicsPerPage, 10) || 20),
|
||||
postsPerPage: Math.min(data.postsPerPage, parseInt(maxPostsPerPage, 10) || 20),
|
||||
userLang: data.userLang || meta.config.defaultLang,
|
||||
acpLang: data.acpLang || meta.config.defaultLang,
|
||||
followTopicsOnCreate: data.followTopicsOnCreate,
|
||||
followTopicsOnReply: data.followTopicsOnReply,
|
||||
restrictChat: data.restrictChat,
|
||||
|
||||
@@ -91,15 +91,6 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<strong>[[admin/general/navigation:installed-plugins-required]]</strong>
|
||||
|
||||
<div class="checkbox">
|
||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||
<input class="mdl-switch__input" type="checkbox" name="property:searchInstalled" <!-- IF enabled.properties.searchInstalled -->checked<!-- ENDIF enabled.properties.searchInstalled -->/>
|
||||
<span class="mdl-switch__label"><strong>[[admin/general/navigation:search-plugin]]</strong></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-danger delete">[[admin/general/navigation:btn.delete]]</button>
|
||||
<!-- IF enabled.enabled -->
|
||||
<button class="btn btn-warning toggle">[[admin/general/navigation:btn.disable]]</button>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<button id="collapse-all" class="btn btn-default">[[admin/manage/categories:collapse-all]]</button> <button id="expand-all" class="btn btn-default">[[admin/manage/categories:expand-all]]</button>
|
||||
<hr/>
|
||||
<div class="categories"></div>
|
||||
|
||||
<button data-action="create" class="floating-button mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
|
||||
|
||||
@@ -232,7 +232,6 @@
|
||||
<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/user:default-user-settings]]</div>
|
||||
<div class="col-sm-10 col-xs-12">
|
||||
<form>
|
||||
|
||||
<div class="checkbox">
|
||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||
<input class="mdl-switch__input" type="checkbox" data-field="showemail">
|
||||
@@ -292,6 +291,85 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label>[[admin/settings/user:default-notification-settings]]</label>
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-7">
|
||||
<label>[[notifications:notificationType_upvote]]</label>
|
||||
</div>
|
||||
<div class="form-group col-xs-5">
|
||||
<select class="form-control" data-field="notificationType_upvote">
|
||||
<option value="none">[[notifications:none]]</option>
|
||||
<option value="notification">[[notifications:notification_only]]</option>
|
||||
<option value="email">[[notifications:email_only]]</option>
|
||||
<option value="notificationemail">[[notifications:notification_and_email]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-7">
|
||||
<label>[[notifications:notificationType_new-topic]]</label>
|
||||
</div>
|
||||
<div class="form-group col-xs-5">
|
||||
<select class="form-control" data-field="notificationType_new-topic">
|
||||
<option value="none">[[notifications:none]]</option>
|
||||
<option value="notification">[[notifications:notification_only]]</option>
|
||||
<option value="email">[[notifications:email_only]]</option>
|
||||
<option value="notificationemail">[[notifications:notification_and_email]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-7">
|
||||
<label>[[notifications:notificationType_new-reply]]</label>
|
||||
</div>
|
||||
<div class="form-group col-xs-5">
|
||||
<select class="form-control" data-field="notificationType_new-reply">
|
||||
<option value="none">[[notifications:none]]</option>
|
||||
<option value="notification">[[notifications:notification_only]]</option>
|
||||
<option value="email">[[notifications:email_only]]</option>
|
||||
<option value="notificationemail">[[notifications:notification_and_email]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-7">
|
||||
<label>[[notifications:notificationType_follow]]</label>
|
||||
</div>
|
||||
<div class="form-group col-xs-5">
|
||||
<select class="form-control" data-field="notificationType_follow">
|
||||
<option value="none">[[notifications:none]]</option>
|
||||
<option value="notification">[[notifications:notification_only]]</option>
|
||||
<option value="email">[[notifications:email_only]]</option>
|
||||
<option value="notificationemail">[[notifications:notification_and_email]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-7">
|
||||
<label>[[notifications:notificationType_new-chat]]</label>
|
||||
</div>
|
||||
<div class="form-group col-xs-5">
|
||||
<select class="form-control" data-field="notificationType_new-chat">
|
||||
<option value="none">[[notifications:none]]</option>
|
||||
<option value="notification">[[notifications:notification_only]]</option>
|
||||
<option value="email">[[notifications:email_only]]</option>
|
||||
<option value="notificationemail">[[notifications:notification_and_email]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-7">
|
||||
<label>[[notifications:notificationType_group-invite]]</label>
|
||||
</div>
|
||||
<div class="form-group col-xs-5">
|
||||
<select class="form-control" data-field="notificationType_group-invite">
|
||||
<option value="none">[[notifications:none]]</option>
|
||||
<option value="notification">[[notifications:notification_only]]</option>
|
||||
<option value="email">[[notifications:email_only]]</option>
|
||||
<option value="notificationemail">[[notifications:notification_and_email]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -265,6 +265,47 @@ describe('Groups', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a hidden group if hidden is 1', function (done) {
|
||||
Groups.create({
|
||||
name: 'hidden group',
|
||||
hidden: '1',
|
||||
}, function (err) {
|
||||
assert.ifError(err);
|
||||
db.isSortedSetMember('groups:visible:memberCount', 'visible group', function (err, isMember) {
|
||||
assert.ifError(err);
|
||||
assert(!isMember);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a visible group if hidden is 0', function (done) {
|
||||
Groups.create({
|
||||
name: 'visible group',
|
||||
hidden: '0',
|
||||
}, function (err) {
|
||||
assert.ifError(err);
|
||||
db.isSortedSetMember('groups:visible:memberCount', 'visible group', function (err, isMember) {
|
||||
assert.ifError(err);
|
||||
assert(isMember);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a visible group if hidden is not passed in', function (done) {
|
||||
Groups.create({
|
||||
name: 'visible group 2',
|
||||
}, function (err) {
|
||||
assert.ifError(err);
|
||||
db.isSortedSetMember('groups:visible:memberCount', 'visible group 2', function (err, isMember) {
|
||||
assert.ifError(err);
|
||||
assert(isMember);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to create group with duplicate group name', function (done) {
|
||||
Groups.create({ name: 'foo' }, function (err) {
|
||||
assert(err);
|
||||
|
||||
@@ -177,7 +177,48 @@ describe('Messaging Library', function () {
|
||||
Messaging.isUserInRoom(bazUid, roomId, function (err, isUserInRoom) {
|
||||
assert.ifError(err);
|
||||
assert.equal(isUserInRoom, false);
|
||||
done();
|
||||
Messaging.getRoomData(roomId, function (err, data) {
|
||||
assert.ifError(err);
|
||||
assert.equal(data.owner, fooUid);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should change owner when owner leaves room', function (done) {
|
||||
socketModules.chats.newRoom({ uid: herpUid }, { touid: fooUid }, function (err, roomId) {
|
||||
assert.ifError(err);
|
||||
socketModules.chats.addUserToRoom({ uid: herpUid }, { roomId: roomId, username: 'baz' }, function (err) {
|
||||
assert.ifError(err);
|
||||
socketModules.chats.leave({ uid: herpUid }, roomId, function (err) {
|
||||
assert.ifError(err);
|
||||
Messaging.getRoomData(roomId, function (err, data) {
|
||||
assert.ifError(err);
|
||||
assert.equal(data.owner, fooUid);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should change owner if owner is deleted', function (done) {
|
||||
User.create({ username: 'deleted_chat_user' }, function (err, sender) {
|
||||
assert.ifError(err);
|
||||
User.create({ username: 'receiver' }, function (err, receiver) {
|
||||
assert.ifError(err);
|
||||
socketModules.chats.newRoom({ uid: sender }, { touid: receiver }, function (err, roomId) {
|
||||
assert.ifError(err);
|
||||
User.deleteAccount(sender, function (err) {
|
||||
assert.ifError(err);
|
||||
Messaging.getRoomData(roomId, function (err, data) {
|
||||
assert.ifError(err);
|
||||
assert.equal(data.owner, receiver);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -357,7 +357,7 @@ describe('Notifications', function () {
|
||||
setTimeout(function () {
|
||||
user.notifications.getAll(uid, 'post', function (err, nids) {
|
||||
assert.ifError(err);
|
||||
assert.notEqual(nids.indexOf(nid), -1);
|
||||
assert(nids.includes(nid));
|
||||
done();
|
||||
});
|
||||
}, 1500);
|
||||
|
||||
@@ -70,22 +70,6 @@ describe('Plugins', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not crash if there is an exception in a hook', function (done) {
|
||||
function filterMethod(data, callback) {
|
||||
var crash;
|
||||
crash.a = 5;
|
||||
callback(null, data);
|
||||
}
|
||||
|
||||
plugins.registerHook('test-plugin-crash', { hook: 'filter:test.crashHook', method: filterMethod });
|
||||
|
||||
plugins.fireHook('filter:test.crashHook', { foo: 1 }, function (err, data) {
|
||||
assert(err);
|
||||
assert.equal(err.message, 'Cannot set property \'a\' of undefined');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get plugin data from nbbpm', function (done) {
|
||||
plugins.get('nodebb-plugin-markdown', function (err, data) {
|
||||
assert.ifError(err);
|
||||
|
||||
Reference in New Issue
Block a user