hiddifypanel 10.30.8.dev0__py3-none-any.whl → 10.30.9.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/hutils/network/net.py +5 -3
  4. hiddifypanel/models/user.py +3 -2
  5. hiddifypanel/panel/admin/Actions.py +2 -2
  6. hiddifypanel/panel/admin/AdminstratorAdmin.py +1 -1
  7. hiddifypanel/panel/admin/Dashboard.py +3 -4
  8. hiddifypanel/panel/admin/DomainAdmin.py +3 -3
  9. hiddifypanel/panel/admin/QuickSetup.py +6 -5
  10. hiddifypanel/panel/admin/SettingAdmin.py +12 -12
  11. hiddifypanel/panel/admin/UserAdmin.py +7 -4
  12. hiddifypanel/panel/admin/templates/model/domain_list.html +13 -12
  13. hiddifypanel/panel/admin/templates/model/user_list.html +8 -5
  14. hiddifypanel/panel/admin/templates/quick_setup.html +1 -1
  15. hiddifypanel/panel/admin/templates/result.html +3 -2
  16. hiddifypanel/panel/commercial/ParentDomainAdmin.py +1 -1
  17. hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +3 -0
  18. hiddifypanel/panel/commercial/telegrambot/Usage.py +1 -4
  19. hiddifypanel/panel/commercial/telegrambot/admin.py +3 -3
  20. hiddifypanel/panel/commercial/telegrambot/information.py +1 -3
  21. hiddifypanel/panel/common_bp/login.py +2 -2
  22. hiddifypanel/panel/user/templates/home/home.html +30 -14
  23. hiddifypanel/panel/user/templates/home/index_old.html +2 -2
  24. hiddifypanel/panel/user/templates/home/multi.html +2 -2
  25. hiddifypanel/panel/user/templates/redirect_to_new_format.html +1 -1
  26. hiddifypanel/templates/500.html +1 -1
  27. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  28. hiddifypanel/translations/en/LC_MESSAGES/messages.po +112 -130
  29. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  30. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +114 -133
  31. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  32. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +104 -127
  33. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  34. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +109 -132
  35. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  36. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +93 -114
  37. hiddifypanel/translations.i18n/en.json +41 -71
  38. hiddifypanel/translations.i18n/fa.json +122 -73
  39. hiddifypanel/translations.i18n/pt.json +327 -69
  40. hiddifypanel/translations.i18n/ru.json +180 -74
  41. hiddifypanel/translations.i18n/zh.json +308 -69
  42. {hiddifypanel-10.30.8.dev0.dist-info → hiddifypanel-10.30.9.dev0.dist-info}/METADATA +1 -1
  43. {hiddifypanel-10.30.8.dev0.dist-info → hiddifypanel-10.30.9.dev0.dist-info}/RECORD +47 -47
  44. {hiddifypanel-10.30.8.dev0.dist-info → hiddifypanel-10.30.9.dev0.dist-info}/LICENSE.md +0 -0
  45. {hiddifypanel-10.30.8.dev0.dist-info → hiddifypanel-10.30.9.dev0.dist-info}/WHEEL +0 -0
  46. {hiddifypanel-10.30.8.dev0.dist-info → hiddifypanel-10.30.9.dev0.dist-info}/entry_points.txt +0 -0
  47. {hiddifypanel-10.30.8.dev0.dist-info → hiddifypanel-10.30.9.dev0.dist-info}/top_level.txt +0 -0
hiddifypanel/VERSION CHANGED
@@ -1 +1 @@
1
- 10.30.8.dev0
1
+ 10.30.9.dev0
hiddifypanel/VERSION.py CHANGED
@@ -1,3 +1,3 @@
1
- __version__='10.30.8.dev0'
1
+ __version__='10.30.9.dev0'
2
2
  from datetime import datetime
3
- __release_date__= datetime.strptime('2024-07-10','%Y-%m-%d')
3
+ __release_date__= datetime.strptime('2024-07-12','%Y-%m-%d')
@@ -136,6 +136,7 @@ def get_ip(version: Literal[4, 6], retry: int = 5) -> ipaddress.IPv4Address | ip
136
136
  ip = get_ip(version, retry=retry - 1)
137
137
  return ip
138
138
 
139
+
139
140
  def get_random_domains(count: int = 1, retry: int = 3) -> List[str]:
140
141
  try:
141
142
  irurl = "https://api.ooni.io/api/v1/measurements?probe_cc=IR&test_name=web_connectivity&anomaly=false&confirmed=false&failure=false&order_by=test_start_time&limit=1000"
@@ -310,7 +311,7 @@ def is_in_same_asn(domain_or_ip: str, domain_or_ip_target: str) -> bool:
310
311
  print(f"An error occurred: {e}")
311
312
  return False
312
313
 
313
- # hutils.flask.flash(_("selected domain for REALITY is not in the same ASN. To better use of the protocol, it is better to find a domain in the same ASN.") +
314
+ # hutils.flask.flash(_("domain.reality.asn_issue") +
314
315
  # f"<br> Server ASN={asn_ipv4.get('autonomous_system_organization','unknown')}<br>{domain}_ASN={asn_dip.get('autonomous_system_organization','unknown')}", "warning")
