valar 1.2.5__tar.gz → 1.3.0__tar.gz

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.

Potentially problematic release.


This version of valar might be problematic. Click here for more details.

Files changed (60) hide show
  1. {valar-1.2.5/src/valar.egg-info → valar-1.3.0}/PKG-INFO +2 -1
  2. {valar-1.2.5 → valar-1.3.0}/setup.py +2 -2
  3. {valar-1.2.5 → valar-1.3.0}/src/valar/apps.py +10 -4
  4. valar-1.3.0/src/valar/auth/Authentication.py +32 -0
  5. valar-1.3.0/src/valar/auth/Middleware.py +28 -0
  6. {valar-1.2.5 → valar-1.3.0}/src/valar/channels/sender.py +4 -1
  7. valar-1.3.0/src/valar/classes/valar_response.py +9 -0
  8. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/abstract.py +6 -3
  9. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/defaults/field_keys_default.py +10 -1
  10. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/engine.py +9 -0
  11. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/orm_field.py +4 -6
  12. valar-1.3.0/src/valar/models/__init__.py +1 -0
  13. valar-1.3.0/src/valar/models/auth.py +47 -0
  14. {valar-1.2.5 → valar-1.3.0}/src/valar/urls.py +10 -4
  15. valar-1.3.0/src/valar/views/__init__.py +0 -0
  16. valar-1.3.0/src/valar/views/auth.py +110 -0
  17. valar-1.3.0/src/valar/views/password.py +60 -0
  18. {valar-1.2.5 → valar-1.3.0/src/valar.egg-info}/PKG-INFO +2 -1
  19. {valar-1.2.5 → valar-1.3.0}/src/valar.egg-info/SOURCES.txt +6 -0
  20. {valar-1.2.5 → valar-1.3.0}/src/valar.egg-info/requires.txt +1 -0
  21. valar-1.2.5/src/valar/classes/valar_response.py +0 -8
  22. valar-1.2.5/src/valar/models/__init__.py +0 -1
  23. {valar-1.2.5 → valar-1.3.0}/LICENSE +0 -0
  24. {valar-1.2.5 → valar-1.3.0}/README.md +0 -0
  25. {valar-1.2.5 → valar-1.3.0}/setup.cfg +0 -0
  26. {valar-1.2.5 → valar-1.3.0}/src/valar/__init__.py +0 -0
  27. {valar-1.2.5/src/valar/channels → valar-1.3.0/src/valar/auth}/__init__.py +0 -0
  28. {valar-1.2.5/src/valar/classes → valar-1.3.0/src/valar/channels}/__init__.py +0 -0
  29. {valar-1.2.5 → valar-1.3.0}/src/valar/channels/consumer.py +0 -0
  30. {valar-1.2.5 → valar-1.3.0}/src/valar/channels/counter.py +0 -0
  31. {valar-1.2.5 → valar-1.3.0}/src/valar/channels/executer.py +0 -0
  32. {valar-1.2.5 → valar-1.3.0}/src/valar/channels/mapping.py +0 -0
  33. {valar-1.2.5 → valar-1.3.0}/src/valar/channels/views.py +0 -0
  34. {valar-1.2.5/src/valar/classes/app_mixins → valar-1.3.0/src/valar/classes}/__init__.py +0 -0
  35. {valar-1.2.5/src/valar/dao/defaults → valar-1.3.0/src/valar/classes/app_mixins}/__init__.py +0 -0
  36. {valar-1.2.5 → valar-1.3.0}/src/valar/classes/app_mixins/auto_migration_mixin.py +0 -0
  37. {valar-1.2.5 → valar-1.3.0}/src/valar/classes/app_mixins/auto_urlpatterns_mixin.py +0 -0
  38. {valar-1.2.5 → valar-1.3.0}/src/valar/classes/singleton_meta.py +0 -0
  39. {valar-1.2.5 → valar-1.3.0}/src/valar/classes/valar_minio.py +0 -0
  40. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/__init__.py +0 -0
  41. {valar-1.2.5/src/valar/migrations → valar-1.3.0/src/valar/dao/defaults}/__init__.py +0 -0
  42. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/defaults/field_values_default.py +0 -0
  43. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/defaults/view_defaults.py +0 -0
  44. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/frame.py +0 -0
  45. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/meta.py +0 -0
  46. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/mon_dao.py +0 -0
  47. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/mon_field.py +0 -0
  48. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/orm_dao.py +0 -0
  49. {valar-1.2.5 → valar-1.3.0}/src/valar/dao/query.py +0 -0
  50. {valar-1.2.5/src/valar/views → valar-1.3.0/src/valar/migrations}/__init__.py +0 -0
  51. {valar-1.2.5 → valar-1.3.0}/src/valar/models/core.py +0 -0
  52. {valar-1.2.5 → valar-1.3.0}/src/valar/models/frame.py +0 -0
  53. {valar-1.2.5 → valar-1.3.0}/src/valar/models/meta.py +0 -0
  54. {valar-1.2.5 → valar-1.3.0}/src/valar/models/test.py +0 -0
  55. {valar-1.2.5 → valar-1.3.0}/src/valar/views/file.py +0 -0
  56. {valar-1.2.5 → valar-1.3.0}/src/valar/views/handler.py +0 -0
  57. {valar-1.2.5 → valar-1.3.0}/src/valar/views/meta.py +0 -0
  58. {valar-1.2.5 → valar-1.3.0}/src/valar/views/rest.py +0 -0
  59. {valar-1.2.5 → valar-1.3.0}/src/valar.egg-info/dependency_links.txt +0 -0
  60. {valar-1.2.5 → valar-1.3.0}/src/valar.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: valar
3
- Version: 1.2.5
3
+ Version: 1.3.0
4
4
  Summary: valar for morghulis
5
5
  Home-page: https://gitee.com/GRIFFIN120/valar_dev
6
6
  Author: LYP
@@ -16,6 +16,7 @@ Requires-Dist: pandas==2.2.3
16
16
  Requires-Dist: openpyxl==3.1.5
17
17
  Requires-Dist: deepmerge~=2.0
18
18
  Requires-Dist: minio==7.2.2
19
+ Requires-Dist: PyJWT~=2.10.1
19
20
  Dynamic: author
20
21
  Dynamic: author-email
21
22
  Dynamic: description
@@ -12,11 +12,11 @@ requires = [
12
12
  'openpyxl==3.1.5',
13
13
  'deepmerge~=2.0',
14
14
  'minio==7.2.2',
15
+ 'PyJWT~=2.10.1'
15
16
  ]
16
-
17
17
  setup(
18
18
  name="valar", # 包名
19
- version="1.2.5", # 版本号
19
+ version="1.3.0", # 版本号
20
20
  author="LYP", # 作者
21
21
  author_email="liuyinpeng@buaa.edu.cn", # 邮箱
22
22
  description="valar for morghulis", # 简短描述
@@ -1,4 +1,6 @@
1
1
  import os
2
+ import traceback
3
+
2
4
  from django.apps import AppConfig
3
5
 
4
6
  from .classes.app_mixins.auto_migration_mixin import AutoMigrationMixin
@@ -11,7 +13,11 @@ class ValarConfig(AutoMigrationMixin, AutoUrlPatternsMixin, AppConfig):
11
13
 
12
14
  def ready(self):
13
15
  if os.environ.get('RUN_MAIN') == 'true':
14
- from .dao.frame import MetaFrame
15
- getattr(super(), 'set_url', None)()
16
- getattr(super(), 'auto_migrate', None)()
17
- MetaFrame()
16
+ try:
17
+ from .dao.frame import MetaFrame
18
+ getattr(super(), 'set_url', None)()
19
+ getattr(super(), 'auto_migrate', None)()
20
+ MetaFrame()
21
+ except Exception as e:
22
+ traceback.print_exc()
23
+ print('ERROR', e)
@@ -0,0 +1,32 @@
1
+ import jwt
2
+ from django.conf import settings
3
+
4
+ from src.valar.classes.valar_response import ValarResponse
5
+
6
+
7
+ def auth_required(view_func):
8
+ def wrapper(request, *args, **kwargs):
9
+ payload, response = validate(request)
10
+ if payload:
11
+ request.user_id = payload["user_id"]
12
+ return view_func(request, *args, **kwargs)
13
+ else:
14
+ return response
15
+
16
+ return wrapper
17
+
18
+
19
+ def validate(request):
20
+ auth_header = request.headers.get("Authorization")
21
+ if not auth_header or not auth_header.startswith("Bearer "):
22
+ return None, ValarResponse(False, '请登录系统', 'info', status=401)
23
+ token = auth_header.split(" ")[1]
24
+ if not token:
25
+ return None, ValarResponse(False, status=401)
26
+ try:
27
+ payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
28
+ return payload, ValarResponse(False)
29
+ except jwt.ExpiredSignatureError:
30
+ return None, ValarResponse(False, '状态已过期,请重新登录', 'warning', status=401)
31
+ except jwt.InvalidTokenError:
32
+ return None, ValarResponse(False, '错误状态,请重新登录', 'error', status=401)
@@ -0,0 +1,28 @@
1
+ import base64
2
+ import json
3
+
4
+ from django.http import HttpRequest
5
+ from django.utils.deprecation import MiddlewareMixin
6
+
7
+ from src.valar.auth.Authentication import validate
8
+ from src.valar.classes.valar_response import ValarResponse
9
+
10
+
11
+ class ValarMiddleware(MiddlewareMixin):
12
+ @staticmethod
13
+ def process_response(request: HttpRequest, response: ValarResponse):
14
+ auth = request.headers.get("Auth")
15
+ if auth:
16
+ payload, _ = validate(request)
17
+ if not payload:
18
+ return ValarResponse(False, '无效权限', 'error', status=403)
19
+ if type(response) == ValarResponse:
20
+ valar_message, valar_code = response.valar_message, response.valar_code
21
+ data = {
22
+ 'payload': json.loads(response.content),
23
+ 'message': valar_message,
24
+ 'code': valar_code
25
+ }
26
+ response.content = json.dumps(data, ensure_ascii=False).encode("utf-8")
27
+ response["Content-Type"] = "application/json; charset=utf-8"
28
+ return response
@@ -7,6 +7,7 @@ from channels.layers import get_channel_layer
7
7
  from django.http import HttpRequest
8
8
  import threading
9
9
  from .consumer import VALAR_CHANNEL_GROUP
10
+ from ..auth.Authentication import validate
10
11
 
11
12
 
12
13
  class Channel:
@@ -54,7 +55,9 @@ class ValarChannelSender(Sender):
54
55
  self.__lock__ = threading.Lock()
55
56
  self.__interval__ = interval
56
57
  if self.__channel__.auth and not self.uid:
57
- raise Exception('Unauthorized!')
58
+ payload, _ = validate(request)
59
+ if payload is None:
60
+ raise Exception('Unauthorized!')
58
61
 
59
62
  def _run(self):
60
63
  while self.__loading__:
@@ -0,0 +1,9 @@
1
+ from django.http import JsonResponse
2
+
3
+
4
+ class ValarResponse(JsonResponse):
5
+ def __init__(self, data=True, message='', code='info', status=200):
6
+ self.valar_message = message
7
+ self.valar_code = code
8
+ self.status_code = status
9
+ super(ValarResponse, self).__init__(data, safe=False)
@@ -1,8 +1,10 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
3
  from bson import ObjectId
4
+ from django.db.models import QuerySet
4
5
 
5
6
  from ..dao.engine import ValarEngine
7
+ from ..models.core import VModel
6
8
 
7
9
 
8
10
  class AbstractField(ABC):
@@ -12,6 +14,7 @@ class AbstractField(ABC):
12
14
  label = None
13
15
  domain = None
14
16
  refer = None
17
+ model_field = None
15
18
 
16
19
  @abstractmethod
17
20
  def to_dict(self):
@@ -51,7 +54,7 @@ class AbstractDao(ABC):
51
54
  pass
52
55
 
53
56
  @abstractmethod
54
- def values(self, conditions, props):
57
+ def values(self, conditions, props) -> list:
55
58
  pass
56
59
 
57
60
  @abstractmethod
@@ -59,11 +62,11 @@ class AbstractDao(ABC):
59
62
  pass
60
63
 
61
64
  @abstractmethod
62
- def find_one(self, _id):
65
+ def find_one(self, _id) -> VModel:
63
66
  pass
64
67
 
65
68
  @abstractmethod
66
- def find(self, conditions=None, orders=None, size=0, page=1):
69
+ def find(self, conditions=None, orders=None, size=0, page=1) -> (QuerySet, int):
67
70
  pass
68
71
 
69
72
  @abstractmethod
@@ -39,10 +39,19 @@ meta_field_key_defaults = {
39
39
  ]
40
40
  ),
41
41
  },
42
- 'valar.Valar': {
42
+ 'valar.Vala': {
43
43
  'simple': ('pick', ['id', 'name', 'text_field', 'boolean_field', 'integer_field', 'float_field']),
44
44
  'date': ('pick', ['id', 'name', 'date_field', 'datetime_field', 'time_field']),
45
45
  'special': ('pick', ['id', 'name', 'text_field', 'json_field', 'file', 'm2m']),
46
46
  'ref': ('pick', ['id', 'name', 'm2o', 'm2m', 'o2o_id']),
47
47
  },
48
+ 'valar.Account': {
49
+ 'auth': ('pick', ['user_id', 'username', 'email', 'is_active', 'is_admin', 'roles']),
50
+ },
51
+ 'valar.Role': {
52
+ 'auth': ('pick', ['name', 'duty', 'menu', 'account']),
53
+ },
54
+ 'valar.Menu': {
55
+ 'auth': ('pick', ['icon', 'path', 'name', 'roles', 'is_admin', 'scope']),
56
+ },
48
57
  }
@@ -2,6 +2,8 @@ import pymongo
2
2
  from django.apps import apps
3
3
  from django.conf import settings
4
4
  from urllib.parse import urlparse
5
+
6
+ from django.core.mail import EmailMessage
5
7
  from minio import Minio
