From f7560c585f211be41b093906e3a8fb5a6071c660 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 15 Feb 2015 09:54:04 -0500 Subject: Add hebrew translation This is a copy-paste job from mat-mo PR. There is missing translations since it was done prior to the i18n changes. See #689 for more information --- app/i18n/de/gen.php | 1 + app/i18n/en/gen.php | 1 + app/i18n/fr/gen.php | 1 + app/i18n/he/admin.php | 170 +++++++++++++++++++++++++++++++++++++++++++++++ app/i18n/he/conf.php | 169 ++++++++++++++++++++++++++++++++++++++++++++++ app/i18n/he/feedback.php | 110 ++++++++++++++++++++++++++++++ app/i18n/he/gen.php | 164 +++++++++++++++++++++++++++++++++++++++++++++ app/i18n/he/index.php | 61 +++++++++++++++++ app/i18n/he/install.php | 107 +++++++++++++++++++++++++++++ app/i18n/he/sub.php | 61 +++++++++++++++++ 10 files changed, 845 insertions(+) create mode 100644 app/i18n/he/admin.php create mode 100644 app/i18n/he/conf.php create mode 100644 app/i18n/he/feedback.php create mode 100644 app/i18n/he/gen.php create mode 100644 app/i18n/he/index.php create mode 100644 app/i18n/he/install.php create mode 100644 app/i18n/he/sub.php diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index f3479ed53..bdc10d77a 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -107,6 +107,7 @@ return array( 'de' => 'Deutsch', 'en' => 'English', 'fr' => 'Français', + 'he' => 'עברית', ), 'menu' => array( 'about' => 'Über', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 2143822ed..223cd82b1 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -107,6 +107,7 @@ return array( 'de' => 'Deutsch', 'en' => 'English', 'fr' => 'Français', + 'he' => 'עברית', ), 'menu' => array( 'about' => 'About', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 1cfec6969..92dc297c0 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -107,6 +107,7 @@ return array( 'de' => 'Deutsch', 'en' => 'English', 'fr' => 'Français', + 'he' => 'עברית', ), 'menu' => array( 'about' => 'À propos', diff --git a/app/i18n/he/admin.php b/app/i18n/he/admin.php new file mode 100644 index 000000000..6153a62c5 --- /dev/null +++ b/app/i18n/he/admin.php @@ -0,0 +1,170 @@ + array( + 'allow_anonymous' => 'הרשאה לאנונימיים לקרוא את מאמרי משתמש ברירת המחדל (%s)', + 'allow_anonymous_refresh' => 'הרשאה לאנונימיים לרענן את רשימת המאמרים', + 'api_enabled' => 'הרשאת גישה ל API (נדרש ליישומים סלולריים)', + 'form' => 'טופס אינטרנטי (מסורתי, דורש JavaScript)', + 'http' => 'HTTP (למשתמשים מתקדמים עם HTTPS)', + 'none' => 'ללא (מסוכן)', + 'persona' => 'מוזילה פרסונה (מודרני, דורש JavaScript)', + 'title' => 'Authentication', // @todo + 'title_reset' => 'איפוס אימות', + 'token' => 'מחרוזת אימות', + 'token_help' => 'Allows to access RSS output of the default user without authentication:', // @todo + 'type' => 'שיטת אימות', + 'unsafe_autologin' => 'הרשאה להתחברות אוטומטית בפורמט: ', + ), + 'check_install' => array( + 'cache' => array( + 'nok' => 'יש לבדוק את ההרשאות בתיקייה %s. שרת הHTTP חייב להיות בעל הרשאות כתיבה.', + 'ok' => 'ההרשאות בתיקיית המטמון תקינות', + ), + 'categories' => array( + 'nok' => 'Category table is bad configured.', // @todo + 'ok' => 'Category table is ok.', // @todo + ), + 'connection' => array( + 'nok' => 'Connection to the database cannot being established.', // @todo + 'ok' => 'Connection to the database is ok.', // @todo + ), + 'ctype' => array( + 'nok' => 'הספרייה הנדרשת ל character type checking (php-ctype) אינה מותקנת', + 'ok' => 'הספרייה הנדרשת ל character type checking (ctype) מותקנת', + ), + 'curl' => array( + 'nok' => 'בURL לא מותקן (php5-curl package)', + 'ok' => 'You have cURL extension.', // @todo + ), + 'data' => array( + 'nok' => 'יש לבדוק את ההרשאות בתיקייה %s. שרת הHTTP חייב להיות בעל הרשאות כתיבה.', + 'ok' => 'ההרשאות בתיקיית הדאטא תקינות', + ), + 'database' => 'Database installation', // @todo + 'dom' => array( + 'nok' => 'הספרייה הנדרשת לסיור ב DOM אינה מותקנת (php-xml package)', + 'ok' => 'הספרייה הנדרשת לסיור ב DOM מותקנת', + ), + 'entries' => array( + 'nok' => 'Entry table is bad configured.', // @todo + 'ok' => 'Entry table is ok.', // @todo + ), + 'favicons' => array( + 'nok' => 'Check permissions on ./data/favicons directory. HTTP server must have rights to write into', // @todo + 'ok' => 'ההרשאות בתיקיית הfavicons תקינות', + ), + 'feeds' => array( + 'nok' => 'Feed table is bad configured.', // @todo + 'ok' => 'Feed table is ok.', // @todo + ), + 'files' => 'File installation', // @todo + 'json' => array( + 'nok' => 'You lack JSON (php5-json package).', // @todo + 'ok' => 'You have JSON extension.', // @todo + ), + 'minz' => array( + 'nok' => 'You lack the Minz framework.', // @todo + 'ok' => 'יש לכם את תשתית Minz', + ), + 'pcre' => array( + 'nok' => 'הספרייה הנדרשת לביטויים רגולריים אינה מותקנת (php-pcre)', + 'ok' => 'הספרייה הנדרשת לביטויים רגולריים מותקנת (PCRE)', + ), + 'pdo' => array( + 'nok' => 'PDO אינו מותקן או שאחד ממנהלי ההתקנים שלו חסר (pdo_mysql, pdo_sqlite)', + 'ok' => 'PDO מותקן ולפחות אחד ממנהלי ההתקן הנתמכים מותקן (pdo_mysql, pdo_sqlite)', + ), + 'persona' => array( + 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', // @todo + 'ok' => 'ההרשאות בתיקיית מוזילה פרסונה תקינות', + ), + 'php' => array( + '_' => 'PHP installation', // @todo + 'nok' => 'גירסת PHP שלכם היא %s אך FreshRSS דורש לפחות את גירסה %s', + 'ok' => 'גירסת PHP שלכם היא %s, שתואמת ל FreshRSS', + ), + 'tables' => array( + 'nok' => 'There is one or more lacking tables in the database.', // @todo + 'ok' => 'Tables are existing in the database.', // @todo + ), + 'title' => 'Installation checking', // @todo + 'tokens' => array( + 'nok' => 'Check permissions on ./data/tokens directory. HTTP server must have rights to write into', // @todo + 'ok' => 'Permissions on tokens directory are good.', // @todo + ), + 'users' => array( + 'nok' => 'Check permissions on ./data/users directory. HTTP server must have rights to write into', // @todo + 'ok' => 'Permissions on users directory are good.', // @todo + ), + 'zip' => array( + 'nok' => 'You lack ZIP extension (php5-zip package).', // @todo + 'ok' => 'You have ZIP extension.', // @todo + ), + ), + 'extensions' => array( + 'disabled' => 'Disabled', // @todo + 'empty_list' => 'There is no installed extension', // @todo + 'enabled' => 'Enabled', // @todo + 'no_configure_view' => 'This extension cannot be configured.', // @todo + 'system' => array( + '_' => 'System extensions', // @todo + 'no_rights' => 'System extension (you have no rights on it)', // @todo + ), + 'title' => 'Extensions', // @todo + 'user' => 'User extensions', // @todo + ), + 'stats' => array( + '_' => 'סטטיסטיקות', + 'all_feeds' => 'כל ההזנות', + 'category' => 'קטגוריה', + 'entry_count' => 'סכום המאמרים', + 'entry_per_category' => 'מאמרים על פי קטגוריה', + 'entry_per_day' => 'מספר מאמרים ליום (30 ימים אחרונים)', + 'entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', // @todo + 'entry_per_hour' => 'Per hour (average: %.2f messages)', // @todo + 'entry_per_month' => 'Per month (average: %.2f messages)', // @todo + 'entry_repartition' => 'חלוקת המאמרים', + 'feed' => 'הזנה', + 'feed_per_category' => 'הזנות על פי קטגוריה', + 'idle' => 'הזנות שלא עודכנו', + 'main' => 'סטטיסטיקות ראשיות', + 'main_stream' => 'הזנה ראשית', + 'menu' => array( + 'idle' => 'הזנות שלא עודכנו', + 'main' => 'סטטיסטיקות ראשיות', + 'repartition' => 'חלוקת המאמרים', + ), + 'no_idle' => 'אין הזנות מובטלות!', + 'number_entries' => '%d מאמרים', + 'percent_of_total' => '%% מסך הכל', + 'repartition' => 'חלוקת המאמרים', + 'status_favorites' => 'מועדפים', + 'status_read' => 'נקרא', + 'status_total' => 'סך הכל', + 'status_unread' => 'לא נקרא', + 'title' => 'סטטיסטיקות', + 'top_feed' => 'עשרת ההזנות המובילות', + ), + 'update' => array( + '_' => 'מערכת העדכון', + 'apply' => 'החלת העדכון', + 'check' => 'בדיקת עדכונים חדשים', + 'current_version' => 'Your current version of FreshRSS is the %s.', // @todo + 'last' => 'תאריך בדיקה אחרון: %s', + 'none' => 'אין עדכון להחלה', + 'title' => 'מערכת העדכון', + ), + 'user' => array( + 'articles_and_size' => '%s articles (%s)', // @todo + 'create' => 'יצירת משתמש חדש', + 'email_persona' => 'כתובת דואר אלקטרוני להרשמה
(לצורך מוזילה פרסונה)', + 'language' => 'שפה', + 'password_form' => 'סיסמה
(לשימוש בטפוס ההרשמה)', + 'password_format' => 'At least 7 characters', // @todo + 'title' => 'Manage users', // @todo + 'user_list' => 'רשימת משתמשים', + 'username' => 'שם משתמש', + 'users' => 'משתמשים', + ), +); diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php new file mode 100644 index 000000000..e318bba4d --- /dev/null +++ b/app/i18n/he/conf.php @@ -0,0 +1,169 @@ + array( + '_' => 'ארכוב', + 'advanced' => 'מתקדם', + 'delete_after' => 'מחיקת מאמרים לאחר', + 'help' => 'אפשרויות נוספות זמינות בזרמים ספציפיים', + 'keep_history_by_feed' => 'Minimum number of articles to keep by feed', // @todo + 'optimize' => 'מיטוב בסיס הנתונים', + 'optimize_help' => 'ביצוע לעיתים קרובות על מנת למטב את בסיס הנתונים', + 'purge_now' => 'ניקוי עכשיו', + 'title' => 'ארכוב', + 'ttl' => 'אין לרענן אוטומטית יותר מ', + ), + 'display' => array( + '_' => 'תצוגה', + 'icon' => array( + 'bottom_line' => 'שורה תחתונה', + 'entry' => 'סמלילי מאמרים', + 'publication_date' => 'תאריך הפרסום', + 'related_tags' => 'תגיות קשורות', + 'sharing' => 'שיתוף', + 'top_line' => 'שורה עליונה', + ), + 'language' => 'שפה', + 'notif_html5' => array( + 'seconds' => 'שניות (0 משמעותה ללא פג תוקף)', + 'timeout' => 'HTML5 התראה פג תוקף', + ), + 'theme' => 'ערכת נושא', + 'title' => 'תצוגה', + 'width' => array( + 'content' => 'רוחב התוכן', + 'large' => 'גדול', + 'medium' => 'בינוני', + 'no_limit' => 'ללא הגבלה', + 'thin' => 'צר', + ), + ), + 'query' => array( + '_' => 'שאילתות', + 'deprecated' => 'שאילתה זו אינה בתוקף יותר, הפיד או הקטגוריה לייחוס נמחקו.', + 'filter' => 'מסננים בשימוש:', + 'get_all' => 'הצגת כל המאמרים', + 'get_category' => 'הצגת קטגוריה "%s"', + 'get_favorite' => 'הצגת מאמרים מועדפים', + 'get_feed' => 'הצגת הזנה %s', + 'no_filter' => 'ללא סינון', + 'none' => 'אף שאילתה לא נוצרה עדיין.', + 'number' => 'שאילתה מספר °%d', + 'order_asc' => 'הצגת מאמרים ישנים בראש', + 'order_desc' => 'הצגת מאמרים חדשים בראש', + 'search' => 'חיפוש "%s"', + 'state_0' => 'הצגת כל המאמרים', + 'state_1' => 'הצגת מאמרים שנקראו', + 'state_2' => 'הצגת מאמרים שלא נקראו', + 'state_3' => 'הצגת כל המאמרים', + 'state_4' => 'הצגת מאמרים מועדפים', + 'state_5' => 'הצגת מאמרים מועדפים שנקראו', + 'state_6' => 'הצגת מאמרים מועדפים שלא נקראו', + 'state_7' => 'הצגת מאמרים מועדפים', + 'state_8' => 'הצגת מאמרים שאינם מועדפים', + 'state_9' => 'הצגת מאמרים שנקראו ואינם מועדפים', + 'state_10' => 'הצגת מאמרים שלא נקראו ואינם מועדפים', + 'state_11' => 'הצגת מאמרים לא מועדפים', + 'state_12' => 'הצגת כל המאמרים', + 'state_13' => 'הצגת מאמרים שנקראו', + 'state_14' => 'הצגת מאמרים שלא נקראו', + 'state_15' => 'הצגת כל המאמרים', + 'title' => 'שאילתות', + ), + 'profile' => array( + '_' => 'Profile management', // @todo + 'email_persona' => 'כתובת דואר אלקטרוני להרשמה
(לצורך מוזילה פרסונה)', + 'password_api' => 'סיסמת API
(לדוגמה ליישומים סלולריים)', + 'password_form' => 'סיסמה
(לשימוש בטפוס ההרשמה)', + 'password_format' => 'At least 7 characters', // @todo + 'title' => 'Profile', // @todo + ), + 'reading' => array( + '_' => 'קריאה', + 'after_onread' => 'לאחר “סימון הכל כנקרא”,', + 'articles_per_page' => 'מספר המאמרים בעמוד', + 'auto_load_more' => 'טעינת המאמר הבא סוף העמוד', + 'auto_remove_article' => 'Hide articles after reading', // @todo + 'confirm_enabled' => 'הצגת דו-שיח לאישור “סימון הכל כנקרא” ', + 'display_articles_unfolded' => 'הצגת מאמרים בשלמותם כברירת מחדל', + 'display_categories_unfolded' => 'הצגת קטגוריות מקופלות כברירת מחדל', + 'hide_read_feeds' => 'הסתרת קטגוריות & הזנות ללא מאמרים שלא נקראו (לא עובד יחד עם “הצגת כל המאמרים”)', + 'img_with_lazyload' => 'שימוש ב "טעינה עצלה" על מנת לטעון תמונות', + 'jump_next' => 'קפיצה לפריט הבא שלא נקרא (הזנה או קטגוריה)', + 'number_divided_when_reader' => 'חלוקה ב2 במצב קריאה.', + 'read' => array( + 'article_open_on_website' => 'כאשר מאמר נפתח באתר המקורי', + 'article_viewed' => 'כאשר מאמר נצפה', + 'scroll' => 'כאשר גוללים', + 'upon_reception' => 'כאשר המאמר מתקבל', + 'when' => 'סימון מאמרים כנקראו…', + ), + 'show' => array( + '_' => 'מאמרים להצגה', + 'adaptive' => 'תצוגה מתעדכנת', + 'all_articles' => 'הצגת כל המאמרים', + 'unread' => 'הצגת מאמרים שלא נקראו בלבד', + ), + 'sort' => array( + '_' => 'סדר המיון', + 'newer_first' => 'חדשים בראש', + 'older_first' => 'ישנים יותר בראש', + ), + 'sticky_post' => 'הצמדת המאמר לחלק העליון כאשר הוא פתוח', + 'title' => 'קריאה', + 'view' => array( + 'default' => 'תצוגת ברירת המחדל', + 'global' => 'תצוגה גלובלית', + 'normal' => 'תצוגה רגילה', + 'reader' => 'תצוגת קריאה', + ), + ), + 'sharing' => array( + '_' => 'שיתוף', + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'email' => 'דואר אלקטרוני', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'more_information' => 'מידע נוסף', + 'print' => 'הדפסה', + 'shaarli' => 'Shaarli', + 'share_name' => 'שיתוף שם לתצוגה', + 'share_url' => 'לשימוש שתפו URL', + 'title' => 'שיתוף', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag', + ), + 'shortcut' => array( + '_' => 'קיצורי דרך', + 'article_action' => 'פעולות על מאמרים', + 'auto_share' => 'שיתוף', + 'auto_share_help' => 'אם יש רק מצב שיתוף אחד, הוא מופעל. אחרת המצבים נבחרים על בסיס המספר שלהם.', + 'close_dropdown' => 'Close menus', // @todo + 'collapse_article' => 'כיווץ', + 'first_article' => 'דילוג למאמר הראשון', + 'focus_search' => 'גישה לתיבת החיפוש', + 'help' => 'הצגת התיעוד', + 'javascript' => 'חובה להפעיל JavaScript על מנת לעשות שימוש בקיצורי דרך', + 'last_article' => 'דילוג למאמר האחרון', + 'load_more' => 'טעינת מאמרים נוספים', + 'mark_read' => 'סימון כנקרא', + 'mark_favorite' => 'סימון כמועדף', + 'navigation' => 'ניווט', + 'navigation_help' => 'בעזרת מקש השיפט קיצורי דרך חלים על הזנות .
עם מקש האלט הם חלים על קטגוריות.', + 'next_article' => 'דילוג למאמר הבא', + 'other_action' => 'פעולות אחרות', + 'previous_article' => 'דילוג למאמר הקודם', + 'see_on_website' => 'ראו את המקור באתר', + 'shift_for_all_read' => '+ shift על מנת לסמן את כל המאמרים כנקראו', + 'title' => 'קיצורי דרך', + 'user_filter' => 'גישה למססנים', + 'user_filter_help' => 'אם יש רק מזנן אחד הוא יהיה בשימוש. אחרת המסננים ישמשו על בסיס המספר שלהם.', + ), + 'user' => array( + 'articles_and_size' => '%s articles (%s)', // @todo + 'current' => 'משתמש נוכחי', + 'is_admin' => 'מנהל', + 'users' => 'משתמשים', + ), +); diff --git a/app/i18n/he/feedback.php b/app/i18n/he/feedback.php new file mode 100644 index 000000000..9a72b2ba0 --- /dev/null +++ b/app/i18n/he/feedback.php @@ -0,0 +1,110 @@ + array( + 'optimization_complete' => 'המיטוב הושלם', + ), + 'access' => array( + 'denied' => 'אין לך הרשאות לצפות בדף זה', + 'not_found' => 'הדף הזה לא נמצא', + ), + 'auth' => array( + 'form' => array( + 'not_set' => 'אירעה שגיאה במהלך הגדרת מערכת האימיות. אנא נסו שוב מאוחר יותר.', + 'set' => 'טופס הוא כרגע מערכת האימות כברירת מחדל.', + ), + 'login' => array( + 'invalid' => 'הכניסה לחשבון שגויה', + 'success' => 'You are connected', // @todo + ), + 'logout' => array( + 'success' => 'You are disconnected', // @todo + ), + 'no_password_set' => 'לא הוגדרה סיסמת מנהל. תכונה זו אינה זמינה.', + 'not_persona' => 'ניתן לאפס את מערכת הפרסונה בלבד.', + ), + 'conf' => array( + 'error' => 'An error occurred during configuration saving', // @todo + 'query_created' => 'השאילתה "%s" נוצרה.', + 'shortcuts_updated' => 'קיצורי הדרך עודכנו', + 'updated' => 'ההגדרות עודכנו', + ), + 'extensions' => array( + 'already_enabled' => '%s is already enabled', // @todo + 'disable' => array( + 'ko' => '%s cannot be disabled. Check FressRSS logs for details.', // @todo + 'ok' => '%s is now disabled', // @todo + ), + 'enable' => array( + 'ko' => '%s cannot be enabled. Check FressRSS logs for details.', // @todo + 'ok' => '%s is now enabled', // @todo + ), + 'no_access' => 'You have no access on %s', // @todo + 'not_enabled' => '%s is not enabled yet', // @todo + 'not_found' => '%s does not exist', // @todo + ), + 'import_export' => array( + 'export_no_zip_extension' => 'הרחבת ZIP אינה מותקנת על השרת.', + 'feeds_imported' => 'ההזנות שלך יובאו וכעת יעודכנו', + 'feeds_imported_with_errors' => 'ההזנות שלך יובאו אך אירעו מספר שגיאות', + 'file_cannot_be_uploaded' => 'אין אפשרות להעלות את הקובץ!', + 'no_zip_extension' => 'הרחבת ZIP אינה מותקנת על השרת.', + 'zip_error' => 'אירעה שגיאה במהלך ייבוא קובץ הZIP.', + ), + 'sub' => array( + 'actualize' => 'מימוש', + 'category' => array( + 'created' => 'Category %s has been created.', // @todo + 'deleted' => 'Category has been deleted.', // @todo + 'emptied' => 'הקטגוריה רוקנה', + 'error' => 'Category cannot be updated', // @todo + 'name_exists' => 'Category name already exists.', // @todo + 'no_id' => 'You must precise the id of the category.', // @todo + 'no_name' => 'Category name cannot be empty.', // @todo + 'not_delete_default' => 'You cannot delete the default category!', // @todo + 'not_exist' => 'The category does not exist!', // @todo + 'over_max' => 'You have reached your limit of categories (%d)', // @todo + 'updated' => 'Category has been updated.', // @todo + ), + 'feed' => array( + 'actualized' => '%s עודכן', + 'actualizeds' => 'הזנות RSS עודכנו', + 'added' => 'RSS הזנת %s נוספה', + 'already_subscribed' => 'אתה כבר רשום ל %s', + 'deleted' => 'ההזנה נמחקה', + 'error' => 'Feed cannot be updated', // @todo + 'internal_problem' => 'אין אפשרות להוסיף את ההזנה. בדקו את הלוגים לפרטים.', + 'invalid_url' => 'URL %s אינו תקין', + 'marked_read' => 'הזנות סומנו כנקראו', + 'n_actualized' => '%d הזנות עודכנו', + 'n_entries_deleted' => '%d המאמרים נמחקו', + 'no_refresh' => 'אין הזנה שניתן לרענן…', + 'not_added' => '%s אין אפשרות להוסיף את', + 'over_max' => 'You have reached your limit of feeds (%d)', // @todo + 'updated' => 'ההזנה התעדכנה', + ), + 'purge_completed' => 'הניקוי הושלם (%d מאמרים נמחקו)', + ), + 'update' => array( + 'can_apply' => 'FreshRSS will be now updated to the version %s.', // @todo + 'error' => 'תהליך העדכון נתקל בשגיאה: %s', + 'file_is_nok' => 'יש לבדוק את ההרשאות בתיקייה %s. שרת הHTTP חייב להיות בעל הרשאות כתיבה.', + 'finished' => 'העדכון הושלם!', + 'none' => 'אין עדכון להחלה', + 'server_not_found' => 'לא ניתן למצוא את שרת העדכון. [%s]', + ), + 'user' => array( + 'created' => array( + '_' => 'המשתמש %s נוצר', + 'error' => 'User %s cannot be created', // @todo + ), + 'deleted' => array( + '_' => 'המשתמש %s נמחק', + 'error' => 'User %s cannot be deleted', // @todo + ), + ), + 'profile' => array( + 'error' => 'Your profile cannot be modified', // @todo + 'updated' => 'Your profile has been modified', // @todo + ), +); diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php new file mode 100644 index 000000000..35bc7e3e2 --- /dev/null +++ b/app/i18n/he/gen.php @@ -0,0 +1,164 @@ + array( + 'actualize' => 'מימוש', + 'back_to_rss_feeds' => '← חזרה להזנות הRSS שלך', + 'cancel' => 'ביטול', + 'create' => 'יצירה', + 'disable' => 'Disable', // @todo + 'empty' => 'Empty', // @todo + 'enable' => 'Enable', // @todo + 'export' => 'ייצוא', + 'filter' => 'מסנן', + 'import' => 'ייבוא', + 'manage' => 'ניהול', + 'mark_read' => 'סימון כנקרא', + 'mark_favorite' => 'סימון כמועדף', + 'remove' => 'Remove', // @todo + 'see_website' => 'ראו אתר', + 'submit' => 'אישור', + 'truncate' => 'מחיקת כל המאמרים', + ), + 'auth' => array( + 'keep_logged_in' => 'השאר מחובר חודש', + 'login' => 'כניסה לחשבון', + 'login_persona' => 'התחברות באמצעות פרסונה', + 'login_persona_problem' => 'בעיות התחברות עם פרסונה?', + 'logout' => 'יציאה מהחשבון', + 'password' => 'סיסמה', + 'reset' => 'איפוס אימות', + 'username' => 'שם משתמש', + 'username_admin' => 'שם משתמש של המנהל', + 'will_reset' => 'מערכת האימות אופסה: טופס ישמש לאימות במקום מוזילה פרסונה.', + ), + 'date' => array( + 'Apr' => '\\A\\p\\r\\i\\l', + 'Aug' => '\\A\\u\\g\\u\\s\\t', + 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', + 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', + 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'Jul' => '\\J\\u\\l\\y', + 'Jun' => '\\J\\u\\n\\e', + 'Mar' => '\\M\\a\\r\\c\\h', + 'May' => '\\M\\a\\y', + 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', + 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'apr' => 'apr', + 'april' => 'Apr', + 'aug' => 'aug', + 'august' => 'Aug', + 'before_yesterday' => 'ישן יותר', + 'dec' => 'dec', + 'december' => 'Dec', + 'feb' => 'feb', + 'february' => 'Feb', + 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', + 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', + 'fri' => 'Fri', + 'jan' => 'jan', + 'january' => 'Jan', + 'jul' => 'jul', + 'july' => 'Jul', + 'jun' => 'jun', + 'june' => 'Jun', + 'last_3_month' => 'בשלושת החודשים האחרונים', + 'last_6_month' => 'בששת החודשים האחרונים', + 'last_month' => 'בחודש שעבר', + 'last_week' => 'בשבוע שעבר', + 'last_year' => 'בשנה האחרונה', + 'mar' => 'mar', + 'march' => 'Mar', + 'may' => 'May', + 'mon' => 'Mon', + 'month' => 'חודשים', + 'nov' => 'nov', + 'november' => 'Nov', + 'oct' => 'oct', + 'october' => 'Oct', + 'sat' => 'Sat', + 'sep' => 'sep', + 'september' => 'Sep', + 'sun' => 'Sun', + 'thu' => 'Thu', + 'today' => 'היום', + 'tue' => 'Tue', + 'wed' => 'Wed', + 'yesterday' => 'אתמול', + ), + 'freshrss' => array( + '_' => 'FreshRSS', + 'about' => 'אודות FreshRSS', + ), + 'js' => array( + 'category_empty' => 'Empty category', // @todo + 'confirm_action' => 'האם אתם בטוחים שברצונכם לבצע פעולה זו? אין אפשרות לבטל אותה!', + 'confirm_action_feed_cat' => 'האם אתם בטוחים שברצוניכם לבצע פעולה זו? מועדפים ושאילתות עשויות לאבוד. אין אפשרות לבטל אותה!', + 'feedback' => array( + 'body_new_articles' => 'ישנם \d מאמרים חדשים לקרוא ב FreshRSS.', + 'request_failed' => 'A request has failed, it may have been caused by Internet connection problems.', // @todo + 'title_new_articles' => 'FreshRSS: מאמרים חדשים!', + ), + 'new_article' => 'מאמרים חדשים זמינים, לחצו לרענון העמוד.', + 'should_be_activated' => 'חובה להפעיל JavaScript', + ), + 'lang' => array( + 'de' => 'Deutsch', + 'en' => 'English', + 'fr' => 'Français', + 'he' => 'עברית', + ), + 'menu' => array( + 'about' => 'אודות', + 'admin' => 'ניהול', + 'archiving' => 'ארכוב', + 'authentication' => 'Authentication', // @todo + 'check_install' => 'Installation checking', // @todo + 'configuration' => 'הגדרות', + 'display' => 'תצוגה', + 'extensions' => 'Extensions', // @todo + 'logs' => 'לוגים', + 'queries' => 'שאילתות', + 'reading' => 'קריאה', + 'search' => 'חיפוש מילים או #תגים', + 'sharing' => 'שיתוף', + 'shortcuts' => 'קיצורי דרך', + 'stats' => 'סטטיסטיקות', + 'update' => 'עדכון', + 'user_management' => 'Manage users', // @todo + 'user_profile' => 'Profile', // @todo + ), + 'pagination' => array( + 'first' => 'הראשון', + 'last' => 'אחרון', + 'load_more' => 'טעינת מאמרים נוספים', + 'mark_all_read' => 'סימון הכל כנקרא', + 'next' => 'הבא', + 'nothing_to_load' => 'אין מאמרים נוספים', + 'previous' => 'הקודם', + ), + 'share' => array( + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'email' => 'דואר אלקטרוני', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'print' => 'הדפסה', + 'shaarli' => 'Shaarli', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag', + ), + 'short' => array( + 'attention' => 'זהירות!', + 'blank_to_disable' => 'יש להשאיר ריק על מנת לנטרל', + 'by_author' => 'מאת %s', + 'by_default' => 'ברירת מחדל', + 'damn' => 'הו לא!', + 'default_category' => 'ללא קטגוריה', + 'no' => 'לא', + 'ok' => 'כן!', + 'or' => 'או', + 'yes' => 'כן', + ), +); diff --git a/app/i18n/he/index.php b/app/i18n/he/index.php new file mode 100644 index 000000000..cef07eaf8 --- /dev/null +++ b/app/i18n/he/index.php @@ -0,0 +1,61 @@ + array( + '_' => 'אודות', + 'agpl3' => 'AGPL 3', + 'bugs_reports' => 'דיווח באגים', + 'credits' => 'קרדיטים', + 'credits_content' => 'מאפייני עיצוב מסויימים הגיעו מ Bootstrap אף על פי ש FreshRSS אינו משתמש בתשתית הזו. סמלילים הגיעו מ פרוייקט GNOME . Open Sans הגופן police נוצר על ידי Steve Matteson. Favicons נאספים בעזרת getFavicon API. FreshRSS מבוסס על Minz, תשתית PHP.', + 'freshrss_description' => 'FreshRSS הוא קורא RSS לאחסון עצמי בדומה ל Kriss Feed או Leed. אינו צורך משאבים רבים, וקל לתפעול אך בו בזמן חזק וניתן להתאמה.', + 'github' => 'בגיטהאב', + 'license' => 'רישיון', + 'project_website' => 'אתר', + 'title' => 'אודות', + 'version' => 'גרסה', + 'website' => 'אתר', + ), + 'feed' => array( + 'add' => 'ניתן להוסיף הזנות חדשות.', + 'empty' => 'אין מאמר להצגה.', + 'rss_of' => 'הזנת RSS של %s', + 'title' => 'ההזנות שלך', + 'title_global' => 'תצוגה גלובלית', + 'title_fav' => 'המועדפים שלך', + ), + 'log' => array( + '_' => 'לוגים', + 'clear' => 'ניקוי הלוגים', + 'empty' => 'קובץ הלוג ריק', + 'title' => 'לוגים', + ), + 'menu' => array( + 'about' => 'אודות FreshRSS', + 'add_query' => 'הוספת שאילתה', + 'before_one_day' => 'אתמול', + 'before_one_week' => 'לפני שבוע', + 'favorites' => 'מועדפים (%s)', + 'global_view' => 'תצוגה גלובלית', + 'main_stream' => 'הזנה ראשית', + 'mark_all_read' => 'סימון הכל כנקרא', + 'mark_cat_read' => 'סימון קטגוריה כנקראה', + 'mark_feed_read' => 'סימון הזנה כנקראה', + 'newer_first' => 'חדשים בראש', + 'non-starred' => 'הצגת הכל פרט למועדפים', + 'normal_view' => 'תצוגה רגילה', + 'older_first' => 'ישנים יותר בראש', + 'queries' => 'שאילתות', + 'read' => 'הצגת נקראו בלבד', + 'reader_view' => 'תצוגת קריאה', + 'rss_view' => 'הזנת RSS', + 'search_short' => 'חיפוש', + 'starred' => 'הצגת מועדפים בלבד', + 'stats' => 'סטטיסטיקות', + 'subscription' => 'ניהול הרשמות', + 'unread' => 'הצגת מאמרים שלא נקראו בלבד', + ), + 'share' => 'שיתוף', + 'tag' => array( + 'related' => 'תגיות קשורות', + ), +); diff --git a/app/i18n/he/install.php b/app/i18n/he/install.php new file mode 100644 index 000000000..6d7cee661 --- /dev/null +++ b/app/i18n/he/install.php @@ -0,0 +1,107 @@ + array( + 'finish' => 'השלמת ההתקנה', + 'fix_errors_before' => 'יש לתקן את השגיאות לפני המעבר לשלב הבא.', + 'next_step' => 'לשלב הבא', + ), + 'auth' => array( + 'email_persona' => 'כתובת דואר אלקטרוני להרשמה
(לצורך מוזילה פרסונה)', + 'form' => 'טופס אינטרנטי (מסורתי, דורש JavaScript)', + 'http' => 'HTTP (למשתמשים מתקדמים עם HTTPS)', + 'none' => 'ללא (מסוכן)', + 'password_form' => 'סיסמה
(לשימוש בטפוס ההרשמה)', + 'password_format' => 'At least 7 characters', // @todo + 'persona' => 'מוזילה פרסונה (מודרני, דורש JavaScript)', + 'type' => 'שיטת אימות', + ), + 'bdd' => array( + '_' => 'בסיס נתונים', + 'conf' => array( + '_' => 'הגדרות בסיס נתונים', + 'ko' => 'נא לוודא את הגדרות בסיס הנתונים.', + 'ok' => 'הגדרות בסיס הנתונים נשמרו.', + ), + 'host' => 'מארח', + 'prefix' => 'קידומת הטבלה', + 'password' => 'HTTP סיסמה', + 'type' => 'סוג בסיס הנתונים', + 'username' => 'HTTP שם משתמש', + ), + 'check' => array( + '_' => 'בדיקות', + 'cache' => array( + 'nok' => 'Check permissions on ./data/cache directory. HTTP server must have rights to write into', // @todo + 'ok' => 'ההרשאות בתיקיית המטמון תקינות', + ), + 'ctype' => array( + 'nok' => 'הספרייה הנדרשת ל character type checking (php-ctype) אינה מותקנת', + 'ok' => 'הספרייה הנדרשת ל character type checking (ctype) מותקנת', + ), + 'curl' => array( + 'nok' => 'בURL לא מותקן (php5-curl package)', + 'ok' => 'יש לכם את גירסת %s של cURL', + ), + 'data' => array( + 'nok' => 'Check permissions on ./data directory. HTTP server must have rights to write into', // @todo + 'ok' => 'ההרשאות בתיקיית הדאטא תקינות', + ), + 'dom' => array( + 'nok' => 'הספרייה הנדרשת לסיור ב DOM אינה מותקנת (php-xml package)', + 'ok' => 'הספרייה הנדרשת לסיור ב DOM מותקנת', + ), + 'favicons' => array( + 'nok' => 'Check permissions on ./data/favicons directory. HTTP server must have rights to write into', // @todo + 'ok' => 'ההרשאות בתיקיית הfavicons תקינות', + ), + 'http_referer' => array( + 'nok' => 'נא לדבוק שאינך פוגעת ב HTTP REFERER שלך.', + 'ok' => 'הHTTP REFERER ידוע ותאם לשרת שלך.', + ), + 'minz' => array( + 'nok' => 'You lack the Minz framework.', // @todo + 'ok' => 'יש לכם את תשתית Minz', + ), + 'pcre' => array( + 'nok' => 'הספרייה הנדרשת לביטויים רגולריים אינה מותקנת (php-pcre)', + 'ok' => 'הספרייה הנדרשת לביטויים רגולריים מותקנת (PCRE)', + ), + 'pdo' => array( + 'nok' => 'PDO אינו מותקן או שאחד ממנהלי ההתקנים שלו חסר (pdo_mysql, pdo_sqlite)', + 'ok' => 'PDO מותקן ולפחות אחד ממנהלי ההתקן הנתמכים מותקן (pdo_mysql, pdo_sqlite)', + ), + 'persona' => array( + 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', // @todo + 'ok' => 'ההרשאות בתיקיית מוזילה פרסונה תקינות', + ), + 'php' => array( + 'nok' => 'גירסת PHP שלכם היא %s אך FreshRSS דורש לפחות את גירסה %s', + 'ok' => 'גירסת PHP שלכם היא %s, שתואמת ל FreshRSS', + ), + 'users' => array( + 'nok' => 'Check permissions on ./data/users directory. HTTP server must have rights to write into', // @todo + 'ok' => 'Permissions on users directory are good.', // @todo + ), + ), + 'conf' => array( + '_' => 'הגדרות כלליות', + 'ok' => 'ההגדרות הכלליות נשמרו.', + ), + 'congratulations' => 'מזל טוב!', + 'default_user' => 'שם המשתמש של משתמש ברירת המחדל (לכל היותר 16 תווים אלפאנומריים)', + 'delete_articles_after' => 'מחיקת מאמרים לאחר', + 'fix_errors_before' => 'יש לתקן את השגיאות לפני המעבר לשלב הבא.', + 'javascript_is_better' => 'FreshRSS מעדיף שתאפשרו JavaScript', + 'language' => array( + '_' => 'שפה', + 'choose' => 'בחירת שפה ל FreshRSS', + 'defined' => 'השפה הוגדרה.', + ), + 'not_deleted' => 'משהו נכשל; יש צורך למחוק את הקובץ %s ידנית.', + 'ok' => 'The installation process was successful.', // @todo + 'step' => 'step %d', // @todo + 'steps' => 'שלבים', + 'title' => 'התקנה · FreshRSS', + 'this_is_the_end' => 'סיום', +); diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php new file mode 100644 index 000000000..9c7af0dc4 --- /dev/null +++ b/app/i18n/he/sub.php @@ -0,0 +1,61 @@ + array( + '_' => 'קטגוריה', + 'add' => 'הוספת קטגוריה', + 'empty' => 'Empty category', // @todo + 'new' => 'קטגוריה חדשה', + ), + 'feed' => array( + 'add' => 'הוספת הזנה', + 'advanced' => 'מתקדם', + 'archiving' => 'ארכוב', + 'auth' => array( + 'configuration' => 'כניסה לחשבון', + 'help' => 'החיבור מתיר לגשת להזנות RSS מוגנות', + 'http' => 'HTTP אימות', + 'password' => 'HTTP סיסמה', + 'username' => 'HTTP שם משתמש', + ), + 'css_help' => 'קבלת הזנות RSS קטומות (זהירות, לוקח זמן רב יותר!)', + 'css_path' => 'נתיב הCSS של המאמר באתר המקורי', + 'description' => 'תיאור', + 'empty' => 'הזנה זו ריקה. אנא ודאו שהיא עדיין מתוחזקת.', + 'error' => 'הזנה זו נתקלה בשגיאה, אנא ודאו שהיא תקינה ואז נסו שנית.', + 'in_main_stream' => 'הצגה בזרם המרכזי', + 'informations' => 'מידע', + 'keep_history' => 'מסםר מינימלי של מאמרים לשמור', + 'moved_category_deleted' => 'כאשר הקטגוריה נמחקת ההזנות שבתוכה אוטומטית מקוטלגות תחת %s.', + 'no_selected' => 'אף הזנה לא נבחרה.', + 'number_entries' => '%d מאמרים', + 'stats' => 'סטטיסטיקות', + 'think_to_add' => 'ניתן להוסיף הזנות חדשות.', + 'title' => 'כותרת', + 'title_add' => 'הוספת הזנה', + 'ttl' => 'אין לרענן אוטומטית יותר מ', + 'url' => 'הזנה URL', + 'validator' => 'בדיקות תקינות ההזנה', + 'website' => 'אתר URL', + ), + 'import_export' => array( + 'export' => 'ייצוא', + 'export_opml' => 'ייצוא רשימת הזנות (OPML)', + 'export_starred' => 'ייצוא מועדפים', + 'feed_list' => 'רשימה של %s מאמרים', + 'file_to_import' => 'קובץ לייבוא
(OPML, Json or Zip)', + 'file_to_import_no_zip' => 'קובץ לייבוא
(OPML or Json)', + 'import' => 'ייבוא', + 'starred_list' => 'רשימת מאמרים מועדפים', + 'title' => 'יבוא / יצוא ', + ), + 'menu' => array( + 'bookmark' => 'הרשמה (FreshRSS סימניית)', + 'import_export' => 'יבוא / יצוא ', + 'subscription_management' => 'ניהול הרשמות', + ), + 'title' => array( + '_' => 'ניהול הרשמות', + 'feed_management' => 'ניהול הזנות RSS', + ), +); -- cgit v1.2.3 From 1cf9816fe5b0c6aa6436c368ab69e43665d67f21 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 1 Oct 2017 18:37:09 +0200 Subject: Prepare future version 1.8.1 --- CHANGELOG.md | 3 +++ constants.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dbdbe960..6c364a5af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 2017-1X-XX FreshRSS 1.8.1-dev + + ## 2017-10-01 FreshRSS 1.8.0 * Compatibility: diff --git a/constants.php b/constants.php index be70188e0..195c7e073 100644 --- a/constants.php +++ b/constants.php @@ -1,5 +1,5 @@ Date: Sun, 1 Oct 2017 20:54:06 +0200 Subject: [CI] Add a translation validation tool. (#1653) It's triggered by Travis to check what is missing. --- .travis.yml | 20 +++++-- tools/check.translation.php | 127 +++++++++++++++++++++++++++++++++++++++++++ tools/translation.ignore.php | 58 ++++++++++++++++++++ 3 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 tools/check.translation.php create mode 100644 tools/translation.ignore.php diff --git a/.travis.yml b/.travis.yml index 5c43e5666..945e77a74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,16 +14,27 @@ install: script: - phpenv rehash - - phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p + - | + if [[ $VALIDATE_STANDARD == yes ]]; then + phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p + fi + - | + if [[ $CHECK_TRANSLATION == yes ]]; then + php tools/check.translation.php -r + fi + +env: + - CHECK_TRANSLATION=no VALIDATE_STANDARD=yes -env: # important! otherwise no job will be allowed to fail matrix: - # PHP 5.3 only runs on Ubuntu 12.04 (precise), not 14.04 (trusty) + fast_finish: true include: - php: "5.3" dist: precise - fast_finish: true + - php: "7.1" + env: CHECK_TRANSLATION=yes VALIDATE_STANDARD=no allow_failures: + # PHP 5.3 only runs on Ubuntu 12.04 (precise), not 14.04 (trusty) - php: "5.3" dist: precise - php: "5.4" @@ -32,3 +43,4 @@ matrix: - php: "7.0" - php: hhvm - php: nightly + - env: CHECK_TRANSLATION=yes VALIDATE_STANDARD=no diff --git a/tools/check.translation.php b/tools/check.translation.php new file mode 100644 index 000000000..7854e131f --- /dev/null +++ b/tools/check.translation.php @@ -0,0 +1,127 @@ +[^/]+)/(?P[^/]*.php)#', $i18nFile, $matches); + $lang = $matches['lang']; + $file = $matches['file']; + if ('en' === $lang) { + continue; + } + if (!array_key_exists($lang, $report)) { + $report[$lang]['total'] = 0; + $report[$lang]['errors'] = 0; + } + $i18n = flatten(include $i18nFile); + foreach ($en as $key => $value) { + $report[$lang]['total'] ++; + if (array_key_exists($lang, $ignore) && array_key_exists($file, $ignore[$lang]) && in_array($key, $ignore[$lang][$file])) { + continue; + } + if (!array_key_exists($key, $i18n)) { + $errors[$lang][$file][] = sprintf('Missing key %s', $key); + $report[$lang]['errors'] ++; + continue; + } + if ($i18n[$key] === $value) { + $errors[$lang][$file][] = sprintf('Untranslated key %s - %s', $key, $value); + $report[$lang]['errors'] ++; + continue; + } + } + } +} + +if ($displayErrors) { + foreach ($errors as $lang => $value) { + echo 'Language: ', $lang, PHP_EOL; + foreach ($value as $file => $messages) { + echo ' - File: ', $file, PHP_EOL; + foreach ($messages as $message) { + echo ' - ', $message, PHP_EOL; + } + } + echo PHP_EOL; + } +} + +if ($displayReport) { + foreach ($report as $lang => $value) { + $completion = ($value['total'] - $value['errors']) / $value['total'] * 100; + echo sprintf('Translation for %-5s is %5.1f%% complete.', $lang, $completion), PHP_EOL; + } +} + +if (!empty($errors)) { + exit(1); +} + +/** + * Flatten an array of translation + * + * @param array $translation + * @param string $prependKey + * @return array + */ +function flatten($translation, $prependKey = '') { + $a = array(); + + if ('' !== $prependKey) { + $prependKey .= '.'; + } + + foreach ($translation as $key => $value) { + if (is_array($value)) { + $a += flatten($value, $prependKey . $key); + } else { + $a[$prependKey . $key] = $value; + } + } + + return $a; +} + +/** + * Output help message. + */ +function help() { + $help = << Date: Sun, 1 Oct 2017 21:58:13 +0200 Subject: Changelog 1653 https://github.com/FreshRSS/FreshRSS/pull/1653 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c364a5af..28c16a37a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 2017-1X-XX FreshRSS 1.8.1-dev +* Misc. + * Travis translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) + ## 2017-10-01 FreshRSS 1.8.0 -- cgit v1.2.3 From 9bbec9a1e8035555bec014bc26f7ef178daaf725 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 7 Oct 2017 13:29:08 +0200 Subject: Minor changelog fix --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c16a37a..0b73bc2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ * Fix share menu on small screens [#1645](https://github.com/FreshRSS/FreshRSS/pull/1645) * Go back to previous view when collapsing article [#1177](https://github.com/FreshRSS/FreshRSS/issues/1177) * CLI - * New command `./cli/update-user` to update user settings [#1600](https://github.com/FreshRSS/FreshRSS/issues/1600) + * New command `./cli/update-user.php` to update user settings [#1600](https://github.com/FreshRSS/FreshRSS/issues/1600) * I18n * Korean [#1578](https://github.com/FreshRSS/FreshRSS/pull/1578) * Portuguese (Brazilian) [#1648](https://github.com/FreshRSS/FreshRSS/pull/1648) -- cgit v1.2.3 From 4058ff3ff4631bcc2c9cba534162c80db5cf2b65 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 7 Oct 2017 13:51:45 +0200 Subject: Remove SimplePie name from HTTP User-Agent string https://github.com/FreshRSS/FreshRSS/issues/1622#issuecomment-334928486 https://github.com/FreshRSS/FreshRSS/issues/1627 https://github.com/FreshRSS/FreshRSS/issues/1607 --- CHANGELOG.md | 8 +++++--- app/Models/Feed.php | 2 +- constants.php | 2 ++ lib/favicons.php | 2 +- lib/lib_rss.php | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b73bc2c8..09a644478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,15 @@ ## 2017-1X-XX FreshRSS 1.8.1-dev +* SimplePie + * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Misc. * Travis translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) ## 2017-10-01 FreshRSS 1.8.0 -* Compatibility: +* Compatibility * Minimal PHP version increased to PHP 5.3.8+ to fix sanitize bug [#1604](https://github.com/FreshRSS/FreshRSS/issues/1604) * Add support for PHP 7.1 in the API [#1584](https://github.com/FreshRSS/FreshRSS/issues/1584), [#1594](https://github.com/FreshRSS/FreshRSS/pull/1594) * UI @@ -36,7 +38,7 @@ ## 2017-06-03 FreshRSS 1.7.0 -* Features: +* Features * Deferred insertion of new articles, for better chronological order [#530](https://github.com/FreshRSS/FreshRSS/issues/530) * Better search: * Possibility to use multiple `intitle:`, `inurl:`, `author:` [#1478](https://github.com/FreshRSS/FreshRSS/pull/1478) @@ -44,7 +46,7 @@ * Examples: `!intitle:unwanted`, `-intitle:unwanted`, `-inurl:unwanted`, `-author:unwanted`, `-#unwanted`, `-unwanted` * Allow double-quotes, such as `author:"some name"`, in addition to single-quotes such as `author:'some name'` [#1478](https://github.com/FreshRSS/FreshRSS/pull/1478) * Multi-user tokens (to access RSS outputs of any user) [#1390](https://github.com/FreshRSS/FreshRSS/issues/1390) -* Compatibility: +* Compatibility * Add support for PHP 7.1 [#1471](https://github.com/FreshRSS/FreshRSS/issues/1471) * PostgreSQL is not experimental anymore [#1476](https://github.com/FreshRSS/FreshRSS/pull/1476) * Bug fixing diff --git a/app/Models/Feed.php b/app/Models/Feed.php index d8fe03197..44d518a47 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -484,7 +484,7 @@ class FreshRSS_Feed extends Minz_Model { CURLOPT_URL => $hubJson['hub'], CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, - CURLOPT_USERAGENT => 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')', + CURLOPT_USERAGENT => FRESHRSS_USERAGENT, CURLOPT_POSTFIELDS => http_build_query(array( 'hub.verify' => 'sync', 'hub.mode' => $state ? 'subscribe' : 'unsubscribe', diff --git a/constants.php b/constants.php index 195c7e073..9c647eb74 100644 --- a/constants.php +++ b/constants.php @@ -3,6 +3,8 @@ define('FRESHRSS_VERSION', '1.8.1-dev'); define('FRESHRSS_WEBSITE', 'https://freshrss.org'); define('FRESHRSS_WIKI', 'https://freshrss.github.io/FreshRSS/'); +define('FRESHRSS_USERAGENT', 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')'); + // PHP text output compression http://php.net/ob_gzhandler (better to do it at Web server level) define('PHP_COMPRESSION', false); diff --git a/lib/favicons.php b/lib/favicons.php index a7ed966a1..80246ee74 100644 --- a/lib/favicons.php +++ b/lib/favicons.php @@ -35,7 +35,7 @@ function downloadHttp(&$url, $curlOptions = array()) { CURLOPT_MAXREDIRS => 10, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, - CURLOPT_USERAGENT => 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')', + CURLOPT_USERAGENT => FRESHRSS_USERAGENT, )); if (defined('CURLOPT_ENCODING')) { curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 09048700d..7381ff2bd 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -174,7 +174,7 @@ function customSimplePie() { $system_conf = Minz_Configuration::get('system'); $limits = $system_conf->limits; $simplePie = new SimplePie(); - $simplePie->set_useragent('FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); + $simplePie->set_useragent(FRESHRSS_USERAGENT); $simplePie->set_syslog($system_conf->simplepie_syslog_enabled); $simplePie->set_cache_location(CACHE_PATH); $simplePie->set_cache_duration($limits['cache_duration']); -- cgit v1.2.3 From 1eb19409b5435546774425c00523b9f88d4fccf9 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 8 Oct 2017 17:26:43 +0200 Subject: CURLOPT_FOLLOWLOCATION open_basedir bug (#1657) CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set https://github.com/FreshRSS/FreshRSS/issues/1655#issuecomment-334999448 https://stackoverflow.com/questions/6918623/curlopt-followlocation-cannot-be-activated --- CHANGELOG.md | 2 ++ app/Models/Feed.php | 27 +++++++++++++++------------ lib/favicons.php | 4 ++-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09a644478..4b24cd116 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) +* Bug fixing + * Work-around for `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) * Misc. * Travis translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 44d518a47..85273d3f7 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -481,18 +481,21 @@ class FreshRSS_Feed extends Minz_Model { } $ch = curl_init(); curl_setopt_array($ch, array( - CURLOPT_URL => $hubJson['hub'], - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_USERAGENT => FRESHRSS_USERAGENT, - CURLOPT_POSTFIELDS => http_build_query(array( - 'hub.verify' => 'sync', - 'hub.mode' => $state ? 'subscribe' : 'unsubscribe', - 'hub.topic' => $url, - 'hub.callback' => $callbackUrl, - )) - ) - ); + CURLOPT_URL => $hubJson['hub'], + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POSTFIELDS => http_build_query(array( + 'hub.verify' => 'sync', + 'hub.mode' => $state ? 'subscribe' : 'unsubscribe', + 'hub.topic' => $url, + 'hub.callback' => $callbackUrl, + )), + CURLOPT_USERAGENT => FRESHRSS_USERAGENT, + CURLOPT_MAXREDIRS => 10, + )); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir bug + if (defined('CURLOPT_ENCODING')) { + curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings + } $response = curl_exec($ch); $info = curl_getinfo($ch); diff --git a/lib/favicons.php b/lib/favicons.php index 80246ee74..2d6f7aab7 100644 --- a/lib/favicons.php +++ b/lib/favicons.php @@ -31,12 +31,12 @@ function downloadHttp(&$url, $curlOptions = array()) { } $ch = curl_init($url); curl_setopt_array($ch, array( - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_MAXREDIRS => 10, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, CURLOPT_USERAGENT => FRESHRSS_USERAGENT, + CURLOPT_MAXREDIRS => 10, )); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir bug if (defined('CURLOPT_ENCODING')) { curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings } -- cgit v1.2.3 From e6fc86b4b110966bf11b1d5ac4755a3163f74945 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 9 Oct 2017 21:01:47 +0200 Subject: Add an entry in the subscription tool page I reworked @Alkarex idea proposed in #1292. I though it was a good idea to merge everything in the same location. --- app/i18n/cz/sub.php | 4 ++++ app/i18n/de/sub.php | 4 ++++ app/i18n/en/sub.php | 4 ++++ app/i18n/es/sub.php | 4 ++++ app/i18n/fr/sub.php | 4 ++++ app/i18n/it/sub.php | 4 ++++ app/i18n/kr/sub.php | 4 ++++ app/i18n/nl/sub.php | 4 ++++ app/i18n/pt-br/sub.php | 9 +++++++++ app/i18n/ru/sub.php | 4 ++++ app/i18n/tr/sub.php | 4 ++++ app/i18n/zh-cn/sub.php | 4 ++++ app/views/subscription/bookmarklet.phtml | 4 ++++ 13 files changed, 57 insertions(+) diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php index 09b23d222..807c249d3 100644 --- a/app/i18n/cz/sub.php +++ b/app/i18n/cz/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO 'label' => 'Subscribe',// TODO diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php index c16d09db1..4ffef4302 100644 --- a/app/i18n/de/sub.php +++ b/app/i18n/de/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO 'label' => 'Subscribe',// TODO diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index ca696280a..47b15ae7a 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.', + 'title' => 'API', + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.', 'label' => 'Subscribe', diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php index c18f0b786..72eb06eb7 100755 --- a/app/i18n/es/sub.php +++ b/app/i18n/es/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'category' => array( '_' => 'Categoría', 'add' => 'Añadir a la categoría', diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php index 9135b2b7c..607863c8f 100644 --- a/app/i18n/fr/sub.php +++ b/app/i18n/fr/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copier l’URL suivante dans l’outil qui utilisera l’API.', + 'title' => 'API', + ), 'bookmarklet' => array( 'documentation' => 'Glisser ce bouton dans la barre des favoris ou cliquer droit dessus et choisir "Enregistrer ce lien". Ensuite, cliquer sur le bouton "S’abonner" sur les pages auxquelles vous voulez vous abonner.', 'label' => 'S’abonner', diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php index e730e2bc8..fe18855fb 100644 --- a/app/i18n/it/sub.php +++ b/app/i18n/it/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO 'label' => 'Subscribe',// TODO diff --git a/app/i18n/kr/sub.php b/app/i18n/kr/sub.php index 8af29422d..b8f2385b3 100644 --- a/app/i18n/kr/sub.php +++ b/app/i18n/kr/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => '이 버튼을 즐겨찾기 막대로 끌어다 놓거나 마우스 오른쪽 클릭으로 나타나는 메뉴에서 "이 링크를 즐겨찾기에 추가"를 선택하세요. 그리고 피드를 구독하길 원하는 페이지에서 "구독하기" 버튼을 클릭하세요.', 'label' => '구독하기', diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index bfa0911b7..ae84c37eb 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO 'label' => 'Subscribe',// TODO diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php index 61a80d41e..4249dcabf 100644 --- a/app/i18n/pt-br/sub.php +++ b/app/i18n/pt-br/sub.php @@ -1,6 +1,15 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), + 'bookmarklet' => array( + 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO + 'label' => 'Subscribe',// TODO + 'title' => 'Bookmarklet',// TODO + ), 'category' => array( '_' => 'Categoria', 'add' => 'Adicionar uma categoria', diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php index fa28a3ec4..6a5530de0 100644 --- a/app/i18n/ru/sub.php +++ b/app/i18n/ru/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO 'label' => 'Subscribe',// TODO diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php index e928fae72..0bbaeec5b 100644 --- a/app/i18n/tr/sub.php +++ b/app/i18n/tr/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO 'label' => 'Subscribe',// TODO diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php index 159bcd919..48057e74c 100644 --- a/app/i18n/zh-cn/sub.php +++ b/app/i18n/zh-cn/sub.php @@ -1,6 +1,10 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO + 'title' => 'API',// TODO + ), 'bookmarklet' => array( 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO 'label' => 'Subscribe',// TODO diff --git a/app/views/subscription/bookmarklet.phtml b/app/views/subscription/bookmarklet.phtml index 162501be6..76ac700e0 100644 --- a/app/views/subscription/bookmarklet.phtml +++ b/app/views/subscription/bookmarklet.phtml @@ -10,4 +10,8 @@

browser.contentHandlers.types.number.uri →  'feed', 'a' => 'add'), 'html', true); ?>&url_rss=%s
+ + +

+
 'feed', 'a' => 'add'), 'html', true); ?>&url_rss=%s
\ No newline at end of file -- cgit v1.2.3 From ac60e35f6a6849f2dc13b3644d94fae59d83db77 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 8 Oct 2017 19:05:19 +0200 Subject: Improve translation tools I was not happy with the previous version. I refactored everything to make it reusable. It allows me do do more verifications and to build a tool to handle the files themselves. --- CHANGELOG.md | 3 +- app/layout/nav_menu.phtml | 6 +- app/views/configure/system.phtml | 2 +- tools/I18nCompletionValidator.php | 49 ++++++++++++++++ tools/I18nData.php | 118 ++++++++++++++++++++++++++++++++++++++ tools/I18nFile.php | 92 +++++++++++++++++++++++++++++ tools/I18nUsageValidator.php | 47 +++++++++++++++ tools/I18nValidatorInterface.php | 26 +++++++++ tools/check.translation.php | 111 +++++++++++++++-------------------- tools/ignore/en.php | 105 +++++++++++++++++++++++++++++++++ tools/ignore/fr.php | 55 ++++++++++++++++++ tools/manipulate.translation.php | 79 +++++++++++++++++++++++++ tools/translation.ignore.php | 58 ------------------- 13 files changed, 622 insertions(+), 129 deletions(-) create mode 100644 tools/I18nCompletionValidator.php create mode 100644 tools/I18nData.php create mode 100644 tools/I18nFile.php create mode 100644 tools/I18nUsageValidator.php create mode 100644 tools/I18nValidatorInterface.php create mode 100644 tools/ignore/en.php create mode 100644 tools/ignore/fr.php create mode 100644 tools/manipulate.translation.php delete mode 100644 tools/translation.ignore.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c16a37a..43c582919 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## 2017-1X-XX FreshRSS 1.8.1-dev * Misc. - * Travis translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) + * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) + * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) ## 2017-10-01 FreshRSS 1.8.0 diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 04ee03cd6..2bc693e5d 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -186,16 +186,16 @@ if (FreshRSS_Context::$order === 'DESC') { $order = 'ASC'; $icon = 'up'; - $title = 'index.menu.older_first'; + $title = _t('index.menu.older_first'); } else { $order = 'DESC'; $icon = 'down'; - $title = 'index.menu.newer_first'; + $title = _t('index.menu.newer_first'); } $url_order = Minz_Request::currentRequest(); $url_order['params']['order'] = $order; ?> - + diff --git a/app/views/configure/system.phtml b/app/views/configure/system.phtml index 935b49fda..37b68c991 100644 --- a/app/views/configure/system.phtml +++ b/app/views/configure/system.phtml @@ -33,7 +33,7 @@
1 ? 'admin.user.numbers' : 'admin.user.number', $number); + echo ($number > 1 ? _t('admin.user.numbers', $number) : _t('admin.user.number', $number)); ?>
diff --git a/tools/I18nCompletionValidator.php b/tools/I18nCompletionValidator.php new file mode 100644 index 000000000..2cb71acd5 --- /dev/null +++ b/tools/I18nCompletionValidator.php @@ -0,0 +1,49 @@ +reference = $reference; + $this->language = $language; + } + + public function displayReport() { + return sprintf('Translation is %5.1f%% complete.', $this->passEntries / $this->totalEntries * 100) . PHP_EOL; + } + + public function displayResult() { + return $this->result; + } + + public function validate($ignore) { + foreach ($this->reference as $file => $data) { + foreach ($data as $key => $value) { + $this->totalEntries++; + if (is_array($ignore) && in_array($key, $ignore)) { + $this->passEntries++; + continue; + } + if (!array_key_exists($key, $this->language[$file])) { + $this->result .= sprintf('Missing key %s', $key) . PHP_EOL; + continue; + } + if ($value === $this->language[$file][$key]) { + $this->result .= sprintf('Untranslated key %s - %s', $key, $value) . PHP_EOL; + continue; + } + $this->passEntries++; + } + } + + return $this->totalEntries === $this->passEntries; + } + +} diff --git a/tools/I18nData.php b/tools/I18nData.php new file mode 100644 index 000000000..cd8ba0765 --- /dev/null +++ b/tools/I18nData.php @@ -0,0 +1,118 @@ +data = $data; + $this->originalData = $data; + } + + public function getData() { + return $this->data; + } + + /** + * Return the available languages + * + * @return array + */ + public function getAvailableLanguages() { + $languages = array_keys($this->data); + sort($languages); + + return $languages; + } + + /** + * Add a new language. It's a copy of the reference language. + * + * @param string $language + */ + public function addLanguage($language) { + if (array_key_exists($language, $this->data)) { + throw new Exception('The selected language already exist.'); + } + $this->data[$language] = $this->data[static::REFERENCE_LANGUAGE]; + } + + /** + * Add a key in the reference language + * + * @param string $key + * @param string $value + */ + public function addKey($key, $value) { + if (array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { + throw new Exception('The selected key already exist.'); + } + $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key] = $value; + } + + /** + * Duplicate a key from the reference language to all other languages + * + * @param string $key + */ + public function duplicateKey($key) { + if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { + throw new Exception('The selected key does not exist.'); + } + $value = $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key]; + foreach ($this->getAvailableLanguages() as $language) { + if (static::REFERENCE_LANGUAGE === $language) { + continue; + } + if (array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) { + throw new Exception(sprintf('The selected key already exist in %s.', $language)); + } + $this->data[$language][$this->getFilenamePrefix($key)][$key] = $value; + } + } + + /** + * Remove a key in all languages + * + * @param string $key + */ + public function removeKey($key) { + if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { + throw new Exception('The selected key does not exist.'); + } + foreach ($this->getAvailableLanguages() as $language) { + if (array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) { + unset($this->data[$language][$this->getFilenamePrefix($key)][$key]); + } + } + } + + /** + * Check if the data has changed + * + * @return bool + */ + public function hasChanged() { + return $this->data !== $this->originalData; + } + + public function getLanguage($language) { + return $this->data[$language]; + } + + public function getReferenceLanguage() { + return $this->getLanguage(static::REFERENCE_LANGUAGE); + } + + /** + * @param string $key + * @return string + */ + private function getFilenamePrefix($key) { + return preg_replace('/\..*/', '.php', $key); + } + +} diff --git a/tools/I18nFile.php b/tools/I18nFile.php new file mode 100644 index 000000000..d8c16a6eb --- /dev/null +++ b/tools/I18nFile.php @@ -0,0 +1,92 @@ +i18nPath = __DIR__ . '/../app/i18n'; + } + + public function load() { + $dirs = new DirectoryIterator($this->i18nPath); + foreach ($dirs as $dir) { + if ($dir->isDot()) { + continue; + } + $files = new DirectoryIterator($dir->getPathname()); + foreach ($files as $file) { + if (!$file->isFile()) { + continue; + } + $i18n[$dir->getFilename()][$file->getFilename()] = $this->flatten(include $file->getPathname(), $file->getBasename('.php')); + } + } + + return new I18nData($i18n); + } + + public function dump(I18nData $i18n) { + foreach ($i18n->getData() as $language => $file) { + $dir = $this->i18nPath . DIRECTORY_SEPARATOR . $language; + if (!file_exists($dir)) { + mkdir($dir); + } + foreach ($file as $name => $content) { + $filename = $dir . DIRECTORY_SEPARATOR . $name; + $fullContent = var_export($this->unflatten($content), true); + file_put_contents($filename, sprintf(' $value) { + if (is_array($value)) { + $a += $this->flatten($value, $prefix . $key); + } else { + $a[$prefix . $key] = $value; + } + } + + return $a; + } + + /** + * Unflatten an array of translation + * + * The first key is dropped since it represents the filename and we have + * no use of it. + * + * @param array $translation + * @return array + */ + private function unflatten($translation) { + $a = array(); + + ksort($translation); + foreach ($translation as $compoundKey => $value) { + $keys = explode('.', $compoundKey); + array_shift($keys); + eval("\$a['" . implode("']['", $keys) . "'] = '" . $value . "';"); + } + + return $a; + } + +} diff --git a/tools/I18nUsageValidator.php b/tools/I18nUsageValidator.php new file mode 100644 index 000000000..8ab934971 --- /dev/null +++ b/tools/I18nUsageValidator.php @@ -0,0 +1,47 @@ +code = $code; + $this->reference = $reference; + } + + public function displayReport() { + return sprintf('%5.1f%% of translation keys are unused.', $this->failedEntries / $this->totalEntries * 100) . PHP_EOL; + } + + public function displayResult() { + return $this->result; + } + + public function validate($ignore) { + foreach ($this->reference as $file => $data) { + foreach ($data as $key => $value) { + $this->totalEntries++; + if (preg_match('/\._$/', $key) && in_array(preg_replace('/\._$/', '', $key), $this->code)) { + continue; + } + if (is_array($ignore) && in_array($key, $ignore)) { + continue; + } + if (!in_array($key, $this->code)) { + $this->result .= sprintf('Unused key %s - %s', $key, $value) . PHP_EOL; + $this->failedEntries++; + continue; + } + } + } + + return 0 === $this->failedEntries; + } + +} diff --git a/tools/I18nValidatorInterface.php b/tools/I18nValidatorInterface.php new file mode 100644 index 000000000..edfe7aac0 --- /dev/null +++ b/tools/I18nValidatorInterface.php @@ -0,0 +1,26 @@ +load(); -$ignore = include __DIR__ . '/translation.ignore.php'; +$options = getopt("dhl:r"); if (array_key_exists('h', $options)) { help(); } if (array_key_exists('l', $options)) { - $langPattern = sprintf('/%s/', $options['l']); + $languages = array($options['l']); } else { - $langPattern = '/*/'; + $languages = $i18nData->getAvailableLanguages(); } -$displayErrors = array_key_exists('d', $options); +$displayResults = array_key_exists('d', $options); $displayReport = array_key_exists('r', $options); -$i18nPath = __DIR__ . '/../app/i18n/'; -$errors = array(); +$isValidated = true; +$result = array(); $report = array(); -foreach (glob($i18nPath . 'en/*.php') as $i18nFileReference) { - $en = flatten(include $i18nFileReference); - foreach (glob(str_replace('/en/', $langPattern, $i18nFileReference)) as $i18nFile) { - preg_match('#(?P[^/]+)/(?P[^/]*.php)#', $i18nFile, $matches); - $lang = $matches['lang']; - $file = $matches['file']; - if ('en' === $lang) { - continue; - } - if (!array_key_exists($lang, $report)) { - $report[$lang]['total'] = 0; - $report[$lang]['errors'] = 0; - } - $i18n = flatten(include $i18nFile); - foreach ($en as $key => $value) { - $report[$lang]['total'] ++; - if (array_key_exists($lang, $ignore) && array_key_exists($file, $ignore[$lang]) && in_array($key, $ignore[$lang][$file])) { - continue; - } - if (!array_key_exists($key, $i18n)) { - $errors[$lang][$file][] = sprintf('Missing key %s', $key); - $report[$lang]['errors'] ++; - continue; - } - if ($i18n[$key] === $value) { - $errors[$lang][$file][] = sprintf('Untranslated key %s - %s', $key, $value); - $report[$lang]['errors'] ++; - continue; - } +foreach ($languages as $language) { + if ($language === $i18nData::REFERENCE_LANGUAGE) { + $i18nValidator = new I18nUsageValidator($i18nData->getReferenceLanguage(), findUsedTranslations()); + $isValidated = $i18nValidator->validate(include __DIR__ . '/ignore/' . $language . '.php') && $isValidated; + } else { + $i18nValidator = new I18nCompletionValidator($i18nData->getReferenceLanguage(), $i18nData->getLanguage($language)); + if (file_exists(__DIR__ . '/ignore/' . $language . '.php')) { + $isValidated = $i18nValidator->validate(include __DIR__ . '/ignore/' . $language . '.php') && $isValidated; + } else { + $isValidated = $i18nValidator->validate(null) && $isValidated; } } + + $report[$language] = sprintf('%-5s - %s', $language, $i18nValidator->displayReport()); + $result[$language] = $i18nValidator->displayResult(); } -if ($displayErrors) { - foreach ($errors as $lang => $value) { +if ($displayResults) { + foreach ($result as $lang => $value) { echo 'Language: ', $lang, PHP_EOL; - foreach ($value as $file => $messages) { - echo ' - File: ', $file, PHP_EOL; - foreach ($messages as $message) { - echo ' - ', $message, PHP_EOL; - } - } + print_r($value); echo PHP_EOL; } } if ($displayReport) { - foreach ($report as $lang => $value) { - $completion = ($value['total'] - $value['errors']) / $value['total'] * 100; - echo sprintf('Translation for %-5s is %5.1f%% complete.', $lang, $completion), PHP_EOL; + foreach ($report as $value) { + echo $value; } } -if (!empty($errors)) { +if (!$isValidated) { exit(1); } /** - * Flatten an array of translation + * Find used translation keys in the project + * + * Iterates through all php and phtml files in the whole project and extracts all + * translation keys used. * - * @param array $translation - * @param string $prependKey * @return array */ -function flatten($translation, $prependKey = '') { - $a = array(); - - if ('' !== $prependKey) { - $prependKey .= '.'; +function findUsedTranslations() { + $directory = new RecursiveDirectoryIterator(__DIR__ . '/..'); + $iterator = new RecursiveIteratorIterator($directory); + $regex = new RegexIterator($iterator, '/^.+\.(php|phtml)$/i', RecursiveRegexIterator::GET_MATCH); + $usedI18n = array(); + foreach (array_keys(iterator_to_array($regex)) as $file) { + $fileContent = file_get_contents($file); + preg_match_all('/_t\([\'"](?P[^\'"]+)[\'"]/', $fileContent, $matches); + $usedI18n = array_merge($usedI18n, $matches['strings']); } - - foreach ($translation as $key => $value) { - if (is_array($value)) { - $a += flatten($value, $prependKey . $key); - } else { - $a[$prependKey . $key] = $value; - } - } - - return $a; + return $usedI18n; } /** diff --git a/tools/ignore/en.php b/tools/ignore/en.php new file mode 100644 index 000000000..e231afdda --- /dev/null +++ b/tools/ignore/en.php @@ -0,0 +1,105 @@ +load(); + +switch ($argv[1]) { + case 'add_language' : + $i18nData->addLanguage($argv[2]); + break; + case 'add_key' : + if (3 === $argc) { + help(); + } + $i18nData->addKey($argv[2], $argv[3]); + break; + case 'duplicate_key' : + $i18nData->duplicateKey($argv[2]); + break; + case 'delete_key' : + $i18nData->removeKey($argv[2]); + break; + default : + help(); +} + +if ($i18nData->hasChanged()) { + $i18nFile->dump($i18nData); +} + +/** + * Output help message. + */ +function help() { + $help = << Date: Tue, 10 Oct 2017 20:57:19 +0200 Subject: Changelog 1247 https://github.com/FreshRSS/FreshRSS/pull/1660 https://github.com/FreshRSS/FreshRSS/pull/1292 https://github.com/FreshRSS/FreshRSS/issues/1247 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38f4c4cff..9d5d1a78e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## 2017-1X-XX FreshRSS 1.8.1-dev +* UI + Show API subscription URL [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing -- cgit v1.2.3 From 02c5ffa1e06bf7f7863765a63ad0368ada1d2f73 Mon Sep 17 00:00:00 2001 From: Frans de Jonge Date: Tue, 10 Oct 2017 21:21:12 +0200 Subject: [i18] nl/sub: add a few translations --- app/i18n/nl/sub.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index ae84c37eb..15c1c9a0d 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -2,13 +2,13 @@ /* Dutch translation by Wanabo. http://www.nieuwskop.be */ return array( 'api' => array( - 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO - 'title' => 'API',// TODO + 'documentation' => 'Kopieer de volgende URL om hem in een externe toepassing te gebruiken.' + 'title' => 'API', ), 'bookmarklet' => array( - 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO - 'label' => 'Subscribe',// TODO - 'title' => 'Bookmarklet',// TODO + 'documentation' => 'Sleep deze knop naar je bladwijzerwerkbalk of klik erop met de rechtermuisknop en kies "Deze link aan bladwijzers toevoegen."', + 'label' => 'Abonneren', + 'title' => 'Bookmarklet', ), 'category' => array( '_' => 'Categorie', @@ -49,8 +49,8 @@ return array( 'website' => 'Website URL', ), 'firefox' => array( - 'documentation' => 'Follow the steps described here to add FreshRSS to Firefox feed reader list.',// TODO - 'title' => 'Firefox feed reader',// TODO + 'documentation' => 'Volg de stappen die hier beschreven wordem om FreshRSS aan de Firefox-nieuwslezerlijst toe te voegen.', + 'title' => 'Firefox-nieuwslezer', ), 'import_export' => array( 'export' => 'Exporteer', -- cgit v1.2.3 From 6cebd7197f1300e4da101aad4b8d78948c77aa09 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 11 Oct 2017 20:38:51 +0200 Subject: Reworded changelog 1247 https://github.com/FreshRSS/FreshRSS/pull/1660 https://github.com/FreshRSS/FreshRSS/pull/1292 https://github.com/FreshRSS/FreshRSS/issues/1247 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d5d1a78e..051b04a3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 2017-1X-XX FreshRSS 1.8.1-dev * UI - Show API subscription URL [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) + Show URL to add subscriptions from third-party tools [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing -- cgit v1.2.3 From f632a346269100d6a93bef318ffa66c97f16f6fa Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 12 Oct 2017 20:11:06 +0200 Subject: CLI optimize database (#1663) CLI optimize database https://github.com/FreshRSS/FreshRSS/issues/1583 And VACUUM in SQLite https://github.com/FreshRSS/FreshRSS/issues/918 Add VACUUM for PostgreSQL (Not tested yet) --- CHANGELOG.md | 4 ++++ app/Controllers/configureController.php | 6 +++-- app/Controllers/entryController.php | 4 ++-- app/Controllers/userController.php | 4 +++- app/Models/DatabaseDAO.php | 41 +++++++++++++++++++++++++++++++++ app/Models/DatabaseDAOPGSQL.php | 37 +++++++++++++++++++++++++++++ app/Models/DatabaseDAOSQLite.php | 13 +++++++++++ app/Models/EntryDAO.php | 22 ------------------ app/Models/EntryDAOPGSQL.php | 11 --------- app/Models/EntryDAOSQLite.php | 8 ------- cli/README.md | 3 +++ cli/db-optimize.php | 20 ++++++++++++++++ cli/user-info.php | 5 ++-- 13 files changed, 130 insertions(+), 48 deletions(-) create mode 100755 cli/db-optimize.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 051b04a3e..97fcdcbed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing * Work-around for `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) +* CLI + * New command `./cli/db-optimize.php` for database optimisation [#1583](https://github.com/FreshRSS/FreshRSS/issues/1583) +* SQL + * Perform `VACUUM` on SQLite and PostgreSQL databases when optimisation is requested [#918](https://github.com/FreshRSS/FreshRSS/issues/918) * Misc. * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 155221d19..9d2ee450c 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -225,10 +225,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $entryDAO = FreshRSS_Factory::createEntryDao(); $this->view->nb_total = $entryDAO->count(); - $this->view->size_user = $entryDAO->size(); + + $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); + $this->view->size_user = $databaseDAO->size(); if (FreshRSS_Auth::hasAccess('admin')) { - $this->view->size_total = $entryDAO->size(true); + $this->view->size_total = $databaseDAO->size(true); } } diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index c40588105..bd8b65b2b 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -147,8 +147,8 @@ class FreshRSS_entry_Controller extends Minz_ActionController { @set_time_limit(300); - $entryDAO = FreshRSS_Factory::createEntryDao(); - $entryDAO->optimizeTable(); + $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); + $databaseDAO->optimize(); $feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO->updateCachedValues(); diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index a58501186..2a1d43d9e 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -120,7 +120,9 @@ class FreshRSS_user_Controller extends Minz_ActionController { // Get information about the current user. $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); $this->view->nb_articles = $entryDAO->count(); - $this->view->size_user = $entryDAO->size(); + + $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); + $this->view->size_user = $databaseDAO->size(); } public static function createUser($new_user_name, $passwordPlain, $apiPasswordPlain, $userConfig = array(), $insertDefaultFeeds = true) { diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php index 6ba5bca3e..f5469f2b7 100644 --- a/app/Models/DatabaseDAO.php +++ b/app/Models/DatabaseDAO.php @@ -80,4 +80,45 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo { return $list; } + + public function size($all = false) { + $db = FreshRSS_Context::$system_conf->db; + $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema=?'; //MySQL + $values = array($db['base']); + if (!$all) { + $sql .= ' AND table_name LIKE ?'; + $values[] = $this->prefix . '%'; + } + $stm = $this->bd->prepare($sql); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return $res[0]; + } + + public function optimize() { + $ok = true; + + $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'entry`'; //MySQL + $stm = $this->bd->prepare($sql); + $ok &= $stm != false; + if ($stm) { + $ok &= $stm->execute(); + } + + $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'feed`'; //MySQL + $stm = $this->bd->prepare($sql); + $ok &= $stm != false; + if ($stm) { + $ok &= $stm->execute(); + } + + $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'category`'; //MySQL + $stm = $this->bd->prepare($sql); + $ok &= $stm != false; + if ($stm) { + $ok &= $stm->execute(); + } + + return $ok; + } } diff --git a/app/Models/DatabaseDAOPGSQL.php b/app/Models/DatabaseDAOPGSQL.php index 2a18db970..1b3f7408d 100644 --- a/app/Models/DatabaseDAOPGSQL.php +++ b/app/Models/DatabaseDAOPGSQL.php @@ -40,4 +40,41 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAO { 'default' => $dao['default'], ); } + + public function size($all = true) { + $db = FreshRSS_Context::$system_conf->db; + $sql = 'SELECT pg_size_pretty(pg_database_size(?))'; + $values = array($db['base']); + $stm = $this->bd->prepare($sql); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return $res[0]; + } + + public function optimize() { + $ok = true; + + $sql = 'VACUUM `' . $this->prefix . 'entry`'; + $stm = $this->bd->prepare($sql); + $ok &= $stm != false; + if ($stm) { + $ok &= $stm->execute(); + } + + $sql = 'VACUUM `' . $this->prefix . 'feed`'; + $stm = $this->bd->prepare($sql); + $ok &= $stm != false; + if ($stm) { + $ok &= $stm->execute(); + } + + $sql = 'VACUUM `' . $this->prefix . 'category`'; + $stm = $this->bd->prepare($sql); + $ok &= $stm != false; + if ($stm) { + $ok &= $stm->execute(); + } + + return $ok; + } } diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php index 2e1df132e..d3aedb3c0 100644 --- a/app/Models/DatabaseDAOSQLite.php +++ b/app/Models/DatabaseDAOSQLite.php @@ -45,4 +45,17 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO { 'default' => $dao['dflt_value'], ); } + + public function size($all = false) { + return @filesize(join_path(DATA_PATH, 'users', $this->current_user, 'db.sqlite')); + } + + public function optimize() { + $sql = 'VACUUM'; + $stm = $this->bd->prepare($sql); + if ($stm) { + return $stm->execute(); + } + return false; + } } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index bebafe500..e8b6dcdae 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -885,28 +885,6 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread); } - public function optimizeTable() { - $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'entry`'; //MySQL - $stm = $this->bd->prepare($sql); - if ($stm) { - return $stm->execute(); - } - } - - public function size($all = false) { - $db = FreshRSS_Context::$system_conf->db; - $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema=?'; //MySQL - $values = array($db['base']); - if (!$all) { - $sql .= ' AND table_name LIKE ?'; - $values[] = $this->prefix . '%'; - } - $stm = $this->bd->prepare($sql); - $stm->execute($values); - $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); - return $res[0]; - } - public static function daoToEntry($dao) { $entry = new FreshRSS_Entry( $dao['id_feed'], diff --git a/app/Models/EntryDAOPGSQL.php b/app/Models/EntryDAOPGSQL.php index 405774abf..f09fe8e75 100644 --- a/app/Models/EntryDAOPGSQL.php +++ b/app/Models/EntryDAOPGSQL.php @@ -46,15 +46,4 @@ END $$;'; } return $result; } - - public function size($all = true) { - $db = FreshRSS_Context::$system_conf->db; - $sql = 'SELECT pg_size_pretty(pg_database_size(?))'; - $values = array($db['base']); - $stm = $this->bd->prepare($sql); - $stm->execute($values); - $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); - return $res[0]; - } - } diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 8dad54322..0f57dc1ba 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -261,12 +261,4 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } return $affected; } - - public function optimizeTable() { - //TODO: Search for an equivalent in SQLite - } - - public function size($all = false) { - return @filesize(join_path(DATA_PATH, 'users', $this->current_user, 'db.sqlite')); - } } diff --git a/cli/README.md b/cli/README.md index ce1be10a7..6f907566c 100644 --- a/cli/README.md +++ b/cli/README.md @@ -69,6 +69,9 @@ cd /usr/share/FreshRSS # Returns: 1) a * iff the user is admin, 2) the name of the user, # 3) the date/time of last user action, 4) the size occupied, # and the number of: 5) categories, 6) feeds, 7) read articles, 8) unread articles, and 9) favourites + +./cli/db-optimize.php --user username +# Optimize database (reduces the size) for a given user (perform `OPTIMIZE TABLE` in MySQL, `VACUUM` in SQLite) ``` diff --git a/cli/db-optimize.php b/cli/db-optimize.php new file mode 100755 index 000000000..83123a669 --- /dev/null +++ b/cli/db-optimize.php @@ -0,0 +1,20 @@ +#!/usr/bin/php +optimize(); + +done($ok); diff --git a/cli/user-info.php b/cli/user-info.php index aa3e239b8..41b95cbf3 100755 --- a/cli/user-info.php +++ b/cli/user-info.php @@ -19,6 +19,7 @@ foreach ($users as $username) { $catDAO = new FreshRSS_CategoryDAO(); $feedDAO = FreshRSS_Factory::createFeedDao($username); $entryDAO = FreshRSS_Factory::createEntryDao($username); + $databaseDAO = FreshRSS_Factory::createDatabaseDAO($username); $nbEntries = $entryDAO->countUnreadRead(); $nbFavorites = $entryDAO->countUnreadReadFavorites(); @@ -27,7 +28,7 @@ foreach ($users as $username) { echo $username, "\t", date('c', FreshRSS_UserDAO::mtime($username)), "\t", - format_bytes($entryDAO->size()), "\t", + format_bytes($databaseDAO->size()), "\t", $catDAO->count(), " categories\t", count($feedDAO->listFeedsIds()), " feeds\t", $nbEntries['read'], " reads\t", @@ -38,7 +39,7 @@ foreach ($users as $username) { echo $username, "\t", FreshRSS_UserDAO::mtime($username), "\t", - $entryDAO->size(), "\t", + $databaseDAO->size(), "\t", $catDAO->count(), "\t", count($feedDAO->listFeedsIds()), "\t", $nbEntries['read'], "\t", -- cgit v1.2.3 From 920f886c55ef6cc241fac0e70127c9fe183a229c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 14 Oct 2017 14:16:59 +0200 Subject: A bit of Apache documentation (#1670) https://github.com/FreshRSS/FreshRSS/issues/1666 https://github.com/FreshRSS/FreshRSS/issues/1669 https://github.com/FreshRSS/FreshRSS/issues/908 --- README.fr.md | 5 +- README.md | 5 +- docs/en/users/01_Installation.md | 119 ++++++++++++++++++++++----------------- docs/fr/users/01_Installation.md | 117 +++++++++++++++++++++++++------------- 4 files changed, 150 insertions(+), 96 deletions(-) diff --git a/README.fr.md b/README.fr.md index 8f19b280a..797d43504 100644 --- a/README.fr.md +++ b/README.fr.md @@ -44,7 +44,7 @@ Nous sommes une communauté amicale. # Documentation * https://freshrss.github.io/FreshRSS/fr/ -# Installation +# [Installation](https://freshrss.github.io/FreshRSS/fr/users/01_Installation.html) 1. Récupérez l’application FreshRSS via la commande git ou [en téléchargeant l’archive](../releases) 2. Placez l’application sur votre serveur (la partie à exposer au Web est le répertoire `./p/`) 3. Le serveur Web doit avoir les droits d’écriture dans le répertoire `./data/` @@ -52,6 +52,7 @@ Nous sommes une communauté amicale. * ou utilisez [l’interface en ligne de commande](./cli/README.md) 5. Tout devrait fonctionner :) En cas de problème, n’hésitez pas à [nous contacter](https://github.com/FreshRSS/FreshRSS/issues). 6. Des paramètres de configuration avancée peuvent être vues dans [config.default.php](./config.default.php) et modifiées dans `data/config.php`. +7. Avec Apache, activer [`AllowEncodedSlashes`](http://httpd.apache.org/docs/trunk/mod/core.html#allowencodedslashes) pour une meilleure compatibilité avec les clients mobiles. ## Installation automatisée * [![DP deploy](https://raw.githubusercontent.com/DFabric/DPlatform-ShellCore/gh-pages/img/deploy.png)](https://dfabric.github.io/DPlatform-ShellCore) @@ -171,7 +172,7 @@ Voir le [dépôt dédié à ces extensions](https://github.com/FreshRSS/Extensio * [password_compat](https://github.com/ircmaxell/password_compat) -# Clients compatibles +# [Clients compatibles](https://freshrss.github.io/FreshRSS/en/users/06_Mobile_access.html) Tout client supportant une API de type Google Reader. Sélection : * Android diff --git a/README.md b/README.md index 14ca65a51..e59d553cf 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ We are a friendly community. # Documentation * https://freshrss.github.io/FreshRSS/en/ -# Installation +# [Installation](https://freshrss.github.io/FreshRSS/en/users/01_Installation.html) 1. Get FreshRSS with git or [by downloading the archive](https://github.com/FreshRSS/FreshRSS/archive/master.zip) 2. Dump the application on your server (expose only the `./p/` folder) 3. Add write access on `./data/` folder to the webserver user @@ -54,6 +54,7 @@ We are a friendly community. * or use the [Command-Line Interface](./cli/README.md) 5. Everything should be working :) If you encounter any problem, feel free [contact us](https://github.com/FreshRSS/FreshRSS/issues). 6. Advanced configuration settings can be seen in [config.default.php](./config.default.php) and modified in `data/config.php`. +7. When using Apache, enable [`AllowEncodedSlashes`](http://httpd.apache.org/docs/trunk/mod/core.html#allowencodedslashes) for better compatibility with mobile clients. ## Automated install * [![Install on Cloudron](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=org.freshrss.cloudronapp) @@ -175,7 +176,7 @@ See the [repository dedicated to those extensions](https://github.com/FreshRSS/E * [password_compat](https://github.com/ircmaxell/password_compat) -# Compatible clients +# [Compatible clients](https://freshrss.github.io/FreshRSS/en/users/06_Mobile_access.html) Any client supporting a Google Reader-like API. Selection: * Android diff --git a/docs/en/users/01_Installation.md b/docs/en/users/01_Installation.md index b2a717629..d0046eebe 100644 --- a/docs/en/users/01_Installation.md +++ b/docs/en/users/01_Installation.md @@ -10,7 +10,7 @@ You need to verify that your server can run FreshRSS before installing it. If yo | PHP | **PHP 5.5+** | PHP 5.3.8+ | | PHP modules | Required: libxml, cURL, PDO_MySQL, PCRE and ctype. \\ Required (32-bit only): GMP \\Recommanded: JSON, Zlib, mbstring, iconv, ZipArchive | | | Database | **MySQL 5.0.3+** | SQLite 3.7.4+ | -| Browser | **Firefox** | Chrome, Opera, Safari or IE9+ | +| Browser | **Firefox** | Chrome, Opera, Safari, or IE11+ | ## Important notice @@ -39,31 +39,44 @@ This is an example Apache virtual hosts configuration file. It covers http and h ``` - ServerName example.com - DocumentRoot /path/to/FreshRSS + DocumentRoot /var/www/html/ - ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log - CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined + #Default site... - RewriteEngine on - RewriteCond %{SERVER_NAME} = example.com - RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent] + ErrorLog ${APACHE_LOG_DIR}/error.default.log + CustomLog ${APACHE_LOG_DIR}/access.default.log vhost_combined + + + + ServerName rss.example.net + DocumentRoot /path/to/FreshRSS/p/ + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log + CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined + + AllowEncodedSlashes On - - ServerName example.com - DocumentRoot /path/to/FreshRSS + + ServerName rss.example.net + DocumentRoot /path/to/FreshRSS/p/ - ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log - CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log + CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined - SSLCertificateFile /path/to/server.crt - SSLCertificateKeyFile /path/to/server.key + + Protocols h2 http/1.1 + - # Optional letsencrypt config (uncomment) line below - #Include /etc/letsencrypt/options-ssl-apache.conf - + AllowEncodedSlashes On + + SSLEngine on + SSLCompression off + SSLCertificateFile /path/to/server.crt + SSLCertificateKeyFile /path/to/server.key + # Additional SSL configuration, e.g. with LetsEncrypt + ``` @@ -75,41 +88,41 @@ _You can find simpler config file but they may be incompatible with FreshRSS API ``` server { - listen 80; # http on port 80 - listen 443 ssl; # https on port 443 - - # https configuration - ssl on; - ssl_certificate /etc/nginx/server.crt; - ssl_certificate_key /etc/nginx/server.key; - - # your server's url(s) - server_name example.com rss.example.com; - - # the folder p of your FreshRSS installation - root /srv/FreshRSS/p/; - - index index.php index.html index.htm; - - # nginx log files - access_log /var/log/nginx/rss.access.log; - error_log /var/log/nginx/rss.error.log; - - # php files handling - # this regex is mandatory because of the API - location ~ ^.+?\.php(/.*)?$ { - fastcgi_pass unix:/var/run/php5-fpm.sock; - fastcgi_split_path_info ^(.+\.php)(/.*)$; - # By default, the variable PATH_INFO is not set under PHP-FPM - # But FreshRSS API greader.php need it. If you have a "Bad Request" error, double check this var ! - fastcgi_param PATH_INFO $fastcgi_path_info; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - } - - location / { - try_files $uri $uri/ index.php; - } + listen 80; + listen 443 ssl; + + # https configuration + ssl on; + ssl_certificate /etc/nginx/server.crt; + ssl_certificate_key /etc/nginx/server.key; + + # your server's url(s) + server_name rss.example.net; + + # the folder p of your FreshRSS installation + root /srv/FreshRSS/p/; + + index index.php index.html index.htm; + + # nginx log files + access_log /var/log/nginx/rss.access.log; + error_log /var/log/nginx/rss.error.log; + + # php files handling + # this regex is mandatory because of the API + location ~ ^.+?\.php(/.*)?$ { + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + # By default, the variable PATH_INFO is not set under PHP-FPM + # But FreshRSS API greader.php need it. If you have a "Bad Request" error, double check this var ! + fastcgi_param PATH_INFO $fastcgi_path_info; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } + + location / { + try_files $uri $uri/ index.php; + } } ``` diff --git a/docs/fr/users/01_Installation.md b/docs/fr/users/01_Installation.md index 765cb9481..03cdbdd88 100644 --- a/docs/fr/users/01_Installation.md +++ b/docs/fr/users/01_Installation.md @@ -10,7 +10,7 @@ Il est toutefois de votre responsabilité de vérifier que votre hébergement pe | PHP | **PHP 5.5+** | PHP 5.3.8+ | | Modules PHP | Requis : libxml, cURL, PDO_MySQL, PCRE et ctype \\ Requis (32 bits seulement) : GMP \\ Recommandé : JSON, Zlib, mbstring et iconv, ZipArchive | | | Base de données | **MySQL 5.0.3+** | SQLite 3.7.4+ | - | Navigateur | **Firefox** | Chrome, Opera, Safari or IE 9+ | + | Navigateur | **Firefox** | Chrome, Opera, Safari, or IE 11+ | ## Note importante @@ -30,13 +30,52 @@ Cette version sort lorsqu'on considère qu'on a répondu à nos objectifs en ter [Téléchargement](https://github.com/FreshRSS/FreshRSS/archive/dev.zip) -Comme son nom l'indique, il s'agit de la version sur laquelle les développeurs travaillent. **Elle est donc totalement instable !** Si vous souhaitez recevoir les améliorations au jour le jour, vous pouvez l'utiliser, mais attention à bien suivre les évolutions sur Github (via [le flux RSS de la branche](https://github.com/FreshRSS/FreshRSS/commits/dev.atom) par exemple). On raconte que les développeurs principaux l'utilisent quotidiennement sans avoir de soucis. Sans doute savent-ils ce qu'ils font… +Comme son nom l'indique, il s'agit de la version sur laquelle les développeurs travaillent. **Elle est donc instable !** Si vous souhaitez recevoir les améliorations au jour le jour, vous pouvez l'utiliser, mais attention à bien suivre les évolutions sur Github (via [le flux RSS de la branche](https://github.com/FreshRSS/FreshRSS/commits/dev.atom) par exemple). On raconte que les développeurs principaux l'utilisent quotidiennement sans avoir de soucis. Sans doute savent-ils ce qu'ils font… # Installation sur Apache -**TODO** +``` + + DocumentRoot /var/www/html/ + + #Site par défaut... + + ErrorLog ${APACHE_LOG_DIR}/error.default.log + CustomLog ${APACHE_LOG_DIR}/access.default.log vhost_combined + + + + ServerName rss.example.net + DocumentRoot /path/to/FreshRSS/p/ + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log + CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined -Cette partie n'a pas encore été écrite. Néanmoins, comme il s'agit d'une bête application PHP, cela ne pose généralement pas de soucis à installer :) + AllowEncodedSlashes On + + + + + ServerName rss.example.net + DocumentRoot /path/to/FreshRSS/p/ + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log + CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined + + + Protocols h2 http/1.1 + + + AllowEncodedSlashes On + + SSLEngine on + SSLCompression off + SSLCertificateFile /path/to/server.crt + SSLCertificateKeyFile /path/to/server.key + # Additional SSL configuration, e.g. with LetsEncrypt + + +``` # Installation sur Nginx @@ -46,41 +85,41 @@ _Vous pourrez trouver d'autres fichiers de configuration plus simples mais ces d ``` server { - listen 80; # http sur le port 80 - listen 443 ssl; # https sur le port 443 - - # configuration https - ssl on; - ssl_certificate /etc/nginx/server.crt; - ssl_certificate_key /etc/nginx/server.key; - - # l'url ou les urls de votre serveur - server_name example.com rss.example.com; - - # le répertoire où se trouve le dossier p de FreshRSS - root /srv/FreshRSS/p/; - - index index.php index.html index.htm; - - # les fichiers de log nginx - access_log /var/log/nginx/rss.access.log; - error_log /var/log/nginx/rss.error.log; - - # gestion des fichiers php - # il est nécessaire d'utiliser cette expression régulière pour le bon fonctionnement de l'API - location ~ ^.+?\.php(/.*)?$ { - fastcgi_pass unix:/var/run/php5-fpm.sock; - fastcgi_split_path_info ^(.+\.php)(/.*)$; - # Par défaut la variable PATH_INFO n'est pas définie sous PHP-FPM - # or l'API FreshRSS greader.php en a besoin. Si vous avez un "Bad Request", vérifiez bien cette dernière ! - fastcgi_param PATH_INFO $fastcgi_path_info; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - } - - location / { - try_files $uri $uri/ index.php; - } + listen 80; + listen 443 ssl; + + # configuration https + ssl on; + ssl_certificate /etc/nginx/server.crt; + ssl_certificate_key /etc/nginx/server.key; + + # l'url ou les urls de votre serveur + server_name rss.example.net; + + # le répertoire où se trouve le dossier p de FreshRSS + root /srv/FreshRSS/p/; + + index index.php index.html index.htm; + + # les fichiers de log nginx + access_log /var/log/nginx/rss.access.log; + error_log /var/log/nginx/rss.error.log; + + # gestion des fichiers php + # il est nécessaire d'utiliser cette expression régulière pour le bon fonctionnement de l'API + location ~ ^.+?\.php(/.*)?$ { + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + # Par défaut la variable PATH_INFO n'est pas définie sous PHP-FPM + # or l'API FreshRSS greader.php en a besoin. Si vous avez un "Bad Request", vérifiez bien cette dernière ! + fastcgi_param PATH_INFO $fastcgi_path_info; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } + + location / { + try_files $uri $uri/ index.php; + } } ``` -- cgit v1.2.3 From 875b302179e043ad810203852e78896f68ce6478 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Tue, 17 Oct 2017 23:15:16 +0200 Subject: Fix typo in nl i18n (#1675) --- app/i18n/nl/sub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index 15c1c9a0d..ce446778c 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -2,7 +2,7 @@ /* Dutch translation by Wanabo. http://www.nieuwskop.be */ return array( 'api' => array( - 'documentation' => 'Kopieer de volgende URL om hem in een externe toepassing te gebruiken.' + 'documentation' => 'Kopieer de volgende URL om hem in een externe toepassing te gebruiken.', 'title' => 'API', ), 'bookmarklet' => array( -- cgit v1.2.3 From fe84e6135e7bfb35085fafbc7191ba6306bdb20d Mon Sep 17 00:00:00 2001 From: hoilc Date: Thu, 26 Oct 2017 18:46:53 +0800 Subject: improve zh-cn i18n (#1678) --- app/i18n/zh-cn/admin.php | 34 +++++++++++++++++----------------- app/i18n/zh-cn/conf.php | 14 +++++++------- app/i18n/zh-cn/feedback.php | 6 +++--- app/i18n/zh-cn/gen.php | 4 ++-- app/i18n/zh-cn/install.php | 18 +++++++++--------- app/i18n/zh-cn/sub.php | 28 ++++++++++++++-------------- 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/app/i18n/zh-cn/admin.php b/app/i18n/zh-cn/admin.php index 202114c75..4ecc52e64 100644 --- a/app/i18n/zh-cn/admin.php +++ b/app/i18n/zh-cn/admin.php @@ -9,9 +9,9 @@ return array( 'http' => 'HTTP (面向启用 HTTPS 的高级用户)', 'none' => '无 (危险)', 'title' => '认证', - 'title_reset' => '认证重置', + 'title_reset' => '密码重置', 'token' => '认证口令', - 'token_help' => '允许不经认证访问默认用户的 RSS 输出:', + 'token_help' => '用于不经认证访问默认用户的 RSS 输出:', 'type' => '认证方式', 'unsafe_autologin' => '允许不安全的自动登陆方式:', ), @@ -21,8 +21,8 @@ return array( 'ok' => 'cache 目录权限正常。', ), 'categories' => array( - 'nok' => '分类表配置错误。', - 'ok' => '分类表正常。', + 'nok' => 'Category 表配置错误。', + 'ok' => 'Category 表正常。', ), 'connection' => array( 'nok' => '数据库连接失败。', @@ -30,11 +30,11 @@ return array( ), 'ctype' => array( 'nok' => '找不到字符类型检测库 (php-ctype) 。', - 'ok' => '你已有字符类型检测库 (ctype) 。', + 'ok' => '已找到字符类型检测库 (ctype) 。', ), 'curl' => array( 'nok' => '找不到 cURL 库 (php-curl package) 。', - 'ok' => '你已有 cURL 库。', + 'ok' => '已找到 cURL 库。', ), 'data' => array( 'nok' => '请检查 ./data 目录权限。HTTP 服务器必须有其写入权限。', @@ -43,40 +43,40 @@ return array( 'database' => '数据库相关', 'dom' => array( 'nok' => '找不到用于浏览 DOM 的库 (php-xml) 。', - 'ok' => '你已有用于浏览 DOM 的库。', + 'ok' => '已找到用于浏览 DOM 的库。', ), 'entries' => array( - 'nok' => '条目表配置错误。', - 'ok' => '条目表正常。', + 'nok' => 'Entry 表配置错误。', + 'ok' => 'Entry 表正常。', ), 'favicons' => array( 'nok' => '请检查 ./data/favicons 目录权限。HTTP 服务器必须有其写入权限。', 'ok' => 'favicons 目录权限正常。', ), 'feeds' => array( - 'nok' => 'RSS 源表配置错误。', - 'ok' => 'RSS 源表正常。', + 'nok' => 'Feed 表配置错误。', + 'ok' => 'Feed 表正常。', ), 'fileinfo' => array( 'nok' => '找不到 PHP fileinfo 库 (fileinfo) 。', - 'ok' => '你已有 fileinfo 库。', + 'ok' => '已找到 fileinfo 库。', ), 'files' => '文件相关', 'json' => array( 'nok' => '找不到 JSON 扩展 (php5-json ) 。', - 'ok' => '你已有 JSON 扩展', + 'ok' => '已找到 JSON 扩展', ), 'minz' => array( 'nok' => '找不到 Minz 框架。', - 'ok' => '你已有 Minz 框架。', + 'ok' => '已找到 Minz 框架。', ), 'pcre' => array( 'nok' => '找不到正则表达式解析库 (php-pcre) 。', - 'ok' => '你已有正则表达式解析库 (PCRE) 。', + 'ok' => '已找到正则表达式解析库 (PCRE) 。', ), 'pdo' => array( 'nok' => '找不到 PDO 或支持的驱动 (pdo_mysql, pdo_sqlite, pdo_pgsql) 。', - 'ok' => '你已有 PDO 和支持的至少一种驱动 (pdo_mysql, pdo_sqlite, pdo_pgsql) 。', + 'ok' => '已找到 PDO 和支持的至少一种驱动 (pdo_mysql, pdo_sqlite, pdo_pgsql) 。', ), 'php' => array( '_' => 'PHP 相关', @@ -98,7 +98,7 @@ return array( ), 'zip' => array( 'nok' => '找不到 ZIP 扩展 (php-zip) 。', - 'ok' => '你已有 ZIP 扩展。', + 'ok' => '已找到 ZIP 扩展。', ), ), 'extensions' => array( diff --git a/app/i18n/zh-cn/conf.php b/app/i18n/zh-cn/conf.php index fb62c48ef..1b52ac38f 100644 --- a/app/i18n/zh-cn/conf.php +++ b/app/i18n/zh-cn/conf.php @@ -8,7 +8,7 @@ return array( 'help' => '详细选项位于单独的 RSS 源设置', 'keep_history_by_feed' => '至少保存的文章数', 'optimize' => '优化数据库', - 'optimize_help' => '不时地执行优化可以减少数据库大小', + 'optimize_help' => '偶尔执行优化可以减少数据库大小', 'purge_now' => '立即清除', 'title' => '存档', 'ttl' => '最小自动更新时间', @@ -87,15 +87,15 @@ return array( 'articles_per_page' => '每页文章数', 'auto_load_more' => '在页面底部载入下一篇文章', 'auto_remove_article' => '阅读后隐藏文章', - 'mark_updated_article_unread' => '将有更新的文章设为未读', + 'mark_updated_article_unread' => '有更新的文章设为未读', 'confirm_enabled' => '“全部设为已读”时显示确认对话框', 'display_articles_unfolded' => '默认展开文章', 'display_categories_unfolded' => '默认展开分类', 'hide_read_feeds' => '隐藏没有未读文章的分类或 RSS 源 (启用“显示所有文章”时不生效))', - 'img_with_lazyload' => '使用 "lazy load" 模式加载图片', + 'img_with_lazyload' => '延迟加载图片', 'sides_close_article' => '点击文章外区域以关闭文章', 'jump_next' => '跳转到下一未读项 (RSS 源或分类)', - 'number_divided_when_reader' => '阅读视图除以 2', + 'number_divided_when_reader' => '阅读视图中显示一半', 'read' => array( 'article_open_on_website' => '在打开原文章后', 'article_viewed' => '在文章被浏览后', @@ -134,7 +134,7 @@ return array( 'print' => '打印', 'shaarli' => 'Shaarli', 'share_name' => '名称', - 'share_url' => 'URL', + 'share_url' => '地址', 'title' => '分享', 'twitter' => 'Twitter', 'wallabag' => 'wallabag', @@ -143,7 +143,7 @@ return array( '_' => '快捷键', 'article_action' => '文章操作', 'auto_share' => '分享', - 'auto_share_help' => '如果有多种分享模式,则会按照它们的编号访问。', + 'auto_share_help' => '如果有多种分享模式,则会按照它们的编号依次访问。', 'close_dropdown' => '关闭菜单', 'collapse_article' => '收起文章', 'first_article' => '跳转到第一篇文章', @@ -163,7 +163,7 @@ return array( 'shift_for_all_read' => '+ shift 可以将全部文章设为已读', 'title' => '快捷键', 'user_filter' => '显示自定义查询', - 'user_filter_help' => '如果有多个自定义过滤器,则会按照它们的编号访问。', + 'user_filter_help' => '如果有多个自定义过滤器,则会按照它们的编号依次访问。', ), 'user' => array( 'articles_and_size' => '%s 篇文章 (%s)', diff --git a/app/i18n/zh-cn/feedback.php b/app/i18n/zh-cn/feedback.php index bee5914e9..4ec833668 100644 --- a/app/i18n/zh-cn/feedback.php +++ b/app/i18n/zh-cn/feedback.php @@ -15,10 +15,10 @@ return array( ), 'login' => array( 'invalid' => '用户名或密码无效', - 'success' => '你已成功登录', + 'success' => '登录成功', ), 'logout' => array( - 'success' => '你已登出', + 'success' => '登出成功', ), 'no_password_set' => '管理员密码尚未设置。此特性不可用。', ), @@ -43,7 +43,7 @@ return array( 'not_found' => '%s 不存在', ), 'import_export' => array( - 'export_no_zip_extension' => '服务器未启用 ZIP 扩展。请尝试一个一个导出文件。', + 'export_no_zip_extension' => '服务器未启用 ZIP 扩展。请尝试逐个导出文件。', 'feeds_imported' => '你的 RSS 源已导入,即将更新', 'feeds_imported_with_errors' => '你的 RSS 源已导入,但发生错误', 'file_cannot_be_uploaded' => '文件未能上传!', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index a69f02b3f..3fd2abef6 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -34,7 +34,7 @@ return array( 'ask' => '创建新账户?', 'title' => '账户创建', ), - 'reset' => '认证重置', + 'reset' => '密码重置', 'username' => array( '_' => '用户名', 'admin' => '管理员用户名', @@ -176,7 +176,7 @@ return array( 'short' => array( 'attention' => '警告!', 'blank_to_disable' => '留空以禁用', - 'by_author' => 'By %s', + 'by_author' => '作者 %s', 'by_default' => '默认', 'damn' => '错误!', 'default_category' => '未分类', diff --git a/app/i18n/zh-cn/install.php b/app/i18n/zh-cn/install.php index f247a20fd..1e172f0d5 100644 --- a/app/i18n/zh-cn/install.php +++ b/app/i18n/zh-cn/install.php @@ -38,11 +38,11 @@ return array( ), 'ctype' => array( 'nok' => '找不到字符类型检测库 (php-ctype) 。', - 'ok' => '你已有字符类型检测库 (ctype) 。', + 'ok' => '已找到字符类型检测库 (ctype) 。', ), 'curl' => array( 'nok' => '找不到 cURL 库 (php-curl package) 。', - 'ok' => '你已有 cURL 库。', + 'ok' => '已找到 cURL 库。', ), 'data' => array( 'nok' => '请检查 ./data 目录权限。HTTP 服务器必须有其写入权限。', @@ -50,7 +50,7 @@ return array( ), 'dom' => array( 'nok' => '找不到用于浏览 DOM 的库 (php-xml) 。', - 'ok' => '你已有用于浏览 DOM 的库。', + 'ok' => '已找到用于浏览 DOM 的库。', ), 'favicons' => array( 'nok' => '请检查 ./data/favicons 目录权限。HTTP 服务器必须有其写入权限。', @@ -58,7 +58,7 @@ return array( ), 'fileinfo' => array( 'nok' => '找不到 PHP fileinfo 库 (fileinfo) 。', - 'ok' => '你已有 fileinfo 库。', + 'ok' => '已找到 fileinfo 库。', ), 'http_referer' => array( 'nok' => '请检查你是否修改了 HTTP REFERER。', @@ -66,19 +66,19 @@ return array( ), 'json' => array( 'nok' => '找不到推荐的 JSON 解析库。', - 'ok' => '你已有推荐的 JSON 解析库。', + 'ok' => '已找到推荐的 JSON 解析库。', ), 'minz' => array( 'nok' => '找不到 Minz 框架。', - 'ok' => '你已有 Minz 框架。', + 'ok' => '已找到 Minz 框架。', ), 'pcre' => array( 'nok' => '找不到正则表达式解析库 (php-pcre) 。', - 'ok' => '你已有正则表达式解析库 (PCRE) 。', + 'ok' => '已找到正则表达式解析库 (PCRE) 。', ), 'pdo' => array( 'nok' => '找不到 PDO 或支持的驱动 (pdo_mysql, pdo_sqlite, pdo_pgsql) 。', - 'ok' => '你已有 PDO 和支持的至少一种驱动 (pdo_mysql, pdo_sqlite, pdo_pgsql) 。', + 'ok' => '已找到 PDO 和支持的至少一种驱动 (pdo_mysql, pdo_sqlite, pdo_pgsql) 。', ), 'php' => array( 'nok' => '你的 PHP 版本为 %s,但 FreshRSS 最低需要 %s。', @@ -90,7 +90,7 @@ return array( ), 'xml' => array( 'nok' => '找不到用于 XML 解析库。', - 'ok' => '你已有 XML 解析库。', + 'ok' => '已找到 XML 解析库。', ), ), 'conf' => array( diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php index 48057e74c..026f436d7 100644 --- a/app/i18n/zh-cn/sub.php +++ b/app/i18n/zh-cn/sub.php @@ -2,13 +2,13 @@ return array( 'api' => array( - 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO - 'title' => 'API',// TODO + 'documentation' => '复制以下地址,可供外部工具使用', + 'title' => 'API', ), 'bookmarklet' => array( - 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO - 'label' => 'Subscribe',// TODO - 'title' => 'Bookmarklet',// TODO + 'documentation' => '拖动此书签到你的书签栏或者右键选择“收藏此链接”,然后在你想要订阅的页面上点击“订阅”按钮', + 'label' => '订阅', + 'title' => '书签应用', ), 'category' => array( '_' => '分类', @@ -22,20 +22,20 @@ return array( 'archiving' => '存档', 'auth' => array( 'configuration' => '认证', - 'help' => '连接启用 HTTP 认证的 RSS 源', + 'help' => '用于连接启用 HTTP 认证的 RSS 源', 'http' => 'HTTP 认证', 'password' => 'HTTP 密码', 'username' => 'HTTP 用户名', ), - 'css_help' => '获取全文(注意,会耗费更多时间!)', - 'css_path' => '原网站中文章的 CSS 路径', + 'css_help' => '用于获取全文(注意,这将耗费更多时间!)', + 'css_path' => '原文的 CSS 选择器', 'description' => '描述', 'empty' => '此源为空。请确认它是否正常更新。', - 'error' => '此源遇到一些问题。请确认它是否可访问后重试。', + 'error' => '此源遇到一些问题。请在确认是否能正常访问后重试。', 'in_main_stream' => '在首页中显示', 'informations' => '信息', 'keep_history' => '至少保存的文章数', - 'moved_category_deleted' => '删除分类时,其中的 RSS 源会自动归类到%s。', + 'moved_category_deleted' => '删除分类时,其中的 RSS 源会自动归类到 %s', 'no_selected' => '未选择 RSS 源。', 'number_entries' => '%d 篇文章', 'stats' => '统计', @@ -49,8 +49,8 @@ return array( 'pubsubhubbub' => 'PubSubHubbub 即时通知', ), 'firefox' => array( - 'documentation' => 'Follow the steps described here to add FreshRSS to Firefox feed reader list.',// TODO - 'title' => 'Firefox feed reader',// TODO + 'documentation' => '按照 这里 描述的步骤可将 FreshRSS 添加到 Firefox 阅读器列表', + 'title' => 'Firefox RSS 阅读器', ), 'import_export' => array( 'export' => '导出', @@ -67,11 +67,11 @@ return array( 'bookmark' => '订阅 (FreshRSS 书签)', 'import_export' => '导入/导出', 'subscription_management' => '订阅管理', - 'subscription_tools' => 'Subscription tools',// TODO + 'subscription_tools' => '订阅工具', ), 'title' => array( '_' => '订阅管理', 'feed_management' => 'RSS 源管理', - 'subscription_tools' => 'Subscription tools',// TODO + 'subscription_tools' => '订阅工具', ), ); -- cgit v1.2.3 From 05b1901fcdbb051077d12f776980484d3b782970 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Nov 2017 21:17:08 +0100 Subject: Move translation tools into the cli folder (#1673) Translation tools must be used on cli. It is better to have them in the cli folder. --- .travis.yml | 2 +- cli/check.translation.php | 106 +++++++++++++++++++++++++++++++ cli/i18n/I18nCompletionValidator.php | 49 +++++++++++++++ cli/i18n/I18nData.php | 118 +++++++++++++++++++++++++++++++++++ cli/i18n/I18nFile.php | 92 +++++++++++++++++++++++++++ cli/i18n/I18nUsageValidator.php | 47 ++++++++++++++ cli/i18n/I18nValidatorInterface.php | 26 ++++++++ cli/i18n/ignore/en.php | 105 +++++++++++++++++++++++++++++++ cli/i18n/ignore/fr.php | 55 ++++++++++++++++ cli/manipulate.translation.php | 79 +++++++++++++++++++++++ tools/I18nCompletionValidator.php | 49 --------------- tools/I18nData.php | 118 ----------------------------------- tools/I18nFile.php | 92 --------------------------- tools/I18nUsageValidator.php | 47 -------------- tools/I18nValidatorInterface.php | 26 -------- tools/check.translation.php | 106 ------------------------------- tools/ignore/en.php | 105 ------------------------------- tools/ignore/fr.php | 55 ---------------- tools/manipulate.translation.php | 79 ----------------------- 19 files changed, 678 insertions(+), 678 deletions(-) create mode 100644 cli/check.translation.php create mode 100644 cli/i18n/I18nCompletionValidator.php create mode 100644 cli/i18n/I18nData.php create mode 100644 cli/i18n/I18nFile.php create mode 100644 cli/i18n/I18nUsageValidator.php create mode 100644 cli/i18n/I18nValidatorInterface.php create mode 100644 cli/i18n/ignore/en.php create mode 100644 cli/i18n/ignore/fr.php create mode 100644 cli/manipulate.translation.php delete mode 100644 tools/I18nCompletionValidator.php delete mode 100644 tools/I18nData.php delete mode 100644 tools/I18nFile.php delete mode 100644 tools/I18nUsageValidator.php delete mode 100644 tools/I18nValidatorInterface.php delete mode 100644 tools/check.translation.php delete mode 100644 tools/ignore/en.php delete mode 100644 tools/ignore/fr.php delete mode 100644 tools/manipulate.translation.php diff --git a/.travis.yml b/.travis.yml index 945e77a74..7bfefd8ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ script: fi - | if [[ $CHECK_TRANSLATION == yes ]]; then - php tools/check.translation.php -r + php cli/check.translation.php -r fi env: diff --git a/cli/check.translation.php b/cli/check.translation.php new file mode 100644 index 000000000..6ebd12973 --- /dev/null +++ b/cli/check.translation.php @@ -0,0 +1,106 @@ +load(); + +$options = getopt("dhl:r"); + +if (array_key_exists('h', $options)) { + help(); +} +if (array_key_exists('l', $options)) { + $languages = array($options['l']); +} else { + $languages = $i18nData->getAvailableLanguages(); +} +$displayResults = array_key_exists('d', $options); +$displayReport = array_key_exists('r', $options); + +$isValidated = true; +$result = array(); +$report = array(); + +foreach ($languages as $language) { + if ($language === $i18nData::REFERENCE_LANGUAGE) { + $i18nValidator = new I18nUsageValidator($i18nData->getReferenceLanguage(), findUsedTranslations()); + $isValidated = $i18nValidator->validate(include __DIR__ . '/i18n/ignore/' . $language . '.php') && $isValidated; + } else { + $i18nValidator = new I18nCompletionValidator($i18nData->getReferenceLanguage(), $i18nData->getLanguage($language)); + if (file_exists(__DIR__ . '/i18n/ignore/' . $language . '.php')) { + $isValidated = $i18nValidator->validate(include __DIR__ . '/i18n/ignore/' . $language . '.php') && $isValidated; + } else { + $isValidated = $i18nValidator->validate(null) && $isValidated; + } + } + + $report[$language] = sprintf('%-5s - %s', $language, $i18nValidator->displayReport()); + $result[$language] = $i18nValidator->displayResult(); +} + +if ($displayResults) { + foreach ($result as $lang => $value) { + echo 'Language: ', $lang, PHP_EOL; + print_r($value); + echo PHP_EOL; + } +} + +if ($displayReport) { + foreach ($report as $value) { + echo $value; + } +} + +if (!$isValidated) { + exit(1); +} + +/** + * Find used translation keys in the project + * + * Iterates through all php and phtml files in the whole project and extracts all + * translation keys used. + * + * @return array + */ +function findUsedTranslations() { + $directory = new RecursiveDirectoryIterator(__DIR__ . '/..'); + $iterator = new RecursiveIteratorIterator($directory); + $regex = new RegexIterator($iterator, '/^.+\.(php|phtml)$/i', RecursiveRegexIterator::GET_MATCH); + $usedI18n = array(); + foreach (array_keys(iterator_to_array($regex)) as $file) { + $fileContent = file_get_contents($file); + preg_match_all('/_t\([\'"](?P[^\'"]+)[\'"]/', $fileContent, $matches); + $usedI18n = array_merge($usedI18n, $matches['strings']); + } + return $usedI18n; +} + +/** + * Output help message. + */ +function help() { + $help = <<reference = $reference; + $this->language = $language; + } + + public function displayReport() { + return sprintf('Translation is %5.1f%% complete.', $this->passEntries / $this->totalEntries * 100) . PHP_EOL; + } + + public function displayResult() { + return $this->result; + } + + public function validate($ignore) { + foreach ($this->reference as $file => $data) { + foreach ($data as $key => $value) { + $this->totalEntries++; + if (is_array($ignore) && in_array($key, $ignore)) { + $this->passEntries++; + continue; + } + if (!array_key_exists($key, $this->language[$file])) { + $this->result .= sprintf('Missing key %s', $key) . PHP_EOL; + continue; + } + if ($value === $this->language[$file][$key]) { + $this->result .= sprintf('Untranslated key %s - %s', $key, $value) . PHP_EOL; + continue; + } + $this->passEntries++; + } + } + + return $this->totalEntries === $this->passEntries; + } + +} diff --git a/cli/i18n/I18nData.php b/cli/i18n/I18nData.php new file mode 100644 index 000000000..cd8ba0765 --- /dev/null +++ b/cli/i18n/I18nData.php @@ -0,0 +1,118 @@ +data = $data; + $this->originalData = $data; + } + + public function getData() { + return $this->data; + } + + /** + * Return the available languages + * + * @return array + */ + public function getAvailableLanguages() { + $languages = array_keys($this->data); + sort($languages); + + return $languages; + } + + /** + * Add a new language. It's a copy of the reference language. + * + * @param string $language + */ + public function addLanguage($language) { + if (array_key_exists($language, $this->data)) { + throw new Exception('The selected language already exist.'); + } + $this->data[$language] = $this->data[static::REFERENCE_LANGUAGE]; + } + + /** + * Add a key in the reference language + * + * @param string $key + * @param string $value + */ + public function addKey($key, $value) { + if (array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { + throw new Exception('The selected key already exist.'); + } + $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key] = $value; + } + + /** + * Duplicate a key from the reference language to all other languages + * + * @param string $key + */ + public function duplicateKey($key) { + if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { + throw new Exception('The selected key does not exist.'); + } + $value = $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key]; + foreach ($this->getAvailableLanguages() as $language) { + if (static::REFERENCE_LANGUAGE === $language) { + continue; + } + if (array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) { + throw new Exception(sprintf('The selected key already exist in %s.', $language)); + } + $this->data[$language][$this->getFilenamePrefix($key)][$key] = $value; + } + } + + /** + * Remove a key in all languages + * + * @param string $key + */ + public function removeKey($key) { + if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { + throw new Exception('The selected key does not exist.'); + } + foreach ($this->getAvailableLanguages() as $language) { + if (array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) { + unset($this->data[$language][$this->getFilenamePrefix($key)][$key]); + } + } + } + + /** + * Check if the data has changed + * + * @return bool + */ + public function hasChanged() { + return $this->data !== $this->originalData; + } + + public function getLanguage($language) { + return $this->data[$language]; + } + + public function getReferenceLanguage() { + return $this->getLanguage(static::REFERENCE_LANGUAGE); + } + + /** + * @param string $key + * @return string + */ + private function getFilenamePrefix($key) { + return preg_replace('/\..*/', '.php', $key); + } + +} diff --git a/cli/i18n/I18nFile.php b/cli/i18n/I18nFile.php new file mode 100644 index 000000000..d6489ee21 --- /dev/null +++ b/cli/i18n/I18nFile.php @@ -0,0 +1,92 @@ +i18nPath = __DIR__ . '/../../app/i18n'; + } + + public function load() { + $dirs = new DirectoryIterator($this->i18nPath); + foreach ($dirs as $dir) { + if ($dir->isDot()) { + continue; + } + $files = new DirectoryIterator($dir->getPathname()); + foreach ($files as $file) { + if (!$file->isFile()) { + continue; + } + $i18n[$dir->getFilename()][$file->getFilename()] = $this->flatten(include $file->getPathname(), $file->getBasename('.php')); + } + } + + return new I18nData($i18n); + } + + public function dump(I18nData $i18n) { + foreach ($i18n->getData() as $language => $file) { + $dir = $this->i18nPath . DIRECTORY_SEPARATOR . $language; + if (!file_exists($dir)) { + mkdir($dir); + } + foreach ($file as $name => $content) { + $filename = $dir . DIRECTORY_SEPARATOR . $name; + $fullContent = var_export($this->unflatten($content), true); + file_put_contents($filename, sprintf(' $value) { + if (is_array($value)) { + $a += $this->flatten($value, $prefix . $key); + } else { + $a[$prefix . $key] = $value; + } + } + + return $a; + } + + /** + * Unflatten an array of translation + * + * The first key is dropped since it represents the filename and we have + * no use of it. + * + * @param array $translation + * @return array + */ + private function unflatten($translation) { + $a = array(); + + ksort($translation); + foreach ($translation as $compoundKey => $value) { + $keys = explode('.', $compoundKey); + array_shift($keys); + eval("\$a['" . implode("']['", $keys) . "'] = '" . $value . "';"); + } + + return $a; + } + +} diff --git a/cli/i18n/I18nUsageValidator.php b/cli/i18n/I18nUsageValidator.php new file mode 100644 index 000000000..8ab934971 --- /dev/null +++ b/cli/i18n/I18nUsageValidator.php @@ -0,0 +1,47 @@ +code = $code; + $this->reference = $reference; + } + + public function displayReport() { + return sprintf('%5.1f%% of translation keys are unused.', $this->failedEntries / $this->totalEntries * 100) . PHP_EOL; + } + + public function displayResult() { + return $this->result; + } + + public function validate($ignore) { + foreach ($this->reference as $file => $data) { + foreach ($data as $key => $value) { + $this->totalEntries++; + if (preg_match('/\._$/', $key) && in_array(preg_replace('/\._$/', '', $key), $this->code)) { + continue; + } + if (is_array($ignore) && in_array($key, $ignore)) { + continue; + } + if (!in_array($key, $this->code)) { + $this->result .= sprintf('Unused key %s - %s', $key, $value) . PHP_EOL; + $this->failedEntries++; + continue; + } + } + } + + return 0 === $this->failedEntries; + } + +} diff --git a/cli/i18n/I18nValidatorInterface.php b/cli/i18n/I18nValidatorInterface.php new file mode 100644 index 000000000..edfe7aac0 --- /dev/null +++ b/cli/i18n/I18nValidatorInterface.php @@ -0,0 +1,26 @@ +load(); + +switch ($argv[1]) { + case 'add_language' : + $i18nData->addLanguage($argv[2]); + break; + case 'add_key' : + if (3 === $argc) { + help(); + } + $i18nData->addKey($argv[2], $argv[3]); + break; + case 'duplicate_key' : + $i18nData->duplicateKey($argv[2]); + break; + case 'delete_key' : + $i18nData->removeKey($argv[2]); + break; + default : + help(); +} + +if ($i18nData->hasChanged()) { + $i18nFile->dump($i18nData); +} + +/** + * Output help message. + */ +function help() { + $help = <<reference = $reference; - $this->language = $language; - } - - public function displayReport() { - return sprintf('Translation is %5.1f%% complete.', $this->passEntries / $this->totalEntries * 100) . PHP_EOL; - } - - public function displayResult() { - return $this->result; - } - - public function validate($ignore) { - foreach ($this->reference as $file => $data) { - foreach ($data as $key => $value) { - $this->totalEntries++; - if (is_array($ignore) && in_array($key, $ignore)) { - $this->passEntries++; - continue; - } - if (!array_key_exists($key, $this->language[$file])) { - $this->result .= sprintf('Missing key %s', $key) . PHP_EOL; - continue; - } - if ($value === $this->language[$file][$key]) { - $this->result .= sprintf('Untranslated key %s - %s', $key, $value) . PHP_EOL; - continue; - } - $this->passEntries++; - } - } - - return $this->totalEntries === $this->passEntries; - } - -} diff --git a/tools/I18nData.php b/tools/I18nData.php deleted file mode 100644 index cd8ba0765..000000000 --- a/tools/I18nData.php +++ /dev/null @@ -1,118 +0,0 @@ -data = $data; - $this->originalData = $data; - } - - public function getData() { - return $this->data; - } - - /** - * Return the available languages - * - * @return array - */ - public function getAvailableLanguages() { - $languages = array_keys($this->data); - sort($languages); - - return $languages; - } - - /** - * Add a new language. It's a copy of the reference language. - * - * @param string $language - */ - public function addLanguage($language) { - if (array_key_exists($language, $this->data)) { - throw new Exception('The selected language already exist.'); - } - $this->data[$language] = $this->data[static::REFERENCE_LANGUAGE]; - } - - /** - * Add a key in the reference language - * - * @param string $key - * @param string $value - */ - public function addKey($key, $value) { - if (array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { - throw new Exception('The selected key already exist.'); - } - $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key] = $value; - } - - /** - * Duplicate a key from the reference language to all other languages - * - * @param string $key - */ - public function duplicateKey($key) { - if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { - throw new Exception('The selected key does not exist.'); - } - $value = $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key]; - foreach ($this->getAvailableLanguages() as $language) { - if (static::REFERENCE_LANGUAGE === $language) { - continue; - } - if (array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) { - throw new Exception(sprintf('The selected key already exist in %s.', $language)); - } - $this->data[$language][$this->getFilenamePrefix($key)][$key] = $value; - } - } - - /** - * Remove a key in all languages - * - * @param string $key - */ - public function removeKey($key) { - if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) { - throw new Exception('The selected key does not exist.'); - } - foreach ($this->getAvailableLanguages() as $language) { - if (array_key_exists($key, $this->data[$language][$this->getFilenamePrefix($key)])) { - unset($this->data[$language][$this->getFilenamePrefix($key)][$key]); - } - } - } - - /** - * Check if the data has changed - * - * @return bool - */ - public function hasChanged() { - return $this->data !== $this->originalData; - } - - public function getLanguage($language) { - return $this->data[$language]; - } - - public function getReferenceLanguage() { - return $this->getLanguage(static::REFERENCE_LANGUAGE); - } - - /** - * @param string $key - * @return string - */ - private function getFilenamePrefix($key) { - return preg_replace('/\..*/', '.php', $key); - } - -} diff --git a/tools/I18nFile.php b/tools/I18nFile.php deleted file mode 100644 index d8c16a6eb..000000000 --- a/tools/I18nFile.php +++ /dev/null @@ -1,92 +0,0 @@ -i18nPath = __DIR__ . '/../app/i18n'; - } - - public function load() { - $dirs = new DirectoryIterator($this->i18nPath); - foreach ($dirs as $dir) { - if ($dir->isDot()) { - continue; - } - $files = new DirectoryIterator($dir->getPathname()); - foreach ($files as $file) { - if (!$file->isFile()) { - continue; - } - $i18n[$dir->getFilename()][$file->getFilename()] = $this->flatten(include $file->getPathname(), $file->getBasename('.php')); - } - } - - return new I18nData($i18n); - } - - public function dump(I18nData $i18n) { - foreach ($i18n->getData() as $language => $file) { - $dir = $this->i18nPath . DIRECTORY_SEPARATOR . $language; - if (!file_exists($dir)) { - mkdir($dir); - } - foreach ($file as $name => $content) { - $filename = $dir . DIRECTORY_SEPARATOR . $name; - $fullContent = var_export($this->unflatten($content), true); - file_put_contents($filename, sprintf(' $value) { - if (is_array($value)) { - $a += $this->flatten($value, $prefix . $key); - } else { - $a[$prefix . $key] = $value; - } - } - - return $a; - } - - /** - * Unflatten an array of translation - * - * The first key is dropped since it represents the filename and we have - * no use of it. - * - * @param array $translation - * @return array - */ - private function unflatten($translation) { - $a = array(); - - ksort($translation); - foreach ($translation as $compoundKey => $value) { - $keys = explode('.', $compoundKey); - array_shift($keys); - eval("\$a['" . implode("']['", $keys) . "'] = '" . $value . "';"); - } - - return $a; - } - -} diff --git a/tools/I18nUsageValidator.php b/tools/I18nUsageValidator.php deleted file mode 100644 index 8ab934971..000000000 --- a/tools/I18nUsageValidator.php +++ /dev/null @@ -1,47 +0,0 @@ -code = $code; - $this->reference = $reference; - } - - public function displayReport() { - return sprintf('%5.1f%% of translation keys are unused.', $this->failedEntries / $this->totalEntries * 100) . PHP_EOL; - } - - public function displayResult() { - return $this->result; - } - - public function validate($ignore) { - foreach ($this->reference as $file => $data) { - foreach ($data as $key => $value) { - $this->totalEntries++; - if (preg_match('/\._$/', $key) && in_array(preg_replace('/\._$/', '', $key), $this->code)) { - continue; - } - if (is_array($ignore) && in_array($key, $ignore)) { - continue; - } - if (!in_array($key, $this->code)) { - $this->result .= sprintf('Unused key %s - %s', $key, $value) . PHP_EOL; - $this->failedEntries++; - continue; - } - } - } - - return 0 === $this->failedEntries; - } - -} diff --git a/tools/I18nValidatorInterface.php b/tools/I18nValidatorInterface.php deleted file mode 100644 index edfe7aac0..000000000 --- a/tools/I18nValidatorInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -load(); - -$options = getopt("dhl:r"); - -if (array_key_exists('h', $options)) { - help(); -} -if (array_key_exists('l', $options)) { - $languages = array($options['l']); -} else { - $languages = $i18nData->getAvailableLanguages(); -} -$displayResults = array_key_exists('d', $options); -$displayReport = array_key_exists('r', $options); - -$isValidated = true; -$result = array(); -$report = array(); - -foreach ($languages as $language) { - if ($language === $i18nData::REFERENCE_LANGUAGE) { - $i18nValidator = new I18nUsageValidator($i18nData->getReferenceLanguage(), findUsedTranslations()); - $isValidated = $i18nValidator->validate(include __DIR__ . '/ignore/' . $language . '.php') && $isValidated; - } else { - $i18nValidator = new I18nCompletionValidator($i18nData->getReferenceLanguage(), $i18nData->getLanguage($language)); - if (file_exists(__DIR__ . '/ignore/' . $language . '.php')) { - $isValidated = $i18nValidator->validate(include __DIR__ . '/ignore/' . $language . '.php') && $isValidated; - } else { - $isValidated = $i18nValidator->validate(null) && $isValidated; - } - } - - $report[$language] = sprintf('%-5s - %s', $language, $i18nValidator->displayReport()); - $result[$language] = $i18nValidator->displayResult(); -} - -if ($displayResults) { - foreach ($result as $lang => $value) { - echo 'Language: ', $lang, PHP_EOL; - print_r($value); - echo PHP_EOL; - } -} - -if ($displayReport) { - foreach ($report as $value) { - echo $value; - } -} - -if (!$isValidated) { - exit(1); -} - -/** - * Find used translation keys in the project - * - * Iterates through all php and phtml files in the whole project and extracts all - * translation keys used. - * - * @return array - */ -function findUsedTranslations() { - $directory = new RecursiveDirectoryIterator(__DIR__ . '/..'); - $iterator = new RecursiveIteratorIterator($directory); - $regex = new RegexIterator($iterator, '/^.+\.(php|phtml)$/i', RecursiveRegexIterator::GET_MATCH); - $usedI18n = array(); - foreach (array_keys(iterator_to_array($regex)) as $file) { - $fileContent = file_get_contents($file); - preg_match_all('/_t\([\'"](?P[^\'"]+)[\'"]/', $fileContent, $matches); - $usedI18n = array_merge($usedI18n, $matches['strings']); - } - return $usedI18n; -} - -/** - * Output help message. - */ -function help() { - $help = <<load(); - -switch ($argv[1]) { - case 'add_language' : - $i18nData->addLanguage($argv[2]); - break; - case 'add_key' : - if (3 === $argc) { - help(); - } - $i18nData->addKey($argv[2], $argv[3]); - break; - case 'duplicate_key' : - $i18nData->duplicateKey($argv[2]); - break; - case 'delete_key' : - $i18nData->removeKey($argv[2]); - break; - default : - help(); -} - -if ($i18nData->hasChanged()) { - $i18nFile->dump($i18nData); -} - -/** - * Output help message. - */ -function help() { - $help = << Date: Sat, 4 Nov 2017 21:19:51 +0100 Subject: Add a Mastodon share (#1674) See #1521 --- app/FreshRSS.php | 8 +++++- app/Models/Share.php | 31 +++++++++++++++++++++-- app/i18n/cz/gen.php | 13 +++++----- app/i18n/de/gen.php | 10 ++++---- app/i18n/en/gen.php | 10 ++++---- app/i18n/es/gen.php | 11 ++++---- app/i18n/fr/gen.php | 11 ++++---- app/i18n/it/gen.php | 11 ++++---- app/i18n/kr/gen.php | 11 ++++---- app/i18n/nl/gen.php | 17 +++++++------ app/i18n/pt-br/gen.php | 11 ++++---- app/i18n/ru/gen.php | 9 ++++--- app/i18n/tr/gen.php | 11 ++++---- app/i18n/zh-cn/gen.php | 11 ++++---- app/views/configure/sharing.phtml | 6 ++++- app/views/helpers/index/normal/entry_bottom.phtml | 9 ++++++- data/shares.php | 25 ++++++++++++++++++ p/scripts/main.js | 11 ++++++++ 18 files changed, 158 insertions(+), 68 deletions(-) diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 90d6fae06..8f4ee334c 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -111,7 +111,13 @@ class FreshRSS extends Minz_FrontController { public static function preLayout() { switch (Minz_Request::controllerName()) { case 'index': - header("Content-Security-Policy: default-src 'self'; child-src *; frame-src *; img-src * data:; media-src *"); + $urlToAuthorize = array_filter(array_map(function($a) { + if ('POST' === $a['method']) { + return $a['url']; + } + }, FreshRSS_Context::$user_conf->sharing)); + $connectSrc = count($urlToAuthorize) ? sprintf("; connect-src 'self' %s", implode(' ', $urlToAuthorize)) : ''; + header(sprintf("Content-Security-Policy: default-src 'self'; child-src *; frame-src *; img-src * data:; media-src *%s", $connectSrc)); break; case 'stats': header("Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'"); diff --git a/app/Models/Share.php b/app/Models/Share.php index 86b1b9ed9..7378b30df 100644 --- a/app/Models/Share.php +++ b/app/Models/Share.php @@ -21,9 +21,11 @@ class FreshRSS_Share { } $help_url = isset($share_options['help']) ? $share_options['help'] : ''; + $field = isset($share_options['field']) ? $share_options['field'] : null; self::$list_sharing[$type] = new FreshRSS_Share( $type, $share_options['url'], $share_options['transform'], - $share_options['form'], $help_url + $share_options['form'], $help_url, $share_options['method'], + $field ); } @@ -76,6 +78,8 @@ class FreshRSS_Share { private $base_url = null; private $title = null; private $link = null; + private $method = 'GET'; + private $field; /** * Create a FreshRSS_Share object. @@ -86,9 +90,10 @@ class FreshRSS_Share { * is typically for a centralized service while "advanced" is for * decentralized ones. * @param $help_url is an optional url to give help on this option. + * @param $method defines the sharing method (GET or POST) */ private function __construct($type, $url_transform, $transform, - $form_type, $help_url = '') { + $form_type, $help_url, $method, $field) { $this->type = $type; $this->name = _t('gen.share.' . $type); $this->url_transform = $url_transform; @@ -103,6 +108,11 @@ class FreshRSS_Share { $form_type = 'simple'; } $this->form_type = $form_type; + if (!in_array($method, array('GET', 'POST'))) { + $method = 'GET'; + } + $this->method = $method; + $this->field = $field; } /** @@ -116,6 +126,8 @@ class FreshRSS_Share { 'url' => 'base_url', 'title' => 'title', 'link' => 'link', + 'method' => 'method', + 'field' => 'field', ); foreach ($options as $key => $value) { @@ -132,6 +144,21 @@ class FreshRSS_Share { return $this->type; } + /** + * Return the current method of the share option. + */ + public function method() { + return $this->method; + } + + /** + * Return the current field of the share option. It's null for shares + * using the GET method. + */ + public function field() { + return $this->field; + } + /** * Return the current form type of the share option. */ diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index a9c7dc875..e43355f64 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filtrovat', 'import' => 'Import', 'manage' => 'Spravovat', - 'mark_read' => 'Označit jako přečtené', 'mark_favorite' => 'Označit jako oblíbené', + 'mark_read' => 'Označit jako přečtené', 'remove' => 'Odstranit', 'see_website' => 'Navštívit WWW stránku', 'submit' => 'Odeslat', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Minulý rok', 'mar' => 'bře', 'march' => 'Bře', - 'may_' => 'Kvě', 'may' => 'Květen', + 'may_' => 'Kvě', 'mon' => 'Po', 'month' => 'měsíce', 'nov' => 'lis', @@ -143,7 +143,7 @@ return array( 'sharing' => 'Sdílení', 'shortcuts' => 'Zkratky', 'stats' => 'Statistika', - 'system' => 'System configuration',// @todo translate + 'system' => 'System configuration', // @todo translate 'update' => 'Aktualizace', 'user_management' => 'Správa uživatelů', 'user_profile' => 'Profil', @@ -158,20 +158,21 @@ return array( 'previous' => 'Předchozí', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Tisk', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Upozornění!', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index 43d0a2c05..b42081324 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filtern', 'import' => 'Importieren', 'manage' => 'Verwalten', - 'mark_read' => 'Als gelesen markieren', 'mark_favorite' => 'Als Favorit markieren', + 'mark_read' => 'Als gelesen markieren', 'remove' => 'Entfernen', 'see_website' => 'Webseite ansehen', 'submit' => 'Abschicken', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Letztes Jahr', 'mar' => 'Mär', 'march' => 'März', - 'may_' => 'Mai', 'may' => 'Mai', + 'may_' => 'Mai', 'mon' => 'Mo', 'month' => 'Monat(en)', 'nov' => 'Nov', @@ -163,15 +163,15 @@ return array( 'email' => 'E-Mail', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Drucken', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Achtung!', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 095eb17d3..ef1993dbc 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filter', 'import' => 'Import', 'manage' => 'Manage', - 'mark_read' => 'Mark as read', 'mark_favorite' => 'Mark as favourite', + 'mark_read' => 'Mark as read', 'remove' => 'Remove', 'see_website' => 'See website', 'submit' => 'Submit', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Last year', 'mar' => 'Mar.', 'march' => 'March', - 'may_' => 'May', 'may' => 'May', + 'may_' => 'May', 'mon' => 'Mon', 'month' => 'months', 'nov' => 'Nov.', @@ -163,15 +163,15 @@ return array( 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Warning!', diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php index 68fdaf429..0f113e073 100755 --- a/app/i18n/es/gen.php +++ b/app/i18n/es/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filtrar', 'import' => 'Importar', 'manage' => 'Administrar', - 'mark_read' => 'Marcar como leído', 'mark_favorite' => 'Marcar como favorita', + 'mark_read' => 'Marcar como leído', 'remove' => 'Borrar', 'see_website' => 'Ver web', 'submit' => 'Enviar', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Año pasado', 'mar' => 'mar', 'march' => 'marzo', - 'may_' => 'may', 'may' => 'mayo', + 'may_' => 'may', 'mon' => 'Lun', 'month' => 'meses', 'nov' => 'nov', @@ -158,20 +158,21 @@ return array( 'previous' => 'Anterior', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => '¡Aviso!', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 16935c3c4..29b7f8e4a 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filtrer', 'import' => 'Importer', 'manage' => 'Gérer', - 'mark_read' => 'Marquer comme lu', 'mark_favorite' => 'Mettre en favori', + 'mark_read' => 'Marquer comme lu', 'remove' => 'Supprimer', 'see_website' => 'Voir le site', 'submit' => 'Valider', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Depuis l’année dernière', 'mar' => 'mars', 'march' => 'mars', - 'may_' => 'mai', 'may' => 'mai', + 'may_' => 'mai', 'mon' => 'lun.', 'month' => 'mois', 'nov' => 'nov.', @@ -158,20 +158,21 @@ return array( 'previous' => 'Précédent', ), 'share' => array( + 'Known' => 'Sites basés sur Known', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Courriel', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Imprimer', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Sites basés sur Known', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Attention !', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index ae39d7324..9eaabc2be 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filtra', 'import' => 'Importa', 'manage' => 'Gestisci', - 'mark_read' => 'Segna come letto', 'mark_favorite' => 'Segna come preferito', + 'mark_read' => 'Segna come letto', 'remove' => 'Rimuovi', 'see_website' => 'Vai al sito', 'submit' => 'Conferma', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Ultimo anno', 'mar' => 'mar.', 'march' => 'marzo', - 'may_' => 'May', 'may' => 'maggio', + 'may_' => 'May', 'mon' => 'Mon', 'month' => 'mesi', 'nov' => 'nov.', @@ -158,20 +158,21 @@ return array( 'previous' => 'Precedente', ), 'share' => array( + 'Known' => 'Siti basati su Known', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Stampa', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Siti basati su Known', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Attenzione!', diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php index 35d5e8143..e9b6ea9b8 100644 --- a/app/i18n/kr/gen.php +++ b/app/i18n/kr/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => '해당하는 글 보기', 'import' => '불러오기', 'manage' => '관리', - 'mark_read' => '읽음으로 표시', 'mark_favorite' => '즐겨찾기에 등록', + 'mark_read' => '읽음으로 표시', 'remove' => '삭제', 'see_website' => '웹사이트 열기', 'submit' => '설정 저장', @@ -79,8 +79,8 @@ return array( 'last_year' => '최근 일 년', 'mar' => '3월', 'march' => '3월', - 'may_' => '5월', 'may' => '5월', + 'may_' => '5월', 'mon' => '월', 'month' => '개월', 'nov' => '11월', @@ -158,20 +158,21 @@ return array( 'previous' => 'Previous', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => '메일', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => '인쇄', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => '경고!', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 1617936ab..bccab8310 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -1,5 +1,5 @@ array( 'actualize' => 'Actualiseren', @@ -13,8 +13,8 @@ return array( 'filter' => 'Filteren', 'import' => 'Importeren', 'manage' => 'Beheren', - 'mark_read' => 'Markeer als gelezen', 'mark_favorite' => 'Markeer als favoriet', + 'mark_read' => 'Markeer als gelezen', 'remove' => 'Verwijder', 'see_website' => 'Bekijk website', 'submit' => 'Opslaan', @@ -63,8 +63,8 @@ return array( 'december' => 'Dec', 'feb' => 'feb', 'february' => 'Feb', - 'format_date' => 'j %s Y', //<-- European date format // 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', - 'format_date_hour' => 'j %s Y \\o\\m H\\:i', //<-- European date format // 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', + 'format_date' => 'j %s Y', + 'format_date_hour' => 'j %s Y \\o\\m H\\:i', 'fri' => 'Vr', 'jan' => 'jan', 'january' => 'Jan', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Vorig jaar', 'mar' => 'mrt', 'march' => 'Mrt', - 'may_' => 'Mei', 'may' => 'Mei', + 'may_' => 'Mei', 'mon' => 'Ma', 'month' => 'maanden', 'nov' => 'nov', @@ -158,20 +158,21 @@ return array( 'previous' => 'Vorige', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Attentie!', diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php index 1a74e1437..e313b0d8b 100644 --- a/app/i18n/pt-br/gen.php +++ b/app/i18n/pt-br/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filtrar', 'import' => 'Importar', 'manage' => 'Gerenciar', - 'mark_read' => 'Marcar como lido', 'mark_favorite' => 'Marcar como favorito', + 'mark_read' => 'Marcar como lido', 'remove' => 'Remover', 'see_website' => 'Ver o site', 'submit' => 'Enviar', @@ -124,7 +124,7 @@ return array( 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', - 'zh-cn' => '简体中文' + 'zh-cn' => '简体中文', ), 'menu' => array( 'about' => 'Sobre', @@ -157,20 +157,21 @@ return array( 'previous' => 'Anterior', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Imprimir', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Atencão!', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index 3a728016d..3283731df 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filter', 'import' => 'Import', 'manage' => 'Manage', - 'mark_read' => 'Mark as read', 'mark_favorite' => 'Mark as favourite', + 'mark_read' => 'Mark as read', 'remove' => 'Remove', 'see_website' => 'See website', 'submit' => 'Submit', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Last year', 'mar' => 'mar', 'march' => 'Mar', - 'may_' => 'May', 'may' => 'May', + 'may_' => 'May', 'mon' => 'Mon', 'month' => 'months', 'nov' => 'nov', @@ -158,20 +158,21 @@ return array( 'previous' => 'Previous', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Warning!', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 81f926840..535563542 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => 'Filtrele', 'import' => 'İçe Aktar', 'manage' => 'Yönet', - 'mark_read' => 'Okundu olarak işaretle', 'mark_favorite' => 'Favoriye ekle', + 'mark_read' => 'Okundu olarak işaretle', 'remove' => 'Sil', 'see_website' => 'Siteyi gör', 'submit' => 'Onayla', @@ -79,8 +79,8 @@ return array( 'last_year' => 'Geçen yıl', 'mar' => 'mar', 'march' => 'Mar', - 'may_' => 'May', 'may' => 'Mayıs', + 'may_' => 'May', 'mon' => 'Pzt', 'month' => 'ay', 'nov' => 'kas', @@ -158,20 +158,21 @@ return array( 'previous' => 'Önceki', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => 'Tehlike!', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index 3fd2abef6..84be9f4ba 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -13,8 +13,8 @@ return array( 'filter' => '过滤器', 'import' => '导入', 'manage' => '管理', - 'mark_read' => '设为已读', 'mark_favorite' => '加入收藏', + 'mark_read' => '设为已读', 'remove' => '删除', 'see_website' => '查看网站', 'submit' => '提交', @@ -79,8 +79,8 @@ return array( 'last_year' => '去年', 'mar' => '三月', 'march' => '三月', - 'may_' => '五月', 'may' => '五月', + 'may_' => '五月', 'mon' => '周一', 'month' => '个月', 'nov' => '十一月', @@ -158,20 +158,21 @@ return array( 'previous' => '上一页', ), 'share' => array( + 'Known' => 'Known based sites', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', 'wallabagv2' => 'wallabag v2', - 'jdh' => 'Journal du hacker', - 'Known' => 'Known based sites', - 'gnusocial' => 'GNU social', ), 'short' => array( 'attention' => '警告!', diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index ffcfb8b29..b0e6618fa 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -9,6 +9,8 @@ ' data-advanced='
+ +
@@ -28,6 +30,8 @@
+ +
formType() === 'advanced') { ?> @@ -48,7 +52,7 @@
+ + diff --git a/data/shares.php b/data/shares.php index d73ae3826..5403fd48c 100644 --- a/data/shares.php +++ b/data/shares.php @@ -14,6 +14,10 @@ * The ~TITLE~ placeholder represents the title of the shared article. * - transform is an array of transformation to apply on links and titles * - help is a URL to a help page + * - form is the type of form to display during configuration. It's either + * 'simple' or 'advanced'. 'simple' is used when only the name is configurable, + * 'advanced' is used when the name and the location are configurable. + * - method is the HTTP method (POST or GET) used to share a link. */ return array( @@ -22,12 +26,14 @@ return array( 'transform' => array('rawurlencode'), 'help' => 'http://sebsauvage.net/wiki/doku.php?id=php:shaarli', 'form' => 'advanced', + 'method' => 'GET', ), 'blogotext' => array( 'url' => '~URL~/admin/links.php?url=~LINK~', 'transform' => array(), 'help' => 'http://lehollandaisvolant.net/blogotext/fr/', 'form' => 'advanced', + 'method' => 'GET', ), 'wallabag' => array( 'url' => '~URL~?action=add&url=~LINK~', @@ -37,6 +43,7 @@ return array( ), 'help' => 'http://www.wallabag.org/', 'form' => 'advanced', + 'method' => 'GET', ), 'wallabagv2' => array( 'url' => '~URL~/bookmarklet?url=~LINK~', @@ -46,59 +53,77 @@ return array( ), 'help' => 'http://www.wallabag.org/', 'form' => 'advanced', + 'method' => 'GET', ), 'diaspora' => array( 'url' => '~URL~/bookmarklet?url=~LINK~&title=~TITLE~', 'transform' => array('rawurlencode'), 'help' => 'https://diasporafoundation.org/', 'form' => 'advanced', + 'method' => 'GET', ), 'movim' => array( 'url' => '~URL~/?share/~LINK~', 'transform' => array('rawurlencode', 'urlencode'), 'help' => 'https://github.com/edhelas/movim', 'form' => 'advanced', + 'method' => 'GET', ), 'twitter' => array( 'url' => 'https://twitter.com/share?url=~LINK~&text=~TITLE~', 'transform' => array('rawurlencode'), 'form' => 'simple', + 'method' => 'GET', ), 'g+' => array( 'url' => 'https://plus.google.com/share?url=~LINK~', 'transform' => array('rawurlencode'), 'form' => 'simple', + 'method' => 'GET', ), 'facebook' => array( 'url' => 'https://www.facebook.com/sharer.php?u=~LINK~&t=~TITLE~', 'transform' => array('rawurlencode'), 'form' => 'simple', + 'method' => 'GET', ), 'email' => array( 'url' => 'mailto:?subject=~TITLE~&body=~LINK~', 'transform' => array('rawurlencode'), 'form' => 'simple', + 'method' => 'GET', ), 'print' => array( 'url' => '#', 'transform' => array(), 'form' => 'simple', + 'method' => 'GET', ), 'jdh' => array( 'url' => 'https://www.journalduhacker.net/stories/new?url=~LINK~&title=~TITLE~', 'transform' => array('rawurlencode'), 'form' => 'simple', + 'method' => 'GET', ), 'Known' => array( 'url' => '~URL~/share?share_url=~LINK~&share_title=~TITLE~', 'transform' => array('rawurlencode'), 'help' => 'https://withknown.com/', 'form' => 'advanced', + 'method' => 'GET', ), 'gnusocial' => array( 'url' => '~URL~/notice/new?content=~TITLE~%20~LINK~', 'transform' => array('urlencode'), 'help' => 'https://gnu.io/social/', 'form' => 'advanced', + 'method' => 'GET', + ), + 'mastodon' => array( + 'url' => '~URL~/api/v1/statuses', + 'transform' => array(), + 'form' => 'advanced', + 'method' => 'POST', + 'field' => 'status', ), ); diff --git a/p/scripts/main.js b/p/scripts/main.js index 278ecfee9..ce8070008 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1172,6 +1172,14 @@ function init_print_action() { }); } +function init_post_action() { + $('.item.share > a[href="POST"]').click(function (event) { + event.preventDefault(); + var form = $(this).next('form'); + $.post(form.data('url'), form.serialize()); + }); +} + function init_share_observers() { shares = $('.group-share').length; @@ -1182,6 +1190,8 @@ function init_share_observers() { row = row.replace(/##type##/g, opt.val()); row = row.replace(/##help##/g, opt.data('help')); row = row.replace(/##key##/g, shares); + row = row.replace(/##method##/g, opt.data('method')); + row = row.replace(/##field##/g, opt.data('field')); $(this).parents('.form-group').before(row); shares++; @@ -1398,6 +1408,7 @@ function init_afterDOM() { init_posts(); init_nav_entries(); init_print_action(); + init_post_action(); init_notifs_html5(); window.setInterval(refreshUnreads, 120000); } else { -- cgit v1.2.3 From 38de643d090effd487730f7406589f2f3d7bb169 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 4 Nov 2017 21:34:34 +0100 Subject: Small fix Mastodon share $a['method'] can be undefined. https://github.com/FreshRSS/FreshRSS/pull/1674 https://github.com/FreshRSS/FreshRSS/issues/1521 --- app/FreshRSS.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 8f4ee334c..f53c85bfb 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -111,8 +111,8 @@ class FreshRSS extends Minz_FrontController { public static function preLayout() { switch (Minz_Request::controllerName()) { case 'index': - $urlToAuthorize = array_filter(array_map(function($a) { - if ('POST' === $a['method']) { + $urlToAuthorize = array_filter(array_map(function ($a) { + if (isset($a['method']) && $a['method'] === 'POST') { return $a['url']; } }, FreshRSS_Context::$user_conf->sharing)); -- cgit v1.2.3 From 90554db7ee8ba7b553da3c1ee0a451de7c6c66b4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 4 Nov 2017 21:38:15 +0100 Subject: Changelog Mastodon --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97fcdcbed..b74efe42f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,10 @@ ## 2017-1X-XX FreshRSS 1.8.1-dev +* Features + * Share with Mastodon [#1521](https://github.com/FreshRSS/FreshRSS/issues/1521) * UI - Show URL to add subscriptions from third-party tools [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) + * Show URL to add subscriptions from third-party tools [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing -- cgit v1.2.3 From 07fa243bf24f0c4bef2df612a316e8d58907dc8a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 11 Nov 2017 12:21:41 +0100 Subject: Fix link encoding in API (#1686) https://github.com/FreshRSS/FreshRSS/issues/1683 https://github.com/Alkarex/EasyRSS/issues/35 --- CHANGELOG.md | 2 ++ p/api/greader.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b74efe42f..d7f045397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## 2017-1X-XX FreshRSS 1.8.1-dev +* API + * Breaking change / compatibility fix (EasyRSS): Provide `link` to articles without HTML-encoding [#1683](https://github.com/FreshRSS/FreshRSS/issues/1683) * Features * Share with Mastodon [#1521](https://github.com/FreshRSS/FreshRSS/issues/1521) * UI diff --git a/p/api/greader.php b/p/api/greader.php index b87fcc225..f086ee442 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -517,7 +517,7 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex 'title' => $entry->title(), 'summary' => array('content' => $entry->content()), 'alternate' => array( - array('href' => $entry->link()), + array('href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES)), ), 'categories' => array( 'user/-/state/com.google/reading-list', -- cgit v1.2.3 From 32e9d3a5a17edd33ed19158bf567c857fb4fea78 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 12 Nov 2017 15:51:43 +0100 Subject: A bit of documentation for the API (#1689) https://github.com/FreshRSS/FreshRSS/issues/1687 https://github.com/FreshRSS/FreshRSS/issues/443#issuecomment-36666133 --- app/views/user/profile.phtml | 2 +- config.default.php | 2 +- docs/en/users/01_Installation.md | 25 +++++++++++++------ docs/en/users/06_Mobile_access.md | 52 ++++++++++++++++++++++++++++++++++++++- docs/fr/users/01_Installation.md | 29 +++++++++++++++------- docs/fr/users/06_Mobile_access.md | 50 ++++++++++++++++++++++++++++++++++++- 6 files changed, 140 insertions(+), 20 deletions(-) diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml index f09c87765..7a63c0941 100644 --- a/app/views/user/profile.phtml +++ b/app/views/user/profile.phtml @@ -38,7 +38,7 @@ />
- +
diff --git a/config.default.php b/config.default.php index 748df1884..4e4c97e67 100644 --- a/config.default.php +++ b/config.default.php @@ -49,7 +49,7 @@ return array( 'auth_type' => 'form', # Allow or not the use of the API, used for mobile apps. - # End-point is http://example.net/FreshRSS/p/api/greader.php + # End-point is https://freshrss.example.net/api/greader.php # You need to set the user's API password. 'api_enabled' => false, diff --git a/docs/en/users/01_Installation.md b/docs/en/users/01_Installation.md index d0046eebe..9d012f2b1 100644 --- a/docs/en/users/01_Installation.md +++ b/docs/en/users/01_Installation.md @@ -1,6 +1,6 @@ # Server requirements -FreshRSS is a web application. This means you'll need a web server to run it. FreshRSS requirements are really low, so it could run on most shared host servers. +FreshRSS is a web application. This means you’ll need a web server to run it. FreshRSS requirements are really low, so it could run on most shared host servers. You need to verify that your server can run FreshRSS before installing it. If your server has the proper requirements and FreshRSS does not work, please contact us to find a solution. @@ -35,7 +35,7 @@ As its name suggests, it is the working release for developers. **This release i # Apache installation -This is an example Apache virtual hosts configuration file. It covers http and https configuration. +This is an example Apache virtual hosts configuration file. It covers HTTP and HTTPS configuration. ``` @@ -51,6 +51,11 @@ This is an example Apache virtual hosts configuration file. It covers http and h ServerName rss.example.net DocumentRoot /path/to/FreshRSS/p/ + + AllowOverride AuthConfig FileInfo Indexes Limit + Require all granted + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined @@ -62,6 +67,11 @@ This is an example Apache virtual hosts configuration file. It covers http and h ServerName rss.example.net DocumentRoot /path/to/FreshRSS/p/ + + AllowOverride AuthConfig FileInfo Indexes Limit + Require all granted + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined @@ -69,6 +79,7 @@ This is an example Apache virtual hosts configuration file. It covers http and h Protocols h2 http/1.1 + # For the API AllowEncodedSlashes On SSLEngine on @@ -82,7 +93,7 @@ This is an example Apache virtual hosts configuration file. It covers http and h # Nginx installation -This is an example nginx configuration file. It covers http, https and php-fpm configuration. +This is an example nginx configuration file. It covers HTTP, HTTP, and php-fpm configuration. _You can find simpler config file but they may be incompatible with FreshRSS API._ @@ -91,12 +102,12 @@ server { listen 80; listen 443 ssl; - # https configuration + # HTTPS configuration ssl on; ssl_certificate /etc/nginx/server.crt; ssl_certificate_key /etc/nginx/server.key; - # your server's url(s) + # your server’s URL(s) server_name rss.example.net; # the folder p of your FreshRSS installation @@ -114,7 +125,7 @@ server { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; # By default, the variable PATH_INFO is not set under PHP-FPM - # But FreshRSS API greader.php need it. If you have a "Bad Request" error, double check this var ! + # But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var! fastcgi_param PATH_INFO $fastcgi_path_info; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; @@ -126,7 +137,7 @@ server { } ``` -A step-by-step tutorial is available [in french](http://www.pihomeserver.fr/2013/05/08/raspberry-pi-home-server-installer-un-agregateur-de-flux-rss-pour-remplacer-google-reader/). +A step-by-step tutorial is available [in French](http://www.pihomeserver.fr/2013/05/08/raspberry-pi-home-server-installer-un-agregateur-de-flux-rss-pour-remplacer-google-reader/). # Security diff --git a/docs/en/users/06_Mobile_access.md b/docs/en/users/06_Mobile_access.md index e1a23c8ba..d935411eb 100644 --- a/docs/en/users/06_Mobile_access.md +++ b/docs/en/users/06_Mobile_access.md @@ -1 +1,51 @@ -**TODO** +This page assumes you have completed the [server setup](01_Installation.md). + +# Enable the API in FreshRSS + +1. Under the section “Authentication”, enable the option “Allow API access (required for mobile apps)”. +2. Under the section “Profile”, fill-in the field “API password (e.g., for mobile apps)”. + * Every user must define an API password. + * The reason for an API-specific password is that it may be used in less safe situations than the main password, and does not grant access to as many things. + + +# Testing + +3. Under the section “Profile”, click on the link like `https://rss.example.net/api/` next to the field “API password”. +4. Click on first link “Check full server configuration”: + * If you get *PASS* then you are done, all is good: you may proceed to step 6. + * If you get *Bad Request!* or *Not Found*, then your server probably does not accept slashes `/` that are escaped `%2F`. Proceed to step 5. + * If you get any other error message, proceed to step 5. + + +# Fix server configuration + +5. Click on the second link “Check partial server configuration (without `%2F` support)”: + * If you get `PASS`, then the problem is indeed that your server does not accept slashes `/` that are escaped `%2F`. + * With Apache, remember the directive [`AllowEncodedSlashes On`](http://httpd.apache.org/docs/trunk/mod/core.html#allowencodedslashes) + * Or use a client that does not escape slashes (such as EasyRSS), in which case proceed to step 6. + * If you get *Service Unavailable!*, then check from step 1 again. + * With __Apache__: + * If you get *FAIL getallheaders!*, the combination of your PHP version and your Web server does not provide access to [`getallheaders`](http://php.net/getallheaders) + * Update to PHP 5.4+, or use PHP as module instead of CGI. Otherwise turn on Apache `mod_rewrite`: + * Allow [`FileInfo` in `.htaccess`](http://httpd.apache.org/docs/trunk/mod/core.html#allowoverride): see the [server setup](01_Installation.md) again. + * Enable [`mod_rewrite`](http://httpd.apache.org/docs/trunk/mod/mod_rewrite.html): + * With Debian / Ubuntu: `sudo a2enmod rewrite` + * With __nginx__: + * If you get *Bad Request!*, check your server `PATH_INFO` configuration. + * If you get *File not found!*, check your server `fastcgi_split_path_info`. + * If you get *FAIL 64-bit or GMP extension!*, then your PHP version does not pass the requirement of being 64-bit and/or have PHP [GMP](http://php.net/gmp) extension. + * The easiest is to add the GMP extension. On Debian / Ubuntu: `sudo apt install php-gmp` + * Update and try again from step 3. + + +# Compatible clients + +6. On the same FreshRSS API page, note the adress given under “Your API address”, like `https://freshrss.example.net/api/greader.php` + * You will type it in a client, together with your FreshRSS username, and the corresponding special API password. + +7. Pick a client supporting a Google Reader-like API. Selection: + * Android + * [News+](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus) with [News+ Google Reader extension](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader) (Closed source) + * [EasyRSS](https://github.com/Alkarex/EasyRSS) (Open source, [F-Droid](https://f-droid.org/packages/org.freshrss.easyrss/)) + * Linux + * [FeedReader 2.0+](https://jangernert.github.io/FeedReader/) (Open source) diff --git a/docs/fr/users/01_Installation.md b/docs/fr/users/01_Installation.md index 03cdbdd88..dd1bacd00 100644 --- a/docs/fr/users/01_Installation.md +++ b/docs/fr/users/01_Installation.md @@ -1,6 +1,6 @@ # Les pré-requis sur le serveur -FreshRSS est un logiciel développé en PHP reposant sur le modèle client - serveur. C'est-à-dire qu'il vous faudra un serveur web pour en profiter. Ensuite, FreshRSS ne demande pas une configuration très fournie et peut donc, en théorie, tourner sur la plupart des serveurs mutualisés. +FreshRSS est un logiciel développé en PHP reposant sur le modèle client - serveur. C’est-à-dire qu’il vous faudra un serveur web pour en profiter. Ensuite, FreshRSS ne demande pas une configuration très fournie et peut donc, en théorie, tourner sur la plupart des serveurs mutualisés. Il est toutefois de votre responsabilité de vérifier que votre hébergement permettra de faire tourner FreshRSS avant de nous taper dessus. Dans le cas où les informations listées ci-dessous ne seraient pas à jour, vous pourrez. @@ -24,13 +24,13 @@ FreshRSS possède trois versions différentes (nous parlons de branches) qui sor [Téléchargement](https://github.com/FreshRSS/FreshRSS/archive/master.zip) -Cette version sort lorsqu'on considère qu'on a répondu à nos objectifs en terme de nouvelles fonctionnalités. Deux versions peuvent ainsi sortir de façon très rapprochée si les développeurs travaillent bien. En pratique, comme nous nous fixons de nombreux objectifs et que nous travaillons sur notre temps libre, les versions sont souvent assez espacées (plusieurs mois). Son avantage est que le code est particulièrement stable et vous ne devriez pas faire face à de méchants bugs. +Cette version sort lorsqu’on considère qu’on a répondu à nos objectifs en terme de nouvelles fonctionnalités. Deux versions peuvent ainsi sortir de façon très rapprochée si les développeurs travaillent bien. En pratique, comme nous nous fixons de nombreux objectifs et que nous travaillons sur notre temps libre, les versions sont souvent assez espacées (plusieurs mois). Son avantage est que le code est particulièrement stable et vous ne devriez pas faire face à de méchants bugs. ## La version de développement [Téléchargement](https://github.com/FreshRSS/FreshRSS/archive/dev.zip) -Comme son nom l'indique, il s'agit de la version sur laquelle les développeurs travaillent. **Elle est donc instable !** Si vous souhaitez recevoir les améliorations au jour le jour, vous pouvez l'utiliser, mais attention à bien suivre les évolutions sur Github (via [le flux RSS de la branche](https://github.com/FreshRSS/FreshRSS/commits/dev.atom) par exemple). On raconte que les développeurs principaux l'utilisent quotidiennement sans avoir de soucis. Sans doute savent-ils ce qu'ils font… +Comme son nom l’indique, il s’agit de la version sur laquelle les développeurs travaillent. **Elle est donc instable !** Si vous souhaitez recevoir les améliorations au jour le jour, vous pouvez l’utiliser, mais attention à bien suivre les évolutions sur Github (via [le flux RSS de la branche](https://github.com/FreshRSS/FreshRSS/commits/dev.atom) par exemple). On raconte que les développeurs principaux l’utilisent quotidiennement sans avoir de soucis. Sans doute savent-ils ce qu’ils font… # Installation sur Apache @@ -48,6 +48,11 @@ Comme son nom l'indique, il s'agit de la version sur laquelle les développeurs ServerName rss.example.net DocumentRoot /path/to/FreshRSS/p/ + + AllowOverride AuthConfig FileInfo Indexes Limit + Require all granted + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined @@ -59,6 +64,11 @@ Comme son nom l'indique, il s'agit de la version sur laquelle les développeurs ServerName rss.example.net DocumentRoot /path/to/FreshRSS/p/ + + AllowOverride AuthConfig FileInfo Indexes Limit + Require all granted + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined @@ -66,6 +76,7 @@ Comme son nom l'indique, il s'agit de la version sur laquelle les développeurs Protocols h2 http/1.1 + # Pour l’API AllowEncodedSlashes On SSLEngine on @@ -79,9 +90,9 @@ Comme son nom l'indique, il s'agit de la version sur laquelle les développeurs # Installation sur Nginx -Voici un fichier de configuration pour nginx. Il couvre la configuration pour http, https et php. +Voici un fichier de configuration pour nginx. Il couvre la configuration pour HTTP, HTTPS, et PHP. -_Vous pourrez trouver d'autres fichiers de configuration plus simples mais ces derniers ne seront peut-être pas compatibles avec l'API FreshRSS._ +_Vous pourrez trouver d’autres fichiers de configuration plus simples mais ces derniers ne seront peut-être pas compatibles avec l’API FreshRSS._ ``` server { @@ -93,7 +104,7 @@ server { ssl_certificate /etc/nginx/server.crt; ssl_certificate_key /etc/nginx/server.key; - # l'url ou les urls de votre serveur + # l’URL ou les URLs de votre serveur server_name rss.example.net; # le répertoire où se trouve le dossier p de FreshRSS @@ -106,12 +117,12 @@ server { error_log /var/log/nginx/rss.error.log; # gestion des fichiers php - # il est nécessaire d'utiliser cette expression régulière pour le bon fonctionnement de l'API + # il est nécessaire d’utiliser cette expression régulière pour le bon fonctionnement de l’API location ~ ^.+?\.php(/.*)?$ { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; - # Par défaut la variable PATH_INFO n'est pas définie sous PHP-FPM - # or l'API FreshRSS greader.php en a besoin. Si vous avez un "Bad Request", vérifiez bien cette dernière ! + # Par défaut la variable PATH_INFO n’est pas définie sous PHP-FPM + # or l’API FreshRSS greader.php en a besoin. Si vous avez un “Bad Request”, vérifiez bien cette dernière ! fastcgi_param PATH_INFO $fastcgi_path_info; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; diff --git a/docs/fr/users/06_Mobile_access.md b/docs/fr/users/06_Mobile_access.md index e1a23c8ba..185c94098 100644 --- a/docs/fr/users/06_Mobile_access.md +++ b/docs/fr/users/06_Mobile_access.md @@ -1 +1,49 @@ -**TODO** +Cette page suppose que vous avez fini [l’installation du serveur](01_Installation.md). + +# Activer l’API dans FreshRSS + +1. Dans la section “Authentification”, cocher l’option “Autoriser l’accès par API (nécessaire pour les applis mobiles)”. +2. Dans la section “Profil”, remplir le champ “Mot de passe API (ex. : pour applis mobiles)”. + * Chaque utilisateur doit choisir son mot de passe API. + * La raison d’être d’un mot de passe API différent du mot de passe principal est que le mot de passe API est potentiellement utilisé de manière moins sûre, mais il permet aussi moins de choses. + + +# Tester + +3. Dans la section “Profil”, cliquer sur le lien de la forme `https://rss.example.net/api/` à côté du champ “Mot de passe API”. +4. Cliquer sur le premier lien “Check full server configuration”: + * Si vous obtenez `PASS`, tout est bon : passer à l’étape 6. + * Si vous obtenez *Bad Request!* ou *Not Found*, alors votre serveur ne semble pas accepter les slashs `/` qui sont encodés `%2F`. Passer à l’étape 5. + * Si vous obtenez un autre message d’erreur, passer à l’étape 5. + + +# Débogger la configuration du serveur + +5. Cliquer sur le second lien “Check partial server configuration (without `%2F` support)”: + * Si vous obtenez `PASS`, alors le problème est bien que votre serveur n’accepte pas les slashs `/` qui sont encodés `%2F`. + * Avec Apache, vérifiez la directive [`AllowEncodedSlashes On`](http://httpd.apache.org/docs/trunk/mod/core.html#allowencodedslashes) + * Ou utilisez un client qui n’encode pas les slashs (comme EasyRSS), auquel cas passer à l’étape 6. + * Si vous obtenez *Service Unavailable!*, retourner à l’étape 6. + * Avec __Apache__: + * Si vous obtenez *FAIL getallheaders!*, alors la combinaison de votre version de PHP et de votre serveur Web ne permet pas l’accès à [`getallheaders`](http://php.net/getallheaders) + * Utilisez au moins PHP 5.4+, ou utilisez PHP en tant que module plutôt que CGI. Sinon, activer Apache `mod_rewrite` : + * Autoriser [`FileInfo` dans `.htaccess`](http://httpd.apache.org/docs/trunk/mod/core.html#allowoverride) : revoir [l’installation du serveur](01_Installation.md). + * Activer [`mod_rewrite`](http://httpd.apache.org/docs/trunk/mod/mod_rewrite.html) : + * Sur Debian / Ubuntu : `sudo a2enmod rewrite` + * Avec __nginx__: + * Si vous obtenez *Bad Request!*, vérifier la configuration `PATH_INFO` de votre serveur. + * Si vous obtenez *File not found!*, vérifier la configuration `fastcgi_split_path_info` de votre serveur. + * Si vous obtenez *FAIL 64-bit or GMP extension!*, alors votre installation PHP soit n’est pas en 64 bit, soit n’a pas l’extension PHP [GMP](http://php.net/gmp) activée. + * Le plus simple est d’activer l’extension GMP. Sur Debian / Ubuntu : `sudo apt install php-gmp` + * Mettre à jour et retourner à l’étape 3. + + +# Clients compatibles + +Tout client supportant une API de type Google Reader. Sélection : + +* Android + * [News+](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus) avec [News+ Google Reader extension](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader) (Propriétaire) + * [EasyRSS](https://github.com/Alkarex/EasyRSS) (Libre, F-Droid) +* Linux + * [FeedReader 2.0+](https://jangernert.github.io/FeedReader/) (Libre) -- cgit v1.2.3 From bf32835db314f86e66b36f649a9d31d02e4c8a4e Mon Sep 17 00:00:00 2001 From: Frans de Jonge Date: Thu, 16 Nov 2017 20:58:46 +0100 Subject: [docs] Configuration: some stylistic improvements (#1693) The main purpose is to fix the `imapcted` typo that was exposed by https://github.com/FreshRSS/FreshRSS/issues/1259#issuecomment-345034276 --- docs/en/users/05_Configuration.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/en/users/05_Configuration.md b/docs/en/users/05_Configuration.md index f8ac56cd7..d0951e905 100644 --- a/docs/en/users/05_Configuration.md +++ b/docs/en/users/05_Configuration.md @@ -20,7 +20,7 @@ In matters of taste and color, there can be no disputes. This is why FreshRSS of If none of these are suitable for you, it is always possible to create your own. -To select a theme, simply scroll through the themes and select a theme that appears. After confirmation, the theme will be applied to the interface. +To select a theme, simply scroll through the themes and select one that strikes your fancy. After confirmation, the theme will be applied to the interface. ## Content width @@ -69,10 +69,10 @@ The duration of this notification can be set. By default, the value is 0. ### HTTP Authentication (Apache) - 1. User control is based on the .htaccess file - 2. It is best practice to place the .htaccess file in ./i/ subdirecotry so API and other third party services can work. - 3. If you want to limit all access to registered users only, place the file in the directory of FreshRSS or in a parent directory. Note that PubsubHubbub and API will not work! - 4. Example .htaccess file for a user "marie": + 1. User control is based on the `.htaccess` file. + 2. It is best practice to place the `.htaccess` file in the `./i/` subdirectory so the API and other third party services can work. + 3. If you want to limit all access to registered users only, place the file in the FreshRSS directory itself or in a parent directory. Note that PubsubHubbub and API will not work! + 4. Example `.htaccess` file for a user "marie": ``` AuthUserFile /home/marie/repertoire/.htpasswd @@ -82,7 +82,7 @@ AuthType Basic Require user marie ``` -More information can be found in [Apache documentation](http://httpd.apache.org/docs/trunk/howto/auth.html#gettingitworking). +More information can be found in the [Apache documentation](http://httpd.apache.org/docs/trunk/howto/auth.html#gettingitworking). # Subscription management @@ -104,7 +104,7 @@ More information can be found in [Apache documentation](http://httpd.apache.org/ The question comes up regularly, so we will try to clarify here how one can retrieve a truncated RSS feed with FreshRSS. Please note that the process is absolutely not "user friendly", but it works :) -Also know that this way you are generating much more traffic to the originating sites and that they can block you accordingly. The performance of FreshRSS is also imapcted because you have to fetch the contents of the articles one by one. So it's a feature to use sparingly! +Also know that this way you are generating much more traffic to the originating sites and that they might block you accordingly. The performance of FreshRSS is also negatively affected because you have to fetch the full article content one by one. So it's a feature to use sparingly! What is meant by "CSS path of articles on the original site" actually corresponds to the "path" consisting of IDs and classes (which in html, matches the id and class attributes) to retrieve only the interesting part that corresponds to the article. Ideally, this path starts with an id (which is unique to the page). @@ -118,4 +118,4 @@ We find here that the block that encompasses only the content of the article is * Rue89: ```#article .content``` * PCINpact: ```#actu_content``` -* Lesnumériques: ```article#body div.text.clearfix``` \ No newline at end of file +* Lesnumériques: ```article#body div.text.clearfix``` -- cgit v1.2.3 From d651c41e0c30ee1d17c0c51faf4c69bece8210fd Mon Sep 17 00:00:00 2001 From: Olivier DOSSMANN Date: Thu, 16 Nov 2017 18:27:11 +0100 Subject: [FIX] #1690 - Also check pdo_pgsql extension in check_install() --- lib/lib_rss.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 7381ff2bd..dd0eb11f6 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -397,12 +397,13 @@ function is_referer_from_same_domain() { */ function check_install_php() { $pdo_mysql = extension_loaded('pdo_mysql'); + $pdo_pgsql = extension_loaded('pdo_pgsql'); $pdo_sqlite = extension_loaded('pdo_sqlite'); return array( 'php' => version_compare(PHP_VERSION, '5.3.8') >= 0, 'minz' => file_exists(LIB_PATH . '/Minz'), 'curl' => extension_loaded('curl'), - 'pdo' => $pdo_mysql || $pdo_sqlite, + 'pdo' => $pdo_mysql || $pdo_sqlite || $pdo_pgsql, 'pcre' => extension_loaded('pcre'), 'ctype' => extension_loaded('ctype'), 'fileinfo' => extension_loaded('fileinfo'), -- cgit v1.2.3 From c558955a15560a83e75e7fa813bce6cb595bdf59 Mon Sep 17 00:00:00 2001 From: Olivier DOSSMANN Date: Sat, 18 Nov 2017 09:32:54 +0100 Subject: [ADD] 'blankoworld' as contributor in CREDITS --- CREDITS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.md b/CREDITS.md index cbbef73d6..605a2ff07 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -38,6 +38,7 @@ People are sorted by name so please keep this order. * [MSZ](https://github.com/mszkb): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=mszkb) * [Nicolas Elie](https://github.com/nicolaselie): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=nicolaselie) * [Nicolas Lœuillet](https://github.com/nicosomb): [contributions](https://github.com/FreshRSS/documentation/commits?author=nicosomb), [Web](http://www.loeuillet.org/) +* [Olivier Dossmann](https://github.com/blankoworld): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=blankoworld), [Web](https://olivier.dossmann.net) * [plopoyop](https://github.com/plopoyop): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=plopoyop) * [Paulius Šukys](https://github.com/psukys): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:psukys), [Web](http://sukys.eu) * [purexo](https://github.com/purexo): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:purexo), [Web](https://purexo.mom/) -- cgit v1.2.3 From 6c022aeca8ee93d396ecf8de6883ab084dfef77b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 20 Nov 2017 08:03:14 +0100 Subject: Changelog 1690 https://github.com/FreshRSS/FreshRSS/issues/1690 https://github.com/FreshRSS/FreshRSS/pull/1691 https://github.com/FreshRSS/FreshRSS/pull/1692 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f045397..23414cfef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing * Work-around for `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) + * Fix PDO PostgreSQL detection [#1690](https://github.com/FreshRSS/FreshRSS/issues/1690) * CLI * New command `./cli/db-optimize.php` for database optimisation [#1583](https://github.com/FreshRSS/FreshRSS/issues/1583) * SQL -- cgit v1.2.3 From 6c6d9bdfdcfb0155e8adfaaae679512ec819c0f9 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Fri, 1 Dec 2017 13:20:04 +0100 Subject: I18n - DE (#1698) * added missing german translations --- app/i18n/de/admin.php | 10 +++++----- app/i18n/de/gen.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index 8fc43a7bb..b5deea989 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -146,11 +146,11 @@ return array( 'top_feed' => 'Top 10-Feeds', ), 'system' => array( - '_' => 'System configuration', // @todo translate - 'auto-update-url' => 'Auto-update server URL', // @todo translate - 'instance-name' => 'Instance name', // @todo translate - 'max-categories' => 'Categories per user limit', // @todo translate - 'max-feeds' => 'Feeds per user limit', // @todo translate + '_' => 'Systemeinstellungen', + 'auto-update-url' => 'Auto-update URL', + 'instance-name' => 'Dein Reader Name', + 'max-categories' => 'Anzahl erlaubter Kategorien pro Benutzer', + 'max-feeds' => 'Anzahl erlaubter Feeds pro Benutzer', 'registration' => array( 'help' => '0 meint, dass es kein Account Limit gibt', 'number' => 'Maximale Anzahl von Accounts', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index b42081324..118de5164 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -143,7 +143,7 @@ return array( 'sharing' => 'Teilen', 'shortcuts' => 'Tastaturkürzel', 'stats' => 'Statistiken', - 'system' => 'System configuration',// @todo translate + 'system' => 'Systemeinstellungen', 'update' => 'Aktualisieren', 'user_management' => 'Benutzer verwalten', 'user_profile' => 'Profil', -- cgit v1.2.3 From aea78f4d99ff541cabc758033da1005022422fe3 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Fri, 1 Dec 2017 18:42:15 -0500 Subject: Call idn_to_ascii with INTL_IDNA_VARIANT_UTS46 Under PHP 7.2, calling `idn_to_ascii($idn)` results in a deprecation warning: 'INTL_IDNA_VARIANT_2003 is deprecated' See https://secure.php.net/manual/en/function.idn-to-ascii.php Therefore, if possible, `idn_to_ascii($idn, 0, INTL_IDNA_VARIANT_UTS46)` should be used instead. `INTL_IDNA_VARIANT_UTS46` was introduced in PHP 5.4, so on versions before that, `idn_to_ascii($idn)` must still be used. Fixed #1699 --- lib/lib_rss.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 09048700d..d62ab97a0 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -62,6 +62,12 @@ function idn_to_puny($url) { $parts = parse_url($url); if (!empty($parts['host'])) { $idn = $parts['host']; + // INTL_IDNA_VARIANT_UTS46 is defined starting in PHP 5.4 + if (defined('INTL_IDNA_VARIANT_UTS46')) { + $puny = idn_to_ascii($idn, 0, INTL_IDNA_VARIANT_UTS46); + } else { + $puny = idn_to_ascii($idn); + } $puny = idn_to_ascii($idn); $pos = strpos($url, $idn); if ($pos !== false) { -- cgit v1.2.3 From b5626391553b57d85cca87869c27ffdbdb9a0b04 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sat, 2 Dec 2017 13:43:28 +0100 Subject: Documentation updates (#1697) * added documentation about updating FreshRSS moved Installation to admin directory linked some already existing documentation files --- README.md | 2 + cli/README.md | 50 +----------- docs/en/admins/01_Index.md | 8 ++ docs/en/admins/02_Installation.md | 147 +++++++++++++++++++++++++++++++++++ docs/en/admins/03_Updating.md | 90 +++++++++++++++++++++ docs/en/contributing.md | 7 +- docs/en/developers/01_First_steps.md | 4 + docs/en/index.md | 8 +- docs/en/users/01_Installation.md | 144 ---------------------------------- docs/en/users/02_First_steps.md | 4 +- docs/en/users/06_Mobile_access.md | 4 +- 11 files changed, 267 insertions(+), 201 deletions(-) create mode 100644 docs/en/admins/01_Index.md create mode 100644 docs/en/admins/02_Installation.md create mode 100644 docs/en/admins/03_Updating.md delete mode 100644 docs/en/users/01_Installation.md diff --git a/README.md b/README.md index e59d553cf..1cf66a688 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ We are a friendly community. 6. Advanced configuration settings can be seen in [config.default.php](./config.default.php) and modified in `data/config.php`. 7. When using Apache, enable [`AllowEncodedSlashes`](http://httpd.apache.org/docs/trunk/mod/core.html#allowencodedslashes) for better compatibility with mobile clients. +More information about installation and server configuration can be found in [our documentation](https://freshrss.github.io/FreshRSS/en/admins/02_Installation.html). + ## Automated install * [![Install on Cloudron](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=org.freshrss.cloudronapp) * [![DP deploy](https://raw.githubusercontent.com/DFabric/DPlatform-ShellCore/gh-pages/img/deploy.png)](https://dfabric.github.io/DPlatform-ShellCore) diff --git a/cli/README.md b/cli/README.md index 6f907566c..b7e8ac7f5 100644 --- a/cli/README.md +++ b/cli/README.md @@ -99,51 +99,5 @@ Example to get the number of feeds of a given user: # Install and updates -## Using git - -If you manage FreshRSS via command line, then installing and updating FreshRSS can be done via git: - -```sh -# If your local user does not have write access, prefix all commands by sudo: -sudo ... - -# Install FreshRSS -cd /usr/share/ -git clone https://github.com/FreshRSS/FreshRSS.git - -# Perform all commands below in your FreshRSS directory: -cd /usr/share/FreshRSS - -# Use the development version of FreshRSS -git checkout -b dev origin/dev - -# Check out a specific version of FreshRSS -# See release names on https://github.com/FreshRSS/FreshRSS/releases -# You will then need to manually change version -# or checkout master or dev branch to get new versions -git checkout 1.7.0 - -# Verify what branch is used -git branch - -# Check whether there is a new version of FreshRSS, -# assuming you are on the /master or /dev branch -git fetch --all -git status - -# Discard manual changes (do a backup before) -git reset --hard -# Then re-delete the file forcing the setup wizard -rm data/do-install.txt - -# Delete manual additions (do a backup before) -git clean -f -d - -# Update to a newer version of FreshRSS, -# assuming you are on the /master or /dev branch -git pull - -# Set the rights so that your Web server can access the files -# (Example for Debian / Ubuntu) -chown -R :www-data . && chmod -R g+r . && chmod -R g+w ./data/ -``` +If you want to administrate FreshRSS using git, please read our [installation docs](https://freshrss.github.io/FreshRSS/en/admins/02_Installation.html) +and [update guidelines](https://freshrss.github.io/FreshRSS/en/users/08_Updating.html). \ No newline at end of file diff --git a/docs/en/admins/01_Index.md b/docs/en/admins/01_Index.md new file mode 100644 index 000000000..446780060 --- /dev/null +++ b/docs/en/admins/01_Index.md @@ -0,0 +1,8 @@ +# FreshRSS administration + +Learn how to install, update and backup FreshRSS and how to use the command line tools. + +* [Install FreshRSS](02_Installation.md) on your server +* [Update your installation](03_Updating.md) to the latest stable or dev version +* [The command line interface](https://github.com/FreshRSS/FreshRSS/tree/master/cli) can be used to administrate feeds and users +* [Automatic feed updates](https://github.com/FreshRSS/FreshRSS#automatic-feed-update) using cron is the preferred way to get the latest feeds entries diff --git a/docs/en/admins/02_Installation.md b/docs/en/admins/02_Installation.md new file mode 100644 index 000000000..ef6531bd0 --- /dev/null +++ b/docs/en/admins/02_Installation.md @@ -0,0 +1,147 @@ +# Server requirements + +FreshRSS is a web application. This means you’ll need a web server to run it. FreshRSS requirements are really low, so it could run on most shared host servers. + +You need to verify that your server can run FreshRSS before installing it. If your server has the proper requirements and FreshRSS does not work, please contact us to find a solution. + +| Software | Recommended | Works also with | +| ----------- | ---------------- | ----------------------------- | +| Web server | **Apache 2** | Nginx | +| PHP | **PHP 5.5+** | PHP 5.3.8+ | +| PHP modules | Required: libxml, cURL, PDO_MySQL, PCRE and ctype. \\ Required (32-bit only): GMP \\Recommanded: JSON, Zlib, mbstring, iconv, ZipArchive | | +| Database | **MySQL 5.0.3+** | SQLite 3.7.4+ | +| Browser | **Firefox** | Chrome, Opera, Safari, or IE11+ | + +## Important notice + +FreshRSS **CAN** work with PHP 5.3.8+. To do so, we are using specific functions available in the [''password_compat'' library](https://github.com/ircmaxell/password_compat#requirements) for the form authentication. + + +# Getting the appropriate version of FreshRSS + +FreshRSS has three different releases or branches. Each branch has its own release frequency. So it is better if you spend some time to understand the purpose of each release. + +## Stable release + +[Download](https://github.com/FreshRSS/FreshRSS/archive/master.zip) + +This release is done when we consider that our goal concerning the new features and the stability is reached. It could happen that we make two releases in a really short time if we have a really good coding pace. In reality, we are all working on our spare time, so we release every few months. But this version is really stable, tested thoroughly and you should not face any major bugs. + +## Development release + +[Download](https://github.com/FreshRSS/FreshRSS/archive/dev.zip) + +As its name suggests, it is the working release for developers. **This release is unstable!** If you want to keep track of enhancements on a daily basis, you can use it. But keep in mind that you need to follow the branch activity on Github (via [the branch RSS feed](https://github.com/FreshRSS/FreshRSS/commits/dev.atom) for instance). Some say that the main developers use it on a daily basis without problem. They may know what they are doing… + +# Apache installation + +This is an example Apache virtual hosts configuration file. It covers HTTP and HTTPS configuration. + +``` + + DocumentRoot /var/www/html/ + + #Default site... + + ErrorLog ${APACHE_LOG_DIR}/error.default.log + CustomLog ${APACHE_LOG_DIR}/access.default.log vhost_combined + + + + ServerName rss.example.net + DocumentRoot /path/to/FreshRSS/p/ + + + AllowOverride AuthConfig FileInfo Indexes Limit + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log + CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined + + AllowEncodedSlashes On + + + + + ServerName rss.example.net + DocumentRoot /path/to/FreshRSS/p/ + + + AllowOverride AuthConfig FileInfo Indexes Limit + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log + CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined + + + Protocols h2 http/1.1 + + + # For the API + AllowEncodedSlashes On + + SSLEngine on + SSLCompression off + SSLCertificateFile /path/to/server.crt + SSLCertificateKeyFile /path/to/server.key + # Additional SSL configuration, e.g. with LetsEncrypt + + +``` + +# Nginx installation + +This is an example nginx configuration file. It covers HTTP, HTTP, and php-fpm configuration. + +_You can find simpler config file but they may be incompatible with FreshRSS API._ + +``` +server { + listen 80; + listen 443 ssl; + + # HTTPS configuration + ssl on; + ssl_certificate /etc/nginx/server.crt; + ssl_certificate_key /etc/nginx/server.key; + + # your server’s URL(s) + server_name rss.example.net; + + # the folder p of your FreshRSS installation + root /srv/FreshRSS/p/; + + index index.php index.html index.htm; + + # nginx log files + access_log /var/log/nginx/rss.access.log; + error_log /var/log/nginx/rss.error.log; + + # php files handling + # this regex is mandatory because of the API + location ~ ^.+?\.php(/.*)?$ { + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + # By default, the variable PATH_INFO is not set under PHP-FPM + # But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var! + fastcgi_param PATH_INFO $fastcgi_path_info; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } + + location / { + try_files $uri $uri/ index.php; + } +} +``` + +A step-by-step tutorial is available [in French](http://www.pihomeserver.fr/2013/05/08/raspberry-pi-home-server-installer-un-agregateur-de-flux-rss-pour-remplacer-google-reader/). + +# Security + +Make sure to expose only the `./p/` folder on the web, the other directories contain personal and sensitive data. +See the Apache and nginx config examples above. + +**TODO** diff --git a/docs/en/admins/03_Updating.md b/docs/en/admins/03_Updating.md new file mode 100644 index 000000000..4e1fdfa5d --- /dev/null +++ b/docs/en/admins/03_Updating.md @@ -0,0 +1,90 @@ + +First things first: we recommend to create a backup before updating: + +```sh +# Perform all commands below in your FreshRSS directory: +cd /usr/share/FreshRSS + +tar -czvf FreshRSS-backup.tgz . +``` + +The update process depends on your installation type, see below: + + +## Using the web admin panel + +Change to your installation at http://localhost/FreshRSS/p/i/?c=update and hit the "Check for new updates" button. + +If there is a new version you will be prompted again. + + +## Using git + +If you manage FreshRSS via command line, then installing and updating FreshRSS can be done via git: + +```sh +# If your local user does not have write access, prefix all commands by sudo: +sudo ... + +# Perform all commands below in your FreshRSS directory: +cd /usr/share/FreshRSS + +# Use the development version of FreshRSS +git checkout -b dev origin/dev + +# Check out a specific version of FreshRSS +# See release names on https://github.com/FreshRSS/FreshRSS/releases +# You will then need to manually change version +# or checkout master or dev branch to get new versions +git checkout 1.7.0 + +# Verify what branch is used +git branch + +# Check whether there is a new version of FreshRSS, +# assuming you are on the /master or /dev branch +git fetch --all +git status + +# Discard manual changes (do a backup before) +git reset --hard +# Then re-delete the file forcing the setup wizard +rm data/do-install.txt + +# Delete manual additions (do a backup before) +git clean -f -d + +# Update to a newer version of FreshRSS, +# assuming you are on the /master or /dev branch +git pull + +# Set the rights so that your Web server can access the files +# (Example for Debian / Ubuntu) +chown -R :www-data . && chmod -R g+r . && chmod -R g+w ./data/ +``` + + +## Using the zip archive + +Perform all commands in your FreshRSS directory: +```sh +cd /usr/share/FreshRSS +``` + +Commands intended to be executed in order (you can c/p the whole block if desired): + +```sh +wget https://github.com/FreshRSS/FreshRSS/archive/master.zip +unzip master.zip +cp -R FreshRSS-master/* . +chown -R :www-data . && chmod -R g+r . && chmod -R g+w ./data/ +rm -f master.zip +rm -f data/do-install.txt +rm -rf FreshRSS-master/ +``` + +Short explanation of the commands above: +* Download the latest version and unzip it +* Overwrite all your existing files with the new ones +* Fix possible permission issues +* Cleanup by deleting the downloaded zip, the file forcing the setup wizard and the temporary directory diff --git a/docs/en/contributing.md b/docs/en/contributing.md index 7f0c3da6c..19f9cb9b1 100644 --- a/docs/en/contributing.md +++ b/docs/en/contributing.md @@ -32,9 +32,9 @@ Did you want to fix a bug? To keep a great coordination between collaborators, y 3. [Create a new branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/). The name of the branch must be explicit and being prefixed by the related ticket id. For instance, `783-contributing-file` to fix [ticket #783](https://github.com/FreshRSS/FreshRSS/issues/783). 4. Make your changes to your fork and [send a pull request](https://help.github.com/articles/using-pull-requests/) on the **dev branch**. -If you have to write code, please follow [our coding style recommendations](http://doc2.freshrss.org/en/Developer_documentation/First_steps/Coding_style). +If you have to write code, please follow [our coding style recommendations](developers/01_First_steps.md). -**Tip:** if you are searching for bugs easy to fix, have a look at the « [New comers](https://github.com/FreshRSS/FreshRSS/labels/New%20comers) » ticket label. +**Tip:** if you are searching for easy-to-fix bugs, have a look at the « [good first issue](https://github.com/FreshRSS/FreshRSS/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) » ticket label. ## Submit an idea @@ -52,4 +52,5 @@ We are working on a better way to handle internationalization but don't hesitate ## Contribute to documentation -The documentation needs a lot of improvements in order to be more useful to new contributors and we are working on it. If you want to give some help, meet us on [the dedicated repository](https://github.com/FreshRSS/documentation)! +The documentation needs a lot of improvements in order to be more useful to new contributors and we are working on it. +If you want to give some help, meet us in the main repositories [docs directory](https://github.com/FreshRSS/FreshRSS/tree/master/docs)! diff --git a/docs/en/developers/01_First_steps.md b/docs/en/developers/01_First_steps.md index e35dbda12..adca4495b 100644 --- a/docs/en/developers/01_First_steps.md +++ b/docs/en/developers/01_First_steps.md @@ -6,6 +6,10 @@ **TODO** +# Extensions + +If you want to create your own FreshRSS extension, take a look at the [extension documentation](03_Backend/05_Extensions.md). + # Coding style If you want to contribute to the source code, it is important to follow the project coding style. The actual code does not follow it throughout the project, but every time we have an opportunity, we should fix it. diff --git a/docs/en/index.md b/docs/en/index.md index c2f12380b..a0c97a0d9 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -16,7 +16,9 @@ FreshRSS has a lot of features including: - Multi-users so you can host your friends and your family - And a lot more! -This documentation is splitted in two sections: +This documentation is split into four sections: -- [users documentation](users/02_First_steps.md) so you can discover all the power of FreshRSS -- [developers documentation](developers/01_First_steps.md) to guide you in the source code of FreshRSS and to help you if you want to contribute +- [user documentation](users/02_First_steps.md) so you can discover all the power of FreshRSS +- [developer documentation](developers/01_First_steps.md) to guide you in the source code of FreshRSS and to help you if you want to contribute +- [administrator documentation](admins/01_Index.md) to guide you in the source code of FreshRSS and to help you if you want to contribute +- [contributor guidelines](contributing.md) for all of you who want to help improving FreshRSS diff --git a/docs/en/users/01_Installation.md b/docs/en/users/01_Installation.md deleted file mode 100644 index 9d012f2b1..000000000 --- a/docs/en/users/01_Installation.md +++ /dev/null @@ -1,144 +0,0 @@ -# Server requirements - -FreshRSS is a web application. This means you’ll need a web server to run it. FreshRSS requirements are really low, so it could run on most shared host servers. - -You need to verify that your server can run FreshRSS before installing it. If your server has the proper requirements and FreshRSS does not work, please contact us to find a solution. - -| Software | Recommended | Works also with | -| ----------- | ---------------- | ----------------------------- | -| Web server | **Apache 2** | Nginx | -| PHP | **PHP 5.5+** | PHP 5.3.8+ | -| PHP modules | Required: libxml, cURL, PDO_MySQL, PCRE and ctype. \\ Required (32-bit only): GMP \\Recommanded: JSON, Zlib, mbstring, iconv, ZipArchive | | -| Database | **MySQL 5.0.3+** | SQLite 3.7.4+ | -| Browser | **Firefox** | Chrome, Opera, Safari, or IE11+ | - -## Important notice - -FreshRSS **CAN** work with PHP 5.3.8+. To do so, we are using specific functions available in the [''password_compat'' library](https://github.com/ircmaxell/password_compat#requirements) for the form authentication. - - -# Getting the appropriate version of FreshRSS - -FreshRSS has three different releases or branches. Each branch has its own release frequency. So it is better if you spend some time to understand the purpose of each release. - -## Stable release - -[Download](https://github.com/FreshRSS/FreshRSS/archive/master.zip) - -This release is done when we consider that our goal concerning the new features and the stability is reached. It could happen that we make two releases in a really short time if we have a really good coding pace. In reality, we are all working on our spare time, so we release every few months. But this version is really stable, tested thoroughly and you should not face any major bugs. - -## Development release - -[Download](https://github.com/FreshRSS/FreshRSS/archive/dev.zip) - -As its name suggests, it is the working release for developers. **This release is unstable!** If you want to keep track of enhancements on a daily basis, you can use it. But keep in mind that you need to follow the branch activity on Github (via [the branch RSS feed](https://github.com/FreshRSS/FreshRSS/commits/dev.atom) for instance). Some say that the main developers use it on a daily basis without problem. They may know what they are doing… - -# Apache installation - -This is an example Apache virtual hosts configuration file. It covers HTTP and HTTPS configuration. - -``` - - DocumentRoot /var/www/html/ - - #Default site... - - ErrorLog ${APACHE_LOG_DIR}/error.default.log - CustomLog ${APACHE_LOG_DIR}/access.default.log vhost_combined - - - - ServerName rss.example.net - DocumentRoot /path/to/FreshRSS/p/ - - - AllowOverride AuthConfig FileInfo Indexes Limit - Require all granted - - - ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log - CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined - - AllowEncodedSlashes On - - - - - ServerName rss.example.net - DocumentRoot /path/to/FreshRSS/p/ - - - AllowOverride AuthConfig FileInfo Indexes Limit - Require all granted - - - ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log - CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined - - - Protocols h2 http/1.1 - - - # For the API - AllowEncodedSlashes On - - SSLEngine on - SSLCompression off - SSLCertificateFile /path/to/server.crt - SSLCertificateKeyFile /path/to/server.key - # Additional SSL configuration, e.g. with LetsEncrypt - - -``` - -# Nginx installation - -This is an example nginx configuration file. It covers HTTP, HTTP, and php-fpm configuration. - -_You can find simpler config file but they may be incompatible with FreshRSS API._ - -``` -server { - listen 80; - listen 443 ssl; - - # HTTPS configuration - ssl on; - ssl_certificate /etc/nginx/server.crt; - ssl_certificate_key /etc/nginx/server.key; - - # your server’s URL(s) - server_name rss.example.net; - - # the folder p of your FreshRSS installation - root /srv/FreshRSS/p/; - - index index.php index.html index.htm; - - # nginx log files - access_log /var/log/nginx/rss.access.log; - error_log /var/log/nginx/rss.error.log; - - # php files handling - # this regex is mandatory because of the API - location ~ ^.+?\.php(/.*)?$ { - fastcgi_pass unix:/var/run/php5-fpm.sock; - fastcgi_split_path_info ^(.+\.php)(/.*)$; - # By default, the variable PATH_INFO is not set under PHP-FPM - # But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var! - fastcgi_param PATH_INFO $fastcgi_path_info; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - } - - location / { - try_files $uri $uri/ index.php; - } -} -``` - -A step-by-step tutorial is available [in French](http://www.pihomeserver.fr/2013/05/08/raspberry-pi-home-server-installer-un-agregateur-de-flux-rss-pour-remplacer-google-reader/). - -# Security - -**TODO** diff --git a/docs/en/users/02_First_steps.md b/docs/en/users/02_First_steps.md index 96ee264a6..2fb1b7256 100644 --- a/docs/en/users/02_First_steps.md +++ b/docs/en/users/02_First_steps.md @@ -2,7 +2,7 @@ Learning how to handle a new application is not always easy. We build FreshRSS t This section guides you to the pages you need as a new comer. -[After you installed the application](01_Installation.md), the first step is to add one or more feeds. You have few options: +[After installing the application](../admins/02_Installation.md), the first step is to add some feeds. You have a few options: 1. [Add a feed manually](04_Subscriptions.md#adding-a-feed) 2. [Import an OPML or JSON file](04_Subscriptions.md#import-and-export) @@ -24,3 +24,5 @@ Now that you know the basic usages, it is time to configure FreshRSS to improve * [Filter articles](03_Main_view.md#filtering-articles) for a fast access to a selection * [Search an article](03_Main_view.md#searching-articles) published some time ago * [Access your feeds on a mobile device](06_Mobile_access.md) +* [Add some extensions](https://github.com/FreshRSS/Extensions) +* [Frequently asked questions](07_Frequently_Asked_Questions.md) diff --git a/docs/en/users/06_Mobile_access.md b/docs/en/users/06_Mobile_access.md index d935411eb..3472172b0 100644 --- a/docs/en/users/06_Mobile_access.md +++ b/docs/en/users/06_Mobile_access.md @@ -1,4 +1,4 @@ -This page assumes you have completed the [server setup](01_Installation.md). +This page assumes you have completed the [server setup](../admins/02_Installation.md). # Enable the API in FreshRSS @@ -27,7 +27,7 @@ This page assumes you have completed the [server setup](01_Installation.md). * With __Apache__: * If you get *FAIL getallheaders!*, the combination of your PHP version and your Web server does not provide access to [`getallheaders`](http://php.net/getallheaders) * Update to PHP 5.4+, or use PHP as module instead of CGI. Otherwise turn on Apache `mod_rewrite`: - * Allow [`FileInfo` in `.htaccess`](http://httpd.apache.org/docs/trunk/mod/core.html#allowoverride): see the [server setup](01_Installation.md) again. + * Allow [`FileInfo` in `.htaccess`](http://httpd.apache.org/docs/trunk/mod/core.html#allowoverride): see the [server setup](../admins/02_Installation.md) again. * Enable [`mod_rewrite`](http://httpd.apache.org/docs/trunk/mod/mod_rewrite.html): * With Debian / Ubuntu: `sudo a2enmod rewrite` * With __nginx__: -- cgit v1.2.3 From 8abfe1cf28b9ca4b1b53073dbb1ec24953855777 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sat, 2 Dec 2017 13:45:26 +0100 Subject: Update panel shows latest version message as success (#1701) show latest version message as success, FIXES #1586 --- app/Controllers/updateController.php | 4 ++-- app/views/update/index.phtml | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 7a8a3d6c0..c67b358bb 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -102,7 +102,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { $version = 'git'; } else { $this->view->message = array( - 'status' => 'bad', + 'status' => 'latest', 'title' => _t('gen.short.damn'), 'body' => _t('feedback.update.none') ); @@ -138,7 +138,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { $status = $res_array[0]; if (strpos($status, 'UPDATE') !== 0) { $this->view->message = array( - 'status' => 'bad', + 'status' => 'latest', 'title' => _t('gen.short.damn'), 'body' => _t('feedback.update.none') ); diff --git a/app/views/update/index.phtml b/app/views/update/index.phtml index da1bc7ef5..0599d5b0d 100644 --- a/app/views/update/index.phtml +++ b/app/views/update/index.phtml @@ -14,7 +14,21 @@

message)) { ?> -

+ message['status']) { + case 'bad': + $class = 'alert-error'; + break; + case 'latest': + $class = 'alert-success'; + break; + default: + $class = 'alert-warn'; + break; + } + ?> +

message['title']; ?> message['body']; ?>

-- cgit v1.2.3 From 1cf545342e4b89510fbd8517b638c6133d3e2c07 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 2 Dec 2017 14:03:19 +0100 Subject: Remove forgotten punycode line --- lib/lib_rss.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/lib_rss.php b/lib/lib_rss.php index d62ab97a0..8dfad7861 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -68,7 +68,6 @@ function idn_to_puny($url) { } else { $puny = idn_to_ascii($idn); } - $puny = idn_to_ascii($idn); $pos = strpos($url, $idn); if ($pos !== false) { return substr_replace($url, $puny, $pos, strlen($idn)); -- cgit v1.2.3 From 3814dd6613f5525d62a407de11f9edbcf76f0e83 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 2 Dec 2017 14:06:07 +0100 Subject: Credits Craig Andrews --- CREDITS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.md b/CREDITS.md index cbbef73d6..ed7efe035 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -13,6 +13,7 @@ People are sorted by name so please keep this order. * [Amaury Carrade](https://github.com/AmauryCarrade): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=AmauryCarrade), [Web](https://amaury.carrade.eu/) * [Anton Smirnov](https://github.com/sandfoxme): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:sandfoxme), [Web](http://sandfox.me/) * [ASMfreaK](https://github.com/ASMfreaK): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=ASMfreaK) +* [Craig Andrews](https://github.com/candrews): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:candrews), [Web](http://candrews.integralblue.com/) * [Crupuk](https://github.com/Crupuk): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:Crupuk) * [Damstre](https://github.com/Damstre): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:Damstre) * [danc](https://github.com/danc): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=danc), [Web](http://tintouli.free.fr/) -- cgit v1.2.3 From e16a20c8925c5aaf737e94f45ebf5a0508f108de Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 2 Dec 2017 14:12:55 +0100 Subject: Changelog 1586 1698 1699 https://github.com/FreshRSS/FreshRSS/issues/1586 https://github.com/FreshRSS/FreshRSS/pull/1701 https://github.com/FreshRSS/FreshRSS/pull/1698 https://github.com/FreshRSS/FreshRSS/issues/1699 https://github.com/FreshRSS/FreshRSS/pull/1700 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23414cfef..9e3b143dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,15 +8,19 @@ * Share with Mastodon [#1521](https://github.com/FreshRSS/FreshRSS/issues/1521) * UI * Show URL to add subscriptions from third-party tools [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) + * Improved message when checking for new versions [#1586](https://github.com/FreshRSS/FreshRSS/issues/1586) * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing * Work-around for `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) * Fix PDO PostgreSQL detection [#1690](https://github.com/FreshRSS/FreshRSS/issues/1690) + * Fix punycode warning in PHP 7.2 [#1699](https://github.com/FreshRSS/FreshRSS/issues/1699) * CLI * New command `./cli/db-optimize.php` for database optimisation [#1583](https://github.com/FreshRSS/FreshRSS/issues/1583) * SQL * Perform `VACUUM` on SQLite and PostgreSQL databases when optimisation is requested [#918](https://github.com/FreshRSS/FreshRSS/issues/918) +* I18n + * Improved German [#1698](https://github.com/FreshRSS/FreshRSS/pull/1698) * Misc. * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) -- cgit v1.2.3 From ac73ba3accd8f5638b330002d002460067c4e012 Mon Sep 17 00:00:00 2001 From: Pavel Pletenev Date: Sat, 2 Dec 2017 21:01:29 +0300 Subject: Add more glyphs for opensans font (#1032) * Add more glyphs for opensans font * Update .htaccess to support woff2 file format * Fixed browser support for new font face * Fixed Origine theme css and .htaccess * Deleted unneeded fonts * Added stylefiles for OpenSans font * Fixed all themes with new font css * Avoid additional CSS file * htaccess cache control public * Font casing bug * Remove TTF font Too big, low need https://caniuse.com/#search=woff * Changelog 1032 https://github.com/FreshRSS/FreshRSS/pull/1032 https://github.com/FreshRSS/FreshRSS/pull/1028 --- CHANGELOG.md | 1 + p/.htaccess | 9 ++++++++- p/themes/BlueLagoon/BlueLagoon.css | 6 ------ p/themes/Dark/dark.css | 6 ------ p/themes/Flat/flat.css | 6 ------ p/themes/Origine/origine.css | 6 ------ p/themes/Pafat/pafat.css | 8 +------- p/themes/Screwdriver/screwdriver.css | 6 ------ p/themes/base-theme/base.css | 6 ------ p/themes/base-theme/template.css | 10 ++++++++++ p/themes/fonts/OpenSans.woff | Bin 0 -> 67528 bytes p/themes/fonts/OpenSans.woff2 | Bin 0 -> 61980 bytes p/themes/fonts/openSans.woff | Bin 21956 -> 0 bytes 13 files changed, 20 insertions(+), 44 deletions(-) create mode 100644 p/themes/fonts/OpenSans.woff create mode 100644 p/themes/fonts/OpenSans.woff2 delete mode 100644 p/themes/fonts/openSans.woff diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e3b143dd..f5b3b06b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Features * Share with Mastodon [#1521](https://github.com/FreshRSS/FreshRSS/issues/1521) * UI + * Add more Unicode glyphs in the Open Sans font [#1032](https://github.com/FreshRSS/FreshRSS/pull/1032) * Show URL to add subscriptions from third-party tools [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) * Improved message when checking for new versions [#1586](https://github.com/FreshRSS/FreshRSS/issues/1586) * SimplePie diff --git a/p/.htaccess b/p/.htaccess index 4321c82d7..74ba7ed11 100644 --- a/p/.htaccess +++ b/p/.htaccess @@ -6,6 +6,11 @@ FileETag None AddDefaultCharset UTF-8 + AddType application/json .map + AddType application/font-woff .woff + AddType application/font-woff2 .woff2 + + AddCharset UTF-8 .css AddCharset UTF-8 .html AddCharset UTF-8 .js @@ -16,6 +21,8 @@ AddDefaultCharset UTF-8 ExpiresActive on + ExpiresByType application/font-woff "access plus 1 month" + ExpiresByType application/font-woff2 "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ExpiresByType application/xhtml+xml "access plus 1 month" ExpiresByType image/x-icon "access plus 1 month" @@ -27,7 +34,7 @@ AddDefaultCharset UTF-8 - + Header merge Cache-Control "public" diff --git a/p/themes/BlueLagoon/BlueLagoon.css b/p/themes/BlueLagoon/BlueLagoon.css index 150e27908..186258752 100644 --- a/p/themes/BlueLagoon/BlueLagoon.css +++ b/p/themes/BlueLagoon/BlueLagoon.css @@ -1,11 +1,5 @@ @charset "UTF-8"; -/*=== FONTS */ -@font-face { - font-family: "OpenSans"; - src: url("../fonts/openSans.woff") format("woff"); -} - /*=== GENERAL */ /*============*/ html, body { diff --git a/p/themes/Dark/dark.css b/p/themes/Dark/dark.css index d8415ef25..348b00009 100644 --- a/p/themes/Dark/dark.css +++ b/p/themes/Dark/dark.css @@ -1,11 +1,5 @@ @charset "UTF-8"; -/*=== FONTS */ -@font-face { - font-family: "OpenSans"; - src: url("../fonts/openSans.woff") format("woff"); -} - /*=== GENERAL */ /*============*/ html, body { diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index 0240fe4b4..62c4808a4 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -1,11 +1,5 @@ @charset "UTF-8"; -/*=== FONTS */ -@font-face { - font-family: "OpenSans"; - src: url("../fonts/openSans.woff") format("woff"); -} - /*=== GENERAL */ /*============*/ html, body { diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index becf3f433..4a697e811 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -1,11 +1,5 @@ @charset "UTF-8"; -/*=== FONTS */ -@font-face { - font-family: "OpenSans"; - src: url("../fonts/openSans.woff") format("woff"); -} - /*=== GENERAL */ /*============*/ html, body { diff --git a/p/themes/Pafat/pafat.css b/p/themes/Pafat/pafat.css index 23bc6671d..1b6ebca29 100644 --- a/p/themes/Pafat/pafat.css +++ b/p/themes/Pafat/pafat.css @@ -1,11 +1,5 @@ @charset "UTF-8"; -/*=== FONTS */ -@font-face { - font-family: "OpenSans"; - src: url("../fonts/openSans.woff") format("woff"); -} - /*=== GENERAL */ /*============*/ html, body { @@ -1069,4 +1063,4 @@ a.btn { .notification a.close .icon { display: none; } -} \ No newline at end of file +} diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index b2c539b13..969695f13 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -1,11 +1,5 @@ @charset "UTF-8"; -/*=== FONTS */ -@font-face { - font-family: "OpenSans"; - src: url("../fonts/openSans.woff") format("woff"); -} - /*=== GENERAL */ /*============*/ html, body { diff --git a/p/themes/base-theme/base.css b/p/themes/base-theme/base.css index 1bf73d8b3..e265cd7ff 100644 --- a/p/themes/base-theme/base.css +++ b/p/themes/base-theme/base.css @@ -1,11 +1,5 @@ @charset "UTF-8"; -/*=== FONTS */ -@font-face { - font-family: "OpenSans"; - src: url("../fonts/openSans.woff") format("woff"); -} - /*=== GENERAL */ /*============*/ html, body { diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 320ad2d9b..e5e1bca05 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -2,9 +2,19 @@ /*=== GENERAL */ /*============*/ +@font-face { + font-family: 'OpenSans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans'), local('OpenSans'), + url('../fonts/OpenSans.woff2') format('woff2'), + url('../fonts/OpenSans.woff') format('woff'); +} + html, body { margin: 0; padding: 0; + font-family: "OpenSans", "Cantarell", "Helvetica", "Arial", sans-serif; font-size: 100%; } diff --git a/p/themes/fonts/OpenSans.woff b/p/themes/fonts/OpenSans.woff new file mode 100644 index 000000000..9a96e3baf Binary files /dev/null and b/p/themes/fonts/OpenSans.woff differ diff --git a/p/themes/fonts/OpenSans.woff2 b/p/themes/fonts/OpenSans.woff2 new file mode 100644 index 000000000..0964c7c46 Binary files /dev/null and b/p/themes/fonts/OpenSans.woff2 differ diff --git a/p/themes/fonts/openSans.woff b/p/themes/fonts/openSans.woff deleted file mode 100644 index 55b25f867..000000000 Binary files a/p/themes/fonts/openSans.woff and /dev/null differ -- cgit v1.2.3 From 4f06b17e005456515768f46b3cc3130428f579bf Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 3 Dec 2017 17:30:02 +0100 Subject: Extension function to override entry hash (#1707) Extension function to override entry hash https://github.com/FreshRSS/FreshRSS/issues/1706 --- CHANGELOG.md | 2 ++ app/Models/Entry.php | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5b3b06b4..c7fec5334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ * Perform `VACUUM` on SQLite and PostgreSQL databases when optimisation is requested [#918](https://github.com/FreshRSS/FreshRSS/issues/918) * I18n * Improved German [#1698](https://github.com/FreshRSS/FreshRSS/pull/1698) +* Extensions + * New function `$entry->_hash($hex)` for extensios that change the content of entries [#1707](https://github.com/FreshRSS/FreshRSS/pull/1707) * Misc. * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) diff --git a/app/Models/Entry.php b/app/Models/Entry.php index df3d59bea..0ad3781e5 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -97,6 +97,14 @@ class FreshRSS_Entry extends Minz_Model { return $this->hash; } + public function _hash($value) { + $value = trim($value); + if (ctype_xdigit($value)) { + $this->hash = substr($value, 0, 32); + } + return $this->hash; + } + public function _id($value) { $this->id = $value; } -- cgit v1.2.3 From 3902d3f43330504945e78627b4c49e67ae88aea9 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Wed, 6 Dec 2017 21:04:45 +0100 Subject: Show existing extensions in admin panel (#1708) * first draft * display installed extension state * fixed whitespace vs tabs * added translation in all languages * added error checks and log messages * fixed tabs vs whitespace * another try in fixing whitespaces * another try in fixing whitespaces * improved extension list translations * using JSON from official extension repo * improved version compare * updated translations * French translation --- app/Controllers/extensionController.php | 37 +++++++++++++++++++++++++++++++++ app/i18n/cz/admin.php | 7 +++++++ app/i18n/de/admin.php | 7 +++++++ app/i18n/en/admin.php | 7 +++++++ app/i18n/es/admin.php | 7 +++++++ app/i18n/fr/admin.php | 13 +++++++++--- app/i18n/it/admin.php | 7 +++++++ app/i18n/kr/admin.php | 7 +++++++ app/i18n/nl/admin.php | 7 +++++++ app/i18n/pt-br/admin.php | 7 +++++++ app/i18n/ru/admin.php | 7 +++++++ app/i18n/tr/admin.php | 7 +++++++ app/i18n/zh-cn/admin.php | 7 +++++++ app/views/extension/index.phtml | 37 +++++++++++++++++++++++++++++++-- 14 files changed, 159 insertions(+), 5 deletions(-) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index b6d2d3fe4..bb846e921 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -25,10 +25,47 @@ class FreshRSS_extension_Controller extends Minz_ActionController { 'user' => array(), ); + $this->view->extensions_installed = array(); + $extensions = Minz_ExtensionManager::listExtensions(); foreach ($extensions as $ext) { $this->view->extension_list[$ext->getType()][] = $ext; + $this->view->extensions_installed[$ext->getEntrypoint()] = $ext->getVersion(); + } + + $availableExtensions = $this->getAvailableExtensionList(); + $this->view->available_extensions = $availableExtensions; + } + + /** + * fetch extension list from GitHub + */ + protected function getAvailableExtensionList() { + $extensionListUrl = 'https://raw.githubusercontent.com/FreshRSS/Extensions/master/extensions.json'; + $json = file_get_contents($extensionListUrl); + + // we ran into problems, simply ignore them + if ($json === false) { + Minz_Log::error('Could not fetch available extension from GitHub'); + return array(); + } + + // fetch the list as an array + $list = json_decode($json, true); + if (empty($list)) { + Minz_Log::warning('Failed to convert extension file list'); + return array(); } + + // we could use that for comparing and caching later + $version = $list['version']; + + // By now, all the needed data is kept in the main extension file. + // In the future we could fetch detail information from the extensions metadata.json, but I tend to stick with + // the current implementation for now, unless it becomes too much effort maintain the extension list manually + $extensions = $list['extensions']; + + return $extensions; } /** diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index 63cee3cca..dbfebd4c9 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -155,6 +155,13 @@ return array( 'help' => '0 znamená žádná omezení účtu', 'number' => 'Maximální počet účtů', ), + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'update' => array( '_' => 'Aktualizace systému', diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index b5deea989..bb2c9352d 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Erweiterungen', 'user' => 'Benutzer-Erweiterungen', + 'community' => 'Verfügbare Community Erweiterungen', + 'name' => 'Name', + 'version' => 'Version', + 'description' => 'Beschreibungen', + 'author' => 'Autor', + 'latest' => 'Installiert', + 'update' => 'Update verfügbar', ), 'stats' => array( '_' => 'Statistiken', diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index 707627782..d92a016af 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Extensions', 'user' => 'User extensions', + 'community' => 'Available community extensions', + 'name' => 'Name', + 'version' => 'Version', + 'description' => 'Description', + 'author' => 'Author', + 'latest' => 'Installed', + 'update' => 'Update available' ), 'stats' => array( '_' => 'Statistics', diff --git a/app/i18n/es/admin.php b/app/i18n/es/admin.php index c9d9368eb..93b1e6e5c 100755 --- a/app/i18n/es/admin.php +++ b/app/i18n/es/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Extensiones', 'user' => 'Extensiones de usuario', + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'stats' => array( '_' => 'Estadísticas', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index 9a13ecc21..b2bc48209 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -103,15 +103,22 @@ return array( ), 'extensions' => array( 'disabled' => 'Désactivée', - 'empty_list' => 'Il n’y a aucune extension installée.', + 'empty_list' => 'Aucune extension installée', 'enabled' => 'Activée', - 'no_configure_view' => 'Cette extension ne peut pas être configurée.', + 'no_configure_view' => 'Cette extension n’a pas à être configurée', 'system' => array( '_' => 'Extensions système', - 'no_rights' => 'Extension système (vous n’avez aucun droit dessus)', + 'no_rights' => 'Extensions système (contrôlées par l’administrateur)', ), 'title' => 'Extensions', 'user' => 'Extensions utilisateur', + 'community' => 'Extensions utilisateur disponibles', + 'name' => 'Nom', + 'version' => 'Version', + 'description' => 'Description', + 'author' => 'Auteur', + 'latest' => 'Installée', + 'update' => 'Mise à jour disponible', ), 'stats' => array( '_' => 'Statistiques', diff --git a/app/i18n/it/admin.php b/app/i18n/it/admin.php index ae46818ae..0248d9317 100644 --- a/app/i18n/it/admin.php +++ b/app/i18n/it/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Estensioni', 'user' => 'Estensioni utente', + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'stats' => array( '_' => 'Statistiche', diff --git a/app/i18n/kr/admin.php b/app/i18n/kr/admin.php index 13f4695e1..9781fb640 100644 --- a/app/i18n/kr/admin.php +++ b/app/i18n/kr/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => '확장 기능', 'user' => '사용자 확장 기능', + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'stats' => array( '_' => '통계', diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php index fdfe6e3bc..384242b4d 100644 --- a/app/i18n/nl/admin.php +++ b/app/i18n/nl/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Uitbreidingen', 'user' => 'Gebruikersuitbreidingen', + 'community' => 'Gebruikersuitbreidingen beschikbaar', + 'name' => 'Naam', + 'version' => 'Versie', + 'description' => 'Beschrijving', + 'author' => 'Auteur', + 'latest' => 'Geïnstalleerd', + 'update' => 'Update beschikbaar', ), 'stats' => array( '_' => 'Statistieken', diff --git a/app/i18n/pt-br/admin.php b/app/i18n/pt-br/admin.php index 1076534b2..e62718e80 100644 --- a/app/i18n/pt-br/admin.php +++ b/app/i18n/pt-br/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Extensões', 'user' => 'Extensões do usuário', + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'stats' => array( '_' => 'Estatísticas', diff --git a/app/i18n/ru/admin.php b/app/i18n/ru/admin.php index f5da97371..d877c5006 100644 --- a/app/i18n/ru/admin.php +++ b/app/i18n/ru/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Расширения', 'user' => 'Расширения пользователя', + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'stats' => array( '_' => 'Статистика', diff --git a/app/i18n/tr/admin.php b/app/i18n/tr/admin.php index 9d10ef9dd..aa3aad7b7 100644 --- a/app/i18n/tr/admin.php +++ b/app/i18n/tr/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => 'Eklentiler', 'user' => 'Kullanıcı eklentileri', + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'stats' => array( '_' => 'İstatistikler', diff --git a/app/i18n/zh-cn/admin.php b/app/i18n/zh-cn/admin.php index 4ecc52e64..ca18bf63d 100644 --- a/app/i18n/zh-cn/admin.php +++ b/app/i18n/zh-cn/admin.php @@ -112,6 +112,13 @@ return array( ), 'title' => '扩展', 'user' => '用户扩展', + 'community' => 'Available community extensions', // @todo translate + 'name' => 'Name', // @todo translate + 'version' => 'Version', // @todo translate + 'description' => 'Description', // @todo translate + 'author' => 'Author', // @todo translate + 'latest' => 'Installed', // @todo translate + 'update' => 'Update available', // @todo translate ), 'stats' => array( '_' => '统计', diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml index 7cb16bfff..6439a0333 100644 --- a/app/views/extension/index.phtml +++ b/app/views/extension/index.phtml @@ -26,13 +26,46 @@ } ?> extension_list['system']) && empty($this->extension_list['user'])) { + if (empty($this->extension_list['system']) && empty($this->extension_list['user'])) { ?>

+ + available_extensions)) { ?> +

+ + + + + + + + available_extensions as $ext) { ?> + + + + + + + +
+ + extensions_installed[$ext['name']])) { ?> + extensions_installed[$ext['name']], $ext['version']) >= 0) { ?> + + + + extensions_installed[$ext['name']] != $ext['version']) { ?> + + + + + +
+
extension) ? ' class="active"' : ''; ?> -- cgit v1.2.3 From a96b751d319665c6702bcf60feffdcf56694003a Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Fri, 8 Dec 2017 17:08:41 +0100 Subject: make sure that we do not exceed a certain file size for the users log file --- lib/Minz/Log.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index 9559a0bd4..72947272e 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -20,6 +20,8 @@ class Minz_Log { const NOTICE = 8; const DEBUG = 16; + const MAX_LOG_SIZE = 512000; // 500kB + /** * Enregistre un message dans un fichier de log spécifique * Message non loggué si @@ -29,6 +31,7 @@ class Minz_Log { * @param $information message d'erreur / information à enregistrer * @param $level niveau d'erreur * @param $file_name fichier de log + * @throws Minz_PermissionDeniedException */ public static function record ($information, $level, $file_name = null) { try { @@ -70,12 +73,31 @@ class Minz_Log { . ' [' . $level_label . ']' . ' --- ' . $information . "\n"; + self::checkForLogfileSize($file_name); + if (file_put_contents($file_name, $log, FILE_APPEND | LOCK_EX) === false) { throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); } } } + /** + * Make sure we do not waste a huge amount of disk space with old log messages. + * + * This method can be called multiple times for one script execution, but its result will not change unless + * you call clearstatcache() in between. We won't due do that for performance reasons. + * + * @param $file_name + * @throws Minz_PermissionDeniedException + */ + protected static function checkForLogfileSize($file_name) { + if (file_exists($file_name) && filesize($file_name) > self::MAX_LOG_SIZE) { + if (!unlink($file_name)) { + throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); + } + } + } + /** * Automatise le log des variables globales $_GET et $_POST * Fait appel à la fonction record(...) -- cgit v1.2.3 From 0480d4331cb3e21279220c7cd7b7486bd63d5412 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Fri, 8 Dec 2017 21:18:07 +0100 Subject: renamed method --- lib/Minz/Log.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index 72947272e..f7029f47d 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -73,7 +73,7 @@ class Minz_Log { . ' [' . $level_label . ']' . ' --- ' . $information . "\n"; - self::checkForLogfileSize($file_name); + self::checkLogfileSize($file_name); if (file_put_contents($file_name, $log, FILE_APPEND | LOCK_EX) === false) { throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); @@ -90,7 +90,7 @@ class Minz_Log { * @param $file_name * @throws Minz_PermissionDeniedException */ - protected static function checkForLogfileSize($file_name) { + protected static function checkLogfileSize($file_name) { if (file_exists($file_name) && filesize($file_name) > self::MAX_LOG_SIZE) { if (!unlink($file_name)) { throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); -- cgit v1.2.3 From 452886ea3ac4b91bc72952df659fb53ae7807c22 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sat, 9 Dec 2017 13:52:05 +0100 Subject: incorporated code review feedback --- constants.php | 3 +++ lib/Minz/Log.php | 7 +++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/constants.php b/constants.php index 9c647eb74..b48c1be96 100644 --- a/constants.php +++ b/constants.php @@ -8,6 +8,9 @@ define('FRESHRSS_USERAGENT', 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; // PHP text output compression http://php.net/ob_gzhandler (better to do it at Web server level) define('PHP_COMPRESSION', false); +// maximum log file size, before it will be purged (defaults to 512000 = 500kB) +define('MAX_LOG_SIZE', 512000); + // Constantes de chemins define('FRESHRSS_PATH', dirname(__FILE__)); diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index f7029f47d..6231754fa 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -20,8 +20,6 @@ class Minz_Log { const NOTICE = 8; const DEBUG = 16; - const MAX_LOG_SIZE = 512000; // 500kB - /** * Enregistre un message dans un fichier de log spécifique * Message non loggué si @@ -91,8 +89,9 @@ class Minz_Log { * @throws Minz_PermissionDeniedException */ protected static function checkLogfileSize($file_name) { - if (file_exists($file_name) && filesize($file_name) > self::MAX_LOG_SIZE) { - if (!unlink($file_name)) { + $maxSize = defined('MAX_LOG_SIZE') ? MAX_LOG_SIZE : 512000; + if (@filesize($file_name) > $maxSize) { + if (file_put_contents($file_name, '') === false) { throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); } } -- cgit v1.2.3 From b1c317a253445a6458f1263c1b622a788cc7cd0e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 10 Dec 2017 21:31:41 +0100 Subject: Log rotation, use Minz_Log, new log constants ADMIN_LOG, API_LOG, PSHB_LOG --- app/Controllers/feedController.php | 4 ++-- app/Models/Feed.php | 14 +++++------- app/Models/LogDAO.php | 6 ++--- app/actualize_script.php | 13 ++++------- constants.php | 7 ++++-- lib/Minz/Log.php | 22 ++++++++++++++---- p/api/greader.php | 47 +++++++++----------------------------- p/api/pshb.php | 40 +++++++++++++++----------------- 8 files changed, 66 insertions(+), 87 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 45cba9e98..883f7af05 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -263,7 +263,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ((!$simplePiePush) && (!$feed_id) && $pubSubHubbubEnabled && ($feed->lastUpdate() > $pshbMinAge)) { //$text = 'Skip pull of feed using PubSubHubbub: ' . $url; //Minz_Log::debug($text); - //file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); + //Minz_Log::debug($text, PSHB_LOG); continue; //When PubSubHubbub is used, do not pull refresh so often } @@ -371,7 +371,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($pubSubHubbubEnabled && !$simplePiePush) { //We use push, but have discovered an article by pull! $text = 'An article was discovered by pull although we use PubSubHubbub!: Feed ' . $url . ' GUID ' . $entry->guid(); - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); + Minz_Log::warning($text, PSHB_LOG); Minz_Log::warning($text); $pubSubHubbubEnabled = false; $feed->pubSubHubbubError(true); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 85273d3f7..75d9f6d6f 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -403,8 +403,7 @@ class FreshRSS_Feed extends Minz_Model { if (!isset($hubJson['error']) || $hubJson['error'] !== (bool)$error) { $hubJson['error'] = (bool)$error; file_put_contents($hubFilename, json_encode($hubJson)); - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" - . 'Set error to ' . ($error ? 1 : 0) . ' for ' . $url . "\n", FILE_APPEND); + Minz_Log::warning('Set error to ' . ($error ? 1 : 0) . ' for ' . $url, PSHB_LOG); } return false; } @@ -419,7 +418,7 @@ class FreshRSS_Feed extends Minz_Model { if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) { $text = 'Invalid JSON for PubSubHubbub: ' . $this->url; Minz_Log::warning($text); - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); + Minz_Log::warning($text, PSHB_LOG); return false; } if ((!empty($hubJson['lease_end'])) && ($hubJson['lease_end'] < (time() + (3600 * 23)))) { //TODO: Make a better policy @@ -427,7 +426,7 @@ class FreshRSS_Feed extends Minz_Model { . date('c', empty($hubJson['lease_end']) ? time() : $hubJson['lease_end']) . ' and needs renewal: ' . $this->url; Minz_Log::warning($text); - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); + Minz_Log::warning($text, PSHB_LOG); $key = $hubJson['key']; //To renew our lease } elseif (((!empty($hubJson['error'])) || empty($hubJson['lease_end'])) && (empty($hubJson['lease_start']) || $hubJson['lease_start'] < time() - (3600 * 23))) { //Do not renew too often @@ -445,7 +444,7 @@ class FreshRSS_Feed extends Minz_Model { file_put_contents(PSHB_PATH . '/keys/' . $key . '.txt', base64url_encode($this->selfUrl)); $text = 'PubSubHubbub prepared for ' . $this->url; Minz_Log::debug($text); - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); + Minz_Log::debug($text, PSHB_LOG); } $currentUser = Minz_Session::param('currentUser'); if (FreshRSS_user_Controller::checkUsername($currentUser) && !file_exists($path . '/' . $currentUser . '.txt')) { @@ -499,9 +498,8 @@ class FreshRSS_Feed extends Minz_Model { $response = curl_exec($ch); $info = curl_getinfo($ch); - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . - 'PubSubHubbub ' . ($state ? 'subscribe' : 'unsubscribe') . ' to ' . $url . - ' with callback ' . $callbackUrl . ': ' . $info['http_code'] . ' ' . $response . "\n", FILE_APPEND); + Minz_Log::warning('PubSubHubbub ' . ($state ? 'subscribe' : 'unsubscribe') . ' to ' . $url . + ' with callback ' . $callbackUrl . ': ' . $info['http_code'] . ' ' . $response, PSHB_LOG); if (substr($info['http_code'], 0, 1) == '2') { return true; diff --git a/app/Models/LogDAO.php b/app/Models/LogDAO.php index ab258cd58..5bce466d5 100644 --- a/app/Models/LogDAO.php +++ b/app/Models/LogDAO.php @@ -22,9 +22,9 @@ class FreshRSS_LogDAO { public static function truncate() { file_put_contents(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'), ''); if (FreshRSS_Auth::hasAccess('admin')) { - file_put_contents(join_path(DATA_PATH, 'users', '_', 'log.txt'), ''); - file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_api.txt'), ''); - file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_pshb.txt'), ''); + file_put_contents(ADMIN_LOG, ''); + file_put_contents(API_LOG, ''); + file_put_contents(PSHB_LOG, ''); } } } diff --git a/app/actualize_script.php b/app/actualize_script.php index deaa1bf7c..d4908d3ea 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -20,10 +20,6 @@ $_GET['ajax'] = 1; $_GET['force'] = true; $_SERVER['HTTP_HOST'] = ''; - -$log_file = join_path(USERS_PATH, '_', 'log.txt'); - - $app = new FreshRSS(); $system_conf = Minz_Configuration::get('system'); @@ -45,13 +41,13 @@ $min_last_activity = time() - $limits['max_inactivity']; foreach ($users as $user) { if (($user !== $system_conf->default_user) && (FreshRSS_UserDAO::mtime($user) < $min_last_activity)) { - Minz_Log::notice('FreshRSS skip inactive user ' . $user, $log_file); + Minz_Log::notice('FreshRSS skip inactive user ' . $user, ADMIN_LOG); if (defined('STDOUT')) { fwrite(STDOUT, 'FreshRSS skip inactive user ' . $user . "\n"); //Unbuffered } continue; } - Minz_Log::notice('FreshRSS actualize ' . $user, $log_file); + Minz_Log::notice('FreshRSS actualize ' . $user, ADMIN_LOG); if (defined('STDOUT')) { fwrite(STDOUT, 'Actualize ' . $user . "...\n"); //Unbuffered } @@ -66,8 +62,7 @@ foreach ($users as $user) { if (!invalidateHttpCache()) { - Minz_Log::notice('FreshRSS write access problem in ' . join_path(USERS_PATH, $user, 'log.txt'), - $log_file); + Minz_Log::warning('FreshRSS write access problem in ' . join_path(USERS_PATH, $user, 'log.txt'), ADMIN_LOG); if (defined('STDERR')) { fwrite(STDERR, 'Write access problem in ' . join_path(USERS_PATH, $user, 'log.txt') . "\n"); } @@ -75,7 +70,7 @@ foreach ($users as $user) { } -Minz_Log::notice('FreshRSS actualize done.', $log_file); +Minz_Log::notice('FreshRSS actualize done.', ADMIN_LOG); if (defined('STDOUT')) { fwrite(STDOUT, 'Done.' . "\n"); $end_date = date_create('now'); diff --git a/constants.php b/constants.php index b48c1be96..576be09b9 100644 --- a/constants.php +++ b/constants.php @@ -8,8 +8,8 @@ define('FRESHRSS_USERAGENT', 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; // PHP text output compression http://php.net/ob_gzhandler (better to do it at Web server level) define('PHP_COMPRESSION', false); -// maximum log file size, before it will be purged (defaults to 512000 = 500kB) -define('MAX_LOG_SIZE', 512000); +// Maximum log file size in Bytes, before it will be divided by two +define('MAX_LOG_SIZE', 1048576); // Constantes de chemins define('FRESHRSS_PATH', dirname(__FILE__)); @@ -22,7 +22,10 @@ define('FRESHRSS_PATH', dirname(__FILE__)); define('DATA_PATH', FRESHRSS_PATH . '/data'); define('UPDATE_FILENAME', DATA_PATH . '/update.php'); define('USERS_PATH', DATA_PATH . '/users'); + define('ADMIN_LOG', USERS_PATH . '/_/log.txt'); + define('API_LOG', USERS_PATH . '/_/log_api.txt'); define('CACHE_PATH', DATA_PATH . '/cache'); + define('PSHB_LOG', USERS_PATH . '/_/log_pshb.txt'); define('PSHB_PATH', DATA_PATH . '/PubSubHubbub'); define('LIB_PATH', FRESHRSS_PATH . '/lib'); diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index 6231754fa..5e7831cdb 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -71,7 +71,7 @@ class Minz_Log { . ' [' . $level_label . ']' . ' --- ' . $information . "\n"; - self::checkLogfileSize($file_name); + self::ensureMaxLogSize($file_name); if (file_put_contents($file_name, $log, FILE_APPEND | LOCK_EX) === false) { throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); @@ -88,12 +88,24 @@ class Minz_Log { * @param $file_name * @throws Minz_PermissionDeniedException */ - protected static function checkLogfileSize($file_name) { - $maxSize = defined('MAX_LOG_SIZE') ? MAX_LOG_SIZE : 512000; - if (@filesize($file_name) > $maxSize) { - if (file_put_contents($file_name, '') === false) { + protected static function ensureMaxLogSize($file_name) { + $maxSize = defined('MAX_LOG_SIZE') ? MAX_LOG_SIZE : 1048576; + if ($maxSize > 0 && @filesize($file_name) > $maxSize) { + $fp = fopen($file_name, 'c+'); + if ($fp && flock($fp, LOCK_EX)) { + fseek($fp, -intval($maxSize / 2), SEEK_END); + $content = fread($fp, $maxSize); + rewind($fp); + ftruncate($fp, 0); + fwrite($fp, $content ? $content : ''); + fflush($fp); + flock($fp, LOCK_UN); + } else { throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); } + if ($fp) { + fclose($fp); + } } } diff --git a/p/api/greader.php b/p/api/greader.php index f086ee442..b27f5bd43 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -78,10 +78,6 @@ class MyPDO extends Minz_ModelPdo { } } -function logMe($text) { - file_put_contents(join_path(USERS_PATH, '_', 'log_api.txt'), date('c') . "\t" . $text . "\n", FILE_APPEND); -} - function debugInfo() { if (function_exists('getallheaders')) { $ALL_HEADERS = getallheaders(); @@ -107,16 +103,14 @@ function debugInfo() { } function badRequest() { - logMe("badRequest()"); - logMe(debugInfo()); + Minz_Log::warning('badRequest() ' . debugInfo(), API_LOG); header('HTTP/1.1 400 Bad Request'); header('Content-Type: text/plain; charset=UTF-8'); die('Bad Request!'); } function unauthorized() { - logMe("unauthorized()"); - logMe(debugInfo()); + Minz_Log::warning('unauthorized() ' . debugInfo(), API_LOG); header('HTTP/1.1 401 Unauthorized'); header('Content-Type: text/plain; charset=UTF-8'); header('Google-Bad-Token: true'); @@ -124,22 +118,21 @@ function unauthorized() { } function notImplemented() { - logMe("notImplemented()"); - logMe(debugInfo()); + Minz_Log::warning('notImplemented() ' . debugInfo(), API_LOG); header('HTTP/1.1 501 Not Implemented'); header('Content-Type: text/plain; charset=UTF-8'); die('Not Implemented!'); } function serviceUnavailable() { - logMe("serviceUnavailable()"); + Minz_Log::warning('serviceUnavailable() ' . debugInfo(), API_LOG); header('HTTP/1.1 503 Service Unavailable'); header('Content-Type: text/plain; charset=UTF-8'); die('Service Unavailable!'); } function checkCompatibility() { - logMe("checkCompatibility()"); + Minz_Log::warning('checkCompatibility() ' . debugInfo(), API_LOG); header('Content-Type: text/plain; charset=UTF-8'); if (PHP_INT_SIZE < 8 && !function_exists('gmp_init')) { die('FAIL 64-bit or GMP extension!'); @@ -170,7 +163,7 @@ function authorizationToUser() { if ($headerAuthX[1] === sha1(FreshRSS_Context::$system_conf->salt . $user . FreshRSS_Context::$user_conf->apiPasswordHash)) { return $user; } else { - logMe('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]); + Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1], API_LOG); Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]); unauthorized(); } @@ -183,7 +176,6 @@ function authorizationToUser() { } function clientLogin($email, $pass) { //http://web.archive.org/web/20130604091042/http://undoc.in/clientLogin.html - //logMe('clientLogin(' . $email . ")"); if (ctype_alnum($email)) { if (!function_exists('password_verify')) { include_once(LIB_PATH . '/password_compat.php'); @@ -215,7 +207,7 @@ function token($conf) { //http://blog.martindoms.com/2009/08/15/using-the-google-reader-api-part-1/ //https://github.com/ericmann/gReader-Library/blob/master/greader.class.php $user = Minz_Session::param('currentUser', '_'); - //logMe('token('. $user . ")"); //TODO: Implement real token that expires + //Minz_Log::debug('token('. $user . ')', API_LOG); //TODO: Implement real token that expires $token = str_pad(sha1(FreshRSS_Context::$system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters echo $token, "\n"; exit(); @@ -224,7 +216,6 @@ function token($conf) { function checkToken($conf, $token) { //http://code.google.com/p/google-reader-api/wiki/ActionToken $user = Minz_Session::param('currentUser', '_'); - //logMe('checkToken(' . $token . ")"); if ($token === str_pad(sha1(FreshRSS_Context::$system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z')) { return true; } @@ -232,7 +223,6 @@ function checkToken($conf, $token) { } function userInfo() { //https://github.com/theoldreader/api#user-info - //logMe("userInfo()"); $user = Minz_Session::param('currentUser', '_'); exit(json_encode(array( 'userId' => $user, @@ -243,7 +233,6 @@ function userInfo() { //https://github.com/theoldreader/api#user-info } function tagList() { - //logMe("tagList()"); header('Content-Type: application/json; charset=UTF-8'); $pdo = new MyPDO(); @@ -268,7 +257,6 @@ function tagList() { } function subscriptionList() { - //logMe("subscriptionList()"); header('Content-Type: application/json; charset=UTF-8'); $pdo = new MyPDO(); @@ -303,7 +291,6 @@ function subscriptionList() { } function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = '') { - //logMe("subscriptionEdit()"); //https://github.com/mihaip/google-reader-api/blob/master/wiki/ApiSubscriptionEdit.wiki switch ($action) { case 'subscribe': @@ -360,7 +347,7 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' $feed = FreshRSS_feed_Controller::addFeed($streamName, $title, $addCatId, $c_name, $http_auth); continue; } catch (Exception $e) { - logMe("subscriptionEdit error subscribe: " . $e->getMessage()); + Minz_Log::error('subscriptionEdit error subscribe: ' . $e->getMessage(), API_LOG); } } badRequest(); @@ -389,7 +376,6 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' } function quickadd($url) { - //logMe("quickadd($url)"); try { $feed = FreshRSS_feed_Controller::addFeed($url); exit(json_encode(array( @@ -397,7 +383,7 @@ function quickadd($url) { 'streamId' => $feed->id(), ))); } catch (Exception $e) { - logMe("subscriptionEdit error subscribe: " . $e->getMessage()); + Minz_Log::error('quickadd error: ' . $e->getMessage(), API_LOG); die(json_encode(array( 'numResults' => 0, 'error' => $e->getMessage(), @@ -406,7 +392,6 @@ function quickadd($url) { } function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#unread-count - //logMe("unreadCount()"); header('Content-Type: application/json; charset=UTF-8'); $totalUnreads = 0; @@ -453,7 +438,6 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl function streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation) { //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed - //logMe("streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation)"); header('Content-Type: application/json; charset=UTF-8'); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -562,8 +546,6 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude //http://code.google.com/p/google-reader-api/wiki/ApiStreamItemsIds //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed - //logMe("streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target)"); - $type = 'A'; $id = ''; if ($streamId === 'user/-/state/com.google/reading-list') { @@ -610,8 +592,6 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude } function editTag($e_ids, $a, $r) { - //logMe("editTag()"); - foreach ($e_ids as $i => $e_id) { $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' } @@ -645,7 +625,6 @@ function editTag($e_ids, $a, $r) { } function renameTag($s, $dest) { - //logMe("renameTag()"); if ($s != '' && strpos($s, 'user/-/label/') === 0 && $dest != '' && strpos($dest, 'user/-/label/') === 0) { $s = substr($s, 13); @@ -661,7 +640,6 @@ function renameTag($s, $dest) { } function disableTag($s) { - //logMe("disableTag($s)"); if ($s != '' && strpos($s, 'user/-/label/') === 0) { $s = substr($s, 13); $categoryDAO = new FreshRSS_CategoryDAO(); @@ -679,7 +657,6 @@ function disableTag($s) { } function markAllAsRead($streamId, $olderThanId) { - //logMe("markAllAsRead($streamId, $olderThanId)"); $entryDAO = FreshRSS_Factory::createEntryDao(); if (strpos($streamId, 'feed/') === 0) { $f_id = basename($streamId); @@ -696,8 +673,8 @@ function markAllAsRead($streamId, $olderThanId) { exit('OK'); } -//logMe('----------------------------------------------------------------'); -//logMe(debugInfo()); +//Minz_Log::debug('----------------------------------------------------------------', API_LOG); +//Minz_Log::debug(debugInfo(), API_LOG); $pathInfo = empty($_SERVER['PATH_INFO']) ? '/Error' : urldecode($_SERVER['PATH_INFO']); $pathInfos = explode('/', $pathInfo); @@ -718,8 +695,6 @@ if ($user !== '') { FreshRSS_Context::$user_conf = get_user_configuration($user); } -//logMe('User => ' . $user); - Minz_Session::_param('currentUser', $user); if (count($pathInfos) < 3) { diff --git a/p/api/pshb.php b/p/api/pshb.php index ed8326cf5..578681cc4 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -2,18 +2,18 @@ require('../../constants.php'); require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader -define('MAX_PAYLOAD', 3145728); +const MAX_PAYLOAD = 3145728; header('Content-Type: text/plain; charset=UTF-8'); header('X-Content-Type-Options: nosniff'); -function logMe($text) { - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); -} - $ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, MAX_PAYLOAD); -//logMe(print_r(array('_SERVER' => $_SERVER, '_GET' => $_GET, '_POST' => $_POST, 'INPUT' => $ORIGINAL_INPUT), true)); +Minz_Configuration::register('system', DATA_PATH . '/config.php', FRESHRSS_PATH . '/config.default.php'); +$system_conf = Minz_Configuration::get('system'); +$system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!) + +//Minz_Log::debug(print_r(array('_SERVER' => $_SERVER, '_GET' => $_GET, '_POST' => $_POST, 'INPUT' => $ORIGINAL_INPUT), true), PSHB_LOG); $key = isset($_GET['k']) ? substr($_GET['k'], 0, 128) : ''; if (!ctype_xdigit($key)) { @@ -24,31 +24,31 @@ chdir(PSHB_PATH); $canonical64 = @file_get_contents('keys/' . $key . '.txt'); if ($canonical64 === false) { if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'unsubscribe') { - logMe('Warning: Accept unknown unsubscribe'); + Minz_Log::warning('Warning: Accept unknown unsubscribe', PSHB_LOG); header('Connection: close'); exit(isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : ''); } header('HTTP/1.1 404 Not Found'); - logMe('Warning: Feed key not found!: ' . $key); + Minz_Log::warning('Warning: Feed key not found!: ' . $key, PSHB_LOG); die('Feed key not found!'); } $canonical64 = trim($canonical64); if (!preg_match('/^[A-Za-z0-9_-]+$/D', $canonical64)) { header('HTTP/1.1 500 Internal Server Error'); - logMe('Error: Invalid key reference!: ' . $canonical64); + Minz_Log::error('Error: Invalid key reference!: ' . $canonical64, PSHB_LOG); die('Invalid key reference!'); } $hubFile = @file_get_contents('feeds/' . $canonical64 . '/!hub.json'); if ($hubFile === false) { header('HTTP/1.1 404 Not Found'); unlink('keys/' . $key . '.txt'); - logMe('Error: Feed info not found!: ' . $canonical64); + Minz_Log::error('Error: Feed info not found!: ' . $canonical64, PSHB_LOG); die('Feed info not found!'); } $hubJson = json_decode($hubFile, true); if (!$hubJson || empty($hubJson['key']) || $hubJson['key'] !== $key) { header('HTTP/1.1 500 Internal Server Error'); - logMe('Error: Invalid key cross-check!: ' . $key); + Minz_Log::error('Error: Invalid key cross-check!: ' . $key, PSHB_LOG); die('Invalid key cross-check!'); } chdir('feeds/' . $canonical64); @@ -56,7 +56,7 @@ $users = glob('*.txt', GLOB_NOSORT); if (empty($users)) { header('HTTP/1.1 410 Gone'); $url = base64url_decode($canonical64); - logMe('Warning: Nobody subscribes to this feed anymore!: ' . $url); + Minz_Log::warning('Warning: Nobody subscribes to this feed anymore!: ' . $url, PSHB_LOG); unlink('../../keys/' . $key . '.txt'); Minz_Configuration::register('system', DATA_PATH . '/config.php', @@ -101,10 +101,6 @@ if ($ORIGINAL_INPUT == '') { die('Missing XML payload!'); } -Minz_Configuration::register('system', DATA_PATH . '/config.php', FRESHRSS_PATH . '/config.default.php'); -$system_conf = Minz_Configuration::get('system'); -$system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!) - $simplePie = customSimplePie(); $simplePie->set_raw_data($ORIGINAL_INPUT); $simplePie->init(); @@ -115,7 +111,7 @@ $self = isset($links[0]) ? $links[0] : null; if ($self !== base64url_decode($canonical64)) { //header('HTTP/1.1 422 Unprocessable Entity'); - logMe('Warning: Self URL [' . $self . '] does not match registered canonical URL!: ' . base64url_decode($canonical64)); + Minz_Log::warning('Warning: Self URL [' . $self . '] does not match registered canonical URL!: ' . base64url_decode($canonical64), PSHB_LOG); //die('Self URL does not match registered canonical URL!'); $self = base64url_decode($canonical64); } @@ -124,7 +120,7 @@ $nb = 0; foreach ($users as $userFilename) { $username = basename($userFilename, '.txt'); if (!file_exists(USERS_PATH . '/' . $username . '/config.php')) { - logMe('Warning: Removing broken user link: ' . $username . ' for ' . $self); + Minz_Log::warning('Warning: Removing broken user link: ' . $username . ' for ' . $self, PSHB_LOG); unlink($userFilename); continue; } @@ -140,11 +136,11 @@ foreach ($users as $userFilename) { if ($updated_feeds > 0 || $feed != false) { $nb++; } else { - logMe('Warning: User ' . $username . ' does not subscribe anymore to ' . $self); + Minz_Log::warning('Warning: User ' . $username . ' does not subscribe anymore to ' . $self, PSHB_LOG); unlink($userFilename); } } catch (Exception $e) { - logMe('Error: ' . $e->getMessage() . ' for user ' . $username . ' and feed ' . $self); + Minz_Log::error('Error: ' . $e->getMessage() . ' for user ' . $username . ' and feed ' . $self, PSHB_LOG); } } @@ -153,12 +149,12 @@ unset($simplePie); if ($nb === 0) { header('HTTP/1.1 410 Gone'); - logMe('Warning: Nobody subscribes to this feed anymore after all!: ' . $self); + Minz_Log::warning('Warning: Nobody subscribes to this feed anymore after all!: ' . $self, PSHB_LOG); die('Nobody subscribes to this feed anymore after all!'); } elseif (!empty($hubJson['error'])) { $hubJson['error'] = false; file_put_contents('./!hub.json', json_encode($hubJson)); } -logMe('PubSubHubbub ' . $self . ' done: ' . $nb); +Minz_Log::notice('PubSubHubbub ' . $self . ' done: ' . $nb, PSHB_LOG); exit('Done: ' . $nb . "\n"); -- cgit v1.2.3 From 5c52d9b34bb1f1285f92dd557bb8b8cb222b50f4 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sun, 10 Dec 2017 22:09:54 +0100 Subject: Check requirement in CLI script (#1711) * check requirements in actualize_script before executing, fixes #1710 * removed empty whiteline * testing all requirements * incorporated code review feedback * removed code that is already executed in _cli.php * added newline at eof * fixed include problems * fixed include problems --- app/actualize_script.php | 12 ++++-------- cli/_cli.php | 17 +++++++++++++++++ cli/do-install.php | 15 +-------------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/actualize_script.php b/app/actualize_script.php index deaa1bf7c..0bb1f166f 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -1,6 +1,5 @@ format('c') . "\n"); //Unbuffered } - // Set the header params ($_GET) to call the FRSS application. $_GET['c'] = 'feed'; $_GET['a'] = 'actualize'; @@ -20,15 +18,15 @@ $_GET['ajax'] = 1; $_GET['force'] = true; $_SERVER['HTTP_HOST'] = ''; - $log_file = join_path(USERS_PATH, '_', 'log.txt'); - $app = new FreshRSS(); $system_conf = Minz_Configuration::get('system'); $system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!) -FreshRSS_Context::$isCli = true; + +// make sure the PHP setup of the CLI environment is compatible with FreshRSS as well +performRequirementCheck($system_conf->db['type']); // Create the list of users to actualize. // Users are processed in a random order but always start with admin @@ -39,7 +37,6 @@ if ($system_conf->default_user !== '') { $users = array_unique($users); } - $limits = $system_conf->limits; $min_last_activity = time() - $limits['max_inactivity']; foreach ($users as $user) { @@ -74,7 +71,6 @@ foreach ($users as $user) { } } - Minz_Log::notice('FreshRSS actualize done.', $log_file); if (defined('STDOUT')) { fwrite(STDOUT, 'Done.' . "\n"); diff --git a/cli/_cli.php b/cli/_cli.php index 1b26ea738..fb35c4afb 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -5,6 +5,7 @@ if (php_sapi_name() !== 'cli') { require(dirname(__FILE__) . '/../constants.php'); require(LIB_PATH . '/lib_rss.php'); +require(LIB_PATH . '/lib_install.php'); Minz_Configuration::register('system', DATA_PATH . '/config.php', @@ -47,3 +48,19 @@ function done($ok = true) { fwrite(STDERR, 'Result: ' . ($ok ? 'success' : 'fail') . "\n"); exit($ok ? 0 : 1); } + +function performRequirementCheck($databaseType) { + $requirements = checkRequirements($databaseType); + if ($requirements['all'] !== 'ok') { + $message = 'FreshRSS install failed requirements:' . "\n"; + foreach ($requirements as $requirement => $check) { + if ($check !== 'ok' && !in_array($requirement, array('all', 'pdo', 'message'))) { + $message .= '• ' . $requirement . "\n"; + } + } + if (!empty($requirements['message'])) { + $message .= '• ' . $requirements['message'] . "\n"; + } + fail($message); + } +} diff --git a/cli/do-install.php b/cli/do-install.php index 74bbdfcd4..37db85575 100755 --- a/cli/do-install.php +++ b/cli/do-install.php @@ -1,7 +1,6 @@ #!/usr/bin/php $check) { - if ($check !== 'ok' && !in_array($requirement, array('all', 'pdo', 'message'))) { - $message .= '• ' . $requirement . "\n"; - } - } - if (!empty($requirements['message'])) { - $message .= '• ' . $requirements['message'] . "\n"; - } - fail($message); -} +performRequirementCheck($config['db']['type']); if (!FreshRSS_user_Controller::checkUsername($options['default_user'])) { fail('FreshRSS error: invalid default username “' . $options['default_user'] -- cgit v1.2.3 From c722b2cdb7a23ddd37e4cee8b612d4896139038d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 10 Dec 2017 22:28:45 +0100 Subject: Changelog 1708 1711 https://github.com/FreshRSS/FreshRSS/pull/1708 https://github.com/FreshRSS/FreshRSS/pull/1711 --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7fec5334..2ab0edf9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,12 +18,14 @@ * Fix punycode warning in PHP 7.2 [#1699](https://github.com/FreshRSS/FreshRSS/issues/1699) * CLI * New command `./cli/db-optimize.php` for database optimisation [#1583](https://github.com/FreshRSS/FreshRSS/issues/1583) + * Check PHP requirements before running `actualize_script.php` (cron for refreshing feeds) [#1711](https://github.com/FreshRSS/FreshRSS/pull/1711) * SQL * Perform `VACUUM` on SQLite and PostgreSQL databases when optimisation is requested [#918](https://github.com/FreshRSS/FreshRSS/issues/918) * I18n * Improved German [#1698](https://github.com/FreshRSS/FreshRSS/pull/1698) * Extensions - * New function `$entry->_hash($hex)` for extensios that change the content of entries [#1707](https://github.com/FreshRSS/FreshRSS/pull/1707) + * Show existing extensions in admin panel [#1708](https://github.com/FreshRSS/FreshRSS/pull/1708) + * New function `$entry->_hash($hex)` for extensions that change the content of entries [#1707](https://github.com/FreshRSS/FreshRSS/pull/1707) * Misc. * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) -- cgit v1.2.3 From eca01e366481c73d24d3db8d488a53d38d6ecf5d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 11 Dec 2017 20:18:03 +0100 Subject: Changelog 1712 https://github.com/FreshRSS/FreshRSS/pull/1712 https://github.com/FreshRSS/FreshRSS/issues/1562 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ab0edf9c..e4dbc63fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ * Show existing extensions in admin panel [#1708](https://github.com/FreshRSS/FreshRSS/pull/1708) * New function `$entry->_hash($hex)` for extensions that change the content of entries [#1707](https://github.com/FreshRSS/FreshRSS/pull/1707) * Misc. + * Basic mechanism to limit the size of the logs [#1712](https://github.com/FreshRSS/FreshRSS/pull/1712) * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) -- cgit v1.2.3 From 52d09886558361bd818182da9ddc204e83f618ba Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 11 Dec 2017 21:11:34 +0100 Subject: Use __DIR__ for relative include and require For uniformity, and to avoid having PHP searching in include_path. http://php.net/manual/function.include.php https://github.com/FreshRSS/FreshRSS/pull/1715 https://github.com/FreshRSS/FreshRSS/pull/1711#issuecomment-350581350 --- cli/_cli.php | 2 +- cli/_update-or-create-user.php | 2 +- cli/actualize-user.php | 2 +- cli/create-user.php | 2 +- cli/db-optimize.php | 2 +- cli/delete-user.php | 2 +- cli/do-install.php | 2 +- cli/export-opml-for-user.php | 2 +- cli/export-zip-for-user.php | 2 +- cli/import-for-user.php | 2 +- cli/list-users.php | 2 +- cli/reconfigure.php | 2 +- cli/update-user.php | 2 +- cli/user-info.php | 2 +- lib/lib_rss.php | 4 ++-- p/api/greader.php | 2 +- p/api/index.php | 2 +- p/api/pshb.php | 2 +- p/ext.php | 2 +- p/f.php | 2 +- p/i/index.php | 2 +- tests/bootstrap.php | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cli/_cli.php b/cli/_cli.php index fb35c4afb..72629171c 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -3,7 +3,7 @@ if (php_sapi_name() !== 'cli') { die('FreshRSS error: This PHP script may only be invoked from command line!'); } -require(dirname(__FILE__) . '/../constants.php'); +require(__DIR__ . '/../constants.php'); require(LIB_PATH . '/lib_rss.php'); require(LIB_PATH . '/lib_install.php'); diff --git a/cli/_update-or-create-user.php b/cli/_update-or-create-user.php index 15397f1f6..a5960b58a 100644 --- a/cli/_update-or-create-user.php +++ b/cli/_update-or-create-user.php @@ -1,5 +1,5 @@ decode($var); @@ -12,7 +12,7 @@ if (!function_exists('json_decode')) { } if (!function_exists('json_encode')) { - require_once('JSON.php'); + require_once(__DIR__ . '/JSON.php'); function json_encode($var) { $JSON = new Services_JSON(); return $JSON->encodeUnsafe($var); diff --git a/p/api/greader.php b/p/api/greader.php index b27f5bd43..99304f4ec 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -20,7 +20,7 @@ Server-side API compatible with Google Reader API layer 2 * https://github.com/theoldreader/api */ -require('../../constants.php'); +require(__DIR__ . '/../../constants.php'); require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader $ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1048576); diff --git a/p/api/index.php b/p/api/index.php index 08f7b6b7b..429b25225 100644 --- a/p/api/index.php +++ b/p/api/index.php @@ -14,7 +14,7 @@
Your API address:
Date: Wed, 13 Dec 2017 21:59:02 +0100 Subject: fixed bug in catch block added types to docblocks --- lib/Minz/ExtensionManager.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index c5c68a8d4..02a99701f 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -94,8 +94,8 @@ class Minz_ExtensionManager { * If the extension class name is `TestExtension`, entry point will be `Test`. * `entry_point` must be composed of alphanumeric characters. * - * @param $meta is an array of values. - * @return true if the array is valid, false else. + * @param array $meta is an array of values. + * @return bool true if the array is valid, false else. */ public static function isValidMetadata($meta) { $valid_chars = array('_'); @@ -107,8 +107,8 @@ class Minz_ExtensionManager { /** * Load the extension source code based on info metadata. * - * @param $info an array containing information about extension. - * @return an extension inheriting from Minz_Extension. + * @param array $info an array containing information about extension. + * @return Minz_Extension|null an extension inheriting from Minz_Extension. */ public static function load($info) { $entry_point_filename = $info['path'] . '/' . self::$ext_entry_point; @@ -127,9 +127,9 @@ class Minz_ExtensionManager { $extension = null; try { $extension = new $ext_class_name($info); - } catch (Minz_ExtensionException $e) { + } catch (Exception $e) { // We cannot load the extension? Invalid! - Minz_Log::warning('In `' . $metadata_filename . '`: ' . $e->getMessage()); + Minz_Log::warning('Invalid extension `' . $ext_class_name . '`: ' . $e->getMessage()); return null; } @@ -149,7 +149,7 @@ class Minz_ExtensionManager { * If the extension is present in $ext_auto_enabled and if its type is "system", * it will be enabled in the same time. * - * @param $ext a valid extension. + * @param Minz_Extension $ext a valid extension. */ public static function register($ext) { $name = $ext->getName(); @@ -168,7 +168,7 @@ class Minz_ExtensionManager { * * The extension init() method will be called. * - * @param $ext_name is the name of a valid extension present in $ext_list. + * @param Minz_Extension $ext_name is the name of a valid extension present in $ext_list. */ public static function enable($ext_name) { if (isset(self::$ext_list[$ext_name])) { @@ -182,7 +182,7 @@ class Minz_ExtensionManager { /** * Enable a list of extensions. * - * @param $ext_list the names of extensions we want to load. + * @param string[] $ext_list the names of extensions we want to load. */ public static function enableByList($ext_list) { foreach ($ext_list as $ext_name) { @@ -193,8 +193,8 @@ class Minz_ExtensionManager { /** * Return a list of extensions. * - * @param $only_enabled if true returns only the enabled extensions (false by default). - * @return an array of extensions. + * @param bool $only_enabled if true returns only the enabled extensions (false by default). + * @return Minz_Extension[] an array of extensions. */ public static function listExtensions($only_enabled = false) { if ($only_enabled) { @@ -207,8 +207,8 @@ class Minz_ExtensionManager { /** * Return an extension by its name. * - * @param $ext_name the name of the extension. - * @return the corresponding extension or null if it doesn't exist. + * @param string $ext_name the name of the extension. + * @return Minz_Extension|null the corresponding extension or null if it doesn't exist. */ public static function findExtension($ext_name) { if (!isset(self::$ext_list[$ext_name])) { @@ -224,9 +224,9 @@ class Minz_ExtensionManager { * The hook name must be a valid one. For the valid list, see self::$hook_list * array keys. * - * @param $hook_name the hook name (must exist). - * @param $hook_function the function name to call (must be callable). - * @param $ext the extension which register the hook. + * @param string $hook_name the hook name (must exist). + * @param callable $hook_function the function name to call (must be callable). + * @param Minz_Extension $ext the extension which register the hook. */ public static function addHook($hook_name, $hook_function, $ext) { if (isset(self::$hook_list[$hook_name]) && is_callable($hook_function)) { @@ -241,8 +241,8 @@ class Minz_ExtensionManager { * The hook name must be a valid one. For the valid list, see self::$hook_list * array keys. * - * @param $hook_name the hook to call. - * @param additionnal parameters (for signature, please see self::$hook_list). + * @param string $hook_name the hook to call. + * @param additional parameters (for signature, please see self::$hook_list). * @return the final result of the called hook. */ public static function callHook($hook_name) { -- cgit v1.2.3 From e70e9e8e041063caf0922e504fbf6069d06faa5e Mon Sep 17 00:00:00 2001 From: Frans de Jonge Date: Sun, 3 Dec 2017 10:25:25 +0100 Subject: [doc] Extensions: translate various sections from French See https://github.com/FreshRSS/FreshRSS/pull/1697#discussion_r154290857 * lowercase dir as pointed out by @kevinpapst in https://github.com/FreshRSS/FreshRSS/pull/1704#issuecomment-350458110 * Add French translation with improvements suggested by @aledeg --- docs/en/developers/03_Backend/05_Extensions.md | 94 ++++++++++++++++++-------- docs/fr/developers/03_Backend/05_Extensions.md | 2 +- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/docs/en/developers/03_Backend/05_Extensions.md b/docs/en/developers/03_Backend/05_Extensions.md index b0b5793df..1be8ad126 100644 --- a/docs/en/developers/03_Backend/05_Extensions.md +++ b/docs/en/developers/03_Backend/05_Extensions.md @@ -6,21 +6,41 @@ FreshRSS is an RSS / Atom feeds aggregator written in PHP since October 2012. Th ## Problem to solve -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +FreshRSS is limited in its technical possibilities by various factors: + +* The number of developers +* The will to integrate certain changes +* The level of "hacking" required to integrate marginal features + +While the first limitation can, in theory, be lifted by the participation of new contributors to the project, it depends on the willingness of contributors to take an interest in the source code of the entire project. In order to remove the other two limitations, most of the time it will be necessary to create a "fork". + +Another solution consists of an extension system. By allowing users to write their own extension without taking an interest in the core of the basic software, we allow for: + +1. Reducing the amount of source code a new contributor has to take in +2. Unofficial integration of novelties +3. No necessity of forking or main developer approvement. + +Note: it is quite conceivable that the functionalities of an extension can later be officially integrated into the FreshRSS code. Extensions make it easy to propose a proof of concept. ## Understanding basic mechanics (Minz and MVC) **TODO** : move to 02_Minz.md -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +This data sheet should refer to the official FreshRSS and Minz documentation (the PHP framework on which FreshRSS is based). Unfortunately, this documentation does not yet exist. In a few words, here are the main things you should know. It is not necessary to read all the chapters in this section if you don't need to use a feature in your extension (if you don't need to translate your extension, no need to know more about the `Minz_Translate` module for example). ### MVC Architecture -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +Minz relies on and imposes an MVC architecture for projects using it. This architecture consists of three main components: + +* The model: this is the base object that we will manipulate. In FreshRSS, categories, flows and articles are templates. The part of the code that makes it possible to manipulate them in a database is also part of the model but is separated from the base model: we speak of DAO (for "Data Access Object"). The templates are stored in a `Models` folder. +* The view: this is what the user sees. The view is therefore simply HTML code mixed with PHP to display dynamic information. The views are stored in an `views` folder. +* The controller: this is what makes it possible to link models and views. Typically, a controller will load templates from the database (like a list of items) to "pass" them to a view for display. Controllers are stored in a `Controllers` directory. ### Routing -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +In order to link a URL to a controller, first you have to go through a "routing" phase. In FreshRSS, this is particularly simple because it suffices to specify the name of the controller to load into the URL using a `c` parameter. For example, the address http://exemple.com?c=hello will execute the code contained in the `hello` controller. + +One concept that has not yet been discussed is the "actions" system. An action is executed *on* a controller. Concretely, a controller is represented by a class and its actions by methods. To execute an action, it is necessary to specify an `a` parameter in the URL. Code example: @@ -40,13 +60,17 @@ class FreshRSS_hello_Controller extends Minz_ActionController { ?> ``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +When loading the address http://exemple.com?c=hello&a=world, the `world` action is executed on the `hello` controller. + +Note: if `c` or `a` is not specified, the default value for each of these variables is `index`. So the address http://exemple.com?c=hello will execute the `index` action of the `hello` controller. + +Later, the `hello/world` convention will be used to refer to a controller/action pair. ### Views -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +Each view is associated with a controller and an action. The view associated with `hello/world` will be stored in a very specific file: `views/hello/world. phtml`. This convention is imposed by Minz. -Code example: +As explained above, the views consist of HTML mixed with PHP. Code example: ```html

@@ -54,12 +78,11 @@ Code example:

``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +The variable `$this->a_variable` is passed by the controller (see previous example). The difference is that in the controller it is necessary to pass `$this->view`, while in the view `$this` suffices. ### Working with GET / POST -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) - +It is often necessary to take advantage of parameters passed by GET or POST. In Minz, these parameters are accessible using the `Minz_Request` class. Code example: ```php @@ -82,15 +105,17 @@ echo Minz_Request::param('bar'); ?> ``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +The `Minz_Request::isPost()` method can be used to execute a piece of code only if it is a POST request. + +Note: it is preferable to use `Minz_Request` only in controllers. It is likely that you will encounter this method in FreshRSS views, or even in templates, but be aware that this is **not** good practice. ### Access session settings -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +The access to session parameters is strangely similar to the GET / POST parameters but passes through the `Minz_Session` class this time! There is no example here because you can repeat the previous example by changing all `Minz_Request` to `Minz_Session`. ### Working with URLs -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +To take full advantage of the Minz routing system, it is strongly discouraged to write hard URLs in your code. For example, the following view should be avoided: ```html

@@ -98,7 +123,9 @@ echo Minz_Request::param('bar');

``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +Should it be decided one day to use a "url rewriting" system to have addresses in a http://exemple.com/controller/action format, all previous addresses would become ineffective! + +So use the `Minz_Url` class and its `display()` method instead. `Minz_Url::display()` takes an array of the following form as its argument: ```php ``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +Since this can become a bit tedious to use in the long run, especially in views, it is preferable to use the `_url()' shortcut: ```php ``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +Note: as a general rule, the shortened form (`_url()`) should be used in views, while the long form (`Minz_Url::display()`) should be used in controllers. ### Redirections -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +It is often necessary to redirect a user to another page. To do so, the `Minz_Request` class offers another useful method: `forward()`. This method takes the same URL format as the one seen just before as its argument. Code example: @@ -156,7 +183,7 @@ Minz_Request::forward($url_array, true); ?> ``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +It is very common to want display a message to the user while performing a redirect, to tell the user how the action was carried out (validation of a form for example). Such a message is passed through a `notification` session variable (note: we will talk about feedback from now on to avoid confusion with a notification that can occur at any time). To facilitate this kind of very frequent action, there are two shortcuts that both perform a 302 redirect by assigning a feedback message: ```php ``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) - +To access these translations, `Minz_Translate` will help us with its `Minz_Translate::t()` method. As this can be a bit long to type, a shortcut has been introduced that **must** be used in all circumstances: `_t()`. Code example: ```html @@ -213,11 +253,11 @@ Code example:

``` -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +The string to pass to the `_t()` function consists of a series of identifiers separated by dots. The first identifier indicates from which file to extract the translation (in this case, `gen.php`), while the following ones indicate table entries. Thus `action` is an entry of the main array and `back_to_rss_feeds` is an entry of the `action` array. This allows us to further organize our translation files. -### Configuration management +There is a small special case that sometimes makes life easier: the `_` identifier. This must necessarily be present at the end of the chain and gives a value to the higher-level identifier. It's pretty hard to explain but very simple to understand. In the example given above, a `_` is associated with the value `FreshRSS`: this means that there is no need to write `_t('gen.freshrss._')` but `_t('gen.freshrss')` suffices. -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +### Configuration management ## Write an extension for FreshRSS @@ -296,9 +336,9 @@ In addition, you will have a number of methods directly inherited from `Minz_Ext - The "getters" first: most are explicit enough not to detail them here - `getName()`, `getEntrypoint()`, `getPath()` (allows you to retrieve the path to your extension), `getAuthor()`, `getDescription()`, `getVersion()`, `getType()`. - `getFileUrl($filename, $type)` will return the URL to a file in the `static` directory. The first parameter is the name of the file (without `static /`), the second is the type of file to be used (`css` or` js`). -- `registerController($base_name)` will tell Minz to take into account the given controller in the routing system. The controller must be located in your `Controllers` directory, the name of the file must be` Controller.php` and the name of the `FreshExtension__Controller` class. +- `registerController($base_name)` will tell Minz to take into account the given controller in the routing system. The controller must be located in your `controllers` directory, the name of the file must be` Controller.php` and the name of the `FreshExtension__Controller` class. -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +**TODO** - `registerViews()` - `registerTranslates()` @@ -331,4 +371,4 @@ The following events are available: When you want to support user configurations for your extension or simply display some information, you have to create the `configure.phtml` file. -**TODO** translate from [french version](https://github.com/FreshRSS/documentation/blob/master/fr/docs/developers/03_Backend/05_Extensions.md) +**TODO** diff --git a/docs/fr/developers/03_Backend/05_Extensions.md b/docs/fr/developers/03_Backend/05_Extensions.md index a3dc5ad20..1f4fc4a4b 100644 --- a/docs/fr/developers/03_Backend/05_Extensions.md +++ b/docs/fr/developers/03_Backend/05_Extensions.md @@ -332,4 +332,4 @@ TODO : ### Écrire le fichier configure.phtml -TODO +Lorsque vous voulez ajouter de la configuration à votre extension ou afficher ses informations, vous devez créer le fichier `configure.phtml`. -- cgit v1.2.3 From 8c50a44687d7258df4e7f9829fb02721d7f86eea Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 16 Dec 2017 15:41:37 +0100 Subject: Fix whitespace --- app/i18n/he/conf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php index e318bba4d..3ec83b4ad 100644 --- a/app/i18n/he/conf.php +++ b/app/i18n/he/conf.php @@ -99,7 +99,7 @@ return array( 'when' => 'סימון מאמרים כנקראו…', ), 'show' => array( - '_' => 'מאמרים להצגה', + '_' => 'מאמרים להצגה', 'adaptive' => 'תצוגה מתעדכנת', 'all_articles' => 'הצגת כל המאמרים', 'unread' => 'הצגת מאמרים שלא נקראו בלבד', -- cgit v1.2.3 From 92d9d77fe57c8f5a2407889c6c84fed1fb6f22a1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 16 Dec 2017 17:37:32 +0100 Subject: Add message after log rotation https://github.com/FreshRSS/FreshRSS/pull/1712 https://github.com/FreshRSS/FreshRSS/issues/1562 --- lib/Minz/Log.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index 5e7831cdb..a8dbf8350 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -98,6 +98,7 @@ class Minz_Log { rewind($fp); ftruncate($fp, 0); fwrite($fp, $content ? $content : ''); + fwrite($fp, sprintf("[%s] [notice] --- Log rotate.\n", date('r'))); fflush($fp); flock($fp, LOCK_UN); } else { -- cgit v1.2.3 From 425958af5a2d64113ad352e983cd810bc829735e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 16 Dec 2017 22:33:49 +0100 Subject: Minz Dispatcher Controllers path https://github.com/FreshRSS/FreshRSS/pull/1704 --- lib/Minz/Dispatcher.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Minz/Dispatcher.php b/lib/Minz/Dispatcher.php index bdb1c76f6..f05b285b5 100644 --- a/lib/Minz/Dispatcher.php +++ b/lib/Minz/Dispatcher.php @@ -10,7 +10,6 @@ * C'est un singleton */ class Minz_Dispatcher { - const CONTROLLERS_PATH_NAME = '/Controllers'; /* singleton */ private static $instance = null; @@ -149,7 +148,7 @@ class Minz_Dispatcher { */ private static function loadController($base_name) { $base_path = self::$registrations[$base_name]; - $controller_filename = $base_path . '/controllers/' . $base_name . 'Controller.php'; + $controller_filename = $base_path . '/Controllers/' . $base_name . 'Controller.php'; include_once $controller_filename; } -- cgit v1.2.3 From 152a6a9bdc0e7a54532c2ccf65234b843ce99a23 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 16 Dec 2017 22:48:46 +0100 Subject: Customisable constants.local.php (#1725) https://github.com/FreshRSS/FreshRSS/issues/1562 https://github.com/FreshRSS/FreshRSS/issues/1607 https://github.com/FreshRSS/FreshRSS/pull/1656 https://github.com/FreshRSS/FreshRSS/issues/1705 https://github.com/FreshRSS/FreshRSS/pull/1712 --- .gitignore | 1 + constants.php | 67 ++++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..cd2fd5d3a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +constants.local.php diff --git a/constants.php b/constants.php index 576be09b9..2c791c3c5 100644 --- a/constants.php +++ b/constants.php @@ -1,35 +1,50 @@ define('FRESHRSS_VERSION', '1.8.1-dev'); define('FRESHRSS_WEBSITE', 'https://freshrss.org'); define('FRESHRSS_WIKI', 'https://freshrss.github.io/FreshRSS/'); -define('FRESHRSS_USERAGENT', 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')'); +define('FRESHRSS_PATH', __DIR__); +define('PUBLIC_PATH', FRESHRSS_PATH . '/p'); +define('PUBLIC_TO_INDEX_PATH', '/i'); +define('INDEX_PATH', PUBLIC_PATH . PUBLIC_TO_INDEX_PATH); +define('PUBLIC_RELATIVE', '..'); +define('LIB_PATH', FRESHRSS_PATH . '/lib'); +define('APP_PATH', FRESHRSS_PATH . '/app'); +define('EXTENSIONS_PATH', FRESHRSS_PATH . '/extensions'); +// + +function safe_define($name, $value) { + if (!defined($name)) { + return define($name, $value); + } +} + +if (file_exists(__DIR__ . '/constants.local.php')) { + //Include custom / local settings: + include(__DIR__ . '/constants.local.php'); +} + +safe_define('FRESHRSS_USERAGENT', 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')'); // PHP text output compression http://php.net/ob_gzhandler (better to do it at Web server level) -define('PHP_COMPRESSION', false); +safe_define('PHP_COMPRESSION', false); // Maximum log file size in Bytes, before it will be divided by two -define('MAX_LOG_SIZE', 1048576); - -// Constantes de chemins -define('FRESHRSS_PATH', dirname(__FILE__)); - - define('PUBLIC_PATH', FRESHRSS_PATH . '/p'); - define('PUBLIC_TO_INDEX_PATH', '/i'); - define('INDEX_PATH', PUBLIC_PATH . PUBLIC_TO_INDEX_PATH); - define('PUBLIC_RELATIVE', '..'); - - define('DATA_PATH', FRESHRSS_PATH . '/data'); - define('UPDATE_FILENAME', DATA_PATH . '/update.php'); - define('USERS_PATH', DATA_PATH . '/users'); - define('ADMIN_LOG', USERS_PATH . '/_/log.txt'); - define('API_LOG', USERS_PATH . '/_/log_api.txt'); - define('CACHE_PATH', DATA_PATH . '/cache'); - define('PSHB_LOG', USERS_PATH . '/_/log_pshb.txt'); - define('PSHB_PATH', DATA_PATH . '/PubSubHubbub'); - - define('LIB_PATH', FRESHRSS_PATH . '/lib'); - define('APP_PATH', FRESHRSS_PATH . '/app'); - define('EXTENSIONS_PATH', FRESHRSS_PATH . '/extensions'); - -define('TMP_PATH', sys_get_temp_dir()); +safe_define('MAX_LOG_SIZE', 1048576); + +//This directory must be writable +safe_define('DATA_PATH', FRESHRSS_PATH . '/data'); + +safe_define('UPDATE_FILENAME', DATA_PATH . '/update.php'); +safe_define('USERS_PATH', DATA_PATH . '/users'); +safe_define('ADMIN_LOG', USERS_PATH . '/_/log.txt'); +safe_define('API_LOG', USERS_PATH . '/_/log_api.txt'); +safe_define('CACHE_PATH', DATA_PATH . '/cache'); +safe_define('PSHB_LOG', USERS_PATH . '/_/log_pshb.txt'); +safe_define('PSHB_PATH', DATA_PATH . '/PubSubHubbub'); + +//Directory used for feed mutex with *.freshrss.lock files. Must be writable. +safe_define('TMP_PATH', sys_get_temp_dir()); -- cgit v1.2.3 From 46f52c8a5eae6d2995a1397f1c6cebeb382fd9cd Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 16 Dec 2017 23:05:40 +0100 Subject: i18n hebrew more --- app/i18n/he/gen.php | 17 ++++++++++++++++- app/i18n/he/sub.php | 13 +++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php index 35bc7e3e2..c9cd8ff57 100644 --- a/app/i18n/he/gen.php +++ b/app/i18n/he/gen.php @@ -104,10 +104,19 @@ return array( 'should_be_activated' => 'חובה להפעיל JavaScript', ), 'lang' => array( + 'cz' => 'Čeština', 'de' => 'Deutsch', 'en' => 'English', + 'es' => 'Español', 'fr' => 'Français', 'he' => 'עברית', + 'it' => 'Italiano', + 'kr' => '한국어', + 'nl' => 'Nederlands', + 'pt-br' => 'Português (Brasil)', + 'ru' => 'Русский', + 'tr' => 'Türkçe', + 'zh-cn' => '简体中文', ), 'menu' => array( 'about' => 'אודות', @@ -125,6 +134,7 @@ return array( 'sharing' => 'שיתוף', 'shortcuts' => 'קיצורי דרך', 'stats' => 'סטטיסטיקות', + 'system' => 'System configuration', // @todo 'update' => 'עדכון', 'user_management' => 'Manage users', // @todo 'user_profile' => 'Profile', // @todo @@ -144,10 +154,15 @@ return array( 'email' => 'דואר אלקטרוני', 'facebook' => 'Facebook', 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'mastodon' => 'Mastodon', + 'movim' => 'Movim', 'print' => 'הדפסה', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', - 'wallabag' => 'wallabag', + 'wallabag' => 'wallabag v1', + 'wallabagv2' => 'wallabag v2', ), 'short' => array( 'attention' => 'זהירות!', diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php index 9c7af0dc4..398c23588 100644 --- a/app/i18n/he/sub.php +++ b/app/i18n/he/sub.php @@ -1,6 +1,15 @@ array( + 'documentation' => 'Copy the following URL to use it within an external tool.', // @todo + 'title' => 'API', // @todo + ), + 'bookmarklet' => array( + 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.', // @todo + 'label' => 'Subscribe', // @todo + 'title' => 'Bookmarklet', // @todo + ), 'category' => array( '_' => 'קטגוריה', 'add' => 'הוספת קטגוריה', @@ -38,6 +47,10 @@ return array( 'validator' => 'בדיקות תקינות ההזנה', 'website' => 'אתר URL', ), + 'firefox' => array( + 'documentation' => 'Follow the steps described here to add FreshRSS to Firefox feed reader list.', // @todo + 'title' => 'Firefox feed reader', // @todo + ), 'import_export' => array( 'export' => 'ייצוא', 'export_opml' => 'ייצוא רשימת הזנות (OPML)', -- cgit v1.2.3 From 0cdae3978d4de61c1fb06088d20878455987ac67 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 16 Dec 2017 23:24:08 +0100 Subject: 18n Hebrew more 2 --- app/i18n/cz/gen.php | 1 + app/i18n/en/admin.php | 2 +- app/i18n/en/gen.php | 1 + app/i18n/es/gen.php | 1 + app/i18n/he/admin.php | 30 ++++++++++++++++++++++++------ app/i18n/he/conf.php | 2 ++ app/i18n/he/gen.php | 24 ++++++++++++++++++------ app/i18n/he/sub.php | 2 ++ app/i18n/it/gen.php | 1 + app/i18n/kr/gen.php | 1 + app/i18n/nl/gen.php | 1 + app/i18n/pt-br/gen.php | 1 + app/i18n/ru/gen.php | 1 + app/i18n/tr/gen.php | 1 + app/i18n/zh-cn/gen.php | 1 + 15 files changed, 57 insertions(+), 13 deletions(-) diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index e43355f64..fcddf452c 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index d92a016af..187b66a8c 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -118,7 +118,7 @@ return array( 'description' => 'Description', 'author' => 'Author', 'latest' => 'Installed', - 'update' => 'Update available' + 'update' => 'Update available', ), 'stats' => array( '_' => 'Statistics', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 0dc03795b..ac48e3486 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -166,6 +166,7 @@ return array( 'g+' => 'Google+', 'gnusocial' => 'GNU social', 'jdh' => 'Journal du hacker', + 'Known' => 'Known based sites', 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'Print', diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php index 0f113e073..32fbcdaee 100755 --- a/app/i18n/es/gen.php +++ b/app/i18n/es/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/he/admin.php b/app/i18n/he/admin.php index 6153a62c5..b7c83c828 100644 --- a/app/i18n/he/admin.php +++ b/app/i18n/he/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'טופס אינטרנטי (מסורתי, דורש JavaScript)', 'http' => 'HTTP (למשתמשים מתקדמים עם HTTPS)', 'none' => 'ללא (מסוכן)', - 'persona' => 'מוזילה פרסונה (מודרני, דורש JavaScript)', 'title' => 'Authentication', // @todo 'title_reset' => 'איפוס אימות', 'token' => 'מחרוזת אימות', @@ -58,6 +57,10 @@ return array( 'nok' => 'Feed table is bad configured.', // @todo 'ok' => 'Feed table is ok.', // @todo ), + 'fileinfo' => array( + 'nok' => 'Cannot find the PHP fileinfo library (fileinfo package).', // @todo + 'ok' => 'You have the fileinfo library.', // @todo + ), 'files' => 'File installation', // @todo 'json' => array( 'nok' => 'You lack JSON (php5-json package).', // @todo @@ -75,10 +78,6 @@ return array( 'nok' => 'PDO אינו מותקן או שאחד ממנהלי ההתקנים שלו חסר (pdo_mysql, pdo_sqlite)', 'ok' => 'PDO מותקן ולפחות אחד ממנהלי ההתקן הנתמכים מותקן (pdo_mysql, pdo_sqlite)', ), - 'persona' => array( - 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', // @todo - 'ok' => 'ההרשאות בתיקיית מוזילה פרסונה תקינות', - ), 'php' => array( '_' => 'PHP installation', // @todo 'nok' => 'גירסת PHP שלכם היא %s אך FreshRSS דורש לפחות את גירסה %s', @@ -113,6 +112,13 @@ return array( ), 'title' => 'Extensions', // @todo 'user' => 'User extensions', // @todo + 'community' => 'Available community extensions', // @todo + 'name' => 'Name', // @todo + 'version' => 'Version', // @todo + 'description' => 'Description', // @todo + 'author' => 'Author', // @todo + 'latest' => 'Installed', // @todo + 'update' => 'Update available', // @todo ), 'stats' => array( '_' => 'סטטיסטיקות', @@ -146,6 +152,17 @@ return array( 'title' => 'סטטיסטיקות', 'top_feed' => 'עשרת ההזנות המובילות', ), + 'system' => array( + '_' => 'System configuration', // @todo + 'auto-update-url' => 'Auto-update server URL', // @todo + 'instance-name' => 'Instance name', // @todo + 'max-categories' => 'Categories per user limit', // @todo + 'max-feeds' => 'Feeds per user limit', // @todo + 'registration' => array( + 'help' => '0 means that there is no account limit', // @todo + 'number' => 'Max number of accounts', // @todo + ), + ), 'update' => array( '_' => 'מערכת העדכון', 'apply' => 'החלת העדכון', @@ -158,8 +175,9 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', // @todo 'create' => 'יצירת משתמש חדש', - 'email_persona' => 'כתובת דואר אלקטרוני להרשמה
(לצורך מוזילה פרסונה)', 'language' => 'שפה', + 'number' => 'There is %d account created', // @todo + 'numbers' => 'There are %d accounts created', // @todo 'password_form' => 'סיסמה
(לשימוש בטפוס ההרשמה)', 'password_format' => 'At least 7 characters', // @todo 'title' => 'Manage users', // @todo diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php index 3ec83b4ad..ba9985d45 100644 --- a/app/i18n/he/conf.php +++ b/app/i18n/he/conf.php @@ -84,11 +84,13 @@ return array( 'articles_per_page' => 'מספר המאמרים בעמוד', 'auto_load_more' => 'טעינת המאמר הבא סוף העמוד', 'auto_remove_article' => 'Hide articles after reading', // @todo + 'mark_updated_article_unread' => 'Mark updated articles as unread', // @todo 'confirm_enabled' => 'הצגת דו-שיח לאישור “סימון הכל כנקרא” ', 'display_articles_unfolded' => 'הצגת מאמרים בשלמותם כברירת מחדל', 'display_categories_unfolded' => 'הצגת קטגוריות מקופלות כברירת מחדל', 'hide_read_feeds' => 'הסתרת קטגוריות & הזנות ללא מאמרים שלא נקראו (לא עובד יחד עם “הצגת כל המאמרים”)', 'img_with_lazyload' => 'שימוש ב "טעינה עצלה" על מנת לטעון תמונות', + 'sides_close_article' => 'Clicking outside of article text area closes the article', // @todo 'jump_next' => 'קפיצה לפריט הבא שלא נקרא (הזנה או קטגוריה)', 'number_divided_when_reader' => 'חלוקה ב2 במצב קריאה.', 'read' => array( diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php index c9cd8ff57..cacc8eaed 100644 --- a/app/i18n/he/gen.php +++ b/app/i18n/he/gen.php @@ -21,16 +21,25 @@ return array( 'truncate' => 'מחיקת כל המאמרים', ), 'auth' => array( + 'email' => 'Email address', // @todo 'keep_logged_in' => 'השאר מחובר חודש', 'login' => 'כניסה לחשבון', - 'login_persona' => 'התחברות באמצעות פרסונה', - 'login_persona_problem' => 'בעיות התחברות עם פרסונה?', 'logout' => 'יציאה מהחשבון', - 'password' => 'סיסמה', + 'password' => array( + '_' => 'סיסמה', + 'format' => 'At least 7 characters', + ), + 'registration' => array( + '_' => 'New account', // @todo + 'ask' => 'Create an account?', // @todo + 'title' => 'Account creation', // @todo + ), 'reset' => 'איפוס אימות', - 'username' => 'שם משתמש', - 'username_admin' => 'שם משתמש של המנהל', - 'will_reset' => 'מערכת האימות אופסה: טופס ישמש לאימות במקום מוזילה פרסונה.', + 'username' => array( + '_' => 'שם משתמש', + 'admin' => 'שם משתמש של המנהל', + 'format' => 'maximum 16 alphanumeric characters', // @todo + ), ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', @@ -71,6 +80,7 @@ return array( 'mar' => 'mar', 'march' => 'Mar', 'may' => 'May', + 'may_' => 'May', 'mon' => 'Mon', 'month' => 'חודשים', 'nov' => 'nov', @@ -156,6 +166,7 @@ return array( 'g+' => 'Google+', 'gnusocial' => 'GNU social', 'jdh' => 'Journal du hacker', + 'Known' => 'Known based sites', 'mastodon' => 'Mastodon', 'movim' => 'Movim', 'print' => 'הדפסה', @@ -172,6 +183,7 @@ return array( 'damn' => 'הו לא!', 'default_category' => 'ללא קטגוריה', 'no' => 'לא', + 'not_applicable' => 'Not available', // @todo 'ok' => 'כן!', 'or' => 'או', 'yes' => 'כן', diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php index 398c23588..333de0edf 100644 --- a/app/i18n/he/sub.php +++ b/app/i18n/he/sub.php @@ -66,9 +66,11 @@ return array( 'bookmark' => 'הרשמה (FreshRSS סימניית)', 'import_export' => 'יבוא / יצוא ', 'subscription_management' => 'ניהול הרשמות', + 'subscription_tools' => 'Subscription tools', // @todo ), 'title' => array( '_' => 'ניהול הרשמות', 'feed_management' => 'ניהול הזנות RSS', + 'subscription_tools' => 'Subscription tools', // @todo ), ); diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index 9eaabc2be..ccc8c0e7c 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php index e9b6ea9b8..8997ba14b 100644 --- a/app/i18n/kr/gen.php +++ b/app/i18n/kr/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index bccab8310..3215bdfec 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php index e313b0d8b..4bc8535d6 100644 --- a/app/i18n/pt-br/gen.php +++ b/app/i18n/pt-br/gen.php @@ -118,6 +118,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index 3283731df..cc7e8765c 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 535563542..dcfd12c01 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index 84be9f4ba..caaa388c7 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -119,6 +119,7 @@ return array( 'en' => 'English', 'es' => 'Español', 'fr' => 'Français', + 'he' => 'עברית', 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', -- cgit v1.2.3 From dc9ae355b93a7188c9f26a5ccb3a59765e813529 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 16 Dec 2017 23:51:31 +0100 Subject: Changelog 1716 1724 1725 https://github.com/FreshRSS/FreshRSS/pull/1716 https://github.com/FreshRSS/FreshRSS/pull/1724 https://github.com/FreshRSS/FreshRSS/pull/1725 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4dbc63fb..85fc76aef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,12 +10,14 @@ * Add more Unicode glyphs in the Open Sans font [#1032](https://github.com/FreshRSS/FreshRSS/pull/1032) * Show URL to add subscriptions from third-party tools [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) * Improved message when checking for new versions [#1586](https://github.com/FreshRSS/FreshRSS/issues/1586) + * Hebrew [#1716](https://github.com/FreshRSS/FreshRSS/pull/1716) * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing * Work-around for `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) * Fix PDO PostgreSQL detection [#1690](https://github.com/FreshRSS/FreshRSS/issues/1690) * Fix punycode warning in PHP 7.2 [#1699](https://github.com/FreshRSS/FreshRSS/issues/1699) + * Fix ExtensionManager exception handling [#1724](https://github.com/FreshRSS/FreshRSS/pull/1724) * CLI * New command `./cli/db-optimize.php` for database optimisation [#1583](https://github.com/FreshRSS/FreshRSS/issues/1583) * Check PHP requirements before running `actualize_script.php` (cron for refreshing feeds) [#1711](https://github.com/FreshRSS/FreshRSS/pull/1711) @@ -27,6 +29,7 @@ * Show existing extensions in admin panel [#1708](https://github.com/FreshRSS/FreshRSS/pull/1708) * New function `$entry->_hash($hex)` for extensions that change the content of entries [#1707](https://github.com/FreshRSS/FreshRSS/pull/1707) * Misc. + * Customisable `constants.local.php` [#1725](https://github.com/FreshRSS/FreshRSS/pull/1725) * Basic mechanism to limit the size of the logs [#1712](https://github.com/FreshRSS/FreshRSS/pull/1712) * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) -- cgit v1.2.3 From 3b2dfdbe1e6f0ef9c97734e56f941456046cd7f2 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 17 Dec 2017 00:02:02 +0100 Subject: Changelog 1729 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85fc76aef..73855c99e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ * I18n * Improved German [#1698](https://github.com/FreshRSS/FreshRSS/pull/1698) * Extensions + * Breaking change: uppercase `./Controllers/` directory [#1729](https://github.com/FreshRSS/FreshRSS/pull/1729) * Show existing extensions in admin panel [#1708](https://github.com/FreshRSS/FreshRSS/pull/1708) * New function `$entry->_hash($hex)` for extensions that change the content of entries [#1707](https://github.com/FreshRSS/FreshRSS/pull/1707) * Misc. -- cgit v1.2.3 From 6b202eb291d83fcbf8799988028fc86f2e04a6c6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 17 Dec 2017 00:06:26 +0100 Subject: Changelog 1716 https://github.com/FreshRSS/FreshRSS/pull/1716 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85fc76aef..5dbabff60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,6 @@ * Add more Unicode glyphs in the Open Sans font [#1032](https://github.com/FreshRSS/FreshRSS/pull/1032) * Show URL to add subscriptions from third-party tools [#1247](https://github.com/FreshRSS/FreshRSS/issues/1247) * Improved message when checking for new versions [#1586](https://github.com/FreshRSS/FreshRSS/issues/1586) - * Hebrew [#1716](https://github.com/FreshRSS/FreshRSS/pull/1716) * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing @@ -24,6 +23,7 @@ * SQL * Perform `VACUUM` on SQLite and PostgreSQL databases when optimisation is requested [#918](https://github.com/FreshRSS/FreshRSS/issues/918) * I18n + * Hebrew [#1716](https://github.com/FreshRSS/FreshRSS/pull/1716) * Improved German [#1698](https://github.com/FreshRSS/FreshRSS/pull/1698) * Extensions * Show existing extensions in admin panel [#1708](https://github.com/FreshRSS/FreshRSS/pull/1708) -- cgit v1.2.3 From 08252928b65bda88b709526fedc20be89cfb9ed4 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sun, 17 Dec 2017 15:23:10 +0100 Subject: added .editorconfig with basic settings --- .editorconfig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..e18761a1a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +[*] +end_of_line = lf + +[*.php] +indent_style = tab +indent_size = 4 +insert_final_newline = true -- cgit v1.2.3 From 82ba18511403dae8efb829c4b9be9c3539a355ab Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 17 Dec 2017 15:28:18 +0100 Subject: Minz Controllers directory uppercase https://github.com/FreshRSS/FreshRSS/pull/1729 --- docs/en/developers/03_Backend/05_Extensions.md | 4 ++-- docs/fr/developers/03_Backend/05_Extensions.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/developers/03_Backend/05_Extensions.md b/docs/en/developers/03_Backend/05_Extensions.md index 1be8ad126..fb85234c4 100644 --- a/docs/en/developers/03_Backend/05_Extensions.md +++ b/docs/en/developers/03_Backend/05_Extensions.md @@ -294,7 +294,7 @@ You may also need additional files or subdirectories depending on your needs: - `configure.phtml` is the file containing the form to parameterize your extension - A `static/` directory containing CSS and JavaScript files that you will need for your extension (note that if you need to write a lot of CSS it may be more interesting to write a complete theme) -- A `controllers` directory containing additional controllers +- A `Controllers` directory containing additional controllers - An `i18n` directory containing additional translations - `layout` and` views` directories to define new views or to overwrite the current views @@ -336,7 +336,7 @@ In addition, you will have a number of methods directly inherited from `Minz_Ext - The "getters" first: most are explicit enough not to detail them here - `getName()`, `getEntrypoint()`, `getPath()` (allows you to retrieve the path to your extension), `getAuthor()`, `getDescription()`, `getVersion()`, `getType()`. - `getFileUrl($filename, $type)` will return the URL to a file in the `static` directory. The first parameter is the name of the file (without `static /`), the second is the type of file to be used (`css` or` js`). -- `registerController($base_name)` will tell Minz to take into account the given controller in the routing system. The controller must be located in your `controllers` directory, the name of the file must be` Controller.php` and the name of the `FreshExtension__Controller` class. +- `registerController($base_name)` will tell Minz to take into account the given controller in the routing system. The controller must be located in your `Controllers` directory, the name of the file must be` Controller.php` and the name of the `FreshExtension__Controller` class. **TODO** diff --git a/docs/fr/developers/03_Backend/05_Extensions.md b/docs/fr/developers/03_Backend/05_Extensions.md index 1f4fc4a4b..f844accd1 100644 --- a/docs/fr/developers/03_Backend/05_Extensions.md +++ b/docs/fr/developers/03_Backend/05_Extensions.md @@ -277,7 +277,7 @@ Il est possible aussi que vous ayez besoin de fichiers ou sous-répertoires addi - `configure.phtml` est le fichier contenant le formulaire permettant de paramétrer votre extension ; - Un répertoire `static/` contenant fichiers CSS et JavaScript dont vous aurez besoin pour votre extension. Notez que si vous devez écrire beaucoup de CSS il est peut-être plus intéressant d'écrire un thème complet (mais ce n'est pas le sujet de cette fiche technique) ; -- Un répertoire `controllers` contenant des contrôleurs additionnels ; +- Un répertoire `Controllers` contenant des contrôleurs additionnels ; - Un répertoire `i18n` contenant des traductions supplémentaires ; - Des répertoires `layout` et `views` permettant de définir de nouvelles vues ou d'écraser les vues actuelles. -- cgit v1.2.3 From aadb632fffe22efcf5e1ecc0731329601f156f56 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 17 Dec 2017 15:43:02 +0100 Subject: Changelog 1697, 1704, 1732 https://github.com/FreshRSS/FreshRSS/pull/1697 https://github.com/FreshRSS/FreshRSS/pull/1704 https://github.com/FreshRSS/FreshRSS/pull/1732 --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 453a06b7d..c53050cef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ -# Changelog +# FreshRSS changelog -## 2017-1X-XX FreshRSS 1.8.1-dev +## 2017-12-17 FreshRSS 1.9.0-dev * API * Breaking change / compatibility fix (EasyRSS): Provide `link` to articles without HTML-encoding [#1683](https://github.com/FreshRSS/FreshRSS/issues/1683) @@ -34,6 +34,8 @@ * Basic mechanism to limit the size of the logs [#1712](https://github.com/FreshRSS/FreshRSS/pull/1712) * Translation validation tool [#1653](https://github.com/FreshRSS/FreshRSS/pull/1653) * Translation manipulation tool [#1658](https://github.com/FreshRSS/FreshRSS/pull/1658) + * Improved documentation [#1697](https://github.com/FreshRSS/FreshRSS/pull/1697), [#1704](https://github.com/FreshRSS/FreshRSS/pull/1704) + * New `.editorconfig` file [#1732](https://github.com/FreshRSS/FreshRSS/pull/1732) ## 2017-10-01 FreshRSS 1.8.0 -- cgit v1.2.3 From 62e9db55b21034f92b0f4603512c3e788e0351f1 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sun, 17 Dec 2017 16:36:48 +0100 Subject: fixed bug when adding a category and feed at the same time (#1731) fixed bug when adding a category and feed at the same time --- app/Controllers/feedController.php | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 883f7af05..fff20f798 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -26,6 +26,18 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } + /** + * @param $url + * @param string $title + * @param int $cat_id + * @param string $new_cat_name + * @param string $http_auth + * @return FreshRSS_Feed|the + * @throws FreshRSS_AlreadySubscribed_Exception + * @throws FreshRSS_FeedNotAdded_Exception + * @throws FreshRSS_Feed_Exception + * @throws Minz_FileNotExistException + */ public static function addFeed($url, $title = '', $cat_id = 0, $new_cat_name = '', $http_auth = '') { FreshRSS_UserDAO::touch(); @set_time_limit(300); @@ -33,12 +45,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); $cat = null; + if ($new_cat_name != '') { + $new_cat_id = $catDAO->addCategory(array('name' => $new_cat_name)); + $cat_id = $new_cat_id > 0 ? $new_cat_id : $cat_id; + } if ($cat_id > 0) { $cat = $catDAO->searchById($cat_id); } - if ($cat == null && $new_cat_name != '') { - $cat = $catDAO->addCategory(array('name' => $new_cat_name)); - } if ($cat == null) { $catDAO->checkDefault(); } @@ -54,7 +67,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { throw new FreshRSS_AlreadySubscribed_Exception($url, $feed->name()); } - // Call the extension hook + /** @var FreshRSS_Feed $feed */ $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); if ($feed === null) { throw new FreshRSS_FeedNotAdded_Exception($url, $feed->name()); @@ -136,7 +149,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // User want to create a new category, new_category parameter // must exist $new_cat = Minz_Request::param('new_category'); - $new_cat_name = isset($new_cat['name']) ? $new_cat['name'] : ''; + $new_cat_name = isset($new_cat['name']) ? trim($new_cat['name']) : ''; } // HTTP information are useful if feed is protected behind a -- cgit v1.2.3 From 25a51f045dbbd1188d1149cde40c1df17111c41a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 17 Dec 2017 17:10:38 +0100 Subject: Changelog 1731 https://github.com/FreshRSS/FreshRSS/pull/1731 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c53050cef..65e25bec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * Work-around for `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) * Fix PDO PostgreSQL detection [#1690](https://github.com/FreshRSS/FreshRSS/issues/1690) * Fix punycode warning in PHP 7.2 [#1699](https://github.com/FreshRSS/FreshRSS/issues/1699) + * Fix crash when adding a new category while adding a new feed [#1731](https://github.com/FreshRSS/FreshRSS/pull/1731) * Fix ExtensionManager exception handling [#1724](https://github.com/FreshRSS/FreshRSS/pull/1724) * CLI * New command `./cli/db-optimize.php` for database optimisation [#1583](https://github.com/FreshRSS/FreshRSS/issues/1583) -- cgit v1.2.3 From be3ed001a4803b4279c34249f20ebffc13c8cc9b Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Sun, 17 Dec 2017 17:46:04 +0100 Subject: Fix favicon for open_basedir (#1733) Remove open_basedir warning for CURLOPT_FOLLOWLOCATION with PHP 5.6.0- https://bugs.php.net/bug.php?id=65646 --- lib/favicons.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/favicons.php b/lib/favicons.php index 2d6f7aab7..75e40900a 100644 --- a/lib/favicons.php +++ b/lib/favicons.php @@ -24,7 +24,7 @@ function isImgMime($content) { function downloadHttp(&$url, $curlOptions = array()) { syslog(LOG_INFO, 'FreshRSS Favicon GET ' . $url); if (substr($url, 0, 2) === '//') { - $url = 'https:' . $favicon; + $url = 'https:' . $url; } if ($url == '' || filter_var($url, FILTER_VALIDATE_URL) === false) { return ''; @@ -36,7 +36,9 @@ function downloadHttp(&$url, $curlOptions = array()) { CURLOPT_USERAGENT => FRESHRSS_USERAGENT, CURLOPT_MAXREDIRS => 10, )); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir bug + if (ini_get('open_basedir') == '') { // see PHP bug 65646 + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + } if (defined('CURLOPT_ENCODING')) { curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings } -- cgit v1.2.3 From e399bc4b929b660908e60f1928014ae6445327f5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 17 Dec 2017 20:14:20 +0100 Subject: Remove warning for CURLOPT_FOLLOWLOCATION with open_basedir (#1734) For PHP 5.6.0- http://www.php.net/ChangeLog-5.php#5.6.0 https://bugs.php.net/bug.php?id=65646 https://github.com/FreshRSS/FreshRSS/pull/1733 https://github.com/FreshRSS/FreshRSS/pull/1657 https://github.com/FreshRSS/FreshRSS/issues/1655 --- app/Models/Feed.php | 4 +++- lib/favicons.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 75d9f6d6f..560f7415d 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -491,7 +491,9 @@ class FreshRSS_Feed extends Minz_Model { CURLOPT_USERAGENT => FRESHRSS_USERAGENT, CURLOPT_MAXREDIRS => 10, )); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir bug + if (version_compare(PHP_VERSION, '5.6.0') >= 0 || ini_get('open_basedir') == '') { + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir PHP bug 65646 + } if (defined('CURLOPT_ENCODING')) { curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings } diff --git a/lib/favicons.php b/lib/favicons.php index 75e40900a..fe2e65f1f 100644 --- a/lib/favicons.php +++ b/lib/favicons.php @@ -36,8 +36,8 @@ function downloadHttp(&$url, $curlOptions = array()) { CURLOPT_USERAGENT => FRESHRSS_USERAGENT, CURLOPT_MAXREDIRS => 10, )); - if (ini_get('open_basedir') == '') { // see PHP bug 65646 - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + if (version_compare(PHP_VERSION, '5.6.0') >= 0 || ini_get('open_basedir') == '') { + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir PHP bug 65646 } if (defined('CURLOPT_ENCODING')) { curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings -- cgit v1.2.3 From 0b1516af91792f86868689392f72ad4b6e32cdcf Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 17 Dec 2017 20:15:10 +0100 Subject: Prepare release of FreshRSS 1.9.0 --- CHANGELOG.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65e25bec4..77252fb78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,7 @@ # FreshRSS changelog -## 2017-12-17 FreshRSS 1.9.0-dev +## 2017-12-17 FreshRSS 1.9.0 -* API - * Breaking change / compatibility fix (EasyRSS): Provide `link` to articles without HTML-encoding [#1683](https://github.com/FreshRSS/FreshRSS/issues/1683) * Features * Share with Mastodon [#1521](https://github.com/FreshRSS/FreshRSS/issues/1521) * UI @@ -13,7 +11,7 @@ * SimplePie * Remove "SimplePie" name from HTTP User-Agent string [#1656](https://github.com/FreshRSS/FreshRSS/pull/1656) * Bug fixing - * Work-around for `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) + * Work-around for PHP 5.6.0- `CURLOPT_FOLLOWLOCATION` `open_basedir` bug in favicons and PubSubHubbub [#1655](https://github.com/FreshRSS/FreshRSS/issues/1655) * Fix PDO PostgreSQL detection [#1690](https://github.com/FreshRSS/FreshRSS/issues/1690) * Fix punycode warning in PHP 7.2 [#1699](https://github.com/FreshRSS/FreshRSS/issues/1699) * Fix crash when adding a new category while adding a new feed [#1731](https://github.com/FreshRSS/FreshRSS/pull/1731) @@ -23,13 +21,15 @@ * Check PHP requirements before running `actualize_script.php` (cron for refreshing feeds) [#1711](https://github.com/FreshRSS/FreshRSS/pull/1711) * SQL * Perform `VACUUM` on SQLite and PostgreSQL databases when optimisation is requested [#918](https://github.com/FreshRSS/FreshRSS/issues/918) -* I18n - * Hebrew [#1716](https://github.com/FreshRSS/FreshRSS/pull/1716) - * Improved German [#1698](https://github.com/FreshRSS/FreshRSS/pull/1698) +* API + * Breaking change / compatibility fix (EasyRSS): Provide `link` to articles without HTML-encoding [#1683](https://github.com/FreshRSS/FreshRSS/issues/1683) * Extensions * Breaking change: uppercase `./Controllers/` directory [#1729](https://github.com/FreshRSS/FreshRSS/pull/1729) * Show existing extensions in admin panel [#1708](https://github.com/FreshRSS/FreshRSS/pull/1708) * New function `$entry->_hash($hex)` for extensions that change the content of entries [#1707](https://github.com/FreshRSS/FreshRSS/pull/1707) +* I18n + * Hebrew [#1716](https://github.com/FreshRSS/FreshRSS/pull/1716) + * Improved German [#1698](https://github.com/FreshRSS/FreshRSS/pull/1698) * Misc. * Customisable `constants.local.php` [#1725](https://github.com/FreshRSS/FreshRSS/pull/1725) * Basic mechanism to limit the size of the logs [#1712](https://github.com/FreshRSS/FreshRSS/pull/1712) -- cgit v1.2.3