315
316
 
316
317
 
@@ -342,8 +343,9 @@ def is_ip(input: str):
342
343
  except:
343
344
  return False
344
345
 
345
- def resolve_domain_with_api(domain:str) -> str:
346
+
347
+ def resolve_domain_with_api(domain: str) -> str:
346
348
  if not domain:
347
349
  return ''
348
350
  endpoint = f'http://ip-api.com/json/{domain}?fields=query'
349
- return str(requests.get(endpoint).json().get('query'))
351
+ return str(requests.get(endpoint).json().get('query'))
@@ -290,7 +290,7 @@ class User(BaseAccount, SerializerMixin):
290
290
  return schema.dump(User())
291
291
 
292
292
  def to_schema(self):
293
- user_dict = self.to_dict()
293
+ user_dict = self.to_dict(dump_id=True)
294
294
  from hiddifypanel.panel.commercial.restapi.v2.admin.user_api import UserSchema
295
295
  return UserSchema().load(user_dict)
296
296
 
@@ -317,7 +317,8 @@ class User(BaseAccount, SerializerMixin):
317
317
  'wg_pk': self.wg_pk,
318
318
  'wg_pub': self.wg_pub,
319
319
  'wg_psk': self.wg_psk,
320
- 'is_active': self.is_active
320
+ 'is_active': self.is_active,
321
+ 'enable': self.enable
321
322
  }
322
323
 
323
324
  # @staticmethod
@@ -65,7 +65,7 @@ class Actions(FlaskView):
65
65
  domain_changed = request.args.get("domain_changed", str(domain_changed)).lower() == "true"
66
66
  complete_install = request.args.get("complete_install", str(complete_install)).lower() == "true"
67
67
  if domain_changed:
68
- hutils.flask.flash((_('Your domains changed. Please do not forget to copy admin links, otherwise you can not access to the panel anymore.')), 'info')
68
+ hutils.flask.flash((_('domain.changed_in_domain_warning')), 'info')
69
69
  # hutils.flask.flash(f'complete_install={complete_install} domain_changed={domain_changed} ', 'info')
70
70
  # return render_template("result.html")
71
71
  # hiddify.add_temporary_access()
@@ -87,7 +87,7 @@ class Actions(FlaskView):
87
87
 