6
8
  from pymongo.synchronous.collection import Collection
7
9
 
@@ -55,6 +57,13 @@ class ValarEngine(metaclass=SingletonMeta):
55
57
  else:
56
58
  self.minio_engine = None
57
59
 
60
+ self.from_email = settings.EMAIL_HOST_USER
61
+
62
+ def send_email(self, title, content, email):
63
+ e = EmailMessage(title, content, self.from_email, [email])
64
+ e.content_subtype = 'html'
65
+ e.send()
66
+
58
67
  def get_orm_model(self, entity) -> VModel:
59
68
  return self.orm_engine[entity]
60
69
 
@@ -131,12 +131,10 @@ class OrmField(AbstractField):
131
131
 
132
132
 
133
133
  def column_width(domain, tool):
134
- if domain in ['BooleanField', 'FileField', 'JSONField']:
135
- return 80
136
- elif domain in ['DateField', 'DateTimeField', 'TimeField']:
134
+ if domain in ['BooleanField', 'DateField', 'DateTimeField', 'TimeField']:
137
135
  return 120
138
- elif domain in ['ManyToManyRel', 'ManyToManyRel', 'ManyToOneRel']:
139
- return 80
140
- elif domain in ['TextField']:
136
+ elif domain in ['ManyToManyRel', 'ManyToManyField', 'ManyToOneRel']:
137
+ return 120
138
+ elif domain in ['TextField', 'FileField', 'JSONField']:
141
139
  return 80 if tool == 'rich' else 0
142
140
  return 0
