mirror of
https://github.com/miniflux/v2.git
synced 2025-09-15 18:57:04 +00:00
fix(timezone): make sure legacy time zones are no longer used
Debian Trixie has removed several time zones. This change makes sure only the current IANA time zones are in use.
This commit is contained in:
parent
4eff9129ab
commit
b1742168e1
6 changed files with 652 additions and 54 deletions
|
@ -1158,4 +1158,187 @@ var migrations = [...]func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
|
// This migration replaces deprecated timezones by their equivalent on Debian Trixie.
|
||||||
|
func(tx *sql.Tx) (err error) {
|
||||||
|
var deprecatedTimeZoneMap = map[string]string{
|
||||||
|
// Africa
|
||||||
|
"Africa/Asmera": "Africa/Asmara",
|
||||||
|
|
||||||
|
// America - Argentina
|
||||||
|
"America/Argentina/ComodRivadavia": "America/Argentina/Catamarca",
|
||||||
|
"America/Buenos_Aires": "America/Argentina/Buenos_Aires",
|
||||||
|
"America/Catamarca": "America/Argentina/Catamarca",
|
||||||
|
"America/Cordoba": "America/Argentina/Cordoba",
|
||||||
|
"America/Jujuy": "America/Argentina/Jujuy",
|
||||||
|
"America/Mendoza": "America/Argentina/Mendoza",
|
||||||
|
"America/Rosario": "America/Argentina/Cordoba",
|
||||||
|
|
||||||
|
// America - US
|
||||||
|
"America/Fort_Wayne": "America/Indiana/Indianapolis",
|
||||||
|
"America/Indianapolis": "America/Indiana/Indianapolis",
|
||||||
|
"America/Knox_IN": "America/Indiana/Knox",
|
||||||
|
"America/Louisville": "America/Kentucky/Louisville",
|
||||||
|
|
||||||
|
// America - Greenland
|
||||||
|
"America/Godthab": "America/Nuuk",
|
||||||
|
|
||||||
|
// Antarctica
|
||||||
|
"Antarctica/South_Pole": "Pacific/Auckland",
|
||||||
|
|
||||||
|
// Asia
|
||||||
|
"Asia/Ashkhabad": "Asia/Ashgabat",
|
||||||
|
"Asia/Calcutta": "Asia/Kolkata",
|
||||||
|
"Asia/Choibalsan": "Asia/Ulaanbaatar",
|
||||||
|
"Asia/Chungking": "Asia/Chongqing",
|
||||||
|
"Asia/Dacca": "Asia/Dhaka",
|
||||||
|
"Asia/Katmandu": "Asia/Kathmandu",
|
||||||
|
"Asia/Macao": "Asia/Macau",
|
||||||
|
"Asia/Rangoon": "Asia/Yangon",
|
||||||
|
"Asia/Saigon": "Asia/Ho_Chi_Minh",
|
||||||
|
"Asia/Thimbu": "Asia/Thimphu",
|
||||||
|
"Asia/Ujung_Pandang": "Asia/Makassar",
|
||||||
|
"Asia/Ulan_Bator": "Asia/Ulaanbaatar",
|
||||||
|
|
||||||
|
// Atlantic
|
||||||
|
"Atlantic/Faeroe": "Atlantic/Faroe",
|
||||||
|
|
||||||
|
// Australia
|
||||||
|
"Australia/ACT": "Australia/Sydney",
|
||||||
|
"Australia/LHI": "Australia/Lord_Howe",
|
||||||
|
"Australia/North": "Australia/Darwin",
|
||||||
|
"Australia/NSW": "Australia/Sydney",
|
||||||
|
"Australia/Queensland": "Australia/Brisbane",
|
||||||
|
"Australia/South": "Australia/Adelaide",
|
||||||
|
"Australia/Tasmania": "Australia/Hobart",
|
||||||
|
"Australia/Victoria": "Australia/Melbourne",
|
||||||
|
"Australia/West": "Australia/Perth",
|
||||||
|
|
||||||
|
// Brazil
|
||||||
|
"Brazil/Acre": "America/Rio_Branco",
|
||||||
|
"Brazil/DeNoronha": "America/Noronha",
|
||||||
|
"Brazil/East": "America/Sao_Paulo",
|
||||||
|
"Brazil/West": "America/Manaus",
|
||||||
|
|
||||||
|
// Canada
|
||||||
|
"Canada/Atlantic": "America/Halifax",
|
||||||
|
"Canada/Central": "America/Winnipeg",
|
||||||
|
"Canada/Eastern": "America/Toronto",
|
||||||
|
"Canada/Mountain": "America/Edmonton",
|
||||||
|
"Canada/Newfoundland": "America/St_Johns",
|
||||||
|
"Canada/Pacific": "America/Vancouver",
|
||||||
|
"Canada/Saskatchewan": "America/Regina",
|
||||||
|
"Canada/Yukon": "America/Whitehorse",
|
||||||
|
|
||||||
|
// Europe
|
||||||
|
"CET": "Europe/Paris",
|
||||||
|
"EET": "Europe/Sofia",
|
||||||
|
"Europe/Kiev": "Europe/Kyiv",
|
||||||
|
"Europe/Uzhgorod": "Europe/Kyiv",
|
||||||
|
"Europe/Zaporozhye": "Europe/Kyiv",
|
||||||
|
"MET": "Europe/Paris",
|
||||||
|
"WET": "Europe/Lisbon",
|
||||||
|
|
||||||
|
// Chile
|
||||||
|
"Chile/Continental": "America/Santiago",
|
||||||
|
"Chile/EasterIsland": "Pacific/Easter",
|
||||||
|
|
||||||
|
// Fixed offset and generic zones
|
||||||
|
"CST6CDT": "America/Chicago",
|
||||||
|
"EST": "America/New_York",
|
||||||
|
"EST5EDT": "America/New_York",
|
||||||
|
"HST": "Pacific/Honolulu",
|
||||||
|
"MST": "America/Denver",
|
||||||
|
"MST7MDT": "America/Denver",
|
||||||
|
"PST8PDT": "America/Los_Angeles",
|
||||||
|
|
||||||
|
// Countries/Regions
|
||||||
|
"Cuba": "America/Havana",
|
||||||
|
"Egypt": "Africa/Cairo",
|
||||||
|
"Eire": "Europe/Dublin",
|
||||||
|
"GB": "Europe/London",
|
||||||
|
"GB-Eire": "Europe/London",
|
||||||
|
"Hongkong": "Asia/Hong_Kong",
|
||||||
|
"Iceland": "Atlantic/Reykjavik",
|
||||||
|
"Iran": "Asia/Tehran",
|
||||||
|
"Israel": "Asia/Jerusalem",
|
||||||
|
"Jamaica": "America/Jamaica",
|
||||||
|
"Japan": "Asia/Tokyo",
|
||||||
|
"Libya": "Africa/Tripoli",
|
||||||
|
"Poland": "Europe/Warsaw",
|
||||||
|
"Portugal": "Europe/Lisbon",
|
||||||
|
"PRC": "Asia/Shanghai",
|
||||||
|
"ROC": "Asia/Taipei",
|
||||||
|
"ROK": "Asia/Seoul",
|
||||||
|
"Singapore": "Asia/Singapore",
|
||||||
|
"Turkey": "Europe/Istanbul",
|
||||||
|
|
||||||
|
// GMT variations
|
||||||
|
"GMT+0": "GMT",
|
||||||
|
"GMT-0": "GMT",
|
||||||
|
"GMT0": "GMT",
|
||||||
|
"Greenwich": "GMT",
|
||||||
|
"UCT": "UTC",
|
||||||
|
"Universal": "UTC",
|
||||||
|
"Zulu": "UTC",
|
||||||
|
|
||||||
|
// Mexico
|
||||||
|
"Mexico/BajaNorte": "America/Tijuana",
|
||||||
|
"Mexico/BajaSur": "America/Mazatlan",
|
||||||
|
"Mexico/General": "America/Mexico_City",
|
||||||
|
|
||||||
|
// US zones
|
||||||
|
"Navajo": "America/Denver",
|
||||||
|
"US/Alaska": "America/Anchorage",
|
||||||
|
"US/Aleutian": "America/Adak",
|
||||||
|
"US/Arizona": "America/Phoenix",
|
||||||
|
"US/Central": "America/Chicago",
|
||||||
|
"US/Eastern": "America/New_York",
|
||||||
|
"US/East-Indiana": "America/Indiana/Indianapolis",
|
||||||
|
"US/Hawaii": "Pacific/Honolulu",
|
||||||
|
"US/Indiana-Starke": "America/Indiana/Knox",
|
||||||
|
"US/Michigan": "America/Detroit",
|
||||||
|
"US/Mountain": "America/Denver",
|
||||||
|
"US/Pacific": "America/Los_Angeles",
|
||||||
|
"US/Samoa": "Pacific/Pago_Pago",
|
||||||
|
|
||||||
|
// Pacific
|
||||||
|
"Kwajalein": "Pacific/Kwajalein",
|
||||||
|
"NZ": "Pacific/Auckland",
|
||||||
|
"NZ-CHAT": "Pacific/Chatham",
|
||||||
|
"Pacific/Enderbury": "Pacific/Kanton",
|
||||||
|
"Pacific/Ponape": "Pacific/Pohnpei",
|
||||||
|
"Pacific/Truk": "Pacific/Chuuk",
|
||||||
|
|
||||||
|
// Special cases
|
||||||
|
"Factory": "UTC", // Factory is used for unconfigured systems
|
||||||
|
"W-SU": "Europe/Moscow",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through each user and correct the timezone
|
||||||
|
rows, err := tx.Query(`SELECT id, timezone FROM users`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userTimezoneMap := make(map[int64]string)
|
||||||
|
for rows.Next() {
|
||||||
|
var userID int64
|
||||||
|
var userTimezone string
|
||||||
|
if err := rows.Scan(&userID, &userTimezone); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
userTimezoneMap[userID] = userTimezone
|
||||||
|
}
|
||||||
|
rows.Close()
|
||||||
|
|
||||||
|
for userID, userTimezone := range userTimezoneMap {
|
||||||
|
if newTimezone, found := deprecatedTimeZoneMap[userTimezone]; found {
|
||||||
|
if _, err := tx.Exec(`UPDATE users SET timezone = $1 WHERE id = $2`, newTimezone, userID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package storage // import "miniflux.app/v2/internal/storage"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Timezones returns all timezones supported by the database.
|
|
||||||
func (s *Storage) Timezones() (map[string]string, error) {
|
|
||||||
timezones := make(map[string]string)
|
|
||||||
rows, err := s.db.Query(`SELECT name FROM pg_timezone_names ORDER BY name ASC`)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(`store: unable to fetch timezones: %v`, err)
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var timezone string
|
|
||||||
if err := rows.Scan(&timezone); err != nil {
|
|
||||||
return nil, fmt.Errorf(`store: unable to fetch timezones row: %v`, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(timezone, "posix") && !strings.HasPrefix(timezone, "SystemV") && timezone != "localtime" {
|
|
||||||
timezones[timezone] = timezone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return timezones, nil
|
|
||||||
}
|
|
|
@ -59,3 +59,464 @@ func getLocation(tz string) *time.Location {
|
||||||
tzCache.Store(tz, loc)
|
tzCache.Store(tz, loc)
|
||||||
return loc
|
return loc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AvailableTimezones returns a map of supported timezones.
|
||||||
|
// This list is taken from Postgres on Debian Trixie.
|
||||||
|
func AvailableTimezones() map[string]string {
|
||||||
|
timezones := []string{
|
||||||
|
"Africa/Abidjan",
|
||||||
|
"Africa/Accra",
|
||||||
|
"Africa/Addis_Ababa",
|
||||||
|
"Africa/Algiers",
|
||||||
|
"Africa/Asmara",
|
||||||
|
"Africa/Bamako",
|
||||||
|
"Africa/Bangui",
|
||||||
|
"Africa/Banjul",
|
||||||
|
"Africa/Bissau",
|
||||||
|
"Africa/Blantyre",
|
||||||
|
"Africa/Brazzaville",
|
||||||
|
"Africa/Bujumbura",
|
||||||
|
"Africa/Cairo",
|
||||||
|
"Africa/Casablanca",
|
||||||
|
"Africa/Ceuta",
|
||||||
|
"Africa/Conakry",
|
||||||
|
"Africa/Dakar",
|
||||||
|
"Africa/Dar_es_Salaam",
|
||||||
|
"Africa/Djibouti",
|
||||||
|
"Africa/Douala",
|
||||||
|
"Africa/El_Aaiun",
|
||||||
|
"Africa/Freetown",
|
||||||
|
"Africa/Gaborone",
|
||||||
|
"Africa/Harare",
|
||||||
|
"Africa/Johannesburg",
|
||||||
|
"Africa/Juba",
|
||||||
|
"Africa/Kampala",
|
||||||
|
"Africa/Khartoum",
|
||||||
|
"Africa/Kigali",
|
||||||
|
"Africa/Kinshasa",
|
||||||
|
"Africa/Lagos",
|
||||||
|
"Africa/Libreville",
|
||||||
|
"Africa/Lome",
|
||||||
|
"Africa/Luanda",
|
||||||
|
"Africa/Lubumbashi",
|
||||||
|
"Africa/Lusaka",
|
||||||
|
"Africa/Malabo",
|
||||||
|
"Africa/Maputo",
|
||||||
|
"Africa/Maseru",
|
||||||
|
"Africa/Mbabane",
|
||||||
|
"Africa/Mogadishu",
|
||||||
|
"Africa/Monrovia",
|
||||||
|
"Africa/Nairobi",
|
||||||
|
"Africa/Ndjamena",
|
||||||
|
"Africa/Niamey",
|
||||||
|
"Africa/Nouakchott",
|
||||||
|
"Africa/Ouagadougou",
|
||||||
|
"Africa/Porto-Novo",
|
||||||
|
"Africa/Sao_Tome",
|
||||||
|
"Africa/Timbuktu",
|
||||||
|
"Africa/Tripoli",
|
||||||
|
"Africa/Tunis",
|
||||||
|
"Africa/Windhoek",
|
||||||
|
"America/Adak",
|
||||||
|
"America/Anchorage",
|
||||||
|
"America/Anguilla",
|
||||||
|
"America/Antigua",
|
||||||
|
"America/Araguaina",
|
||||||
|
"America/Argentina/Buenos_Aires",
|
||||||
|
"America/Argentina/Catamarca",
|
||||||
|
"America/Argentina/Cordoba",
|
||||||
|
"America/Argentina/Jujuy",
|
||||||
|
"America/Argentina/La_Rioja",
|
||||||
|
"America/Argentina/Mendoza",
|
||||||
|
"America/Argentina/Rio_Gallegos",
|
||||||
|
"America/Argentina/Salta",
|
||||||
|
"America/Argentina/San_Juan",
|
||||||
|
"America/Argentina/San_Luis",
|
||||||
|
"America/Argentina/Tucuman",
|
||||||
|
"America/Argentina/Ushuaia",
|
||||||
|
"America/Aruba",
|
||||||
|
"America/Asuncion",
|
||||||
|
"America/Atikokan",
|
||||||
|
"America/Atka",
|
||||||
|
"America/Bahia",
|
||||||
|
"America/Bahia_Banderas",
|
||||||
|
"America/Barbados",
|
||||||
|
"America/Belem",
|
||||||
|
"America/Belize",
|
||||||
|
"America/Blanc-Sablon",
|
||||||
|
"America/Boa_Vista",
|
||||||
|
"America/Bogota",
|
||||||
|
"America/Boise",
|
||||||
|
"America/Cambridge_Bay",
|
||||||
|
"America/Campo_Grande",
|
||||||
|
"America/Cancun",
|
||||||
|
"America/Caracas",
|
||||||
|
"America/Cayenne",
|
||||||
|
"America/Cayman",
|
||||||
|
"America/Chicago",
|
||||||
|
"America/Chihuahua",
|
||||||
|
"America/Ciudad_Juarez",
|
||||||
|
"America/Coral_Harbour",
|
||||||
|
"America/Costa_Rica",
|
||||||
|
"America/Coyhaique",
|
||||||
|
"America/Creston",
|
||||||
|
"America/Cuiaba",
|
||||||
|
"America/Curacao",
|
||||||
|
"America/Danmarkshavn",
|
||||||
|
"America/Dawson",
|
||||||
|
"America/Dawson_Creek",
|
||||||
|
"America/Denver",
|
||||||
|
"America/Detroit",
|
||||||
|
"America/Dominica",
|
||||||
|
"America/Edmonton",
|
||||||
|
"America/Eirunepe",
|
||||||
|
"America/El_Salvador",
|
||||||
|
"America/Ensenada",
|
||||||
|
"America/Fortaleza",
|
||||||
|
"America/Fort_Nelson",
|
||||||
|
"America/Glace_Bay",
|
||||||
|
"America/Goose_Bay",
|
||||||
|
"America/Grand_Turk",
|
||||||
|
"America/Grenada",
|
||||||
|
"America/Guadeloupe",
|
||||||
|
"America/Guatemala",
|
||||||
|
"America/Guayaquil",
|
||||||
|
"America/Guyana",
|
||||||
|
"America/Halifax",
|
||||||
|
"America/Havana",
|
||||||
|
"America/Hermosillo",
|
||||||
|
"America/Indiana/Indianapolis",
|
||||||
|
"America/Indiana/Knox",
|
||||||
|
"America/Indiana/Marengo",
|
||||||
|
"America/Indiana/Petersburg",
|
||||||
|
"America/Indiana/Tell_City",
|
||||||
|
"America/Indiana/Vevay",
|
||||||
|
"America/Indiana/Vincennes",
|
||||||
|
"America/Indiana/Winamac",
|
||||||
|
"America/Inuvik",
|
||||||
|
"America/Iqaluit",
|
||||||
|
"America/Jamaica",
|
||||||
|
"America/Juneau",
|
||||||
|
"America/Kentucky/Louisville",
|
||||||
|
"America/Kentucky/Monticello",
|
||||||
|
"America/Kralendijk",
|
||||||
|
"America/La_Paz",
|
||||||
|
"America/Lima",
|
||||||
|
"America/Los_Angeles",
|
||||||
|
"America/Lower_Princes",
|
||||||
|
"America/Maceio",
|
||||||
|
"America/Managua",
|
||||||
|
"America/Manaus",
|
||||||
|
"America/Marigot",
|
||||||
|
"America/Martinique",
|
||||||
|
"America/Matamoros",
|
||||||
|
"America/Mazatlan",
|
||||||
|
"America/Menominee",
|
||||||
|
"America/Merida",
|
||||||
|
"America/Metlakatla",
|
||||||
|
"America/Mexico_City",
|
||||||
|
"America/Miquelon",
|
||||||
|
"America/Moncton",
|
||||||
|
"America/Monterrey",
|
||||||
|
"America/Montevideo",
|
||||||
|
"America/Montreal",
|
||||||
|
"America/Montserrat",
|
||||||
|
"America/Nassau",
|
||||||
|
"America/New_York",
|
||||||
|
"America/Nipigon",
|
||||||
|
"America/Nome",
|
||||||
|
"America/Noronha",
|
||||||
|
"America/North_Dakota/Beulah",
|
||||||
|
"America/North_Dakota/Center",
|
||||||
|
"America/North_Dakota/New_Salem",
|
||||||
|
"America/Nuuk",
|
||||||
|
"America/Ojinaga",
|
||||||
|
"America/Panama",
|
||||||
|
"America/Pangnirtung",
|
||||||
|
"America/Paramaribo",
|
||||||
|
"America/Phoenix",
|
||||||
|
"America/Port-au-Prince",
|
||||||
|
"America/Porto_Acre",
|
||||||
|
"America/Port_of_Spain",
|
||||||
|
"America/Porto_Velho",
|
||||||
|
"America/Puerto_Rico",
|
||||||
|
"America/Punta_Arenas",
|
||||||
|
"America/Rainy_River",
|
||||||
|
"America/Rankin_Inlet",
|
||||||
|
"America/Recife",
|
||||||
|
"America/Regina",
|
||||||
|
"America/Resolute",
|
||||||
|
"America/Rio_Branco",
|
||||||
|
"America/Santa_Isabel",
|
||||||
|
"America/Santarem",
|
||||||
|
"America/Santiago",
|
||||||
|
"America/Santo_Domingo",
|
||||||
|
"America/Sao_Paulo",
|
||||||
|
"America/Scoresbysund",
|
||||||
|
"America/Shiprock",
|
||||||
|
"America/Sitka",
|
||||||
|
"America/St_Barthelemy",
|
||||||
|
"America/St_Johns",
|
||||||
|
"America/St_Kitts",
|
||||||
|
"America/St_Lucia",
|
||||||
|
"America/St_Thomas",
|
||||||
|
"America/St_Vincent",
|
||||||
|
"America/Swift_Current",
|
||||||
|
"America/Tegucigalpa",
|
||||||
|
"America/Thule",
|
||||||
|
"America/Thunder_Bay",
|
||||||
|
"America/Tijuana",
|
||||||
|
"America/Toronto",
|
||||||
|
"America/Tortola",
|
||||||
|
"America/Vancouver",
|
||||||
|
"America/Virgin",
|
||||||
|
"America/Whitehorse",
|
||||||
|
"America/Winnipeg",
|
||||||
|
"America/Yakutat",
|
||||||
|
"America/Yellowknife",
|
||||||
|
"Antarctica/Casey",
|
||||||
|
"Antarctica/Davis",
|
||||||
|
"Antarctica/DumontDUrville",
|
||||||
|
"Antarctica/Macquarie",
|
||||||
|
"Antarctica/Mawson",
|
||||||
|
"Antarctica/McMurdo",
|
||||||
|
"Antarctica/Palmer",
|
||||||
|
"Antarctica/Rothera",
|
||||||
|
"Antarctica/Syowa",
|
||||||
|
"Antarctica/Troll",
|
||||||
|
"Antarctica/Vostok",
|
||||||
|
"Arctic/Longyearbyen",
|
||||||
|
"Asia/Aden",
|
||||||
|
"Asia/Almaty",
|
||||||
|
"Asia/Amman",
|
||||||
|
"Asia/Anadyr",
|
||||||
|
"Asia/Aqtau",
|
||||||
|
"Asia/Aqtobe",
|
||||||
|
"Asia/Ashgabat",
|
||||||
|
"Asia/Atyrau",
|
||||||
|
"Asia/Baghdad",
|
||||||
|
"Asia/Bahrain",
|
||||||
|
"Asia/Baku",
|
||||||
|
"Asia/Bangkok",
|
||||||
|
"Asia/Barnaul",
|
||||||
|
"Asia/Beirut",
|
||||||
|
"Asia/Bishkek",
|
||||||
|
"Asia/Brunei",
|
||||||
|
"Asia/Chita",
|
||||||
|
"Asia/Chongqing",
|
||||||
|
"Asia/Colombo",
|
||||||
|
"Asia/Damascus",
|
||||||
|
"Asia/Dhaka",
|
||||||
|
"Asia/Dili",
|
||||||
|
"Asia/Dubai",
|
||||||
|
"Asia/Dushanbe",
|
||||||
|
"Asia/Famagusta",
|
||||||
|
"Asia/Gaza",
|
||||||
|
"Asia/Harbin",
|
||||||
|
"Asia/Hebron",
|
||||||
|
"Asia/Ho_Chi_Minh",
|
||||||
|
"Asia/Hong_Kong",
|
||||||
|
"Asia/Hovd",
|
||||||
|
"Asia/Irkutsk",
|
||||||
|
"Asia/Istanbul",
|
||||||
|
"Asia/Jakarta",
|
||||||
|
"Asia/Jayapura",
|
||||||
|
"Asia/Jerusalem",
|
||||||
|
"Asia/Kabul",
|
||||||
|
"Asia/Kamchatka",
|
||||||
|
"Asia/Karachi",
|
||||||
|
"Asia/Kashgar",
|
||||||
|
"Asia/Kathmandu",
|
||||||
|
"Asia/Khandyga",
|
||||||
|
"Asia/Kolkata",
|
||||||
|
"Asia/Krasnoyarsk",
|
||||||
|
"Asia/Kuala_Lumpur",
|
||||||
|
"Asia/Kuching",
|
||||||
|
"Asia/Kuwait",
|
||||||
|
"Asia/Macau",
|
||||||
|
"Asia/Magadan",
|
||||||
|
"Asia/Makassar",
|
||||||
|
"Asia/Manila",
|
||||||
|
"Asia/Muscat",
|
||||||
|
"Asia/Nicosia",
|
||||||
|
"Asia/Novokuznetsk",
|
||||||
|
"Asia/Novosibirsk",
|
||||||
|
"Asia/Omsk",
|
||||||
|
"Asia/Oral",
|
||||||
|
"Asia/Phnom_Penh",
|
||||||
|
"Asia/Pontianak",
|
||||||
|
"Asia/Pyongyang",
|
||||||
|
"Asia/Qatar",
|
||||||
|
"Asia/Qostanay",
|
||||||
|
"Asia/Qyzylorda",
|
||||||
|
"Asia/Riyadh",
|
||||||
|
"Asia/Sakhalin",
|
||||||
|
"Asia/Samarkand",
|
||||||
|
"Asia/Seoul",
|
||||||
|
"Asia/Shanghai",
|
||||||
|
"Asia/Singapore",
|
||||||
|
"Asia/Srednekolymsk",
|
||||||
|
"Asia/Taipei",
|
||||||
|
"Asia/Tashkent",
|
||||||
|
"Asia/Tbilisi",
|
||||||
|
"Asia/Tehran",
|
||||||
|
"Asia/Tel_Aviv",
|
||||||
|
"Asia/Thimphu",
|
||||||
|
"Asia/Tokyo",
|
||||||
|
"Asia/Tomsk",
|
||||||
|
"Asia/Ulaanbaatar",
|
||||||
|
"Asia/Urumqi",
|
||||||
|
"Asia/Ust-Nera",
|
||||||
|
"Asia/Vientiane",
|
||||||
|
"Asia/Vladivostok",
|
||||||
|
"Asia/Yakutsk",
|
||||||
|
"Asia/Yangon",
|
||||||
|
"Asia/Yekaterinburg",
|
||||||
|
"Asia/Yerevan",
|
||||||
|
"Atlantic/Azores",
|
||||||
|
"Atlantic/Bermuda",
|
||||||
|
"Atlantic/Canary",
|
||||||
|
"Atlantic/Cape_Verde",
|
||||||
|
"Atlantic/Faroe",
|
||||||
|
"Atlantic/Jan_Mayen",
|
||||||
|
"Atlantic/Madeira",
|
||||||
|
"Atlantic/Reykjavik",
|
||||||
|
"Atlantic/South_Georgia",
|
||||||
|
"Atlantic/Stanley",
|
||||||
|
"Atlantic/St_Helena",
|
||||||
|
"Australia/Adelaide",
|
||||||
|
"Australia/Brisbane",
|
||||||
|
"Australia/Broken_Hill",
|
||||||
|
"Australia/Canberra",
|
||||||
|
"Australia/Currie",
|
||||||
|
"Australia/Darwin",
|
||||||
|
"Australia/Eucla",
|
||||||
|
"Australia/Hobart",
|
||||||
|
"Australia/Lindeman",
|
||||||
|
"Australia/Lord_Howe",
|
||||||
|
"Australia/Melbourne",
|
||||||
|
"Australia/Perth",
|
||||||
|
"Australia/Sydney",
|
||||||
|
"Australia/Yancowinna",
|
||||||
|
"Europe/Amsterdam",
|
||||||
|
"Europe/Andorra",
|
||||||
|
"Europe/Astrakhan",
|
||||||
|
"Europe/Athens",
|
||||||
|
"Europe/Belfast",
|
||||||
|
"Europe/Belgrade",
|
||||||
|
"Europe/Berlin",
|
||||||
|
"Europe/Bratislava",
|
||||||
|
"Europe/Brussels",
|
||||||
|
"Europe/Bucharest",
|
||||||
|
"Europe/Budapest",
|
||||||
|
"Europe/Busingen",
|
||||||
|
"Europe/Chisinau",
|
||||||
|
"Europe/Copenhagen",
|
||||||
|
"Europe/Dublin",
|
||||||
|
"Europe/Gibraltar",
|
||||||
|
"Europe/Guernsey",
|
||||||
|
"Europe/Helsinki",
|
||||||
|
"Europe/Isle_of_Man",
|
||||||
|
"Europe/Istanbul",
|
||||||
|
"Europe/Jersey",
|
||||||
|
"Europe/Kaliningrad",
|
||||||
|
"Europe/Kirov",
|
||||||
|
"Europe/Kyiv",
|
||||||
|
"Europe/Lisbon",
|
||||||
|
"Europe/Ljubljana",
|
||||||
|
"Europe/London",
|
||||||
|
"Europe/Luxembourg",
|
||||||
|
"Europe/Madrid",
|
||||||
|
"Europe/Malta",
|
||||||
|
"Europe/Mariehamn",
|
||||||
|
"Europe/Minsk",
|
||||||
|
"Europe/Monaco",
|
||||||
|
"Europe/Moscow",
|
||||||
|
"Europe/Nicosia",
|
||||||
|
"Europe/Oslo",
|
||||||
|
"Europe/Paris",
|
||||||
|
"Europe/Podgorica",
|
||||||
|
"Europe/Prague",
|
||||||
|
"Europe/Riga",
|
||||||
|
"Europe/Rome",
|
||||||
|
"Europe/Samara",
|
||||||
|
"Europe/San_Marino",
|
||||||
|
"Europe/Sarajevo",
|
||||||
|
"Europe/Saratov",
|
||||||
|
"Europe/Simferopol",
|
||||||
|
"Europe/Skopje",
|
||||||
|
"Europe/Sofia",
|
||||||
|
"Europe/Stockholm",
|
||||||
|
"Europe/Tallinn",
|
||||||
|
"Europe/Tirane",
|
||||||
|
"Europe/Tiraspol",
|
||||||
|
"Europe/Ulyanovsk",
|
||||||
|
"Europe/Vaduz",
|
||||||
|
"Europe/Vatican",
|
||||||
|
"Europe/Vienna",
|
||||||
|
"Europe/Vilnius",
|
||||||
|
"Europe/Volgograd",
|
||||||
|
"Europe/Warsaw",
|
||||||
|
"Europe/Zagreb",
|
||||||
|
"Europe/Zurich",
|
||||||
|
"GMT",
|
||||||
|
"Indian/Antananarivo",
|
||||||
|
"Indian/Chagos",
|
||||||
|
"Indian/Christmas",
|
||||||
|
"Indian/Cocos",
|
||||||
|
"Indian/Comoro",
|
||||||
|
"Indian/Kerguelen",
|
||||||
|
"Indian/Mahe",
|
||||||
|
"Indian/Maldives",
|
||||||
|
"Indian/Mauritius",
|
||||||
|
"Indian/Mayotte",
|
||||||
|
"Indian/Reunion",
|
||||||
|
"Pacific/Apia",
|
||||||
|
"Pacific/Auckland",
|
||||||
|
"Pacific/Bougainville",
|
||||||
|
"Pacific/Chatham",
|
||||||
|
"Pacific/Chuuk",
|
||||||
|
"Pacific/Easter",
|
||||||
|
"Pacific/Efate",
|
||||||
|
"Pacific/Fakaofo",
|
||||||
|
"Pacific/Fiji",
|
||||||
|
"Pacific/Funafuti",
|
||||||
|
"Pacific/Galapagos",
|
||||||
|
"Pacific/Gambier",
|
||||||
|
"Pacific/Guadalcanal",
|
||||||
|
"Pacific/Guam",
|
||||||
|
"Pacific/Honolulu",
|
||||||
|
"Pacific/Johnston",
|
||||||
|
"Pacific/Kanton",
|
||||||
|
"Pacific/Kiritimati",
|
||||||
|
"Pacific/Kosrae",
|
||||||
|
"Pacific/Kwajalein",
|
||||||
|
"Pacific/Majuro",
|
||||||
|
"Pacific/Marquesas",
|
||||||
|
"Pacific/Midway",
|
||||||
|
"Pacific/Nauru",
|
||||||
|
"Pacific/Niue",
|
||||||
|
"Pacific/Norfolk",
|
||||||
|
"Pacific/Noumea",
|
||||||
|
"Pacific/Pago_Pago",
|
||||||
|
"Pacific/Palau",
|
||||||
|
"Pacific/Pitcairn",
|
||||||
|
"Pacific/Pohnpei",
|
||||||
|
"Pacific/Port_Moresby",
|
||||||
|
"Pacific/Rarotonga",
|
||||||
|
"Pacific/Saipan",
|
||||||
|
"Pacific/Samoa",
|
||||||
|
"Pacific/Tahiti",
|
||||||
|
"Pacific/Tarawa",
|
||||||
|
"Pacific/Tongatapu",
|
||||||
|
"Pacific/Wake",
|
||||||
|
"Pacific/Wallis",
|
||||||
|
"Pacific/Yap",
|
||||||
|
"UTC",
|
||||||
|
}
|
||||||
|
availableTimezones := make(map[string]string, len(timezones))
|
||||||
|
for _, tz := range timezones {
|
||||||
|
availableTimezones[tz] = tz
|
||||||
|
}
|
||||||
|
return availableTimezones
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"miniflux.app/v2/internal/http/response/html"
|
"miniflux.app/v2/internal/http/response/html"
|
||||||
"miniflux.app/v2/internal/locale"
|
"miniflux.app/v2/internal/locale"
|
||||||
"miniflux.app/v2/internal/model"
|
"miniflux.app/v2/internal/model"
|
||||||
|
"miniflux.app/v2/internal/timezone"
|
||||||
"miniflux.app/v2/internal/ui/form"
|
"miniflux.app/v2/internal/ui/form"
|
||||||
"miniflux.app/v2/internal/ui/session"
|
"miniflux.app/v2/internal/ui/session"
|
||||||
"miniflux.app/v2/internal/ui/view"
|
"miniflux.app/v2/internal/ui/view"
|
||||||
|
@ -50,12 +51,6 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
|
||||||
OpenExternalLinksInNewTab: user.OpenExternalLinksInNewTab,
|
OpenExternalLinksInNewTab: user.OpenExternalLinksInNewTab,
|
||||||
}
|
}
|
||||||
|
|
||||||
timezones, err := h.store.Timezones()
|
|
||||||
if err != nil {
|
|
||||||
html.ServerError(w, r, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := h.store.WebAuthnCredentialsByUserID(user.ID)
|
creds, err := h.store.WebAuthnCredentialsByUserID(user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
html.ServerError(w, r, err)
|
html.ServerError(w, r, err)
|
||||||
|
@ -73,7 +68,7 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
view.Set("themes", model.Themes())
|
view.Set("themes", model.Themes())
|
||||||
view.Set("languages", locale.AvailableLanguages)
|
view.Set("languages", locale.AvailableLanguages)
|
||||||
view.Set("timezones", timezones)
|
view.Set("timezones", timezone.AvailableTimezones())
|
||||||
view.Set("menu", "settings")
|
view.Set("menu", "settings")
|
||||||
view.Set("user", user)
|
view.Set("user", user)
|
||||||
view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
|
view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"miniflux.app/v2/internal/http/route"
|
"miniflux.app/v2/internal/http/route"
|
||||||
"miniflux.app/v2/internal/locale"
|
"miniflux.app/v2/internal/locale"
|
||||||
"miniflux.app/v2/internal/model"
|
"miniflux.app/v2/internal/model"
|
||||||
|
"miniflux.app/v2/internal/timezone"
|
||||||
"miniflux.app/v2/internal/ui/form"
|
"miniflux.app/v2/internal/ui/form"
|
||||||
"miniflux.app/v2/internal/ui/session"
|
"miniflux.app/v2/internal/ui/session"
|
||||||
"miniflux.app/v2/internal/ui/view"
|
"miniflux.app/v2/internal/ui/view"
|
||||||
|
@ -24,12 +25,6 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
timezones, err := h.store.Timezones()
|
|
||||||
if err != nil {
|
|
||||||
html.ServerError(w, r, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := h.store.WebAuthnCredentialsByUserID(user.ID)
|
creds, err := h.store.WebAuthnCredentialsByUserID(user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
html.ServerError(w, r, err)
|
html.ServerError(w, r, err)
|
||||||
|
@ -49,7 +44,7 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
view.Set("themes", model.Themes())
|
view.Set("themes", model.Themes())
|
||||||
view.Set("languages", locale.AvailableLanguages)
|
view.Set("languages", locale.AvailableLanguages)
|
||||||
view.Set("timezones", timezones)
|
view.Set("timezones", timezone.AvailableTimezones())
|
||||||
view.Set("menu", "settings")
|
view.Set("menu", "settings")
|
||||||
view.Set("user", user)
|
view.Set("user", user)
|
||||||
view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
|
view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"miniflux.app/v2/internal/locale"
|
"miniflux.app/v2/internal/locale"
|
||||||
"miniflux.app/v2/internal/model"
|
"miniflux.app/v2/internal/model"
|
||||||
"miniflux.app/v2/internal/storage"
|
"miniflux.app/v2/internal/storage"
|
||||||
|
"miniflux.app/v2/internal/timezone"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateUserCreationWithPassword validates user creation with a password.
|
// ValidateUserCreationWithPassword validates user creation with a password.
|
||||||
|
@ -63,7 +64,7 @@ func ValidateUserModification(store *storage.Storage, userID int64, changes *mod
|
||||||
}
|
}
|
||||||
|
|
||||||
if changes.Timezone != nil {
|
if changes.Timezone != nil {
|
||||||
if err := validateTimezone(store, *changes.Timezone); err != nil {
|
if err := validateTimezone(*changes.Timezone); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,13 +201,8 @@ func validateLanguage(language string) *locale.LocalizedError {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateTimezone(store *storage.Storage, timezone string) *locale.LocalizedError {
|
func validateTimezone(timezoneValue string) *locale.LocalizedError {
|
||||||
timezones, err := store.Timezones()
|
if _, found := timezone.AvailableTimezones()[timezoneValue]; !found {
|
||||||
if err != nil {
|
|
||||||
return locale.NewLocalizedError(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, found := timezones[timezone]; !found {
|
|
||||||
return locale.NewLocalizedError("error.invalid_timezone")
|
return locale.NewLocalizedError("error.invalid_timezone")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue