oxutils 0.1.5__py3-none-any.whl → 0.1.12__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 (67) hide show
  1. oxutils/__init__.py +2 -2
  2. oxutils/audit/migrations/0001_initial.py +2 -2
  3. oxutils/audit/models.py +2 -2
  4. oxutils/constants.py +6 -0
  5. oxutils/jwt/auth.py +150 -1
  6. oxutils/jwt/models.py +81 -0
  7. oxutils/jwt/tokens.py +69 -0
  8. oxutils/jwt/utils.py +45 -0
  9. oxutils/logger/__init__.py +10 -0
  10. oxutils/logger/receivers.py +10 -6
  11. oxutils/logger/settings.py +2 -2
  12. oxutils/models/base.py +102 -0
  13. oxutils/models/fields.py +79 -0
  14. oxutils/oxiliere/apps.py +9 -1
  15. oxutils/oxiliere/authorization.py +45 -0
  16. oxutils/oxiliere/caches.py +13 -11
  17. oxutils/oxiliere/checks.py +31 -0
  18. oxutils/oxiliere/constants.py +3 -0
  19. oxutils/oxiliere/context.py +16 -0
  20. oxutils/oxiliere/exceptions.py +16 -0
  21. oxutils/oxiliere/management/commands/grant_tenant_owners.py +19 -0
  22. oxutils/oxiliere/management/commands/init_oxiliere_system.py +30 -11
  23. oxutils/oxiliere/middleware.py +65 -11
  24. oxutils/oxiliere/models.py +146 -9
  25. oxutils/oxiliere/permissions.py +28 -35
  26. oxutils/oxiliere/schemas.py +16 -6
  27. oxutils/oxiliere/signals.py +5 -0
  28. oxutils/oxiliere/utils.py +36 -1
  29. oxutils/pagination/cursor.py +367 -0
  30. oxutils/permissions/__init__.py +0 -0
  31. oxutils/permissions/actions.py +57 -0
  32. oxutils/permissions/admin.py +3 -0
  33. oxutils/permissions/apps.py +10 -0
  34. oxutils/permissions/caches.py +19 -0
  35. oxutils/permissions/checks.py +188 -0
  36. oxutils/permissions/constants.py +0 -0
  37. oxutils/permissions/controllers.py +344 -0
  38. oxutils/permissions/exceptions.py +60 -0
  39. oxutils/permissions/management/__init__.py +0 -0
  40. oxutils/permissions/management/commands/__init__.py +0 -0
  41. oxutils/permissions/management/commands/load_permission_preset.py +112 -0
  42. oxutils/permissions/migrations/0001_initial.py +112 -0
  43. oxutils/permissions/migrations/0002_alter_grant_role.py +19 -0
  44. oxutils/permissions/migrations/0003_alter_grant_options_alter_group_options_and_more.py +33 -0
  45. oxutils/permissions/migrations/__init__.py +0 -0
  46. oxutils/permissions/models.py +171 -0
  47. oxutils/permissions/perms.py +95 -0
  48. oxutils/permissions/queryset.py +92 -0
  49. oxutils/permissions/schemas.py +276 -0
  50. oxutils/permissions/services.py +663 -0
  51. oxutils/permissions/tests.py +3 -0
  52. oxutils/permissions/utils.py +628 -0
  53. oxutils/settings.py +14 -194
  54. oxutils/users/apps.py +1 -1
  55. oxutils/users/migrations/0001_initial.py +47 -0
  56. oxutils/users/migrations/0002_alter_user_first_name_alter_user_last_name.py +23 -0
  57. oxutils/users/models.py +2 -0
  58. oxutils/utils.py +25 -0
  59. {oxutils-0.1.5.dist-info → oxutils-0.1.12.dist-info}/METADATA +21 -11
  60. oxutils-0.1.12.dist-info/RECORD +122 -0
  61. oxutils/jwt/client.py +0 -123
  62. oxutils/jwt/constants.py +0 -1
  63. oxutils/s3/settings.py +0 -34
  64. oxutils/s3/storages.py +0 -130
  65. oxutils-0.1.5.dist-info/RECORD +0 -88
  66. /oxutils/{s3 → pagination}/__init__.py +0 -0
  67. {oxutils-0.1.5.dist-info → oxutils-0.1.12.dist-info}/WHEEL +0 -0