@@ -0,0 +1 @@
1
+ from . import core, frame, meta, auth, test
@@ -0,0 +1,47 @@
1
+ from django.db import models
2
+ from .core import VModel, VTree
3
+ from django.contrib.auth.hashers import check_password
4
+
5
+
6
+ class Role(VModel):
7
+ duty = models.TextField(null=True, verbose_name='职责描述')
8
+
9
+ class Meta:
10
+ verbose_name = '角色'
11
+
12
+
13
+ class Account(VModel):
14
+ """账户核心信息"""
15
+ username = models.CharField(max_length=255, null=True, unique=True, verbose_name='账号')
16
+ password = models.CharField(max_length=255, verbose_name='密码')
17
+ email = models.CharField(max_length=255, null=True, unique=True, verbose_name='邮箱')
18
+ """权限"""
19
+ is_admin = models.BooleanField(default=False, verbose_name='超级管理员')
20
+ roles = models.ManyToManyField(Role)
21
+ """密码找回"""
22
+ is_active = models.BooleanField(default=False, verbose_name='激活状态')
23
+ token = models.CharField(max_length=255, null=True, verbose_name='Token')
24
+
25
+ def is_auth(self, password):
26
+ return password == self.token or check_password(password, self.password)
27
+
28
+ class Meta:
29
+ verbose_name = '账户信息'
30
+
31
+
32
+ class Menu(VTree):
33
+ scope = models.CharField(max_length=100, null=True, verbose_name='域')
34
+ path = models.CharField(max_length=255, null=True, verbose_name='地址')
35
+ roles = models.ManyToManyField(Role)
36
+ is_admin = models.BooleanField(null=True, default=False, verbose_name='超管权限')
37
+
38
+ class Meta:
39
+ verbose_name = '菜单'
40
+ unique_together = ('scope', 'path')
41
+
42
+
43
+ class AbstractUser(VModel):
44
+ account = models.OneToOneField(Account, null=True, on_delete=models.SET_NULL)
45
+
46
+ class Meta:
47
+ abstract = True
@@ -1,7 +1,6 @@
1
- from django.urls import path
2
-
3
1
  from .channels.views import handel_channel
4
- from .views import rest, meta, file
2
+ from .views import rest, meta, file, auth, password
3
+ from django.urls import path
5
4
 
