hiddifypanel 9.0.0.dev82__py3-none-any.whl → 9.0.0.dev92__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 (49) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/base.py +2 -2
  4. hiddifypanel/hutils/encode.py +5 -0
  5. hiddifypanel/models/proxy.py +4 -0
  6. hiddifypanel/models/user.py +2 -1
  7. hiddifypanel/models/utils.py +0 -2
  8. hiddifypanel/panel/admin/AdminstratorAdmin.py +1 -0
  9. hiddifypanel/panel/admin/DomainAdmin.py +3 -3
  10. hiddifypanel/panel/admin/ProxyAdmin.py +8 -2
  11. hiddifypanel/panel/admin/SettingAdmin.py +5 -2
  12. hiddifypanel/panel/admin/UserAdmin.py +36 -29
  13. hiddifypanel/panel/admin/adminlte.py +2 -2
  14. hiddifypanel/panel/admin/fix_flaskadmin_babel.py +1 -2
  15. hiddifypanel/panel/admin/templates/configfake.html +1 -0
  16. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +14 -2
  17. hiddifypanel/panel/commercial/restapi/v2/user/info_api.py +3 -2
  18. hiddifypanel/panel/hiddify.py +1 -1
  19. hiddifypanel/panel/init_db.py +2 -2
  20. hiddifypanel/panel/user/link_maker.py +2 -2
  21. hiddifypanel/panel/user/user.py +1 -1
  22. hiddifypanel/static/js/custom-rtl.js +8 -4
  23. hiddifypanel/static/js/custom.js +1 -1
  24. hiddifypanel/static/plugins/bootstrap4-editable/js/bootstrap-editable.js +3106 -3106
  25. hiddifypanel/static/plugins/bootstrap4-editable/js/bootstrap-editable.min.js +15 -3
  26. hiddifypanel/templates/admin-layout.html +2 -2
  27. hiddifypanel/templates/flaskadmin-layout.html +104 -80
  28. hiddifypanel/templates/master.html +4 -1
  29. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  30. hiddifypanel/translations/en/LC_MESSAGES/messages.po +8 -6
  31. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  32. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +7 -3
  33. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  34. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +40 -28
  35. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  36. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +41 -27
  37. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  38. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +22 -12
  39. hiddifypanel/translations.i18n/en.json +3 -1
  40. hiddifypanel/translations.i18n/fa.json +3 -1
  41. hiddifypanel/translations.i18n/pt.json +30 -28
  42. hiddifypanel/translations.i18n/ru.json +30 -28
  43. hiddifypanel/translations.i18n/zh.json +14 -12
  44. {hiddifypanel-9.0.0.dev82.dist-info → hiddifypanel-9.0.0.dev92.dist-info}/METADATA +1 -1
  45. {hiddifypanel-9.0.0.dev82.dist-info → hiddifypanel-9.0.0.dev92.dist-info}/RECORD +49 -49
  46. {hiddifypanel-9.0.0.dev82.dist-info → hiddifypanel-9.0.0.dev92.dist-info}/LICENSE.md +0 -0
  47. {hiddifypanel-9.0.0.dev82.dist-info → hiddifypanel-9.0.0.dev92.dist-info}/WHEEL +0 -0
  48. {hiddifypanel-9.0.0.dev82.dist-info → hiddifypanel-9.0.0.dev92.dist-info}/entry_points.txt +0 -0
  49. {hiddifypanel-9.0.0.dev82.dist-info → hiddifypanel-9.0.0.dev92.dist-info}/top_level.txt +0 -0
hiddifypanel/VERSION CHANGED
@@ -1 +1 @@
1
- 9.0.0.dev82
1
+ 9.0.0.dev92
hiddifypanel/VERSION.py CHANGED
@@ -1,3 +1,3 @@
1
- __version__='9.0.0.dev82'
1
+ __version__='9.0.0.dev92'
2
2
  from datetime import datetime
3
- __release_date__= datetime.strptime('2024-03-02','%Y-%m-%d')
3
+ __release_date__= datetime.strptime('2024-03-03','%Y-%m-%d')
hiddifypanel/base.py CHANGED
@@ -95,8 +95,8 @@ def create_app(*args, cli=False, **config):
95
95
  commercial.init_app(app)
96
96
 