88
88
  resp = render_template("result.html",
89
89
  out_type="info",
90
- out_msg=_("Success! Please wait around 4 minutes to make sure everything is updated. During this time, please save your proxy links which are:") +
90
+ out_msg=_("admin.waiting_for_update") +
91
91
  admin_links,
92
92
  log_file_url=get_log_api_url(),
93
93
  log_file="0-install.log",
@@ -72,7 +72,7 @@ class AdminstratorAdmin(AdminLTEModelView):
72
72
 
73
73
  column_descriptions = dict(
74
74
  comment=_("Add some text that is only visible to super_admin."),
75
- mode=_("Define the admin mode. "),
75
+ mode=_("admin.define_mode"),
76
76
  )
77
77
  # create_modal = True
78
78
  can_export = False
@@ -22,7 +22,7 @@ class Dashboard(FlaskView):
22
22
  return redirect(hurl_for("admin.QuickSetup:index"))
23
23
 
24
24
  if hutils.utils.is_panel_outdated():
25
- hutils.flask.flash(_('This version of hiddify panel is outdated. Please update it from admin area.'), "danger") # type: ignore
25
+ hutils.flask.flash(_('outdated_panel'), "danger") # type: ignore
26
26
 
27
27
  childs = None
28
28
  admin_id = request.args.get("admin_id") or g.account.id
@@ -48,8 +48,7 @@ class Dashboard(FlaskView):
48
48
 
49
49
  if def_user and sslip_domains:
50
50
  quick_setup = hurl_for("admin.QuickSetup:index")
51
- hutils.flask.flash((_('It seems that you have not setup the system completely. <a class="btn btn-success" href="%(quick_setup)s">Click here</a> to complete setup.',
52
- quick_setup=quick_setup)), 'warning') # type: ignore
51
+ hutils.flask.flash((_('admin.incomplete_setup_warning', quick_setup=quick_setup)), 'warning') # type: ignore
53
52
  if hutils.node.is_parent():
54
53
  hutils.flask.flash(
55
54
  _("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
@@ -61,7 +60,7 @@ class Dashboard(FlaskView):
61
60
  _("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
62
61
  elif def_user:
63
62
  d = domains[0]
64
- hutils.flask.flash((_('It seems that you have not created any users yet. Default user link: %(default_link)s',
63
+ hutils.flask.flash((_("admin.no_user_warning",
65
64
  default_link=hiddify.get_html_user_link(def_user, d))), 'secondary') # type: ignore
66
65
  if hutils.network.is_ssh_password_authentication_enabled():
67
66
  hutils.flask.flash(_('serverssh.password-login.warning'), "warning") # type: ignore
@@ -46,11 +46,11 @@ class DomainAdmin(AdminLTEModelView):
46
46
  mode=_("Direct mode means you want to use your server directly (for usual use), CDN means that you use your server on behind of a CDN provider."),
47
47
  cdn_ip=_("config.cdn_forced_host.description"),
48
48
  show_domains=_(
49
- 'You can select the configs with which domains show be shown in the user area. If you select all, automatically, all the new domains will be added for each users.'),
49
+ 'domain.show_domains_description'),
50
50
  alias=_('The name shown in the configs for this domain.'),
51
51
  servernames=_('config.reality_server_names.description'),
52
52
  sub_link_only=_('This can be used for giving your users a permanent non blockable links.'),
53
- grpc=_('gRPC is a H2 based protocol. Maybe it is faster for you!'))
53
+ grpc=_('grpc-proxy.description'))
54
54
 
55
55
  # create_modal = True
56
56
  can_export = False
@@ -243,7 +243,7 @@ class DomainAdmin(AdminLTEModelView):
243
243
  if not hutils.network.is_in_same_asn(d, ipv4_list[0]):
244
244
  server_asn = hutils.network.get_ip_asn(ipv4_list[0])
245
245
  domain_asn = hutils.network.get_ip_asn(dip) # type: ignore
246
- msg = _("selected domain for REALITY is not in the same ASN. To better use of the protocol, it is better to find a domain in the same ASN.") + \
246
+ msg = _("domain.reality.asn_issue") + \
247
247
  (f"<br> Server ASN={server_asn}<br>{d}_ASN={domain_asn}" if server_asn or domain_asn else "")
248
248
  hutils.flask.flash(msg, 'warning')
249
249
 
@@ -112,10 +112,10 @@ def get_quick_setup_form(empty=False):
112
112
  domain_regex = "^([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})$"
113
113
 
114
114
  domain_validators = [
115
- wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid domain")),
115
+ wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid_domain")),
116
116
  validate_domain,
117
- wtf.validators.NoneOf([d.domain.lower() for d in Domain.query.all()], _("config.Domain already used")),
118
- wtf.validators.NoneOf([c.value.lower() for c in StrConfig.query.all() if "fakedomain" in c.key and c.key != ConfigEnum.decoy_domain], _("config.Domain already used"))]
117
+ wtf.validators.NoneOf([d.domain.lower() for d in Domain.query.all()], _("config.Domain_already_used")),
118
+ wtf.validators.NoneOf([c.value.lower() for c in StrConfig.query.all() if "fakedomain" in c.key and c.key != ConfigEnum.decoy_domain], _("config.Domain_already_used"))]
119
119
  domain = wtf.StringField(
120
120
  _("domain.domain"),
121
121
  domain_validators,
@@ -132,7 +132,7 @@ def get_quick_setup_form(empty=False):
132
132
  "config.block_iran_sites.description"), default=hconfig(ConfigEnum.block_iran_sites))
133
133
  # enable_vmess = SwitchField(_("config.vmess_enable.label"), description=_("config.vmess_enable.description"), default=hconfig(ConfigEnum.vmess_enable))
134
134
  decoy_domain = wtf.StringField(_("config.decoy_domain.label"), description=_("config.decoy_domain.description"), default=hconfig(
135
- ConfigEnum.decoy_domain), validators=[wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid domain")), hutils.flask.validate_domain_exist])
135
+ ConfigEnum.decoy_domain), validators=[wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid_domain")), hutils.flask.validate_domain_exist])
136
136
  submit = wtf.SubmitField(_('Submit'))
137
137
 
138
138
  return QuickSetupForm(None) if empty else QuickSetupForm()
@@ -146,7 +146,8 @@ def validate_domain(form, field):
146
146
 
147
147
  myip = hutils.network.get_ip(4)
148
148
  if dip and myip != dip:
149
- raise ValidationError(_("Domain (%(domain)s)-> IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode", server_ip=myip, domain_ip=dip, domain=domain))
149
+ raise ValidationError(_("Domain (%(domain)s)-> IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode",
150
+ server_ip=myip, domain_ip=dip, domain=domain))
150
151
 
151
152
 
152
153
  def admin_link():
@@ -267,16 +267,16 @@ def get_config_form():
267
267
  render_kw = {'class': "ltr"}
268
268
  validators = []
269
269
  if c.key == ConfigEnum.domain_fronting_domain:
270
- validators.append(wtf.validators.Regexp("^([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})|$", re.IGNORECASE, _("config.Invalid domain")))
270
+ validators.append(wtf.validators.Regexp("^([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})|$", re.IGNORECASE, _("config.Invalid_domain")))
271
271
  validators.append(hutils.flask.validate_domain_exist)
272
272
  elif '_domain' in c.key or "_fakedomain" in c.key:
273
- validators.append(wtf.validators.Regexp("^([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})$", re.IGNORECASE, _("config.Invalid domain")))
273
+ validators.append(wtf.validators.Regexp("^([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})$", re.IGNORECASE, _("config.Invalid_domain")))
274
274
  validators.append(hutils.flask.validate_domain_exist)
275
275
 
276
276
  if c.key != ConfigEnum.decoy_domain:
277
- validators.append(wtf.validators.NoneOf([d.domain.lower() for d in Domain.query.all()], _("config.Domain already used")))
277
+ validators.append(wtf.validators.NoneOf([d.domain.lower() for d in Domain.query.all()], _("config.Domain_already_used")))
278
278
  validators.append(wtf.validators.NoneOf(
279
- [cc.value.lower() for cc in StrConfig.query.filter(StrConfig.child_id == Child.current().id).all() if cc.key != c.key and "fakedomain" in cc.key and cc.key != ConfigEnum.decoy_domain], _("config.Domain already used")))
279
+ [cc.value.lower() for cc in StrConfig.query.filter(StrConfig.child_id == Child.current().id).all() if cc.key != c.key and "fakedomain" in cc.key and cc.key != ConfigEnum.decoy_domain], _("config.Domain_already_used")))
280
280
 
281
281
  render_kw['required'] = ""
282
282
  if len(c.value) < 3:
@@ -292,36 +292,36 @@ def get_config_form():
292
292
  if c.key == ConfigEnum.parent_panel:
293
293
  validators.append(wtf.validators.Regexp("()|(http(s|)://([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})/.*)", re.IGNORECASE, _("Invalid admin link")))
294
294
  if c.key == ConfigEnum.telegram_bot_token:
295
- validators.append(wtf.validators.Regexp("()|^([0-9]{8,12}:[a-zA-Z0-9_-]{30,40})|$", re.IGNORECASE, _("config.Invalid telegram bot token")))
295
+ validators.append(wtf.validators.Regexp("()|^([0-9]{8,12}:[a-zA-Z0-9_-]{30,40})|$", re.IGNORECASE, _("config.Invalid_telegram_bot_token")))
296
296
  if c.key == ConfigEnum.branding_site:
297
297
  validators.append(wtf.validators.Regexp(
298
- "()|(http(s|)://([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})/?.*)", re.IGNORECASE, _("config.Invalid brand link")))
298
+ "()|(http(s|)://([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})/?.*)", re.IGNORECASE, _("config.Invalid_brand_link")))
299
299
  # render_kw['required']=""
