diff --git a/CHANGELOG.md b/CHANGELOG.md index 2808bece2b..783b4dd082 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,53 @@ +#### v4.0.3 (2025-02-09) + +##### Chores + +* up harmony (2ee0cda2) +* update persona (b6b76639) +* bump persona to fix theme description issue (cd88cce0) +* up harmony (a01bf73e) +* forgot to remove bad code (865c09a5) +* up harmony (c3f8222f) +* up harmony (f07f3801) +* up harmony (67a789ad) +* up themes (c1c5cc6e) +* up themes (b2b0ed35) +* up peace (55eedcbe) +* up themes (38a21e29) +* up harmony (58e551fe) +* incrementing version number - v4.0.2 (73fe5fcf) +* update changelog for v4.0.2 (75588ffe) +* incrementing version number - v4.0.1 (a461b758) +* incrementing version number - v4.0.0 (c1eaee45) + +##### Bug Fixes + +* delete from payload instead of setting null (1b4e0c87) +* regression :tmi: (f5328aa8) +* #13139, payload.version can be null (bfe6d9d8) +* tidChanged (1f8e2f9a) +* #13135, tids are not numeric for ap topics (d687f081) +* handle cases where url passed to mime does not pass because url contained a query string (5baa46d0) +* isDraft logic, closes #13119 (21156673) +* path on windows, #13119 (36063d1f) +* #13115, prevent messages from getting duplicated (1ff8e1e4) +* #13115, limit bodyLength length (8e9fdb5f) + +##### Other Changes + +* remove log (a8e7bf35) + +##### Refactors + +* events are returned inside post objects (3ab22c2c) +* move dropdown search inputs into dropdown (b993be6f) +* server.destroy (72091ec4) +* remove deprecated methods (265e44f0) + +##### Tests + +* search endpoint with start & end (c1b630d4) + #### v4.0.2 (2025-02-02) ##### Chores diff --git a/install/package.json b/install/package.json index af56f2d072..ee8ba84e8a 100644 --- a/install/package.json +++ b/install/package.json @@ -98,17 +98,17 @@ "mousetrap": "1.6.5", "multiparty": "4.2.3", "nconf": "0.12.1", - "nodebb-plugin-2factor": "7.5.8", - "nodebb-plugin-composer-default": "10.2.44", - "nodebb-plugin-dbsearch": "6.2.8", + "nodebb-plugin-2factor": "7.5.9", + "nodebb-plugin-composer-default": "10.2.45", + "nodebb-plugin-dbsearch": "6.2.9", "nodebb-plugin-emoji": "6.0.2", "nodebb-plugin-emoji-android": "4.1.1", - "nodebb-plugin-markdown": "13.0.0", + "nodebb-plugin-markdown": "13.1.0", "nodebb-plugin-mentions": "4.6.10", - "nodebb-plugin-spam-be-gone": "2.3.0", + "nodebb-plugin-spam-be-gone": "2.3.1", "nodebb-plugin-web-push": "0.7.2", - "nodebb-rewards-essentials": "1.0.0", - "nodebb-theme-harmony": "2.0.18", + "nodebb-rewards-essentials": "1.0.1", + "nodebb-theme-harmony": "2.0.25", "nodebb-theme-lavender": "7.1.17", "nodebb-theme-peace": "2.2.38", "nodebb-theme-persona": "14.0.14", diff --git a/public/language/ar/themes/harmony.json b/public/language/ar/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/ar/themes/harmony.json +++ b/public/language/ar/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/bg/themes/harmony.json b/public/language/bg/themes/harmony.json index 27e0c320e1..0aa61b4924 100644 --- a/public/language/bg/themes/harmony.json +++ b/public/language/bg/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Показване на резюмета на темите на мобилни устройства", "settings.stickyToolbar": "Статична лента с инструменти", "settings.stickyToolbar.help": "Лентата с инструменти в страниците с теми и категории ще стои винаги в горния край на страницата", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Автоматично скриване на долната лента", "settings.autohideBottombar.help": "В изгледа за мобилни устройства долната лента ще се скрива, когато страницата се превърта надолу", "settings.openSidebars": "Отваряне на страничните ленти", diff --git a/public/language/bn/themes/harmony.json b/public/language/bn/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/bn/themes/harmony.json +++ b/public/language/bn/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/cs/themes/harmony.json b/public/language/cs/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/cs/themes/harmony.json +++ b/public/language/cs/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/da/themes/harmony.json b/public/language/da/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/da/themes/harmony.json +++ b/public/language/da/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/de/themes/harmony.json b/public/language/de/themes/harmony.json index 304a3ec023..b6f021d6cb 100644 --- a/public/language/de/themes/harmony.json +++ b/public/language/de/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Themen-Vorschau auf Mobilgeräten anzeigen", "settings.stickyToolbar": "Klebrige Toolbar", "settings.stickyToolbar.help": "Die Toolbar auf Themen- und Kategorieseiten bleibt oben an der Seite kleben", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Fußzeile automatisch verbergen", "settings.autohideBottombar.help": "Die Fußzeile wird auf Mobilgeräten versteckt, sobald nach unten gescrollt wird", "settings.openSidebars": "Seitennavigation öffnen", diff --git a/public/language/el/themes/harmony.json b/public/language/el/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/el/themes/harmony.json +++ b/public/language/el/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/en-GB/admin/settings/advanced.json b/public/language/en-GB/admin/settings/advanced.json index 982eaa2f64..fa1abbad0f 100644 --- a/public/language/en-GB/admin/settings/advanced.json +++ b/public/language/en-GB/admin/settings/advanced.json @@ -41,9 +41,6 @@ "sockets.default-placeholder": "Default: %1", "sockets.delay": "Reconnection Delay", - "analytics.settings": "Analytics Settings", - "analytics.max-cache": "Analytics Cache Max Value", - "analytics.max-cache-help": "On high-traffic installs, the cache could be exhausted continuously if there are more concurrent active users than the Max Cache value. (Restart required)", "compression.settings": "Compression Settings", "compression.enable": "Enable Compression", "compression.help": "This setting enables gzip compression. For a high-traffic website in production, the best way to put compression in place is to implement it at a reverse proxy level. You can enable it here for testing purposes." diff --git a/public/language/en-GB/themes/harmony.json b/public/language/en-GB/themes/harmony.json index e3ba514912..727a1b0553 100644 --- a/public/language/en-GB/themes/harmony.json +++ b/public/language/en-GB/themes/harmony.json @@ -15,8 +15,9 @@ "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", "settings.topicSidebarTools": "Topic sidebar tools", "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", - "settings.autohideBottombar": "Auto hide bottom bar", - "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", + "settings.autohideBottombar": "Auto hide mobile navigation bar", + "settings.autohideBottombar.help": "The mobile bar will be hidden when the page is scrolled down", + "settings.topMobilebar": "Move the mobile navigation bar to the top", "settings.openSidebars": "Open sidebars", "settings.chatModals": "Enable chat modals" } \ No newline at end of file diff --git a/public/language/en-US/themes/harmony.json b/public/language/en-US/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/en-US/themes/harmony.json +++ b/public/language/en-US/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/en-x-pirate/themes/harmony.json b/public/language/en-x-pirate/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/en-x-pirate/themes/harmony.json +++ b/public/language/en-x-pirate/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/es/themes/harmony.json b/public/language/es/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/es/themes/harmony.json +++ b/public/language/es/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/et/themes/harmony.json b/public/language/et/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/et/themes/harmony.json +++ b/public/language/et/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/fa-IR/themes/harmony.json b/public/language/fa-IR/themes/harmony.json index 4f0b0e7e95..69dfb3e60f 100644 --- a/public/language/fa-IR/themes/harmony.json +++ b/public/language/fa-IR/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "نمایش تیزرهای تاپیک در گوشی", "settings.stickyToolbar": "نوار ابزار چسبیده ", "settings.stickyToolbar.help": "نوار ابزار در تاپیک و صفحه دسته بدی ها در بالای صفحه ثابت میماند", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "مخفی کردن اتوماتیک منوی پایینی ", "settings.autohideBottombar.help": "وقتی صفحه به پایین اسکرول می شود، منوی پایین در نمایش گوشی مخفی خواهد شد ", "settings.openSidebars": "Open sidebars", diff --git a/public/language/fi/themes/harmony.json b/public/language/fi/themes/harmony.json index ddd27c40fe..9d2db8a733 100644 --- a/public/language/fi/themes/harmony.json +++ b/public/language/fi/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Näytä aihe-ehdotukset mobiilinäkymässä", "settings.stickyToolbar": "Kiinteä työkalupalkki", "settings.stickyToolbar.help": "Aihe- ja kategoriasivujen työkalupalkki näytetään yläreunassa aina.", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Piilota alapalkki automaattisesti", "settings.autohideBottombar.help": "Mobiilinäykymän alapalkki piilotetaan kun sivua vieritetään alaspäin.", "settings.openSidebars": "Avaa sivupalkit", diff --git a/public/language/fr/themes/harmony.json b/public/language/fr/themes/harmony.json index eb122d9d02..d58d85cad7 100644 --- a/public/language/fr/themes/harmony.json +++ b/public/language/fr/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Afficher les teasers de sujet sur mobile", "settings.stickyToolbar": "Barre d'outils", "settings.stickyToolbar.help": "La barre d'outils sur les pages de sujets et de catégories restera en haut de la page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Masquer automatiquement la barre inférieure", "settings.autohideBottombar.help": "La barre inférieure sur mobile sera masquée lorsque la page défilera vers le bas", "settings.openSidebars": "Barres latérales ouvertes", diff --git a/public/language/gl/themes/harmony.json b/public/language/gl/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/gl/themes/harmony.json +++ b/public/language/gl/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/he/themes/harmony.json b/public/language/he/themes/harmony.json index 90675cc6bf..500a923904 100644 --- a/public/language/he/themes/harmony.json +++ b/public/language/he/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "הצגת טיזרים של נושאים בנייד", "settings.stickyToolbar": "הצמד את סרגל הכלים בעת גלילה", "settings.stickyToolbar.help": "סרגל הכלים בדפי נושאים וקטגוריות ייצמד לראש העמוד בעת גלילה", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "הסתרה אוטומטית של סרגל תחתון", "settings.autohideBottombar.help": "הסרגל התחתון בתצוגת הנייד יוסתר כאשר הדף ייגלל מטה", "settings.openSidebars": "פתח סרגלי צד", diff --git a/public/language/hr/themes/harmony.json b/public/language/hr/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/hr/themes/harmony.json +++ b/public/language/hr/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/hu/themes/harmony.json b/public/language/hu/themes/harmony.json index bee0ab5838..c6d48ad76a 100644 --- a/public/language/hu/themes/harmony.json +++ b/public/language/hu/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Oldalsáv nyitása", diff --git a/public/language/hy/themes/harmony.json b/public/language/hy/themes/harmony.json index 72b6b4166a..787a8d7ed5 100644 --- a/public/language/hy/themes/harmony.json +++ b/public/language/hy/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Ցույց տալ թեմայի թիզերները բջջայինով", "settings.stickyToolbar": "Կպչուն գործիքագոտի", "settings.stickyToolbar.help": "Թեմայի և կատեգորիայի էջերի գործիքագոտին կմնա էջի վերևում", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Ավտոմատ թաքցնել ներքևի բարը", "settings.autohideBottombar.help": "Բջջային դիտման ներքևի տողը կթաքցվի, երբ էջը ներքև իջացնեք", "settings.openSidebars": "Բացել կողքի տողերը", diff --git a/public/language/id/themes/harmony.json b/public/language/id/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/id/themes/harmony.json +++ b/public/language/id/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/it/themes/harmony.json b/public/language/it/themes/harmony.json index b63252bdaa..f52afb85ec 100644 --- a/public/language/it/themes/harmony.json +++ b/public/language/it/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Mostra le anteprime delle discussioni su mobile", "settings.stickyToolbar": "Barra degli strumenti adesiva", "settings.stickyToolbar.help": "La barra degli strumenti nelle pagine delle discussioni e delle categorie si attacca alla parte superiore della pagina.", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Nascondi automaticamente la barra inferiore", "settings.autohideBottombar.help": "La barra inferiore nella visualizzazione mobile sarà nascosta quando la pagina viene fatta scorrere verso il basso.", "settings.openSidebars": "Apri le barre laterali", diff --git a/public/language/ja/themes/harmony.json b/public/language/ja/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/ja/themes/harmony.json +++ b/public/language/ja/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/ko/themes/harmony.json b/public/language/ko/themes/harmony.json index e9b4b96845..a8d98525b6 100644 --- a/public/language/ko/themes/harmony.json +++ b/public/language/ko/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "모바일에서 토픽 미리보기 표시", "settings.stickyToolbar": "툴바 고정", "settings.stickyToolbar.help": "토픽 및 카테고리 페이지의 툴바가 페이지 상단에 고정됩니다.", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "하단 바 자동 숨기기", "settings.autohideBottombar.help": "모바일 뷰에서 페이지가 아래로 스크롤될 때 하단 막대가 숨겨집니다.", "settings.openSidebars": "사이드바 열기", diff --git a/public/language/lt/themes/harmony.json b/public/language/lt/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/lt/themes/harmony.json +++ b/public/language/lt/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/lv/themes/harmony.json b/public/language/lv/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/lv/themes/harmony.json +++ b/public/language/lv/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/ms/themes/harmony.json b/public/language/ms/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/ms/themes/harmony.json +++ b/public/language/ms/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/nb/themes/harmony.json b/public/language/nb/themes/harmony.json index 2c78382d54..bd6204cb1a 100644 --- a/public/language/nb/themes/harmony.json +++ b/public/language/nb/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Vis emneforhåndsvisninger på mobil", "settings.stickyToolbar": "Festet verktøylinje", "settings.stickyToolbar.help": "Verktøylinjen på emne- og kategorisider vil feste seg til toppen av siden", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Skjul bunnlinjen automatisk", "settings.autohideBottombar.help": "Bunnlinjen i mobilvisning skjules automatisk når siden rulles ned", "settings.openSidebars": "Åpne sidepaneler", diff --git a/public/language/nl/themes/harmony.json b/public/language/nl/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/nl/themes/harmony.json +++ b/public/language/nl/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/nn-NO/themes/harmony.json b/public/language/nn-NO/themes/harmony.json index ca69583fb2..d7d23b22a7 100644 --- a/public/language/nn-NO/themes/harmony.json +++ b/public/language/nn-NO/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Vis emneteasere på mobil", "settings.stickyToolbar": "Fast verktøylinje", "settings.stickyToolbar.help": "Gjer verktøylinja fast øvst på sida når du rullar.", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Gøym botnlinja automatisk", "settings.autohideBottombar.help": "Botnlinja vert automatisk gøymd når du rullar nedover.", "settings.openSidebars": "Opne sidefelt", diff --git a/public/language/pl/themes/harmony.json b/public/language/pl/themes/harmony.json index 829416ddeb..0a7a315138 100644 --- a/public/language/pl/themes/harmony.json +++ b/public/language/pl/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Pokazuj zwiastuny tematów na telefonie", "settings.stickyToolbar": "Przyklejaj pasek narzędziowy", "settings.stickyToolbar.help": "Pasek z narzędziami na stronach tematów i kategorii będzie przyklejony do góry strony", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Automatycznie chowaj dolny panel", "settings.autohideBottombar.help": "Dolny panel schowa się w widoku mobilnym, jeśli strona zostanie przesunięta w dół", "settings.openSidebars": "Otwórz panele boczne", diff --git a/public/language/pt-BR/themes/harmony.json b/public/language/pt-BR/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/pt-BR/themes/harmony.json +++ b/public/language/pt-BR/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/pt-PT/themes/harmony.json b/public/language/pt-PT/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/pt-PT/themes/harmony.json +++ b/public/language/pt-PT/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/ro/themes/harmony.json b/public/language/ro/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/ro/themes/harmony.json +++ b/public/language/ro/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/ru/themes/harmony.json b/public/language/ru/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/ru/themes/harmony.json +++ b/public/language/ru/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/rw/themes/harmony.json b/public/language/rw/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/rw/themes/harmony.json +++ b/public/language/rw/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/sc/themes/harmony.json b/public/language/sc/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/sc/themes/harmony.json +++ b/public/language/sc/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/sk/themes/harmony.json b/public/language/sk/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/sk/themes/harmony.json +++ b/public/language/sk/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/sl/themes/harmony.json b/public/language/sl/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/sl/themes/harmony.json +++ b/public/language/sl/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/sq-AL/themes/harmony.json b/public/language/sq-AL/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/sq-AL/themes/harmony.json +++ b/public/language/sq-AL/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/sr/themes/harmony.json b/public/language/sr/themes/harmony.json index 06eb4ec656..03c5638a6d 100644 --- a/public/language/sr/themes/harmony.json +++ b/public/language/sr/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Прикажи најавне теме на мобилном телефону", "settings.stickyToolbar": "Лепљива трака алата", "settings.stickyToolbar.help": "Трака алата на страницама са темама и категоријама ће бити на врху странице", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Аутоматско сакривање доње траке", "settings.autohideBottombar.help": "Доња трака у приказу за мобилне уређаје биће скривена када се страница помера надоле", "settings.openSidebars": "Open sidebars", diff --git a/public/language/sv/themes/harmony.json b/public/language/sv/themes/harmony.json index 14a2604e1c..797298e428 100644 --- a/public/language/sv/themes/harmony.json +++ b/public/language/sv/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/th/themes/harmony.json b/public/language/th/themes/harmony.json index 94bb567d0a..bd67eabcce 100644 --- a/public/language/th/themes/harmony.json +++ b/public/language/th/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "แสดงตัวอย่างเนื้อหากระทู้บนมือถือ", "settings.stickyToolbar": "แถบเครื่องมือแบบ sticky", "settings.stickyToolbar.help": "แถบเครื่องมือในหน้ากระทู้และหมวดหมู่จะอยู่ด้านบนสุดของหน้าเสมอ", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "ซ่อนแถบล่าง", "settings.autohideBottombar.help": "แถบล่างบนมือถือจะถูกซ่อนเมื่อเลื่อนหน้าลง", "settings.openSidebars": "เปิดแถบข้าง", diff --git a/public/language/tr/themes/harmony.json b/public/language/tr/themes/harmony.json index 524af6091f..b8f56c369a 100644 --- a/public/language/tr/themes/harmony.json +++ b/public/language/tr/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Başlık Önizlemelerini mobilde göster", "settings.stickyToolbar": "Yapışkan Araç Çubuğu", "settings.stickyToolbar.help": "Kategori ve konu sayfalarındaki araç çubuğu sayfanın üstünde sabitlenmiş şekilde kalacak", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Alttaki şeridi otomatik olarak gizle", "settings.autohideBottombar.help": "Sayfanın altındaki şerit sayfayı aşağıya doğru kaydırırken mobilde gizlenecek", "settings.openSidebars": "Yan menüleri aç", diff --git a/public/language/uk/themes/harmony.json b/public/language/uk/themes/harmony.json index 01038d7641..e3ba514912 100644 --- a/public/language/uk/themes/harmony.json +++ b/public/language/uk/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "Open sidebars", diff --git a/public/language/vi/themes/harmony.json b/public/language/vi/themes/harmony.json index 4f7b19c44e..a4740df89e 100644 --- a/public/language/vi/themes/harmony.json +++ b/public/language/vi/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Hiển thị đoạn giới thiệu chủ đề trên di động", "settings.stickyToolbar": "Thanh công cụ cố định", "settings.stickyToolbar.help": "Thanh công cụ trên các trang chủ đề và danh mục sẽ nằm ở đầu trang", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Tự động ẩn thanh dưới cùng", "settings.autohideBottombar.help": "Thanh dưới cùng trên chế độ xem di động sẽ ẩn khi trang được cuộn xuống", "settings.openSidebars": "Mở thanh bên", diff --git a/public/language/zh-CN/themes/harmony.json b/public/language/zh-CN/themes/harmony.json index 64cc85a607..dfba3d89d5 100644 --- a/public/language/zh-CN/themes/harmony.json +++ b/public/language/zh-CN/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "在移动设备显示话题预告", "settings.stickyToolbar": "附着工具条", "settings.stickyToolbar.help": "主题和类别页面上的工具条将附着在页面顶部", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "自动隐藏底栏", "settings.autohideBottombar.help": "当页面向下滚动时,移动设备视图的底栏将被隐藏", "settings.openSidebars": "打开侧栏", diff --git a/public/language/zh-TW/themes/harmony.json b/public/language/zh-TW/themes/harmony.json index bf12d4f6f0..2a04ca3420 100644 --- a/public/language/zh-TW/themes/harmony.json +++ b/public/language/zh-TW/themes/harmony.json @@ -13,6 +13,8 @@ "settings.mobileTopicTeasers": "Show topic teasers on mobile", "settings.stickyToolbar": "Sticky toolbar", "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", + "settings.topicSidebarTools": "Topic sidebar tools", + "settings.topicSidebarTools.help": "This option will move the topic tools to the sidebar on desktop", "settings.autohideBottombar": "Auto hide bottom bar", "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", "settings.openSidebars": "打開側欄", diff --git a/public/openapi/read/admin/dashboard.yaml b/public/openapi/read/admin/dashboard.yaml index a416d51b56..72f989b2b2 100644 --- a/public/openapi/read/admin/dashboard.yaml +++ b/public/openapi/read/admin/dashboard.yaml @@ -18,6 +18,8 @@ get: latestVersion: type: string nullable: true + hideAllTime: + type: boolean upgradeAvailable: type: boolean nullable: true diff --git a/src/activitypub/actors.js b/src/activitypub/actors.js index 2208f03de7..bda513661c 100644 --- a/src/activitypub/actors.js +++ b/src/activitypub/actors.js @@ -2,6 +2,7 @@ const nconf = require('nconf'); const winston = require('winston'); +const _ = require('lodash'); const db = require('../database'); const meta = require('../meta'); @@ -230,19 +231,34 @@ Actors.getLocalFollowers = async (id) => { return response; }; -Actors.getLocalFollowCounts = async (actor) => { - let followers = 0; // x local followers - let following = 0; // following x local users - if (!activitypub.helpers.isUri(actor)) { - return { followers, following }; +Actors.getLocalFollowCounts = async (actors) => { + const isArray = Array.isArray(actors); + if (!isArray) { + actors = [actors]; } - [followers, following] = await Promise.all([ - db.sortedSetCard(`followersRemote:${actor}`), - db.sortedSetCard(`followingRemote:${actor}`), - ]); + const validActors = actors.filter(actor => activitypub.helpers.isUri(actor)); + const followerKeys = validActors.map(actor => `followersRemote:${actor}`); + const followingKeys = validActors.map(actor => `followingRemote:${actor}`); - return { followers, following }; + const [followersCounts, followingCounts] = await Promise.all([ + db.sortedSetsCard(followerKeys), + db.sortedSetsCard(followingKeys), + ]); + const actorToCounts = _.zipObject(validActors, validActors.map( + (a, idx) => ({ followers: followersCounts[idx], following: followingCounts[idx] }) + )); + const results = actors.map((actor) => { + if (!actorToCounts.hasOwnProperty(actor)) { + return { followers: 0, following: 0 }; + } + return { + followers: actorToCounts[actor].followers, + following: actorToCounts[actor].following, + }; + }); + + return isArray ? results : results[0]; }; Actors.remove = async (id) => { @@ -288,7 +304,7 @@ Actors.prune = async () => { const days = parseInt(meta.config.activitypubUserPruneDays, 10); const timestamp = Date.now() - (1000 * 60 * 60 * 24 * days); - const uids = await db.getSortedSetRangeByScore('usersRemote:lastCrawled', 0, -1, '-inf', timestamp); + const uids = await db.getSortedSetRangeByScore('usersRemote:lastCrawled', 0, 500, '-inf', timestamp); if (!uids.length) { winston.info('[actors/prune] No remote users to prune, all done.'); return; @@ -296,21 +312,23 @@ Actors.prune = async () => { winston.info(`[actors/prune] Found ${uids.length} remote users last crawled more than ${days} days ago`); let deletionCount = 0; - + let deletionCountNonExisting = 0; + let notDeletedDueToLocalContent = 0; + const notDeletedUids = []; await batch.processArray(uids, async (uids) => { const exists = await db.exists(uids.map(uid => `userRemote:${uid}`)); - const [postCounts, roomCounts] = await Promise.all([ - db.sortedSetsCard(uids.map(uid => `uid:${uid}:posts`)), - db.sortedSetsCard(uids.map(uid => `uid:${uid}:chat:rooms`)), - ]); - await Promise.all(uids.map(async (uid, idx) => { - if (!exists[idx]) { - // id in zset but not asserted, handle and return early - await db.sortedSetRemove('usersRemote:lastCrawled', uid); - return; - } - const { followers, following } = await Actors.getLocalFollowCounts(uid); + const uidsThatExist = uids.filter((uid, idx) => exists[idx]); + const uidsThatDontExist = uids.filter((uid, idx) => !exists[idx]); + + const [postCounts, roomCounts, followCounts] = await Promise.all([ + db.sortedSetsCard(uidsThatExist.map(uid => `uid:${uid}:posts`)), + db.sortedSetsCard(uidsThatExist.map(uid => `uid:${uid}:chat:rooms`)), + Actors.getLocalFollowCounts(uidsThatExist), + ]); + + await Promise.all(uidsThatExist.map(async (uid, idx) => { + const { followers, following } = followCounts[idx]; const postCount = postCounts[idx]; const roomCount = roomCounts[idx]; if ([postCount, roomCount, followers, following].every(metric => metric < 1)) { @@ -320,12 +338,22 @@ Actors.prune = async () => { } catch (err) { winston.error(err.stack); } + } else { + notDeletedDueToLocalContent += 1; + notDeletedUids.push(uid); } })); + + deletionCountNonExisting += uidsThatDontExist.length; + await db.sortedSetRemove('usersRemote:lastCrawled', uidsThatDontExist); + // update timestamp in usersRemote:lastCrawled so we don't try to delete users + // with content over and over + const now = Date.now(); + await db.sortedSetAdd('usersRemote:lastCrawled', notDeletedUids.map(() => now), notDeletedUids); }, { batch: 50, interval: 1000, }); - winston.info(`[actors/prune] ${deletionCount} remote users pruned.`); + winston.info(`[actors/prune] ${deletionCount} remote users pruned. ${deletionCountNonExisting} does not exist. ${notDeletedDueToLocalContent} not deleted due to local content`); }; diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 4a6d95b48b..3eec80eae1 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -66,7 +66,7 @@ ActivityPub.startJobs = () => { } }, null, true, null, null, false); // change last argument to true for debugging - new CronJob('0 1 * * *', async () => { + new CronJob('*/30 * * * *', async () => { try { await ActivityPub.actors.prune(); } catch (err) { diff --git a/src/activitypub/mocks.js b/src/activitypub/mocks.js index 3ea4c03494..003d392333 100644 --- a/src/activitypub/mocks.js +++ b/src/activitypub/mocks.js @@ -155,7 +155,10 @@ Mocks.post = async (objects) => { await activitypub.actors.assert(Array.from(actorIds)); const posts = await Promise.all(objects.map(async (object) => { - if (!activitypub._constants.acceptedPostTypes.includes(object.type)) { + if ( + !activitypub._constants.acceptedPostTypes.includes(object.type) || + !activitypub.helpers.isUri(object.id) // sanity-check the id + ) { return null; } @@ -187,7 +190,7 @@ Mocks.post = async (objects) => { } switch (true) { - case image && image.hasOwnProperty('url') && image.url: { + case image && image.hasOwnProperty('url') && !!image.url: { image = image.url; break; } diff --git a/src/analytics.js b/src/analytics.js index 49c987d52d..45e8f698d9 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -3,7 +3,6 @@ const cronJob = require('cron').CronJob; const winston = require('winston'); const nconf = require('nconf'); -const crypto = require('crypto'); const util = require('util'); const _ = require('lodash'); @@ -12,36 +11,24 @@ const sleep = util.promisify(setTimeout); const db = require('./database'); const utils = require('./utils'); const plugins = require('./plugins'); -const meta = require('./meta'); const pubsub = require('./pubsub'); -const cacheCreate = require('./cache/lru'); const Analytics = module.exports; -const secret = nconf.get('secret'); - let local = { counters: {}, pageViews: 0, pageViewsRegistered: 0, pageViewsGuest: 0, pageViewsBot: 0, - uniqueIPCount: 0, uniquevisitors: 0, }; const empty = _.cloneDeep(local); const total = _.cloneDeep(local); -let ipCache; - const runJobs = nconf.get('runJobs'); Analytics.init = async function () { - ipCache = cacheCreate({ - max: parseInt(meta.config['analytics:maxCache'], 10) || 500, - ttl: 0, - }); - new cronJob('*/10 * * * * *', (async () => { publishLocalAnalytics(); if (runJobs) { @@ -50,6 +37,12 @@ Analytics.init = async function () { } }), null, true); + if (runJobs) { + new cronJob('*/30 * * * *', (async () => { + await db.sortedSetsRemoveRangeByScore(['ip:recent'], '-inf', Date.now() - 172800000); + }), null, true); + } + if (runJobs) { pubsub.on('analytics:publish', (data) => { incrementProperties(total, data.local); @@ -106,22 +99,17 @@ Analytics.pageView = async function (payload) { } if (payload.ip) { - // Retrieve hash or calculate if not present - let hash = ipCache.get(payload.ip + secret); - if (!hash) { - hash = crypto.createHash('sha1').update(payload.ip + secret).digest('hex'); - ipCache.set(payload.ip + secret, hash); + const score = await db.sortedSetScore('ip:recent', payload.ip); + let record = !score; + if (score) { + const today = new Date(); + today.setHours(today.getHours(), 0, 0, 0); + record = score < today.getTime(); } - const score = await db.sortedSetScore('ip:recent', hash); - if (!score) { - local.uniqueIPCount += 1; - } - const today = new Date(); - today.setHours(today.getHours(), 0, 0, 0); - if (!score || score < today.getTime()) { + if (record) { local.uniquevisitors += 1; - await db.sortedSetAdd('ip:recent', Date.now(), hash); + await db.sortedSetAdd('ip:recent', Date.now(), payload.ip); } } }; @@ -176,11 +164,6 @@ Analytics.writeData = async function () { total.uniquevisitors = 0; } - if (total.uniqueIPCount > 0) { - dbQueue.push(db.incrObjectFieldBy('global', 'uniqueIPCount', total.uniqueIPCount)); - total.uniqueIPCount = 0; - } - for (const [key, value] of Object.entries(total.counters)) { incrByBulk.push([`analytics:${key}`, value, today.getTime()]); metrics.push(key); diff --git a/src/api/activitypub.js b/src/api/activitypub.js index 76abcc9c51..3b078a7862 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -168,6 +168,7 @@ activitypubApi.create.privateNote = enabledCheck(async (caller, { messageObj }) const payload = { id: `${object.id}#activity/create/${Date.now()}`, type: 'Create', + actor: object.attributedTo, to: object.to, object, }; @@ -186,6 +187,7 @@ activitypubApi.update.profile = enabledCheck(async (caller, { uid }) => { await activitypub.send('uid', caller.uid, targets, { id: `${object.id}#activity/update/${Date.now()}`, type: 'Update', + actor: object.id, to: [activitypub._constants.publicAddress], cc: [], object, @@ -201,6 +203,7 @@ activitypubApi.update.category = enabledCheck(async (caller, { cid }) => { await activitypub.send('cid', cid, targets, { id: `${object.id}#activity/update/${Date.now()}`, type: 'Update', + actor: object.id, to: [activitypub._constants.publicAddress], cc: [], object, @@ -227,6 +230,7 @@ activitypubApi.update.note = enabledCheck(async (caller, { post }) => { const payload = { id: `${object.id}#activity/update/${post.edited || Date.now()}`, type: 'Update', + actor: object.attributedTo, to, cc, object, @@ -251,6 +255,7 @@ activitypubApi.update.privateNote = enabledCheck(async (caller, { messageObj }) const payload = { id: `${object.id}#activity/create/${Date.now()}`, type: 'Update', + actor: object.attributedTo, to, object, }; @@ -280,6 +285,7 @@ activitypubApi.delete.note = enabledCheck(async (caller, { pid }) => { const payload = { id: `${id}#activity/delete/${Date.now()}`, type: 'Delete', + actor: object.attributedTo, to, cc, object: id, @@ -334,6 +340,7 @@ activitypubApi.announce.note = enabledCheck(async (caller, { tid }) => { await activitypub.send('uid', caller.uid, Array.from(targets), { id: `${nconf.get('url')}/post/${encodeURIComponent(pid)}#activity/announce/${Date.now()}`, type: 'Announce', + actor: `${nconf.get('url')}/uid/${caller.uid}`, to, cc, object: pid, @@ -380,6 +387,7 @@ activitypubApi.flag = enabledCheck(async (caller, flag) => { await activitypub.send('uid', caller.uid, reportedIds, { id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/flag/${caller.uid}`, type: 'Flag', + actor: `${nconf.get('url')}/uid/${caller.uid}`, object: reportedIds, content: reason, }); @@ -426,6 +434,7 @@ activitypubApi.undo.flag = enabledCheck(async (caller, flag) => { await activitypub.send('uid', caller.uid, reportedIds, { id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/undo:flag/${caller.uid}/${Date.now()}`, type: 'Undo', + actor: `${nconf.get('url')}/uid/${caller.uid}`, object: { id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/flag/${caller.uid}`, actor: `${nconf.get('url')}/uid/${caller.uid}`, diff --git a/src/categories/data.js b/src/categories/data.js index 452ccf20b8..2b4e029caf 100644 --- a/src/categories/data.js +++ b/src/categories/data.js @@ -73,7 +73,7 @@ module.exports = function (Categories) { Categories.getCategoryField = async function (cid, field) { const category = await Categories.getCategoryFields(cid, [field]); - return category ? category[field] : null; + return category && category.hasOwnProperty(field) ? category[field] : null; }; Categories.getCategoryFields = async function (cid, fields) { diff --git a/src/controllers/admin/dashboard.js b/src/controllers/admin/dashboard.js index 405a239aaf..d3bf019443 100644 --- a/src/controllers/admin/dashboard.js +++ b/src/controllers/admin/dashboard.js @@ -41,6 +41,7 @@ dashboardController.get = async function (req, res) { lastrestart: lastrestart, showSystemControls: isAdmin, popularSearches: popularSearches, + hideAllTime: true, }); }; @@ -128,7 +129,7 @@ async function getStats() { } let results = await Promise.all([ - getStatsFromAnalytics('uniquevisitors', 'uniqueIPCount'), + getStatsFromAnalytics('uniquevisitors', ''), getStatsFromAnalytics('logins', 'loginCount'), getStatsForSet('users:joindate', 'userCount'), getStatsForSet('posts:pid', 'postCount'), @@ -227,6 +228,7 @@ function calculateDeltas(results) { } async function getGlobalField(field) { + if (!field) return 0; const count = await db.getObjectField('global', field); return parseInt(count, 10) || 0; } diff --git a/src/groups/data.js b/src/groups/data.js index 5ecb9081e0..1dc52e44ad 100644 --- a/src/groups/data.js +++ b/src/groups/data.js @@ -51,7 +51,7 @@ module.exports = function (Groups) { Groups.getGroupField = async function (groupName, field) { const groupData = await Groups.getGroupFields(groupName, [field]); - return groupData ? groupData[field] : null; + return groupData && groupData.hasOwnProperty(field) ? groupData[field] : null; }; Groups.getGroupFields = async function (groupName, fields) { diff --git a/src/messaging/data.js b/src/messaging/data.js index aa96e11a67..2c3257c74f 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -29,7 +29,7 @@ module.exports = function (Messaging) { Messaging.getMessageField = async (mid, field) => { const fields = await Messaging.getMessageFields(mid, [field]); - return fields ? fields[field] : null; + return fields && fields.hasOwnProperty(field) ? fields[field] : null; }; Messaging.getMessageFields = async (mid, fields) => { diff --git a/src/posts/attachments.js b/src/posts/attachments.js index 3683aa0de4..99aece3010 100644 --- a/src/posts/attachments.js +++ b/src/posts/attachments.js @@ -63,6 +63,7 @@ Attachments.update = async (pid, attachments) => { await Promise.all([ db.setObjectBulk(bulkOps.hash), db.setObjectField(`post:${pid}`, 'attachments', hashes.join(',')), + posts.clearCachedPost(pid), ]); }; diff --git a/src/posts/data.js b/src/posts/data.js index 5c44b49254..688c131b8a 100644 --- a/src/posts/data.js +++ b/src/posts/data.js @@ -37,7 +37,7 @@ module.exports = function (Posts) { Posts.getPostField = async function (pid, field) { const post = await Posts.getPostFields(pid, [field]); - return post ? post[field] : null; + return post && post.hasOwnProperty(field) ? post[field] : null; }; Posts.getPostFields = async function (pid, fields) { diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index a684d95783..d6833e363a 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -28,8 +28,6 @@ SocketPosts.getRawPost = async function (socket, pid) { }; SocketPosts.getPostSummaryByIndex = async function (socket, data) { - sockets.warnDeprecated(socket, 'GET /api/v3/posts/byIndex/:index/summary?tid=:tid'); - if (data.index < 0) { data.index = 0; } diff --git a/src/topics/create.js b/src/topics/create.js index 96113c3e5a..e6d97af77f 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -2,6 +2,7 @@ 'use strict'; const _ = require('lodash'); +const winston = require('winston'); const db = require('../database'); const utils = require('../utils'); @@ -154,12 +155,19 @@ module.exports = function (Topics) { plugins.hooks.fire('action:topic.post', { topic: topicData, post: postData, data: data }); if (!topicData.scheduled) { - if (utils.isNumber(uid)) { - // New topic notifications only sent for local-to-local follows only - user.notifications.sendTopicNotificationToFollowers(uid, topicData, postData); - } - Topics.notifyTagFollowers(postData, uid); - categories.notifyCategoryFollowers(postData, uid); + setImmediate(async () => { + try { + if (utils.isNumber(uid)) { + // New topic notifications only sent for local-to-local follows only + await user.notifications.sendTopicNotificationToFollowers(uid, topicData, postData); + } + + await Topics.notifyTagFollowers(postData, uid); + await categories.notifyCategoryFollowers(postData, uid); + } catch (err) { + winston.error(err.stack); + } + }); } return { @@ -211,13 +219,17 @@ module.exports = function (Topics) { } if (parseInt(uid, 10) || activitypub.helpers.isUri(uid) || meta.config.allowGuestReplyNotifications) { - const { displayname } = postData.user; - - Topics.notifyFollowers(postData, uid, { - type: 'new-reply', - bodyShort: translator.compile('notifications:user-posted-to', displayname, postData.topic.title), - nid: `new_post:tid:${postData.topic.tid}:pid:${postData.pid}:uid:${uid}`, - mergeId: `notifications:user-posted-to|${postData.topic.tid}`, + setImmediate(async () => { + try { + await Topics.notifyFollowers(postData, uid, { + type: 'new-reply', + bodyShort: translator.compile('notifications:user-posted-to', postData.user.displayname, postData.topic.title), + nid: `new_post:tid:${postData.topic.tid}:pid:${postData.pid}:uid:${uid}`, + mergeId: `notifications:user-posted-to|${postData.topic.tid}`, + }); + } catch (err) { + winston.error(err.stack); + } }); } diff --git a/src/topics/data.js b/src/topics/data.js index 1260c092e1..e9a281ecaa 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -40,7 +40,7 @@ module.exports = function (Topics) { Topics.getTopicField = async function (tid, field) { const topic = await Topics.getTopicFields(tid, [field]); - return topic ? topic[field] : null; + return topic && topic.hasOwnProperty(field) ? topic[field] : null; }; Topics.getTopicFields = async function (tid, fields) { diff --git a/src/topics/tags.js b/src/topics/tags.js index 4f2bc6dc97..9d4865122d 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -621,7 +621,7 @@ module.exports = function (Topics) { const notification = await notifications.create({ type: 'new-topic-with-tag', - nid: `new_topic:tid:${postData.topic.tid}:uid:${exceptUid}`, + nid: `new_topic:tags:${tags.join('.')}:tid:${postData.topic.tid}:uid:${exceptUid}`, bodyShort: bodyShort, bodyLong: postData.content, pid: postData.pid, diff --git a/src/user/data.js b/src/user/data.js index ec643f729b..c9d8cb5ae6 100644 --- a/src/user/data.js +++ b/src/user/data.js @@ -161,7 +161,7 @@ module.exports = function (User) { User.getUserField = async function (uid, field) { const user = await User.getUserFields(uid, [field]); - return user ? user[field] : null; + return user && user.hasOwnProperty(field) ? user[field] : null; }; User.getUserFields = async function (uid, fields) { diff --git a/src/views/admin/advanced/hooks.tpl b/src/views/admin/advanced/hooks.tpl index fceffc3655..1f1b4682cc 100644 --- a/src/views/admin/advanced/hooks.tpl +++ b/src/views/admin/advanced/hooks.tpl @@ -2,9 +2,8 @@ {{{ each hooks }}}
| - | [[admin/dashboard:stats.yesterday]] | -[[admin/dashboard:stats.today]] | +[[admin/dashboard:stats.yesterday]] | +[[admin/dashboard:stats.today]] | - | [[admin/dashboard:stats.last-week]] | -[[admin/dashboard:stats.this-week]] | +[[admin/dashboard:stats.last-week]] | +[[admin/dashboard:stats.this-week]] | - | [[admin/dashboard:stats.last-month]] | -[[admin/dashboard:stats.this-month]] | +[[admin/dashboard:stats.last-month]] | +[[admin/dashboard:stats.this-month]] | + {{{ if !hideAllTime}}} | [[admin/dashboard:stats.all]] | + {{{ end }}}
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
-
+ |
+
{{{ if ./href }}}
{./name}
{{{ else }}}
{./name}
{{{ end }}}
-
+
|
{formattedNumber(./yesterday)} |
{formattedNumber(./today)} |
@@ -38,8 +40,9 @@
{formattedNumber(./lastmonth)} |
{formattedNumber(./thismonth)} |
{./monthIncrease}% |
-
+ {{{ if !hideAllTime}}}
{formattedNumber(./alltime)} |
+ {{{ end }}}
|