97
97
  app.config.update(config) # Override with passed config
98
- app.config['WTF_CSRF_CHECK_DEFAULT'] = False
99
-
98
+ # app.config['WTF_CSRF_CHECK_DEFAULT'] = False
99
+ app.config['WTF_CSRF_ENABLED'] = False
100
100
  # app.config['BABEL_TRANSLATION_DIRECTORIES'] = '/workspace/Hiddify-Server/hiddify-panel/src/translations.i18n'
101
101
 
102
102
  # from flask_wtf.csrf import CSRFProtect
@@ -2,6 +2,11 @@ import urllib.parse
2
2
  import base64
3
3
  import uuid
4
4
  import string
5
+ from slugify import slugify
6
+
7
+
8
+ def unicode_slug(instr: str) -> str:
9
+ return slugify(instr, lowercase=False, allow_unicode=True)
5
10
 
6
11
 
7
12
  def url_encode(url: str) -> str:
@@ -67,6 +67,10 @@ class Proxy(db.Model, SerializerMixin):
67
67
  transport = db.Column(db.Enum(ProxyTransport), nullable=False)
68
68
  cdn = db.Column(db.Enum(ProxyCDN), nullable=False)
69
69
 
70
+ @property
71
+ def enabled(self):
72
+ return self.enable * 1
73
+
70
74
  def to_dict(self):
