Merge remote-tracking branch 'origin/master' into develop

v1.18.x
Peter Jaszkowiak 7 years ago
commit 62ae171432

1
.gitignore vendored

@ -58,6 +58,7 @@ tx.exe
##Coverage output
coverage
.nyc_output
build
*.log

@ -34,7 +34,7 @@ function getDatabaseConfig(config, callback) {
prompt.get(questions.redis, callback);
}
} else if (config.database === 'mongo') {
if (config['mongo:host'] && config['mongo:port']) {
if ((config['mongo:host'] && config['mongo:port']) || config['mongo:uri']) {
callback(null, config);
} else {
prompt.get(questions.mongo, callback);
@ -68,6 +68,7 @@ function saveDatabaseConfig(config, databaseConfig, callback) {
username: databaseConfig['mongo:username'],
password: databaseConfig['mongo:password'],
database: databaseConfig['mongo:database'],
uri: databaseConfig['mongo:uri'],
};
} else {
return callback(new Error('unknown database : ' + config.database));

@ -13,38 +13,38 @@
"start": "node loader.js",
"lint": "eslint --cache ./nodebb .",
"pretest": "npm run lint",
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R dot",
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
"test": "nyc --reporter=html --reporter=text-summary mocha",
"coveralls": "nyc report --reporter=text-lcov | coveralls && rm -r coverage"
},
"dependencies": {
"ace-builds": "^1.2.8",
"ace-builds": "^1.2.9",
"async": "2.5.0",
"autoprefixer": "7.1.4",
"autoprefixer": "7.1.6",
"bcryptjs": "2.4.3",
"benchpressjs": "^1.1.0",
"benchpressjs": "^1.1.2",
"body-parser": "^1.18.2",
"bootstrap": "^3.3.7",
"chart.js": "^2.6.0",
"chart.js": "^2.7.0",
"colors": "^1.1.2",
"compression": "^1.7.1",
"connect-ensure-login": "^0.1.1",
"connect-flash": "^0.1.1",
"connect-mongo": "1.3.2",
"connect-multiparty": "^2.0.0",
"connect-mongo": "2.0.0",
"connect-multiparty": "^2.1.0",
"connect-redis": "3.3.2",
"cookie-parser": "^1.4.3",
"cron": "^1.2.1",
"cropperjs": "^1.0.0",
"cron": "^1.3.0",
"cropperjs": "^1.1.3",
"csurf": "^1.9.0",
"daemon": "^1.1.0",
"express": "^4.16.1",
"express": "^4.16.2",
"express-session": "^1.15.6",
"express-useragent": "1.0.8",
"html-to-text": "3.3.0",
"ipaddr.js": "^1.5.2",
"ipaddr.js": "^1.5.4",
"jimp": "0.2.28",
"jquery": "^3.2.1",
"json-2-csv": "^2.1.1",
"json-2-csv": "^2.1.2",
"less": "^2.7.2",
"lodash": "^4.17.4",
"logrotate-stream": "^0.2.5",
@ -52,7 +52,7 @@
"mime": "^2.0.3",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"mongodb": "2.2.31",
"mongodb": "2.2.33",
"morgan": "^1.9.0",
"mousetrap": "^1.6.1",
"nconf": "^0.8.5",
@ -70,10 +70,10 @@
"nodebb-theme-slick": "1.1.1",
"nodebb-theme-vanilla": "7.1.2",
"nodebb-widget-essentials": "3.0.7",
"nodemailer": "4.1.1",
"nodemailer": "4.3.0",
"passport": "^0.4.0",
"passport-local": "1.0.0",
"postcss": "6.0.12",
"postcss": "6.0.13",
"postcss-clean": "1.1.0",
"promise-polyfill": "^6.0.2",
"prompt": "^1.0.0",
@ -85,30 +85,30 @@
"semver": "^5.4.1",
"serve-favicon": "^2.4.5",
"sitemap": "^1.13.0",
"socket.io": "2.0.3",
"socket.io-client": "2.0.3",
"socket.io": "2.0.4",
"socket.io-client": "2.0.4",
"socket.io-redis": "5.2.0",
"socketio-wildcard": "2.0.0",
"spdx-license-list": "^3.0.1",
"toobusy-js": "^0.5.1",
"uglify-js": "^3.1.3",
"uglify-js": "^3.1.5",
"validator": "9.0.0",
"winston": "^2.3.1",
"winston": "^2.4.0",
"xml": "^1.0.1",
"xregexp": "3.2.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"coveralls": "^3.0.0",
"eslint": "^4.8.0",
"eslint-config-airbnb-base": "^12.0.1",
"eslint-plugin-import": "^2.7.0",
"eslint": "^4.9.0",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.8.0",
"grunt": "^1.0.1",
"grunt-contrib-watch": "^1.0.0",
"istanbul": "^0.4.5",
"jsdom": "^11.3.0",
"mocha": "^3.5.3",
"mocha-lcov-reporter": "^1.3.0"
"mocha": "^4.0.1",
"mocha-lcov-reporter": "^1.3.0",
"nyc": "^11.2.1"
},
"bugs": {
"url": "https://github.com/NodeBB/NodeBB/issues"

@ -65,7 +65,7 @@
"logout": "Log out",
"view-forum": "View Forum",
"search.placeholder": "Search...",
"search.placeholder": "Search for settings",
"search.no-results": "No results...",
"search.search-forum": "Search the forum for <strong></strong>",
"search.keep-typing": "Type more to see results...",

@ -1,6 +1,6 @@
{
"alert.confirm-reload": "Está seguro que desea recargar NodeBB?",
"alert.confirm-restart": "Está seguro que desea reiniciar NodeBB?",
"alert.confirm-reload": "¿Está seguro que desea recargar NodeBB?",
"alert.confirm-restart": "¿Está seguro que desea reiniciar NodeBB?",
"acp-title": "%1 | Panel de control de administrador NodeBB",
"settings-header-contents": "Contenidos"

@ -5,11 +5,11 @@
"out-of-date": "Périmé",
"none-found": "Aucun plugin trouvé",
"none-active": "Aucun plugin actif",
"find-plugins": "Plugins trouvés",
"find-plugins": "Chercher des plugins",
"plugin-search": "Recherche de plugin",
"plugin-search-placeholder": "Rechercher un plugin…",
"reorder-plugins": "Re-ordonner les plugins",
"reorder-plugins": "Réordonner les plugins",
"order-active": "Trier les plugins actifs",
"dev-interested": "Êtes-vous intéressés par l'écriture de plugins pour NodeBB ?",
"docs-info": "La documentation complète concernant lécriture de plugin peut être trouvée sur le<a target=\"_blank\" href=\"https://docs.nodebb.org/development/plugins/\">Portail Documentation NodeBB</a>.",
@ -47,5 +47,5 @@
"license.title": "Information sur la licence du plugin",
"license.intro": "Le plugin <strong>%1</strong> est sous licence %2. Veuillez lire et comprendre les termes de la licence avant dactiver ce plugin.",
"license.cta": "Voulez-vous continuer lactivation de ce plugin ?"
"license.cta": "Voulez-vous poursuivre en activant ce plugin ?"
}

@ -1,11 +1,11 @@
{
"post-cache": "Prześlij pamięć podręczną",
"posts-in-cache": "Postów w pamięci podręcznej",
"post-cache": "Pamięć podręczna postów",
"posts-in-cache": "Posty w pamięci podręcznej",
"average-post-size": "Średnia wielkość posta",
"length-to-max": "Długość / Maks.",
"percent-full": "%1%",
"post-cache-size": "Rozmiar pamięci podręcznej posta",
"items-in-cache": "Pozycji w pamięci podręcznej",
"post-cache-size": "Rozmiar pamięci podręcznej postów",
"items-in-cache": "Elementów w pamięci podręcznej",
"control-panel": "Panel administracyjny",
"update-settings": "Zaktualizuj ustawienia pamięci podręcznej"
"update-settings": "Zaktualizuj ustawienia pamięci"
}

@ -2,12 +2,12 @@
"x-b": "%1 b",
"x-mb": "%1 mb",
"x-gb": "%1 gb",
"uptime-seconds": "Uptime w sekundach",
"uptime-days": "Uptime w dniach",
"uptime-seconds": "Czas od restartu w sekundach",
"uptime-days": "Czas od restartu w dniach",
"mongo": "Mongo",
"mongo.version": "Wersja MongoDB",
"mongo.storage-engine": "Silnik Magazynowania",
"mongo.storage-engine": "Silnik magazynowania",
"mongo.collections": "Kolekcje",
"mongo.objects": "Obiekty",
"mongo.avg-object-size": "Przybliżony rozmiar obiektu",
@ -15,22 +15,22 @@
"mongo.storage-size": "Rozmiar pamięci",
"mongo.index-size": "Rozmiar indeksu",
"mongo.file-size": "Rozmiar pliku",
"mongo.resident-memory": "Przynależna Pamięć",
"mongo.resident-memory": "Pamięć przydzielona",
"mongo.virtual-memory": "Pamięc wirtualna",
"mongo.mapped-memory": "Pamięc zmapowana",
"mongo.raw-info": "Surowe informacje MongoDB",
"mongo.raw-info": "Informacje MongoDB",
"redis": "Redis",
"redis.version": "Wersja Redis",
"redis.connected-clients": "Połączonych klientów",
"redis.connected-slaves": "Połączonych niewolników",
"redis.connected-slaves": "Połączonych urządzeń podrzędnych",
"redis.blocked-clients": "Zablokowanych klientów",
"redis.used-memory": "Użyta pamięć",
"redis.memory-frag-ratio": "Proporcja fragmentacji pamięci",
"redis.total-connections-recieved": "Otrzymanych połączeń",
"redis.total-commands-processed": "Przetworzonych połączeń",
"redis.total-commands-processed": "Przetworzonych komend",
"redis.iops": "Natychmiastowe Operacje Na Sekundę",
"redis.keyspace-hits": "Trafienia Kluczy",
"redis.keyspace-hits": "Trafione Klucze",
"redis.keyspace-misses": "Nietrafione Klucze",
"redis.raw-info": "Surowe informacje Redis"
"redis.raw-info": "Informacje Redis"
}

@ -1,11 +1,11 @@
{
"figure-x": "Błąd %1",
"error-events-per-day": "<code>%1</code> wydarzeń dziennie",
"error-events-per-day": "<code>%1</code> zdarzeń dziennie",
"error.404": "404 Nie znaleziono",
"error.503": "503 Usługa niedostępna",
"manage-error-log": "Zarządzaj dziennikiem błędów",
"export-error-log": "Eksportuj dziennik błędów (CSV)",
"clear-error-log": "Wyczyść dziennik błędów",
"export-error-log": "Eksportuj dziennik (CSV)",
"clear-error-log": "Wyczyść dziennik",
"route": "Scieżka",
"count": "Licznik",
"no-routes-not-found": "Hura! Żadnych błędów 404!",

@ -1,5 +1,5 @@
{
"events": "Wydarzenia",
"events": "Zdarzenia",
"no-events": "Brak zdarzeń",
"control-panel": "Panel zdarzeń",
"delete-events": "Usuń zdarzenia"

@ -1,7 +1,7 @@
{
"logs": "Logi",
"control-panel": "Logi Panelu Kontroli",
"control-panel": "Logi Panelu Sterowania",
"reload": "Przeładuj logi",
"clear": "Wyczyść Logi",
"clear-success": "Logi Wyczyszczone!"
"clear-success": "Logi wyczyszczone!"
}

@ -1,12 +1,12 @@
{
"custom-css": "Własny CSS",
"custom-css.description": "Wpisz własne deklaracje CSS tutaj, będą one zastosowane do wszystkich styli.",
"custom-css.description": "Wprowadź tu własne deklaracje CSS, będą one zastosowane po wszystkich innych stylach.",
"custom-css.enable": "Włącz własne style CSS",
"custom-header": "Własny nagłówek",
"custom-header.description": "Wpisz tutaj kod HTML (JavaScript, tagi <code>&lt;meta&gt;</code>) który ma być dołączony do sekcji <code>&lt;head&gt;</code> w szablonie forum.",
"custom-header.enable": "Włącz własny nagłówek",
"custom-css.livereload": "Włącz żywe przeładowanie",
"custom-css.livereload": "Włącz dynamiczne przeładowanie",
"custom-css.livereload.description": "Włącz to, aby zmusić wszystkie sesje do odświeżenia na każdym urządzeniu na twoim koncie gdziekolwiek klikniesz zapisz."
}

@ -1,7 +1,7 @@
{
"you-are-on": "Informacja - Jesteś na <strong>%1:%2</strong>",
"nodes-responded": "%1 nodes odpowiedziały w ciągu %2ms!",
"host": "Host",
"nodes-responded": "%1 węzły odpowiedziały w ciągu %2ms!",
"host": "host",
"pid": "pid",
"nodejs": "nodejs",
"online": "online",

@ -8,8 +8,8 @@
"delete": "Usuń",
"enable": "Włącz",
"disable": "Wyłącz",
"control-panel": "Ustawienia Nagród",
"new-reward": "Nowa Nagroda",
"control-panel": "Ustawienia nagród",
"new-reward": "Nowa nagroda",
"alert.delete-success": "Pomyślnie usunięto nagrodę",
"alert.no-inputs-found": "Niepoprawnie dodana nagroda ",

@ -8,12 +8,12 @@
"container.well": "Well",
"container.jumbotron": "Jumbotron",
"container.panel": "Panel",
"container.panel-header": "Panel nagłówka",
"container.panel-header": "Nagłówek panelu",
"container.panel-body": "Zawartość panelu",
"container.alert": "Alarm",
"alert.confirm-delete": "Czy na pewno chcesz usunąć ten widget?",
"alert.updated": "Widżety zaktualizowane",
"alert.update-success": "Pomyślnie widżety zostały zaktualizowane"
"alert.update-success": "Widżety zostały pomyślnie zaktualizowane"
}

@ -8,7 +8,7 @@
"page-views-seven": "Ostatnie 7 dni",
"page-views-thirty": "Ostatnie 30 dni",
"page-views-last-day": "Ostatnie 24 godziny",
"page-views-custom": "Własna zakres dat",
"page-views-custom": "Własny zakres dat",
"page-views-custom-start": "Początek zakresu",
"page-views-custom-end": "Koniec zakresu",
"page-views-custom-help": "Wprowadź zakres dat dla wyświetl strony, które chciałbyś zobaczyć. Jeśli brakuje możliwości wybory daty, akceptowalny format to <code>YYYY-MM-DD</code>",
@ -33,12 +33,12 @@
"restart-required": "Wymagany restart",
"search-plugin-installed": "Wyszukiwarka jest zainstalowana",
"search-plugin-not-installed": "Wyszukiwarka nie jest zainstalowana",
"search-plugin-tooltip": "Zainstaluj wtyczkę wyszukiwania ze strony wtyczek, aby aktywować funkcjonalność szukania",
"search-plugin-tooltip": "Zainstaluj wtyczkę wyszukiwania ze strony wtyczek, aby aktywować funkcję szukania",
"control-panel": "Zarządzanie systemem",
"reload": "Odśwież",
"restart": "Restart",
"restart-warning": "Przeładowanie lub Restart NodeBB spowoduje przerwanie wszystkich istniejących połączeń na kilka sekund.",
"restart-warning": "Przeładowanie lub restart NodeBB spowoduje przerwanie wszystkich istniejących połączeń na kilka sekund.",
"maintenance-mode": "Tryb konserwacji",
"maintenance-mode-title": "Kliknij tutaj aby skonfigurować tryb konserwacji dla NodeBB",
"realtime-chart-updates": "Wykresy aktualizowane na żywo",
@ -60,10 +60,10 @@
"recent": "Ostatnie",
"unread": "Nieprzeczytane",
"high-presence-topics": "Tematy wysokiej obecności",
"high-presence-topics": "Popularne tematy",
"graphs.page-views": "Wyświetlenia strony",
"graphs.unique-visitors": "Unikalni Użytkownicy",
"graphs.registered-users": "Zarejestrowani Użytkownicy",
"graphs.anonymous-users": "Anonimowi Użytkownicy"
"graphs.unique-visitors": "Unikalni użytkownicy",
"graphs.registered-users": "Zarejestrowani użytkownicy",
"graphs.anonymous-users": "Anonimowi użytkownicy"
}

@ -8,8 +8,8 @@
"id": "ID: <small>opcjonalnie</small>",
"properties": "Ustawienia:",
"only-admins": "Pokazuj tylko administracji",
"only-global-mods-and-admins": "Pokazuj tylko globalnym moderatorom oraz administracji",
"only-admins": "Pokazuj tylko administratorom",
"only-global-mods-and-admins": "Pokazuj tylko globalnym moderatorom oraz administratorom",
"only-logged-in": "Pokazuj tylko zalogowanym użytkownikom",
"only-guest": "Pokazuj tylko gościom",
"open-new-window": "Otwórz w nowym oknie",
@ -17,12 +17,12 @@
"installed-plugins-required": "Wymagane zainstalowane wtyczki:",
"search-plugin": "Wyszukiwarka",
"btn.delete": "Usunąć",
"btn.delete": "Usuń",
"btn.disable": "Wyłącz",
"btn.enable": "Włącz",
"available-menu-items": "Dostępne obiekty menu",
"custom-route": "Niestandardowa ścieżka",
"core": "core",
"core": "system",
"plugin": "wtyczka"
}

@ -1,5 +1,5 @@
{
"post-sharing": "Udostępnianie postów",
"info-plugins-additional": "Wtyczki mogą dodać dodatkowe platformy do udostępniania postów",
"save-success": "Pomyślnie zapisano sieci udostępniania postów!"
"save-success": "Pomyślnie zapisano!"
}

@ -1,9 +1,9 @@
{
"notifications": "Powiadomienia",
"chat-messages": "Wiadomości czatu",
"play-sound": "Otwórz",
"play-sound": "Odtwórz",
"incoming-message": "Przychodzące wiadomości",
"outgoing-message": "Wychodzące wiadomości",
"upload-new-sound": "Prześlij nowy dźwięk",
"saved": "Ustawienia Zapisane"
"saved": "Ustawienia zapisane"
}

@ -10,9 +10,9 @@
"custom-class": "Niestandardowa klasa",
"num-recent-replies": "# z ostatnich odpowiedzi",
"ext-link": "Zewnętrzny odnośnik",
"is-section": "Traktuj tą kategorię jako sekcję",
"is-section": "Traktuj tę kategorię jako sekcję",
"upload-image": "Prześlij obrazek",
"delete-image": "Usunąć",
"delete-image": "Usuń",
"category-image": "Obrazek kategorii",
"parent-category": "Kategoria nadrzędna",
"optional-parent-category": "(Opcjonalne) Kategoria nadrzędna",
@ -21,8 +21,8 @@
"optional-clone-settings": "(Opcjonalnie) Spoiowanie ustawień z kategorii",
"purge": "Usuń kategorię",
"enable": "Włączona",
"disable": "Wyłączona",
"enable": "Włącz",
"disable": "Wyłącz",
"edit": "Edytuj",
"select-category": "Wybierz kategorię",
@ -50,10 +50,10 @@
"analytics.topics-daily": "<strong>Ilustracja 3</strong>&ndash; Dzienne tematy tworzone w tej kategorii</small>",
"analytics.posts-daily": "<strong>Ilustracja 4</strong> &ndash; Dzienne posty pisane w tej kategorii</small>",
"alert.created": "Stworzony",
"alert.created": "Utworzony",
"alert.create-success": "Kategoria pomyślnie dodana!",
"alert.none-active": "Nie masz aktywnych kategorii.",
"alert.create": "Stwórz kategorie",
"alert.create": "Utwórz kategorię",
"alert.confirm-moderate": "<strong>Czy jesteś pewien, że chcesz udzielić uprawnień moderatorskich dla tej grupy użytkowników?</strong>Ta grupa jest publiczna i każdy użytkownik może do niej dołączyć.",
"alert.confirm-purge": "<p class=\"lead\">Czy na pewno chcesz wymazać tą kategorię \"%1\"?</p><h5><strong class=\"text-danger\">Uwaga!</strong> Wszystkie tematy oraz posty z tej kategorii zostaną wymazane!</h5><p class=\"help-block\">Wymazanie kategorii skasuje wszystkie tematy, posty oraz skasuję kategorię z bazy danych. Jeśli chcesz <em>tymczasowo</em>usunąć kategorię, będziesz musiał \"wyłączyć\" kategorię.</p>",
"alert.purge-success": "Kategoria usunięta!",
@ -63,7 +63,7 @@
"alert.updated-success": "ID kategorii %1 pomyślnie zaktualizowano.",
"alert.upload-image": "Prześlij obrazek kategorii",
"alert.find-user": "Znajdź użytkownika",
"alert.user-search": "Szukaj użytkownika tutaj...",
"alert.find-group": "Szukaj grupę",
"alert.group-search": "Szukaj grupę tutaj..."
"alert.user-search": "Wyszukaj użytkownika tutaj...",
"alert.find-group": "Znajdź grupę",
"alert.group-search": "Wyszukaj grupę tutaj..."
}

@ -2,12 +2,12 @@
"name": "Nazwa grupy",
"description": "Opis grupy",
"member-count": "Liczba użytkowników",
"system": "System grup",
"system": "Grupa systemowa",
"edit": "Edytuj",
"search-placeholder": "Szukaj",
"create": "Stwórz Grupę",
"description-placeholder": "Krótki opisz grupy",
"create-button": "Stwórz",
"create": "Utwórz grupę",
"description-placeholder": "Krótki opis grupy",
"create-button": "Utwórz",
"alerts.create-failure": "<strong>Uh-Oh</strong><p>Wystąpił problem podczas tworzenia grupy. Spróbuj ponownie później</p>",
"alerts.confirm-delete": "Czy na pewno chcesz usunąć tę grupę?",
@ -16,7 +16,7 @@
"edit.description": "Opis",
"edit.user-title": "Tytuł członków ",
"edit.icon": "Ikona grupy",
"edit.label-color": "Kolor Etykiety Grupy",
"edit.label-color": "Kolor etykiety grupy",
"edit.show-badge": "Pokazuj odznakę",
"edit.private-details": "Jeśli włączone, przystępowanie do grup wymaga zatwierdzenia przez właściciela grupy",
"edit.private-override": "Ostrzeżenie: Prywatne grupy są wyłączone w ustawieniach, co powoduje przesłonięcia opcji.",

@ -1,12 +1,12 @@
{
"lead": "Tutaj skonfigurują swoją czarną listę IP.",
"description": "Czasami ban konta użytkownika nie jest wystarczającym odstraszaczem i wtedy ograniczanie dostępu do forum dla konkretnego adresu IP lub zakresu adresów IP, są najlepszymi metodami ochrony forum. W tym przypadkach, możesz dodać adresy UP lub całe bloki CIDR do tej czarnej listy i będą one ograniczały możliwość logowania na forum lub rejestracji nowych kont.",
"lead": "Tutaj skonfiguruj swoją czarną listę IP.",
"description": "Czasami ban konta użytkownika nie jest wystarczającym zabezpieczeniem. Wtedy ograniczanie dostępu do forum dla konkretnego adresu IP lub zakresu adresów IP jest najlepszą metodą ochrony forum. W tym przypadku możesz dodać adresy IP lub całe bloki CIDR do czarnej listy i będą one miały zablokowaną możliwość logowania na forum lub rejestracji nowych kont.",
"active-rules": "Aktywne reguły",
"validate": "Sprawdzanie czarnej listy",
"apply": "Zastosuj czarną listę",
"hints": "Podpowiedzi składni",
"hint-1": "W każdej linii zdefiniuj pojedynczy adres IP. Możesz dodać bloki IP pod warunkiem, że spełniają one wymagania formatu CIDR (np. <code>192.168.100.0/22</code>).",
"hint-2": "Możesz dodawać komentarze porze rozpoczęcie linii symbolem <code>#</code>.",
"hint-2": "Możesz dodawać komentarze poprzez rozpoczęcie linii symbolem <code>#</code>.",
"validate.x-valid": "<strong>%1</strong> z <strong>%2</strong> reguła(-u) są poprawne.",
"validate.x-invalid": "Następujące <strong>%1</strong> reguły są niewłaściwe:",

@ -1,9 +1,9 @@
{
"none": "Twoje forum nie ma jeszcze żadnych tematów z tagami.",
"bg-color": "Kolor tła",
"text-color": "Kolor Tekstu",
"text-color": "Kolor tekstu",
"create-modify": "Utwórz oraz modyfikuj tagi",
"description": "Wybierz tagi poprzez klikanie oraz/lub przeciąganie, użyj przycisku shift do zaznaczenia wielu.",
"description": "Wybierz tagi poprzez klikanie lub przeciąganie, użyj przycisku shift do zaznaczenia wielu.",
"create": "Utwórz tag",
"modify": "Modyfikuj tagi",
"delete": "Usuń zaznaczone tagi",

@ -1,8 +1,8 @@
{
"users": "Użytkownicy",
"edit": "Edytuj",
"make-admin": "Nadaj Admina",
"remove-admin": "Odbierz Admin",
"make-admin": "Nadaj uprawnienia administratora",
"remove-admin": "Odbierz uprawnienia administratora",
"validate-email": "Zweryfikuj email",
"send-validation-email": "Wyślij email weryfikacyjny",
"password-reset-email": "Wyślij email resetowania hasła",
@ -11,7 +11,7 @@
"unban": "Odbanuj użytkownika(-ów)",
"reset-lockout": "Zresetuj blokadę",
"reset-flags": "Zresetuj flagi",
"delete": "Skasuj użytkownika(-ów)",
"delete": "Usuń użytkownika(-ów)",
"purge": "Usuń użytkownika(-ów) oraz zawartość",
"download-csv": "Pobierz CSV",
"invite": "Zaproś",
@ -22,10 +22,10 @@
"pills.no-posts": "Brak postów",
"pills.top-posters": "Najwięcej postów",
"pills.top-rep": "Najlepsza reputacja",
"pills.inactive": "Nieaktywny(-a)",
"pills.inactive": "Nieaktywny",
"pills.flagged": "Najwięcej flag",
"pills.banned": "Zbanowany(-a)",
"pills.search": "Wyszukiwanie użytkownków",
"pills.banned": "Zbanowany",
"pills.search": "Wyszukiwanie użytkowników",
"search.username": "Po nazwie użytkownika",
"search.username-placeholder": "Wpisz nazwę użytkownika, aby wyszukać",
@ -40,14 +40,14 @@
"inactive.12-months": "12 miesięcy",
"users.uid": "uid",
"users.username": "Nazwa użytkownika",
"users.email": "Adres e-mail",
"users.postcount": "Liczba postów",
"users.username": "nazwa użytkownika",
"users.email": "adres e-mail",
"users.postcount": "liczba postów",
"users.reputation": "reputacja",
"users.flags": "Flagi",
"users.joined": "Dołączono",
"users.last-online": "Ostatnio online",
"users.banned": "Zbanowany(-a)",
"users.flags": "flagi",
"users.joined": "dołączono",
"users.last-online": "ostatnio online",
"users.banned": "zbanowany",
"create.username": "Nazwa użytkownika",
"create.email": "Adres e-mail",
@ -59,10 +59,10 @@
"temp-ban.reason": "Powód <span class=\"text-muted\">(Opcjonalnie)</span>",
"temp-ban.hours": "Godzin(-a/-y)",
"temp-ban.days": "Dzień/Dni",
"temp-ban.explanation": "Wprowadzać długość (czas trwania) bana. Długość równa 0 będzie traktowana jako ban permanentny,",
"temp-ban.explanation": "Wprowadź długość (czas trwania) bana. Długość równa 0 będzie traktowana jako ban permanentny,",
"alerts.confirm-ban": "Czy na pewno chcesz zbanować tego użytkownika <strong>pernamentnie</strong>?",
"alerts.confirm-ban-multi": "\nCzy na pewno chcesz zbanować tych użytkowników <strong>pernamentnie</strong>?",
"alerts.confirm-ban": "Czy na pewno chcesz zbanować tego użytkownika <strong>permanentnie</strong>?",
"alerts.confirm-ban-multi": "Czy na pewno chcesz zbanować tych użytkowników <strong>permanentnie</strong>?",
"alerts.ban-success": "Użytkownik(-cy) zostali zbanowani!",
"alerts.button-ban-x": "Zbanowano %1 użytkownika (-ów)",
"alerts.unban-success": "Użytkownik(-cy) nie są już zbanowani!",
@ -75,11 +75,11 @@
"alerts.confirm-validate-email": "Czy chcesz zweryfikować email(-e) tego użytkownika (-ów)?",
"alerts.validate-email-success": "Zweryfikowano adresy email",
"alerts.password-reset-confirm": "Czy chcesz wysłać email (-e) resetujące hasło tego użytkownika(-ów)?",
"alerts.confirm-delete": "<b>Uwaga!</b><br/>Czy na pewno chcesz skasować użytkownika(-ów)?<br/>Ta akcja jest nieodwracalna! Zostanie skasowane tylko konto użytkownika, jego posty oraz tematy pozostaną niezmienione.",
"alerts.confirm-delete": "<b>Uwaga!</b><br/>Czy na pewno chcesz skasować użytkownika(-ów)?<br/>Ta operacja jest nieodwracalna! Zostanie skasowane tylko konto użytkownika, jego posty oraz tematy pozostaną niezmienione.",
"alerts.delete-success": "Użytkownik(-cy) zostali skasowani!",
"alerts.confirm-purge": "<b>Uwaga!</b><br/>Czy na pewno chcesz skasować użytkownika(-ów) oraz ich zawartość?<br/>Ta akcja jest nieodwracalna! Wszystkie dane użytkownika oraz jego zawartość zostaną wymazane.",
"alerts.create": "Stwórz użytkownika",
"alerts.button-create": "Stwórz",
"alerts.create": "Utwórz użytkownika",
"alerts.button-create": "Utwórz",
"alerts.button-cancel": "Anuluj",
"alerts.error-passwords-different": "Hasła muszą być takie same!",
"alerts.error-x": "<strong>Błąd</strong><p>%1</p>",

@ -1,6 +1,6 @@
{
"section-general": "Ogólne",
"general/dashboard": "Deska rozdzielcza",
"general/dashboard": "Pulpit menedżerski",
"general/homepage": "Strona startowa",
"general/navigation": "Nawigacja",
"general/languages": "Języki",
@ -20,24 +20,24 @@
"settings/general": "Ogólne",
"settings/reputation": "Reputacja",
"settings/email": "Email",
"settings/user": "Użytkownik",
"settings/group": "Grupa",
"settings/guest": "Gość",
"settings/uploads": "Przesłane",
"settings/user": "Użytkownicy",
"settings/group": "Grupy",
"settings/guest": "Goście",
"settings/uploads": "Przesyłanie plików",
"settings/post": "Posty",
"settings/chat": "Czat",
"settings/chat": "Czaty",
"settings/pagination": "Paginacja",
"settings/tags": "Tagi",
"settings/notifications": "Powiadomienia",
"settings/cookies": "Ciasteczka",
"settings/web-crawler": "Roboty internetowe",
"settings/sockets": "Sockets",
"settings/sockets": "Sockety",
"settings/advanced": "Zaawansowane",
"settings.page-title": "%1 Ustawienia",
"section-appearance": "Wygląd",
"appearance/themes": "Style",
"appearance/themes": "Motywy",
"appearance/skins": "Skórki",
"appearance/customise": "Niestandardowy HTML & CSS",
@ -46,27 +46,27 @@
"extend/widgets": "Widgety",
"extend/rewards": "Nagrody",
"section-social-auth": "Alternatywne Logowanie",
"section-social-auth": "Alternatywne logowanie",
"section-plugins": "Wtyczki",
"extend/plugins.install": "Zainstalowane wtyczki",
"section-advanced": "Zaawansowane",
"advanced/database": "Baza Danych",
"advanced/events": "Wydarzenia",
"advanced/database": "Baza danych",
"advanced/events": "Zdarzenia",
"advanced/logs": "Logi",
"advanced/errors": "Błędy",
"advanced/cache": "Pamięć",
"development/logger": "Loger",
"development/info": "Informacja",
"reload-forum": "Przeładuj Forum",
"reload-forum": "Przeładuj forum",
"restart-forum": "Restartuj forum",
"logout": "Wyloguj się",
"view-forum": "Zobacz Forum",
"view-forum": "Zobacz forum",
"search.placeholder": "Szukaj...",
"search.no-results": "Brak rezultatów...",
"search.no-results": "Brak wyników...",
"search.search-forum": "Szukaj w forum <strong></strong>",
"search.keep-typing": "Wpisz więcej, aby zobaczyć wyniki ...",
"search.start-typing": "Zacznij pisać, aby zobaczyć wyniki ...",

@ -1,7 +1,7 @@
{
"maintenance-mode": "Tryb konserwacji",
"maintenance-mode.help": "Kiedy forum jest w trybie konserwacji, wszystkie żądania będą przekierowane do statycznej strony oczekiwania. Administratorzy nie są objęci tym przekierowaniem i mogą normalnie korzystać ze strony.",
"maintenance-mode.message": "Wiadomość podczas konserwacji",
"maintenance-mode.message": "Komunikat na ekranie konserwacji",
"headers": "Nagłówek",
"headers.allow-from": "Ustaw ALLOW-FROM, aby umieścić NodeBB w ramce iFrame",
"headers.powered-by": "Dopasuj nagłówek \"Powered By\" wysyłany przez NodeBB",
@ -10,7 +10,7 @@
"headers.acam": "Access-Control-Allow-Methods",
"headers.acah": "Access-Control-Allow-Headers",
"traffic-management": "Zarządzanie ruchem",
"traffic.help": "NodeBB jest dostarczane z modułem, który automatycznie blokuje żądania w sytuacjach wysokiego ruchu. Tutaj możesz zmienić te ustawienia, ale ustawienia początkowe są dobrym punktem wyjścia w większości sytuacji.",
"traffic.help": "System NodeBB jest dostarczany z modułem, który automatycznie blokuje żądania w przypadku nadmiernego ruchu. Tutaj możesz zmienić te ustawienia, ale ustawienia początkowe są dobrym punktem wyjścia w większości sytuacji.",
"traffic.enable": "Włącz zarządzanie ruchem",
"traffic.event-lag": "Próg opóźnienia pętli zdarzeń (w milisekundach)",
"traffic.event-lag-help": "Obniżenie tej wartości spowoduje krótsze ładowanie stron, ale równocześnie wyświetli komunikat \"excessive load\" dla większej liczby użytkowników (wymagany restart).",

@ -1,37 +1,37 @@
{
"email-settings": "Ustawienia Poczty",
"address": "Adres Email",
"address-help": "Ten adres email referuje do adresu, który odbiora zobaczy w polach \"Od\" oraz \"Odpowiedz do\" wiadomości email.",
"email-settings": "Ustawienia poczty",
"address": "Adres email",
"address-help": "Ten adres email odbiorca zobaczy w polach \"Od\" oraz \"Odpowiedz do\" wiadomości email.",
"from": "Pole Od",
"from-help": "Nazwa \"Od\" widoczna w wiadomościach email",
"smtp-transport": "Transport SMTP",
"smtp-transport.enabled": "Używaj zewnętrznego serwera email, aby wysyłać wiadomości email.",
"smtp-transport-help": "Możesz wybrać z listy dobrze znanych usług lub wprowadzić własne.",
"smtp-transport-help": "Możesz wybrać z listy dobrze znanych usług lub wprowadzić własne ustawienia.",
"smtp-transport.service": "Wybierz usługę",
"smtp-transport.service-custom": "Własna usługa",
"smtp-transport.service-custom": "Usługa niestandardowa",
"smtp-transport.service-help": "Wybierz nazwę usługi powyżej w celu wykorzystania jej parametrów. Alternatywnie, wybierz \"Własna usługa\" i wpisz szczegóły poniżej.",
"smtp-transport.gmail-warning1": "Zdarzały się raporty dot. usługi Gmail nie działającej na kontach z podwyższonym bezpieczeństwem. W takim przypadku będziesz musiał <a href=\"https://www.google.com/settings/security/lesssecureapps\">skonfigurować swoje konto Gmail, aby dopuszczało mniej bezpieczne aplikacji</a>. ",
"smtp-transport.gmail-warning2": "W celu uzyskania dalszych informacji o tym rozwiązaniu, proszę zapoznać się z artykułem NodeMailer dot. tego zagadnienia.</a>Alternatywą byłoby wykorzystanie zewnętrznej wtyczki obsługi email np. SendGrid, Mailgun itp. <a href=\"{config.relative_path}/admin/extend/plugins\">Przeglądaj dostępne wtyczki tyutaj</a>.",
"smtp-transport.host": "Host SMTP",
"smtp-transport.port": "Port SMTP",
"smtp-transport.security": "Connection security",
"smtp-transport.security-encrypted": "Encrypted",
"smtp-transport.security": "Bezpieczeństwo połączenia",
"smtp-transport.security-encrypted": "Szyfrowane",
"smtp-transport.security-starttls": "StartTLS",
"smtp-transport.security-none": "None",
"smtp-transport.security-none": "Bez szyfrowania",
"smtp-transport.username": "Nazwa użytkownika",
"smtp-transport.username-help": "<b>Dla usługi Gmail</b> wprowadź tutaj pełny adres email, w szczególności jeśli korzystasz z domeny zrządzanej przez G Suite.",
"smtp-transport.password": "Hasło",
"template": "Edytuj szablon email-a",
"template.select": "Wybierz szablon email-a",
"template.revert": "Przywróć orginał",
"template.revert": "Przywróć oryginalny szablon",
"testing": "Testowanie email",
"testing.select": "Wybierz szablon email-a",
"testing.send": "Wyślij testowy email",
"testing.send-help": "Wiadomość testowa email zostanie wysłana na adres aktualnie zalogowanego użytkownika.",
"subscriptions": "Subskrypcje email",
"subscriptions.disable": "Wyłącz emaile powiadomień subskrybentów",
"subscriptions.disable": "Wyłącz powiadomienia subskrybentów",
"subscriptions.hour": "Godzina podsumowania",
"subscriptions.hour-help": "Proszę wprowadzić liczbę odpowiadającej godzinie, o które ma być planowane wysłanie mailowego przeglądu (np. <code>0</code> dla północy lub <code>17</code> dla 17:00). Należy pamiętać, że godzina jest godziną serwera i nie koniecznie musi odpowiadać czasowi lokalnemu administratora. Przybliżony czas serwera teraz to: <span id=\"serverTime\"></span><br />Następny przegląd mailowy jest zaplanowany do wysłania o <span id=\"nextDigestTime\"></span>"
}

@ -3,12 +3,12 @@
"title": "Tytuł strony",
"title.url": "URL",
"title.url-placeholder": "Adres URL strony tytułowej",
"title.url-help": "W momencie kliknięcia na tytule, wysyłaj użytkownika na ten adres. Jeśli pozostawione puste, użytkownik będzie wysyłany do indeksu forum.",
"title.url-help": "W momencie kliknięcia na tytule, użytkownik zostanie przeniesiony na ten adres. Jeśli to pole będzie puste, użytkownik zostanie przeniesiony do strony głównej forum.",
"title.name": "Nazwa twojej społeczności",
"title.show-in-header": "Pokazuj tytuł strony w nagłówku",
"browser-title": "Tytuł karty przeglądarki",
"browser-title-help": "Jeśli nie wyspecyfikowano tytułu karty przeglądarki, zostanie użyty tytuł strony",
"title-layout": "Ułożenie tytułu",
"title-layout": "Struktura tytułu karty przeglądarki",
"title-layout-help": "Zdefiniuj strukturę, jaką będzie miał tytuł karty przeglądarki np. &#123;pageTitle&#125; | &#123;browserTitle&#125;",
"description.placeholder": "Krótki opis twojej społeczności",
"description": "Opis strony",
@ -20,7 +20,7 @@
"logo.upload": "Prześlij",
"logo.url": "Adres URL",
"logo.url-placeholder": "Adres URL logo strony",
"logo.url-help": "W momencie kliknięcia na logo, wysyłaj użytkownika na ten adres. Jeśli pozostawione puste, użytkownik będzie wysyłany do indeksu forum.",
"logo.url-help": "W momencie kliknięcia na logo, użytkownik zostanie przeniesiony na ten adres. Jeśli to pole będzie puste, użytkownik zostanie przeniesiony do strony głównej forum.",
"logo.alt-text": "Cały tekst",
"log.alt-text-placeholder": "Alternatywny tekst dla dostępności",
"favicon": "Favikona",

@ -1,8 +1,8 @@
{
"general": "Ogólne",
"private-groups": "Prywatne grupy",
"private-groups.help": "Jeśli włączone, dołączenie do grup wymaga zatwierdzenia przez właściciela grupy <em>(domyślnie: włączone)</em>",
"private-groups.warning": "<strong>Uwaga!</strong>Jeśli ta opcja jest wyłączona i masz prywatne grupy, automatycznie stają się one publiczne.",
"private-groups": "Grupy prywatne",
"private-groups.help": "Jeśli włączone, dołączenie do grupy wymaga zatwierdzenia przez właściciela grupy <em>(domyślnie: włączone)</em>",
"private-groups.warning": "<strong>Uwaga!</strong> Jeśli ta opcja jest wyłączona i masz prywatne grupy, automatycznie stają się one publiczne.",
"allow-creation": "Zezwalaj na tworzeni grup",
"allow-creation-help": "Jeśli włączone, użytkownicy mogą tworzyć grupy <em>(domyślnie: wyłączone)</em>",
"max-name-length": "Maksymalna długość nazwy grupy",

@ -1,6 +1,6 @@
{
"handles": "Uchwyty gości",
"handles.enabled": "Zezwalaj na uchwyty gości",
"handles": "Podpisywanie się gości",
"handles.enabled": "Zezwalaj gościom na podpisywanie się",
"handles.enabled-help": "Ta opcja udostępnia gościom nowe pole, które umożliwia wybranie nazwy, pod którą będą publikowane ich posty. Jeśli wyłączone, będą po prostu nazywani \"Gość\"",
"privileges": "Uprawnienia gości",
"privileges.can-search": "Zezwalaj gościom na szukanie bez logowania",

@ -1,11 +1,11 @@
{
"sorting": "Sortowanie postów",
"sorting.post-default": "Domyślne sortowanie postów",
"sorting.oldest-to-newest": "Najstarsze do Najnowszych",
"sorting.newest-to-oldest": "Najnowsze do Najstarszych",
"sorting.oldest-to-newest": "Najstarsze do najnowszych",
"sorting.newest-to-oldest": "Najnowsze do najstarszych",
"sorting.most-votes": "Najwięcej głosów",
"sorting.topic-default": "Domyślne sortowanie tematów",
"restrictions": "Ograniczenia pistania",
"restrictions": "Ograniczenia pisania",
"restrictions.post-queue": "Włącz kolejkę postów",
"restrictions.post-queue-help": "Włączenie kolejki postów będzie dodawało posty nowych użytkowników do kolejki w celu zatwierdzenia.",
"restrictions.seconds-between": "Sekund pomiędzy postami",
@ -41,7 +41,7 @@
"composer": "Ustawienia okna pisania",
"composer-help": "Następujące ustawienia zarządzają funkcjonalnością oraz/lub wyglądem okna pisania postów wyświetlanego\n\t\t\t\tużytkownikom kiedy tworzą nowe tematy lub odpowiadają w istniejących.",
"composer.show-help": "Pokazuj zakładkę \"Pomoc\"",
"composer.enable-plugin-help": "Zezwalaj wtyczką na dodawanie zawartości do zakładki pomocy",
"composer.enable-plugin-help": "Zezwalaj wtyczkom na dodawanie zawartości do zakładki pomocy",
"composer.custom-help": "Własny tekst pomocy",
"ip-tracking": "Śledzenie IP",
"ip-tracking.each-post": "Śledź adres IP każdego z postów"

@ -1,6 +1,6 @@
{
"reconnection": "Ustawienia ponownego łączenia",
"max-attempts": "Maksymalna liczna prób połączenia",
"max-attempts": "Maksymalna liczba prób połączenia",
"default-placeholder": "Domyślnie: %1",
"delay": "Opóźnienie ponownego łączenia"
}

@ -1,5 +1,5 @@
{
"tag": "Ustawienia Tagów",
"tag": "Ustawienia tagów",
"min-per-topic": "Minimalna liczba tagów na temat",
"max-per-topic": "Maksymalna liczba tagów na temat",
"min-length": "Minimalna długość taga",

@ -1,15 +1,15 @@
{
"posts": "Posty",
"allow-files": "Zezwalaj użytkownikom wysyłać pliki",
"private": "Rób wysyłane pliki prywatnymi",
"max-image-width": "Zmniejszaj obrazy do specyficznej szerokości (w pikselach)",
"private": "Oznaczaj wysyłane pliki jako prywatne",
"max-image-width": "Zmniejszaj obrazy do zadanej szerokości (w pikselach)",
"max-image-width-help": "(w pikselach, domyślnie: 760px; ustaw 0, aby wyłączyć)",
"max-file-size": "Maksymalny rozmiar plików (w KiB)",
"max-file-size-help": "(w kilobajtach, domyślnie: 2,048 KiB)",
"allow-topic-thumbnails": "Zezwalaj użytkownikom na wysyłanie obrazków tematów",
"max-file-size-help": "(w kilobajtach, domyślnie: 2048 KiB)",
"allow-topic-thumbnails": "Zezwalaj użytkownikom na ustawianie miniaturek tematów",
"topic-thumb-size": "Rozmiar miniatury tematu",
"allowed-file-extensions": "Dozwolone typy plików",
"allowed-file-extensions-help": "Tutaj wprowadź oddzielone kropką rozszerzenia plików (np. <code>pdf,xls,doc</code>). Pusta lista oznacza, że wszystkie rozszerzenia są dozwolone.",
"allowed-file-extensions-help": "Wprowadź rozdzielone przecinkami rozszerzenia plików (np. <code>pdf,xls,doc</code>). Pusta lista oznacza, że wszystkie rozszerzenia są dozwolone.",
"profile-avatars": "Profilowe awatary",
"allow-profile-image-uploads": "Zezwalaj użytkownikom na ładowanie obrazów profilowych",
"convert-profile-image-png": "Konwertuj przesłane obrazy profilowe na PNG",
@ -20,9 +20,9 @@
"max-profile-image-size": "Maksymalny rozmiar obrazka profilowego",
"max-profile-image-size-help": "(w kilobajtach, domyślnie: 256 KiB)",
"max-cover-image-size": "Maksymalny rozmiar obrazka profilowego",
"max-cover-image-size-help": "(w kilobajtach, domyślnie: 2,048 KiB)",
"max-cover-image-size-help": "(w kilobajtach, domyślnie: 2048 KiB)",
"keep-all-user-images": "Zachowaj stare wersje awatarów oraz okładek profili na serwerze",
"profile-covers": "Okładki profili",
"default-covers": "Domyślne obrazy profilowe",
"default-covers-help": "Dodaj udzieloną kropkami listę domyślnych obrazów dla kont użytkowników, którzy nie wysłali swoich własnych obrazów profilowych."
"default-covers-help": "Dodaj rozdzieloną przecinkami listę domyślnych obrazów dla kont użytkowników, którzy nie wysłali swoich własnych obrazów profilowych."
}

@ -1,38 +1,38 @@
{
"authentication": "Autoryzacja",
"authentication": "Uwierzytelnianie",
"allow-local-login": "Zezwalaj na lokalne logowanie",
"require-email-confirmation": "Wymagaj potwierdzenia adresu email",
"email-confirm-interval": "Użytkownik nie może ponownie wysłać email z potwierdzeniem, dopóki",
"email-confirm-email2": "minut upłynęło",
"email-confirm-interval": "Użytkownik nie może ponownie wysłać email z potwierdzeniem, dopóki nie minie",
"email-confirm-email2": "minut",
"allow-login-with": "Zezwalaj na logowanie przy użyciu",
"allow-login-with.username-email": "Nazwy użytkownika lub adresu email",
"allow-login-with.username": "Tylko Nazwy Użytkownia",
"allow-login-with.username": "Tylko nazwy użytkownika",
"allow-login-with.email": "Tylko adresu email",
"account-settings": "Ustawienia konta",
"disable-username-changes": "Wyłącz możliwość zmiany nazwy użytkownika",
"disable-email-changes": "Wyłącz możliwość zmiany adresu email",
"disable-password-changes": "Wyłącz możliwość zmiany hasła",
"allow-account-deletion": "Zezwalaj na usunięcie konta",
"user-info-private": "Ukrywaj listę oraz dane użytkowników przed goścmi",
"user-info-private": "Ukrywaj listę oraz dane użytkowników przed gośćmi",
"hide-fullname": "Ukrywaj pełne imię i nazwisko przed innymi użytkownikami",
"hide-email": "Ukryj adresy email użytkowników.",
"themes": "Style",
"disable-user-skins": "Uniemożliwić użytkownikom wybranie niestandardowej skórę",
"hide-email": "Ukryj adresy email użytkowników",
"themes": "Motywy",
"disable-user-skins": "Nie zezwalaj użytkownikom na wybranie niestandardowej skórki",
"account-protection": "Ochrona konta",
"login-attempts": "Prób logowania na godzinę",
"login-attempts": "Maksymalna liczba prób logowania na godzinę",
"login-attempts-help": "Jeśli liczba prób logowania na konto użytkownika przekroczy ten próg, to konto zostanie zablokowane na zdefiniowany wcześniej czas",
"lockout-duration": "Czas trwania blokady konta (minuty)",
"login-days": "Liczba dni zapamiętywania sesji logowania użytkownika",
"password-expiry-days": "Wymuś resetowanie hasła po określonej liczbie dni",
"registration": "Rejestracja Użytkownika",
"registration": "Rejestracja użytkownika",
"registration-type": "Typ rejestracji",
"registration-type.normal": "Normalna",
"registration-type.admin-approval": "Zatwierdzenie Admina",
"registration-type.admin-approval-ip": "Zatwierdzenie Admina dla IP",
"registration-type.normal": "Standardowa",
"registration-type.admin-approval": "Zatwierdzenie administratora",
"registration-type.admin-approval-ip": "Zatwierdzenie administratora dla IP",
"registration-type.invite-only": "Tylko zaproszenia",
"registration-type.admin-invite-only": "Tylko zaproszenia Admina",
"registration-type.admin-invite-only": "Tylko zaproszenia administratora",
"registration-type.disabled": "Brak rejestracji",
"registration-type.help": "Normalna - Użytkownicy mogą się rejestrować na stronie /register.<br/>\nZatwierdzenie Admina - Rejestracja użytkowników trafia do <a href=\"%1/admin/manage/registration\">kolejki zatwierdzeń</a> for administrators.<br/>\nZatwierdzenie Admina dla IP - Normalna dla nowych użytkowników, Zatwierdzenie Admina dla adresów IP, które mają już konta.<br/>\nTylko zaproszenia - Użytkownicy mogą zapraszać innych poprzez stronę <a href=\"%1/users\" target=\"_blank\">users</a>.<br/>\nTylko zaproszenia Admina - Tylko admini mogą zapraszać innych poprzez stronę <a href=\"%1/users\" target=\"_blank\">users</a> oraz <a href=\"%1/admin/manage/users\">admin/manage/users</a>.<br/>\nBrak rejestracji - Brak rejestracji użytkowników.<br/>",
"registration-type.help": "Standardowa - Użytkownicy mogą się rejestrować na stronie /register.<br/>\nZatwierdzenie administratora - Rejestracja użytkowników trafia do <a href=\"%1/admin/manage/registration\">kolejki zatwierdzeń</a> administratora.<br/>\nZatwierdzenie administratora dla IP - Standardowa dla nowych użytkowników, Zatwierdzenie administratora dla adresów IP, które mają już konta.<br/>\nTylko zaproszenia - Użytkownicy mogą zapraszać innych poprzez stronę <a href=\"%1/users\" target=\"_blank\">users</a>.<br/>\nTylko zaproszenia administratora - Tylko administratorzy mogą zapraszać innych poprzez stronę <a href=\"%1/users\" target=\"_blank\">users</a> oraz <a href=\"%1/admin/manage/users\">admin/manage/users</a>.<br/>\nBrak rejestracji - Brak rejestracji użytkowników.<br/>",
"registration.max-invites": "Maksymalnie liczba zaproszeń na użytkownika",
"max-invites": "Maksymalnie liczba zaproszeń na użytkownika",
"max-invites-help": "0 dla braku ograniczeń. Administratorzy otrzymują nieskończoną liczbę zaproszeń<br>Aplikowane tylko dla \"Tylko zaproszeni\"",
@ -40,25 +40,25 @@
"invite-expiration-help": "Liczba dni, po których wygasają zaproszenia.",
"min-username-length": "Minimalna długość nazwy użytkownika",
"max-username-length": "Maksymalna długość nazwy użytkownika",
"min-password-length": "Maksymalna długość hasła",
"min-password-strength": "Minimalna długość hasła",
"min-password-length": "Minimalna długość hasła",
"min-password-strength": "Minimalna siła hasła",
"max-about-me-length": "Maksymalna długość pola O mnie",
"terms-of-use": "Warunki użytkowania forum <small>(Pozostaw puste, aby wyłączyć)</small>",
"user-search": "Wyszukiwanie użytkownków",
"user-search-results-per-page": "Liczba wyników do wyświetlenia",
"default-user-settings": "Domyślne ustawienie użytkownia",
"default-user-settings": "Domyślne ustawienia użytkownika",
"show-email": "Pokazuj adres email",
"show-fullname": "Pokazuj imię",
"restrict-chat": "Pozwalaj tylko wiadomości chat od użytkowników, których śledzę",
"outgoing-new-tab": "Otwieraj odnośniki wychodzące w nowej karcie",
"show-fullname": "Pokazuj pełną nazwę uzytkownika",
"restrict-chat": "Pozwalaj na wiadomości chat tylko od użytkowników, których śledzę",
"outgoing-new-tab": "Otwieraj odnośniki wychodzące na nowej karcie",
"topic-search": "Włącz wyszukiwanie wewnątrz tematów",
"digest-freq": "Zapisz się do podsumowań",
"digest-freq": "Podsumowania - tryb",
"digest-freq.off": "Wyłączone",
"digest-freq.daily": "Dzienny ",
"digest-freq.weekly": "Tygodniowy",
"digest-freq.monthly": "Miesięczny",
"email-chat-notifs": "Wyślij e-maila, jeśli dostanę nową wiadomość, a nie jestem on-line",
"email-post-notif": "Wyślij email, kiedy w tematach, które subskrybuję, pojawią się odpowiedzi",
"email-chat-notifs": "Wyślij powiadomienie email, jeśli dostanę nową wiadomość, a nie jestem on-line",
"email-post-notif": "Wyślij wiadomość email, kiedy w tematach, które subskrybuję, pojawią się odpowiedzi",
"follow-created-topics": "Śledź tematy, które stworzyłeś",
"follow-replied-topics": "Śledź tematy, w których się wypowiedziałeś "
}

@ -5,6 +5,6 @@
"disable-rss-feeds": "Wyłącz kanały RSS",
"disable-sitemap-xml": "Wyłącz Sitemap.xml",
"sitemap-topics": "Liczba tematów do wyświetlenia w mapie strony",
"clear-sitemap-cache": "Wyczyść pamięć podręczną map strony",
"view-sitemap": "Zobacz mapę strony"
"clear-sitemap-cache": "Wyczyść pamięć podręczną mapy strony",
"view-sitemap": "Wyświetl mapę strony"
}

@ -10,11 +10,11 @@
"share_this_category": "Udostępnij tę kategorię",
"watch": "Obserwuj",
"ignore": "Ignoruj",
"watching": "Obserwowanie",
"ignoring": "Ignorowanie",
"watching.description": "Pokazuj tematy jako nieprzeczytane",
"ignoring.description": "Nie pokazuj tematów jako nieprzeczytane",
"watch.message": "Włączyłeś powiadomienia dla tej kategorii oraz subkategorii.",
"ignore.message": "Wyłączyłeś powiadomienia dla tej kategorii oraz subkategorii.",
"watching": "Obserwowane",
"ignoring": "Ignorowane",
"watching.description": "Pokazuj tematy w nieprzeczytanych",
"ignoring.description": "Nie pokazuj tematów w nieprzeczytanych",
"watch.message": "Włączyłeś powiadomienia dla tej kategorii oraz wszystkich podkategorii.",
"ignore.message": "Wyłączyłeś powiadomienia dla tej kategorii oraz wszystkich podkategorii.",
"watched-categories": "Obserwowane kategorie"
}

@ -6,15 +6,15 @@
"greeting_with_name": "Witaj %1",
"welcome.text1": "Dziękujemy za rejestrację w %1",
"welcome.text2": "Aby aktywować swoje konto, musisz potwierdzić, że skorzystałeś z własnego adresu e-mail.",
"welcome.text3": "Administrator zaakceptował twoje podanie o rejestrację. Możesz się zalogować, używając swojej nazwy użytkownika i hasła.",
"welcome.cta": "Kliknij tutaj, by potwierdzić swój adres",
"welcome.text3": "Administrator zaakceptował twój wniosek o rejestrację. Możesz się zalogować, używając swojej nazwy użytkownika i hasła.",
"welcome.cta": "Kliknij tutaj, aby potwierdzić swój adres",
"invitation.text1": "%1 zaprasza do dołączenia do %2",
"invitation.ctr": "Kliknij tutaj, aby utworzyć konto.",
"reset.text1": "Otrzymaliśmy żądanie przywrócenia twojego hasła. Jeśli nie żądałeś przywrócenia hasła, zignoruj ten e-mail.",
"reset.text2": "Aby przywrócić swoje hasło, skorzystaj z poniższego odnośnika:",
"reset.cta": "Kliknij tu, by przywrócić swoje hasło",
"reset.notify.subject": "Hasło pomyślnie zmienione",
"reset.notify.text1": "Informujemy, że %1, twoje hasło zostało pomyślnie zmienione.",
"reset.cta": "Kliknij tu, aby przywrócić swoje hasło",
"reset.notify.subject": "Hasło zmienione pomyślnie",
"reset.notify.text1": "Informujemy, że twoje hasło zostało pomyślnie zmienione w %1",
"reset.notify.text2": "Jeśli nie wyraziłeś na to zgody, proszę niezwłocznie poinformować administratora.",
"digest.notifications": "Masz nowe powiadomienia od %1:",
"digest.latest_topics": "Ostatnie tematy z %1",
@ -24,16 +24,16 @@
"digest.day": "dzień",
"digest.week": "tydzień",
"digest.month": "miesiąc",
"digest.subject": "Digest for %1",
"digest.subject": "Podpis %1",
"notif.chat.subject": "Nowa wiadomość czatu od %1",
"notif.chat.cta": "Kliknij tutaj, by kontynuować konwersację",
"notif.chat.unsub.info": "To powiadomienie o czacie zostało Ci wysłane zgodnie z ustawieniami twojego konta.",
"notif.post.cta": "Kliknij tutaj, aby przeczytać cały temat.",
"notif.post.unsub.info": "To powiadomienie o poście zostało Ci wysłane zgodnie z ustawieniami twojego konta.",
"test.text1": "To jest e-mail testowy, aby sprawdzić, czy poprawnie skonfigurowałeś e-mailer w swoim NodeBB.",
"unsub.cta": "Kliknij tutaj, by zmienić te ustawienia",
"banned.subject": "Zostałeś zbanowany przez %1",
"banned.text1": "Użytkownik %1 został zbanowany przez %2.",
"unsub.cta": "Kliknij tutaj, aby zmienić te ustawienia",
"banned.subject": "Zostałeś zbanowany na %1",
"banned.text1": "Użytkownik %1 został zbanowany na %2.",
"banned.text2": "Ban potrwa do %1",
"banned.text3": "To jest powód, dla którego zostałeś zbanowany:",
"closing": "Dziękujemy!"

@ -72,11 +72,11 @@
"guest_posted_ago": "Gość napisał %1",
"last_edited_by": "ostatnio edytowany przez %1",
"norecentposts": "Brak ostatnich postów",
"norecenttopics": "Brak Ostatnich tematów",
"norecenttopics": "Brak ostatnich tematów",
"recentposts": "Ostatnie posty",
"recentips": "Adresy IP ostatnich logowań",
"moderator_tools": "Narzędzia dla moderatorów",
"away": "Z dala",
"away": "Zaraz wracam",
"dnd": "Nie przeszkadzać",
"invisible": "Niewidoczny",
"offline": "Niedostępny",
@ -101,7 +101,7 @@
"reconnecting-message": "Wygląda na to, że twoje połączenie z %1 zostało przerwane. Proszę czekać, gdy staramy się je odnowić.",
"play": "Odtwórz",
"cookies.message": "Ta strona używa plików cookies, by zapewnić Ci najlepsze działanie naszej strony.",
"cookies.accept": "Mam to!",
"cookies.accept": "Rozumiem!",
"cookies.learn_more": "Dowiedz się więcej",
"edited": "Edytowany",
"disabled": "Wyłączony",

@ -12,7 +12,7 @@
"reply-count": "Liczba odpowiedzi",
"at-least": "Przynajmniej",
"at-most": "Co najwyżej",
"relevance": "Stosowność",
"relevance": "Trafność",
"post-time": "Napisano",
"newer-than": "Nowsze niż",
"older-than": "Starsze niż",

@ -4,7 +4,7 @@
"topic_id_placeholder": "Podaj identyfikator tematu",
"no_topics_found": "Nie znaleziono żadnych tematów!",
"no_posts_found": "Nie znaleziono żadnych postów.",
"post_is_deleted": "Ten post jest usunięty",
"post_is_deleted": "Ten post jest usunięty!",
"topic_is_deleted": "Ten temat jest usunięty!",
"profile": "Profil",
"posted_by": "Napisane przez %1",
@ -17,7 +17,7 @@
"one_reply_to_this_post": "1 Odpowiedź",
"last_reply_time": "Ostatnia odpowiedź",
"reply-as-topic": "Odpowiedz na temat",
"guest-login-reply": "Zaloguj się, aby odpowiedzieć.",
"guest-login-reply": "Zaloguj się, aby odpowiedzieć",
"edit": "Edytuj",
"delete": "Usuń",
"purge": "Wymaż",

@ -4,13 +4,13 @@
"username": "Nazwa użytkownika",
"joindate": "Data rejestracji",
"postcount": "Liczba postów",
"email": "Adres e-mail",
"confirm_email": "Potwierdź e-mail",
"email": "Adres email",
"confirm_email": "Potwierdź email",
"account_info": "Informacje o koncie",
"ban_account": "Zbanuj Konto",
"ban_account": "Zbanuj konto",
"ban_account_confirm": "Na pewno chcesz zbanować tego użytkownika?",
"unban_account": "Odbanuj Konto",
"delete_account": "Skasuj konto",
"unban_account": "Odbanuj konto",
"delete_account": "Usuń konto",
"delete_account_confirm": "Jesteś pewny, że chcesz skasować swoje konto? <br /><strong>Tej operacji nie można cofnąć i utracisz wszystkie swoje dane</strong><br/><br/>Podaj swoją nazwę użytkownika, by potwierdzić skasowanie konta.",
"delete_this_account_confirm": "Na pewno chcesz usunąć to konto? <br /><strong>Tej operacji nie można cofnąć i nie będzie możliwości odzyskania swoich danych</strong><br /><br />",
"account-deleted": "Konto usunięte",
@ -92,7 +92,7 @@
"email_hidden": "Adres e-mail ukryty",
"hidden": "ukryty",
"paginate_description": "Dziel tematy i posty na strony zamiast używać nieskończonego przewijania",
"topics_per_page": "Tematów na Stronę",
"topics_per_page": "Tematów na stronę",
"posts_per_page": "Postów na stronę",
"notification_sounds": "Odtwarzaj dźwięk, gdy otrzymujesz powiadomienie",
"notifications_and_sounds": "Powiadomienia i dźwięki",
@ -111,7 +111,7 @@
"follow_topics_you_create": "Obserwuj tematy, które utworzyłeś",
"grouptitle": "Tytuł grupy",
"no-group-title": "Brak tytułu grupy",
"select-skin": "Wybierz Skórkę",
"select-skin": "Wybierz skórkę",
"select-homepage": "Wybierz stronę startową",
"homepage": "Strona startowa",
"homepage_description": "Wybierz stronę, jaką chcesz mieć ustawioną na domyślną, lub \"None\", jeśli chcesz używać domyślnej. ",
@ -129,8 +129,8 @@
"info.banned-reason-label": "Powód",
"info.banned-no-reason": "Nie podano powodu.",
"info.username-history": "Historia nazwy użytkownika",
"info.email-history": "Historia adresu e-mail",
"info.moderation-note": "Notka moderatora",
"info.moderation-note.success": "Notka nie została zapisana",
"info.email-history": "Historia adresu email",
"info.moderation-note": "Notatka moderatora",
"info.moderation-note.success": "Notatka została zapisana",
"info.moderation-note.add": "Dodaj notatkę"
}

@ -15,10 +15,10 @@
"smtp-transport.gmail-warning2": "有关此解决方法的更多信息,请参阅有关该问题的<a href=\"https://nodemailer.com/usage/using-gmail/\">NodeMailer 文章</a>。 另一种方法是利用 SendGridMailgun 等第三方电子邮件插件。<a href=\"{config.relative_path}/admin/extend/plugins\">点这儿以浏览可用的插件。</a>",
"smtp-transport.host": "SMTP 主机名",
"smtp-transport.port": "SMTP 端口",
"smtp-transport.security": "Connection security",
"smtp-transport.security-encrypted": "Encrypted",
"smtp-transport.security": "连接安全设置",
"smtp-transport.security-encrypted": "加密的",
"smtp-transport.security-starttls": "StartTLS",
"smtp-transport.security-none": "None",
"smtp-transport.security-none": "",
"smtp-transport.username": "用户名",
"smtp-transport.username-help": "<b>对于Gmail服务</b>请在这里输入完整的电子邮箱地址,尤其是如果您使用的是 Google Apps 托管的域名。",
"smtp-transport.password": "密码",

@ -46,20 +46,20 @@
"no-privileges": "您没有权限执行此操作。",
"category-disabled": "版块已禁用",
"topic-locked": "主题已锁定",
"post-edit-duration-expired": "您必须在发表 %1 秒后才能修改内容",
"post-edit-duration-expired-minutes": "在发表 %1 分钟后才能修改内容",
"post-edit-duration-expired-minutes-seconds": "发表 %1 分 %2 秒后才能修改内容",
"post-edit-duration-expired-hours": "发表 %1 小时后才能修改内容",
"post-edit-duration-expired-hours-minutes": "发表 %1 小时 2 分钟后才能修改内容",
"post-edit-duration-expired-days": "发表 %1 天后才能修改内容",
"post-edit-duration-expired-days-hours": "发表 %1 天 %2 小时后才能修改内容",
"post-delete-duration-expired": "您只能在发表 %1 秒后删除帖子",
"post-delete-duration-expired-minutes": "您只能在发表 %1 分钟后删除帖子",
"post-delete-duration-expired-minutes-seconds": "您只能在发表 %1 分 %2 秒后删除帖子",
"post-delete-duration-expired-hours": "您只能在发表 %1 小时后删除帖子",
"post-delete-duration-expired-hours-minutes": "您只能在发表 %1 小时 %2 分钟后删除帖子",
"post-delete-duration-expired-days": "您只能在发表 %1 天后删除帖子",
"post-delete-duration-expired-days-hours": "您只能在发表 %1 天 %2 小时后删除帖子",
"post-edit-duration-expired": "您只能在发表后 %1 秒内修改内容",
"post-edit-duration-expired-minutes": "您只能在发表后 %1 分钟内修改内容",
"post-edit-duration-expired-minutes-seconds": "您只能在发表后 %1 分 %2 秒内修改内容",
"post-edit-duration-expired-hours": "您只能在发表后 %1 小时后内修改内容",
"post-edit-duration-expired-hours-minutes": "您只能在发表后 %1 小时 2 分钟内修改内容",
"post-edit-duration-expired-days": "您只能在发表后 %1 天内修改内容",
"post-edit-duration-expired-days-hours": "您只能在发表后 %1 天 %2 小时内修改内容",
"post-delete-duration-expired": "您只能在发表后 %1 秒内删除帖子",
"post-delete-duration-expired-minutes": "您只能在发表后 %1 分钟内删除帖子",
"post-delete-duration-expired-minutes-seconds": "您只能在发表发 %1 分 %2 秒内删除帖子",
"post-delete-duration-expired-hours": "您只能在发表后 %1 小时内删除帖子",
"post-delete-duration-expired-hours-minutes": "您只能在发表后 %1 小时 %2 分钟内删除帖子",
"post-delete-duration-expired-days": "您只能在发表后 %1 天内删除帖子",
"post-delete-duration-expired-days-hours": "您只能在发表后 %1 天 %2 小时内删除帖子",
"cant-delete-topic-has-reply": "您不能删除您的主题,因为已有回复。",
"cant-delete-topic-has-replies": "您不能删除您的主题,因为已有 %1 条回复。",
"content-too-short": "请增添发帖内容,不能少于 %1 个字符。",

@ -5,7 +5,7 @@ var cacheController = module.exports;
cacheController.get = function (req, res) {
var postCache = require('../../posts/cache');
var groupCache = require('../../groups').cache;
var userSettingsCache = require('../../user').settingsCache;
var objectCache = require('../../database').objectCache;
var avgPostSize = 0;
var percentFull = 0;
@ -14,7 +14,7 @@ cacheController.get = function (req, res) {
percentFull = ((postCache.length / postCache.max) * 100).toFixed(2);
}
res.render('admin/advanced/cache', {
var data = {
postCache: {
length: postCache.length,
max: postCache.max,
@ -22,12 +22,6 @@ cacheController.get = function (req, res) {
percentFull: percentFull,
avgPostSize: avgPostSize,
},
userSettingsCache: {
length: userSettingsCache.length,
max: userSettingsCache.max,
itemCount: userSettingsCache.itemCount,
percentFull: ((userSettingsCache.length / userSettingsCache.max) * 100).toFixed(2),
},
groupCache: {
length: groupCache.length,
max: groupCache.max,
@ -35,5 +29,17 @@ cacheController.get = function (req, res) {
percentFull: ((groupCache.length / groupCache.max) * 100).toFixed(2),
dump: req.query.debug ? JSON.stringify(groupCache.dump(), null, 4) : false,
},
});
};
if (objectCache) {
data.objectCache = {
length: objectCache.length,
max: objectCache.max,
itemCount: objectCache.itemCount,
percentFull: ((objectCache.length / objectCache.max) * 100).toFixed(2),
dump: req.query.debug ? JSON.stringify(objectCache.dump(), null, 4) : false,
};
}
res.render('admin/advanced/cache', data);
};

@ -37,6 +37,9 @@ uploadsController.upload = function (req, res, filesIterator) {
uploadsController.uploadPost = function (req, res, next) {
uploadsController.upload(req, res, function (uploadedFile, next) {
if (!parseInt(req.body.cid, 10)) {
return next(new Error('[[error:category-not-selected]]'));
}
var isImage = uploadedFile.type.match(/image./);
if (isImage) {
uploadAsImage(req, uploadedFile, next);

@ -8,37 +8,52 @@ var nconf = require('nconf');
var session = require('express-session');
var _ = require('lodash');
var semver = require('semver');
var prompt = require('prompt');
var db;
var mongoModule = module.exports;
function isUriNotSpecified() {
return !prompt.history('mongo:uri').value;
}
mongoModule.questions = [
{
name: 'mongo:uri',
description: 'MongoDB connection URI: (leave blank if you wish to specify host, port, username/password and database individually)\nFormat: mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]',
default: nconf.get('mongo:uri') || '',
},
{
name: 'mongo:host',
description: 'Host IP or address of your MongoDB instance',
default: nconf.get('mongo:host') || '127.0.0.1',
ask: isUriNotSpecified,
},
{
name: 'mongo:port',
description: 'Host port of your MongoDB instance',
default: nconf.get('mongo:port') || 27017,
ask: isUriNotSpecified,
},
{
name: 'mongo:username',
description: 'MongoDB username',
default: nconf.get('mongo:username') || '',
ask: isUriNotSpecified,
},
{
name: 'mongo:password',
description: 'Password of your MongoDB database',
hidden: true,
default: nconf.get('mongo:password') || '',
hidden: true,
ask: isUriNotSpecified,
before: function (value) { value = value || nconf.get('mongo:password') || ''; return value; },
},
{
name: 'mongo:database',
description: 'MongoDB database name',
default: nconf.get('mongo:database') || 'nodebb',
ask: isUriNotSpecified,
},
];

@ -3,6 +3,36 @@
module.exports = function (db, module) {
var helpers = module.helpers.mongo;
var LRU = require('lru-cache');
var _ = require('lodash');
var pubsub = require('../../pubsub');
var cache = LRU({
max: 10000,
length: function () { return 1; },
maxAge: 0,
});
module.objectCache = cache;
pubsub.on('mongo:hash:cache:del', function (key) {
cache.del(key);
});
pubsub.on('mongo:hash:cache:reset', function () {
cache.reset();
});
module.delObjectCache = function (key) {
pubsub.publish('mongo:hash:cache:del', key);
cache.del(key);
};
module.resetObjectCache = function () {
pubsub.publish('mongo:hash:cache:reset');
cache.reset();
};
module.setObject = function (key, data, callback) {
callback = callback || helpers.noop;
if (!key || !data) {
@ -12,7 +42,11 @@ module.exports = function (db, module) {
delete data[''];
}
db.collection('objects').update({ _key: key }, { $set: data }, { upsert: true, w: 1 }, function (err) {
callback(err);
if (err) {
return callback(err);
}
module.delObjectCache(key);
callback();
});
};
@ -31,26 +65,48 @@ module.exports = function (db, module) {
if (!key) {
return callback();
}
db.collection('objects').findOne({ _key: key }, { _id: 0, _key: 0 }, callback);
module.getObjects([key], function (err, data) {
if (err) {
return callback(err);
}
callback(null, data && data.length ? data[0] : null);
});
};
module.getObjects = function (keys, callback) {
function getFromCache(next) {
setImmediate(next, null, keys.map(function (key) {
return _.clone(cache.get(key));
}));
}
if (!Array.isArray(keys) || !keys.length) {
return callback(null, []);
}
db.collection('objects').find({ _key: { $in: keys } }, { _id: 0 }).toArray(function (err, data) {
var nonCachedKeys = keys.filter(function (key) {
return !cache.get(key);
});
if (!nonCachedKeys.length) {
return getFromCache(callback);
}
db.collection('objects').find({ _key: { $in: nonCachedKeys } }, { _id: 0 }).toArray(function (err, data) {
if (err) {
return callback(err);
}
var map = helpers.toMap(data);
var returnData = [];
for (var i = 0; i < keys.length; i += 1) {
returnData.push(map[keys[i]]);
}
data.forEach(function (objectData) {
if (objectData) {
var key = objectData._key;
delete objectData._key;
cache.set(key, objectData);
}
});
callback(null, returnData);
getFromCache(callback);
});
};
@ -58,16 +114,10 @@ module.exports = function (db, module) {
if (!key) {
return callback();
}
field = helpers.fieldToString(field);
var _fields = {
_id: 0,
};
_fields[field] = 1;
db.collection('objects').findOne({ _key: key }, { fields: _fields }, function (err, item) {
module.getObject(key, function (err, item) {
if (err || !item) {
return callback(err, null);
}
callback(null, item.hasOwnProperty(field) ? item[field] : null);
});
};
@ -76,22 +126,13 @@ module.exports = function (db, module) {
if (!key) {
return callback();
}
var _fields = {
_id: 0,
};
var i;
for (i = 0; i < fields.length; i += 1) {
fields[i] = helpers.fieldToString(fields[i]);
_fields[fields[i]] = 1;
}
db.collection('objects').findOne({ _key: key }, { fields: _fields }, function (err, item) {
module.getObject(key, function (err, item) {
if (err) {
return callback(err);
}
item = item || {};
var result = {};
for (i = 0; i < fields.length; i += 1) {
for (var i = 0; i < fields.length; i += 1) {
result[fields[i]] = item[fields[i]] !== undefined ? item[fields[i]] : null;
}
callback(null, result);
@ -102,38 +143,24 @@ module.exports = function (db, module) {
if (!Array.isArray(keys) || !keys.length) {
return callback(null, []);
}
var _fields = {
_id: 0,
_key: 1,
};
for (var i = 0; i < fields.length; i += 1) {
fields[i] = helpers.fieldToString(fields[i]);
_fields[fields[i]] = 1;
}
db.collection('objects').find({ _key: { $in: keys } }, { fields: _fields }).toArray(function (err, items) {
module.getObjects(keys, function (err, items) {
if (err) {
return callback(err);
}
if (items === null) {
items = [];
}
var map = helpers.toMap(items);
var returnData = [];
var item;
var result;
for (var i = 0; i < keys.length; i += 1) {
item = map[keys[i]] || {};
item = items[i] || {};
result = {};
for (var k = 0; k < fields.length; k += 1) {
if (item[fields[k]] === undefined) {
item[fields[k]] = null;
}
result[fields[k]] = item[fields[k]] !== undefined ? item[fields[k]] : null;
}
returnData.push(item);
returnData.push(result);
}
callback(null, returnData);
@ -220,7 +247,11 @@ module.exports = function (db, module) {
});
db.collection('objects').update({ _key: key }, { $unset: data }, function (err) {
callback(err);
if (err) {
return callback(err);
}
module.delObjectCache(key);
callback();
});
};
@ -244,7 +275,11 @@ module.exports = function (db, module) {
data[field] = value;
db.collection('objects').findAndModify({ _key: key }, {}, { $inc: data }, { new: true, upsert: true }, function (err, result) {
callback(err, result && result.value ? result.value[field] : null);
if (err) {
return callback(err);
}
module.delObjectCache(key);
callback(null, result && result.value ? result.value[field] : null);
});
};
};

@ -13,7 +13,11 @@ module.exports = function (db, module) {
module.emptydb = function (callback) {
callback = callback || helpers.noop;
db.collection('objects').remove({}, function (err) {
callback(err);
if (err) {
return callback(err);
}
module.resetObjectCache();
callback();
});
};
@ -32,7 +36,11 @@ module.exports = function (db, module) {
return callback();
}
db.collection('objects').remove({ _key: key }, function (err) {
callback(err);
if (err) {
return callback(err);
}
module.delObjectCache(key);
callback();
});
};
@ -42,7 +50,15 @@ module.exports = function (db, module) {
return callback();
}
db.collection('objects').remove({ _key: { $in: keys } }, function (err) {
callback(err);
if (err) {
return callback(err);
}
keys.forEach(function (key) {
module.delObjectCache(key);
});
callback(null);
});
};
@ -75,7 +91,34 @@ module.exports = function (db, module) {
module.rename = function (oldKey, newKey, callback) {
callback = callback || helpers.noop;
db.collection('objects').update({ _key: oldKey }, { $set: { _key: newKey } }, { multi: true }, function (err) {
callback(err);
if (err) {
return callback(err);
}
module.delObjectCache(oldKey);
module.delObjectCache(newKey);
callback();
});
};
module.type = function (key, callback) {
db.collection('objects').findOne({ _key: key }, function (err, data) {
if (err) {
return callback(err);
}
if (!data) {
return callback(null, null);
}
var keys = Object.keys(data);
if (keys.length === 4 && data.hasOwnProperty('_key') && data.hasOwnProperty('score') && data.hasOwnProperty('value')) {
return callback(null, 'zset');
} else if (keys.length === 3 && data.hasOwnProperty('_key') && data.hasOwnProperty('members')) {
return callback(null, 'set');
} else if (keys.length === 3 && data.hasOwnProperty('_key') && data.hasOwnProperty('array')) {
return callback(null, 'list');
} else if (keys.length === 3 && data.hasOwnProperty('_key') && data.hasOwnProperty('value')) {
return callback(null, 'string');
}
callback(null, 'hash');
});
};

@ -137,13 +137,13 @@ module.exports = function (db, module) {
if (err) {
return callback(err);
}
result = result.map(function (item) {
return item._key;
var map = {};
result.forEach(function (item) {
map[item._key] = true;
});
result = sets.map(function (set) {
return result.indexOf(set) !== -1;
return !!map[set];
});
callback(null, result);

@ -60,6 +60,12 @@ module.exports = function (redisClient, module) {
});
};
module.type = function (key, callback) {
redisClient.type(key, function (err, type) {
callback(err, type !== 'none' ? type : null);
});
};
module.expire = function (key, seconds, callback) {
callback = callback || function () {};
redisClient.expire(key, seconds, function (err) {

@ -15,7 +15,7 @@ var LRU = require('lru-cache');
var cache = LRU({
max: 40000,
maxAge: 1000 * 60 * 60,
maxAge: 0,
});
module.exports = function (Groups) {
@ -382,7 +382,7 @@ module.exports = function (Groups) {
}
var nonCachedUids = uids.filter(function (uid) {
return !cache.has(uid + ':' + groupName);
return !cache.get(uid + ':' + groupName);
});
if (!nonCachedUids.length) {
@ -415,7 +415,7 @@ module.exports = function (Groups) {
}
var nonCachedGroups = groups.filter(function (groupName) {
return !cache.has(uid + ':' + groupName);
return !cache.get(uid + ':' + groupName);
});
if (!nonCachedGroups.length) {

@ -44,8 +44,8 @@ Blacklist.save = function (rules, callback) {
db.setObject('ip-blacklist-rules', { rules: rules }, next);
},
function (next) {
Blacklist.load(next);
pubsub.publish('blacklist:reload');
setImmediate(next);
},
], callback);
};

@ -6,7 +6,7 @@ var meta = require('../meta');
var cache = LRU({
max: parseInt(meta.config.postCacheSize, 10) || 1048576,
length: function (n) { return n.length; },
maxAge: 1000 * 60 * 60,
maxAge: 0,
});
module.exports = cache;

@ -170,6 +170,9 @@ module.exports = function (app, middleware, hotswapIds, callback) {
res.redirect(relativePath + '/assets/uploads' + req.path + '?' + meta.config['cache-buster']);
});
// only warn once
var warned = new Set();
// DEPRECATED
var deprecatedPaths = [
'/nodebb.min.js',
@ -188,8 +191,11 @@ module.exports = function (app, middleware, hotswapIds, callback) {
];
app.use(relativePath, function (req, res, next) {
if (deprecatedPaths.some(function (path) { return req.path.startsWith(path); })) {
winston.verbose('[deprecated] Accessing `' + req.path.slice(1) + '` from `/` is deprecated. ' +
if (!warned.has(req.path)) {
winston.warn('[deprecated] Accessing `' + req.path.slice(1) + '` from `/` is deprecated to be REMOVED in NodeBB v1.7.0. ' +
'Use `/assets' + req.path + '` to access this file.');
warned.add(req.path);
}
res.redirect(relativePath + '/assets' + req.path + '?' + meta.config['cache-buster']);
} else {
next();
@ -197,8 +203,11 @@ module.exports = function (app, middleware, hotswapIds, callback) {
});
// DEPRECATED
app.use(relativePath + '/api/language', function (req, res) {
winston.verbose('[deprecated] Accessing language files from `/api/language` is deprecated. ' +
if (!warned.has(req.path)) {
winston.warn('[deprecated] Accessing language files from `/api/language` is deprecated to be REMOVED in NodeBB v1.7.0. ' +
'Use `/assets/language' + req.path + '.json` for prefetch paths.');
warned.add(req.path);
}
res.redirect(relativePath + '/assets/language' + req.path + '.json?' + meta.config['cache-buster']);
});

@ -4,6 +4,7 @@ var async = require('async');
var path = require('path');
var semver = require('semver');
var readline = require('readline');
var winston = require('winston');
var db = require('./database');
var file = require('../src/file');
@ -35,6 +36,37 @@ Upgrade.getAll = function (callback) {
return semver.compare(versionA, versionB);
}));
},
async.apply(Upgrade.appendPluginScripts),
], callback);
};
Upgrade.appendPluginScripts = function (files, callback) {
async.waterfall([
// Find all active plugins
async.apply(db.getSortedSetRange.bind(db), 'plugins:active', 0, -1),
// Read plugin.json and check for upgrade scripts
function (plugins, next) {
async.each(plugins, function (plugin, next) {
var configPath = path.join(__dirname, '../node_modules', plugin, 'plugin.json');
try {
var pluginConfig = require(configPath);
if (pluginConfig.hasOwnProperty('upgrades') && Array.isArray(pluginConfig.upgrades)) {
pluginConfig.upgrades.forEach(function (script) {
files.push(path.join(path.dirname(configPath), script));
});
}
next();
} catch (e) {
winston.warn('[upgrade/appendPluginScripts] Unable to read plugin.json for plugin `' + plugin + '`. Skipping.');
process.nextTick(next);
}
}, function (err) {
// Return list of upgrade scripts for continued processing
next(err, files);
});
},
], callback);
};

@ -2,38 +2,17 @@
'use strict';
var async = require('async');
var _ = require('lodash');
var meta = require('../meta');
var db = require('../database');
var plugins = require('../plugins');
var pubsub = require('../pubsub');
var LRU = require('lru-cache');
var cache = LRU({
max: 2000,
length: function () { return 1; },
maxAge: 1000 * 60 * 60,
});
module.exports = function (User) {
User.settingsCache = cache;
pubsub.on('user:settings:cache:del', function (uid) {
cache.del('user:' + uid + ':settings');
});
User.getSettings = function (uid, callback) {
if (!parseInt(uid, 10)) {
return onSettingsLoaded(0, {}, callback);
}
var cached = cache.get('user:' + uid + ':settings');
if (cached) {
return onSettingsLoaded(uid, _.clone(cached || {}), callback);
}
async.waterfall([
function (next) {
db.getObject('user:' + uid + ':settings', next);
@ -41,36 +20,17 @@ module.exports = function (User) {
function (settings, next) {
settings = settings || {};
settings.uid = uid;
cache.set('user:' + uid + ':settings', settings);
onSettingsLoaded(uid, _.clone(settings || {}), next);
onSettingsLoaded(uid, settings, next);
},
], callback);
};
User.getMultipleUserSettings = function (uids, callback) {
function getFromCache(next) {
var settings = uids.map(function (uid) {
return cache.get('user:' + uid + ':settings') || {};
});
async.map(settings, function (setting, next) {
onSettingsLoaded(setting.uid, _.clone(setting), next);
}, next);
}
if (!Array.isArray(uids) || !uids.length) {
return callback(null, []);
}
var nonCachedUids = uids.filter(function (uid) {
return !cache.has('user:' + uid + ':settings');
});
if (!nonCachedUids.length) {
return getFromCache(callback);
}
var keys = nonCachedUids.map(function (uid) {
var keys = uids.map(function (uid) {
return 'user:' + uid + ':settings';
});
@ -79,13 +39,13 @@ module.exports = function (User) {
db.getObjects(keys, next);
},
function (settings, next) {
settings.forEach(function (userSettings, index) {
settings = settings.map(function (userSettings, index) {
userSettings = userSettings || {};
userSettings.uid = nonCachedUids[index];
cache.set('user:' + userSettings.uid + ':settings', userSettings);
userSettings.uid = uids[index];
return userSettings;
});
getFromCache(next);
next(null, settings);
},
], callback);
};
@ -187,8 +147,6 @@ module.exports = function (User) {
User.updateDigestSetting(uid, data.dailyDigestFreq, next);
},
function (next) {
cache.del('user:' + uid + ':settings');
pubsub.publish('user:settings:cache:del', uid);
User.getSettings(uid, next);
},
], callback);
@ -213,7 +171,7 @@ module.exports = function (User) {
if (!parseInt(uid, 10)) {
return setImmediate(callback);
}
cache.del('user:' + uid + ':settings');
db.setObjectField('user:' + uid + ':settings', key, value, callback);
};
};

@ -27,20 +27,21 @@
</div>
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-calendar-o"></i> User Settings Cache</div>
<div class="panel-heading"><i class="fa fa-calendar-o"></i> Object Cache</div>
<div class="panel-body">
<label>[[admin/advanced/cache:items-in-cache]]</label><br/>
<span>{userSettingsCache.itemCount}</span><br/>
<label>[[admin/advanced/cache:length-to-max]]</label><br/>
<span>{userSettingsCache.length} / {userSettingsCache.max}</span><br/>
<span>{objectCache.length} / {objectCache.max}</span><br/>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="{userSettingsCache.percentFull}" aria-valuemin="0" aria-valuemax="100" style="width: {userSettingsCache.percentFull}%;">
[[admin/advanced/cache:percent-full, {userSettingsCache.percentFull}]]
<div class="progress-bar" role="progressbar" aria-valuenow="{objectCache.percentFull}" aria-valuemin="0" aria-valuemax="100" style="width: {objectCache.percentFull}%;">
[[admin/advanced/cache:percent-full, {objectCache.percentFull}]]
</div>
</div>
<!-- IF objectCache.dump -->
<pre>{objectCache.dump}</pre>
<!-- ENDIF objectCache.dump -->
</div>
</div>
@ -48,9 +49,6 @@
<div class="panel-heading"><i class="fa fa-calendar-o"></i> Group Cache</div>
<div class="panel-body">
<label>[[admin/advanced/cache:items-in-cache]]</label><br/>
<span>{groupCache.itemCount}</span><br/>
<label>[[admin/advanced/cache:length-to-max]]</label><br/>
<span>{groupCache.length} / {groupCache.max}</span><br/>

@ -19,8 +19,8 @@ describe('Hash methods', function () {
describe('setObject()', function () {
it('should create a object', function (done) {
db.setObject('testObject1', { foo: 'baris', bar: 99 }, function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err);
assert(arguments.length < 2);
done();
});
});
@ -57,16 +57,16 @@ describe('Hash methods', function () {
describe('setObjectField()', function () {
it('should create a new object with field', function (done) {
db.setObjectField('testObject2', 'name', 'ginger', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err);
assert(arguments.length < 2);
done();
});
});
it('should add a new field to an object', function (done) {
db.setObjectField('testObject2', 'type', 'cat', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err, null);
assert(arguments.length < 2);
done();
});
});
@ -305,10 +305,10 @@ describe('Hash methods', function () {
it('should delete an objects field', function (done) {
db.deleteObjectField('testObject10', 'delete', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err);
assert(arguments.length < 2);
db.isObjectField('testObject10', 'delete', function (err, isField) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(isField, false);
done();
});
@ -318,7 +318,7 @@ describe('Hash methods', function () {
it('should delete multiple fields of the object', function (done) {
db.deleteObjectFields('testObject10', ['delete1', 'delete2'], function (err) {
assert.ifError(err);
assert.equal(arguments.length, 1);
assert(arguments.length < 2);
async.parallel({
delete1: async.apply(db.isObjectField, 'testObject10', 'delete1'),
delete2: async.apply(db.isObjectField, 'testObject10', 'delete2'),

@ -12,15 +12,15 @@ describe('Key methods', function () {
it('should set a key without error', function (done) {
db.set('testKey', 'testValue', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err);
assert(arguments.length < 2);
done();
});
});
it('should get a key without error', function (done) {
db.get('testKey', function (err, value) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(arguments.length, 2);
assert.strictEqual(value, 'testValue');
done();
@ -29,7 +29,7 @@ describe('Key methods', function () {
it('should return true if key exist', function (done) {
db.exists('testKey', function (err, exists) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(arguments.length, 2);
assert.strictEqual(exists, true);
done();
@ -38,7 +38,7 @@ describe('Key methods', function () {
it('should return false if key does not exist', function (done) {
db.exists('doesnotexist', function (err, exists) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(arguments.length, 2);
assert.strictEqual(exists, false);
done();
@ -47,11 +47,11 @@ describe('Key methods', function () {
it('should delete a key without error', function (done) {
db.delete('testKey', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err);
assert(arguments.length < 2);
db.get('testKey', function (err, value) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(false, !!value);
done();
});
@ -60,10 +60,10 @@ describe('Key methods', function () {
it('should return false if key was deleted', function (done) {
db.delete('testKey', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err);
assert(arguments.length < 2);
db.exists('testKey', function (err, exists) {
assert.equal(err, null);
assert.ifError(err);
assert.strictEqual(exists, false);
done();
});
@ -83,7 +83,7 @@ describe('Key methods', function () {
return done(err);
}
db.deleteAll(['key1', 'key2'], function (err) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(arguments.length, 1);
async.parallel({
key1exists: function (next) {
@ -93,7 +93,7 @@ describe('Key methods', function () {
db.exists('key2', next);
},
}, function (err, results) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(results.key1exists, false);
assert.equal(results.key2exists, false);
done();
@ -124,7 +124,7 @@ describe('Key methods', function () {
db.isSortedSetMember('deletezset', 'value2', next);
},
}, function (err, results) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(results.key1exists, false);
assert.equal(results.key2exists, false);
done();
@ -136,7 +136,7 @@ describe('Key methods', function () {
describe('increment', function () {
it('should initialize key to 1', function (done) {
db.increment('keyToIncrement', function (err, value) {
assert.equal(err, null);
assert.ifError(err);
assert.strictEqual(parseInt(value, 10), 1);
done();
});
@ -144,7 +144,7 @@ describe('Key methods', function () {
it('should increment key to 2', function (done) {
db.increment('keyToIncrement', function (err, value) {
assert.equal(err, null);
assert.ifError(err);
assert.strictEqual(parseInt(value, 10), 2);
done();
});
@ -158,11 +158,11 @@ describe('Key methods', function () {
return done(err);
}
db.rename('keyOldName', 'keyNewName', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
assert.ifError(err);
assert(arguments.length < 2);
db.get('keyNewName', function (err, value) {
assert.equal(err, null);
assert.ifError(err);
assert.equal(value, 'renamedKeyValue');
done();
});
@ -170,4 +170,69 @@ describe('Key methods', function () {
});
});
});
describe('type', function () {
it('should return null if key does not exist', function (done) {
db.type('doesnotexist', function (err, type) {
assert.ifError(err);
assert.strictEqual(type, null);
done();
});
});
it('should return hash as type', function (done) {
db.setObject('typeHash', { foo: 1 }, function (err) {
assert.ifError(err);
db.type('typeHash', function (err, type) {
assert.ifError(err);
assert.equal(type, 'hash');
done();
});
});
});
it('should return zset as type', function (done) {
db.sortedSetAdd('typeZset', 123, 'value1', function (err) {
assert.ifError(err);
db.type('typeZset', function (err, type) {
assert.ifError(err);
assert.equal(type, 'zset');
done();
});
});
});
it('should return set as type', function (done) {
db.setAdd('typeSet', 'value1', function (err) {
assert.ifError(err);
db.type('typeSet', function (err, type) {
assert.ifError(err);
assert.equal(type, 'set');
done();
});
});
});
it('should return list as type', function (done) {
db.listAppend('typeList', 'value1', function (err) {
assert.ifError(err);
db.type('typeList', function (err, type) {
assert.ifError(err);
assert.equal(type, 'list');
done();
});
});
});
it('should return string as type', function (done) {
db.set('typeString', 'value1', function (err) {
assert.ifError(err);
db.type('typeString', function (err, type) {
assert.ifError(err);
assert.equal(type, 'string');
done();
});
});
});
});
});

@ -1,2 +1,3 @@
--reporter dot
--timeout 25000
--exit

@ -77,6 +77,15 @@ describe('Upload Controllers', function () {
});
});
it('should fail to upload an image to a post with invalid cid', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), { cid: '0' }, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 500);
assert.equal(body.error, '[[error:category-not-selected]]');
done();
});
});
it('should upload an image to a post', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), { cid: cid }, jar, csrf_token, function (err, res, body) {
assert.ifError(err);

Loading…
Cancel
Save