300
300
 
301
301
  if 'secret' in c.key:
302
302
  validators.append(wtf.validators.Regexp(
303
- "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", re.IGNORECASE, _('config.invalid uuid')))
303
+ "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", re.IGNORECASE, _('config.invalid_uuid')))
304
304
  render_kw['required'] = ""
305
305
 
306
306
  if c.key == ConfigEnum.proxy_path:
307
- validators.append(wtf.validators.Regexp("^[a-zA-Z0-9]*$", re.IGNORECASE, _("config.Invalid proxy path")))
307
+ validators.append(wtf.validators.Regexp("^[a-zA-Z0-9]*$", re.IGNORECASE, _("config.Invalid_proxy_path")))
308
308
  render_kw['required'] = ""
309
309
 
310
310
  if 'port' in c.key:
311
311
  if c.key in [ConfigEnum.http_ports, ConfigEnum.tls_ports]:
312
- validators.append(wtf.validators.Regexp("^(\\d+)(,\\d+)*$", re.IGNORECASE, _("config.Invalid port")))
312
+ validators.append(wtf.validators.Regexp("^(\\d+)(,\\d+)*$", re.IGNORECASE, _("config.Invalid_port")))
313
313
  render_kw['required'] = ""
314
314
  else:
315
- validators.append(wtf.validators.Regexp("^(\\d+)(,\\d+)*$|^$", re.IGNORECASE, _("config.Invalid port")))
315
+ validators.append(wtf.validators.Regexp("^(\\d+)(,\\d+)*$|^$", re.IGNORECASE, _("config.Invalid_port")))
316
316
  # validators.append(wtf.validators.Regexp("^(\d+)(,\d+)*$",re.IGNORECASE,_("config.port is required")))
317
317
 
318
318
  # tls tricks validations
319
319
  if c.key in [ConfigEnum.tls_fragment_size, ConfigEnum.tls_fragment_sleep, ConfigEnum.tls_padding_length, ConfigEnum.wireguard_noise_trick]:
320
- validators.append(wtf.validators.Regexp("^\\d+-\\d+$", re.IGNORECASE, _("config.Invalid! The pattern is number-number") + f' {c.key}'))
320
+ validators.append(wtf.validators.Regexp("^\\d+-\\d+$", re.IGNORECASE, _("config.Invalid_The_pattern_is_number-number") + f' {c.key}'))
321
321
  # mux and hysteria validations
322
322
  if c.key in [ConfigEnum.hysteria_up_mbps, ConfigEnum.hysteria_down_mbps, ConfigEnum.mux_max_connections, ConfigEnum.mux_min_streams, ConfigEnum.mux_max_streams,
323
323
  ConfigEnum.mux_brutal_down_mbps, ConfigEnum.mux_brutal_up_mbps]:
324
- validators.append(wtf.validators.Regexp("^\\d+$", re.IGNORECASE, _("config.Invalid! it should be a number only") + f' {c.key}'))
324
+ validators.append(wtf.validators.Regexp("^\\d+$", re.IGNORECASE, _("config.Invalid_it_should_be_a_number_only") + f' {c.key}'))
325
325
 
326
326
  for val in validators:
327
327
  if hasattr(val, "regex"):
