From 43c7dcb2a889b65ddf57705fae35759eedcc527c Mon Sep 17 00:00:00 2001 From: Mohammad20000 Date: Fri, 17 Nov 2023 16:07:16 +0330 Subject: [PATCH 1/2] add SOLAR_EXPIRE_DATE & EXPIRE_DATE --- app/dashboard/public/locales/en.json | 2 + app/dashboard/public/locales/fa.json | 2 + app/dashboard/public/locales/ru.json | 312 ++++++++++--------- app/dashboard/public/locales/zh.json | 4 +- app/dashboard/src/components/HostsDialog.tsx | 30 +- app/utils/share.py | 14 +- requirements.txt | 1 + 7 files changed, 204 insertions(+), 161 deletions(-) diff --git a/app/dashboard/public/locales/en.json b/app/dashboard/public/locales/en.json index 3569d7d19..bb87919eb 100644 --- a/app/dashboard/public/locales/en.json +++ b/app/dashboard/public/locales/en.json @@ -75,6 +75,8 @@ "hostsDialog.remainingData": "Remaining data of the user", "hostsDialog.dataLimit": "The usage limit of the user", "hostsDialog.remainingDays": "Remaining days of the user", + "hostsDialog.expireDate": "Expiry date of the user", + "hostsDialog.solarExpireDate": "Expiry date of the user in solar calendar", "hostsDialog.remainingTime": "Remaining time of the user", "hostsDialog.statusEmoji": "User status as an emoji (✅,⌛️,🪫,❌)", "hostsDialog.proxyProtocol": "Proxy protocol (e.g. VMess)", diff --git a/app/dashboard/public/locales/fa.json b/app/dashboard/public/locales/fa.json index 6075aec0e..9c6201d14 100644 --- a/app/dashboard/public/locales/fa.json +++ b/app/dashboard/public/locales/fa.json @@ -78,6 +78,8 @@ "hostsDialog.remainingData": "حجم باقی‌مانده کاربر", "hostsDialog.dataLimit": "حد مصرف کاربر", "hostsDialog.remainingDays": "روزهای باقی مانده کاربر", + "hostsDialog.expireDate": "تاریخ انقضای کاربر به میلادی", + "hostsDialog.solarExpireDate": "تاریخ انقضای کاربر به شمسی", "hostsDialog.remainingTime": "زمان باقی مانده کاربر", "hostsDialog.statusEmoji": "وضعیت کاربر در قالب اموجی (✅,⌛️,🪫,❌)", "hostsDialog.proxyProtocol": "پروتکل پروکسی (مانند VMess)", diff --git a/app/dashboard/public/locales/ru.json b/app/dashboard/public/locales/ru.json index 8396228d5..7421c9c6d 100644 --- a/app/dashboard/public/locales/ru.json +++ b/app/dashboard/public/locales/ru.json @@ -1,156 +1,158 @@ { - "password": "Пароль", - "login": "Вход", - "cancel": "Отмена", - "apply": "Применить", - "delete": "Удалить", - "reset": "Сбросить", - "createUser": "Создать", - "username": "Имя пользователя", - "expires": "Истекает через {{time}}", - "expired": "Истекло {{time}} назад", - "dateFormat": "MMMM d, yyy", - "inbound": "inbound", - "login.loginYourAccount": "Войдите в свой аккаунт", - "login.welcomeBack": "Пожалуйста, введите свои данные", - "login.fieldRequired": "Это поле обязательно для заполнения", - "header.hostSettings": "Настройки хоста", - "header.nodeSettings": "Настройки узлов", - "header.nodesUsage": "Использование узлов", - "header.donation": "Пожертвование", - "header.logout": "Выйти", - "deleteUser.title": "Удалить пользователя", - "deleteUser.prompt": "Вы уверены, что хотите удалить пользователя {{username}}?", - "deleteUser.deleteSuccess": "{{username}} успешно удален.", - "usersTable.status": "Статус", - "usersTable.dataUsage": "Расход трафика", - "usersTable.noUserMatched": "Похоже, нет пользователя, соответствующего вашему запросу", - "usersTable.noUser": "В системе нет добавленных пользователей", - "usersTable.copyLink": "Скопировать ссылку на подписку", - "usersTable.copied": "Скопировано", - "usersTable.copyConfigs": "Скопировать конфигурации", - "usersTable.total": "Всего", - "userDialog.dataLimit": "Лимит трафика", - "userDialog.periodicUsageReset": "Период сброса трафика", - "userDialog.warningNoProtocol": "Пожалуйста, выберите хотя бы один протокол", - "userDialog.expiryDate": "Дата истечения срока", - "userDialog.note": "Примечание", - "userDialog.resetUsage": "Сбросить трафик", - "userDialog.usage": "Потребление", - "userDialog.protocols": "Протоколы", - "userDialog.editUserTitle": "Редактировать пользователя", - "userDialog.editUser": "Редактировать", - "userDialog.userEdited": "Пользователь {{username}} отредактирован.", - "userDialog.userCreated": "Пользователь {{username}} создан.", - "userDialog.userAlreadyExists": "Пользователь уже существует", - "userDialog.vmessDesc": "Быстрый и безопасный", - "userDialog.vlessDesc": "Легковесный, быстрый и безопасный", - "userDialog.trojanDesc": "Легковесный, безопасный и быстрый", - "userDialog.shadowsocksDesc": "Быстрый и безопасный, но не такой эффективный, как другие", - "userDialog.resetStrategyNo": "Нет", - "userDialog.resetStrategyDaily": "Ежедневно", - "userDialog.resetStrategyWeekly": "Еженедельно", - "userDialog.resetStrategyMonthly": "Ежемесячно", - "userDialog.resetStrategyAnnually": "Ежегодно", - "userDialog.selectOneProtocol": "Пожалуйста, выберите хотя бы один протокол", - "userDialog.optional": "необязательно", - "userDialog.method": "Метод", - "userDialog.generatedByDefault": "по умолчанию", - "userDialog.hours": "Часы", - "userDialog.days": "Дни", - "userDialog.weeks": "Недели", - "userDialog.months": "Месяцы", - "userDialog.relative": "Относительно", - "userDialog.absolute": "Абсолютно", - "userDialog.custom": "Пользовательский", - "userDialog.startDate": "Дата начала", - "userDialog.endDate": "Дата окончания", - "userDialog.revokeSubscription": "Отозвать подписку", - "revoke": "Отозвать", - "userDialog.total": "Всего: ", - "hostsDialog.title": "Используя эту настройку, вы можете настроить свои inbound.", - "hostsDialog.desc": "Используйте эти переменные, чтобы сделать его динамическим", - "hostsDialog.username": "Имя пользователя", - "hostsDialog.dataUsage": "Текущий расход трафика пользователя", - "hostsDialog.remainingData": "Оставшийся трафик пользователя", - "hostsDialog.dataLimit": "Лимит трафика пользователя", - "hostsDialog.remainingDays": "Оставшиеся дни пользователя", - "hostsDialog.remainingTime": "Оставшееся время пользователя", - "hostsDialog.statusEmoji": "Статус пользователя в виде смайлика (✅,⌛️,🪫,❌)", - "hostsDialog.proxyProtocol": "Протокол прокси (например, VMess)", - "hostsDialog.proxyMethod": "Метод транспорта прокси (например, ws)", - "hostsDialog.currentServer": "Текущий IP-адрес сервера", - "hostsDialog.security": "Уровень безопасности", - "hostsDialog.host": "Host", - "hostsDialog.port": "Port", - "hostsDialog.sni": "SNI", - "hostsDialog.advancedOptions": "Дополнительные опции", - "hostsDialog.addHost": "Добавить хост", - "hostsDialog.savedSuccess": "Хосты успешно сохранены", - "hostsDialog.loading": "загрузка...", - "hostsDialog.apply": "Применить", - "hostsDialog.port.info": "По умолчанию хост использует порт входящего соединения. Вы можете установить пользовательский порт, если этот хост является сервером, который перенаправляет трафик с порта, отличного от порта вашего сервера. Например, сервер может перенаправлять трафик с порта 8443 на порт входящего сервера по умолчанию.", - "hostsDialog.sni.info": "По умолчанию хост использует SNI входящего соединения. Вы можете установить пользовательский SNI, если этот хост является сервером, у которого есть другой SNI. Например, сервер может принимать трафик с другим SSL-сертификатом, выполнять окончание SSL и перенаправлять его на ваш входящий сервер.", - "hostsDialog.host.info": "По умолчанию, если в конфигурации Xray задан запрашиваемый хост, будет использоваться этот хост. Однако, если необходимо, вы можете установить здесь пользовательский запрашиваемый хост.", - "hostsDialog.security.info": "Если промежуточный сервер этого хоста использует другой уровень безопасности, отличный от уровня безопасности входящего соединения по умолчанию, вы можете установить здесь пользовательский уровень безопасности.", - "hostsDialog.alpn": "ALPN", - "hostsDialog.fingerprint": "Fingerprint", - "hostsDialog.host.multiHost": "Чтобы установить несколько адресов, разделяйте их с помощью ,. Каждый раз выбирается случайный адрес.", - "hostsDialog.host.wildcard": "Используйте *, чтобы сгенерировать случайную строку (работает для доменных имен с подстановочными знаками)", - "nodes.title": "Используя Marzban-Node, вы можете повысить качество соединения, добавляя узлы на разных серверах.", - "nodes.addNewMarzbanNode": "Добавить новый узел Marzban", - "nodes.certificate": "Сертификат", - "nodes.addHostForEveryInbound": "Добавить этот узел как новый хост для каждого inbound", - "nodes.addNode": "Добавить узел", - "nodes.addNodeSuccess": "Узел {{name}} успешно добавлен", - "nodes.apply": "editNode", - "nodes.nodeName": "Имя", - "nodes.nodeAddress": "Адрес", - "nodes.nodePort": "Порт", - "nodes.nodeAPIPort": "API порт", - "nodes.editNode": "Редактировать узел", - "nodes.reconnect": "Переподключиться", - "nodes.connection-hint": "Для настройки узла Marzban, необходимо установить на нем данный сертификат, для инициализации безопасного соединения между главным сервером и узлом", - "nodes.download-certificate": "Скачать сертификат", - "nodes.show-certificate": "Показать сертификат", - "nodes.hide-certificate": "Скрыть сертификат", - "nodes.reconnecting": "Переподключение...", - "deleteNode.title": "Удалить узел", - "deleteNode.prompt": "Вы уверены, что хотите удалить узел {{name}}?", - "deleteNode.deleteSuccess": "Узел {{name}} успешно удален", - "users": "Пользователи", - "activeUsers": "Пользователи", - "dataUsage": "Трафик", - "memoryUsage": "Память", - "itemsPerPage": "Элементов на страницу", - "previous": "Назад", - "next": "Вперед", - "createNewUser": "Создать нового пользователя", - "search": "Поиск", - "resetAllUsage": "Сбросить расход трафика", - "qrcodeDialog.sublink": "Ссылка на подписку", - "resetUserUsage.prompt": "Вы уверены, что хотите сбросить расход трафика для пользователя {{username}}?", - "resetUserUsage.title": "Сбросить расход трафика пользователя", - "resetUserUsage.success": "расход трафика пользователя {{username}} успешно сброшен.", - "resetUserUsage.error": "Сброс расхода не удался, пожалуйста, попробуйте еще раз.", - "revokeUserSub.prompt": "Вы уверены, что хотите отозвать подписку для пользователя {{username}}?", - "revokeUserSub.title": "Отозвать подписку пользователя", - "revokeUserSub.success": "Подписка пользователя {{username}} успешно отозвана.", - "revokeUserSub.error": "Отзыв подписки не удался, пожалуйста, попробуйте еще раз.", - "resetAllUsage.title": "Сбросить расход трафика для всех пользователей", - "resetAllUsage.prompt": "Это действие полностью очищает весь расход трафика пользователей. Вы уверены? ЭТО ДЕЙСТВИЕ НЕОБРАТИМО!", - "resetAllUsage.success": "расход трафика успешно сброшен.", - "resetAllUsage.error": "Сброс расхода трафика не удался, пожалуйста, попробуйте еще раз.", - "core.title": "Основные настройки", - "core.socket.connecting": "Соединение...", - "core.socket.connected": "Подключено", - "core.socket.not_connected": "Не подключено", - "core.socket.closed": "Закрыто", - "core.restarting": "Перезагрузка...", - "core.restartCore": "Перезагрузить ядро", - "core.save": "Сохранить", - "core.logs": "Логи", - "core.configuration": "Конфигурация", - "core.generalErrorMessage": "Что-то пошло не так, пожалуйста, проверьте конфигурацию", - "core.successMessage": "Основные настройки успешно обновлены" -} \ No newline at end of file + "password": "Пароль", + "login": "Вход", + "cancel": "Отмена", + "apply": "Применить", + "delete": "Удалить", + "reset": "Сбросить", + "createUser": "Создать", + "username": "Имя пользователя", + "expires": "Истекает через {{time}}", + "expired": "Истекло {{time}} назад", + "dateFormat": "MMMM d, yyy", + "inbound": "inbound", + "login.loginYourAccount": "Войдите в свой аккаунт", + "login.welcomeBack": "Пожалуйста, введите свои данные", + "login.fieldRequired": "Это поле обязательно для заполнения", + "header.hostSettings": "Настройки хоста", + "header.nodeSettings": "Настройки узлов", + "header.nodesUsage": "Использование узлов", + "header.donation": "Пожертвование", + "header.logout": "Выйти", + "deleteUser.title": "Удалить пользователя", + "deleteUser.prompt": "Вы уверены, что хотите удалить пользователя {{username}}?", + "deleteUser.deleteSuccess": "{{username}} успешно удален.", + "usersTable.status": "Статус", + "usersTable.dataUsage": "Расход трафика", + "usersTable.noUserMatched": "Похоже, нет пользователя, соответствующего вашему запросу", + "usersTable.noUser": "В системе нет добавленных пользователей", + "usersTable.copyLink": "Скопировать ссылку на подписку", + "usersTable.copied": "Скопировано", + "usersTable.copyConfigs": "Скопировать конфигурации", + "usersTable.total": "Всего", + "userDialog.dataLimit": "Лимит трафика", + "userDialog.periodicUsageReset": "Период сброса трафика", + "userDialog.warningNoProtocol": "Пожалуйста, выберите хотя бы один протокол", + "userDialog.expiryDate": "Дата истечения срока", + "userDialog.note": "Примечание", + "userDialog.resetUsage": "Сбросить трафик", + "userDialog.usage": "Потребление", + "userDialog.protocols": "Протоколы", + "userDialog.editUserTitle": "Редактировать пользователя", + "userDialog.editUser": "Редактировать", + "userDialog.userEdited": "Пользователь {{username}} отредактирован.", + "userDialog.userCreated": "Пользователь {{username}} создан.", + "userDialog.userAlreadyExists": "Пользователь уже существует", + "userDialog.vmessDesc": "Быстрый и безопасный", + "userDialog.vlessDesc": "Легковесный, быстрый и безопасный", + "userDialog.trojanDesc": "Легковесный, безопасный и быстрый", + "userDialog.shadowsocksDesc": "Быстрый и безопасный, но не такой эффективный, как другие", + "userDialog.resetStrategyNo": "Нет", + "userDialog.resetStrategyDaily": "Ежедневно", + "userDialog.resetStrategyWeekly": "Еженедельно", + "userDialog.resetStrategyMonthly": "Ежемесячно", + "userDialog.resetStrategyAnnually": "Ежегодно", + "userDialog.selectOneProtocol": "Пожалуйста, выберите хотя бы один протокол", + "userDialog.optional": "необязательно", + "userDialog.method": "Метод", + "userDialog.generatedByDefault": "по умолчанию", + "userDialog.hours": "Часы", + "userDialog.days": "Дни", + "userDialog.weeks": "Недели", + "userDialog.months": "Месяцы", + "userDialog.relative": "Относительно", + "userDialog.absolute": "Абсолютно", + "userDialog.custom": "Пользовательский", + "userDialog.startDate": "Дата начала", + "userDialog.endDate": "Дата окончания", + "userDialog.revokeSubscription": "Отозвать подписку", + "revoke": "Отозвать", + "userDialog.total": "Всего: ", + "hostsDialog.title": "Используя эту настройку, вы можете настроить свои inbound.", + "hostsDialog.desc": "Используйте эти переменные, чтобы сделать его динамическим", + "hostsDialog.username": "Имя пользователя", + "hostsDialog.dataUsage": "Текущий расход трафика пользователя", + "hostsDialog.remainingData": "Оставшийся трафик пользователя", + "hostsDialog.dataLimit": "Лимит трафика пользователя", + "hostsDialog.remainingDays": "Оставшиеся дни пользователя", + "hostsDialog.expireDate": "Срок действия пользователя", + "hostsDialog.solarExpireDate": "Срок действия пользователя в солнечном календаре", + "hostsDialog.remainingTime": "Оставшееся время пользователя", + "hostsDialog.statusEmoji": "Статус пользователя в виде смайлика (✅,⌛️,🪫,❌)", + "hostsDialog.proxyProtocol": "Протокол прокси (например, VMess)", + "hostsDialog.proxyMethod": "Метод транспорта прокси (например, ws)", + "hostsDialog.currentServer": "Текущий IP-адрес сервера", + "hostsDialog.security": "Уровень безопасности", + "hostsDialog.host": "Host", + "hostsDialog.port": "Port", + "hostsDialog.sni": "SNI", + "hostsDialog.advancedOptions": "Дополнительные опции", + "hostsDialog.addHost": "Добавить хост", + "hostsDialog.savedSuccess": "Хосты успешно сохранены", + "hostsDialog.loading": "загрузка...", + "hostsDialog.apply": "Применить", + "hostsDialog.port.info": "По умолчанию хост использует порт входящего соединения. Вы можете установить пользовательский порт, если этот хост является сервером, который перенаправляет трафик с порта, отличного от порта вашего сервера. Например, сервер может перенаправлять трафик с порта 8443 на порт входящего сервера по умолчанию.", + "hostsDialog.sni.info": "По умолчанию хост использует SNI входящего соединения. Вы можете установить пользовательский SNI, если этот хост является сервером, у которого есть другой SNI. Например, сервер может принимать трафик с другим SSL-сертификатом, выполнять окончание SSL и перенаправлять его на ваш входящий сервер.", + "hostsDialog.host.info": "По умолчанию, если в конфигурации Xray задан запрашиваемый хост, будет использоваться этот хост. Однако, если необходимо, вы можете установить здесь пользовательский запрашиваемый хост.", + "hostsDialog.security.info": "Если промежуточный сервер этого хоста использует другой уровень безопасности, отличный от уровня безопасности входящего соединения по умолчанию, вы можете установить здесь пользовательский уровень безопасности.", + "hostsDialog.alpn": "ALPN", + "hostsDialog.fingerprint": "Fingerprint", + "hostsDialog.host.multiHost": "Чтобы установить несколько адресов, разделяйте их с помощью ,. Каждый раз выбирается случайный адрес.", + "hostsDialog.host.wildcard": "Используйте *, чтобы сгенерировать случайную строку (работает для доменных имен с подстановочными знаками)", + "nodes.title": "Используя Marzban-Node, вы можете повысить качество соединения, добавляя узлы на разных серверах.", + "nodes.addNewMarzbanNode": "Добавить новый узел Marzban", + "nodes.certificate": "Сертификат", + "nodes.addHostForEveryInbound": "Добавить этот узел как новый хост для каждого inbound", + "nodes.addNode": "Добавить узел", + "nodes.addNodeSuccess": "Узел {{name}} успешно добавлен", + "nodes.apply": "editNode", + "nodes.nodeName": "Имя", + "nodes.nodeAddress": "Адрес", + "nodes.nodePort": "Порт", + "nodes.nodeAPIPort": "API порт", + "nodes.editNode": "Редактировать узел", + "nodes.reconnect": "Переподключиться", + "nodes.connection-hint": "Для настройки узла Marzban, необходимо установить на нем данный сертификат, для инициализации безопасного соединения между главным сервером и узлом", + "nodes.download-certificate": "Скачать сертификат", + "nodes.show-certificate": "Показать сертификат", + "nodes.hide-certificate": "Скрыть сертификат", + "nodes.reconnecting": "Переподключение...", + "deleteNode.title": "Удалить узел", + "deleteNode.prompt": "Вы уверены, что хотите удалить узел {{name}}?", + "deleteNode.deleteSuccess": "Узел {{name}} успешно удален", + "users": "Пользователи", + "activeUsers": "Пользователи", + "dataUsage": "Трафик", + "memoryUsage": "Память", + "itemsPerPage": "Элементов на страницу", + "previous": "Назад", + "next": "Вперед", + "createNewUser": "Создать нового пользователя", + "search": "Поиск", + "resetAllUsage": "Сбросить расход трафика", + "qrcodeDialog.sublink": "Ссылка на подписку", + "resetUserUsage.prompt": "Вы уверены, что хотите сбросить расход трафика для пользователя {{username}}?", + "resetUserUsage.title": "Сбросить расход трафика пользователя", + "resetUserUsage.success": "расход трафика пользователя {{username}} успешно сброшен.", + "resetUserUsage.error": "Сброс расхода не удался, пожалуйста, попробуйте еще раз.", + "revokeUserSub.prompt": "Вы уверены, что хотите отозвать подписку для пользователя {{username}}?", + "revokeUserSub.title": "Отозвать подписку пользователя", + "revokeUserSub.success": "Подписка пользователя {{username}} успешно отозвана.", + "revokeUserSub.error": "Отзыв подписки не удался, пожалуйста, попробуйте еще раз.", + "resetAllUsage.title": "Сбросить расход трафика для всех пользователей", + "resetAllUsage.prompt": "Это действие полностью очищает весь расход трафика пользователей. Вы уверены? ЭТО ДЕЙСТВИЕ НЕОБРАТИМО!", + "resetAllUsage.success": "расход трафика успешно сброшен.", + "resetAllUsage.error": "Сброс расхода трафика не удался, пожалуйста, попробуйте еще раз.", + "core.title": "Основные настройки", + "core.socket.connecting": "Соединение...", + "core.socket.connected": "Подключено", + "core.socket.not_connected": "Не подключено", + "core.socket.closed": "Закрыто", + "core.restarting": "Перезагрузка...", + "core.restartCore": "Перезагрузить ядро", + "core.save": "Сохранить", + "core.logs": "Логи", + "core.configuration": "Конфигурация", + "core.generalErrorMessage": "Что-то пошло не так, пожалуйста, проверьте конфигурацию", + "core.successMessage": "Основные настройки успешно обновлены" +} diff --git a/app/dashboard/public/locales/zh.json b/app/dashboard/public/locales/zh.json index 78f58b549..0aab8a5ad 100644 --- a/app/dashboard/public/locales/zh.json +++ b/app/dashboard/public/locales/zh.json @@ -71,6 +71,8 @@ "hostsDialog.remainingData": "用户剩余流量情况", "hostsDialog.dataLimit": "用户的流量限制", "hostsDialog.remainingDays": "用户的剩余天数", + "hostsDialog.expireDate": "用户的有效期", + "hostsDialog.solarExpireDate": "用户阳历有效日期", "hostsDialog.remainingTime": "用户剩余时间", "hostsDialog.statusEmoji": "用户状态作为表情符号 (✅,⌛️,🪫,❌)", "hostsDialog.proxyProtocol": "代理协议(例如 VMess)", @@ -130,4 +132,4 @@ "resetAllUsage.prompt": "此操作将清除所有用户统计,您确定要执行此操作吗? 这不能被撤消!", "resetAllUsage.success": "所有统计重置完成。", "resetAllUsage.error": "重置失败,请稍候再试!" -} \ No newline at end of file +} diff --git a/app/dashboard/src/components/HostsDialog.tsx b/app/dashboard/src/components/HostsDialog.tsx index 65a9dcae8..f72cc7a25 100644 --- a/app/dashboard/src/components/HostsDialog.tsx +++ b/app/dashboard/src/components/HostsDialog.tsx @@ -7,7 +7,7 @@ import { Badge, Box, Button, - chakra, + Select as ChakraSelect, FormControl, FormErrorMessage, FormLabel, @@ -28,11 +28,11 @@ import { PopoverContent, PopoverTrigger, Portal, - Select as ChakraSelect, Text, Tooltip, - useToast, VStack, + chakra, + useToast, } from "@chakra-ui/react"; import { InformationCircleIcon, LinkIcon } from "@heroicons/react/24/outline"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -271,6 +271,18 @@ const AccordionInbound: FC = ({ {" "} {t("hostsDialog.remainingDays")} + + + {"{"}EXPIRE_DATE{"}"} + {" "} + {t("hostsDialog.expireDate")} + + + + {"{"}SOLAR_EXPIRE_DATE{"}"} + {" "} + {t("hostsDialog.solarExpireDate")} + {"{"}TIME_LEFT{"}"} @@ -369,6 +381,18 @@ const AccordionInbound: FC = ({ {" "} {t("hostsDialog.remainingDays")} + + + {"{"}EXPIRE_DATE{"}"} + {" "} + {t("hostsDialog.expireDate")} + + + + {"{"}SOLAR_EXPIRE_DATE{"}"} + {" "} + {t("hostsDialog.solarExpireDate")} + {"{"}TIME_LEFT{"}"} diff --git a/app/utils/share.py b/app/utils/share.py index 3c3342031..cd2c2eb74 100644 --- a/app/utils/share.py +++ b/app/utils/share.py @@ -8,6 +8,7 @@ from uuid import UUID import yaml +from persiantools.jdatetime import JalaliDate from app import xray from app.models.proxy import FormatVariables @@ -811,12 +812,17 @@ def setup_format_variables(extra_data: dict) -> dict: if user_status != UserStatus.on_hold: if expire_timestamp is not None and expire_timestamp >= 0: seconds_left = expire_timestamp - int(dt.utcnow().timestamp()) - days_left = (dt.fromtimestamp( - expire_timestamp) - dt.utcnow()).days + 1 + expire_datetime = dt.fromtimestamp(expire_timestamp) + expire_date = expire_datetime.date() + solar_expire_date = JalaliDate.to_jalali( + dt(expire_date.year, expire_date.month, expire_date.day)).strftime("%Y-%m-%d") + days_left = (expire_datetime - dt.utcnow()).days + 1 time_left = format_time_left(seconds_left) else: days_left = '∞' time_left = '∞' + expire_date = '∞' + solar_expire_date = '∞' else: if on_hold_expire_duration is not None and on_hold_expire_duration >= 0: days_left = timedelta(seconds=on_hold_expire_duration).days @@ -824,6 +830,8 @@ def setup_format_variables(extra_data: dict) -> dict: else: days_left = '∞' time_left = '∞' + expire_date = '∞' + solar_expire_date = '∞' if extra_data.get('data_limit'): data_limit = readable_size(extra_data['data_limit']) @@ -844,6 +852,8 @@ def setup_format_variables(extra_data: dict) -> dict: "DATA_LIMIT": data_limit, "DATA_LEFT": data_left, "DAYS_LEFT": days_left, + "EXPIRE_DATE": expire_date, + "SOLAR_EXPIRE_DATE": solar_expire_date, "TIME_LEFT": time_left, "STATUS_EMOJI": status_emoji } diff --git a/requirements.txt b/requirements.txt index 49c93043c..f385c14ec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,6 +28,7 @@ MarkupSafe==2.1.1 mdurl==0.1.2 packaging==21.3 passlib==1.7.4 +persiantools==3.0.1 Pillow==9.4.0 plumbum==1.8.1 protobuf==3.20.3 From ae184456a6fdcccf55b1c91713a41eee4bd2b114 Mon Sep 17 00:00:00 2001 From: Mohammad20000 Date: Sat, 18 Nov 2023 09:46:02 +0330 Subject: [PATCH 2/2] use jdatetime & rename SOLAR_... to JALALI_... --- app/dashboard/public/locales/en.json | 2 +- app/dashboard/public/locales/fa.json | 2 +- app/dashboard/public/locales/ru.json | 2 +- app/dashboard/public/locales/zh.json | 2 +- app/dashboard/src/components/HostsDialog.tsx | 8 ++++---- app/utils/share.py | 12 ++++++------ requirements.txt | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/dashboard/public/locales/en.json b/app/dashboard/public/locales/en.json index bb87919eb..6d068e152 100644 --- a/app/dashboard/public/locales/en.json +++ b/app/dashboard/public/locales/en.json @@ -76,7 +76,7 @@ "hostsDialog.dataLimit": "The usage limit of the user", "hostsDialog.remainingDays": "Remaining days of the user", "hostsDialog.expireDate": "Expiry date of the user", - "hostsDialog.solarExpireDate": "Expiry date of the user in solar calendar", + "hostsDialog.jalaliExpireDate": "Expiry date of the user in solar calendar", "hostsDialog.remainingTime": "Remaining time of the user", "hostsDialog.statusEmoji": "User status as an emoji (✅,⌛️,🪫,❌)", "hostsDialog.proxyProtocol": "Proxy protocol (e.g. VMess)", diff --git a/app/dashboard/public/locales/fa.json b/app/dashboard/public/locales/fa.json index 9c6201d14..7390f55b3 100644 --- a/app/dashboard/public/locales/fa.json +++ b/app/dashboard/public/locales/fa.json @@ -79,7 +79,7 @@ "hostsDialog.dataLimit": "حد مصرف کاربر", "hostsDialog.remainingDays": "روزهای باقی مانده کاربر", "hostsDialog.expireDate": "تاریخ انقضای کاربر به میلادی", - "hostsDialog.solarExpireDate": "تاریخ انقضای کاربر به شمسی", + "hostsDialog.jalaliExpireDate": "تاریخ انقضای کاربر به شمسی", "hostsDialog.remainingTime": "زمان باقی مانده کاربر", "hostsDialog.statusEmoji": "وضعیت کاربر در قالب اموجی (✅,⌛️,🪫,❌)", "hostsDialog.proxyProtocol": "پروتکل پروکسی (مانند VMess)", diff --git a/app/dashboard/public/locales/ru.json b/app/dashboard/public/locales/ru.json index 7421c9c6d..e636e42d8 100644 --- a/app/dashboard/public/locales/ru.json +++ b/app/dashboard/public/locales/ru.json @@ -76,7 +76,7 @@ "hostsDialog.dataLimit": "Лимит трафика пользователя", "hostsDialog.remainingDays": "Оставшиеся дни пользователя", "hostsDialog.expireDate": "Срок действия пользователя", - "hostsDialog.solarExpireDate": "Срок действия пользователя в солнечном календаре", + "hostsDialog.jalaliExpireDate": "Срок действия пользователя в солнечном календаре", "hostsDialog.remainingTime": "Оставшееся время пользователя", "hostsDialog.statusEmoji": "Статус пользователя в виде смайлика (✅,⌛️,🪫,❌)", "hostsDialog.proxyProtocol": "Протокол прокси (например, VMess)", diff --git a/app/dashboard/public/locales/zh.json b/app/dashboard/public/locales/zh.json index 0aab8a5ad..cf8b41429 100644 --- a/app/dashboard/public/locales/zh.json +++ b/app/dashboard/public/locales/zh.json @@ -72,7 +72,7 @@ "hostsDialog.dataLimit": "用户的流量限制", "hostsDialog.remainingDays": "用户的剩余天数", "hostsDialog.expireDate": "用户的有效期", - "hostsDialog.solarExpireDate": "用户阳历有效日期", + "hostsDialog.jalaliExpireDate": "用户阳历有效日期", "hostsDialog.remainingTime": "用户剩余时间", "hostsDialog.statusEmoji": "用户状态作为表情符号 (✅,⌛️,🪫,❌)", "hostsDialog.proxyProtocol": "代理协议(例如 VMess)", diff --git a/app/dashboard/src/components/HostsDialog.tsx b/app/dashboard/src/components/HostsDialog.tsx index f72cc7a25..1dd45a3d7 100644 --- a/app/dashboard/src/components/HostsDialog.tsx +++ b/app/dashboard/src/components/HostsDialog.tsx @@ -279,9 +279,9 @@ const AccordionInbound: FC = ({ - {"{"}SOLAR_EXPIRE_DATE{"}"} + {"{"}JALALI_EXPIRE_DATE{"}"} {" "} - {t("hostsDialog.solarExpireDate")} + {t("hostsDialog.jalaliExpireDate")} @@ -389,9 +389,9 @@ const AccordionInbound: FC = ({ - {"{"}SOLAR_EXPIRE_DATE{"}"} + {"{"}JALALI_EXPIRE_DATE{"}"} {" "} - {t("hostsDialog.solarExpireDate")} + {t("hostsDialog.jalaliExpireDate")} diff --git a/app/utils/share.py b/app/utils/share.py index cd2c2eb74..ae9802714 100644 --- a/app/utils/share.py +++ b/app/utils/share.py @@ -8,7 +8,7 @@ from uuid import UUID import yaml -from persiantools.jdatetime import JalaliDate +from jdatetime import date as jd from app import xray from app.models.proxy import FormatVariables @@ -814,15 +814,15 @@ def setup_format_variables(extra_data: dict) -> dict: seconds_left = expire_timestamp - int(dt.utcnow().timestamp()) expire_datetime = dt.fromtimestamp(expire_timestamp) expire_date = expire_datetime.date() - solar_expire_date = JalaliDate.to_jalali( - dt(expire_date.year, expire_date.month, expire_date.day)).strftime("%Y-%m-%d") + jalali_expire_date = jd.fromgregorian( + year=expire_date.year, month=expire_date.month, day=expire_date.day).strftime("%Y-%m-%d") days_left = (expire_datetime - dt.utcnow()).days + 1 time_left = format_time_left(seconds_left) else: days_left = '∞' time_left = '∞' expire_date = '∞' - solar_expire_date = '∞' + jalali_expire_date = '∞' else: if on_hold_expire_duration is not None and on_hold_expire_duration >= 0: days_left = timedelta(seconds=on_hold_expire_duration).days @@ -831,7 +831,7 @@ def setup_format_variables(extra_data: dict) -> dict: days_left = '∞' time_left = '∞' expire_date = '∞' - solar_expire_date = '∞' + jalali_expire_date = '∞' if extra_data.get('data_limit'): data_limit = readable_size(extra_data['data_limit']) @@ -853,7 +853,7 @@ def setup_format_variables(extra_data: dict) -> dict: "DATA_LEFT": data_left, "DAYS_LEFT": days_left, "EXPIRE_DATE": expire_date, - "SOLAR_EXPIRE_DATE": solar_expire_date, + "JALALI_EXPIRE_DATE": jalali_expire_date, "TIME_LEFT": time_left, "STATUS_EMOJI": status_emoji } diff --git a/requirements.txt b/requirements.txt index f385c14ec..d444e32cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,6 +21,7 @@ httptools==0.5.0 idna==3.4 importlib-metadata==5.1.0 importlib-resources==5.10.0 +jdatetime==4.1.1 Jinja2==3.1.2 Mako==1.2.4 markdown-it-py==2.2.0 @@ -28,7 +29,6 @@ MarkupSafe==2.1.1 mdurl==0.1.2 packaging==21.3 passlib==1.7.4 -persiantools==3.0.1 Pillow==9.4.0 plumbum==1.8.1 protobuf==3.20.3