71
75
  return {
72
76
  'name': self.name,
@@ -120,7 +120,7 @@ class User(BaseAccount):
120
120
  is_active = False
121
121
  elif self.usage_limit < self.current_usage:
122
122
  is_active = False
123
- elif self.remaining_days() < 0:
123
+ elif self.remaining_days < 0:
124
124
  is_active = False
125
125
  elif len(self.ips) > max(3, self.max_ips):
126
126
  is_active = False
@@ -163,6 +163,7 @@ class User(BaseAccount):
163
163
  days = package_mode_dic.get(self.mode, 10000)
164
164
  return max(-100000, min(days, 100000))
165
165
 
166
+ @property
166
167
  def remaining_days(self) -> int:
167
168
  """
168
169
  The "remaining_days" function calculates the number of days remaining for a user's account package based on the
@@ -1,6 +1,4 @@
1
1
 
2
- from slugify import slugify
3
-
4
2
 
5
3
  def fill_username(model) -> None:
6
4
  from hiddifypanel import hutils
@@ -40,6 +40,7 @@ class AdminstratorAdmin(AdminLTEModelView):
40
40
  column_list = ["name", 'UserLinks', 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'online_users', 'comment']
41
41
  form_columns = ["name", 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'comment', "uuid"]
42
42
  list_template = 'model/admin_list.html'
43
+ # column_editable_list = ['name']
43
44
  # edit_modal = True
44
45
  # form_overrides = {'work_with': Select2Field}
45
46
 
@@ -26,8 +26,8 @@ from flask import current_app
26
26
 
27
27
 
28
28
  class DomainAdmin(AdminLTEModelView):
29
- edit_modal = False
30
- create_modal = False
29
+ # edit_modal = False
30
+ # create_modal = False
31
31
  column_hide_backrefs = False
32
32
 
33
33
  list_template = 'model/domain_list.html'
@@ -77,7 +77,7 @@ class DomainAdmin(AdminLTEModelView):
77
77
  re.IGNORECASE,
78
78
  _("Invalid REALITY hostnames"))]}}
79
79
  column_list = ["domain", "alias", "mode", "domain_ip", "show_domains"]
80
- # column_editable_list=["domain"]
80
+ column_editable_list = ["alias"]
81
81
  # column_filters=["domain","mode"]
82
82
  # form_excluded_columns=['work_with']
83
83
  column_searchable_list = ["domain", "mode"]
@@ -104,11 +104,17 @@ def get_all_proxy_form(empty=False):
104
104
  class CDNForm(FlaskForm):
105
105
  pass
106
106
  cdn_proxies = [c for c in proxies if c.cdn == cdn]
107
- protos = sorted([c for c in {c.proto: 1 for c in cdn_proxies}])
107
+ pgroup = {
108
+ 'wireguard': 'other',
109
+ 'tuic': 'other',
110
+ 'ssh': 'other',
111
+ 'hysteria2': 'other',
112
+ }
113
+ protos = sorted([c for c in {pgroup.get(c.proto, c.proto): 1 for c in cdn_proxies}])
108
114
  for proto in protos:
109
115
  class ProtoForm(FlaskForm):
110
116
  pass
111
- proto_proxies = [c for c in cdn_proxies if c.proto == proto]
117
+ proto_proxies = [c for c in cdn_proxies if pgroup.get(c.proto, c.proto) == proto]
112
118
  for proxy in proto_proxies:
113
119
  field = SwitchField(proxy.name, default=proxy.enable, description=f"l3:{proxy.l3} transport:{proxy.transport}")
114
120
  setattr(ProtoForm, f"p_{proxy.id}", field)
@@ -168,8 +168,11 @@ def get_config_form():
168
168
  field = wtf.fields.SelectField(_(f"config.{c.key}.label"), choices=[("ir", _("Iran")), ("zh", _(
169
169
  "China")), ("other", _("Others"))], description=_(f"config.{c.key}.description"), default=hconfig(c.key))
170
170
  elif c.key == ConfigEnum.package_mode:
171
- field = wtf.fields.SelectField(_(f"config.{c.key}.label"), choices=[("release", _("Release")), ("beta", _("Beta")),
172
- ("develop", _("Develop"))], description=_(f"config.{c.key}.description"), default=hconfig(c.key))
171
+ package_modes = [("release", _("Release")), ("beta", _("Beta"))]
172
+ if hconfig(c.key) == "develop":
173
+ package_modes.append(("develop", _("Develop")))
174
+ field = wtf.fields.SelectField(_(f"config.{c.key}.label"), choices=package_modes,
175
+ description=_(f"config.{c.key}.description"), default=hconfig(c.key))
173
176
 
174
177
  elif c.key == ConfigEnum.shadowsocks2022_method:
175
178
  field = wtf.fields.SelectField(_(f"config.{c.key}.label"), choices=[
@@ -1,8 +1,9 @@
1
1
  import re
2
+ from flask_admin.actions import action
2
3
  import datetime
3
4
  import uuid
4
5
  from apiflask import abort
5
- from flask_bootstrap import SwitchField
6
+ from flask_bootstrap import SwitchField, BooleanField
6
7
  from flask_babel import gettext as __
7
8
  from .adminlte import AdminLTEModelView
8
9
  from wtforms.validators import NumberRange
@@ -22,16 +23,17 @@ from hiddifypanel import hutils
22
23
 
23
24
  class UserAdmin(AdminLTEModelView):
24
25
 
25
- column_sortable_list = ["enable", "name", "current_usage", 'mode', "remaining_days", "comment", 'last_online', "uuid", 'remaining_days']
26
- column_searchable_list = [("uuid"), "name"]
27
- column_list = ["enable", "name", "UserLinks", "current_usage", "remaining_days", "comment", 'last_online', 'mode', 'admin', "uuid"]
26
+ column_sortable_list = ["is_active", "name", "current_usage", 'mode', "remaining_days", "comment", 'last_online', "uuid", 'remaining_days']
27
+ column_searchable_list = ["uuid", "name"]
28
+ column_list = ["is_active", "name", "UserLinks", "current_usage", "remaining_days", "comment", 'last_online', 'mode', 'admin', "uuid"]
29
+ column_editable_list = ["comment", "name"]
28
30
  form_extra_fields = {
29
31
  'reset_days': SwitchField(_("Reset package days")),
30
32
  'reset_usage': SwitchField(_("Reset package usage")),
31
33
  # 'disable_user': SwitchField(_("Disable User"))
32
34
  }
33
35
  list_template = 'model/user_list.html'
34
- column_editable_list = ["comment", "usage_limit", "package_days"]
36
+
35
37
  form_columns = ["name", "comment", "usage_limit", "reset_usage", "package_days", "reset_days", "mode", "uuid", "enable",]
36
38
  # form_excluded_columns = ['current_usage', 'monthly', 'telegram_id', 'last_online', 'expiry_time', 'last_reset_time', 'current_usage_GB',
37
39
  # 'start_date', 'added_by', 'admin', 'details', 'max_ips', 'ed25519_private_key', 'ed25519_public_key', 'username', 'password']
@@ -42,6 +44,7 @@ class UserAdmin(AdminLTEModelView):
42
44
  # can_export = True
43
45
  # form_overrides = dict(monthly=SwitchField)
44
46
  form_overrides = {
47
+
45
48
  'start_date': custom_widgets.DaysLeftField,
46
49
  'mode': custom_widgets.EnumSelectField,
47
50
  'usage_limit': custom_widgets.UsageField
@@ -91,6 +94,7 @@ class UserAdmin(AdminLTEModelView):
91
94
  "package_days": _('Package Days'),
92
95
  "max_ips": _('Max IPs'),
93
96
  "enable": _('Enable'),
97
+ "is_active": _('Active'),
94
98
 
95
99
  }
96
100
  # can_set_page_size=True
@@ -119,33 +123,34 @@ class UserAdmin(AdminLTEModelView):
119
123
  # can_edit = False
120
124
  # def on_model_change(self, form, model, is_created):
121
125
  # model.password = generate_password_hash(model.password)
126
+ def _enable_formatter(view, context, model, name):
127
+ if model.is_active:
128
+ link = '<i class="fa-solid fa-circle-check text-success"></i> '
129
+ elif len(model.ips):
130
+ link = '<i class="fa-solid fa-users-slash text-danger" title="{_("Too many Connected IPs")}"></i>'
131
+ else:
132
+ link = '<i class="fa-solid fa-circle-xmark text-danger"></i> '
122
133
 
123
- def _name_formatter(view, context, model, name):
124
- # print("model.telegram_id",model.telegram_id)
125
- extra = ""
126
134
  if hconfig(ConfigEnum.telegram_bot_token):
127
135
  if model.telegram_id:
128
- extra = f'<button class="btn hbtn bg-h-blue btn-xs " onclick="show_send_message({model.id})" ><i class="fa-solid fa-paper-plane"></i></button> '
136
+ link += f'<button class="btn hbtn bg-h-blue btn-xs " onclick="show_send_message({model.id})" ><i class="fa-solid fa-paper-plane"></i></button> '
129
137
  else:
130
- extra = f'<button class="btn hbtn bg-h-grey btn-xs disabled"><i class="fa-solid fa-paper-plane"></i></button> '
138
+ link += f'<button class="btn hbtn bg-h-grey btn-xs disabled"><i class="fa-solid fa-paper-plane"></i></button> '
131
139
 
132
- link = ''
133
- # if model.is_active:
134
- # link = '<i class="fa-solid fa-circle-check text-success"></i> '
135
- # elif len(model.ips):
136
- # link = '<i class="fa-solid fa-users-slash text-danger" title="{_("Too many Connected IPs")}"></i>'
137
- # else:
138
- # link = '<i class="fa-solid fa-circle-xmark text-danger"></i> '
140
+ return Markup(link)
139
141
 
140
- href = f'{hiddify.get_account_panel_link(model, request.host, is_https=True)}#{hutils.encode.url_encode(model.name)}'
142
+ # def _name_formatter(view, context, model, name):
143
+ # # print("model.telegram_id",model.telegram_id)
141
144
 
142
- link += f"<a target='_blank' class='share-link' data-copy='{href}' href='{href}'>{model.name} <i class='fa-solid fa-arrow-up-right-from-square'></i></a>"
145
+ def _ul_formatter(view, context, model, name):
146
+ href = f'{hiddify.get_account_panel_link(model, request.host, is_https=True)}#{hutils.encode.unicode_slug(model.name)}'
143
147
 
144
- return Markup(extra + link)
148
+ link = f"""<a target='_blank' class='share-link btn btn-xs btn-primary' data-copy='{href}' href='{href}'>
149
+ <i class='fa-solid fa-arrow-up-right-from-square'></i>
150
+ {_("Current Domain")} </a>"""
145
151
 
146
- def _ul_formatter(view, context, model, name):
147
- domains = get_panel_domains()
148
- return Markup(" ".join([hiddify.get_html_user_link(model, d) for d in domains]))
152
+ domains = [d for d in get_panel_domains() if d.domain != request.host]
153
+ return Markup(link + " ".join([hiddify.get_html_user_link(model, d) for d in domains]))
149
154
 
150
155
  def _uuid_formatter(view, context, model, name):
151
156
  return Markup(f"<span>{model.uuid}</span>")
@@ -167,7 +172,7 @@ class UserAdmin(AdminLTEModelView):
167
172
  """)