@@ -10,7 +10,7 @@ from wtforms.validators import NumberRange
10
10
  from flask_babel import lazy_gettext as _
11
11
  from flask import g, request # type: ignore
12
12
  from markupsafe import Markup
13
- from sqlalchemy import desc
13
+ from sqlalchemy import desc, func
14
14
 
15
15
  from hiddifypanel.hutils.flask import hurl_for
16
16
  from wtforms.validators import Regexp, ValidationError
@@ -25,6 +25,7 @@ from hiddifypanel import hutils
25
25
 
26
26
 
27
27
  class UserAdmin(AdminLTEModelView):
28
+ column_default_sort = ('id', False) # Sort by username in ascending order
28
29
 
29
30
  column_sortable_list = ["is_active", "name", "current_usage", 'mode', "remaining_days", "comment", 'last_online', "uuid", 'remaining_days']
30
31
  column_searchable_list = ["uuid", "name"]
@@ -112,7 +113,7 @@ class UserAdmin(AdminLTEModelView):
112
113
  # usage_limit_GB="in GB",
113
114
  # current_usage_GB="in GB"
114
115
  comment=_("Add some text that is only visible to you."),
115
- mode=_("Define the user mode. Should the usage reset every month?"),
116
+ mode=_("user.define_mode"),
116
117
  last_reset_time=_("If monthly is enabled, the usage will be reset after 30 days from this date."),
117
118
  start_date=_("From when the user package will be started? Empty for start from first connection"),
118
119
  package_days=_("How many days this package should be available?")
@@ -376,15 +377,17 @@ class UserAdmin(AdminLTEModelView):
376
377
  abort(403)
377
378
 
378
379
  query = query.filter(User.added_by.in_(admin.recursive_sub_admins_ids()))
379
- query = query.order_by(desc(User.id))
380
+
380
381
  return query
381
382
 
382
383
  # Override get_count_query() to include the filter condition in the count query
383
384
  def get_count_query(self):
384
385
  # Get the base count query
385
386
 
386
- # query = query.session.query(func.count(User.id))
387
+ # query = self.session.query(func.count(User.id)).
388
+
387
389
  query = super().get_count_query()
390
+
388
391
  admin_id = int(request.args.get("admin_id") or g.account.id)
389
392
  if admin_id not in g.account.recursive_sub_admins_ids():
390
393
  abort(403)
@@ -1,19 +1,20 @@
1
1
  {% extends 'hiddify-flask-admin/list.html' %}
2
2
 
3
3
  {% block body %}
4
- {{super()}}
4
+ {{super()}}
5
5
 
6
- <div class="callout callout-info">
7
- {{_('In this section, you can add your domain. You need to add at least one domain in direct mode.')}}
8
- </div>
6
+ <div class="callout callout-info">
7
+ {{_('domain.intro')}}
8
+ </div>
9
9
 
10
10
 
11
- <style>
12
- .table td{
13
- vertical-align: middle;
14
- }
15
- td.col-domain{
16
- /* direction:ltr; */
17
- }
18
- </style>
11
+ <style>
12
+ .table td {
13
+ vertical-align: middle;
14
+ }
15
+
16
+ td.col-domain {
17
+ /* direction:ltr; */
18
+ }
19
+ </style>
19
20
  {% endblock %}
@@ -11,7 +11,8 @@
11
11
  <button onclick="show_send_message('all')" type="button" class="btn hbtn bg-h-green">
12
12
  {{_("All Users")}}
13
13
  </button>
14
- <button onclick="show_send_message('active')" type="button" class="btn hbtn bg-h-green" style="margin-left: 5px;margin-right: 5px;">
14
+ <button onclick="show_send_message('active')" type="button" class="btn hbtn bg-h-green"
15
+ style="margin-left: 5px;margin-right: 5px;">
15
16
  {{_("Active Users")}}
16
17
  </button>
17
18
  <button onclick="show_send_message('selected')" type="button" class="btn hbtn bg-h-green">
@@ -22,9 +23,11 @@
22
23
  <div style="margin-top: 10px;">
23
24
  <button onclick="show_send_message('offline 1h')" type="button" class="btn hbtn bg-h-red">
24
25
  {{_("Offline more than 1 hour")}}</button>
25
- <button onclick="show_send_message('offline 1d')" type="button" class="btn hbtn bg-h-red" style="margin-left: 5px;">
26
+ <button onclick="show_send_message('offline 1d')" type="button" class="btn hbtn bg-h-red"
27
+ style="margin-left: 5px;">
26
28
  {{_("Offline more than 1 day")}}</button>
27
- <button onclick="show_send_message('offline 1w')" type="button" class="btn hbtn bg-h-red" style="margin-left: 5px;margin-right: 5px;">
29
+ <button onclick="show_send_message('offline 1w')" type="button" class="btn hbtn bg-h-red"
30
+ style="margin-left: 5px;margin-right: 5px;">
28
31
  {{_("Offline more than 1 week")}}
29
32
  </button>
30
33
  <button onclick="show_send_message('expired')" type="button" class="btn hbtn bg-h-red">
@@ -37,7 +40,7 @@
37
40
  {{super()}}
38
41
 
39
42
  <div class="callout callout-success">
40
- {{_('User usage will be updated every 6 minutes. To update it now click <a href="%(link)s" class="btn btn-info">here</a>',link=hurl_for("admin.Actions:update_usage"))}}
43
+ {{_('adminuser.force_update_usage',link=hurl_for("admin.Actions:update_usage"))}}
41
44
 
42
45
  </div>
43
46
  <style>
@@ -155,4 +158,4 @@
155
158
  }
156
159
 
157
160
  </script>
158
- {% endblock %}
161
+ {% endblock %}
@@ -5,7 +5,7 @@
5
5
  {% block tail %}
6
6
  {{super()}}
7
7
 
8
- {{modal('quicksetup',_('Save Link'),_('Please note that your panel can be accessed only via <a href="%(adminlink)s" class="btn btn-primary copy-link">%(adminlink)s</a>. Please save this link.',adminlink=admin_link),show=Fales)}}
8
+ {{modal('quicksetup',_('Save Link'),_('admin.save_panel_link',adminlink=admin_link),show=Fales)}}
9
9
 
10
10
  <script>
11
11
  disable_notif = false
@@ -40,7 +40,8 @@ page."),temp_link(),show=False)}}
40
40
  <label class="col-6" id="process-title"></label> <label class="col-6" id="process-details"></label>
41
41
  </div>
42
42
  <div class="progress">
43
- <div id="progress" class="progress-bar" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
43
+ <div id="progress" class="progress-bar" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0"
44
+ aria-valuemax="100"></div>
44
45
  </div>
45
46
  </div>
46
47
  {% endif %}
@@ -153,7 +154,7 @@ page."),temp_link(),show=False)}}
153
154
  $("#process-title").html("")
154
155
  bootbox.alert({
155
156
  title: '{{_("Success")}}',
156
- message: '{{_("The action done successfully. You can now leave this page.")}}',
157
+ message: '{{_("admin.action_done_sucess")}}',
157
158
  locale: '{{get_locale()}}',
158
159
  });
159
160
  }
@@ -25,7 +25,7 @@
25
25
  # column_descriptions = dict(
26
26
  # domain=_("domain.description"),
27
27
  # alias=_('The name shown in the configs for this domain.'),
28
- # show_domains=_('You can select the configs with which domains show be shown in the user area. If you select all, automatically, all the new domains will be added for each users.')
28
+ # show_domains=_('domain.show_domains_description')
29
29
  # # current_usage_GB="in GB"
30
30
  # )
31
31
 
@@ -129,6 +129,7 @@ class UserSchema(Schema):
129
129
  lang = Enum(Lang, required=False, allow_none=True, description="The language of the user")
130
130
  enable = Boolean(required=False, description="Whether the user is enabled or not")
131
131
  is_active = Boolean(required=False, description="Whether the user is active for using hiddify")
132
+ id = Integer(required=False, description="never use it, only for better presentation")
132
133
 
133
134
 
134
135
  class PostUserSchema(UserSchema):
@@ -137,6 +138,7 @@ class PostUserSchema(UserSchema):
137
138
  # the uuid is sent in the url path
138
139
  self.fields['uuid'].required = False
139
140
  self.fields['uuid'].allow_none = True
141
+ del self.fields['id']
140
142
 
141
143
 
142
144
  class PatchUserSchema(UserSchema):
@@ -146,6 +148,7 @@ class PatchUserSchema(UserSchema):
146
148
  self.fields['uuid'].allow_none = True,
147
149
  self.fields['name'].required = False
148
150
  self.fields['name'].allow_none = True,
151
+ del self.fields['id']
149
152
 
150
153
 
151
154
  # endregion
@@ -30,10 +30,7 @@ def send_welcome(message):
30
30
  with force_locale(user.lang or hconfig(ConfigEnum.lang)):
31
31
  bot.reply_to(message, get_usage_msg(user.uuid), reply_markup=user_keyboard(user.uuid))
32
32
  else:
33
- bot.reply_to(message,
34
- _("Hooray \U0001F389 \U0001F389 \U0001F389 \n"
35
- "Welcome to hiddifybot.\n"
36
- "Start by clicking the link on the panel or entering your UUID."))
33
+ bot.reply_to(message, _("bot.welcome"))
37
34
 
38
35
 
39
36
  def user_keyboard(uuid):
@@ -32,7 +32,7 @@ def send_welcome(message):
32
32
 
33
33
  def start_admin(message):
34
34
 
35
- bot.reply_to(message, _("Welcome to admin bot. Choose your action"), reply_markup=admin_keyboard_main())
35
+ bot.reply_to(message, _("bot.admin_welcome"), reply_markup=admin_keyboard_main())
36
36
 
37
37
 
38
38
  def get_admin_by_tgid(message):
@@ -136,14 +136,14 @@ def create_package(call): # <- passes a CallbackQuery type object to your funct
136
136
  days = int(splt[2])
137
137
  count = int(splt[3])
138
138
  domain = int(splt[4])
139
- new_text = _("Please Wait...")
139
+ new_text = _("Please Wait")
140
140
  bot.edit_message_text(new_text, call.message.chat.id, call.message.message_id, reply_markup=None)
