shaapi 0.1.0__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 (141) hide show
  1. shaapi/__init__.py +3 -0
  2. shaapi/cli.py +97 -0
  3. shaapi/generator.py +114 -0
  4. shaapi/template/.dockerignore +37 -0
  5. shaapi/template/.env.template +59 -0
  6. shaapi/template/.gitattributes +12 -0
  7. shaapi/template/.gitignore +170 -0
  8. shaapi/template/.gitlab-ci.yml +89 -0
  9. shaapi/template/Dockerfile +59 -0
  10. shaapi/template/LICENSE +21 -0
  11. shaapi/template/README.md +206 -0
  12. shaapi/template/backend/.gitignore +164 -0
  13. shaapi/template/backend/__init__.py +0 -0
  14. shaapi/template/backend/alembic/README +1 -0
  15. shaapi/template/backend/alembic/env.py +102 -0
  16. shaapi/template/backend/alembic/script.py.mako +26 -0
  17. shaapi/template/backend/alembic/versions/2026_06_08_1024-64524c63b666_initial.py +143 -0
  18. shaapi/template/backend/alembic.ini +117 -0
  19. shaapi/template/backend/app/__init__.py +55 -0
  20. shaapi/template/backend/app/admin/__init__.py +1 -0
  21. shaapi/template/backend/app/admin/api/v1/__init__.py +0 -0
  22. shaapi/template/backend/app/admin/api/v1/auth.py +59 -0
  23. shaapi/template/backend/app/admin/api/v1/casbin.py +218 -0
  24. shaapi/template/backend/app/admin/api/v1/login_log.py +63 -0
  25. shaapi/template/backend/app/admin/api/v1/opera_log.py +61 -0
  26. shaapi/template/backend/app/admin/api/v1/role.py +108 -0
  27. shaapi/template/backend/app/admin/api/v1/user.py +47 -0
  28. shaapi/template/backend/app/admin/schema/casbin_rule.py +45 -0
  29. shaapi/template/backend/app/admin/schema/login_log.py +36 -0
  30. shaapi/template/backend/app/admin/schema/opera_log.py +43 -0
  31. shaapi/template/backend/app/admin/schema/role.py +36 -0
  32. shaapi/template/backend/app/admin/schema/sso.py +37 -0
  33. shaapi/template/backend/app/admin/schema/token.py +74 -0
  34. shaapi/template/backend/app/admin/schema/user.py +93 -0
  35. shaapi/template/backend/app/admin/service/auth_service.py +233 -0
  36. shaapi/template/backend/app/admin/service/casbin_service.py +135 -0
  37. shaapi/template/backend/app/admin/service/login_log_service.py +62 -0
  38. shaapi/template/backend/app/admin/service/opera_log_service.py +31 -0
  39. shaapi/template/backend/app/admin/service/role_service.py +79 -0
  40. shaapi/template/backend/app/admin/service/secure_token_service.py +60 -0
  41. shaapi/template/backend/app/admin/service/user_service.py +153 -0
  42. shaapi/template/backend/app/api.py +11 -0
  43. shaapi/template/backend/common/__init__.py +0 -0
  44. shaapi/template/backend/common/cloud_storage/__init__.py +11 -0
  45. shaapi/template/backend/common/cloud_storage/cloud_storage.py +180 -0
  46. shaapi/template/backend/common/dataclasses.py +52 -0
  47. shaapi/template/backend/common/email_conf/email.py +105 -0
  48. shaapi/template/backend/common/enums.py +144 -0
  49. shaapi/template/backend/common/exception/__init__.py +0 -0
  50. shaapi/template/backend/common/exception/errors.py +87 -0
  51. shaapi/template/backend/common/exception/exception_handler.py +280 -0
  52. shaapi/template/backend/common/log.py +123 -0
  53. shaapi/template/backend/common/model.py +68 -0
  54. shaapi/template/backend/common/pagination.py +83 -0
  55. shaapi/template/backend/common/response/__init__.py +0 -0
  56. shaapi/template/backend/common/response/response_code.py +158 -0
  57. shaapi/template/backend/common/response/response_schema.py +110 -0
  58. shaapi/template/backend/common/schema.py +144 -0
  59. shaapi/template/backend/common/security/jwt.py +203 -0
  60. shaapi/template/backend/common/security/rbac.py +98 -0
  61. shaapi/template/backend/common/security/sec_token.py +6 -0
  62. shaapi/template/backend/common/socketio/action.py +11 -0
  63. shaapi/template/backend/common/socketio/server.py +50 -0
  64. shaapi/template/backend/common/sso/base.py +69 -0
  65. shaapi/template/backend/common/sso/google.py +127 -0
  66. shaapi/template/backend/core/conf.py +208 -0
  67. shaapi/template/backend/core/path_conf.py +24 -0
  68. shaapi/template/backend/core/registrar.py +195 -0
  69. shaapi/template/backend/crud/__init__.py +1 -0
  70. shaapi/template/backend/crud/crud_base.py +35 -0
  71. shaapi/template/backend/crud/crud_casbin.py +46 -0
  72. shaapi/template/backend/crud/crud_login_log.py +58 -0
  73. shaapi/template/backend/crud/crud_opera_log.py +58 -0
  74. shaapi/template/backend/crud/crud_role.py +128 -0
  75. shaapi/template/backend/crud/crud_user.py +267 -0
  76. shaapi/template/backend/database/__init__.py +0 -0
  77. shaapi/template/backend/database/db_postgres.py +125 -0
  78. shaapi/template/backend/database/db_redis.py +62 -0
  79. shaapi/template/backend/entrypoint-api.sh +19 -0
  80. shaapi/template/backend/lang/en/app.py +18 -0
  81. shaapi/template/backend/lang/en/auth.py +10 -0
  82. shaapi/template/backend/lang/fr/app.py +18 -0
  83. shaapi/template/backend/lang/fr/auth.py +10 -0
  84. shaapi/template/backend/main.py +54 -0
  85. shaapi/template/backend/middleware/__init__.py +1 -0
  86. shaapi/template/backend/middleware/access_middleware.py +19 -0
  87. shaapi/template/backend/middleware/i18n_middleware.py +19 -0
  88. shaapi/template/backend/middleware/jwt_auth_middleware.py +73 -0
  89. shaapi/template/backend/middleware/opera_log_middleware.py +179 -0
  90. shaapi/template/backend/middleware/state_middleware.py +26 -0
  91. shaapi/template/backend/models/__init__.py +10 -0
  92. shaapi/template/backend/models/associations.py +20 -0
  93. shaapi/template/backend/models/casbin_rule.py +30 -0
  94. shaapi/template/backend/models/login_log.py +28 -0
  95. shaapi/template/backend/models/opera_log.py +36 -0
  96. shaapi/template/backend/models/role.py +27 -0
  97. shaapi/template/backend/models/user.py +30 -0
  98. shaapi/template/backend/seeder/json/admin.json +15 -0
  99. shaapi/template/backend/seeder/json/user.json +15 -0
  100. shaapi/template/backend/seeder/run.py +34 -0
  101. shaapi/template/backend/static/ip2region.xdb +0 -0
  102. shaapi/template/backend/templates/build/meet.html +169 -0
  103. shaapi/template/backend/templates/build/new_account.html +373 -0
  104. shaapi/template/backend/templates/build/reset-password.html +170 -0
  105. shaapi/template/backend/templates/build/test_email.html +25 -0
  106. shaapi/template/backend/templates/build/welcome-one-1.html +160 -0
  107. shaapi/template/backend/templates/build/welcome-one.html +178 -0
  108. shaapi/template/backend/templates/build/welcome-two.html +234 -0
  109. shaapi/template/backend/templates/index.html +0 -0
  110. shaapi/template/backend/templates/src/new_account.mjml +15 -0
  111. shaapi/template/backend/templates/src/reset_password.mjml +19 -0
  112. shaapi/template/backend/templates/src/test_email.mjml +11 -0
  113. shaapi/template/backend/templates/ws/ws.html +70 -0
  114. shaapi/template/backend/utils/demo_site.py +18 -0
  115. shaapi/template/backend/utils/encrypt.py +108 -0
  116. shaapi/template/backend/utils/health_check.py +34 -0
  117. shaapi/template/backend/utils/prometheus.py +135 -0
  118. shaapi/template/backend/utils/request_parse.py +110 -0
  119. shaapi/template/backend/utils/serializers.py +75 -0
  120. shaapi/template/backend/utils/timezone.py +51 -0
  121. shaapi/template/backend/utils/trace_id.py +7 -0
  122. shaapi/template/backend/utils/translator.py +28 -0
  123. shaapi/template/devops/scripts/deploy.sh +7 -0
  124. shaapi/template/devops/scripts/setup_env.sh +62 -0
  125. shaapi/template/docker-compose.monitoring.yml +63 -0
  126. shaapi/template/docker-compose.override.yml +12 -0
  127. shaapi/template/docker-compose.yml +90 -0
  128. shaapi/template/docker-run.sh +99 -0
  129. shaapi/template/etc/dashboards/fastapi-observability.json +1044 -0
  130. shaapi/template/etc/dashboards.yaml +10 -0
  131. shaapi/template/etc/grafana/datasource.yml +79 -0
  132. shaapi/template/etc/prometheus/prometheus.yml +52 -0
  133. shaapi/template/package-lock.json +2102 -0
  134. shaapi/template/package.json +16 -0
  135. shaapi/template/pyproject.toml +78 -0
  136. shaapi/template/uv.lock +2866 -0
  137. shaapi-0.1.0.dist-info/METADATA +92 -0
  138. shaapi-0.1.0.dist-info/RECORD +141 -0
  139. shaapi-0.1.0.dist-info/WHEEL +4 -0
  140. shaapi-0.1.0.dist-info/entry_points.txt +2 -0
  141. shaapi-0.1.0.dist-info/licenses/LICENCE +21 -0