168
173
 
169
174
  def _expire_formatter(view, context, model, name):
170
- remaining = model.remaining_days()
175
+ remaining = model.remaining_days
171
176
 
172
177
  diff = datetime.timedelta(days=remaining)
173
178
 
@@ -194,13 +199,15 @@ class UserAdmin(AdminLTEModelView):
194
199
  # return Markup(f"<span class='badge ltr badge-{'success' if days>7 else ('warning' if days>0 else 'danger') }'>{days}</span> "+_('days'))
195
200
 
196
201
  column_formatters = {
197
- 'name': _name_formatter,
202
+ # 'name': _name_formatter,
198
203
  'UserLinks': _ul_formatter,
199
204
  'uuid': _uuid_formatter,
200
205
  'current_usage': _usage_formatter,
201
206
  "remaining_days": _expire_formatter,
202
207
  'last_online': _online_formatter,
203
- 'admin': _admin_formatter
208
+ 'admin': _admin_formatter,
209
+
210
+ "is_active": _enable_formatter
204
211
  }
205
212
 
206
213
  def on_model_delete(self, model):
@@ -223,7 +230,7 @@ class UserAdmin(AdminLTEModelView):
223
230
  delattr(form, 'reset_usage')
224
231
  # delattr(form,'disable_user')
225
232
  else:
226
- remaining = form._obj.remaining_days() # remaining_days(form._obj)
233
+ remaining = form._obj.remaining_days # remaining_days(form._obj)
227
234
  msg = _("Remaining: ") + hutils.convert.format_timedelta(datetime.timedelta(days=remaining))
228
235
  form.reset_days.label.text += f" ({msg})"
229
236
  usr_usage = f" ({_('user.home.usage.title')} {round(form._obj.current_usage_GB,3)}GB)"
@@ -297,7 +304,7 @@ class UserAdmin(AdminLTEModelView):
297
304
  def get_list(self, page, sort_column, sort_desc, search, filters, page_size=50, *args, **kwargs):
298
305
  res = None
299
306
  # print('aaa',args, kwargs)
300
- if sort_column == 'remaining_days':
307
+ if sort_column in ['remaining_days', 'is_active']:
301
308
  query = self.get_query()
302
309
 
303
310
  if search:
@@ -312,7 +319,7 @@ class UserAdmin(AdminLTEModelView):
312
319
  count = len(data)
313
320
 
314
321
  # Sorting the data
315
- data = sorted(data, key=lambda p: p.remaining_days(), reverse=sort_desc)
322
+ data = sorted(data, key=lambda p: getattr(p, sort_column), reverse=sort_desc)
316
323
 
317
324
  # Applying pagination
318
325
  start = page * page_size
@@ -5,8 +5,8 @@ from flask_admin.form import SecureForm
5
5
 
6
6
  class AdminLTEModelView(ModelView):
7
7
  form_base_class = SecureForm
8
- edit_modal = False
9
- create_modal = False
8
+ edit_modal = True
9
+ create_modal = True
10
10
 
11
11
  list_template = 'hiddify-flask-admin/list.html'
12
12
  create_template = 'flask-admin/model/create.html'
@@ -11,9 +11,8 @@ import flask_admin.babel
11
11
  def gettext(string, **variables):
12
12
 
13
13
  tt = _(string, **variables)
14
- print("=--", string, tt)
14
+ # print("=--", string, tt)
15
15
  if tt == string:
16
- print("getting orig")
17
16
  return gettext_old(string, **variables)
18
17
  return tt
19
18
 
@@ -2,6 +2,7 @@ Please don't edit this filename
2
2
  It is just for babel
3
3
  generated from /admin/setting-admin/get_babel_string/
4
4
  {{_("Create")}}
5
+ {{_("Current Domain")}}
5
6
 
6
7
  {{_("domain.cdn")}} {{_("Create")}} {{_("Save & Add More")}} {{_("Close")}} {{_("Back")}}
7
8
  {{_("config.admin_lang.label")}}
@@ -3,7 +3,7 @@ from hiddifypanel.panel.admin.adminlte import AdminLTEModelView
3
3
  from flask_babel import gettext as __
4
4
  from flask_babel import lazy_gettext as _
