From 6ada76f401e7111bfdf19d53a5a7e42a3ff365fa Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Thu, 1 May 2025 09:19:38 +0000 Subject: [PATCH 01/76] Latest translations and fallbacks --- public/language/it/category.json | 2 +- public/language/it/world.json | 4 ++-- public/language/pl/category.json | 2 +- public/language/pl/world.json | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/public/language/it/category.json b/public/language/it/category.json index ef47085300..2a22e1a760 100644 --- a/public/language/it/category.json +++ b/public/language/it/category.json @@ -7,7 +7,7 @@ "new-topic-button": "Nuova Discussione", "guest-login-post": "Accedi per postare", "no-topics": "Non ci sono discussioni in questa categoria.
Perché non ne posti una?", - "no-followers": "Nobody on this website is tracking or watching this category. Track or watch this category in order to begin receiving updates.", + "no-followers": "Nessuno su questo sito web sta monitorando o guardando questa categoria. Tieni traccia o guarda questa categoria per iniziare a ricevere aggiornamenti.", "browsing": "navigazione", "no-replies": "Nessuno ha risposto", "no-new-posts": "Nessun nuovo post.", diff --git a/public/language/it/world.json b/public/language/it/world.json index 3b3a3dc6b3..90caea05e1 100644 --- a/public/language/it/world.json +++ b/public/language/it/world.json @@ -16,6 +16,6 @@ "onboard.why": "Ci sono molte cose che accadono al di fuori di questo forum e non tutte sono rilevanti per i tuoi interessi. Ecco perché seguire le persone è il modo migliore per segnalare che vuoi vedere di più da qualcuno.", "onboard.how": "Nel frattempo, puoi cliccare sui pulsanti di scelta rapida in alto per vedere cos'altro conosce questo forum e iniziare a scoprire nuovi contenuti!", - "show-categories": "Show categories", - "hide-categories": "Hide categories" + "show-categories": "Mostra categorie", + "hide-categories": "Nascondi categorie" } \ No newline at end of file diff --git a/public/language/pl/category.json b/public/language/pl/category.json index 38891e4ec6..5e52f25c1f 100644 --- a/public/language/pl/category.json +++ b/public/language/pl/category.json @@ -7,7 +7,7 @@ "new-topic-button": "Nowy temat", "guest-login-post": "Zaloguj się, aby napisać post", "no-topics": "W tej kategorii nie ma jeszcze żadnych tematów.
Może pora na napisanie pierwszego?", - "no-followers": "Nobody on this website is tracking or watching this category. Track or watch this category in order to begin receiving updates.", + "no-followers": "Nikt na tej witrynie nie śledzi ani nie obserwuje tej kategorii. Zacznij śledzić lub obserwować tę kategorię aby zacząć odbierać aktualizacje.", "browsing": "przegląda", "no-replies": "Nikt jeszcze nie odpowiedział", "no-new-posts": "Brak nowych postów.", diff --git a/public/language/pl/world.json b/public/language/pl/world.json index fc9f128a41..d8b73d4cb4 100644 --- a/public/language/pl/world.json +++ b/public/language/pl/world.json @@ -16,6 +16,6 @@ "onboard.why": "Mnóstwo rzeczy dzieje się poza tym forum ale niekoniecznie zgodnych z Twoimi zainteresowaniami. Dlatego śledzenie konkretnych użytkowników jest dobrą metodą aby uzyskać więcej zawartości przez nich dodawanych.", "onboard.how": "W międzyczasie możesz użyć przycisków skrótów na górze aby przekonać się jak forum jest powiązane a okaże się, że zapewnia wiele dodatkowych treści!", - "show-categories": "Show categories", - "hide-categories": "Hide categories" + "show-categories": "Pokaż kategorie", + "hide-categories": "Ukryj kategorie" } \ No newline at end of file From 227bfabb8bef2df5b8a5ba6cbf48cafee432b35a Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Fri, 2 May 2025 09:19:56 +0000 Subject: [PATCH 02/76] Latest translations and fallbacks --- .../language/he/admin/advanced/database.json | 2 +- public/language/he/admin/advanced/errors.json | 2 +- public/language/he/admin/advanced/events.json | 8 +-- public/language/he/admin/advanced/logs.json | 4 +- .../he/admin/appearance/customise.json | 6 +-- .../language/he/admin/appearance/skins.json | 8 +-- .../language/he/admin/appearance/themes.json | 10 ++-- public/language/he/admin/dashboard.json | 28 +++++------ .../language/he/admin/development/info.json | 4 +- .../language/he/admin/development/logger.json | 2 +- public/language/he/admin/extend/rewards.json | 10 ++-- public/language/he/admin/extend/widgets.json | 16 +++--- .../language/he/admin/manage/categories.json | 18 +++---- public/language/he/admin/menu.json | 6 +-- public/language/he/admin/settings/sounds.json | 4 +- public/language/he/admin/settings/user.json | 2 +- public/language/he/category.json | 2 +- public/language/he/email.json | 50 +++++++++---------- public/language/he/error.json | 44 ++++++++-------- public/language/he/global.json | 2 +- public/language/he/groups.json | 20 ++++---- public/language/he/search.json | 2 +- public/language/he/uploads.json | 4 +- public/language/he/user.json | 8 +-- public/language/he/world.json | 4 +- public/language/vi/category.json | 2 +- public/language/vi/flags.json | 2 +- public/language/vi/world.json | 4 +- public/language/zh-CN/category.json | 2 +- public/language/zh-CN/world.json | 4 +- 30 files changed, 140 insertions(+), 140 deletions(-) diff --git a/public/language/he/admin/advanced/database.json b/public/language/he/admin/advanced/database.json index 68c0208cb3..cf3736e51a 100644 --- a/public/language/he/admin/advanced/database.json +++ b/public/language/he/admin/advanced/database.json @@ -22,7 +22,7 @@ "mongo.bytes-out": "ביטים יוצאים", "mongo.num-requests": "מספר בקשות", "mongo.raw-info": "מידע לא מעובד מ-MongoDB", - "mongo.unauthorized": "NodeBB לא הצליחה לקבל את המידע הדרוש מ-MongoDB. אנא בדוק שלמשתמש יש הרשאת clusterMonitor ל-admin database.", + "mongo.unauthorized": "NodeBB לא הצליחה לקבל את המידע הדרוש מ-MongoDB. אנא בדקו שלמשתמש יש הרשאת clusterMonitor ל-admin database.", "redis": "Redis", "redis.version": "גרסת Redis", diff --git a/public/language/he/admin/advanced/errors.json b/public/language/he/admin/advanced/errors.json index ac86dbfdbf..43ec79168d 100644 --- a/public/language/he/admin/advanced/errors.json +++ b/public/language/he/admin/advanced/errors.json @@ -10,6 +10,6 @@ "route": "נתיב", "count": "ספירה", "no-routes-not-found": "הידד! אין שגיאות 404!", - "clear404-confirm": "האם אתה בטוח שאתה רוצה לנקות את לוג שגיאות 404?", + "clear404-confirm": "האם לנקות את לוג שגיאות 404?", "clear404-success": "שגיאות \"404 לא נמצא\" נוקו" } \ No newline at end of file diff --git a/public/language/he/admin/advanced/events.json b/public/language/he/admin/advanced/events.json index 10cfb34164..65d39624ad 100644 --- a/public/language/he/admin/advanced/events.json +++ b/public/language/he/admin/advanced/events.json @@ -3,15 +3,15 @@ "no-events": "אין אירועים", "control-panel": "בקרת אירועים", "delete-events": "מחיקת אירועים", - "confirm-delete-all-events": "האם אתה בטוח שאתה רוצה למחוק את כל האירועים שנרשמו?", + "confirm-delete-all-events": "האם למחוק את כל האירועים שנרשמו?", "filters": "מסננים", - "filters-apply": "החל מסננים", + "filters-apply": "החלת מסננים", "filter-type": "סוג אירוע", "filter-start": "מתאריך", "filter-end": "עד תאריך", "filter-user": "סינון לפי משתמש", - "filter-user.placeholder": "הקלד שם משתמש לסינון...", + "filter-user.placeholder": "הקלידו שם משתמש לסינון...", "filter-group": "סינון לפי קבוצה", - "filter-group.placeholder": "הקלד שם קבוצה לסינון...", + "filter-group.placeholder": "הקלידו שם קבוצה לסינון...", "filter-per-page": "פריטים בכל דף" } \ No newline at end of file diff --git a/public/language/he/admin/advanced/logs.json b/public/language/he/admin/advanced/logs.json index 5c1dd85a15..3c6038df10 100644 --- a/public/language/he/admin/advanced/logs.json +++ b/public/language/he/admin/advanced/logs.json @@ -1,7 +1,7 @@ { "logs": "לוגים", "control-panel": "בקרת לוגים", - "reload": "טען לוג מחדש", - "clear": "נקה לוגים", + "reload": "טעינת לוגים מחדש", + "clear": "ניקוי לוגים", "clear-success": "הלוגים נוקו!" } \ No newline at end of file diff --git a/public/language/he/admin/appearance/customise.json b/public/language/he/admin/appearance/customise.json index fc2c805f5f..fc9ca44159 100644 --- a/public/language/he/admin/appearance/customise.json +++ b/public/language/he/admin/appearance/customise.json @@ -1,8 +1,8 @@ { "customise": "התאמה אישית", "custom-css": "CSS/SASS מותאם אישית", - "custom-css.description": "הזן כאן הצהרות CSS/SASS משלך, שיוחלו לאחר כל הסגנונות האחרים.", - "custom-css.enable": "הפעל CSS/SASS מותאם אישית", + "custom-css.description": "הזינו כאן הצהרות CSS/SASS משלך, שיוחלו לאחר כל הסגנונות האחרים.", + "custom-css.enable": "הפעלת CSS/SASS מותאם אישית", "custom-js": "Javascript מותאם אישית", "custom-js.description": "הכניסו כאן JavaScript משלכם, שיבוצע לאחר טעינת הדף לחלוטין.", @@ -15,6 +15,6 @@ "custom-css.livereload": "הפעלת טעינה מחדש אוטומטית.", "custom-css.livereload.description": "הפעלה זו נועדה כדי לרענן את כל החיבורים מכל מכשיר, כאשר תשמרו את הדף המותאם אישית.", "bsvariables": "_variables.scss", - "bsvariables.description": "ניתן לעקוף משתני Bootstrap כאן. אתה יכול גם להשתמש בכלי כמו bootstrap.build ולהדביק את הפלט כאן.
שינויים דורשים בנייה מחדש והפעלה מחדש.", + "bsvariables.description": "ניתן לעקוף משתני Bootstrap כאן. תוכלו גם להשתמש בכלי כמו bootstrap.build ולהדביק את הפלט כאן.
שינויים דורשים בנייה מחדש והפעלה מחדש.", "bsvariables.enable": "Enable _variables.scss" } \ No newline at end of file diff --git a/public/language/he/admin/appearance/skins.json b/public/language/he/admin/appearance/skins.json index ceb0a6a9b8..39893ab1f6 100644 --- a/public/language/he/admin/appearance/skins.json +++ b/public/language/he/admin/appearance/skins.json @@ -2,15 +2,15 @@ "skins": "עיצובים", "bootswatch-skins": "עיצובי Bootswatch", "custom-skins": "עיצובים מותאמים אישית", - "add-skin": "הוסף עיצוב", - "save-custom-skins": "שמור עיצוב מותאם אישית", + "add-skin": "הוספת עיצוב", + "save-custom-skins": "שמירת עיצוב מותאם אישית", "save-custom-skins-success": "עיצובים מותאמים אישית נשמרו בהצלחה", "custom-skin-name": "שם עיצוב מותאם אישית", "custom-skin-variables": "משתני עיצוב מותאם אישית", "loading": "טוען עיצובים", "homepage": "דף הפרוייקט", - "select-skin": "בחר עיצוב זה", - "revert-skin": "חזור לעיצוב מקורי", + "select-skin": "בחירת עיצוב זה", + "revert-skin": "חזרה לעיצוב מקורי", "current-skin": "עיצוב נוכחי", "skin-updated": "עיצוב עודכן", "applied-success": "עיצוב %1 הוחל בהצלחה", diff --git a/public/language/he/admin/appearance/themes.json b/public/language/he/admin/appearance/themes.json index 507ccd8534..514681e5c8 100644 --- a/public/language/he/admin/appearance/themes.json +++ b/public/language/he/admin/appearance/themes.json @@ -2,12 +2,12 @@ "themes": "ערכות נושא", "checking-for-installed": "בודק ערכות נושא מותקנות...", "homepage": "דף הבית", - "select-theme": "בחר ערכת נושא", - "revert-theme": "חזור לערכת נושא מקורית", + "select-theme": "בחירת ערכת נושא", + "revert-theme": "חזרה לערכת נושא מקורית", "current-theme": "ערכת נושא נוכחית", "no-themes": "לא נמצאו ערכות נושא מותקנות", - "revert-confirm": "האם אתה בטוח שאתה רוצה לשחזר את ערכת הנושא הרגילה של NodeBB?", + "revert-confirm": "האם לשחזר את ערכת הנושא הרגילה של NodeBB?", "theme-changed": "ערכת הנושא שונתה", - "revert-success": "החזרת בהצלחה את הפורום שלך לערכת הנושא ברירת המחדל.", - "restart-to-activate": "אנא בצע בנייה והפעלה מחדש כדי להחיל את ערכת הנושא הזו." + "revert-success": "החזרתם בהצלחה את הפורום שלכם לערכת הנושא ברירת המחדל.", + "restart-to-activate": "אנא בצעו בנייה והפעלה מחדש כדי להחיל את ערכת הנושא הזו." } \ No newline at end of file diff --git a/public/language/he/admin/dashboard.json b/public/language/he/admin/dashboard.json index a1aeceeff0..bdaa869915 100644 --- a/public/language/he/admin/dashboard.json +++ b/public/language/he/admin/dashboard.json @@ -12,8 +12,8 @@ "page-views-custom": "טווח תאריכים מותאם אישית", "page-views-custom-start": "תחילת טווח", "page-views-custom-end": "סוף טווח", - "page-views-custom-help": "הכנס טווח תאריכים של התקופה בה תרצה לצפות בתעבורת הפורום. הפורמט הנדרש הוא YYYY-MM-DD", - "page-views-custom-error": "הזן טווח תאריכים תקין כדלהלן YYYY-MM-DD", + "page-views-custom-help": "הכניסו טווח תאריכים של התקופה בה תרצו לצפות בתעבורת הפורום. הפורמט הנדרש הוא YYYY-MM-DD", + "page-views-custom-error": "הזינו טווח תאריכים תקין כדלהלן YYYY-MM-DD", "stats.yesterday": "אתמול", "stats.today": "היום", @@ -25,21 +25,21 @@ "updates": "עדכונים", "running-version": "הפורום מעודכן לגרסה %1", - "keep-updated": "לעדכוני אבטחה ותיקוני באגים, וודא שהפורום שלך עדכני לגרסה האחרונה.", - "up-to-date": "אתה מעודכן ", + "keep-updated": "לעדכוני אבטחה ותיקוני באגים, וודאו שהפורום שלכם עדכני לגרסה האחרונה.", + "up-to-date": "הינך מעודכן ", "upgrade-available": "גרסה חדשה (v%1) שוחררה. שקול לעדכן את הפורום שלך.", "prerelease-upgrade-available": "זוהי גרסת טרום-הפצה מיושנת של NodeBB. גרסה חדשה (v%1) שוחררה. שקול לשדרג את ה-NodeBB שלך.", "prerelease-warning": " זוהי גרסת טרום-הפצה של NodeBB. עלולים להתרחש באגים לא מכוונים.", "fallback-emailer-not-found": "Fallback emailer לא נמצא!", - "running-in-development": "הפורום פועל במצב פיתוח. הפורום עשוי להיות חשוף לפגיעויות פוטנציאליות; אנא פנה למנהל המערכת שלך", - "latest-lookup-failed": "לא הצליח לחפש את הגרסה האחרונה הזמינה של NodeBB", + "running-in-development": "הפורום פועל במצב פיתוח. הפורום עשוי להיות חשוף לפגיעויות פוטנציאליות; אנא פנו למנהל המערכת שלכם", + "latest-lookup-failed": "לא הצליח למצוא את הגרסה האחרונה הזמינה של NodeBB", "notices": "התראות", "restart-not-required": "לא נדרשת הפעלה מחדש", "restart-required": "נדרשת הפעלה מחדש", "search-plugin-installed": "תוסף חיפוש הותקן", "search-plugin-not-installed": "תוסף חיפוש לא הותקן", - "search-plugin-tooltip": "התקן את תוסף החיפוש מעמוד התוספים על מנת להפעיל את אפשרות החיפוש", + "search-plugin-tooltip": "התקינו את תוסף החיפוש מעמוד התוספים על מנת להפעיל את אפשרות החיפוש", "control-panel": "שליטת מערכת", "rebuild-and-restart": "בנייה והפעלה מחדש", @@ -47,9 +47,9 @@ "restart-warning": "הפעלה או בניה מחדש של הפורום תנתק את כל החיבורים הקיימים למספר שניות", "restart-disabled": "הפעלה או בניה מחדש של הפורום בוטלה, נראה שאינך מפעיל את הפורום דרך שרת מתאים.", "maintenance-mode": "מצב תחזוקה", - "maintenance-mode-title": "לחץ כאן על מנת להכניס את הפורום למצב תחזוקה", + "maintenance-mode-title": "לחצו כאן על מנת להכניס את הפורום למצב תחזוקה", "dark-mode": "מצב כהה", - "realtime-chart-updates": "עדכן תרשים בזמן אמת", + "realtime-chart-updates": "עדכון תרשים בזמן אמת", "active-users": "משתמשים פעילים", "active-users.users": "משתמשים", @@ -91,11 +91,11 @@ "start": "התחלה", "end": "סיום", "filter": "סינון", - "view-as-json": "הצג כ-JSON", - "expand-analytics": "הרחב ניתוח", - "clear-search-history": "מחק היסטוריית חיפושים", - "clear-search-history-confirm": "האם אתה בטוח שברצונך למחוק את כל היסטוריית החיפושים?", + "view-as-json": "הצגה כ-JSON", + "expand-analytics": "הרחבת ניתוח", + "clear-search-history": "מחיקת היסטוריית חיפושים", + "clear-search-history-confirm": "האם למחוק את כל היסטוריית החיפושים?", "search-term": "מונח", "search-count": "כמות", - "view-all": "הצג הכל" + "view-all": "הצגת הכל" } diff --git a/public/language/he/admin/development/info.json b/public/language/he/admin/development/info.json index d0b09aa382..d20aa255f5 100644 --- a/public/language/he/admin/development/info.json +++ b/public/language/he/admin/development/info.json @@ -1,5 +1,5 @@ { - "you-are-on": "אתה נמצא ב %1:%2", + "you-are-on": "הינכם נמצאים ב %1:%2", "ip": "IP %1", "nodes-responded": "%1 nodes הגיבו בתוך %2 מילי שניות!", "host": "host", @@ -17,7 +17,7 @@ "cpu-usage": "שימוש ב-CPU", "uptime": "משך זמן פעולת המערכת ללא השבתה", - "registered": "רשום", + "registered": "רשומים", "sockets": "Sockets", "connection-count": "כמות חיבורים", "guests": "אורחים", diff --git a/public/language/he/admin/development/logger.json b/public/language/he/admin/development/logger.json index 1bdf92c432..2177b19175 100644 --- a/public/language/he/admin/development/logger.json +++ b/public/language/he/admin/development/logger.json @@ -6,7 +6,7 @@ "enable-http": "הפעלת רישום HTTP", "enable-socket": "הפעלת רישום אירועים ב-socket.io", "file-path": "נתיב קובץ לוג", - "file-path-placeholder": "/path/to/log/file.log ::: השאירו ריק כדי שהלוג ישמר בטרמינל שלך", + "file-path-placeholder": "/path/to/log/file.log ::: השאירו ריק כדי שהלוג ישמר בטרמינל שלכם", "control-panel": "ניהול לוגים", "update-settings": "עידכון הגדרות לוגים" diff --git a/public/language/he/admin/extend/rewards.json b/public/language/he/admin/extend/rewards.json index ccad7caf8b..5b054e4eed 100644 --- a/public/language/he/admin/extend/rewards.json +++ b/public/language/he/admin/extend/rewards.json @@ -5,11 +5,11 @@ "condition-is": "הינו:", "condition-then": "תגמל ב:", "max-claims": "מספר פעמים בה ניתן לדרוש תגמול", - "zero-infinite": "הזן 0 ללא הגבלה", - "select-reward": "בחר תגמול", - "delete": "מחק", - "enable": "הפעל", - "disable": "השבת", + "zero-infinite": "הזינו 0 ללא הגבלה", + "select-reward": "בחירת תגמול", + "delete": "מחיקה", + "enable": "הפעלה", + "disable": "השבתה", "alert.delete-success": "תגמול נמחק בהצלחה", "alert.no-inputs-found": "תגמול לא חוקי - לא נמצא מידע!", diff --git a/public/language/he/admin/extend/widgets.json b/public/language/he/admin/extend/widgets.json index 50bd6ce969..c603426857 100644 --- a/public/language/he/admin/extend/widgets.json +++ b/public/language/he/admin/extend/widgets.json @@ -16,22 +16,22 @@ "container.body": "גוף", "container.alert": "התראה", - "alert.confirm-delete": "האם אתה בטוח שאתה רוצה למחוק את הווידג'ט?", + "alert.confirm-delete": "האם למחוק את הווידג'ט?", "alert.updated": "העלאת ווידג'טים", "alert.update-success": "הווידג'טים הועלו בהצלחה", "alert.clone-success": "הווידג'טים שוכפלו בהצלחה", - "error.select-clone": "בחר דף לשכפל ממנו", + "error.select-clone": "בחרו דף לשכפל ממנו", "title": "כותרת", - "title.placeholder": "כותרת (מוצגת רק בגורמים מכילים מסוימים)", - "container": "גורם מכיל", - "container.placeholder": "גרור ושחרר גורם מכיל (container) או הזן HTML כאן.", + "title.placeholder": "כותרת (מוצגת רק ב-containers מסוימים)", + "container": "גורם מכיל - Container", + "container.placeholder": "גררו ושחררו גורם מכיל (container) או הזינו HTML כאן.", "show-to-groups": "יוצג בקבוצות", "hide-from-groups": "יוסתר מקבוצות", "start-date": "תאריך התחלה", "end-date": "תאריך סיום", - "hide-on-mobile": "הסתר במובייל", - "hide-drafts": "הסתר טיוטות", - "show-drafts": "הצג טיוטות" + "hide-on-mobile": "הסתרה במובייל", + "hide-drafts": "הסתרת טיוטות", + "show-drafts": "הצגת טיוטות" } \ No newline at end of file diff --git a/public/language/he/admin/manage/categories.json b/public/language/he/admin/manage/categories.json index ed4a9247f9..c6837046d1 100644 --- a/public/language/he/admin/manage/categories.json +++ b/public/language/he/admin/manage/categories.json @@ -1,9 +1,9 @@ { "manage-categories": "ניהול קטגוריות", - "add-category": "הוסף קטגוריה", - "jump-to": "קפוץ אל...", + "add-category": "הוספת קטגוריה", + "jump-to": "קפיצה אל...", "settings": "הגדרות קטגוריות", - "edit-category": "ערוך קטגוריה", + "edit-category": "עריכת קטגוריה", "privileges": "הרשאות", "back-to-categories": "חזרה לרשימת הקטגוריות", "name": "שם קטגוריה", @@ -23,7 +23,7 @@ "is-section": "הגדר קטגוריה זו כמקטע ללא אפשרות כניסה, רק לתתי קטגוריות.", "post-queue": "תור פוסטים", "tag-whitelist": "רשימה לבנה של תגיות", - "upload-image": "העלה תמונה", + "upload-image": "העלו תמונה", "upload": "העלאה", "delete-image": "הסרה", "category-image": "תמונת קטגוריה", @@ -32,8 +32,8 @@ "optional-parent-category": "קטגוריית הורים (אופציונלי)", "top-level": "רמה עליונה", "parent-category-none": "(ללא)", - "copy-parent": "העתק אב", - "copy-settings": "העתק הגדרות מ:", + "copy-parent": "העתקת אב", + "copy-settings": "העתקת הגדרות מ:", "optional-clone-settings": "שכפול הגדרות מקטגוריה (אופציונלי)", "clone-children": "שכפול קטגוריות והגדרות של צאצאים", "purge": "מחיקת קטגוריה", @@ -59,7 +59,7 @@ "privileges.section-moderation": "הרשאות מנחה", "privileges.section-other": "אחר", "privileges.section-user": "משתמש", - "privileges.search-user": "הוסף משתמש", + "privileges.search-user": "הוספת משתמש", "privileges.no-users": "אין הרשאות ספציפיות למשתמש בקטגוריה זו.", "privileges.section-group": "קבוצה", "privileges.group-private": "קבוצה זו פרטית", @@ -89,7 +89,7 @@ "federation.syncing-intro": "קטגוריה יכולה לעקוב אחר \"שחקן קבוצתי\" באמצעות פרוטוקול ActivityPub. אם יתקבל תוכן מאחד השחקנים המפורטים למטה, הוא יתווסף אוטומטית לקטגוריה זו.", "federation.syncing-caveat": "הגדרת סנכרון N.B. כאן יוצרת סנכרון חד כיווני. NodeBB מנסה להירשם/לעקוב אחרי השחקן, אך לא ניתן להניח את ההיפך.", "federation.syncing-none": "קטגוריה זו אינה עוקבת כעת אחר אף אחד.", - "federation.syncing-add": "סנכרן עם...", + "federation.syncing-add": "סינכרון עם...", "federation.syncing-actorUri": "שחקן", "federation.syncing-follow": "עקוב", "federation.syncing-unfollow": "הפסקת מעקב", @@ -101,7 +101,7 @@ "alert.created": "נוצר", "alert.create-success": "קטגוריה נוצרה בהצלחה!", - "alert.none-active": "אין לך קטגוריות פעילות.", + "alert.none-active": "אין לכם קטגוריות פעילות.", "alert.create": "יצירת קטגוריה", "alert.confirm-purge": "

האם אתם בטוחים שאתם רוצים למחוק את קטגוריית \"%1\"?

אזהרה! כל הנושאים והפוסטים בקטגוריה זו ימחקו!

מחיקת קטגוריה תסיר את כל הנושאים והפוסטים ותמחק את הקטגוריה ממסד הנתונים. אם ברצונכם להסיר את הקטגוריה באופן זמני, בחרו ב\"השבתת\" הקטגוריה.

", "alert.purge-success": "הקטגוריה נמחקה!", diff --git a/public/language/he/admin/menu.json b/public/language/he/admin/menu.json index b06f729f77..d32642d723 100644 --- a/public/language/he/admin/menu.json +++ b/public/language/he/admin/menu.json @@ -83,11 +83,11 @@ "search.placeholder": "חיפוש הגדרות", "search.no-results": "אין תוצאות...", "search.search-forum": "חפש בפורום ", - "search.keep-typing": "המשך להקליד על מנת למצוא תוצאות...", - "search.start-typing": "התחל להקליד על מנת לראות תוצאות...", + "search.keep-typing": "המשיכו להקליד על מנת למצוא תוצאות...", + "search.start-typing": "התחילו להקליד על מנת לראות תוצאות...", "connection-lost": "החיבור ל-%1 אבד, מנסה להתחבר מחדש...", "alerts.version": "מעודכן ל-NodeBB v%1", - "alerts.upgrade": "שדרג ל v%1" + "alerts.upgrade": "שדרגו ל v%1" } \ No newline at end of file diff --git a/public/language/he/admin/settings/sounds.json b/public/language/he/admin/settings/sounds.json index 57cca017c5..cd6cfadc8b 100644 --- a/public/language/he/admin/settings/sounds.json +++ b/public/language/he/admin/settings/sounds.json @@ -1,9 +1,9 @@ { "notifications": "התראות", "chat-messages": "הודעות צ'אט", - "play-sound": "נגן", + "play-sound": "נגינה", "incoming-message": "הודעה נכנסת", "outgoing-message": "הודעה יוצאת", - "upload-new-sound": "העלה צליל חדש", + "upload-new-sound": "העלאת צליל חדש", "saved": "הגדרות נשמרו" } \ No newline at end of file diff --git a/public/language/he/admin/settings/user.json b/public/language/he/admin/settings/user.json index b55ddeddfe..0c0d227b39 100644 --- a/public/language/he/admin/settings/user.json +++ b/public/language/he/admin/settings/user.json @@ -64,7 +64,7 @@ "show-email": "הצג כתובת אימייל", "show-fullname": "הצג שם מלא", "restrict-chat": "אשר הודעות צ'אט רק ממשתמשים שאני עוקב אחריהם", - "disable-incoming-chats": "Disable incoming chat messages", + "disable-incoming-chats": "השבתת הודעות צ'אט נכנסות", "outgoing-new-tab": "פתח קישורים חיצוניים בכרטיסייה חדשה", "topic-search": "הפעל חיפוש בתוך נושא", "update-url-with-post-index": "עדכן את כתובת הURL עם מספר הפוסט הנוכחי בזמן גלישה בנושאים", diff --git a/public/language/he/category.json b/public/language/he/category.json index 8c233ac543..1c66c9ddcc 100644 --- a/public/language/he/category.json +++ b/public/language/he/category.json @@ -7,7 +7,7 @@ "new-topic-button": "נושא חדש", "guest-login-post": "התחברו כדי לפרסם", "no-topics": "קטגוריה זו ריקה מנושאים.
למה שלא תנסו להוסיף נושא חדש?", - "no-followers": "Nobody on this website is tracking or watching this category. Track or watch this category in order to begin receiving updates.", + "no-followers": "אף אחד באתר זה לא עוקב אחר או צופה בקטגוריה זו. עקבו אחר או צפו בקטגוריה זו כדי להתחיל לקבל עדכונים.", "browsing": "צופים בנושא זה כעת", "no-replies": "אין תגובות", "no-new-posts": "אין פוסטים חדשים.", diff --git a/public/language/he/email.json b/public/language/he/email.json index 48b1b41c7b..f627a4aba0 100644 --- a/public/language/he/email.json +++ b/public/language/he/email.json @@ -5,29 +5,29 @@ "invite": "הזמנה מ%1", "greeting-no-name": "שלום", "greeting-with-name": "שלום %1", - "email.verify-your-email.subject": "בבקשה אמת את המייל שלך.", + "email.verify-your-email.subject": "נא לאמת את המייל שלך.", "email.verify.text1": "ביקשת לשנות או לאמת את כתובת הדוא\"ל שלך", "email.verify.text2": "לצורכי אבטחה, אנו משנים או מאמתים את כתובת הדוא\"ל רק לאחר שבעלותך מאומת ע\"י דוא\"ל. אם לא אתה ביקשת זאת, תוכל להתעלם ממייל זו.", "email.verify.text3": "לאחר שתאשר את כתובת הדוא\"ל, נשנה את כתובת דוא\"ל הנוכחית בכתובת הזו (%1).", "welcome.text1": "תודה שנרשמת ל%1!", - "welcome.text2": "על מנת להפעיל את החשבון שלך, אנו צריכים לוודא שאתה בעל חשבון המייל שנרשמת איתו.", - "welcome.text3": "מנהל אישר את ההרשמה שלך.\nאתה יכול להתחבר עם השם משתמש והסיסמא שלך מעכשיו.", - "welcome.cta": "לחץ כאן על מנת לאשר את כתובת המייל שלך.", + "welcome.text2": "להפעלת החשבון, נדרש אימות שהאימייל אתו נרשמתם, הוא בבעלותכם.", + "welcome.text3": "מנהל אישר את ההרשמה שלך.\nניתן להתחבר עם השם משתמש והסיסמא שלך מעכשיו.", + "welcome.cta": "לחצו כאן על מנת לאשר את כתובת המייל שלכם.", "invitation.text1": "%1 הזמין אותך להצטרף ל%2", "invitation.text2": "ההזמנה של תפוג ב %1 ימים", - "invitation.cta": "לחץ כאן ליצירת החשבון שלך.", - "reset.text1": "קיבלנו בקשה לאפס את הסיסמה לחשבון שלך, כנראה מפני ששכחת אותה. אם לא ביקשת לאפס את הסיסמה, אנא התעלם ממייל זה.", - "reset.text2": "על מנת להמשיך עם תהליך איפוס הסיסמה, אנא לחץ על הלינק הבא:", - "reset.cta": "לחץ כאן לאפס את הסיסמה שלך.", + "invitation.cta": "לחצו כאן ליצירת החשבון שלכם.", + "reset.text1": "קיבלנו בקשה לאפס את הסיסמה לחשבון שלכם, כנראה מפני ששכחתם אותה. אם לא ביקשתם לאפס את הסיסמה, אנא התעלמו מאימייל זה.", + "reset.text2": "על מנת להמשיך עם תהליך איפוס הסיסמה, אנא לחצו על הלינק הבא:", + "reset.cta": "לחצו כאן לאפס את הסיסמה שלכם.", "reset.notify.subject": "הסיסמה שונתה בהצלחה.", - "reset.notify.text1": "אנו מודיעים לך שב%1, סיסמתך שונתה בהצלחה.", - "reset.notify.text2": "אם לא אישרת בקשה זו, אנא הודע למנהל מיד.", + "reset.notify.text1": "רצינו להסב את תשומת ליבך שב%1, סיסמתך שונתה בהצלחה.", + "reset.notify.text2": "אם לא אישרתם בקשה זו, אנא הודיעו למנהל בהקדם.", "digest.unread-rooms": "חדרים שלא נקראו", "digest.room-name-unreadcount": "%1 (%2 לא נקראו)", "digest.latest-topics": "נושאים אחרונים מ%1", "digest.top-topics": "נושאים עם הכי הרבה הצבעות מ-%1", "digest.popular-topics": "הנושאים הכי פופולריים מ-%1", - "digest.cta": "לחץ כאן כדי לבקר ב %1", + "digest.cta": "לחצו כאן כדי לבקר ב %1", "digest.unsub.info": "תקציר זה נשלח אליך על-פי הגדרות החשבון שלך.", "digest.day": "יום", "digest.week": "שבוע", @@ -36,23 +36,23 @@ "digest.title.day": "התקציר היומי שלך", "digest.title.week": "התקציר השבועי שלך", "digest.title.month": "התקציר החודשי שלך", - "notif.chat.new-message-from-user": "New message from \"%1\"", - "notif.chat.new-message-from-user-in-room": "New message from %1 in room %2", - "notif.chat.cta": "לחץ כאן כדי להמשיך את השיחה", - "notif.chat.unsub.info": "התראה הצ'אט הזו נשלחה אליך על-פי הגדרות החשבון שלך.", - "notif.post.unsub.info": "התראת הפוסט הזו נשלחה אליך על-פי הגדרות החשבון שלך.", - "notif.post.unsub.one-click": "ניתן גם להפסיק את קבלת המיילים כמו זה, בלחיצה על", + "notif.chat.new-message-from-user": "הודעה חדשה מ-\"%1\"", + "notif.chat.new-message-from-user-in-room": "הודעה חדשה מ-%1 בחדר %2", + "notif.chat.cta": "לחצו כאן כדי להמשיך את השיחה", + "notif.chat.unsub.info": "הודעת צ'אט זו נשלחה אליך על-פי הגדרות החשבון שלך.", + "notif.post.unsub.info": "התראת פוסט זו נשלחה אליך על-פי הגדרות החשבון שלך.", + "notif.post.unsub.one-click": "ניתן גם להפסיק את קבלת האימיילים כמו זה, בלחיצה על", "notif.cta": "כניסה לפורום", - "notif.cta-new-reply": "הצג פוסט", - "notif.cta-new-chat": "הצג צ'אט", - "notif.test.short": "בדיקת התראות.", - "notif.test.long": "זוהי בדיקה של ההתראות במייל.", + "notif.cta-new-reply": "הצגת פוסט", + "notif.cta-new-chat": "הצגת צ'אט", + "notif.test.short": "בדיקת התראות", + "notif.test.long": "זוהי בדיקה של ההתראות באימייל.", "test.text1": "זהו אימייל ניסיון על מנת לוודא שהגדרות המייל בוצעו כהלכה בהגדרות NodeBB.", - "unsub.cta": "לחץ כאן לשנות הגדרות אלו", - "unsubscribe": "בטל רישום", - "unsub.success": "אתה לא תקבל יותר מיילים מרשימת התפוצה של %1", + "unsub.cta": "לחצו כאן לשנות הגדרות אלו", + "unsubscribe": "ביטול רישום", + "unsub.success": "לא תקבלו יותר אימיילים מרשימת התפוצה של %1", "unsub.failure.title": "לא ניתן לבטל את המנוי", - "unsub.failure.message": "למרבה הצער, לא הצלחנו לבטל את הרישום שלך מרשימת התפוצה, מכיוון שהייתה בעיה בקישור. עם זאת, אתה יכול לשנות את העדפות הדוא\"ל שלך על ידי מעבר להגדרות המשתמש שלך.

(שגיאה: %1)", + "unsub.failure.message": "למרבה הצער, לא הצלחנו לבטל את הרישום שלך מרשימת התפוצה, מכיוון שהייתה בעיה בקישור. עם זאת, תוכלו לשנות את העדפות הדוא\"ל שלכם על ידי מעבר להגדרות המשתמש שלכם.

(שגיאה: %1)", "banned.subject": "הורחקת מ %1", "banned.text1": "המשתמש %1 הורחק מ %2.", "banned.text2": "הרחקה זו תמשך עד %1", diff --git a/public/language/he/error.json b/public/language/he/error.json index b7b709b4f3..82af4336b3 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -67,8 +67,8 @@ "no-chat-room": "חדר צ'אט לא קיים", "no-privileges": "ההרשאות שלכם אינן מספיקות לביצוע פעולה זו.", "category-disabled": "קטגוריה לא פעילה", - "post-deleted": "Post deleted", - "topic-locked": "Topic locked", + "post-deleted": "הפוסט נמחק", + "topic-locked": "הנושא נעול", "post-edit-duration-expired": "ניתן לערוך פוסטים עד %1 שניות מרגע כתיבת הפוסט", "post-edit-duration-expired-minutes": "ניתן לערוך פוסטים עד %1 דקות מרגע כתיבת הפוסט", "post-edit-duration-expired-minutes-seconds": "ניתן לערוך פוסטים עד %1 דקות %2 שניות מרגע כתיבת הפוסט", @@ -142,20 +142,20 @@ "group-leave-disabled": "אינכם רשאים לעזוב את הקבוצה כרגע", "group-user-not-pending": "למשתמש אין בקשה ממתינה להצטרף לקבוצה זו.", "gorup-user-not-invited": "המשתמש לא הוזמן להצטרף לקבוצה זו.", - "post-already-deleted": "פוסט זה נמחק כבר", + "post-already-deleted": "פוסט זה כבר נמחק", "post-already-restored": "פוסט זה כבר שוחזר", "topic-already-deleted": "נושא זה כבר נמחק", "topic-already-restored": "נושא זה כבר שוחזר", - "cant-purge-main-post": "אינכם יכולים למחוק את הפוסט הראשי, אנא מחקו את הנושא במקום", + "cant-purge-main-post": "לא ניתן למחוק את הפוסט הראשי, ניתן למחוק את הנושא במקום זה", "topic-thumbnails-are-disabled": "תמונות ממוזערות לנושא אינן מאופשרות.", "invalid-file": "קובץ לא תקין", "uploads-are-disabled": "העלאת קבצים אינה מאופשרת", - "signature-too-long": "מצטערים, החתימה שלכם אינה יכולה להכיל יותר מ-%1 תווים.", - "about-me-too-long": "מצטערים, דף האודות שלכם אינו יכול להיות ארוך מ-%1 תווים.", + "signature-too-long": "מצטערים, החתימה אינה יכולה להכיל יותר מ-%1 תווים.", + "about-me-too-long": "מצטערים, דף האודות אינו יכול להיות ארוך מ-%1 תווים.", "cant-chat-with-yourself": "לא ניתן לעשות צ'אט עם עצמכם!", "chat-restricted": "משתמש זה חסם את הודעות הצ'אט שלו ממשתמשים זרים. המשתמש חייב לעקוב אחריכם לפני שתוכלו לשוחח איתו בצ'אט", - "chat-allow-list-user-already-added": "This user is already in your allow list", - "chat-deny-list-user-already-added": "This user is already in your deny list", + "chat-allow-list-user-already-added": "משתמש זה כבר נמצא ברשימה הלבנה שלכם", + "chat-deny-list-user-already-added": "משתמש זה כבר נמצא ברשימת הדחייה שלכם", "chat-user-blocked": "נחסמתם על ידי משתמש זה.", "chat-disabled": "מערכת הצ'אט לא פעילה", "too-many-messages": "שלחתם יותר מדי הודעות, אנא המתינו זמן מה.", @@ -171,21 +171,21 @@ "cant-add-users-to-chat-room": "לא ניתן להוסיף משתמשים לחדר הצ'אט.", "cant-remove-users-from-chat-room": "לא ניתן להסיר משתמשים מחדר הצ'אט.", "chat-room-name-too-long": "שם החדר ארוך מדי. השם לא יכול להיות ארוך מ-%1 תווים.", - "remote-chat-received-too-long": "קיבלת הודעת צ'אט מ %1, אבל זה היה ארוך מדי ונדחה.", + "remote-chat-received-too-long": "התקבלה הודעת צ'אט מ %1, אבל זה היה ארוך מדי ונדחה.", "already-voting-for-this-post": "הצבעתם כבר בנושא זה.", "reputation-system-disabled": "מערכת המוניטין לא פעילה.", "downvoting-disabled": "היכולת להצביע נגד מושבתת", "not-enough-reputation-to-chat": "נדרש %1 מוניטין כדי לכתוב בצ'אט", "not-enough-reputation-to-upvote": "נדרש %1 מוניטין כדי להצביע בעד", "not-enough-reputation-to-downvote": "נדרש %1 מוניטין כדי להצביע למטה", - "not-enough-reputation-to-post-links": "אתה צריך %1 מוניטין כדי לפרסם קישורים", + "not-enough-reputation-to-post-links": "נדרש %1 מוניטין כדי לפרסם קישורים", "not-enough-reputation-to-flag": "נדרש %1 מוניטין כדי לדווח על פוסט", "not-enough-reputation-min-rep-website": "נרדש %1 מוניטין כדי להוסיף אתר אינטרנט", "not-enough-reputation-min-rep-aboutme": "נדרש %1 מוניטין כדי להוסיף תיאור", "not-enough-reputation-min-rep-signature": "נדרש %1 מוניטין כדי להוסיף חתימה", "not-enough-reputation-min-rep-profile-picture": "נדרש %1 מוניטין כדי להוסיף תמונת פרופיל", "not-enough-reputation-min-rep-cover-picture": "נדרש %1 מוניטין כדי להוסיף תמונת רקע לפרופיל", - "not-enough-reputation-custom-field": "אתה צריך %1 מוניטין עבור %2", + "not-enough-reputation-custom-field": "נדרש %1 מוניטין עבור %2", "custom-user-field-value-too-long": "ערך שדה מותאם אישית ארוך מדי, %1", "custom-user-field-select-value-invalid": "האפשרות שנבחרה בשדה מותאם אישית אינה חוקית, %1", "custom-user-field-invalid-text": "טקסט שדה מותאם אישית אינו חוקי, %1", @@ -201,12 +201,12 @@ "too-many-user-flags-per-day": "ניתן לדווח רק על %1 משתמשים כל יום", "cant-flag-privileged": "לא ניתן לדווח על מנהלים או על תוכן שנכתב על ידי מנהלים.", "cant-locate-flag-report": "לא ניתן לאתר דוח דיווח", - "self-vote": "אי אפשר להצביע על פוסט שיצרתם", - "too-many-upvotes-today": "ביכולתכם להצביע בעד רק %1 פעמים ביום", - "too-many-upvotes-today-user": "ביכולתכם להצביע בעד משתמש מסוים רק %1 פעמים ביום", - "too-many-downvotes-today": "ביכולתכם להצביע נגד %1 פעמים ביום", - "too-many-downvotes-today-user": "ביכולתכם להצביע נגד משתמש %1 פעמים ביום", - "reload-failed": "אירעה תקלה ב NodeBB בזמן הטעינה של: \"%1\". המערכת תמשיך להגיש דפים קיימים, אבל כדאי שתשחזרו את הפעולות שלכם מהפעם האחרונה בה המערכת עבדה כראוי.", + "self-vote": "לא ניתן להצביע לפוסט שלך", + "too-many-upvotes-today": "ניתן להצביע בעד רק %1 פעמים ביום", + "too-many-upvotes-today-user": "ניתן להצביע בעד משתמש מסוים רק %1 פעמים ביום", + "too-many-downvotes-today": "ניתן להצביע נגד %1 פעמים ביום", + "too-many-downvotes-today-user": "ניתן להצביע נגד משתמש %1 פעמים ביום", + "reload-failed": "אירעה תקלה ב-NodeBB בזמן הטעינה של: \"%1\". המערכת תמשיך להציג דפים קיימים, אבל כדאי שתשחזרו את הפעולות שלכם מהפעם האחרונה בה המערכת עבדה כראוי.", "registration-error": "שגיאה בהרשמה", "parse-error": "אירעה שגיאה בעת ניתוח תגובת השרת", "wrong-login-type-email": "אנא השתמשו בכתובת המייל שלכם להתחברות", @@ -225,10 +225,10 @@ "session-mismatch": "סשן לא תואם", "session-mismatch-text": "נראה שסשן ההתחברות שלכם אינו תואם לשרת. אנא רעננו את הדף.", "no-topics-selected": "לא נבחרו נושאים!", - "cant-move-to-same-topic": "אינכם יכולים להעביר פוסט לאותו נושא!", - "cant-move-topic-to-same-category": "אינכם יכולים להעביר נושא לאותה קטגוריה!", - "cannot-block-self": "אינכם יכולים לחסום את עצמכם!", - "cannot-block-privileged": "אינך יכול לחסום מנהלים או מנחים גלובליים", + "cant-move-to-same-topic": "לא ניתן להעביר פוסט לאותו נושא!", + "cant-move-topic-to-same-category": "לא ניתן להעביר נושא לאותה קטגוריה!", + "cannot-block-self": "לא ניתן לחסום את עצמך!", + "cannot-block-privileged": "לא ניתן לחסום מנהלים או מנחים גלובליים", "cannot-block-guest": "אורחים אינם יכולים לחסום משתמשים אחרים", "already-blocked": "המשתמש חסום כבר", "already-unblocked": "המשתמש שוחרר כבר מהחסימה", @@ -237,7 +237,7 @@ "invalid-plugin-id": "מזהה תוסף לא תקין", "plugin-not-whitelisted": "לא ניתן להתקין את התוסף – ניתן להתקין דרך הניהול רק תוספים שנמצאים ברשימה הלבנה של מנהל החבילות של NodeBB.", "plugin-installation-via-acp-disabled": "התקנת תוסף באמצעות ACP מושבתת", - "plugins-set-in-configuration": "אינך רשאי לשנות את מצב הפלאגין כפי שהם מוגדרים בזמן ריצה (config.json, משתני סביבה או ארגומנטים של מסוף), אנא שנה את התצורה במקום זאת.", + "plugins-set-in-configuration": "לא ניתן לשנות את מצב התוסף כפי שהם מוגדרים בזמן ריצה (config.json, משתני סביבה או ארגומנטים של מסוף), שנו את התצורה במקום זאת.", "theme-not-set-in-configuration": "כאשר מגדירים תוספים פעילים בתצורה, שינוי ערכות נושא מחייב הוספת ערכת הנושא החדשה לרשימת התוספים הפעילים לפני עדכון שלו ב-ACP", "topic-event-unrecognized": "אירוע הנושא '%1' לא מזוהה", "category.handle-taken": "קישור הקטגוריה כבר נלקחה, אנא בחרו אחרת.", diff --git a/public/language/he/global.json b/public/language/he/global.json index 0c2e29a309..dcbbbf0dbc 100644 --- a/public/language/he/global.json +++ b/public/language/he/global.json @@ -82,7 +82,7 @@ "downvoted": "הוצבע נגד", "views": "צפיות", "posters": "כותבים", - "watching": "Watching", + "watching": "במעקב", "reputation": "מוניטין", "lastpost": "פוסט אחרון", "firstpost": "פוסט ראשון", diff --git a/public/language/he/groups.json b/public/language/he/groups.json index b97ad4d994..0b30fc0a9c 100644 --- a/public/language/he/groups.json +++ b/public/language/he/groups.json @@ -39,28 +39,28 @@ "details.description": "תיאור", "details.member-post-cids": "מזהי קטגוריות להצגת פוסטים מהם", "details.badge-preview": "תצוגה מקדימה של התג", - "details.change-icon": "שנה אייקון", - "details.change-label-colour": "שנה צבע תווית", - "details.change-text-colour": "שנה צבע טקסט", + "details.change-icon": "שינוי אייקון", + "details.change-label-colour": "שינוי צבע תווית", + "details.change-text-colour": "שינוי צבע טקסט", "details.badge-text": "טקסט תגית", - "details.userTitleEnabled": "הצג תגית", + "details.userTitleEnabled": "הצגת תגית", "details.private-help": "אם אפשרות זו מופעלת, הצטרפות לקבוצות ידרוש אישור מבעל הקבוצה.", "details.hidden": "מוסתר", "details.hidden-help": "אם אפשרות זו מופעלת, קבוצה זו לא תימצא ברשימת הקבוצות, יהיה ניתן להזמין משתמשים רק באופן ידני", - "details.delete-group": "מחק קבוצה", + "details.delete-group": "מחיקת קבוצה", "details.private-system-help": "קבוצות פרטיות מושבתות ברמת המערכת, אפשרות זו אינה עושה דבר", "event.updated": "פרטי הקבוצה עודכנו", "event.deleted": "קבוצת \"%1\" נמחקה", - "membership.accept-invitation": "קבל הזמנה", - "membership.accept.notification-title": "אתה עכשיו חבר ב%1", + "membership.accept-invitation": "קבלת הזמנה", + "membership.accept.notification-title": "מעכשיו הנך חבר ב%1", "membership.invitation-pending": "הזמנה ממתינה", - "membership.join-group": "הצטרפו לקבוצה", - "membership.leave-group": "עזבו קבוצה", + "membership.join-group": "הצטרפות לקבוצה", + "membership.leave-group": "עזיבת קבוצה", "membership.leave.notification-title": "%1 עזב את קבוצת %2", "membership.reject": "דחייה", "new-group.group-name": "שם קבוצה", "upload-group-cover": "העלאת תמונת נושא לקבוצה", "bulk-invite-instructions": "הזינו רשימה מופרדת בפסיק של משתמשים אותם תרצו להזמין לקבוצה זו.", "bulk-invite": "הזמנת מספר משתמשים", - "remove-group-cover-confirm": "האם להסיר תמונת נושא?" + "remove-group-cover-confirm": "להסיר תמונת נושא?" } \ No newline at end of file diff --git a/public/language/he/search.json b/public/language/he/search.json index 564a160918..bc304838d4 100644 --- a/public/language/he/search.json +++ b/public/language/he/search.json @@ -63,7 +63,7 @@ "time-older-than-15552000": "זמן: ישן מחצי שנה", "time-newer-than-31104000": "זמן: חדש משנה", "time-older-than-31104000": "זמן: ישן משנה", - "sort-by": "סדר על-פי", + "sort-by": "מיון לפי", "sort": "מיון", "last-reply-time": "תאריך תגובה אחרון", "topic-title": "כותרת הנושא", diff --git a/public/language/he/uploads.json b/public/language/he/uploads.json index 75476e2a37..00415767b5 100644 --- a/public/language/he/uploads.json +++ b/public/language/he/uploads.json @@ -1,9 +1,9 @@ { "uploading-file": "מעלה את הקובץ...", - "select-file-to-upload": "בחר קובץ להעלאה!", + "select-file-to-upload": "בחרו קובץ להעלאה!", "upload-success": "הקובץ הועלה בהצלחה!", "maximum-file-size": "מקסימום %1 קילובייט", "no-uploads-found": "לא נמצאו העלאות!", - "public-uploads-info": "העלאות הינם ציבוריות. כל מי שיש ברשותו לינק לקובץ יוכל לראות אותו.", + "public-uploads-info": "העלאות הינם ציבוריות. כל מי שיש ברשותו קישור לקובץ יוכל לראות אותו.", "private-uploads-info": "העלאות הינם פרטיות. רק משתמשים מחוברים יוכלו לראותם." } \ No newline at end of file diff --git a/public/language/he/user.json b/public/language/he/user.json index db0dc80c4d..85c7a435d0 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -105,10 +105,10 @@ "show-email": "הצגת כתובת האימייל שלי", "show-fullname": "הצגת שמי המלא", "restrict-chats": "אפשר רק הודעות צ'אט ממשתמשים שאני עוקב אחריהם", - "disable-incoming-chats": "Disable incoming chat messages ", - "chat-allow-list": "Allow chat messages from the following users", - "chat-deny-list": "Deny chat messages from the following users", - "chat-list-add-user": "Add user", + "disable-incoming-chats": "השבתת הודעות צ'אט נכנסות ", + "chat-allow-list": "אפשור הודעות צ'אט מהמשתמשים הבאים", + "chat-deny-list": "דחיית הודעות צ'אט מהמשתמשים הבאים", + "chat-list-add-user": "הוספת משתמש", "digest-label": "הרשמה לקבלת תקציר", "digest-description": "הרשמה לקבלת עדכונים בדואר אלקטרוני מפורום זה (הודעות ונושאים חדשים) בהתאם ללוח זמנים מוגדר מראש", "digest-off": "כבוי", diff --git a/public/language/he/world.json b/public/language/he/world.json index a636d38898..c4d625016c 100644 --- a/public/language/he/world.json +++ b/public/language/he/world.json @@ -16,6 +16,6 @@ "onboard.why": "יש הרבה דברים שקורים מחוץ לפורום הזה, ולא כל זה רלוונטי לתחומי העניין שלכם. לכן מעקב אחר אנשים הוא הדרך הטובה ביותר לאותת שאתם רוצים לראות יותר ממישהו אחר.", "onboard.how": "בינתיים, תוכלו ללחוץ על כפתורי הקיצור בחלק העליון כדי לראות על מה עוד הפורום הזה יודע, ולהתחיל לגלות תוכן חדש!", - "show-categories": "Show categories", - "hide-categories": "Hide categories" + "show-categories": "הצגת קטגוריות", + "hide-categories": "הסתרת קטגוריות" } \ No newline at end of file diff --git a/public/language/vi/category.json b/public/language/vi/category.json index 464aca7b47..4abc703c44 100644 --- a/public/language/vi/category.json +++ b/public/language/vi/category.json @@ -7,7 +7,7 @@ "new-topic-button": "Chủ Đề Mới", "guest-login-post": "Đăng nhập để đăng bài", "no-topics": "Không có chủ đề nào trong danh mục này.
Sao bạn không thử đăng?", - "no-followers": "Nobody on this website is tracking or watching this category. Track or watch this category in order to begin receiving updates.", + "no-followers": "Không ai trên trang web này đang theo dõi hoặc xem danh mục này. Theo dõi hoặc xem danh mục này để bắt đầu nhận cập nhật.", "browsing": "lướt xem", "no-replies": "Không có ai trả lời", "no-new-posts": "Không bài đăng mới.", diff --git a/public/language/vi/flags.json b/public/language/vi/flags.json index bc746b52f7..1ed4630497 100644 --- a/public/language/vi/flags.json +++ b/public/language/vi/flags.json @@ -29,7 +29,7 @@ "filter-assignee": "Ủy nhiệm", "filter-cid": "Chuyên mục", "filter-quick-mine": "Được giao cho tôi", - "filter-cid-all": "Tất cả chuyên mục", + "filter-cid-all": "Tất cả các danh mục", "apply-filters": "Áp Dụng Bộ Lọc", "more-filters": "Thêm Bộ Lọc", "fewer-filters": "Bớt Bộ Lọc", diff --git a/public/language/vi/world.json b/public/language/vi/world.json index 2a1521ed2b..4a34f79c9a 100644 --- a/public/language/vi/world.json +++ b/public/language/vi/world.json @@ -16,6 +16,6 @@ "onboard.why": "Có rất nhiều điều diễn ra bên ngoài diễn đàn này và không phải tất cả đều phù hợp với sở thích của bạn. Đó là lý do tại sao theo dõi mọi người là cách tốt nhất để báo hiệu rằng bạn muốn biết thêm thông tin từ ai đó.", "onboard.how": "Trong thời gian chờ đợi, bạn có thể nhấp vào các nút tắt ở trên cùng để xem diễn đàn này biết thêm những gì và bắt đầu khám phá một số nội dung mới!", - "show-categories": "Show categories", - "hide-categories": "Hide categories" + "show-categories": "Hiển thị các danh mục", + "hide-categories": "Ẩn các danh mục" } \ No newline at end of file diff --git a/public/language/zh-CN/category.json b/public/language/zh-CN/category.json index d3c4c8c5d7..27a3f239b0 100644 --- a/public/language/zh-CN/category.json +++ b/public/language/zh-CN/category.json @@ -7,7 +7,7 @@ "new-topic-button": "发表主题", "guest-login-post": "登录以发布", "no-topics": "此版块还没有任何内容。
赶紧来发帖吧!", - "no-followers": "Nobody on this website is tracking or watching this category. Track or watch this category in order to begin receiving updates.", + "no-followers": "本网站无人跟踪或关注此版块。跟踪或关注此版块,以便开始接收更新。", "browsing": "正在浏览", "no-replies": "尚无回复", "no-new-posts": "没有新主题", diff --git a/public/language/zh-CN/world.json b/public/language/zh-CN/world.json index f9d9d1d3e9..13ea86163f 100644 --- a/public/language/zh-CN/world.json +++ b/public/language/zh-CN/world.json @@ -16,6 +16,6 @@ "onboard.why": "论坛之外的事情很多,而且并非所有事情都与您的兴趣相关。因此,关注他人是表明您想从某人那里了解更多信息的最佳方式。", "onboard.how": "在此期间,您可以点击顶部的快捷按钮,了解本论坛的其他内容,并开始发现一些新内容!", - "show-categories": "Show categories", - "hide-categories": "Hide categories" + "show-categories": "显示版块", + "hide-categories": "隐藏版块" } \ No newline at end of file From f3bd8590e9741751dcf1804ed4568859a6b1c87a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 2 May 2025 14:07:56 -0400 Subject: [PATCH 03/76] fix(deps): bump markdown --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 2a1af9a8a4..ab55e532eb 100644 --- a/install/package.json +++ b/install/package.json @@ -102,7 +102,7 @@ "nodebb-plugin-dbsearch": "6.2.16", "nodebb-plugin-emoji": "6.0.2", "nodebb-plugin-emoji-android": "4.1.1", - "nodebb-plugin-markdown": "13.1.2", + "nodebb-plugin-markdown": "13.2.0", "nodebb-plugin-mentions": "4.7.4", "nodebb-plugin-spam-be-gone": "2.3.2", "nodebb-plugin-web-push": "0.7.4", @@ -200,4 +200,4 @@ "url": "https://github.com/barisusakli" } ] -} \ No newline at end of file +} From e958010f40658ffd2756dbb30a2a427013230b56 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 May 2025 19:41:55 -0400 Subject: [PATCH 04/76] chore(deps): update dependency mocha to v11.2.2 (#13366) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index ab55e532eb..037ccf0901 100644 --- a/install/package.json +++ b/install/package.json @@ -170,7 +170,7 @@ "husky": "8.0.3", "jsdom": "26.1.0", "lint-staged": "15.5.1", - "mocha": "11.1.0", + "mocha": "11.2.2", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", "nyc": "17.1.0", From 39953ee16ba34926fc3f03a93deff1402f45c22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 2 May 2025 19:48:35 -0400 Subject: [PATCH 05/76] https://github.com/NodeBB/NodeBB/issues/13367 --- src/views/partials/topic/post-parent.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/partials/topic/post-parent.tpl b/src/views/partials/topic/post-parent.tpl index 98a2eec002..5e73f8cf70 100644 --- a/src/views/partials/topic/post-parent.tpl +++ b/src/views/partials/topic/post-parent.tpl @@ -5,7 +5,7 @@ {./parent.user.displayname} - +
{./parent.content}
From 4b78710b46f1bbe230d816f79da1c91e390aaba0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 09:06:41 -0400 Subject: [PATCH 06/76] fix(deps): update dependency ace-builds to v1.41.0 (#13372) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 037ccf0901..d039a41093 100644 --- a/install/package.json +++ b/install/package.json @@ -39,7 +39,7 @@ "@textcomplete/contenteditable": "0.1.13", "@textcomplete/core": "0.1.13", "@textcomplete/textarea": "0.1.13", - "ace-builds": "1.40.1", + "ace-builds": "1.41.0", "archiver": "7.0.1", "async": "3.2.6", "autoprefixer": "10.4.21", From 7cf61ab0809b5e7ffd8ebfb5bc4e8ab8c93736b7 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 5 May 2025 16:35:12 -0400 Subject: [PATCH 07/76] fix: update AP api (un)follow ids to be url encoded id instead of handle --- src/api/activitypub.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/api/activitypub.js b/src/api/activitypub.js index be6600d3a2..ddb2cd2386 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -44,11 +44,8 @@ activitypubApi.follow = enabledCheck(async (caller, { type, id, actor } = {}) => } actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; - const [handle, isFollowing] = await Promise.all([ - user.getUserField(actor, 'username'), - db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor), - ]); + const isFollowing = await db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor); if (isFollowing) { // already following return; } @@ -58,7 +55,7 @@ activitypubApi.follow = enabledCheck(async (caller, { type, id, actor } = {}) => await db.sortedSetAdd(`followRequests:${type}.${id}`, timestamp, actor); try { await activitypub.send(type, id, [actor], { - id: `${nconf.get('url')}/${type}/${id}#activity/follow/${handle}/${timestamp}`, + id: `${nconf.get('url')}/${type}/${id}#activity/follow/${encodeURIComponent(actor)}/${timestamp}`, type: 'Follow', object: actor, }); @@ -77,11 +74,8 @@ activitypubApi.unfollow = enabledCheck(async (caller, { type, id, actor }) => { } actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; - const [handle, isFollowing] = await Promise.all([ - user.getUserField(actor, 'username'), - db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor), - ]); + const isFollowing = await db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor); if (!isFollowing) { // already not following return; } @@ -93,7 +87,7 @@ activitypubApi.unfollow = enabledCheck(async (caller, { type, id, actor }) => { const timestamp = timestamps[0] || timestamps[1]; const object = { - id: `${nconf.get('url')}/${type}/${id}#activity/follow/${handle}/${timestamp}`, + id: `${nconf.get('url')}/${type}/${id}#activity/follow/${encodeURIComponent(actor)}/${timestamp}`, type: 'Follow', object: actor, }; From 9f80d10d09a5a6bc9ae040c3119b6063de39b65c Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 5 May 2025 16:50:44 -0400 Subject: [PATCH 08/76] fix: 1b12 creates being dropped --- src/activitypub/inbox.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index 2fb2810a6c..f8ebc250c7 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -252,7 +252,7 @@ inbox.like = async (req) => { }; inbox.announce = async (req) => { - const { actor, object, published, to, cc } = req.body; + let { actor, object, published, to, cc } = req.body; activitypub.helpers.log(`[activitypub/inbox/announce] Parsing Announce(${object.type}) from ${actor}`); let timestamp = new Date(published); timestamp = timestamp.toString() !== 'Invalid Date' ? timestamp.getTime() : Date.now(); @@ -292,6 +292,12 @@ inbox.announce = async (req) => { break; } + case object.type === 'Create': { + object = object.object; + // falls through + } + + // Announce(Object) case activitypub._constants.acceptedPostTypes.includes(object.type): { if (String(object.id).startsWith(nconf.get('url'))) { // Local object const { type, id } = await activitypub.helpers.resolveLocalId(object.id); From f8d012c81c7d9fa1141eed8940db828ee9af9861 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 5 May 2025 17:01:07 -0400 Subject: [PATCH 09/76] fix: AP inbox update handling for non-note objects --- src/activitypub/inbox.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index f8ebc250c7..9094d077b1 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -84,8 +84,8 @@ inbox.update = async (req) => { throw new Error('[[error:activitypub.origin-mismatch]]'); } - switch (object.type) { - case 'Note': { + switch (true) { + case activitypub._constants.acceptedPostTypes.includes(object.type): { const [isNote, isMessage] = await Promise.all([ posts.exists(object.id), messaging.messageExists(object.id), @@ -136,16 +136,12 @@ inbox.update = async (req) => { break; } - case 'Application': // falls through - case 'Group': // falls through - case 'Organization': // falls through - case 'Service': // falls through - case 'Person': { + case activitypub._constants.acceptableActorTypes.has(object.type): { await activitypub.actors.assert(object.id, { update: true }); break; } - case 'Tombstone': { + case object.type === 'Tombstone': { const [isNote, isMessage/* , isActor */] = await Promise.all([ posts.exists(object.id), messaging.messageExists(object.id), From 92af41582951ceda4a263d0fdcd300b69fc55ce4 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 6 May 2025 09:20:36 +0000 Subject: [PATCH 10/76] Latest translations and fallbacks --- public/language/nb/search.json | 2 +- public/language/nn-NO/admin/settings/general.json | 2 +- public/language/nn-NO/admin/settings/user.json | 2 +- public/language/nn-NO/error.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/language/nb/search.json b/public/language/nb/search.json index 498ab1f9a5..e0798274ba 100644 --- a/public/language/nb/search.json +++ b/public/language/nb/search.json @@ -1,7 +1,7 @@ { "type-to-search": "Skriv for å søke", "results-matching": "%1 resultat(er) samsvarer med \"%2\", (%3 sekunder)", - "no-matches": "Ingen treff funnet", + "no-matches": "Ingen treff", "advanced-search": "Avansert søk", "in": "I", "in-titles": "I titler", diff --git a/public/language/nn-NO/admin/settings/general.json b/public/language/nn-NO/admin/settings/general.json index f14f5c6598..2157dd08fb 100644 --- a/public/language/nn-NO/admin/settings/general.json +++ b/public/language/nn-NO/admin/settings/general.json @@ -32,7 +32,7 @@ "pwa": "Progressiv webapp", "touch-icon": "Touch-ikon", "touch-icon.upload": "Last opp touch-ikon", - "touch-icon.help": "Bruk touch-ikonet for å visast på mobile einingar.", + "touch-icon.help": "Bruk touch-ikonet for å vise på mobile einingar.", "maskable-icon": "Maskerbart ikon", "maskable-icon.help": "Maskerbare ikon vert brukt for å tilpasse webappen til ulike skjermstorleikar.", "outgoing-links": "Utgåande lenkjer", diff --git a/public/language/nn-NO/admin/settings/user.json b/public/language/nn-NO/admin/settings/user.json index e7a0a4e540..5dc36d2d55 100644 --- a/public/language/nn-NO/admin/settings/user.json +++ b/public/language/nn-NO/admin/settings/user.json @@ -90,7 +90,7 @@ "restrictions.seconds-edit-after-new": "Sekund til redigering for nye brukarar", "restrictions.milliseconds-between-messages": "Millisekund mellom meldingar", "restrictions.groups-exempt-from-new-user-restrictions": "Grupper unnateke frå nye brukarrestriksjonar", - "guest-settings": "Gjestinnstillingar", + "guest-settings": "Gjesteinnstillingar", "handles.enabled": "Aktiver handtering av gjestar", "handles.enabled-help": "Aktiver for å la gjestar kunne sjå og interagere med forumet innanfor visse grenser.", "topic-views.enabled": "Aktiver visning av emne for gjestar", diff --git a/public/language/nn-NO/error.json b/public/language/nn-NO/error.json index 49728c4b7a..3325de8889 100644 --- a/public/language/nn-NO/error.json +++ b/public/language/nn-NO/error.json @@ -188,7 +188,7 @@ "not-enough-reputation-custom-field": "Du treng %1 i omdømme for å %2", "custom-user-field-value-too-long": "Tilpassa felt er er for langt, %1", "custom-user-field-select-value-invalid": "Alternativet i tilpassa felt er ugyldig, %1 ", - "custom-user-field-invalid-text": "Tilpassa tekst felt er ugyldig, %1", + "custom-user-field-invalid-text": "Tilpassa tekstfelt er ugyldig, %1", "custom-user-field-invalid-link": "Tilpassa lenke felt er ugyldig, %1", "custom-user-field-invalid-number": "Tilpassa felt for tal er ugyldig, %1", "custom-user-field-invalid-date": "Tilpassa felt for dato er ugyldig, %1", From 72b3a21539da1111b5fc9770f2bdb4f6d103a4c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:32:32 -0400 Subject: [PATCH 11/76] fix(deps): update dependency nodebb-theme-harmony to v2.1.12 (#13377) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index d039a41093..4cde5a66d4 100644 --- a/install/package.json +++ b/install/package.json @@ -107,7 +107,7 @@ "nodebb-plugin-spam-be-gone": "2.3.2", "nodebb-plugin-web-push": "0.7.4", "nodebb-rewards-essentials": "1.0.2", - "nodebb-theme-harmony": "2.1.11", + "nodebb-theme-harmony": "2.1.12", "nodebb-theme-lavender": "7.1.19", "nodebb-theme-peace": "2.2.41", "nodebb-theme-persona": "14.1.10", From 2aa0bfc5f660956abf0cffec2016307c3e8ac490 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:32:50 -0400 Subject: [PATCH 12/76] fix(deps): update dependency nodebb-theme-peace to v2.2.42 (#13378) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 4cde5a66d4..b0e880fb40 100644 --- a/install/package.json +++ b/install/package.json @@ -109,7 +109,7 @@ "nodebb-rewards-essentials": "1.0.2", "nodebb-theme-harmony": "2.1.12", "nodebb-theme-lavender": "7.1.19", - "nodebb-theme-peace": "2.2.41", + "nodebb-theme-peace": "2.2.42", "nodebb-theme-persona": "14.1.10", "nodebb-widget-essentials": "7.0.37", "nodemailer": "6.10.1", From 954aa541ac5783c3c345139cc13076caa2039860 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:35:30 -0400 Subject: [PATCH 13/76] fix(deps): update dependency nodebb-theme-persona to v14.1.11 (#13379) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b0e880fb40..7642b7ab88 100644 --- a/install/package.json +++ b/install/package.json @@ -110,7 +110,7 @@ "nodebb-theme-harmony": "2.1.12", "nodebb-theme-lavender": "7.1.19", "nodebb-theme-peace": "2.2.42", - "nodebb-theme-persona": "14.1.10", + "nodebb-theme-persona": "14.1.11", "nodebb-widget-essentials": "7.0.37", "nodemailer": "6.10.1", "nprogress": "0.2.0", From 7f757615e5fc08d686a8580af7df2b32d2c5a22c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:37:52 -0400 Subject: [PATCH 14/76] fix(deps): update dependency nodebb-widget-essentials to v7.0.38 (#13380) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 7642b7ab88..b396f0620e 100644 --- a/install/package.json +++ b/install/package.json @@ -111,7 +111,7 @@ "nodebb-theme-lavender": "7.1.19", "nodebb-theme-peace": "2.2.42", "nodebb-theme-persona": "14.1.11", - "nodebb-widget-essentials": "7.0.37", + "nodebb-widget-essentials": "7.0.38", "nodemailer": "6.10.1", "nprogress": "0.2.0", "passport": "0.7.0", From 2c0aba02d325af8ec49fe76e70aaf0b20a4dccad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:59:17 -0400 Subject: [PATCH 15/76] fix(deps): update dependency nodebb-plugin-mentions to v4.7.5 (#13386) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b396f0620e..b1edf3b79b 100644 --- a/install/package.json +++ b/install/package.json @@ -103,7 +103,7 @@ "nodebb-plugin-emoji": "6.0.2", "nodebb-plugin-emoji-android": "4.1.1", "nodebb-plugin-markdown": "13.2.0", - "nodebb-plugin-mentions": "4.7.4", + "nodebb-plugin-mentions": "4.7.5", "nodebb-plugin-spam-be-gone": "2.3.2", "nodebb-plugin-web-push": "0.7.4", "nodebb-rewards-essentials": "1.0.2", From 625ce96f94cc3197ed94186610d418ed32627dd0 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 10:03:27 -0400 Subject: [PATCH 16/76] fix: leftover `handle` var --- src/api/activitypub.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/activitypub.js b/src/api/activitypub.js index ddb2cd2386..4701c0ca51 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -98,7 +98,7 @@ activitypubApi.unfollow = enabledCheck(async (caller, { type, id, actor }) => { } await activitypub.send(type, id, [actor], { - id: `${nconf.get('url')}/${type}/${id}#activity/undo:follow/${handle}/${timestamp}`, + id: `${nconf.get('url')}/${type}/${id}#activity/undo:follow/${encodeURIComponent(actor)}/${timestamp}`, type: 'Undo', object, }); From b4338489712f44286f52d0a3ea726c83801cde56 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 10:44:47 -0400 Subject: [PATCH 17/76] fix: #13374, updates to posts.edit to handle remote content updates better --- src/activitypub/inbox.js | 1 + src/activitypub/mocks.js | 3 ++- src/activitypub/notes.js | 33 +++++++++++++++++++-------------- src/posts/edit.js | 5 +++-- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index 9094d077b1..19f149caec 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -95,6 +95,7 @@ inbox.update = async (req) => { switch (true) { case isNote: { const postData = await activitypub.mocks.post(object); + postData.tags = await activitypub.notes._normalizeTags(postData._activitypub.tag, postData.cid); await posts.edit(postData); const isDeleted = await posts.getPostField(object.id, 'deleted'); if (isDeleted) { diff --git a/src/activitypub/mocks.js b/src/activitypub/mocks.js index 3bae10b50f..b569768f98 100644 --- a/src/activitypub/mocks.js +++ b/src/activitypub/mocks.js @@ -355,12 +355,13 @@ Mocks.post = async (objects) => { uid, pid, // tid, --> purposely omitted - name, content, sourceContent, timestamp, toPid, + title: name, // used in post.edit + edited, editor: edited ? uid : undefined, _activitypub: { to, cc, audience, attachment, tag, url, image }, diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 747eeb54d2..963ec5469f 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -27,6 +27,24 @@ async function unlock(value) { await db.deleteObjectField('locks', value); } +Notes._normalizeTags = async (tag, cid) => { + const systemTags = (meta.config.systemTags || '').split(','); + const maxTags = await categories.getCategoryField(cid, 'maxTags'); + const tags = (tag || []) + .map((tag) => { + tag.name = tag.name.startsWith('#') ? tag.name.slice(1) : tag.name; + return tag; + }) + .filter(o => o.type === 'Hashtag' && !systemTags.includes(o.name)) + .map(t => t.name); + + if (tags.length > maxTags) { + tags.length = maxTags; + } + + return tags; +}; + Notes.assert = async (uid, input, options = { skipChecks: false }) => { /** * Given the id or object of any as:Note, either retrieves the full context (if resolvable), @@ -166,22 +184,9 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { const count = unprocessed.length; activitypub.helpers.log(`[notes/assert] ${count} new note(s) found.`); - let tags; if (!hasTid) { const { to, cc, attachment } = mainPost._activitypub; - const systemTags = (meta.config.systemTags || '').split(','); - const maxTags = await categories.getCategoryField(cid, 'maxTags'); - tags = (mainPost._activitypub.tag || []) - .map((tag) => { - tag.name = tag.name.startsWith('#') ? tag.name.slice(1) : tag.name; - return tag; - }) - .filter(o => o.type === 'Hashtag' && !systemTags.includes(o.name)) - .map(t => t.name); - - if (tags.length > maxTags) { - tags.length = maxTags; - } + const tags = Notes._normalizeTags(mainPost._activitypub.tag || []); await Promise.all([ topics.post({ diff --git a/src/posts/edit.js b/src/posts/edit.js index 610a659e4f..077616b29e 100644 --- a/src/posts/edit.js +++ b/src/posts/edit.js @@ -35,7 +35,7 @@ module.exports = function (Posts) { await scheduledTopicCheck(data, topicData); data.content = data.content === null ? postData.content : data.content; - const oldContent = postData.content; // for diffing purposes + const oldContent = postData.sourceContent || postData.content; // for diffing purposes const editPostData = getEditPostData(data, topicData, postData); if (data.handle) { @@ -55,7 +55,7 @@ module.exports = function (Posts) { ]); await Posts.setPostFields(data.pid, result.post); - const contentChanged = data.content !== oldContent || + const contentChanged = ((data.sourceContent || data.content) !== oldContent) || topic.renamed || topic.tagsupdated; @@ -194,6 +194,7 @@ module.exports = function (Posts) { function getEditPostData(data, topicData, postData) { const editPostData = { content: data.content, + sourceContent: data.sourceContent, editor: data.uid, }; From e2a8cf98f3f6b95596a24b1991fcd58a1334b2d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 11:17:35 -0400 Subject: [PATCH 18/76] fix(deps): update dependency @fontsource/poppins to v5.2.6 (#13376) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b1edf3b79b..094c74d5b3 100644 --- a/install/package.json +++ b/install/package.json @@ -30,7 +30,7 @@ "dependencies": { "@adactive/bootstrap-tagsinput": "0.8.2", "@fontsource/inter": "5.2.5", - "@fontsource/poppins": "5.2.5", + "@fontsource/poppins": "5.2.6", "@fortawesome/fontawesome-free": "6.7.2", "@isaacs/ttlcache": "1.4.1", "@nodebb/spider-detector": "2.0.3", From 450ce3b85ce86fd1e2411cf033398be90ecd79af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 11:29:19 -0400 Subject: [PATCH 19/76] chore(deps): update dependency @eslint/js to v9.26.0 (#13371) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 094c74d5b3..deaa9b394a 100644 --- a/install/package.json +++ b/install/package.json @@ -161,7 +161,7 @@ "@commitlint/cli": "19.8.0", "@commitlint/config-angular": "19.8.0", "coveralls": "3.1.1", - "@eslint/js": "9.25.1", + "@eslint/js": "9.26.0", "@stylistic/eslint-plugin-js": "4.2.0", "eslint-config-nodebb": "1.1.4", "eslint-plugin-import": "2.31.0", From 7f59238d3a17c8dd077e9e296b15a431c45ae9ed Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 12:09:07 -0400 Subject: [PATCH 20/76] refactor: Helpers.generateCollection so that total count and a bound function can be passed in, #13153 --- src/activitypub/helpers.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/activitypub/helpers.js b/src/activitypub/helpers.js index 4a8b2b08fa..b67484ff1d 100644 --- a/src/activitypub/helpers.js +++ b/src/activitypub/helpers.js @@ -448,11 +448,11 @@ Helpers.makeSet = (object, properties) => new Set(properties.reduce((memo, prope [object[property]] : []), [])); -Helpers.generateCollection = async ({ set, method, page, perPage, url }) => { +Helpers.generateCollection = async ({ set, method, count, page, perPage, url }) => { if (!method) { - method = db.getSortedSetRange; + method = db.getSortedSetRange.bind(null, set); } - const count = await db.sortedSetCard(set); + count = count || await db.sortedSetCard(set); const pageCount = Math.max(1, Math.ceil(count / perPage)); let items = []; let paginate = true; @@ -470,7 +470,7 @@ Helpers.generateCollection = async ({ set, method, page, perPage, url }) => { const start = Math.max(0, ((page - 1) * perPage) - 1); const stop = Math.max(0, start + perPage - 1); - items = await method(set, start, stop); + items = await method.call(null, start, stop); } const object = { From a2de7aaecfacc284a57f0b9389d978ea85216885 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 12:09:33 -0400 Subject: [PATCH 21/76] fix: #13153, follower and following collections to use generateCollection helper --- src/controllers/activitypub/index.js | 91 +++++++++++----------------- 1 file changed, 35 insertions(+), 56 deletions(-) diff --git a/src/controllers/activitypub/index.js b/src/controllers/activitypub/index.js index ccf85b2012..0d9962ebf2 100644 --- a/src/controllers/activitypub/index.js +++ b/src/controllers/activitypub/index.js @@ -6,6 +6,7 @@ const winston = require('winston'); const meta = require('../../meta'); const user = require('../../user'); const activitypub = require('../../activitypub'); +const utils = require('../../utils'); const helpers = require('../helpers'); const Controller = module.exports; @@ -60,71 +61,49 @@ Controller.fetch = async (req, res, next) => { Controller.getFollowing = async (req, res) => { const { followingCount, followingRemoteCount } = await user.getUserFields(req.params.uid, ['followingCount', 'followingRemoteCount']); const totalItems = parseInt(followingCount || 0, 10) + parseInt(followingRemoteCount || 0, 10); - let orderedItems; - let next = (totalItems && `${nconf.get('url')}/uid/${req.params.uid}/following?page=`) || null; - if (totalItems) { - if (req.query.page) { - const page = parseInt(req.query.page, 10) || 1; - const resultsPerPage = 50; - const start = Math.max(0, page - 1) * resultsPerPage; - const stop = start + resultsPerPage - 1; - - orderedItems = await user.getFollowing(req.params.uid, start, stop); - orderedItems = orderedItems.map(({ userslug }) => `${nconf.get('url')}/user/${userslug}`); - if (stop < totalItems - 1) { - next = `${next}${page + 1}`; - } else { - next = null; - } - } else { - orderedItems = []; - next = `${next}1`; - } - } - - res.status(200).json({ - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'OrderedCollection', - totalItems, - orderedItems, - next, + const count = totalItems; + const collection = await activitypub.helpers.generateCollection({ + method: user.getFollowing.bind(null, req.params.uid), + count, + perPage: 50, + page: req.query.page, + url: `${nconf.get('url')}/uid/${req.params.uid}/following`, }); + + collection.orderedItems = collection.orderedItems.map(({ uid }) => { + if (utils.isNumber(uid)) { + return `${nconf.get('url')}/uid/${uid}`; + } + + return uid; + }); + + res.status(200).json(collection); }; Controller.getFollowers = async (req, res) => { const { followerCount, followerRemoteCount } = await user.getUserFields(req.params.uid, ['followerCount', 'followerRemoteCount']); const totalItems = parseInt(followerCount || 0, 10) + parseInt(followerRemoteCount || 0, 10); - let orderedItems = []; - let next = (totalItems && `${nconf.get('url')}/uid/${req.params.uid}/followers?page=`) || null; - if (totalItems) { - if (req.query.page) { - const page = parseInt(req.query.page, 10) || 1; - const resultsPerPage = 50; - const start = Math.max(0, page - 1) * resultsPerPage; - const stop = start + resultsPerPage - 1; - - orderedItems = await user.getFollowers(req.params.uid, start, stop); - orderedItems = orderedItems.map(({ userslug }) => `${nconf.get('url')}/user/${userslug}`); - if (stop < totalItems - 1) { - next = `${next}${page + 1}`; - } else { - next = null; - } - } else { - orderedItems = []; - next = `${next}1`; - } - } - - res.status(200).json({ - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'OrderedCollection', - totalItems, - orderedItems, - next, + const count = totalItems; + const collection = await activitypub.helpers.generateCollection({ + method: user.getFollowers.bind(null, req.params.uid), + count, + perPage: 50, + page: req.query.page, + url: `${nconf.get('url')}/uid/${req.params.uid}/followers`, }); + + collection.orderedItems = collection.orderedItems.map(({ uid }) => { + if (utils.isNumber(uid)) { + return `${nconf.get('url')}/uid/${uid}`; + } + + return uid; + }); + + res.status(200).json(collection); }; Controller.getOutbox = async (req, res) => { From f83b1fbf68a4d5530b9fb0e1e258e90ce31f7cce Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 12:27:27 -0400 Subject: [PATCH 22/76] fix: extra `orderedItems` property in generated paginated OrderedCollection, #13153 --- src/activitypub/helpers.js | 4 ++-- src/controllers/activitypub/actors.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/activitypub/helpers.js b/src/activitypub/helpers.js index b67484ff1d..299d0c3d35 100644 --- a/src/activitypub/helpers.js +++ b/src/activitypub/helpers.js @@ -451,6 +451,8 @@ Helpers.makeSet = (object, properties) => new Set(properties.reduce((memo, prope Helpers.generateCollection = async ({ set, method, count, page, perPage, url }) => { if (!method) { method = db.getSortedSetRange.bind(null, set); + } else if (set) { + method = method.bind(null, set); } count = count || await db.sortedSetCard(set); const pageCount = Math.max(1, Math.ceil(count / perPage)); @@ -486,8 +488,6 @@ Helpers.generateCollection = async ({ set, method, count, page, perPage, url }) object.next = page < pageCount ? `${url}?page=${page + 1}` : null; object.prev = page > 1 ? `${url}?page=${page - 1}` : null; } - } else { - object.orderedItems = []; } if (paginate) { diff --git a/src/controllers/activitypub/actors.js b/src/controllers/activitypub/actors.js index f9212ba09d..bef49ea835 100644 --- a/src/controllers/activitypub/actors.js +++ b/src/controllers/activitypub/actors.js @@ -156,7 +156,7 @@ Actors.topic = async function (req, res, next) { res.set('ETag', digest); // Convert pids to urls - if (page || collection.totalItems < meta.config.postsPerPage) { + if (page || collection.totalItems < perPage) { collection.orderedItems = collection.orderedItems || []; if (!page || page === 1) { // add OP to collection collection.orderedItems.unshift(mainPid); From 53bb0bbc26ed4993a841f0179f35815f90697cc2 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 12:30:43 -0400 Subject: [PATCH 23/76] fix: handle missing orderedItems --- src/controllers/activitypub/actors.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/controllers/activitypub/actors.js b/src/controllers/activitypub/actors.js index bef49ea835..6a74c2da56 100644 --- a/src/controllers/activitypub/actors.js +++ b/src/controllers/activitypub/actors.js @@ -100,7 +100,9 @@ Actors.replies = async function (req, res) { }); // Convert pids to urls - replies.orderedItems = replies.orderedItems.map(pid => (utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid)); + if (replies.orderedItems) { + replies.orderedItems = replies.orderedItems.map(pid => (utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid)); + } const object = { '@context': 'https://www.w3.org/ns/activitystreams', From 651ebaaf6c3e62e7ea02775a51ea5b1de4b6fb81 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 13:24:58 -0400 Subject: [PATCH 24/76] fix: missing await --- src/activitypub/notes.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 963ec5469f..571e038687 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -93,7 +93,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { chain = chain.sort((a, b) => a.timestamp - b.timestamp); const mainPost = chain[0]; - let { pid: mainPid, tid, uid: authorId, timestamp, name, content, sourceContent, _activitypub } = mainPost; + let { pid: mainPid, tid, uid: authorId, timestamp, title, content, sourceContent, _activitypub } = mainPost; const hasTid = !!tid; const cid = hasTid ? await topics.getTopicField(tid, 'cid') : options.cid || -1; @@ -112,7 +112,6 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { return { tid, count: 0 }; } - let title; if (hasTid) { mainPid = await topics.getTopicField(tid, 'mainPid'); } else { @@ -137,7 +136,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { } // mainPid ok to leave as-is - title = name || activitypub.helpers.generateTitle(utils.decodeHTMLEntities(content || sourceContent)); + title = title || activitypub.helpers.generateTitle(utils.decodeHTMLEntities(content || sourceContent)); // Remove any custom emoji from title if (_activitypub && _activitypub.tag && Array.isArray(_activitypub.tag)) { @@ -186,7 +185,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { if (!hasTid) { const { to, cc, attachment } = mainPost._activitypub; - const tags = Notes._normalizeTags(mainPost._activitypub.tag || []); + const tags = await Notes._normalizeTags(mainPost._activitypub.tag || []); await Promise.all([ topics.post({ From b73a8d3e1dd9fe674c164e2bc500fe3a707de539 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Dec 2023 13:56:25 -0500 Subject: [PATCH 25/76] breaking: removal of `filter:email.send` --- src/emailer.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/emailer.js b/src/emailer.js index f280c21399..ad7e762916 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -344,10 +344,7 @@ Emailer.sendToEmail = async (template, email, language, params) => { const usingFallback = !Plugins.hooks.hasListeners('filter:email.send') && !Plugins.hooks.hasListeners('static:email.send'); try { - if (Plugins.hooks.hasListeners('filter:email.send')) { - // Deprecated, remove in v1.19.0 - await Plugins.hooks.fire('filter:email.send', data); - } else if (Plugins.hooks.hasListeners('static:email.send')) { + if (Plugins.hooks.hasListeners('static:email.send')) { await Plugins.hooks.fire('static:email.send', data); } else { await Emailer.sendViaFallback(data); From 9d8061eab9f018dc8478867d637ac711cbb23ba8 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Dec 2023 14:00:48 -0500 Subject: [PATCH 26/76] breaking: removal of `filter:router.page` --- src/middleware/index.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/middleware/index.js b/src/middleware/index.js index fd0597fb6e..6a5e0c07b0 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -91,11 +91,6 @@ middleware.pageView = helpers.try(async (req, res, next) => { }); middleware.pluginHooks = helpers.try(async (req, res, next) => { - // TODO: Deprecate in v2.0 - await async.each(plugins.loadedHooks['filter:router.page'] || [], (hookObj, next) => { - hookObj.method(req, res, next); - }); - await plugins.hooks.fire('response:router.page', { req: req, res: res, From c84b72fb37bbb6991aa9ff80e8313a24552fa48d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Dec 2023 14:02:31 -0500 Subject: [PATCH 27/76] breaking: removal of `filter:post.purge` --- src/plugins/hooks.js | 15 --------------- src/posts/delete.js | 4 ---- 2 files changed, 19 deletions(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 553e90db45..6dfa1cc21d 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -8,21 +8,6 @@ const als = require('../als'); const Hooks = module.exports; Hooks._deprecated = new Map([ - ['filter:email.send', { - new: 'static:email.send', - since: 'v1.17.0', - until: 'v2.0.0', - }], - ['filter:router.page', { - new: 'response:router.page', - since: 'v1.15.3', - until: 'v2.1.0', - }], - ['filter:post.purge', { - new: 'filter:posts.purge', - since: 'v1.19.6', - until: 'v2.1.0', - }], ['action:post.purge', { new: 'action:posts.purge', since: 'v1.19.6', diff --git a/src/posts/delete.js b/src/posts/delete.js index 6ea4b55453..94c3b4cee2 100644 --- a/src/posts/delete.js +++ b/src/posts/delete.js @@ -63,10 +63,6 @@ module.exports = function (Posts) { p.cid = tidToTopic[p.tid] && tidToTopic[p.tid].cid; }); - // deprecated hook - await Promise.all(postData.map(p => plugins.hooks.fire('filter:post.purge', { post: p, pid: p.pid, uid: uid }))); - - // new hook await plugins.hooks.fire('filter:posts.purge', { posts: postData, pids: postData.map(p => p.pid), From df5c1a938de3db394928a2f24d729d8f9a8eb561 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Dec 2023 14:03:19 -0500 Subject: [PATCH 28/76] breaking: removal of `filter:post.purge` --- src/plugins/hooks.js | 5 ----- src/posts/delete.js | 4 ---- 2 files changed, 9 deletions(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 6dfa1cc21d..483a0fd450 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -8,11 +8,6 @@ const als = require('../als'); const Hooks = module.exports; Hooks._deprecated = new Map([ - ['action:post.purge', { - new: 'action:posts.purge', - since: 'v1.19.6', - until: 'v2.1.0', - }], ['filter:user.verify.code', { new: 'filter:user.verify', since: 'v2.2.0', diff --git a/src/posts/delete.js b/src/posts/delete.js index 94c3b4cee2..5668ac3750 100644 --- a/src/posts/delete.js +++ b/src/posts/delete.js @@ -86,10 +86,6 @@ module.exports = function (Posts) { await resolveFlags(postData, uid); - // deprecated hook - Promise.all(postData.map(p => plugins.hooks.fire('action:post.purge', { post: p, uid: uid }))); - - // new hook plugins.hooks.fire('action:posts.purge', { posts: postData, uid: uid }); await db.deleteAll(postData.map(p => `post:${p.pid}`)); From 7e25946cd7e18e17db8f64144fda6fe4d3ae0e28 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Dec 2023 14:04:18 -0500 Subject: [PATCH 29/76] breaking: removal of `filter:user.verify.code` --- src/plugins/hooks.js | 5 ----- src/user/email.js | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 483a0fd450..8e591c42e3 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -8,11 +8,6 @@ const als = require('../als'); const Hooks = module.exports; Hooks._deprecated = new Map([ - ['filter:user.verify.code', { - new: 'filter:user.verify', - since: 'v2.2.0', - until: 'v3.0.0', - }], ['filter:flags.getFilters', { new: 'filter:flags.init', since: 'v2.7.0', diff --git a/src/user/email.js b/src/user/email.js index b485081713..16ec7e04bc 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -145,7 +145,7 @@ UserEmail.sendValidationEmail = async function (uid, options) { uid, username, confirm_link, - confirm_code: await plugins.hooks.fire('filter:user.verify.code', confirm_code), + confirm_code, email: options.email, subject: options.subject || '[[email:email.verify-your-email.subject]]', From 547fb482eb0bc82905956a5440410bcd118795bf Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Dec 2023 14:04:55 -0500 Subject: [PATCH 30/76] breaking: removal of `filter:flags.getFilters` --- src/flags.js | 1 - src/plugins/hooks.js | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/flags.js b/src/flags.js index d19da08d95..8ae9a6c595 100644 --- a/src/flags.js +++ b/src/flags.js @@ -96,7 +96,6 @@ Flags.init = async function () { }; try { - ({ filters: Flags._filters } = await plugins.hooks.fire('filter:flags.getFilters', hookData)); ({ filters: Flags._filters, states: Flags._states } = await plugins.hooks.fire('filter:flags.init', hookData)); } catch (err) { winston.error(`[flags/init] Could not retrieve filters\n${err.stack}`); diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 8e591c42e3..4769766872 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -8,11 +8,6 @@ const als = require('../als'); const Hooks = module.exports; Hooks._deprecated = new Map([ - ['filter:flags.getFilters', { - new: 'filter:flags.init', - since: 'v2.7.0', - until: 'v3.0.0', - }], ['filter:privileges.global.list', { new: 'static:privileges.global.init', since: 'v3.5.0', From 8ea377a4011d9973c2980bdae9657a6fca20927e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Dec 2023 14:21:05 -0500 Subject: [PATCH 31/76] breaking: removal of deprecated privilege hooks * filter:privileges.global.list * filter:privileges.global.groups.list * filter:privileges.global.list_human * filter:privileges.global.groups.list_human * filter:privileges.list * filter:privileges.groups.list * filter:privileges.list_human * filter:privileges.groups.list_human * filter:privileges.admin.list * filter:privileges.admin.groups.list * filter:privileges.admin.list_human * filter:privileges.admin.groups.list_human --- src/plugins/hooks.js | 66 +++--------------------------------- src/privileges/admin.js | 10 ++---- src/privileges/categories.js | 15 +++----- src/privileges/global.js | 13 ++----- 4 files changed, 13 insertions(+), 91 deletions(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 4769766872..0b79e78f5f 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -8,67 +8,11 @@ const als = require('../als'); const Hooks = module.exports; Hooks._deprecated = new Map([ - ['filter:privileges.global.list', { - new: 'static:privileges.global.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.global.groups.list', { - new: 'static:privileges.global.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.global.list_human', { - new: 'static:privileges.global.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.global.groups.list_human', { - new: 'static:privileges.global.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.list', { - new: 'static:privileges.categories.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.groups.list', { - new: 'static:privileges.categories.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.list_human', { - new: 'static:privileges.categories.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.groups.list_human', { - new: 'static:privileges.categories.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - - ['filter:privileges.admin.list', { - new: 'static:privileges.admin.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.admin.groups.list', { - new: 'static:privileges.admin.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.admin.list_human', { - new: 'static:privileges.admin.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], - ['filter:privileges.admin.groups.list_human', { - new: 'static:privileges.admin.init', - since: 'v3.5.0', - until: 'v4.0.0', - }], + /* ['filter:old.hook.name', { + new: 'filter:new.hook.name', + since: 'v4.0.0', + until: 'v5.0.0', + }], */ ]); Hooks.internals = { diff --git a/src/privileges/admin.js b/src/privileges/admin.js index 958b4cfe49..422e9c1060 100644 --- a/src/privileges/admin.js +++ b/src/privileges/admin.js @@ -39,8 +39,8 @@ privsAdmin.init = async () => { } }; -privsAdmin.getUserPrivilegeList = async () => await plugins.hooks.fire('filter:privileges.admin.list', Array.from(_privilegeMap.keys())); -privsAdmin.getGroupPrivilegeList = async () => await plugins.hooks.fire('filter:privileges.admin.groups.list', Array.from(_privilegeMap.keys()).map(privilege => `groups:${privilege}`)); +privsAdmin.getUserPrivilegeList = () => Array.from(_privilegeMap.keys()); +privsAdmin.getGroupPrivilegeList = () => Array.from(_privilegeMap.keys()).map(privilege => `groups:${privilege}`); privsAdmin.getPrivilegeList = async () => { const [user, group] = await Promise.all([ privsAdmin.getUserPrivilegeList(), @@ -149,18 +149,12 @@ privsAdmin.list = async function (uid) { groupPrivilegeList.splice(idx, 1); } - const labels = await utils.promiseParallel({ - users: plugins.hooks.fire('filter:privileges.admin.list_human', privilegeLabels.slice()), - groups: plugins.hooks.fire('filter:privileges.admin.groups.list_human', privilegeLabels.slice()), - }); - const keys = { users: userPrivilegeList, groups: groupPrivilegeList, }; const payload = await utils.promiseParallel({ - labels, labelData: Array.from(_privilegeMap.values()), users: helpers.getUserPrivileges(0, keys.users), groups: helpers.getGroupPrivileges(0, keys.groups), diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 6061b28abe..3efa1e2413 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -53,8 +53,8 @@ privsCategories.getType = function (privilege) { return priv && priv.type ? priv.type : ''; }; -privsCategories.getUserPrivilegeList = async () => await plugins.hooks.fire('filter:privileges.list', Array.from(_privilegeMap.keys())); -privsCategories.getGroupPrivilegeList = async () => await plugins.hooks.fire('filter:privileges.groups.list', Array.from(_privilegeMap.keys()).map(privilege => `groups:${privilege}`)); +privsCategories.getUserPrivilegeList = () => Array.from(_privilegeMap.keys()); +privsCategories.getGroupPrivilegeList = () => Array.from(_privilegeMap.keys()).map(privilege => `groups:${privilege}`); privsCategories.getPrivilegeList = async () => { const [user, group] = await Promise.all([ @@ -72,27 +72,20 @@ privsCategories.getPrivilegesByFilter = function (filter) { // Method used in admin/category controller to show all users/groups with privs in that given cid privsCategories.list = async function (cid) { - let labels = Array.from(_privilegeMap.values()).map(data => data.label); - labels = await utils.promiseParallel({ - users: plugins.hooks.fire('filter:privileges.list_human', labels.slice()), - groups: plugins.hooks.fire('filter:privileges.groups.list_human', labels.slice()), - }); - const keys = await utils.promiseParallel({ users: privsCategories.getUserPrivilegeList(), groups: privsCategories.getGroupPrivilegeList(), }); const payload = await utils.promiseParallel({ - labels, labelData: Array.from(_privilegeMap.values()), users: helpers.getUserPrivileges(cid, keys.users), groups: helpers.getGroupPrivileges(cid, keys.groups), }); payload.keys = keys; - payload.columnCountUserOther = payload.labels.users.length - privsCategories._coreSize; - payload.columnCountGroupOther = payload.labels.groups.length - privsCategories._coreSize; + payload.columnCountUserOther = payload.labelData.length - privsCategories._coreSize; + payload.columnCountGroupOther = payload.labelData.length - privsCategories._coreSize; return payload; }; diff --git a/src/privileges/global.js b/src/privileges/global.js index aca4d85250..9de1beba8d 100644 --- a/src/privileges/global.js +++ b/src/privileges/global.js @@ -54,8 +54,8 @@ privsGlobal.getType = function (privilege) { return priv && priv.type ? priv.type : ''; }; -privsGlobal.getUserPrivilegeList = async () => await plugins.hooks.fire('filter:privileges.global.list', Array.from(_privilegeMap.keys())); -privsGlobal.getGroupPrivilegeList = async () => await plugins.hooks.fire('filter:privileges.global.groups.list', Array.from(_privilegeMap.keys()).map(privilege => `groups:${privilege}`)); +privsGlobal.getUserPrivilegeList = () => Array.from(_privilegeMap.keys()); +privsGlobal.getGroupPrivilegeList = () => Array.from(_privilegeMap.keys()).map(privilege => `groups:${privilege}`); privsGlobal.getPrivilegeList = async () => { const [user, group] = await Promise.all([ privsGlobal.getUserPrivilegeList(), @@ -65,21 +65,12 @@ privsGlobal.getPrivilegeList = async () => { }; privsGlobal.list = async function () { - async function getLabels() { - const labels = Array.from(_privilegeMap.values()).map(data => data.label); - return await utils.promiseParallel({ - users: plugins.hooks.fire('filter:privileges.global.list_human', labels.slice()), - groups: plugins.hooks.fire('filter:privileges.global.groups.list_human', labels.slice()), - }); - } - const keys = await utils.promiseParallel({ users: privsGlobal.getUserPrivilegeList(), groups: privsGlobal.getGroupPrivilegeList(), }); const payload = await utils.promiseParallel({ - labels: getLabels(), labelData: Array.from(_privilegeMap.values()), users: helpers.getUserPrivileges(0, keys.users), groups: helpers.getGroupPrivileges(0, keys.groups), From 15b6a2c117a9ab13afb0eeef631e12b7651be428 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 5 Dec 2023 10:06:36 -0500 Subject: [PATCH 32/76] chore: remove unused require --- src/middleware/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/middleware/index.js b/src/middleware/index.js index 6a5e0c07b0..5a0e69842f 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -1,6 +1,5 @@ 'use strict'; -const async = require('async'); const path = require('path'); const validator = require('validator'); const nconf = require('nconf'); From 860ac8953e753ef29fcc2b8abcb0130b07cb624f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 15:08:21 -0400 Subject: [PATCH 33/76] docs: remove since-removed `labels` property from api --- .../read/admin/manage/privileges/cid.yaml | 13 ---------- .../write/categories/cid/moderator/uid.yaml | 13 ---------- .../write/categories/cid/privileges.yaml | 13 ---------- .../categories/cid/privileges/privilege.yaml | 26 ------------------- 4 files changed, 65 deletions(-) diff --git a/public/openapi/read/admin/manage/privileges/cid.yaml b/public/openapi/read/admin/manage/privileges/cid.yaml index d4b0ed43da..c395f39172 100644 --- a/public/openapi/read/admin/manage/privileges/cid.yaml +++ b/public/openapi/read/admin/manage/privileges/cid.yaml @@ -21,19 +21,6 @@ get: privileges: type: object properties: - labels: - type: object - properties: - users: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name - groups: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name labelData: type: array items: diff --git a/public/openapi/write/categories/cid/moderator/uid.yaml b/public/openapi/write/categories/cid/moderator/uid.yaml index 78ca52ca96..217c3c09b0 100644 --- a/public/openapi/write/categories/cid/moderator/uid.yaml +++ b/public/openapi/write/categories/cid/moderator/uid.yaml @@ -31,19 +31,6 @@ put: response: type: object properties: - labels: - type: object - properties: - users: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name - groups: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name labelData: type: array items: diff --git a/public/openapi/write/categories/cid/privileges.yaml b/public/openapi/write/categories/cid/privileges.yaml index 6ed7c6fbf8..b450aee682 100644 --- a/public/openapi/write/categories/cid/privileges.yaml +++ b/public/openapi/write/categories/cid/privileges.yaml @@ -24,19 +24,6 @@ get: response: type: object properties: - labels: - type: object - properties: - users: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name - groups: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name labelData: type: array items: diff --git a/public/openapi/write/categories/cid/privileges/privilege.yaml b/public/openapi/write/categories/cid/privileges/privilege.yaml index d6985f27f3..06303ac092 100644 --- a/public/openapi/write/categories/cid/privileges/privilege.yaml +++ b/public/openapi/write/categories/cid/privileges/privilege.yaml @@ -41,19 +41,6 @@ put: response: type: object properties: - labels: - type: object - properties: - users: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name - groups: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name labelData: type: array items: @@ -191,19 +178,6 @@ delete: response: type: object properties: - labels: - type: object - properties: - users: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name - groups: - type: array - items: - type: string - description: Language key of the privilege name's user-friendly name labelData: type: array items: From 52df41b9060123390fe3da8f8ba123acb5dc6f4e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2025 15:13:29 -0400 Subject: [PATCH 34/76] test: adjustment for now-removed labels property --- test/categories.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/categories.js b/test/categories.js index 5309bd1545..46972873e9 100644 --- a/test/categories.js +++ b/test/categories.js @@ -476,9 +476,7 @@ describe('Categories', () => { it('should get privilege settings', async () => { const data = await apiCategories.getPrivileges({ uid: adminUid }, categoryObj.cid); - assert(data.labels); - assert(data.labels.users); - assert(data.labels.groups); + assert(data.labelData); assert(data.keys.users); assert(data.keys.groups); assert(data.users); From b6f4de5bffe9f9282e6fb720aed66d3156730fc5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 17:25:40 -0400 Subject: [PATCH 35/76] fix(deps): update dependency esbuild to v0.25.4 (#13385) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index deaa9b394a..e24eb18262 100644 --- a/install/package.json +++ b/install/package.json @@ -67,7 +67,7 @@ "csrf-sync": "4.1.0", "daemon": "1.1.0", "diff": "7.0.0", - "esbuild": "0.25.3", + "esbuild": "0.25.4", "express": "4.21.2", "express-session": "1.18.1", "express-useragent": "1.0.15", From e6a196127435752cd27127290e02e7ad3bd9c17b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 17:25:50 -0400 Subject: [PATCH 36/76] fix(deps): update dependency bootstrap to v5.3.6 (#13384) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index e24eb18262..83b22ec361 100644 --- a/install/package.json +++ b/install/package.json @@ -47,7 +47,7 @@ "benchpressjs": "2.5.5", "body-parser": "2.2.0", "bootbox": "6.0.3", - "bootstrap": "5.3.5", + "bootstrap": "5.3.6", "bootswatch": "5.3.5", "chalk": "4.1.2", "chart.js": "4.4.9", From 96dc5c89a462cc5a289762a6ea618a2192e01eba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 17:26:01 -0400 Subject: [PATCH 37/76] chore(deps): update dependency lint-staged to v15.5.2 (#13383) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 83b22ec361..a56ca35029 100644 --- a/install/package.json +++ b/install/package.json @@ -169,7 +169,7 @@ "grunt-contrib-watch": "1.1.0", "husky": "8.0.3", "jsdom": "26.1.0", - "lint-staged": "15.5.1", + "lint-staged": "15.5.2", "mocha": "11.2.2", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", From ebe40f960c52aa6596a5e7bfc6fa9b97e8155d9d Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 7 May 2025 09:20:10 +0000 Subject: [PATCH 38/76] Latest translations and fallbacks --- public/language/nb/admin/advanced/logs.json | 2 +- public/language/nb/login.json | 2 +- public/language/nb/success.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/nb/admin/advanced/logs.json b/public/language/nb/admin/advanced/logs.json index ba29274563..7f08b66fc6 100644 --- a/public/language/nb/admin/advanced/logs.json +++ b/public/language/nb/admin/advanced/logs.json @@ -3,5 +3,5 @@ "control-panel": "Kontrollpanel for logg", "reload": "Last inn logg på nytt", "clear": "Tøm logg", - "clear-success": "Logg er tømt!" + "clear-success": "Logg er tømt" } \ No newline at end of file diff --git a/public/language/nb/login.json b/public/language/nb/login.json index 7b71016b86..a95e58c37b 100644 --- a/public/language/nb/login.json +++ b/public/language/nb/login.json @@ -5,7 +5,7 @@ "forgot-password": "Glemt passord?", "alternative-logins": "Alternativ innlogging", "failed-login-attempt": "Innlogging mislyktes", - "login-successful": "Du har blitt logget inn!", + "login-successful": "Du er innlogget!", "dont-have-account": "Har du ikke en konto?", "logged-out-due-to-inactivity": "Du har blitt logget ut av administratorsidene fordi du har vært inaktiv for lenge", "caps-lock-enabled": "Caps Lock er skrudd på" diff --git a/public/language/nb/success.json b/public/language/nb/success.json index f1d8830fa0..ec1ca0f243 100644 --- a/public/language/nb/success.json +++ b/public/language/nb/success.json @@ -1,7 +1,7 @@ { "success": "Suksess", "topic-post": "Du har nå publisert.", - "post-queued": "Innlegget ditt er satt i kø for godkjenning. Du vil få en melding når den har blitt godkjent eller avvist.", + "post-queued": "Innlegget ditt er satt i kø for godkjenning. Du vil få en melding når det har blitt godkjent eller avvist.", "authentication-successful": "Innlogging vellykket!", "settings-saved": "Innstillinger lagret!" } \ No newline at end of file From a819d39c31f5f0e843701c5e59cf87de3aa9f294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 7 May 2025 12:42:22 -0400 Subject: [PATCH 39/76] test: update filter:router.page tests to response:router.page --- test/controllers.js | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/test/controllers.js b/test/controllers.js index c0c7b22a7f..b2174d8cf9 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -1442,44 +1442,44 @@ describe('Controllers', () => { }); it('should handle CSRF error', async () => { - plugins.loadedHooks['filter:router.page'] = plugins.loadedHooks['filter:router.page'] || []; - plugins.loadedHooks['filter:router.page'].push({ - method: function (req, res, next) { + plugins.loadedHooks['response:router.page'] = plugins.loadedHooks['response:router.page'] || []; + plugins.loadedHooks['response:router.page'].push({ + method: function () { const err = new Error('csrf-error'); err.code = 'EBADCSRFTOKEN'; - next(err); + throw err; }, }); const { response } = await request.get(`${nconf.get('url')}/users`); - plugins.loadedHooks['filter:router.page'] = []; + plugins.loadedHooks['response:router.page'] = []; assert.equal(response.statusCode, 403); }); it('should handle black-list error', async () => { - plugins.loadedHooks['filter:router.page'] = plugins.loadedHooks['filter:router.page'] || []; - plugins.loadedHooks['filter:router.page'].push({ - method: function (req, res, next) { + plugins.loadedHooks['response:router.page'] = plugins.loadedHooks['response:router.page'] || []; + plugins.loadedHooks['response:router.page'].push({ + method: function () { const err = new Error('blacklist error message'); err.code = 'blacklisted-ip'; - next(err); + throw err; }, }); const { response, body } = await request.get(`${nconf.get('url')}/users`); - plugins.loadedHooks['filter:router.page'] = []; + plugins.loadedHooks['response:router.page'] = []; assert.equal(response.statusCode, 403); assert.equal(body, 'blacklist error message'); }); it('should handle page redirect through error', async () => { - plugins.loadedHooks['filter:router.page'] = plugins.loadedHooks['filter:router.page'] || []; - plugins.loadedHooks['filter:router.page'].push({ - method: function (req, res, next) { + plugins.loadedHooks['response:router.page'] = plugins.loadedHooks['response:router.page'] || []; + plugins.loadedHooks['response:router.page'].push({ + method: function () { const err = new Error('redirect'); err.status = 302; err.path = '/popular'; - plugins.loadedHooks['filter:router.page'] = []; - next(err); + plugins.loadedHooks['response:router.page'] = []; + throw err; }, }); const { response, body } = await request.get(`${nconf.get('url')}/users`); @@ -1488,14 +1488,14 @@ describe('Controllers', () => { }); it('should handle api page redirect through error', async () => { - plugins.loadedHooks['filter:router.page'] = plugins.loadedHooks['filter:router.page'] || []; - plugins.loadedHooks['filter:router.page'].push({ - method: function (req, res, next) { + plugins.loadedHooks['response:router.page'] = plugins.loadedHooks['response:router.page'] || []; + plugins.loadedHooks['response:router.page'].push({ + method: function () { const err = new Error('redirect'); err.status = 308; err.path = '/api/popular'; - plugins.loadedHooks['filter:router.page'] = []; - next(err); + plugins.loadedHooks['response:router.page'] = []; + throw err; }, }); const { response, body } = await request.get(`${nconf.get('url')}/api/users`); @@ -1505,15 +1505,15 @@ describe('Controllers', () => { }); it('should handle error page', async () => { - plugins.loadedHooks['filter:router.page'] = plugins.loadedHooks['filter:router.page'] || []; - plugins.loadedHooks['filter:router.page'].push({ - method: function (req, res, next) { + plugins.loadedHooks['response:router.page'] = plugins.loadedHooks['response:router.page'] || []; + plugins.loadedHooks['response:router.page'].push({ + method: function () { const err = new Error('regular error'); - next(err); + throw err; }, }); const { response, body } = await request.get(`${nconf.get('url')}/users`); - plugins.loadedHooks['filter:router.page'] = []; + plugins.loadedHooks['response:router.page'] = []; assert.equal(response.statusCode, 500); assert(body); }); From c7a164aef559676d4f3e4188ef0aceda78f91b0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 13:02:39 -0400 Subject: [PATCH 40/76] fix(deps): update dependency webpack to v5.99.8 (#13390) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a56ca35029..b9242ac806 100644 --- a/install/package.json +++ b/install/package.json @@ -147,7 +147,7 @@ "toobusy-js": "0.5.1", "tough-cookie": "5.1.2", "validator": "13.15.0", - "webpack": "5.99.7", + "webpack": "5.99.8", "webpack-merge": "6.0.1", "winston": "3.17.0", "workerpool": "9.2.0", From 4f0f67a45f815a93e0aab2a337d36814ef5b3791 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 18:58:52 -0400 Subject: [PATCH 41/76] fix(deps): update dependency csrf-sync to v4.2.0 (#13364) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b9242ac806..16359943a2 100644 --- a/install/package.json +++ b/install/package.json @@ -64,7 +64,7 @@ "cookie-parser": "1.4.7", "cron": "4.3.0", "cropperjs": "1.6.2", - "csrf-sync": "4.1.0", + "csrf-sync": "4.2.0", "daemon": "1.1.0", "diff": "7.0.0", "esbuild": "0.25.4", From 0b4d403c619fbfd00e8fe8d8f95930cd71c7a720 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 18:59:04 -0400 Subject: [PATCH 42/76] fix(deps): update dependency nodemailer to v7 (#13381) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 16359943a2..6c45c9bfef 100644 --- a/install/package.json +++ b/install/package.json @@ -112,7 +112,7 @@ "nodebb-theme-peace": "2.2.42", "nodebb-theme-persona": "14.1.11", "nodebb-widget-essentials": "7.0.38", - "nodemailer": "6.10.1", + "nodemailer": "7.0.2", "nprogress": "0.2.0", "passport": "0.7.0", "passport-http-bearer": "1.0.1", From 7a7a4f0ab7b901806b4c2e3e87323701c1f7755d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 09:40:53 -0400 Subject: [PATCH 43/76] chore(deps): update commitlint monorepo to v19.8.1 (#13394) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 7755411a40..f75b2ae416 100644 --- a/install/package.json +++ b/install/package.json @@ -158,8 +158,8 @@ }, "devDependencies": { "@apidevtools/swagger-parser": "10.1.0", - "@commitlint/cli": "19.8.0", - "@commitlint/config-angular": "19.8.0", + "@commitlint/cli": "19.8.1", + "@commitlint/config-angular": "19.8.1", "coveralls": "3.1.1", "@eslint/js": "9.26.0", "@stylistic/eslint-plugin-js": "4.2.0", From e042201f4bc662cc294ba19f63e218aa0860d82c Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 8 May 2025 16:32:21 -0400 Subject: [PATCH 44/76] fix: handle missing orderedItems property in followers route --- src/controllers/activitypub/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/controllers/activitypub/index.js b/src/controllers/activitypub/index.js index 0d9962ebf2..583d437ffb 100644 --- a/src/controllers/activitypub/index.js +++ b/src/controllers/activitypub/index.js @@ -95,13 +95,15 @@ Controller.getFollowers = async (req, res) => { url: `${nconf.get('url')}/uid/${req.params.uid}/followers`, }); - collection.orderedItems = collection.orderedItems.map(({ uid }) => { - if (utils.isNumber(uid)) { - return `${nconf.get('url')}/uid/${uid}`; - } + if (collection.hasOwnProperty('orderedItems')) { + collection.orderedItems = collection.orderedItems.map(({ uid }) => { + if (utils.isNumber(uid)) { + return `${nconf.get('url')}/uid/${uid}`; + } - return uid; - }); + return uid; + }); + } res.status(200).json(collection); }; From 6bfe4e627d8bd396131442b59ee8c1fade8162b2 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 8 May 2025 16:34:13 -0400 Subject: [PATCH 45/76] fix: another case --- src/controllers/activitypub/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/controllers/activitypub/index.js b/src/controllers/activitypub/index.js index 583d437ffb..36054d6616 100644 --- a/src/controllers/activitypub/index.js +++ b/src/controllers/activitypub/index.js @@ -71,13 +71,15 @@ Controller.getFollowing = async (req, res) => { url: `${nconf.get('url')}/uid/${req.params.uid}/following`, }); - collection.orderedItems = collection.orderedItems.map(({ uid }) => { - if (utils.isNumber(uid)) { - return `${nconf.get('url')}/uid/${uid}`; - } + if (collection.hasOwnProperty('orderedItems')) { + collection.orderedItems = collection.orderedItems.map(({ uid }) => { + if (utils.isNumber(uid)) { + return `${nconf.get('url')}/uid/${uid}`; + } - return uid; - }); + return uid; + }); + } res.status(200).json(collection); }; From af3afba0f8fb495a529e6a61718b855ced50434c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 20:21:13 -0400 Subject: [PATCH 46/76] fix(deps): update dependency nodemailer to v7.0.3 (#13395) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f75b2ae416..c222a0ab93 100644 --- a/install/package.json +++ b/install/package.json @@ -112,7 +112,7 @@ "nodebb-theme-peace": "2.2.42", "nodebb-theme-persona": "14.1.11", "nodebb-widget-essentials": "7.0.38", - "nodemailer": "7.0.2", + "nodemailer": "7.0.3", "nprogress": "0.2.0", "passport": "0.7.0", "passport-http-bearer": "1.0.1", From 9d877481bdb6036effd3996cbe20d96d0c727dc6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:31:50 -0400 Subject: [PATCH 47/76] chore(deps): update dependency lint-staged to v16 (#13404) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index c222a0ab93..9e435857dd 100644 --- a/install/package.json +++ b/install/package.json @@ -169,7 +169,7 @@ "grunt-contrib-watch": "1.1.0", "husky": "8.0.3", "jsdom": "26.1.0", - "lint-staged": "15.5.2", + "lint-staged": "16.0.0", "mocha": "11.2.2", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", From 7ffba2186c144434048dfdb48026343eae86a463 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:31:59 -0400 Subject: [PATCH 48/76] fix(deps): update dependency sass to v1.88.0 (#13403) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 9e435857dd..0a59c1587a 100644 --- a/install/package.json +++ b/install/package.json @@ -128,7 +128,7 @@ "rss": "1.2.2", "rtlcss": "4.3.0", "sanitize-html": "2.16.0", - "sass": "1.87.0", + "sass": "1.88.0", "satori": "0.12.2", "semver": "7.7.1", "serve-favicon": "2.5.0", From 694c79bc9a0af5b96ff4f1455b79fcd3e4056905 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:32:18 -0400 Subject: [PATCH 49/76] chore(deps): update dependency sass-embedded to v1.88.0 (#13402) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 0a59c1587a..74ed4c82ab 100644 --- a/install/package.json +++ b/install/package.json @@ -177,7 +177,7 @@ "smtp-server": "3.13.6" }, "optionalDependencies": { - "sass-embedded": "1.87.0" + "sass-embedded": "1.88.0" }, "resolutions": { "*/jquery": "3.7.1" From ecce9998186d453d3562f5062ec12be5469535a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:32:27 -0400 Subject: [PATCH 50/76] fix(deps): update dependency csrf-sync to v4.2.1 (#13401) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 74ed4c82ab..b3598d21c6 100644 --- a/install/package.json +++ b/install/package.json @@ -64,7 +64,7 @@ "cookie-parser": "1.4.7", "cron": "4.3.0", "cropperjs": "1.6.2", - "csrf-sync": "4.2.0", + "csrf-sync": "4.2.1", "daemon": "1.1.0", "diff": "7.0.0", "esbuild": "0.25.4", From 7a7cf830c317d69bf05559d93832136e2dd7217a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:32:37 -0400 Subject: [PATCH 51/76] fix(deps): update dependency bootswatch to v5.3.6 (#13400) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b3598d21c6..3e4f0c8b1f 100644 --- a/install/package.json +++ b/install/package.json @@ -48,7 +48,7 @@ "body-parser": "2.2.0", "bootbox": "6.0.3", "bootstrap": "5.3.6", - "bootswatch": "5.3.5", + "bootswatch": "5.3.6", "chalk": "4.1.2", "chart.js": "4.4.9", "cli-graph": "3.2.2", From d319b0aaadeee8224ac8788ad0563d72f1360cde Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:32:45 -0400 Subject: [PATCH 52/76] chore(deps): update postgres docker tag to v17.5 (#13398) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose-pgsql.yml | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose-pgsql.yml b/docker-compose-pgsql.yml index 17339889c3..52936cf256 100644 --- a/docker-compose-pgsql.yml +++ b/docker-compose-pgsql.yml @@ -14,7 +14,7 @@ services: - ./install/docker/setup.json:/usr/src/app/setup.json postgres: - image: postgres:17.4-alpine + image: postgres:17.5-alpine restart: unless-stopped environment: POSTGRES_USER: nodebb diff --git a/docker-compose.yml b/docker-compose.yml index 3aa899c8be..d5c6ae11e0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,7 +34,7 @@ services: - redis postgres: - image: postgres:17.4-alpine + image: postgres:17.5-alpine restart: unless-stopped environment: POSTGRES_USER: nodebb From 1df7313c99611733b432e6ba5f53afa2bd159530 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:32:58 -0400 Subject: [PATCH 53/76] chore(deps): update redis docker tag to v8 (#13387) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test.yaml | 2 +- docker-compose-pgsql.yml | 2 +- docker-compose-redis.yml | 2 +- docker-compose.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7ccb52ae62..39b577ca28 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -63,7 +63,7 @@ jobs: - 5432:5432 redis: - image: 'redis:7.4.3' + image: 'redis:8.0.0' # Set health checks to wait until redis has started options: >- --health-cmd "redis-cli ping" diff --git a/docker-compose-pgsql.yml b/docker-compose-pgsql.yml index 52936cf256..242bd04e9c 100644 --- a/docker-compose-pgsql.yml +++ b/docker-compose-pgsql.yml @@ -24,7 +24,7 @@ services: - postgres-data:/var/lib/postgresql/data redis: - image: redis:7.4.3-alpine + image: redis:8.0.0-alpine restart: unless-stopped command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning'] # command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] # uncomment if you want to use snapshotting instead of AOF diff --git a/docker-compose-redis.yml b/docker-compose-redis.yml index 9e1b05b250..e3da62c870 100644 --- a/docker-compose-redis.yml +++ b/docker-compose-redis.yml @@ -14,7 +14,7 @@ services: - ./install/docker/setup.json:/usr/src/app/setup.json redis: - image: redis:7.4.3-alpine + image: redis:8.0.0-alpine restart: unless-stopped command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning'] # command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] # uncomment if you want to use snapshotting instead of AOF diff --git a/docker-compose.yml b/docker-compose.yml index d5c6ae11e0..1bb783c771 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: - mongo-data:/data/db - ./install/docker/mongodb-user-init.js:/docker-entrypoint-initdb.d/user-init.js redis: - image: redis:7.4.3-alpine + image: redis:8.0.0-alpine restart: unless-stopped command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning'] # command: ['redis-server', '--save', '60', '1', '--loglevel', 'warning'] # uncomment if you want to use snapshotting instead of AOF From 6a4ffe02159d133e260fc99036db65aa63ad4d59 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:33:25 -0400 Subject: [PATCH 54/76] fix(deps): update dependency rimraf to v6 (#12686) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 3e4f0c8b1f..44d45bb9ad 100644 --- a/install/package.json +++ b/install/package.json @@ -124,7 +124,7 @@ "progress-webpack-plugin": "1.0.16", "prompt": "1.3.0", "ioredis": "5.6.1", - "rimraf": "5.0.10", + "rimraf": "6.0.1", "rss": "1.2.2", "rtlcss": "4.3.0", "sanitize-html": "2.16.0", From 23374fd7e9b6594b1cbcdaa8a65efa95182bdaf5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 22:33:49 -0400 Subject: [PATCH 55/76] fix(deps): update dependency lru-cache to v11 (#12685) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 44d45bb9ad..d6f2df33c9 100644 --- a/install/package.json +++ b/install/package.json @@ -89,7 +89,7 @@ "jsonwebtoken": "9.0.2", "lodash": "4.17.21", "logrotate-stream": "0.2.9", - "lru-cache": "10.4.3", + "lru-cache": "11.1.0", "mime": "3.0.0", "mkdirp": "3.0.1", "mongodb": "6.16.0", From f60748906030c1e2f475ab5b8edcf951f99cc7b3 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 12 May 2025 14:53:39 +0000 Subject: [PATCH 56/76] chore: incrementing version number - v4.3.2 --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index eca4d69ed8..10896920eb 100644 --- a/install/package.json +++ b/install/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "4.3.1", + "version": "4.3.2", "homepage": "https://www.nodebb.org", "repository": { "type": "git", From 0aa9c187f71606ac0e395b51755b4c0394103193 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 12 May 2025 14:53:40 +0000 Subject: [PATCH 57/76] chore: update changelog for v4.3.2 --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc3228268f..540621ebaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ +#### v4.3.2 (2025-05-12) + +##### Chores + +* up mentions (fcf9e8b7) +* incrementing version number - v4.3.1 (308e6b9f) +* update changelog for v4.3.1 (2310a7b8) +* incrementing version number - v4.3.0 (bff291db) +* incrementing version number - v4.2.2 (17fecc24) +* incrementing version number - v4.2.1 (852a270c) +* incrementing version number - v4.2.0 (87581958) +* incrementing version number - v4.1.1 (b2afbb16) +* incrementing version number - v4.1.0 (36c80850) +* incrementing version number - v4.0.6 (4a52fb2e) +* incrementing version number - v4.0.5 (1792a62b) +* incrementing version number - v4.0.4 (b1125cce) +* incrementing version number - v4.0.3 (2b65c735) +* incrementing version number - v4.0.2 (73fe5fcf) +* incrementing version number - v4.0.1 (a461b758) +* incrementing version number - v4.0.0 (c1eaee45) + +##### Bug Fixes + +* sql injection in sortedSetScan (16504bad) +* escape flag filters (285d438c) +* #13407, don't restart user jobs (31be083e) +* closes #13405, catch errors in ap.verify (8174578c) +* send proper accept header for outgoing webfinger requests (20ab9069) +* wrap generateCollection calls in try..catch to send 404 if thrown (64fdf91b) +* #13397, null values in category sync list (26e6a222) +* #13392, regression from c6f2c87, unable to unfollow from pending follows (401ff797) +* #13397, update getCidByHandle to work with remote categories, fix sync with handles causing issues with null entries (a9a5ab5e) +* correct stage name in dev dockerfile (#13393) (10077d0f) + +##### Refactors + +* wrap ap routes in try/catch (00668bdc) +* call verify if request is POST (dfa21329) + #### v4.3.1 (2025-05-07) ##### Chores From 5802c7ddd9506a4e296f6dbdf2d9a32621c7f4ef Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 12 May 2025 14:59:57 -0400 Subject: [PATCH 58/76] fix: missing awaits, more comprehensive 1b12 tests --- src/activitypub/feps.js | 3 +- src/activitypub/inbox.js | 4 +- src/api/activitypub.js | 17 +- src/api/helpers.js | 4 +- test/activitypub/feps.js | 309 ++++++++++++++++++++++++++++-------- test/activitypub/helpers.js | 2 +- 6 files changed, 258 insertions(+), 81 deletions(-) diff --git a/src/activitypub/feps.js b/src/activitypub/feps.js index 1e2d96441e..7b7816516d 100644 --- a/src/activitypub/feps.js +++ b/src/activitypub/feps.js @@ -3,6 +3,7 @@ const nconf = require('nconf'); const posts = require('../posts'); +const utils = require('../utils'); const activitypub = module.parent.exports; const Feps = module.exports; @@ -13,7 +14,7 @@ Feps.announce = async function announce(id, activity) { ({ id: localId } = await activitypub.helpers.resolveLocalId(id)); } const cid = await posts.getCidByPid(localId || id); - if (cid === -1) { + if (cid === -1 || !utils.isNumber(cid)) { // local cids only return; } diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index 19f149caec..10656a8d73 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -49,7 +49,7 @@ inbox.create = async (req) => { const asserted = await activitypub.notes.assert(0, object, { cid }); if (asserted) { - activitypub.feps.announce(object.id, req.body); + await activitypub.feps.announce(object.id, req.body); // api.activitypub.add(req, { pid: object.id }); } }; @@ -244,7 +244,7 @@ inbox.like = async (req) => { activitypub.helpers.log(`[activitypub/inbox/like] id ${id} via ${actor}`); const result = await posts.upvote(id, actor); - activitypub.feps.announce(object.id, req.body); + await activitypub.feps.announce(object.id, req.body); socketHelpers.upvote(result, 'notifications:upvoted-your-post-in'); }; diff --git a/src/api/activitypub.js b/src/api/activitypub.js index 43dad015b1..ce78f12d23 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -310,7 +310,15 @@ activitypubApi.delete.note = enabledCheck(async (caller, { pid }) => { activitypubApi.like = {}; activitypubApi.like.note = enabledCheck(async (caller, { pid }) => { - if (!activitypub.helpers.isUri(pid)) { // remote only + const payload = { + id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, + type: 'Like', + actor: `${nconf.get('url')}/uid/${caller.uid}`, + object: utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid, + }; + + if (!activitypub.helpers.isUri(pid)) { // only 1b12 announce for local likes + await activitypub.feps.announce(pid, payload); return; } @@ -319,13 +327,6 @@ activitypubApi.like.note = enabledCheck(async (caller, { pid }) => { return; } - const payload = { - id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, - type: 'Like', - actor: `${nconf.get('url')}/uid/${caller.uid}`, - object: pid, - }; - await Promise.all([ activitypub.send('uid', caller.uid, [uid], payload), activitypub.feps.announce(pid, payload), diff --git a/src/api/helpers.js b/src/api/helpers.js index e0d3bbc0bb..168e5539b6 100644 --- a/src/api/helpers.js +++ b/src/api/helpers.js @@ -137,12 +137,12 @@ async function executeCommand(caller, command, eventName, notification, data) { } if (result && command === 'upvote') { socketHelpers.upvote(result, notification); - api.activitypub.like.note(caller, { pid: data.pid }); + await api.activitypub.like.note(caller, { pid: data.pid }); } else if (result && notification) { socketHelpers.sendNotificationToPostOwner(data.pid, caller.uid, command, notification); } else if (result && command === 'unvote') { socketHelpers.rescindUpvoteNotification(data.pid, caller.uid); - api.activitypub.undo.like(caller, { pid: data.pid }); + await api.activitypub.undo.like(caller, { pid: data.pid }); } return result; } diff --git a/test/activitypub/feps.js b/test/activitypub/feps.js index a9b42644d8..65520f0f4e 100644 --- a/test/activitypub/feps.js +++ b/test/activitypub/feps.js @@ -12,6 +12,7 @@ const user = require('../../src/user'); const groups = require('../../src/groups'); const categories = require('../../src/categories'); const topics = require('../../src/topics'); +const posts = require('../../src/posts'); const api = require('../../src/api'); const helpers = require('./helpers'); @@ -47,84 +48,258 @@ describe('FEPs', () => { activitypub._sent.clear(); }); - it('should be called when a topic is moved from uncategorized to another category', async () => { - const { topicData, postData } = await topics.post({ - uid, - cid: -1, - title: utils.generateUUID(), - content: utils.generateUUID(), - }); + describe('local actions (create, reply, vote)', () => { + let topicData; - assert(topicData); - - await api.topics.move({ uid: adminUid }, { - tid: topicData.tid, - cid, - }); - - assert.strictEqual(activitypub._sent.size, 2); - - const key = Array.from(activitypub._sent.keys())[0]; - const activity = activitypub._sent.get(key); - - assert(activity && activity.object && typeof activity.object === 'object'); - assert.strictEqual(activity.object.id, `${nconf.get('url')}/post/${postData.pid}`); - }); - - it('should be called for a newly forked topic', async () => { - const { topicData } = await topics.post({ - uid, - cid: -1, - title: utils.generateUUID(), - content: utils.generateUUID(), - }); - const { tid } = topicData; - const { pid: reply1Pid } = await topics.reply({ uid, tid, content: utils.generateUUID() }); - const { pid: reply2Pid } = await topics.reply({ uid, tid, content: utils.generateUUID() }); - await topics.createTopicFromPosts( - adminUid, utils.generateUUID(), [reply1Pid, reply2Pid], tid, cid - ); - - assert.strictEqual(activitypub._sent.size, 2, activitypub._sent.keys()); - - const key = Array.from(activitypub._sent.keys())[0]; - const activity = activitypub._sent.get(key); - - assert(activity && activity.object && typeof activity.object === 'object'); - assert.strictEqual(activity.object.id, `${nconf.get('url')}/post/${reply1Pid}`); - }); - - it('should be called when a post is moved to another topic', async () => { - const [{ topicData: topic1 }, { topicData: topic2 }] = await Promise.all([ - topics.post({ - uid, + before(async () => { + topicData = await api.topics.create({ uid }, { cid, title: utils.generateUUID(), content: utils.generateUUID(), - }), - topics.post({ - uid, + }); + }); + + afterEach(() => { + activitypub._sent.clear(); + }); + + it('should have federated out both Announce(Create(Article)) and Announce(Article)', () => { + const activities = Array.from(activitypub._sent); + + const test1 = activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Create' && + activity.object.object && activity.object.object.type === 'Article'; + }); + + const test2 = activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Article'; + }); + + assert(test1 && test2); + }); + + it('should federate out Announce(Create(Note)) on local reply', async () => { + await api.topics.reply({ uid }, { + tid: topicData.tid, + content: utils.generateUUID(), + }); + + const activities = Array.from(activitypub._sent); + + assert(activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Create' && + activity.object.object && activity.object.object.type === 'Note'; + })); + }); + + it('should NOT federate out Announce(Note) on local reply', async () => { + await api.topics.reply({ uid }, { + tid: topicData.tid, + content: utils.generateUUID(), + }); + + const activities = Array.from(activitypub._sent); + + assert(activities.every((activity) => { + [, activity] = activity; + if (activity.type === 'Announce' && activity.object && activity.object.type === 'Note') { + return false; + } + + return true; + })); + }); + + it('should federate out Announce(Like) on local vote', async () => { + activitypub._sent.clear(); + await api.posts.upvote({ uid: adminUid }, { pid: topicData.mainPid, room_id: `topic_${topicData.tid}` }); + const activities = Array.from(activitypub._sent); + + assert(activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Like'; + })); + }); + }); + + describe('remote actions (create, reply, vote)', () => { + let activity; + let pid; + let topicData; + + before(async () => { + topicData = await api.topics.create({ uid }, { cid, title: utils.generateUUID(), content: utils.generateUUID(), - }), - ]); + }); + }); - assert(topic1 && topic2); + afterEach(() => { + activitypub._sent.clear(); + }); - // Create new reply and move it to topic 2 - const { pid } = await topics.reply({ uid, tid: topic1.tid, content: utils.generateUUID() }); - await api.posts.move({ uid: adminUid }, { pid, tid: topic2.tid }); + it('should have slotted the note into the test category', async () => { + const { id, note } = await helpers.mocks.note({ + cc: [`${nconf.get('url')}/category/${cid}`], + }); + pid = id; + ({ activity } = await helpers.mocks.create(note)); + await activitypub.inbox.create({ body: activity }); - assert.strictEqual(activitypub._sent.size, 1); - const activities = Array.from(activitypub._sent.keys()).map(key => activitypub._sent.get(key)); + const noteCid = await posts.getCidByPid(pid); + assert.strictEqual(noteCid, cid); + }); - const activity = activities.pop(); - assert.strictEqual(activity.type, 'Announce'); - assert(activity.object && activity.object.type); - assert.strictEqual(activity.object.type, 'Create'); - assert(activity.object.object && activity.object.object.type); - assert.strictEqual(activity.object.object.type, 'Note'); + it('should federate out an Announce(Create(Note)) and Announce(Note) on new topic', async () => { + const { id, note } = await helpers.mocks.note({ + cc: [`${nconf.get('url')}/category/${cid}`], + }); + pid = id; + ({ activity } = await helpers.mocks.create(note)); + await activitypub.inbox.create({ body: activity }); + + const activities = Array.from(activitypub._sent); + + const test1 = activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Create' && + activity.object.object && activity.object.object.type === 'Note'; + }); + + const test2 = activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Note'; + }); + + assert(test1 && test2); + }); + + it('should federate out an Announce(Create(Note)) on reply', async () => { + const { id, note } = await helpers.mocks.note({ + cc: [`${nconf.get('url')}/category/${cid}`], + inReplyTo: `${nconf.get('url')}/post/${topicData.mainPid}`, + }); + pid = id; + ({ activity } = await helpers.mocks.create(note)); + await activitypub.inbox.create({ body: activity }); + + const activities = Array.from(activitypub._sent); + + assert(activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Create' && + activity.object.object && activity.object.object.type === 'Note'; + })); + }); + + it('should federate out an Announce(Like) on vote', async () => { + const { activity } = await helpers.mocks.like({ + object: { + id: `${nconf.get('url')}/post/${topicData.mainPid}`, + }, + }); + await activitypub.inbox.like({ body: activity }); + + const activities = Array.from(activitypub._sent); + assert(activities.some((activity) => { + [, activity] = activity; + return activity.type === 'Announce' && + activity.object && activity.object.type === 'Like'; + })); + }); + }); + + describe('extended actions not explicitly specified in 1b12', () => { + it('should be called when a topic is moved from uncategorized to another category', async () => { + const { topicData, postData } = await topics.post({ + uid, + cid: -1, + title: utils.generateUUID(), + content: utils.generateUUID(), + }); + + assert(topicData); + + await api.topics.move({ uid: adminUid }, { + tid: topicData.tid, + cid, + }); + + assert.strictEqual(activitypub._sent.size, 2); + + const key = Array.from(activitypub._sent.keys())[0]; + const activity = activitypub._sent.get(key); + + assert(activity && activity.object && typeof activity.object === 'object'); + assert.strictEqual(activity.object.id, `${nconf.get('url')}/post/${postData.pid}`); + }); + + it('should be called for a newly forked topic', async () => { + const { topicData } = await topics.post({ + uid, + cid: -1, + title: utils.generateUUID(), + content: utils.generateUUID(), + }); + const { tid } = topicData; + const { pid: reply1Pid } = await topics.reply({ uid, tid, content: utils.generateUUID() }); + const { pid: reply2Pid } = await topics.reply({ uid, tid, content: utils.generateUUID() }); + await topics.createTopicFromPosts( + adminUid, utils.generateUUID(), [reply1Pid, reply2Pid], tid, cid + ); + + assert.strictEqual(activitypub._sent.size, 2, activitypub._sent.keys()); + + const key = Array.from(activitypub._sent.keys())[0]; + const activity = activitypub._sent.get(key); + + assert(activity && activity.object && typeof activity.object === 'object'); + assert.strictEqual(activity.object.id, `${nconf.get('url')}/post/${reply1Pid}`); + }); + + it('should be called when a post is moved to another topic', async () => { + const [{ topicData: topic1 }, { topicData: topic2 }] = await Promise.all([ + topics.post({ + uid, + cid, + title: utils.generateUUID(), + content: utils.generateUUID(), + }), + topics.post({ + uid, + cid, + title: utils.generateUUID(), + content: utils.generateUUID(), + }), + ]); + + assert(topic1 && topic2); + + // Create new reply and move it to topic 2 + const { pid } = await topics.reply({ uid, tid: topic1.tid, content: utils.generateUUID() }); + await api.posts.move({ uid: adminUid }, { pid, tid: topic2.tid }); + + assert.strictEqual(activitypub._sent.size, 1); + const activities = Array.from(activitypub._sent.keys()).map(key => activitypub._sent.get(key)); + + const activity = activities.pop(); + assert.strictEqual(activity.type, 'Announce'); + assert(activity.object && activity.object.type); + assert.strictEqual(activity.object.type, 'Create'); + assert(activity.object.object && activity.object.object.type); + assert.strictEqual(activity.object.object.type, 'Note'); + }); }); }); }); diff --git a/test/activitypub/helpers.js b/test/activitypub/helpers.js index e4c3a4d689..57d1d1826f 100644 --- a/test/activitypub/helpers.js +++ b/test/activitypub/helpers.js @@ -144,7 +144,7 @@ Helpers.mocks.like = (override = {}) => { const activity = { '@context': 'https://www.w3.org/ns/activitystreams', - id: `${Helpers.mocks._baseUrl}/like/${encodeURIComponent(object)}`, + id: `${Helpers.mocks._baseUrl}/like/${encodeURIComponent(object.id)}`, type: 'Like', actor, object, From 1b0b1da6b98c5183bdfd645aba24ab5eafda3040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 12 May 2025 17:48:46 -0400 Subject: [PATCH 59/76] refactor: use a single until --- src/socket.io/admin/analytics.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/socket.io/admin/analytics.js b/src/socket.io/admin/analytics.js index bc084b14f5..8af8881873 100644 --- a/src/socket.io/admin/analytics.js +++ b/src/socket.io/admin/analytics.js @@ -18,14 +18,18 @@ Analytics.get = async function (socket, data) { data.amount = 24; } } - const getStats = data.units === 'days' ? analytics.getDailyStatsForSet : analytics.getHourlyStatsForSet; + const getStats = data.units === 'days' ? + analytics.getDailyStatsForSet : + analytics.getHourlyStatsForSet; + if (data.graph === 'traffic') { + const until = data.until || Date.now(); const result = await utils.promiseParallel({ - uniqueVisitors: getStats('analytics:uniquevisitors', data.until || Date.now(), data.amount), - pageviews: getStats('analytics:pageviews', data.until || Date.now(), data.amount), - pageviewsRegistered: getStats('analytics:pageviews:registered', data.until || Date.now(), data.amount), - pageviewsGuest: getStats('analytics:pageviews:guest', data.until || Date.now(), data.amount), - pageviewsBot: getStats('analytics:pageviews:bot', data.until || Date.now(), data.amount), + uniqueVisitors: getStats('analytics:uniquevisitors', until, data.amount), + pageviews: getStats('analytics:pageviews', until, data.amount), + pageviewsRegistered: getStats('analytics:pageviews:registered', until, data.amount), + pageviewsGuest: getStats('analytics:pageviews:guest', until, data.amount), + pageviewsBot: getStats('analytics:pageviews:bot', until, data.amount), summary: analytics.getSummary(), }); result.pastDay = result.pageviews.reduce((a, b) => parseInt(a, 10) + parseInt(b, 10)); From fe13c75549ff2c9263635a8f1444eac1eedc5287 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 13 May 2025 13:59:34 -0400 Subject: [PATCH 60/76] fix: #13375, plus additional tests --- src/activitypub/inbox.js | 16 ++++--- src/activitypub/notes.js | 12 ++---- test/activitypub/notes.js | 91 ++++++++++++++++++++++++++------------- 3 files changed, 72 insertions(+), 47 deletions(-) diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index 10656a8d73..ab02cef6db 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -41,6 +41,7 @@ inbox.create = async (req) => { return await activitypub.notes.assertPrivate(object); } + // Category sync, remove when cross-posting available const { cids } = await activitypub.actors.getLocalFollowers(actor); let cid = null; if (cids.size > 0) { @@ -262,12 +263,19 @@ inbox.announce = async (req) => { let tid; let pid; + // Category sync, remove when cross-posting available const { cids } = await activitypub.actors.getLocalFollowers(actor); let cid = null; if (cids.size > 0) { cid = Array.from(cids)[0]; } + // 1b12 announce + const categoryActor = await categories.exists(actor); + if (categoryActor) { + cid = actor; + } + switch(true) { case object.type === 'Like': { const id = object.object.id || object.object; @@ -318,13 +326,7 @@ inbox.announce = async (req) => { } } - // Handle case where Announce(Create(Note-ish)) is received - if (object.type === 'Create' && activitypub._constants.acceptedPostTypes.includes(object.object.type)) { - pid = object.object.id; - } else { - pid = object.id; - } - + pid = object.id; pid = await activitypub.resolveId(0, pid); // in case wrong id is passed-in; unlikely, but still. if (!pid) { return; diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 571e038687..31ca249d3d 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -115,24 +115,18 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { if (hasTid) { mainPid = await topics.getTopicField(tid, 'mainPid'); } else { - // Check recipients/audience for category (local or remote) + // Check recipients/audience for local category const set = activitypub.helpers.makeSet(_activitypub, ['to', 'cc', 'audience']); await activitypub.actors.assert(Array.from(set)); - - // Local const resolved = await Promise.all(Array.from(set).map(async id => await activitypub.helpers.resolveLocalId(id))); const recipientCids = resolved .filter(Boolean) .filter(({ type }) => type === 'category') .map(obj => obj.id); - // Remote - const assertedGroups = await db.exists(Array.from(set).map(id => `categoryRemote:${id}`)); - const remoteCid = Array.from(set).filter((_, idx) => assertedGroups[idx]).shift(); - - if (remoteCid || recipientCids.length) { + if (recipientCids.length) { // Overrides passed-in value, respect addressing from main post over booster - options.cid = remoteCid || recipientCids.shift(); + options.cid = recipientCids.shift(); } // mainPid ok to leave as-is diff --git a/test/activitypub/notes.js b/test/activitypub/notes.js index 9b4aaf8653..f079076215 100644 --- a/test/activitypub/notes.js +++ b/test/activitypub/notes.js @@ -83,33 +83,6 @@ describe('Notes', () => { assert.strictEqual(topic.cid, cid); }); - it('should slot newly created topic in remote category if addressed', async () => { - const { id: cid, actor } = helpers.mocks.group(); - await activitypub.actors.assertGroup([cid]); - - const { id } = helpers.mocks.note({ - cc: [cid], - }); - - const assertion = await activitypub.notes.assert(0, id); - assert(assertion); - - const { tid, count } = assertion; - assert(tid); - assert.strictEqual(count, 1); - - const topic = await topics.getTopicData(tid); - assert.strictEqual(topic.cid, cid); - - const tids = await db.getSortedSetMembers(`cid:${cid}:tids`); - assert(tids.includes(tid)); - - const category = await categories.getCategoryData(cid); - ['topic_count', 'post_count', 'totalPostCount', 'totalTopicCount'].forEach((prop) => { - assert.strictEqual(category[prop], 1); - }); - }); - it('should add a remote category topic to a user\'s inbox if they are following the category', async () => { const { id: cid, actor } = helpers.mocks.group(); await activitypub.actors.assertGroup([cid]); @@ -120,7 +93,7 @@ describe('Notes', () => { const { id } = helpers.mocks.note({ cc: [cid], }); - const { tid } = await activitypub.notes.assert(0, id); + const { tid } = await activitypub.notes.assert(0, id, { cid }); const inInbox = await db.isSortedSetMember(`uid:${uid}:inbox`, tid); assert(inInbox); @@ -161,7 +134,7 @@ describe('Notes', () => { const { id } = helpers.mocks.note({ cc: [remoteCid], }); - const assertion = await activitypub.notes.assert(0, id); + const assertion = await activitypub.notes.assert(0, id, { cid: remoteCid }); assert(assertion); const unread = await topics.getTotalUnread(uid); @@ -180,7 +153,7 @@ describe('Notes', () => { const { id, note } = helpers.mocks.note({ cc: [remoteCid], }); - const assertion = await activitypub.notes.assert(0, id); + const assertion = await activitypub.notes.assert(0, id, { cid: remoteCid }); assert(assertion); const unread = await topics.getTotalUnread(uid); @@ -203,7 +176,7 @@ describe('Notes', () => { const { id, note } = helpers.mocks.note({ cc: [remoteCid], }); - const assertion = await activitypub.notes.assert(0, id); + const assertion = await activitypub.notes.assert(0, id, { cid: remoteCid }); assert(assertion); const unread = await topics.getTotalUnread(uid); @@ -457,6 +430,44 @@ describe('Notes', () => { }); }); + describe('Create', () => { + let uid; + + before(async () => { + uid = await user.create({ username: utils.generateUUID() }); + }); + + describe('(Note)', () => { + it('should create a new topic in cid -1', async () => { + const { note, id } = helpers.mocks.note(); + const { activity } = helpers.mocks.create(note); + + await db.sortedSetAdd(`followersRemote:${note.attributedTo}`, Date.now(), uid); + await activitypub.inbox.create({ body: activity }); + + assert(await posts.exists(id)); + + const cid = await posts.getCidByPid(id); + assert.strictEqual(cid, -1); + }); + + it('should create a new topic in cid -1 even if a remote category is addressed', async () => { + const { id: remoteCid } = helpers.mocks.group(); + const { note, id } = helpers.mocks.note({ + audience: [remoteCid], + }); + const { activity } = helpers.mocks.create(note); + + await activitypub.inbox.create({ body: activity }); + + assert(await posts.exists(id)); + + const cid = await posts.getCidByPid(id); + assert.strictEqual(cid, -1); + }); + }); + }); + describe('Announce', () => { let cid; @@ -464,6 +475,24 @@ describe('Notes', () => { ({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) })); }); + describe('(Create)', () => { + it('should create a new topic in a remote category if addressed', async () => { + const { id: remoteCid } = helpers.mocks.group(); + const { id, note } = helpers.mocks.note({ + audience: [remoteCid], + }); + let { activity } = helpers.mocks.create(note); + ({ activity } = helpers.mocks.announce({ actor: remoteCid, object: activity })); + + await activitypub.inbox.announce({ body: activity }); + + assert(await posts.exists(id)); + + const cid = await posts.getCidByPid(id); + assert.strictEqual(cid, remoteCid); + }); + }); + describe('(Note)', () => { it('should create a new topic in cid -1 if category not addressed', async () => { const { note } = helpers.mocks.note(); From 7dc690a14ab1471ce6832e9ea84534cce903a3f7 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 14 May 2025 09:19:59 +0000 Subject: [PATCH 61/76] Latest translations and fallbacks --- public/language/he/global.json | 2 +- public/language/he/themes/harmony.json | 2 +- public/language/he/user.json | 4 +-- public/language/nb/topic.json | 36 +++++++++++++------------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/public/language/he/global.json b/public/language/he/global.json index dcbbbf0dbc..428cd81ac4 100644 --- a/public/language/he/global.json +++ b/public/language/he/global.json @@ -82,7 +82,7 @@ "downvoted": "הוצבע נגד", "views": "צפיות", "posters": "כותבים", - "watching": "במעקב", + "watching": "עוקבים", "reputation": "מוניטין", "lastpost": "פוסט אחרון", "firstpost": "פוסט ראשון", diff --git a/public/language/he/themes/harmony.json b/public/language/he/themes/harmony.json index f71d306f16..cace705973 100644 --- a/public/language/he/themes/harmony.json +++ b/public/language/he/themes/harmony.json @@ -14,7 +14,7 @@ "settings.stickyToolbar": "הצמד את סרגל הכלים בעת גלילה", "settings.stickyToolbar.help": "סרגל הכלים בדפי נושאים וקטגוריות ייצמד לראש העמוד בעת גלילה", "settings.topicSidebarTools": "כלי סרגל הצד", - "settings.topicSidebarTools.help": "אפשרות זו תעביר את כלי הנושא לסרגל הצד במחשבים שולחניים", + "settings.topicSidebarTools.help": "אפשרות זו תעביר את כלי הנושא לסרגל הצד במחשבים", "settings.autohideBottombar": "הסתרה אוטומטי של סרגל ניווט בנייד", "settings.autohideBottombar.help": "הסרגל בתצוגת הנייד יוסתר כאשר הדף ייגלל מטה", "settings.topMobilebar": "העברת סרגל הניווט בנייד לראש הדף", diff --git a/public/language/he/user.json b/public/language/he/user.json index 85c7a435d0..695f2f99c2 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -14,7 +14,7 @@ "account-info": "פרטי חשבון", "admin-actions-label": "פעולות ניהול", "ban-account": "הרחקת חשבון", - "ban-account-confirm": "האם אתהם בטוחים שאתם רוצים להרחיק משתמש זה?", + "ban-account-confirm": "האם להרחיק משתמש זה?", "unban-account": "ביטול הרחקת חשבון", "mute-account": "השתקת חשבון", "unmute-account": "ביטול השתקת חשבון", @@ -105,7 +105,7 @@ "show-email": "הצגת כתובת האימייל שלי", "show-fullname": "הצגת שמי המלא", "restrict-chats": "אפשר רק הודעות צ'אט ממשתמשים שאני עוקב אחריהם", - "disable-incoming-chats": "השבתת הודעות צ'אט נכנסות ", + "disable-incoming-chats": "השבתת הודעות צ'אט נכנסות ", "chat-allow-list": "אפשור הודעות צ'אט מהמשתמשים הבאים", "chat-deny-list": "דחיית הודעות צ'אט מהמשתמשים הבאים", "chat-list-add-user": "הוספת משתמש", diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 5321f0ec4b..48dc204ac2 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -1,10 +1,10 @@ { - "topic": "Emne", + "topic": "Innlegg", "title": "Tittel", - "no-topics-found": "Ingen tråder funnet!", - "no-posts-found": "Ingen innlegg funnet!", - "post-is-deleted": "Dette innlegget er slettet!", - "topic-is-deleted": "Denne tråden er slettet!", + "no-topics-found": "Ingen innlegg funnet!", + "no-posts-found": "Ingen poster funnet!", + "post-is-deleted": "Dette svaret er slettet!", + "topic-is-deleted": "Dette innlegget er slettet!", "profile": "Profil", "posted-by": "Opprettet av %1", "posted-by-guest": "Opprettet av Gjest", @@ -16,7 +16,7 @@ "one-reply-to-this-post": "1 svar", "last-reply-time": "Siste svar", "reply-options": "Alternativer for svar", - "reply-as-topic": "Svar som tråd", + "reply-as-topic": "Svar som innlegg", "guest-login-reply": "Logg inn for å besvare", "login-to-view": "🔒 Logg inn for å se", "edit": "Endre", @@ -58,7 +58,7 @@ "user-deleted-topic-ago": "%1 slett dette emnet %2", "user-deleted-topic-on": "%1 slett dette emnet på %2", "user-restored-topic-ago": "%1 gjenopprettet dette emnet %2", - "user-restored-topic-on": "%1 gjenopprettet dette menet på %2", + "user-restored-topic-on": "%1 gjenopprettet dette emnet på %2", "user-moved-topic-from-ago": "%1 flyttet dette emnet fra %2 %3", "user-moved-topic-from-on": "%1 flyttet dette emnet fra %2 på %3", "user-shared-topic-ago": "%1 delte dette emnet %2", @@ -66,21 +66,21 @@ "user-queued-post-ago": "%1 i kø post til godkjenning %3", "user-queued-post-on": "%1 i køpost til godkjenning %3", "user-referenced-topic-ago": "%1 refererte dette emnet %3", - "user-referenced-topic-on": "%1 refererte dette emnet dette emnet på %3", + "user-referenced-topic-on": "%1 refererte dette innlegget dette innlegget på %3", "user-forked-topic-ago": "%1 gaflet dette emnet %3", "user-forked-topic-on": "%1 gaflet dette emnet på %3", - "bookmark-instructions": "Klikk her for å gå tilbake til det siste innlegget i denne tråden.", - "flag-post": "Flagg denne posten", - "flag-user": "Flagg denne brukeren", - "already-flagged": "Allerede flagget", - "view-flag-report": "Vis flaggrapport", - "resolve-flag": "Løs flagg", + "bookmark-instructions": "Klikk her for å gå tilbake til det siste svaret i denne tråden.", + "flag-post": "Rapporter denne posten", + "flag-user": "Rapporter denne brukeren", + "already-flagged": "Allerede rapportert", + "view-flag-report": "Vis rapporteringsoversikt", + "resolve-flag": "Behandle rapport", "merged-message": "Dette emnet er slått sammen med %2", "forked-message": "This topic was forked from %2", - "deleted-message": "Denne tråden har blitt slettet. Bare brukere med trådhåndterings-privilegier kan se den.", - "following-topic.message": "Du vil nå motta varsler når noen skriver i denne tråden.", - "not-following-topic.message": "Du vil se denne tråden i trådlisten, men du vil ikke motta varslinger når noen skriver i den.", - "ignoring-topic.message": "Du vil ikke lenger se denne tråden blant de uleste trådene. Du vil få et varsel når du blir nevnt eller din tråd blir tilrådd.", + "deleted-message": "Denne innlegget har blitt slettet. ", + "following-topic.message": "Du vil nå motta varsler når noen svarer på dette innlegget.", + "not-following-topic.message": "Du vil se dette innlegget i oversikten over uleste innlegg, men du vil ikke motta varslinger når noen skriver et svar.", + "ignoring-topic.message": "Du vil ikke lenger se dette innlegget blant uleste innlegg. Du vil få et varsel når du blir nevnt eller innlegget blir anbefalt.", "login-to-subscribe": "Vennligst registrer deg eller logg inn for å abonnere på denne tråden.", "markAsUnreadForAll.success": "Tråd markert som ulest for alle.", "mark-unread": "Merk som ulest", From 9dc91f11a4ab57b8312d4c973894e0a4067c2249 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 14 May 2025 11:00:53 -0400 Subject: [PATCH 62/76] test: fix broken test due to adjusted note assertion relation logic --- test/activitypub/actors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/activitypub/actors.js b/test/activitypub/actors.js index 687bc92a44..37fc74280d 100644 --- a/test/activitypub/actors.js +++ b/test/activitypub/actors.js @@ -895,7 +895,7 @@ describe('Pruning', () => { const { id } = helpers.mocks.note({ cc: [cid], }); - await activitypub.notes.assert(0, id); + await activitypub.notes.assert(0, id, { cid }); const total = await db.sortedSetCard('usersRemote:lastCrawled'); const result = await activitypub.actors.prune(); From 5b118904c9544b8cfb53f38b9df0ed6aab888eec Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 14 May 2025 11:05:10 -0400 Subject: [PATCH 63/76] test: fix regression from 5802c7ddd9506a4e296f6dbdf2d9a32621c7f4ef --- test/activitypub/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/activitypub/helpers.js b/test/activitypub/helpers.js index 57d1d1826f..a995866838 100644 --- a/test/activitypub/helpers.js +++ b/test/activitypub/helpers.js @@ -144,7 +144,7 @@ Helpers.mocks.like = (override = {}) => { const activity = { '@context': 'https://www.w3.org/ns/activitystreams', - id: `${Helpers.mocks._baseUrl}/like/${encodeURIComponent(object.id)}`, + id: `${Helpers.mocks._baseUrl}/like/${encodeURIComponent(object.id || object)}`, type: 'Like', actor, object, From 61f6806b6a6939d56733e9c5ee9a3a1900e9aaa8 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 14 May 2025 11:49:12 -0400 Subject: [PATCH 64/76] test: a few additional tests for announce handling --- src/posts/data.js | 2 +- test/activitypub/helpers.js | 3 ++ test/activitypub/notes.js | 77 +++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/posts/data.js b/src/posts/data.js index 688c131b8a..d74a22e69d 100644 --- a/src/posts/data.js +++ b/src/posts/data.js @@ -7,7 +7,7 @@ const utils = require('../utils'); const intFields = [ 'uid', 'pid', 'tid', 'deleted', 'timestamp', 'upvotes', 'downvotes', 'deleterUid', 'edited', - 'replies', 'bookmarks', + 'replies', 'bookmarks', 'announces', ]; module.exports = function (Posts) { diff --git a/test/activitypub/helpers.js b/test/activitypub/helpers.js index a995866838..2690910e06 100644 --- a/test/activitypub/helpers.js +++ b/test/activitypub/helpers.js @@ -162,6 +162,8 @@ Helpers.mocks.announce = (override = {}) => { if (!object) { ({ id: object } = Helpers.mocks.note()); } + delete override.actor; + delete override.object; const activity = { '@context': 'https://www.w3.org/ns/activitystreams', @@ -171,6 +173,7 @@ Helpers.mocks.announce = (override = {}) => { cc: [`${actor}/followers`], actor, object, + ...override, }; return { activity }; diff --git a/test/activitypub/notes.js b/test/activitypub/notes.js index f079076215..afd24081c5 100644 --- a/test/activitypub/notes.js +++ b/test/activitypub/notes.js @@ -493,6 +493,83 @@ describe('Notes', () => { }); }); + describe('(Create) or (Note) referencing local post', () => { + let uid; + let topicData; + let postData; + let localNote; + let announces = 0; + + before(async () => { + uid = await user.create({ username: utils.generateUUID().slice(0, 10) }); + ({ topicData, postData } = await topics.post({ + cid, + uid, + title: utils.generateUUID(), + content: utils.generateUUID(), + })); + localNote = await activitypub.mocks.notes.public(postData); + }); + + it('should increment announces counter when a remote user shares', async () => { + const { id } = helpers.mocks.person(); + const { activity } = helpers.mocks.announce({ + actor: id, + object: localNote, + cc: [`${nconf.get('url')}/uid/${topicData.uid}`], + }); + + await activitypub.inbox.announce({ body: activity }); + announces += 1; + + const count = await posts.getPostField(topicData.mainPid, 'announces'); + assert.strictEqual(count, announces); + }); + + it('should contain the remote user announcer id in the post announces zset', async () => { + const { id } = helpers.mocks.person(); + const { activity } = helpers.mocks.announce({ + actor: id, + object: localNote, + cc: [`${nconf.get('url')}/uid/${topicData.uid}`], + }); + + await activitypub.inbox.announce({ body: activity }); + announces += 1; + + const exists = await db.isSortedSetMember(`pid:${topicData.mainPid}:announces`, id); + assert(exists); + }); + + it('should NOT increment announces counter when a remote category shares', async () => { + const { id } = helpers.mocks.group(); + const { activity } = helpers.mocks.announce({ + actor: id, + object: localNote, + cc: [`${nconf.get('url')}/uid/${topicData.uid}`], + }); + + await activitypub.inbox.announce({ body: activity }); + + const count = await posts.getPostField(topicData.mainPid, 'announces'); + assert.strictEqual(count, announces); + }); + + it('should NOT contain the remote category announcer id in the post announces zset', async () => { + const { id } = helpers.mocks.group(); + const { activity } = helpers.mocks.announce({ + actor: id, + object: localNote, + cc: [`${nconf.get('url')}/uid/${topicData.uid}`], + }); + + await activitypub.inbox.announce({ body: activity }); + + const exists = await db.isSortedSetMember(`pid:${topicData.mainPid}:announces`, id); + assert(!exists); + }); + }); + describe('(Note)', () => { it('should create a new topic in cid -1 if category not addressed', async () => { const { note } = helpers.mocks.note(); From 0f576a42195b42a225eba94213299244e0fc1dfa Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 14 May 2025 12:16:06 -0400 Subject: [PATCH 65/76] fix: add `announces` to postdataobject schema --- public/openapi/components/schemas/PostObject.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/openapi/components/schemas/PostObject.yaml b/public/openapi/components/schemas/PostObject.yaml index 502ea8044d..bcb2f79e53 100644 --- a/public/openapi/components/schemas/PostObject.yaml +++ b/public/openapi/components/schemas/PostObject.yaml @@ -180,6 +180,8 @@ PostDataObject: type: number downvotes: type: number + announces: + type: number bookmarks: type: number deleterUid: From 383a7ce507b7650804520a98e9543ec5b2689b4f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 12:38:00 -0400 Subject: [PATCH 66/76] fix(deps): update dependency nodebb-plugin-mentions to v4.7.6 (#13417) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 4c9faa7c9c..2e9fd8a5bb 100644 --- a/install/package.json +++ b/install/package.json @@ -103,7 +103,7 @@ "nodebb-plugin-emoji": "6.0.2", "nodebb-plugin-emoji-android": "4.1.1", "nodebb-plugin-markdown": "13.2.0", - "nodebb-plugin-mentions": "4.7.5", + "nodebb-plugin-mentions": "4.7.6", "nodebb-plugin-spam-be-gone": "2.3.2", "nodebb-plugin-web-push": "0.7.4", "nodebb-rewards-essentials": "1.0.2", From fbe97b4e914a31cdd1b66f90651ba77305e6a56f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 12:38:22 -0400 Subject: [PATCH 67/76] chore(deps): update redis docker tag to v8.0.1 (#13415) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test.yaml | 2 +- docker-compose-pgsql.yml | 2 +- docker-compose-redis.yml | 2 +- docker-compose.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 39b577ca28..43fdf33611 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -63,7 +63,7 @@ jobs: - 5432:5432 redis: - image: 'redis:8.0.0' + image: 'redis:8.0.1' # Set health checks to wait until redis has started options: >- --health-cmd "redis-cli ping" diff --git a/docker-compose-pgsql.yml b/docker-compose-pgsql.yml index 242bd04e9c..9011d0f92a 100644 --- a/docker-compose-pgsql.yml +++ b/docker-compose-pgsql.yml @@ -24,7 +24,7 @@ services: - postgres-data:/var/lib/postgresql/data redis: - image: redis:8.0.0-alpine + image: redis:8.0.1-alpine restart: unless-stopped command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning'] # command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] # uncomment if you want to use snapshotting instead of AOF diff --git a/docker-compose-redis.yml b/docker-compose-redis.yml index e3da62c870..da31cd6886 100644 --- a/docker-compose-redis.yml +++ b/docker-compose-redis.yml @@ -14,7 +14,7 @@ services: - ./install/docker/setup.json:/usr/src/app/setup.json redis: - image: redis:8.0.0-alpine + image: redis:8.0.1-alpine restart: unless-stopped command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning'] # command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] # uncomment if you want to use snapshotting instead of AOF diff --git a/docker-compose.yml b/docker-compose.yml index 1bb783c771..637cecb0cd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: - mongo-data:/data/db - ./install/docker/mongodb-user-init.js:/docker-entrypoint-initdb.d/user-init.js redis: - image: redis:8.0.0-alpine + image: redis:8.0.1-alpine restart: unless-stopped command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning'] # command: ['redis-server', '--save', '60', '1', '--loglevel', 'warning'] # uncomment if you want to use snapshotting instead of AOF From 0825c569aa72d1e0a3ea526dfe2b3fad6a9404dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 12:40:24 -0400 Subject: [PATCH 68/76] fix(deps): update dependency pg to v8.16.0 (#13411) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 2e9fd8a5bb..8360e2159e 100644 --- a/install/package.json +++ b/install/package.json @@ -117,7 +117,7 @@ "passport": "0.7.0", "passport-http-bearer": "1.0.1", "passport-local": "1.0.0", - "pg": "8.15.6", + "pg": "8.16.0", "pg-cursor": "2.14.6", "postcss": "8.5.3", "postcss-clean": "1.2.0", From 366651d6e1651b0c5265ec21b1395463d3962f2f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 12:40:46 -0400 Subject: [PATCH 69/76] fix(deps): update dependency semver to v7.7.2 (#13410) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 8360e2159e..a09fb8bd8e 100644 --- a/install/package.json +++ b/install/package.json @@ -130,7 +130,7 @@ "sanitize-html": "2.16.0", "sass": "1.88.0", "satori": "0.12.2", - "semver": "7.7.1", + "semver": "7.7.2", "serve-favicon": "2.5.0", "sharp": "0.32.6", "sitemap": "8.0.0", From 84b8ecc7a0bcf20ceae6c5d30865843e952b3534 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 13:45:01 -0400 Subject: [PATCH 70/76] fix(deps): update dependency nodebb-plugin-markdown to v13.2.1 (#13416) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a09fb8bd8e..ffeeab1992 100644 --- a/install/package.json +++ b/install/package.json @@ -102,7 +102,7 @@ "nodebb-plugin-dbsearch": "6.2.16", "nodebb-plugin-emoji": "6.0.2", "nodebb-plugin-emoji-android": "4.1.1", - "nodebb-plugin-markdown": "13.2.0", + "nodebb-plugin-markdown": "13.2.1", "nodebb-plugin-mentions": "4.7.6", "nodebb-plugin-spam-be-gone": "2.3.2", "nodebb-plugin-web-push": "0.7.4", From 7320a858968af80f508aeaeccf731d199f59112f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 13:45:10 -0400 Subject: [PATCH 71/76] fix(deps): update dependency pg-cursor to v2.15.0 (#13414) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index ffeeab1992..ec4e60b1d5 100644 --- a/install/package.json +++ b/install/package.json @@ -118,7 +118,7 @@ "passport-http-bearer": "1.0.1", "passport-local": "1.0.0", "pg": "8.16.0", - "pg-cursor": "2.14.6", + "pg-cursor": "2.15.0", "postcss": "8.5.3", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", From f176d6b2c5cc76ee8ee749c6ed6b3b1f1430b89e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 13:45:21 -0400 Subject: [PATCH 72/76] fix(deps): update dependency satori to v0.13.1 (#13408) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index ec4e60b1d5..452ac8a79d 100644 --- a/install/package.json +++ b/install/package.json @@ -129,7 +129,7 @@ "rtlcss": "4.3.0", "sanitize-html": "2.16.0", "sass": "1.88.0", - "satori": "0.12.2", + "satori": "0.13.1", "semver": "7.7.2", "serve-favicon": "2.5.0", "sharp": "0.32.6", From d5865613e3ca132227150be1be81e9545259ecf3 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 14 May 2025 14:14:06 -0400 Subject: [PATCH 73/76] fix: #13081, don't add mention when you are replying to yourself --- public/src/client/topic/postTools.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 42f10093a0..640d936f16 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -397,7 +397,7 @@ define('forum/topic/postTools', [ return; } const post = button.parents('[data-pid]'); - if (post.length) { + if (post.length && !post.hasClass('self-post')) { require(['slugify'], function (slugify) { slug = slugify(post.attr('data-username'), true); if (!slug) { From 3e18af1e2576ce4cbaef842674f80e15c60a9a4c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 14:22:45 -0400 Subject: [PATCH 74/76] fix(deps): update dependency sanitize-html to v2.17.0 (#13418) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 452ac8a79d..2bf994ee1d 100644 --- a/install/package.json +++ b/install/package.json @@ -127,7 +127,7 @@ "rimraf": "6.0.1", "rss": "1.2.2", "rtlcss": "4.3.0", - "sanitize-html": "2.16.0", + "sanitize-html": "2.17.0", "sass": "1.88.0", "satori": "0.13.1", "semver": "7.7.2", From 919d62ab4e3eb70808264e36f0afd42c62d8dd98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 14:23:24 -0400 Subject: [PATCH 75/76] fix(deps): update dependency diff to v8 (#13409) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 2bf994ee1d..dde27f60ed 100644 --- a/install/package.json +++ b/install/package.json @@ -66,7 +66,7 @@ "cropperjs": "1.6.2", "csrf-sync": "4.2.1", "daemon": "1.1.0", - "diff": "7.0.0", + "diff": "8.0.1", "esbuild": "0.25.4", "express": "4.21.2", "express-session": "1.18.1", From 799b08db3a6f74bf32b4fc45fbb4e94441e3892d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 14 May 2025 15:22:58 -0400 Subject: [PATCH 76/76] fix: adjust Peertube-specific handling to shove mp4 into post attachments, #13324 --- src/activitypub/mocks.js | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/activitypub/mocks.js b/src/activitypub/mocks.js index b569768f98..f2a8446d4a 100644 --- a/src/activitypub/mocks.js +++ b/src/activitypub/mocks.js @@ -42,7 +42,7 @@ const sanitizeConfig = { Mocks._normalize = async (object) => { // Normalized incoming AP objects into expected types for easier mocking - let { attributedTo, url, image, content, source } = object; + let { type, attributedTo, url, image, content, source, attachment } = object; switch (true) { // non-string attributedTo handling case Array.isArray(attributedTo): { @@ -102,6 +102,30 @@ Mocks._normalize = async (object) => { if (url) { // Handle url array if (Array.isArray(url)) { + // Special handling for Video type (from PeerTube specifically) + if (type === 'Video') { + const stream = url.reduce((memo, { type, mediaType, tag }) => { + if (!memo) { + if (type === 'Link' && mediaType === 'application/x-mpegURL') { + memo = tag.reduce((memo, { type, mediaType, href }) => { + if (!memo && (type === 'Link' && mediaType === 'video/mp4')) { + memo = { type, mediaType, href }; + } + + return memo; + }, null); + } + } + + return memo; + }, null); + + if (stream) { + attachment = attachment || []; + attachment.push(stream); + } + } + url = url.reduce((valid, cur) => { if (typeof cur === 'string') { valid.push(cur); @@ -126,6 +150,7 @@ Mocks._normalize = async (object) => { sourceContent, image, url, + attachment, }; }; @@ -332,7 +357,7 @@ Mocks.post = async (objects) => { attributedTo: uid, inReplyTo: toPid, published, updated, name, content, sourceContent, - type, to, cc, audience, attachment, tag, image, + to, cc, audience, attachment, tag, image, } = object; await activitypub.actors.assert(uid); @@ -346,11 +371,6 @@ Mocks.post = async (objects) => { let edited = new Date(updated); edited = Number.isNaN(edited.valueOf()) ? undefined : edited; - if (type === 'Video') { - attachment = attachment || []; - attachment.push({ url }); - } - const payload = { uid, pid,