@@ -0,0 +1,180 @@
1
+ import io
2
+ import json
3
+ import re
4
+ import uuid
5
+ from abc import ABC
6
+ from abc import abstractmethod
7
+ from typing import Any
8
+
9
+ import boto3
10
+
11
+ # from google.cloud import storage
12
+ from minio import Minio
13
+ from minio.error import S3Error
14
+
15
+ from backend.core.conf import settings
16
+
17
+
18
+
19
+ class CloudStorage(ABC):
20
+ @abstractmethod
21
+ def upload_file(self, file_content: bytes, filename: str) -> Any:
22
+ pass
23
+
24
+ @abstractmethod
25
+ def delete_file(self, identifier: str) -> None:
26
+ pass
27
+
28
+
29
+ # GCS ( Google Cloud Storage)
30
+ # class GoogleCloudStorage(CloudStorage):
31
+ # def __init__(self, bucket_name):
32
+ # self.bucket_name = bucket_name
33
+ # self.client = storage.Client()
34
+
35
+ # def upload_file(self, file_content: bytes, filename: str) -> str:
36
+ # bucket = self.client.get_bucket(self.bucket_name)
37
+ # blob = bucket.blob(filename)
38
+ # blob.upload_from_string(file_content)
39
+ # return blob.public_url
40
+
41
+ # def delete_file(self, filename: str) -> None:
42
+ # blob = self.client.get_bucket(self.bucket_name).blob(filename)
43
+ # blob.delete()
44
+
45
+
46
+ # Amazon S3
47
+ class AmazonS3Storage(CloudStorage):
48
+ def __init__(
49
+ self, bucket_name, aws_access_key_id, aws_secret_access_key, region_name
50
+ ):
51
+ self.bucket_name = bucket_name
52
+ self.s3 = boto3.client(
53
+ "s3",
54
+ aws_access_key_id=aws_access_key_id,
55
+ aws_secret_access_key=aws_secret_access_key,
56
+ region_name=region_name,
57
+ )
58
+
59
+ def upload_file(self, file_content: bytes, filename: str) -> str:
60
+ self.s3.upload_fileobj(file_content, self.bucket_name, filename)
61
+ file_url = f"https://{self.bucket_name}.s3.amazonaws.com/{filename}"
62
+ return file_url
63
+
64
+ def delete_file(self, filename: str) -> None:
65
+ self.s3.delete_object(Bucket=self.bucket_name, Key=filename)
66
+
67
+
68
+ # Cloudinary
69
+ # class CloudinaryStorage(CloudStorage):
70
+ # def __init__(self, cloud_name, api_key, api_secret):
71
+ # cloudinary.config(cloud_name=cloud_name, api_key=api_key, api_secret=api_secret)
72
+
73
+ # def upload_file(self, file_content: bytes, filename: str) -> Any:
74
+ # result = uploader.upload(
75
+ # file_content,
76
+ # folder="test",
77
+ # resource_type="raw",
78
+ # filename=filename,
79
+ # use_filename=True,
80
+ # )
81
+ # return result
82
+
83
+ # def delete_file(self, public_id: str) -> None:
84
+ # uploader.destroy(public_id=public_id, resource_type="raw")
85
+
86
+
87
+ class MinioStorage(CloudStorage):
88
+ def __init__(self, endpoint_url, access_key, secret_key, bucket_name):
89
+ self.endpoint_url = endpoint_url
90
+ self.access_key = access_key
91
+ self.secret_key = secret_key
92
+ self.bucket_name = bucket_name
93
+
94
+ # Initialisation du client MinIO
95
+ self.client = Minio(
96
+ endpoint=self.endpoint_url,
97
+ access_key=self.access_key,
98
+ secret_key=self.secret_key,
99
+ secure=False, # En local, on utilise HTTP (pas HTTPS)
100
+ )
101
+
102
+ # Définition de la politique de bucket pour l'accès public en lecture
103
+ policy = {
104
+ "Version": "2012-10-17",
105
+ "Statement": [
106
+ {
107
+ "Effect": "Allow",
108
+ "Principal": "*",
109
+ "Action": ["s3:GetObject"],
110
+ "Resource": [f"arn:aws:s3:::{bucket_name}/*"],
111
+ }
112
+ ],
113
+ }
114
+
115
+ # Vérification et configuration du bucket
116
+ try:
117
+ if not self.client.bucket_exists(bucket_name):
118
+ # Création du bucket
119
+ self.client.make_bucket(bucket_name)
120
+ print(f"Bucket '{bucket_name}' created successfully.")
121
+
122
+ # Application de la politique d'accès public
123
+ self.client.set_bucket_policy(bucket_name, json.dumps(policy))
124
+ print(f"Public access policy applied to bucket '{bucket_name}'.")
125
+ else:
126
+ print(f"Bucket '{bucket_name}' already exists.")
127
+
128
+ except S3Error as e:
129
+ print(f"Error occurred: {e}")
130
+
131
+ def exists(self, filename: str) -> bool:
132
+ try:
133
+ self.client.stat_object(self.bucket_name, filename)
134
+ return True
135
+ except S3Error:
136
+ return False
137
+
138
+ def generate_filename(self, filename: str) -> str:
139
+
140
+ filename, ext = filename.rsplit(".", 1)
141
+
142
+ # Remplacer tous les caractères non alphanumériques (sauf les tirets bas) par des tirets bas
143
+ refilename = re.sub(r"[^\w\-_()]+", "_", filename)
144
+ finalefilename = f"{refilename}.{ext}"
145
+ while self.exists(finalefilename):
146
+ return self.generate_filename(f"{filename}_{uuid.uuid4()}.{ext}")
147
+ return finalefilename
148
+
149
+ def download_file(self, filename: str) -> bytes:
150
+ obj = self.client.get_object(self.bucket_name, filename)
151
+ return obj.read()
152
+
153
+ def delete_file(self, filename: str) -> None:
154
+ self.client.remove_object(self.bucket_name, filename)
155
+
156
+ def list_files(self) -> list[str]:
157
+ objects = self.client.list_objects(self.bucket_name)
158
+ return [obj.object_name for obj in objects]
159
+
160
+ def create_bucket(self) -> None:
161
+ self.client.make_bucket(self.bucket_name)
162
+
163
+ def delete_bucket(self) -> None:
164
+ self.client.remove_bucket(self.bucket_name)
165
+
166
+ def list_buckets(self) -> list[str]:
167
+ buckets = self.client.list_buckets()
168
+ return [bucket.name for bucket in buckets]
169
+
170
+ def upload_file(self, file_content: bytes, filename: str) -> str:
171
+ gen_filename = self.generate_filename(filename)
172
+ self.client.put_object(
173
+ bucket_name=self.bucket_name,
174
+ object_name=gen_filename,
175
+ data=io.BytesIO(file_content),
176
+ length=-1,
177
+ part_size=100 * 1024 * 1024,
178
+ )
179
+ file_url = f"{settings.MINIO_CLOUD_URL}/{self.bucket_name}/{gen_filename}"
180
+ return {"file_url": file_url, "filename": gen_filename}
@@ -0,0 +1,52 @@
1
+ import dataclasses
2
+
3
+ from datetime import datetime
4
+
5
+ from fastapi import Response
6
+
7
+ from backend.common.enums import StatusType
8
+
9
+
10
+ @dataclasses.dataclass
11
+ class IpInfo:
12
+ ip: str
13
+ country: str | None
14
+ region: str | None
15
+ city: str | None
16
+
17
+
18
+ @dataclasses.dataclass
19
+ class UserAgentInfo:
20
+ user_agent: str
21
+ os: str | None
22
+ browser: str | None
23
+ device: str | None
24
+
25
+
26
+ @dataclasses.dataclass
27
+ class RequestCallNext:
28
+ code: str
29
+ msg: str
30
+ status: StatusType
31
+ err: Exception | None
32
+ response: Response
33
+
34
+
35
+ @dataclasses.dataclass
36
+ class NewToken:
37
+ new_access_token: str
38
+ new_access_token_expire_time: datetime
39
+ new_refresh_token: str
40
+ new_refresh_token_expire_time: datetime
41
+
42
+
43
+ @dataclasses.dataclass
44
+ class AccessToken:
45
+ access_token: str
46
+ access_token_expire_time: datetime
47
+
48
+
49
+ @dataclasses.dataclass
50
+ class RefreshToken:
51
+ refresh_token: str
52
+ refresh_token_expire_time: datetime
@@ -0,0 +1,105 @@
1
+ from datetime import datetime
2
+ from datetime import timedelta
3
+ from typing import Any
4
+ from typing import List
5
+
6
+ from fastapi_mail import ConnectionConfig
7
+ from fastapi_mail import FastMail
8
+ from fastapi_mail import MessageSchema
9
+ from jinja2 import Environment
10
+ from jinja2 import PackageLoader
11
+ from jinja2 import select_autoescape
12
+ from pydantic import EmailStr
13
+
14
+ from backend.core.conf import settings
15
+ # from backend.common.enums import Token_type
16
+ # from app.core.security import generate_secret_token
17
+ # from app.models import User
18
+ # from backend.app.admin.schema.token import Token
19
+
20
+ env = Environment(
21
+ loader=PackageLoader("backend", f"{settings.EMAIL_TEMPLATES_DIR}/"),
22
+ autoescape=select_autoescape(
23
+ enabled_extensions=("html", "xml"), default_for_string=True
24
+ ),
25
+ )
26
+
27
+
28
+ class Email:
29
+ def __init__(self):
30
+ self.conf = ConnectionConfig(
31
+ MAIL_USERNAME=settings.SMTP_USER,
32
+ MAIL_PASSWORD=settings.SMTP_PASSWORD,
33
+ MAIL_FROM=settings.EMAILS_FROM_EMAIL,
34
+ MAIL_FROM_NAME=settings.EMAILS_FROM_NAME,
35
+ MAIL_PORT=settings.SMTP_PORT,
36
+ MAIL_SERVER=settings.SMTP_HOST,
37
+ MAIL_STARTTLS=settings.SMTP_TLS,
38
+ MAIL_SSL_TLS=False,
39
+ USE_CREDENTIALS=True,
40
+ VALIDATE_CERTS=False,
41
+ )
42
+ pass
43
+
44
+ async def send_login_mail(
45
+ self, email: EmailStr, url: str | None = None, name: str | None = None
46
+ ):
47
+ pass
48
+
49
+
50
+ async def send_reset_password_mail(
51
+ self, email: EmailStr, url: str | None = None, name: str | None = None
52
+ ):
53
+ pass
54
+
55
+ async def send_verify_mail(
56
+ self, email: EmailStr, url: str | None = None, name: str | None = None
57
+ ):
58
+ pass
59
+
60
+ async def send_welcome_mail(
61
+ self, email: EmailStr, url: str | None = None, name: str | None = None
62
+ ):
63
+ template = env.get_template("welcome-one.html")
64
+
65
+ subject = "Bienvenue sur Boilerplate"
66
+ html = template.render(
67
+ subject=subject,
68
+ link=url,
69
+ email=email
70
+ )
71
+ message = MessageSchema(
72
+ subject=subject, recipients=[email], body=html, subtype="html"
73
+ )
74
+
75
+ fm = FastMail(self.conf)
76
+ await fm.send_message(message)
77
+
78
+ async def send_forgot_password_mail(
79
+ self, email: EmailStr, url: str | None = None, name: str | None = None
80
+ ):
81
+ template = env.get_template("reset-password.html")
82
+ subject = "Réinitialisation du mot de passe"
83
+ html = template.render(
84
+ subject=subject,
85
+ link=url,
86
+ email=email
87
+ )
88
+ message = MessageSchema(
89
+ subject=subject, recipients=[email], body=html, subtype="html"
90
+ )
91
+
92
+ fm = FastMail(self.conf)
93
+ await fm.send_message(message)
94
+
95
+ async def send_change_password_mail(
96
+ self, email: EmailStr, url: str | None = None, name: str | None = None
97
+ ):
98
+ pass
99
+
100
+ async def send_change_email_mail(
101
+ self, email: EmailStr, url: str | None = None, name: str | None = None
102
+ ):
103
+ pass
104
+
105
+ email_service = Email()
@@ -0,0 +1,144 @@
1
+ from enum import Enum
2
+ from enum import IntEnum as SourceIntEnum
3
+ from typing import Type
4
+
5
+
6
+ class _EnumBase:
7
+ @classmethod
8
+ def get_member_keys(cls: Type[Enum]) -> list[str]:
9
+ return [name for name in cls.__members__.keys()]
10
+
11
+ @classmethod
12
+ def get_member_values(cls: Type[Enum]) -> list:
13
+ return [item.value for item in cls.__members__.values()]
14
+
15
+
16
+ class IntEnum(_EnumBase, SourceIntEnum):
17
+ """Integer Enum"""
18
+
19
+ pass
20
+
21
+
22
+ class StrEnum(_EnumBase, str, Enum):
23
+ """String Enum"""
24
+
25
+ pass
26
+
27
+
28
+
29
+ class LoginLogStatusType(IntEnum):
30
+ """Login Log Status"""
31
+
32
+ fail = 0
33
+ success = 1
34
+
35
+
36
+
37
+ class StatusType(IntEnum):
38
+ """Status Type"""
39
+
40
+ disable = 0
41
+ enable = 1
42
+
43
+
44
+ class MethodType(StrEnum):
45
+ """Request method"""
46
+
47
+ GET = 'GET'
48
+ POST = 'POST'
49
+ PUT = 'PUT'
50
+ DELETE = 'DELETE'
51
+ PATCH = 'PATCH'
52
+ OPTIONS = 'OPTIONS'
53
+
54
+
55
+ class OperaLogCipherType(IntEnum):
56
+ """Operation log encryption type"""
57
+
58
+ aes = 0
59
+ md5 = 1
60
+ itsdangerous = 2
61
+ plan = 3
62
+
63
+ class RoleDataScopeType(IntEnum):
64
+ """Data range"""
65
+
66
+ all = 1
67
+ custom = 2
68
+
69
+
70
+ class User_job_status(Enum):
71
+ OPEN_TO_WORK = "open_to_work" #Disponible pour un emploi ou des opportunités professionnelles.
72
+ EMPLOYED = "employed" #Actuellement employé.
73
+ NOT_LOOKING = "not_looking" #Pas à la recherche d'opportunités pour le moment.
74
+ AVAILABLE_FOR_FREELANCE = "available_for_freelance" #Disponible pour des missions freelance ou des contrats à court terme.
75
+ ON_LEAVE = "on_leave" #En congé ou indisponible pour une période définie.
76
+ LOOKING_FOR_INTERNSHIP = "looking_for_internship" #Recherche activement un stage ou une opportunité d'apprentissage.
77
+ OPEN_TO_COLLABORATION = "open_to_collaboration" #Ouvert à des collaborations ou des projets en partenariat.
78
+ HIRED = "hired" #A trouvé un emploi ou est actuellement employé.
79
+
80
+ class Role(Enum):
81
+ USER = "user"
82
+ ADMIN = "admin"
83
+ MENTOR = "mentor"
84
+ COMPANY = "company"
85
+
86
+ class Appointment_status(Enum):
87
+ WAITING_FOR_PAYMENT = "waiting_for_payment"
88
+ PENDING = "pending"
89
+ CANCELED = "canceled"
90
+ DONE = "done"
91
+
92
+ class Payment_type(Enum):
93
+ PAYIN = "payin"
94
+ PAYOUT = "payout"
95
+
96
+ class Contract_type(Enum):
97
+ CDI = "cdi" # Contrat à Durée Indéterminée (CDI).
98
+ CDD = "cdd" # Contrat à Durée Déterminée (CDD).
99
+
100
+ class Collab_invitation_status_type(Enum):
101
+ WAITING_FOR_RESPONSE = "waiting_for_response"
102
+ ACCEPTED = "accepted"
103
+ REJECTED = "rejected"
104
+ CANCELED = "canceled"
105
+
106
+ class Collab_invitation_type(Enum):
107
+ COLLABORATOR = "collaborator"
108
+ RECRUTMENT = "recrutment"
109
+
110
+ class Program_follow_request_status(Enum):
111
+ PENDING = "pending"
112
+ WAITING_FOR_PAYMENT = "waiting_for_payment"
113
+ PAID = "paid"
114
+ CANCELED = "canceled"
115
+
116
+
117
+ class Week_task_status(Enum):
118
+ IN_REVIEW = "in_review"
119
+ COMPLETED = "completed"
120
+ PENDING = "pending"
121
+ REJECTED = "rejected"
122
+
123
+ class Mentor_request_status(Enum):
124
+ PENDING = "Pending"
125
+ APPROVED = "Approved"
126
+ REJECTED = "Rejected"
127
+
128
+ class Transaction_status(Enum):
129
+ PENDING = "pending"
130
+ SUCCESSFULLY = "successfully"
131
+ CANCELED = "canceled"
132
+
133
+ class Secure_token_type(Enum):
134
+ RESET_PWD = "reset_pwd"
135
+ VERIFY_ACCOUNT = "verif_account"
136
+ UPDATE_EMAIL = "update_email"
137
+
138
+ class Waiting_queue_filter_type(Enum):
139
+ COURSE = "course"
140
+ PROGRAM = "program"
141
+
142
+ class Reason_type(Enum):
143
+ COMPANY = "company"
144
+ USER = "user"
File without changes
@@ -0,0 +1,87 @@
1
+ """
2
+ Classe d'exception globale pour les entreprises
3
+
4
+ Les exceptions liées à l'exécution du code métier peuvent être déclenchées avec raise xxxError, qui met en œuvre des exceptions avec des tâches d'arrière-plan dans la mesure du possible, mais ne s'applique pas aux **CustomResponseStatusCodes**
5
+ Si un **CustomResponseStatusCode** est requis, il peut être renvoyé directement par return response_base.fail(res=CustomResponseCode.xxx)
6
+
7
+ Traduit avec DeepL.com (version gratuite)
8
+ """ # noqa: E501
9
+
10
+ from typing import Any
11
+
12
+ from fastapi import HTTPException
13
+ from starlette.background import BackgroundTask
14
+
15
+ from backend.common.response.response_code import CustomErrorCode, StandardResponseCode
16
+
17
+
18
+ class BaseExceptionMixin(Exception):
19
+ code: int
20
+
21
+ def __init__(self, *, msg: str = None, data: Any = None, background: BackgroundTask | None = None):
22
+ self.msg = msg
23
+ self.data = data
24
+ # The original background task: https://www.starlette.io/background/
25
+ self.background = background
26
+
27
+
28
+ class HTTPError(HTTPException):
29
+ def __init__(self, *, code: int, msg: Any = None, headers: dict[str, Any] | None = None):
30
+ super().__init__(status_code=code, detail=msg, headers=headers)
31
+
32
+
33
+ class CustomError(BaseExceptionMixin):
34
+ def __init__(self, *, error: CustomErrorCode, data: Any = None, background: BackgroundTask | None = None):
35
+ self.code = error.code
36
+ super().__init__(msg=error.msg, data=data, background=background)
37
+
38
+
39
+ class RequestError(BaseExceptionMixin):
40
+ code = StandardResponseCode.HTTP_400
41
+
42
+ def __init__(self, *, msg: str = 'Bad Request', data: Any = None, background: BackgroundTask | None = None):
43
+ super().__init__(msg=msg, data=data, background=background)
44
+
45
+
46
+ class ForbiddenError(BaseExceptionMixin):
47
+ code = StandardResponseCode.HTTP_403
48
+
49
+ def __init__(self, *, msg: str = 'Forbidden', data: Any = None, background: BackgroundTask | None = None):
50
+ super().__init__(msg=msg, data=data, background=background)
51
+
52
+
53
+ class NotFoundError(BaseExceptionMixin):
54
+ code = StandardResponseCode.HTTP_404
55
+
56
+ def __init__(self, *, msg: str = 'Not Found', data: Any = None, background: BackgroundTask | None = None):
57
+ super().__init__(msg=msg, data=data, background=background)
58
+
59
+
60
+ class ServerError(BaseExceptionMixin):
61
+ code = StandardResponseCode.HTTP_500
62
+
63
+ def __init__(
64
+ self, *, msg: str = 'Internal Server Error', data: Any = None, background: BackgroundTask | None = None
65
+ ):
66
+ super().__init__(msg=msg, data=data, background=background)
67
+
68
+
69
+ class GatewayError(BaseExceptionMixin):
70
+ code = StandardResponseCode.HTTP_502
71
+
72
+ def __init__(self, *, msg: str = 'Bad Gateway', data: Any = None, background: BackgroundTask | None = None):
73
+ super().__init__(msg=msg, data=data, background=background)
74
+
75
+
76
+ class AuthorizationError(BaseExceptionMixin):
77
+ code = StandardResponseCode.HTTP_401
78
+
79
+ def __init__(self, *, msg: str = 'Permission Denied', data: Any = None, background: BackgroundTask | None = None):
80
+ super().__init__(msg=msg, data=data, background=background)
81
+
82
+
83
+ class TokenError(HTTPError):
84
+ code = StandardResponseCode.HTTP_401
85
+
86
+ def __init__(self, *, msg: str = 'Not Authenticated', headers: dict[str, Any] | None = None):
87
+ super().__init__(code=self.code, msg=msg, headers=headers or {'WWW-Authenticate': 'Bearer'})