5
5
  from hiddifypanel.panel import hiddify
6
- from flask import g, redirect
6
+ from flask import g, redirect, Markup
7
7
  from hiddifypanel.hutils.flask import hurl_for, flash
8
8
  from hiddifypanel.auth import login_required
9
9
  from flask_admin.model.template import EndpointLinkRowAction
@@ -21,6 +21,7 @@ class ProxyDetailsAdmin(AdminLTEModelView):
21
21
  form_excluded_columns = ['child']
22
22
  column_exclude_list = ['child']
23
23
  column_searchable_list = ['name', 'proto', 'transport', 'l3', 'cdn']
24
+ column_editable_list = ['name']
24
25
 
25
26
  @action('disable', 'Disable', 'Are you sure you want to disable selected proxies?')
26
27
  def action_disable(self, ids):
@@ -39,7 +40,7 @@ class ProxyDetailsAdmin(AdminLTEModelView):
39
40
  self.session.commit()
40
41
  flash(_('%(count)s records were successfully enabled.', count=count), 'success')
41
42
  hiddify.get_available_proxies.invalidate_all()
42
- column_editable_list = ['name']
43
+
43
44
  # list_template = 'model/domain_list.html'
44
45
 
45
46
  # form_overrides = {'work_with': Select2Field}
@@ -60,3 +61,14 @@ class ProxyDetailsAdmin(AdminLTEModelView):
60
61
  if login_required(roles={Role.super_admin, Role.admin})(lambda: True)() != True:
61
62
  return False
62
63
  return True
64
+
65
+ def _enable_formatter(view, context, model, name):
66
+ if model.enable:
67
+ link = '<i class="fa-solid fa-circle-check text-success"></i> '
68
+ else:
69
+ link = '<i class="fa-solid fa-circle-xmark text-danger"></i> '
70
+ return Markup(link)
71
+ column_formatters = {
72
+
73
+ "enable": _enable_formatter
74
+ }
@@ -55,7 +55,7 @@ class InfoAPI(MethodView):
55
55
  dto.profile_url = f"{c['profile_url']}#{hutils.encode.url_encode(c['user'].name)}"
56
56
  dto.profile_usage_current = g.account.current_usage_GB
57
57
  dto.profile_usage_total = g.account.usage_limit_GB
58
- dto.profile_remaining_days = g.account.remaining_days()
58
+ dto.profile_remaining_days = g.account.remaining_days
59
59
  dto.profile_reset_days = g.account.days_to_reset()
60
60
  dto.telegram_bot_url = f"https://t.me/{c['bot'].username}?start={g.account.uuid}" if c['bot'] else ""
61
61
  dto.telegram_id = c['user'].telegram_id
@@ -66,7 +66,8 @@ class InfoAPI(MethodView):
66
66
  # with force_locale("fa"):
67
67
  dto.admin_message_html = hconfig(ConfigEnum.branding_freetext) or _("Join our Hiddify Telegram channel to get the latest updates on Hiddify.")
68
68
  if not hconfig(ConfigEnum.branding_freetext) and auth.admin_session_is_exist():
69
- dto.admin_message_html += "<p style='font-style: italic;font-size:8px'>" + _("[Admin only visible message:] You can change this message from settings") + "</p>"
69
+ dto.admin_message_html += "<p style='font-style: italic;font-size:8px'>" + \
70
+ _("[Admin only visible message:] You can change this message from settings") + "</p>"
70
71
  dto.admin_message_url = hconfig(ConfigEnum.branding_site) or "https://t.me/hiddify"
71
72
  dto.brand_title = hconfig(ConfigEnum.branding_title) or _("Hiddify")
72
73
 
@@ -149,7 +149,7 @@ def get_html_user_link(model: BaseAccount, domain: Domain):
149
149
  if "*" in d:
150
150
  d = d.replace("*", hutils.random.get_random_string(5, 15))
151
151
 
152
- link = f'{get_account_panel_link(model, d)}#{hutils.encode.url_encode(model.name)}'
152
+ link = f'{get_account_panel_link(model, d)}#{hutils.encode.unicode_slug(model.name)}'
153
153
 
154
154
  text = domain.alias or domain.domain
155
155
  color_cls = 'info'