oxutils/jwt/client.py DELETED
@@ -1,123 +0,0 @@
1
- import jwt
2
- import requests
3
- from typing import Dict, Any, Optional
4
- from datetime import datetime, timedelta
5
- from django.core.exceptions import ImproperlyConfigured
6
- from oxutils.settings import oxi_settings
7
- from .constants import JWT_ALGORITHM
8
-
9
-
10
- _jwks_cache: Optional[Dict[str, Any]] = None
11
- _jwks_cache_time: Optional[datetime] = None
12
- _jwks_cache_ttl = timedelta(hours=1)
13
-
14
-
15
- def get_jwks_url() -> str:
16
- """
17
- Get JWKS URL from settings.
18
-
19
- Returns:
20
- The configured JWKS URL.
21
-
22
- Raises:
23
- ImproperlyConfigured: If jwt_jwks_url is not configured.
24
- """
25
- if not oxi_settings.jwt_jwks_url:
26
- raise ImproperlyConfigured(
27
- "JWT JWKS URL is not configured. Set OXI_JWT_JWKS_URL environment variable."
28
- )
29
- return oxi_settings.jwt_jwks_url
30
-
31
-
32
- def fetch_jwks(force_refresh: bool = False) -> Dict[str, Any]:
33
- """
34
- Fetch JWKS from the authentication server with caching.
35
-
36
- Args:
37
- force_refresh: Force refresh the cache even if not expired.
38
-
39
- Returns:
40
- Dict containing the JWKS.
41
-
42
- Raises:
43
- ImproperlyConfigured: If JWKS cannot be fetched.
44
- """
45
- global _jwks_cache, _jwks_cache_time
46
-
47
- now = datetime.now()
48
-
49
- # Return cached JWKS if valid
50
- if not force_refresh and _jwks_cache is not None and _jwks_cache_time is not None:
51
- if now - _jwks_cache_time < _jwks_cache_ttl:
52
- return _jwks_cache
53
-
54
- # Fetch fresh JWKS
55
- jwks_url = get_jwks_url()
56
- try:
57
- response = requests.get(jwks_url, timeout=10)
58
- response.raise_for_status()
59
- _jwks_cache = response.json()
60
- _jwks_cache_time = now
61
- return _jwks_cache
62
- except requests.RequestException as e:
63
- raise ImproperlyConfigured(
64
- f"Failed to fetch JWKS from {jwks_url}: {str(e)}"
65
- )
66
-
67
-
68
- def get_key(kid: str):
69
- """
70
- Get the public key for a given Key ID (kid).
71
-
72
- Args:
73
- kid: The Key ID from the JWT header.
74
-
75
- Returns:
76
- RSA public key for verification.
77
-
78
- Raises:
79
- ValueError: If the kid is not found in JWKS.
80
- """
81
- jwks = fetch_jwks()
82
-
83
- for key in jwks.get("keys", []):
84
- if key.get("kid") == kid:
85
- return jwt.algorithms.RSAAlgorithm.from_jwk(key)
86
-
87
- raise ValueError(f"Unknown Key ID (kid): {kid}")
88
-
89
-
90
- def verify_token(token: str) -> Dict[str, Any]:
91
- """
92
- Verify and decode a JWT token.
93
-
94
- Args:
95
- token: The JWT token string to verify.
96
-
97
- Returns:
98
- Dict containing the decoded token payload.
99
-
100
- Raises:
101
- jwt.InvalidTokenError: If token is invalid or expired.
102
- ValueError: If kid is not found.
103
- """
104
- try:
105
- headers = jwt.get_unverified_header(token)
106
- kid = headers.get("kid")
107
-
108
- if not kid:
109
- raise ValueError("Token header missing 'kid' field")
110
-
111
- key = get_key(kid)
112
- return jwt.decode(token, key=key, algorithms=JWT_ALGORITHM)
113
- except jwt.InvalidTokenError:
114
- raise
115
- except Exception as e:
116
- raise jwt.InvalidTokenError(f"Token verification failed: {str(e)}")
117
-
118
-
119
- def clear_jwks_cache() -> None:
120
- """Clear the cached JWKS. Useful for testing or key rotation."""
121
- global _jwks_cache, _jwks_cache_time
122
- _jwks_cache = None
123
- _jwks_cache_time = None
oxutils/jwt/constants.py DELETED
@@ -1 +0,0 @@
1
- JWT_ALGORITHM = ["RS256"]
oxutils/s3/settings.py DELETED
@@ -1,34 +0,0 @@
1
- import os
2
-
3
- USE_S3 = os.getenv('USE_S3') == 'TRUE'
4
-
5
- if USE_S3:
6
- # aws settings
7
- AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
8
- AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
9
- AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
10
- AWS_DEFAULT_ACL = 'public-read'
11
- AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
12
- AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
13
-
14
- # s3 static settings
15
- STATIC_LOCATION = 'static'
16
- STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{STATIC_LOCATION}/'
17
- STATICFILES_STORAGE = 'oxutils.s3.storages.StaticStorage'
18
-
19
- # s3 public media settings
20
- PUBLIC_MEDIA_LOCATION = 'media'
21
- MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_MEDIA_LOCATION}/'
22
- DEFAULT_FILE_STORAGE = 'oxutils.s3.storages.PublicMediaStorage'
23
-
24
- # s3 private media settings
25
- PRIVATE_MEDIA_LOCATION = 'private'
26
- PRIVATE_FILE_STORAGE = 'oxutils.s3.storages.PrivateMediaStorage'
27
- else:
28
- STATIC_URL = '/static/'
29
- STATIC_ROOT = os.path.join(BASE_DIR, 'static')
30
-
31
- STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
32
-
33
- MEDIA_URL = '/media/'
34
- MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
oxutils/s3/storages.py DELETED
@@ -1,130 +0,0 @@
1
- from storages.backends.s3boto3 import S3Boto3Storage
2
- from oxutils.settings import oxi_settings
3
- from django.core.exceptions import ImproperlyConfigured
4
-
5
-
6
- class StaticStorage(S3Boto3Storage):
7
- def __init__(self, *args, **kwargs):
8
- if not oxi_settings.use_static_s3:
9
- raise ImproperlyConfigured(
10
- "StaticStorage requires OXI_USE_STATIC_S3=True"
11
- )
12
-
13
- self.access_key = oxi_settings.static_access_key_id
14
- self.secret_key = oxi_settings.static_secret_access_key
15
- self.bucket_name = oxi_settings.static_storage_bucket_name
16
- self.custom_domain = oxi_settings.static_s3_custom_domain
17
- self.location = oxi_settings.static_location
18
- self.default_acl = oxi_settings.static_default_acl
19
- self.file_overwrite = False
20
-
21
- self._validate_required_fields('StaticStorage', {
22
- 'access_key': self.access_key,
23
- 'secret_key': self.secret_key,
24
- 'bucket_name': self.bucket_name,
25
- 'custom_domain': self.custom_domain,
26
- })
27
-
28
- super().__init__(*args, **kwargs)
29
-
30
- @staticmethod
31
- def _validate_required_fields(storage_name: str, fields: dict):
32
- """Validate that all required fields are present."""
33
- missing = [name for name, value in fields.items() if not value]
34
- if missing:
35
- raise ImproperlyConfigured(
36
- f"{storage_name} is missing required configuration: {', '.join(missing)}"
37
- )
38
-
39
-
40
- class PublicMediaStorage(S3Boto3Storage):
41
- def __init__(self, *args, **kwargs):
42
- if not oxi_settings.use_default_s3:
43
- raise ImproperlyConfigured(
44
- "PublicMediaStorage requires OXI_USE_DEFAULT_S3=True"
45
- )
46
-
47
- if oxi_settings.use_static_s3_as_default:
48
- self.access_key = oxi_settings.static_access_key_id
49
- self.secret_key = oxi_settings.static_secret_access_key
50
- self.bucket_name = oxi_settings.static_storage_bucket_name
51
- self.custom_domain = oxi_settings.static_s3_custom_domain
52
- else:
53
- self.access_key = oxi_settings.default_s3_access_key_id
54
- self.secret_key = oxi_settings.default_s3_secret_access_key
55
- self.bucket_name = oxi_settings.default_s3_storage_bucket_name
56
- self.custom_domain = oxi_settings.default_s3_custom_domain
57
-
58
- self.location = oxi_settings.default_s3_location
59
- self.default_acl = oxi_settings.default_s3_default_acl
60
- self.file_overwrite = False
61
-
62
- StaticStorage._validate_required_fields('PublicMediaStorage', {
63
- 'access_key': self.access_key,
64
- 'secret_key': self.secret_key,
65
- 'bucket_name': self.bucket_name,
66
- 'custom_domain': self.custom_domain,
67
- })
68
-
69
- super().__init__(*args, **kwargs)
70
-
71
-
72
- class PrivateMediaStorage(S3Boto3Storage):
73
- def __init__(self, *args, **kwargs):
74
- if not oxi_settings.use_private_s3:
75
- raise ImproperlyConfigured(
76
- "PrivateMediaStorage requires OXI_USE_PRIVATE_S3=True"
77
- )
78
-
79
- self.access_key = oxi_settings.private_s3_access_key_id
80
- self.secret_key = oxi_settings.private_s3_secret_access_key
81
- self.bucket_name = oxi_settings.private_s3_storage_bucket_name
82
- self.custom_domain = oxi_settings.private_s3_custom_domain
83
- self.location = oxi_settings.private_s3_location
84
- self.default_acl = oxi_settings.private_s3_default_acl
85
- self.file_overwrite = False
86
- self.querystring_auth = True
87
- self.querystring_expire = 3600
88
-
89
- StaticStorage._validate_required_fields('PrivateMediaStorage', {
90
- 'access_key': self.access_key,
91
- 'secret_key': self.secret_key,
92
- 'bucket_name': self.bucket_name,
93
- 'custom_domain': self.custom_domain,
94
- })
95
-
96
- super().__init__(*args, **kwargs)
97
-
98
-
99
- class LogStorage(S3Boto3Storage):
100
- def __init__(self, *args, **kwargs):
101
- if not oxi_settings.use_log_s3:
102
- raise ImproperlyConfigured(
103
- "LogStorage requires OXI_USE_LOG_S3=True"
104
- )
105
-
106
- if oxi_settings.use_private_s3_as_log:
107
- self.access_key = oxi_settings.private_s3_access_key_id
108
- self.secret_key = oxi_settings.private_s3_secret_access_key
109
- self.bucket_name = oxi_settings.private_s3_storage_bucket_name
110
- self.custom_domain = oxi_settings.private_s3_custom_domain
111
- else:
112
- self.access_key = oxi_settings.log_s3_access_key_id
113
- self.secret_key = oxi_settings.log_s3_secret_access_key
114
- self.bucket_name = oxi_settings.log_s3_storage_bucket_name
115
- self.custom_domain = oxi_settings.log_s3_custom_domain
116
-
117
- self.location = f'{oxi_settings.log_s3_location}/{oxi_settings.service_name}'
118
- self.default_acl = oxi_settings.log_s3_default_acl
119
- self.file_overwrite = False
120
- self.querystring_auth = True
121
- self.querystring_expire = 3600
122
-
123
- StaticStorage._validate_required_fields('LogStorage', {
124
- 'access_key': self.access_key,
125
- 'secret_key': self.secret_key,
126
- 'bucket_name': self.bucket_name,
127
- 'custom_domain': self.custom_domain,
128
- })
129
-
130
- super().__init__(*args, **kwargs)
@@ -1,88 +0,0 @@
1
- oxutils/__init__.py,sha256=5PuAYlbVIInYJZ43P2L9jEzxTTH-zn1XIMdRkSImF90,536
2
- oxutils/apps.py,sha256=8pO8eXUZeKYn8fPo0rkoytmHACwDNuTNhdRcpkPTxGM,347
3
- oxutils/audit/__init__.py,sha256=uonc00G73Xm7RwRHVWD-wBn8lJYNCq3iBgnRGMWAEWs,583
4
- oxutils/audit/apps.py,sha256=xvnmB5Z6nLV7ejzhSeQbesTkwRoFygoPFob8H5QTHgU,304
5
- oxutils/audit/export.py,sha256=MVf2RhLzXatBaGK7bIEvSY1VTwEojrPEKwYMvH1stwE,7992
6
- oxutils/audit/masks.py,sha256=BRCz2m8dbaLgqn5umxpWCwn9mT6Z_ww_WIedl36AmPM,2345
7
- oxutils/audit/migrations/0001_initial.py,sha256=xDOxV6NqkU8yuEDPvqG2AKANKrOJsOIAEJn5IbuLLFU,2151
8
- oxutils/audit/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- oxutils/audit/models.py,sha256=NWzZjwgRGB212PeSb0E_aSxSComrTSR0knt2aBCiWhg,2100
10
- oxutils/audit/settings.py,sha256=NNCFaN6tilDj-0WsVRK9HJNcr2nJOBYJT9E8cY5n9iI,133
11
- oxutils/audit/utils.py,sha256=VJESUbMb5bC155XNlkIvr8DMc_o6ZTAIn5r8NDr7k_E,581
12
- oxutils/celery/__init__.py,sha256=29jo4DfdvOoThX-jfL0ZiDjsy3-Z_fNhwHVJaLO5rsk,29
13
- oxutils/celery/base.py,sha256=qLlBU2XvT2zj8qszy8togqH7hM_wUYyWWA3JAQPPJx0,3378
14
- oxutils/celery/settings.py,sha256=njhHBErpcFczV2e23NCPX_Jxs015jr4dIig4Is_wbgE,33
15
- oxutils/conf.py,sha256=TR0RIVaLMHvG0gm3NgbKsoU25eJFBjItAhknFJdiOiQ,231
16
- oxutils/constants.py,sha256=CW-ho9Vasys-L2ZNJHFMovG5NzHNU6GPldE9vqyVcLM,89
17
- oxutils/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- oxutils/context/site_name_processor.py,sha256=1gc0Td_3HVlUn9ThhQBCQ8kfnRnI88bEflK9vEzTvEc,225
19
- oxutils/currency/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- oxutils/currency/admin.py,sha256=cCd4tXIZTctr3Ksa1jTEpaECw-on7aRHibAfYxEjGek,1831
21
- oxutils/currency/apps.py,sha256=w35QaiH3BIjCYv2IU6AadENAyBOw7Hmejy9kT5e_law,194
22
- oxutils/currency/controllers.py,sha256=xDvPBpgXYjCiWyhRQ09fifbdPRSZAG_HC28_sGRfRYc,3042
23
- oxutils/currency/enums.py,sha256=AHm8zpYCyGv0WMnh8XHLa3cAJnQx3aNOCjGug2Q94VQ,141
24
- oxutils/currency/migrations/0001_initial.py,sha256=GHypakExy4jW5iQ6hB9x2UUjBoPgaz0OaHNTcBU64Pw,1707
25
- oxutils/currency/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- oxutils/currency/models.py,sha256=-NrVq-degRc4sAO2BZ_LqSuIAP-IzCwwZJVxfYlNL8o,2448
27
- oxutils/currency/schemas.py,sha256=4DyEjpL_HaMNDhKyu48fZtcXfRdemVP4rdyHUFit8uI,658
28
- oxutils/currency/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
29
- oxutils/currency/utils.py,sha256=eNa9CNlOFC6NMZLJn8VTwLrkME9q7quMTX7NMSZtTv8,2074
30
- oxutils/enums/__init__.py,sha256=gFhZG8ER6ArGZO5agWhdfs7NiD2h9FzrzfQRHq18dD0,40
31
- oxutils/enums/audit.py,sha256=ju2Z9CrtdyPziRQ7oOe4Ygw85t9sW3jynO_1DkgZoAM,126
32
- oxutils/enums/invoices.py,sha256=E33QGQeutZUqvlovJY0VGDxWUb0i_kdfhEiir1ARKuQ,201
33
- oxutils/exceptions.py,sha256=CCjENOD0of6_noif2ajrpfbBLoG16DWa46iB9_uEe3M,3592
34
- oxutils/functions.py,sha256=4stHj94VebWX0s1XeWshubMD2v8w8QztTWppbkTE_Gg,3246
35
- oxutils/jwt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- oxutils/jwt/auth.py,sha256=rO-xWNfug9Ok6zA7EIPvVkpD8TBUdq05CdrnMrL-t9Q,1597
37
- oxutils/jwt/client.py,sha256=bskLpmSBrehi_snbo3Qbq1m99Kbfg2GP7jqfcXKHvys,3341
38
- oxutils/jwt/constants.py,sha256=MUahZjm8plTYpHjLOMQCuH0H18lkIwS45EtRm617wq8,26
39
- oxutils/locale/fr/LC_MESSAGES/django.po,sha256=APXt_8R99seCWjJyS5ELOawvRLvUqqBT32O252BaG5s,7971
40
- oxutils/logger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- oxutils/logger/receivers.py,sha256=EBpkwMCHYacOJvuOPzUtM_8ttWWetz17kIwoudGiV34,488
42
- oxutils/logger/settings.py,sha256=aiKiJqNNkw1g5vQgjk3Zfh6UgY7jx-lbmcFgATiXrGI,1805
43
- oxutils/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
- oxutils/mixins/base.py,sha256=0cGY4mGKhL-hJTEBsbETYiaKMVuUgio5DISCv5iYtGI,589
45
- oxutils/mixins/schemas.py,sha256=DGW0GQBJc9K7hwOJLX-fEryi7KCoY1QaCLny8fjtQMI,319
46
- oxutils/mixins/services.py,sha256=i4MrkCE3y1W7Xrrz6YeMMaY9xMtCQs4WgBIpM7hrDTI,5399
47
- oxutils/models/__init__.py,sha256=mR9hhncZMGKefovg9xSPBtb9Yu2AssAdta26ihcNvI4,77
48
- oxutils/models/base.py,sha256=1HGHB8MnhPpaa1SpnUVgiknCSHTwajz5LxprB2zicbc,2884
49
- oxutils/models/billing.py,sha256=aCDZcMx4CUyAwh3wgJGypAJl_fSEuWrL27-cSYv3gCs,3323
50
- oxutils/models/invoice.py,sha256=nqphkhlBhssODm2H4dBYyb1cOmHS29fToER40UN0cXo,13216
51
- oxutils/oxiliere/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- oxutils/oxiliere/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
53
- oxutils/oxiliere/apps.py,sha256=DAb8O1Vt4XPTIlFg5NB6SISTYRHyW3TY55-l7TC08Lo,148
54
- oxutils/oxiliere/cacheops.py,sha256=VGG5qG5IsxvWJTu1aTlmsaDXV2aiuIMVdVcvHGHeY3g,163
55
- oxutils/oxiliere/caches.py,sha256=PljqpDxkaE5F8Gsmvdqoq8W0MDh6aDtgXxCrN2T8b-4,976
56
- oxutils/oxiliere/controllers.py,sha256=hL_snutY1EuSO0n06NDbjkz-3A3hkqa3sYGie3Grbmg,847
57
- oxutils/oxiliere/enums.py,sha256=etpHgzsHTQKMrPIxVH-d592_DYSRJ2_o0c8bOdIza-8,201
58
- oxutils/oxiliere/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- oxutils/oxiliere/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
- oxutils/oxiliere/management/commands/init_oxiliere_system.py,sha256=ogNQGARqUUfTv4JgZsRuEh4FInfMUO4nFHHCbgeLLbk,3659
61
- oxutils/oxiliere/middleware.py,sha256=mGOUs0bjtp_TKkZRgcC6kE7euZrZ6mIG1PgKHBhTDCc,4013
62
- oxutils/oxiliere/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
- oxutils/oxiliere/models.py,sha256=IqASvymJ6EcLc9bhxnas7-XXZStQYz7_UqroFkqS8xE,1543
64
- oxutils/oxiliere/permissions.py,sha256=BVSbXqMa9Ohb1joBA_uXRCkYsYc3_CabhAWL9-VS4IU,3227
65
- oxutils/oxiliere/schemas.py,sha256=kjX6N1INx9wikatniEM5s-ECuuVtDCcu6VEBbbEIdZE,1897
66
- oxutils/oxiliere/settings.py,sha256=ZuKppEyrucWxvvYC2-wLap4RzKfaEfaRdjJnsNZzpuY,440
67
- oxutils/oxiliere/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
68
- oxutils/oxiliere/utils.py,sha256=iZc3BjaqVSrZkELVpYsYiwMHC5MfDeDQPKn8iTsB3Bk,2488
69
- oxutils/pdf/__init__.py,sha256=Uu_yOEd-FcNHIB7CV6y76c53wjL5Hce2GMjho8gnkbM,236
70
- oxutils/pdf/printer.py,sha256=VVvpGU5GdSNTOP06wLqgm36ICDfRTRaRjmmiS-vJ0wM,2449
71
- oxutils/pdf/utils.py,sha256=cn1Yc7KnjuATSQKM3hrYptCo0IsQurBdrNHh7Nu08b8,3786
72
- oxutils/pdf/views.py,sha256=DBxCh_UXVywlvlWZh9sVBtYc0gZxMo7ut1j1U_gqPA4,6523
73
- oxutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
- oxutils/s3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- oxutils/s3/settings.py,sha256=NIlVhaOzWdsepOgCpxdTTJRHfM0tM5EcAoy4kaFC1R8,1190
76
- oxutils/s3/storages.py,sha256=gjQg05edVn6NuyfJZ-NwUB2lRWwg8GqgzHB8I1D5vbI,5402
77
- oxutils/settings.py,sha256=mp_ZSf8bcCUe2Zc9YdOe_EtltBgIY2n_8lUERQtsIFk,9742
78
- oxutils/types.py,sha256=DIz8YK8xMpLc7FYbf88yEElyLsYN_-rbvaZXvENQkOQ,234
79
- oxutils/users/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
- oxutils/users/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
81
- oxutils/users/apps.py,sha256=u3PAY2AZGQXSWH2DSkQ1lOTIVm33qUbzeKls0J8H8No,142
82
- oxutils/users/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
- oxutils/users/models.py,sha256=YXAHcXuhmHZfcRDOqA5lBiSRcJ24snBs9X6tcJPCcFs,2960
84
- oxutils/users/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
85
- oxutils/users/utils.py,sha256=jY-zL8vLT5U3E2FV3DqCvrPORjKLutbkPZTQ-z96dCw,376
86
- oxutils-0.1.5.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
87
- oxutils-0.1.5.dist-info/METADATA,sha256=My2FOK0fKzrb7w4hrYmg3HWj1Qyf9Ig-USJNFtqN6Zo,7878
88
- oxutils-0.1.5.dist-info/RECORD,,
File without changes