141
141
  domain = Domain.query.filter(Domain.id == domain).first()
142
142
  from . import Usage
143
143
  admin_id = admin.id
144
144
  admin_name = admin.name
145
145
  for i in range(1, count + 1):
146
- new_text = _("Please Wait...") + f' {i}/{count}'
146
+ new_text = _("Please Wait") + f' {i}/{count}'
147
147
  bot.edit_message_text(new_text, call.message.chat.id, call.message.message_id, reply_markup=None)
148
148
  user = User(package_days=days, usage_limit_GB=gig, name=f"{admin_name} auto {i} {datetime.date.today()}", added_by=admin_id)
149
149
  db.session.add(user)
@@ -52,9 +52,7 @@ def prepare_hello_message():
52
52
  @return: A text message
53
53
  """
54
54
 
55
- response = _("Hooray \U0001F389 \U0001F389 \U0001F389 \n"
56
- "Welcome to hiddifybot.\n"
57
- "Start by clicking the link on the panel or entering your UUID.")
55
+ response = _("bot.welcome")
58
56
 
59
57
  return response
60
58
 
@@ -16,11 +16,11 @@ import re
16
16
 
17
17
  class LoginForm(FlaskForm):
18
18
  secret_textbox = wtf.fields.StringField(_(f'login.secret.label'), [wtf.validators.Regexp(
19
- "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", re.IGNORECASE, _('config.invalid uuid'))], default='',
19
+ "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", re.IGNORECASE, _('config.invalid_uuid'))], default='',
20
20
  description=_(f'login.secret.description'), render_kw={
21
21
  'required': "",
22
22
  'pattern': "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
23
- 'message': _('config.invalid uuid')
23
+ 'message': _('config.invalid_uuid')
24
24
  })
25
25
  submit = wtf.fields.SubmitField(_('Submit'))
26
26
 
@@ -19,8 +19,11 @@
19
19
  <i class="fa-solid fa-moon"></i>
20
20
  </a>
21
21
  {% endif %}
22
- <button class='btn btn-sm btn-default' onclick='show_video("features")'><i class="fa-solid fa-question"></i></button> <a href="{{'https://github.com/hiddify/hiddify-manager/wiki'}}">
23
- {{hconfig(ConfigEnum.branding_title) or _('user.home.title')}}</a>: <div class="d-inline-flex">{{_('Welcome %(user)s',user=user.name if user.name!="default" else "")}}</div>
22
+ <button class='btn btn-sm btn-default' onclick='show_video("features")'><i
23
+ class="fa-solid fa-question"></i></button> <a
24
+ href="{{'https://github.com/hiddify/hiddify-manager/wiki'}}">
25
+ {{hconfig(ConfigEnum.branding_title) or _('user.home.title')}}</a>: <div class="d-inline-flex">
26
+ {{_('Welcome %(user)s',user=user.name if user.name!="default" else "")}}</div>
24
27
  </h1>
25
28
 
26
29
 
@@ -48,19 +51,27 @@
48
51
  <h3 class="card-title p-1"> </h3>
49
52
  <ul class="nav nav-pills p-2">
50
53
  {% if telegram_enable %}
51
- <li class="nav-item"><a class="nav-link" href="#telegram" data-toggle="tab"><i class="fa-brands fa-telegram fa-margin"></i> {{_('telegram')}}</a></li>
54
+ <li class="nav-item"><a class="nav-link" href="#telegram" data-toggle="tab"><i
55
+ class="fa-brands fa-telegram fa-margin"></i> {{_('telegram')}}</a></li>
52
56
  {% endif %}
53
- <li class="nav-item"><a class="nav-link {{" active" if ua.os.family=="Android" else "" }}" href="#android" data-toggle="tab"><i class="fa-brands fa-android fa-margin"></i> {{_('android')}}</a></li>
54
- <li class="nav-item"><a class="nav-link {{" active" if ua.os.family=="iOS" else "" }}" href="#ios" data-toggle="tab"><i class="fa-brands fa-app-store-ios fa-margin"></i> {{_('ios')}}</a></li>
55
- <li class="nav-item"><a class="nav-link {{" active" if ua.is_pc else "" }}" href="#windows" data-toggle="tab">
56
- <i class="fa-brands fa-windows fa-margin1"></i> <i class="fa-brands fa-apple fa-margin1"></i> <i class="fa-brands fa-linux fa-margin1"></i> {{_('desktop')}}</a></li>
57
+ <li class="nav-item"><a class="nav-link {{" active" if ua.os.family=="Android" else "" }}"
58
+ href="#android" data-toggle="tab"><i class="fa-brands fa-android fa-margin"></i>
59
+ {{_('android')}}</a></li>
60
+ <li class="nav-item"><a class="nav-link {{" active" if ua.os.family=="iOS" else "" }}" href="#ios"
61
+ data-toggle="tab"><i class="fa-brands fa-app-store-ios fa-margin"></i> {{_('ios')}}</a></li>
62
+ <li class="nav-item"><a class="nav-link {{" active" if ua.is_pc else "" }}" href="#windows"
63
+ data-toggle="tab">
64
+ <i class="fa-brands fa-windows fa-margin1"></i> <i
65
+ class="fa-brands fa-apple fa-margin1"></i> <i class="fa-brands fa-linux fa-margin1"></i>
66
+ {{_('desktop')}}</a></li>
57
67
 
58
68
  </ul>
59
69
  </div><!-- /.card-header -->
60
70
  <div class="card-body">
61
71
  <div class="tab-content">
62
- <div class="tab-pane {{" active" if not ua.is_pc and ua.os.family not in ["Android", "iOS" ] else "" }}" id="default">
63
- {{_('user.home.select os')}}
72
+ <div class="tab-pane {{" active" if not ua.is_pc and ua.os.family not in ["Android", "iOS" ] else ""
73
+ }}" id="default">
74
+ {{_('user.home.select_os')}}
64
75
  </div>
65
76
  <div class="tab-pane" id="telegram">
66
77
  {% include 'home/telegram.html' %}
@@ -94,15 +105,19 @@
94
105
  <div class="card-header d-flex p-0">
95
106
  <h3 class="card-title p-0"></h3>
96
107
  <ul class="nav nav-pills p-2">
97
- <li class="nav-item"><a class="nav-link" href="#all_configs" data-toggle="tab"><i class="fa-solid fa-grip fa-margin"></i> {{_('user.home.all_configs')}}</a></li>
98
- <li class="nav-item"><a class="nav-link" href="#speedtest" data-toggle="tab"><i class="fa-solid fa-gauge-high fa-margin"></i> {{_('user.home.speedtest.title')}}</a></li>
99
- <li class="nav-item"><a class="nav-link" href="#doh" data-toggle="tab"><i class="fa-solid fa-sitemap fa-margin"></i> {{_('user.home.doh')}}</a></li>
108
+ <li class="nav-item"><a class="nav-link" href="#all_configs" data-toggle="tab"><i
109
+ class="fa-solid fa-grip fa-margin"></i> {{_('user.home.all_configs')}}</a></li>
110
+ <li class="nav-item"><a class="nav-link" href="#speedtest" data-toggle="tab"><i
111
+ class="fa-solid fa-gauge-high fa-margin"></i> {{_('user.home.speedtest.title')}}</a>
112
+ </li>
113
+ <li class="nav-item"><a class="nav-link" href="#doh" data-toggle="tab"><i
114
+ class="fa-solid fa-sitemap fa-margin"></i> {{_('user.home.doh')}}</a></li>
100
115
  </ul>
101
116
  </div><!-- /.card-header -->
102
117
  <div class="card-body">
103
118
  <div class="tab-content">
104
119
  <div class="tab-pane active" id="default">
105
- {{_('user.home.select tool')}}
120
+ {{_('user.home.select_tool')}}
106
121
  </div>
107
122
  <div class="tab-pane" id="all_configs">
108
123
  {% include 'home/all-configs.html'%}
@@ -135,7 +150,8 @@
135
150
  <i class="fa-solid fa-qrcode fa-margin"></i>
136
151
  </div>
137
152
  </div>
138
- <a href="https://{{domain}}/{{hconfigs[ConfigEnum.proxy_path]}}/{{user.uuid}}/" class="card-footer share-link">
153
+ <a href="https://{{domain}}/{{hconfigs[ConfigEnum.proxy_path]}}/{{user.uuid}}/"
154
+ class="card-footer share-link">
139
155
  <i class="fas fa-qrcode"></i> {{_('user.home.qr-code.display')}}
140
156
  </a>
141
157
 
@@ -60,7 +60,7 @@
60
60
  <div class="tab-content">
61
61
  <div class="tab-pane {{" active" if not ua.is_pc and ua.os.family not in ["Android", "iOS" ] else ""
62
62
  }}" id="default">
63
- {{_('user.home.select os')}}
63
+ {{_('user.home.select_os')}}
64
64
  </div>
65
65
  <div class="tab-pane" id="telegram">
66
66
  {% include 'home/telegram.html' %}
@@ -106,7 +106,7 @@
106
106
  <div class="card-body">
107
107
  <div class="tab-content">
108
108
  <div class="tab-pane active" id="default">
109
- {{_('user.home.select tool')}}
109
+ {{_('user.home.select_tool')}}
110
110
  </div>
111
111
  <div class="tab-pane" id="all_configs">
112
112
  {% include 'home/all-configs.html'%}
@@ -73,7 +73,7 @@
73
73
  <div class="tab-content">
74
74
  <div class="tab-pane {{" active" if not ua.is_pc and ua.os.family not in ["Android", "iOS" ] else ""
75
75
  }}" id="default">
76
- {{_('user.home.select os')}}
76
+ {{_('user.home.select_os')}}
77
77
  </div>
78
78
  <div class="tab-pane" id="telegram">
79
79
  {% include 'home/telegram.html' %}
@@ -121,7 +121,7 @@
121
121
  <div class="card-body">
122
122
  <div class="tab-content">
123
123
  <div class="tab-pane active" id="default">
124
- {{_('user.home.select tool')}}
124
+ {{_('user.home.select_tool')}}
125
125
  </div>
126
126
 
127
127
  <div class="tab-pane" id="speedtest">