@@ -618,8 +618,8 @@ def init_db():
618
618
  get_hconfigs.invalidate_all()
619
619
  # set_hconfig(ConfigEnum.db_version, 71)
620
620
  # temporary fix
621
- add_column(Child.mode)
622
- add_column(Child.name)
621
+ # add_column(Child.mode)
622
+ # add_column(Child.name)
623
623
  db_version = int(hconfig(ConfigEnum.db_version) or 0)
624
624
  if db_version == latest_db_version():
625
625
  return
@@ -234,7 +234,7 @@ def make_proxy(hconfigs, proxy: Proxy, domain_db: Domain, phttp=80, ptls=443, pp
234
234
  base['flow'] = 'xtls-rprx-vision'
235
235
  return {**base, 'transport': 'tcp'}
236
236
 
237
- if proxy.proto in {'vless', 'trojan', 'vmess'} and hconfigs[ConfigEnum.mux_enable]:
237
+ if proxy.proto in {'vless', 'trojan', 'vmess'} and hconfigs.get(ConfigEnum.mux_enable):
238
238
  if hconfigs[ConfigEnum.mux_enable]:
239
239
  base['mux_enable'] = True
240
240
  base['mux_protocol'] = hconfigs[ConfigEnum.mux_protocol]
@@ -355,7 +355,7 @@ def to_link(proxy):
355
355
  # return f'{baseurl}?plugin=shadow-tls%3Bpassword%3D{proxy["proxy_path"]}%3Bhost%3D{proxy["fakedomain"]}%3Budp-over-tcp=true#{name_link}'
356
356
  if proxy['proto'] == 'v2ray':
357
357
  return f'{baseurl}?plugin=v2ray-plugin%3Bmode%3Dwebsocket%3Bpath%3D{proxy["path"]}%3Bhost%3D{proxy["host"]}%3Btls%3Budp-over-tcp=true#{name_link}'
358
- if proxy['transport']=='shadowsocks':
358
+ if proxy['transport'] == 'shadowsocks':
359
359
  return baseurl
360
360
  if proxy['proto'] == 'tuic':
361
361
  baseurl = f'tuic://{proxy["uuid"]}:{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?congestion_control=cubic&udp_relay_mode=native&sni={proxy["sni"]}&alpn=h3'
@@ -309,7 +309,7 @@ def get_common_data(user_uuid, mode, no_domain=False, filter_domain=None):
309
309
 
310
310
  }
311
311
 
312
- expire_days = user.remaining_days()
312
+ expire_days = user.remaining_days
313
313
  reset_days = user.days_to_reset()
314
314
  if reset_days >= expire_days:
315
315
  reset_days = 1000
@@ -1,8 +1,12 @@
1
- function ConvertNumberToPersion() {
1
+ function ConvertNumberToPersion(elemnt) {
2
2
  let persian = { 0: '۰', 1: '۱', 2: '۲', 3: '۳', 4: '۴', 5: '۵', 6: '۶', 7: '۷', 8: '۸', 9: '۹' };
3
3
  let replace = {
4
4
  "Admin User": "مدیر", "User": 'کاربر',
5
- 'Create': 'ایجاد', "Back": "بازگشت", "Save & Add More": "ذخیره و ایجاد جدید", "Edit": "ویرایش", "Domain": "دامنه", "Proxy": "پروکسی"
5
+ 'Create': 'ایجاد',
6
+ "Edit": "ویرایش",
7
+ "Domain": "دامنه",
8
+ "Proxy": "پروکسی",
9
+
6
10
  }
7
11
  // $('input[value="Save & Add More"]').val("ذخیره و ایجاد جدید")
8
12
 
@@ -31,12 +35,12 @@ function ConvertNumberToPersion() {
31
35
  traverse(el.childNodes[i]);
32
36
  }
33
37
  }
34
- traverse(document.body);
38
+ traverse(elemnt);
35
39
  }
36
40
 
37
41
 
38
42
  $(document).ready(function () {
39
43
 
40
- ConvertNumberToPersion();
44
+ ConvertNumberToPersion(document.body);
41
45
 
42
46
  });
@@ -1,4 +1,4 @@
1
- function ConvertNumberToPersion() {
1
+ function ConvertNumberToPersion(elemnt) {
2
2
  }
3
3
 
4
4
  $(document).ready(function () {