6
5
  urlpatterns = [
7
6
  path('socket/<str:handler>', handel_channel),
@@ -13,7 +12,6 @@ urlpatterns = [
13
12
  path('<str:db>/<str:entity>/update', rest.update),
14
13
  path('<str:db>/<str:entity>/search', rest.search),
15
14
  path('<str:db>/<str:entity>/values', rest.values),
16
- # path('<str:db>/<str:entity>/tree', rest.tree),
17
15
 
18
16
  path('<str:db>/<str:entity>/meta_view', meta.meta_view),
19
17
  path('metas', meta.metas),
@@ -26,4 +24,12 @@ urlpatterns = [
26
24
  path('<str:db>/<str:entity>/save_file', file.save_file),
27
25
  path('<str:db>/<str:entity>/remove_file', file.remove_file),
28
26
 
27
+ path('sign_in', auth.sign_in),
28
+ path("user_profile", auth.user_profile),
29
+ path("free_menus", auth.free_menus),
30
+
31
+ path("change_password", password.change_password),
32
+ path("retrieve_password", password.retrieve_password),
33
+ path("send_password", password.send_password),
34
+
29
35
  ]
File without changes
@@ -0,0 +1,110 @@
1
+ import datetime
2
+ import json
3
+
4
+ import jwt
5
+ from django.conf import settings
6
+ from django.db.models import OneToOneRel
7
+ from django.contrib.auth.hashers import make_password
8
+
9
+ from ..auth.Authentication import auth_required
10
+ from ..classes.valar_response import ValarResponse
11
+ from ..dao import Dao
12
+ from ..models.auth import Account, AbstractUser, Menu
13
+
14
+
15
+ def sign_in(request):
16
+ body = json.loads(request.body)
17
+ username = body.get("username")
18
+ email = body.get("email")
19
+ password = body.get("password")
20
+ signin = body.get("signin")
21
+ dao = Dao('valar.Account')
22
+ account = dao.search({"username": username}).first()
23
+ if account is not None:
24
+ if signin:
25
+ if not account.is_auth(password):
26
+ return ValarResponse(False, '密码错误', 'warning', status=400)
27
+ else:
28
+ return ValarResponse(False, f"{username}已被占用", 'warning', status=400)
29
+ else:
30
+ if signin:
31
+ return ValarResponse(False, f"{username}不存在", 'warning', status=400)
32
+ else:
33
+ if username == 'admin' and password != settings.SECRET_KEY:
34
+ return ValarResponse(False, "请输入正确的admin密码", 'warning', status=400)
35
+ else:
36
+ account = dao.save_one({
37
+ "username": username,
38
+ "email": email,
39
+ "password": make_password(password),
40
+ "is_admin": username == 'admin'
41
+ })
42
+ return ValarResponse(jwt.encode({
43
+ "user_id": account.id,
44
+ "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
45
+ }, settings.SECRET_KEY, algorithm="HS256"))
46
+
47
+
48
+ def free_menus(request):
49
+ body = json.loads(request.body)
50
+ scope = body.get("scope", 'admin')
51
+ menus = Menu.objects.filter(isLeaf=True, scope=scope, is_admin=False, path__isnull=False,
52
+ roles__isnull=True).values('path')
53
+ payload = {
54
+ "permissions": [m['path'] for m in menus]
55
+ }
56
+ token = jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256")
57
+ return ValarResponse(token)
58
+
59
+
60
+ @auth_required
61
+ def user_profile(request):
62
+ body = json.loads(request.body)
63
+ scope = body.get("scope", 'admin')
64
+ account_id = request.user_id
65
+ account = Account.objects.filter(id=account_id).first()
66
+ if account is None:
67
+ return ValarResponse(False, f"账户已不存在", 'warning', status=401)
68
+ user_admin = account.is_admin
69
+ user_roles = list(account.roles.values('id', 'name'))
70
+ user_role_keys = [r['id'] for r in user_roles]
71
+ permissions = []
72
+ for m in Menu.objects.filter(isLeaf=True, scope=scope):
73
+ _id = m.path
74
+ if _id is None:
75
+ continue
76
+ if user_admin:
77
+ permissions.append(_id)
78
+ else:
79
+ if not m.is_admin:
80
+ menu_role_keys = [r['id'] for r in m.roles.all().values('id')]
81
+ if len(menu_role_keys):
82
+ if bool(set(user_role_keys) & set(menu_role_keys)):
83
+ permissions.append(_id)
84
+ else:
85
+ permissions.append(_id)
86
+ payload = {
87
+ "username": account.username,
88
+ "roles": user_roles,
89
+ "is_admin": user_admin,
90
+ "email": account.email,
91
+ "is_active": account.is_active,
92
+ "temporary": account.token is not None,
93
+ "permissions": permissions
94
+ }
95
+ print(permissions)
96
+ field = (
97
+ next((field for field in account.get_meta().get_fields()
98
+ if type(field) == OneToOneRel
99
+ and issubclass(field.related_model, AbstractUser)), None))
100
+ if field:
101
+ accessor = field.get_accessor_name()
102
+ model = field.related_model
103
+ entity = f'{model._meta.app_label}.{model.__name__}'
104
+ payload.update({'user_entity': entity, 'user_accessor': accessor})
105
+ if hasattr(account, accessor):
106
+ user = getattr(account, accessor)
107
+ name = getattr(user, 'name')
108
+ payload.update({'name': name})
109
+ token = jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256")
110
+ return ValarResponse(token)
@@ -0,0 +1,60 @@
1
+ import json
2
+ import secrets
3
+ from django.contrib.auth.hashers import check_password, make_password
4
+
5
+ from ..auth.Authentication import auth_required
6
+ from ..classes.valar_response import ValarResponse
7
+
8
+ from ..dao.engine import ValarEngine
9
+ from ..models.auth import Account, AbstractUser
10
+
11
+
12
+ def send_password(request):
13
+ body = json.loads(request.body)
14
+ account_id = body.get('account_id')
15
+ account = Account.objects.filter(id=account_id).first()
16
+ return __send__(account)
17
+
18
+
19
+ def retrieve_password(request):
20
+ includes = json.loads(request.body)
21
+ account = Account.objects.filter(**includes).first()
22
+ account.token = account.token or secrets.token_hex(16)
23
+ account.save()
24
+ if account:
25
+ return __send__(account)
26
+ else:
27
+ return ValarResponse(False, '该邮箱未在系统中注册', code='error')
28
+
29
+
30
+ @auth_required
31
+ def change_password(request):
32
+ body = json.loads(request.body)
33
+ old_password = body.get('old_password')
34
+ new_password = body.get('new_password')
35
+ account_id = request.user_id
36
+ account = Account.objects.get(id=account_id)
37
+ if not account:
38
+ return ValarResponse(False, '账户不存在', code='error')
39
+ if not account.is_auth(old_password):
40
+ return ValarResponse(False, '当前密码错误', code='error')
41
+ if old_password == new_password:
42
+ return ValarResponse(False, '新密码不能与当前密码一致', code='error')
43
+ account.password = make_password(new_password)
44
+ account.token = None
45
+ account.save()
46
+ return ValarResponse(True)
47
+
48
+
49
+ def __send__(account):
50
+ if not account:
51
+ return ValarResponse(False, '账户不存在', code='error')
52
+ token = account.token
53
+ if not token:
54
+ return ValarResponse(False, '未生成临时密码', code='error')
55
+ email = account.email
56
+ if not email:
57
+ return ValarResponse(False, '该账户未登记邮箱信息', code='error')
58
+ content = f'Your temporary password is {token}, please change it as soon as possible.'
59
+ ValarEngine().send_email('Retrieve Password', content, email)
60
+ return ValarResponse(True, '临时密码发送成功', 'success')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: valar
3
- Version: 1.2.5
3
+ Version: 1.3.0
4
4
  Summary: valar for morghulis
5
5
  Home-page: https://gitee.com/GRIFFIN120/valar_dev
6
6
  Author: LYP
@@ -16,6 +16,7 @@ Requires-Dist: pandas==2.2.3
16
16
  Requires-Dist: openpyxl==3.1.5
17
17
  Requires-Dist: deepmerge~=2.0
18
18
  Requires-Dist: minio==7.2.2
19
+ Requires-Dist: PyJWT~=2.10.1
19
20
  Dynamic: author
20
21
  Dynamic: author-email
21
22
  Dynamic: description
@@ -9,6 +9,9 @@ src/valar.egg-info/SOURCES.txt
9
9
  src/valar.egg-info/dependency_links.txt
10
10
  src/valar.egg-info/requires.txt
11
11
  src/valar.egg-info/top_level.txt
12
+ src/valar/auth/Authentication.py
13
+ src/valar/auth/Middleware.py
14
+ src/valar/auth/__init__.py
12
15
  src/valar/channels/__init__.py
13
16
  src/valar/channels/consumer.py
14
17
  src/valar/channels/counter.py
@@ -39,12 +42,15 @@ src/valar/dao/defaults/field_values_default.py
39
42
  src/valar/dao/defaults/view_defaults.py
40
43
  src/valar/migrations/__init__.py
41
44
  src/valar/models/__init__.py
45
+ src/valar/models/auth.py
42
46
  src/valar/models/core.py
43
47
  src/valar/models/frame.py
44
48
  src/valar/models/meta.py
45
49
  src/valar/models/test.py
46
50
  src/valar/views/__init__.py
51
+ src/valar/views/auth.py
47
52
  src/valar/views/file.py
48
53
  src/valar/views/handler.py
49
54
  src/valar/views/meta.py
55
+ src/valar/views/password.py
50
56
  src/valar/views/rest.py
@@ -6,3 +6,4 @@ pandas==2.2.3
6
6
  openpyxl==3.1.5
7
7
  deepmerge~=2.0
8
8
  minio==7.2.2
9
+ PyJWT~=2.10.1
@@ -1,8 +0,0 @@
1
- from django.http import JsonResponse
2
-
3
-
4
- class ValarResponse(JsonResponse):
5
- def __init__(self, data=True, message='', code='info'):
6
- self.message = message
7
- self.code = code
8
- super(ValarResponse, self).__init__(data, safe=False)
@@ -1 +0,0 @@
1
- from . import core, frame, meta, test
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes