oxutils 0.1.10__tar.gz → 0.1.12__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.
Files changed (127) hide show
  1. {oxutils-0.1.10 → oxutils-0.1.12}/PKG-INFO +2 -11
  2. {oxutils-0.1.10 → oxutils-0.1.12}/README.md +0 -8
  3. {oxutils-0.1.10 → oxutils-0.1.12}/pyproject.toml +2 -3
  4. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/__init__.py +1 -2
  5. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/migrations/0001_initial.py +2 -2
  6. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/models.py +2 -2
  7. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/jwt/auth.py +1 -1
  8. oxutils-0.1.12/src/oxutils/logger/__init__.py +10 -0
  9. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/caches.py +2 -4
  10. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/context.py +2 -4
  11. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/management/commands/init_oxiliere_system.py +12 -5
  12. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/utils.py +3 -7
  13. oxutils-0.1.12/src/oxutils/settings.py +76 -0
  14. oxutils-0.1.10/src/oxutils/s3/settings.py +0 -34
  15. oxutils-0.1.10/src/oxutils/s3/storages.py +0 -130
  16. oxutils-0.1.10/src/oxutils/settings.py +0 -264
  17. oxutils-0.1.10/src/oxutils/users/__init__.py +0 -0
  18. oxutils-0.1.10/src/oxutils/users/migrations/__init__.py +0 -0
  19. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/apps.py +0 -0
  20. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/__init__.py +0 -0
  21. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/apps.py +0 -0
  22. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/export.py +0 -0
  23. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/masks.py +0 -0
  24. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/migrations/__init__.py +0 -0
  25. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/settings.py +0 -0
  26. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/audit/utils.py +0 -0
  27. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/celery/__init__.py +0 -0
  28. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/celery/base.py +0 -0
  29. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/celery/settings.py +0 -0
  30. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/conf.py +0 -0
  31. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/constants.py +0 -0
  32. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/context/__init__.py +0 -0
  33. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/context/site_name_processor.py +0 -0
  34. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/__init__.py +0 -0
  35. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/admin.py +0 -0
  36. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/apps.py +0 -0
  37. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/controllers.py +0 -0
  38. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/enums.py +0 -0
  39. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/migrations/0001_initial.py +0 -0
  40. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/migrations/__init__.py +0 -0
  41. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/models.py +0 -0
  42. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/schemas.py +0 -0
  43. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/tests.py +0 -0
  44. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/currency/utils.py +0 -0
  45. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/enums/__init__.py +0 -0
  46. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/enums/audit.py +0 -0
  47. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/enums/invoices.py +0 -0
  48. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/exceptions.py +0 -0
  49. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/functions.py +0 -0
  50. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/jwt/__init__.py +0 -0
  51. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/jwt/models.py +0 -0
  52. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/jwt/tokens.py +0 -0
  53. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/jwt/utils.py +0 -0
  54. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/locale/fr/LC_MESSAGES/django.po +0 -0
  55. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/logger/receivers.py +0 -0
  56. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/logger/settings.py +0 -0
  57. {oxutils-0.1.10/src/oxutils/logger → oxutils-0.1.12/src/oxutils/mixins}/__init__.py +0 -0
  58. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/mixins/base.py +0 -0
  59. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/mixins/schemas.py +0 -0
  60. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/mixins/services.py +0 -0
  61. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/models/__init__.py +0 -0
  62. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/models/base.py +0 -0
  63. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/models/billing.py +0 -0
  64. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/models/fields.py +0 -0
  65. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/models/invoice.py +0 -0
  66. {oxutils-0.1.10/src/oxutils/mixins → oxutils-0.1.12/src/oxutils/oxiliere}/__init__.py +0 -0
  67. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/admin.py +0 -0
  68. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/apps.py +0 -0
  69. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/authorization.py +0 -0
  70. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/cacheops.py +0 -0
  71. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/checks.py +0 -0
  72. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/constants.py +0 -0
  73. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/controllers.py +0 -0
  74. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/enums.py +0 -0
  75. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/exceptions.py +0 -0
  76. {oxutils-0.1.10/src/oxutils/oxiliere → oxutils-0.1.12/src/oxutils/oxiliere/management}/__init__.py +0 -0
  77. {oxutils-0.1.10/src/oxutils/oxiliere/management → oxutils-0.1.12/src/oxutils/oxiliere/management/commands}/__init__.py +0 -0
  78. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/management/commands/grant_tenant_owners.py +0 -0
  79. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/middleware.py +0 -0
  80. {oxutils-0.1.10/src/oxutils/oxiliere/management/commands → oxutils-0.1.12/src/oxutils/oxiliere/migrations}/__init__.py +0 -0
  81. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/models.py +0 -0
  82. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/permissions.py +0 -0
  83. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/schemas.py +0 -0
  84. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/settings.py +0 -0
  85. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/signals.py +0 -0
  86. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/oxiliere/tests.py +0 -0
  87. {oxutils-0.1.10/src/oxutils/oxiliere/migrations → oxutils-0.1.12/src/oxutils/pagination}/__init__.py +0 -0
  88. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/pagination/cursor.py +0 -0
  89. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/pdf/__init__.py +0 -0
  90. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/pdf/printer.py +0 -0
  91. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/pdf/utils.py +0 -0
  92. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/pdf/views.py +0 -0
  93. {oxutils-0.1.10/src/oxutils/pagination → oxutils-0.1.12/src/oxutils/permissions}/__init__.py +0 -0
  94. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/actions.py +0 -0
  95. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/admin.py +0 -0
  96. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/apps.py +0 -0
  97. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/caches.py +0 -0
  98. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/checks.py +0 -0
  99. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/constants.py +0 -0
  100. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/controllers.py +0 -0
  101. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/exceptions.py +0 -0
  102. {oxutils-0.1.10/src/oxutils/permissions → oxutils-0.1.12/src/oxutils/permissions/management}/__init__.py +0 -0
  103. {oxutils-0.1.10/src/oxutils/permissions/management → oxutils-0.1.12/src/oxutils/permissions/management/commands}/__init__.py +0 -0
  104. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/management/commands/load_permission_preset.py +0 -0
  105. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/migrations/0001_initial.py +0 -0
  106. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/migrations/0002_alter_grant_role.py +0 -0
  107. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/migrations/0003_alter_grant_options_alter_group_options_and_more.py +0 -0
  108. {oxutils-0.1.10/src/oxutils/permissions/management/commands → oxutils-0.1.12/src/oxutils/permissions/migrations}/__init__.py +0 -0
  109. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/models.py +0 -0
  110. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/perms.py +0 -0
  111. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/queryset.py +0 -0
  112. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/schemas.py +0 -0
  113. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/services.py +0 -0
  114. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/tests.py +0 -0
  115. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/permissions/utils.py +0 -0
  116. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/py.typed +0 -0
  117. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/types.py +0 -0
  118. {oxutils-0.1.10/src/oxutils/permissions/migrations → oxutils-0.1.12/src/oxutils/users}/__init__.py +0 -0
  119. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/users/admin.py +0 -0
  120. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/users/apps.py +0 -0
  121. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/users/migrations/0001_initial.py +0 -0
  122. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/users/migrations/0002_alter_user_first_name_alter_user_last_name.py +0 -0
  123. {oxutils-0.1.10/src/oxutils/s3 → oxutils-0.1.12/src/oxutils/users/migrations}/__init__.py +0 -0
  124. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/users/models.py +0 -0
  125. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/users/tests.py +0 -0
  126. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/users/utils.py +0 -0
  127. {oxutils-0.1.10 → oxutils-0.1.12}/src/oxutils/utils.py +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oxutils
3
- Version: 0.1.10
3
+ Version: 0.1.12
4
4
  Summary: Production-ready utilities for Django applications in the Oxiliere ecosystem
5
- Keywords: django,utilities,jwt,s3,audit,logging,celery,structlog
5
+ Keywords: django,utilities,jwt,audit,logging,celery,structlog
6
6
  Author: Edimedia Mutoke
7
7
  Author-email: Edimedia Mutoke <eddycondor07@gmail.com>
8
8
  License-Expression: Apache-2.0
@@ -24,7 +24,6 @@ Requires-Dist: django-celery-results>=2.6.0
24
24
  Requires-Dist: django-extensions>=4.1
25
25
  Requires-Dist: django-ninja>=1.5.0
26
26
  Requires-Dist: django-ninja-extra>=0.30.6
27
- Requires-Dist: django-storages[s3]>=1.14.6
28
27
  Requires-Dist: django-structlog[celery]>=10.0.0
29
28
  Requires-Dist: jwcrypto>=1.5.6
30
29
  Requires-Dist: pydantic-settings>=2.12.0
@@ -71,7 +70,6 @@ Description-Content-Type: text/markdown
71
70
  ## Features
72
71
 
73
72
  - 🔐 **JWT Authentication** - RS256 with JWKS caching
74
- - 📦 **S3 Storage** - Static, media, private, and log backends
75
73
  - 📝 **Structured Logging** - JSON logs with automatic request tracking
76
74
  - 🔍 **Audit System** - Change tracking with S3 export
77
75
  - ⚙️ **Celery Integration** - Pre-configured task processing
@@ -118,8 +116,6 @@ MIDDLEWARE = [
118
116
  ```bash
119
117
  OXI_SERVICE_NAME=my-service
120
118
  OXI_JWT_JWKS_URL=https://auth.example.com/.well-known/jwks.json
121
- OXI_USE_STATIC_S3=True
122
- OXI_STATIC_STORAGE_BUCKET_NAME=my-bucket
123
119
  ```
124
120
 
125
121
  ### 3. Usage Examples
@@ -134,10 +130,6 @@ import structlog
134
130
  logger = structlog.get_logger(__name__)
135
131
  logger.info("user_action", user_id=user_id)
136
132
 
137
- # S3 Storage
138
- from oxutils.s3.storages import PrivateMediaStorage
139
- class Document(models.Model):
140
- file = models.FileField(storage=PrivateMediaStorage())
141
133
 
142
134
  # Model Mixins
143
135
  from oxutils.models.base import BaseModelMixin
@@ -165,7 +157,6 @@ TEMPLATES = [{
165
157
  ### Core Modules
166
158
  - **[Settings](docs/settings.md)** - Configuration reference
167
159
  - **[JWT](docs/jwt.md)** - Authentication
168
- - **[S3](docs/s3.md)** - Storage backends
169
160
  - **[Audit](docs/audit.md)** - Change tracking
170
161
  - **[Logging](docs/logger.md)** - Structured logs
171
162
  - **[Mixins](docs/mixins.md)** - Model/service mixins
@@ -12,7 +12,6 @@
12
12
  ## Features
13
13
 
14
14
  - 🔐 **JWT Authentication** - RS256 with JWKS caching
15
- - 📦 **S3 Storage** - Static, media, private, and log backends
16
15
  - 📝 **Structured Logging** - JSON logs with automatic request tracking
17
16
  - 🔍 **Audit System** - Change tracking with S3 export
18
17
  - ⚙️ **Celery Integration** - Pre-configured task processing
@@ -59,8 +58,6 @@ MIDDLEWARE = [
59
58
  ```bash
60
59
  OXI_SERVICE_NAME=my-service
61
60
  OXI_JWT_JWKS_URL=https://auth.example.com/.well-known/jwks.json
62
- OXI_USE_STATIC_S3=True
63
- OXI_STATIC_STORAGE_BUCKET_NAME=my-bucket
64
61
  ```
65
62
 
66
63
  ### 3. Usage Examples
@@ -75,10 +72,6 @@ import structlog
75
72
  logger = structlog.get_logger(__name__)
76
73
  logger.info("user_action", user_id=user_id)
77
74
 
78
- # S3 Storage
79
- from oxutils.s3.storages import PrivateMediaStorage
80
- class Document(models.Model):
81
- file = models.FileField(storage=PrivateMediaStorage())
82
75
 
83
76
  # Model Mixins
84
77
  from oxutils.models.base import BaseModelMixin
@@ -106,7 +99,6 @@ TEMPLATES = [{
106
99
  ### Core Modules
107
100
  - **[Settings](docs/settings.md)** - Configuration reference
108
101
  - **[JWT](docs/jwt.md)** - Authentication
109
- - **[S3](docs/s3.md)** - Storage backends
110
102
  - **[Audit](docs/audit.md)** - Change tracking
111
103
  - **[Logging](docs/logger.md)** - Structured logs
112
104
  - **[Mixins](docs/mixins.md)** - Model/service mixins
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "oxutils"
3
- version = "0.1.10"
3
+ version = "0.1.12"
4
4
  description = "Production-ready utilities for Django applications in the Oxiliere ecosystem"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -8,7 +8,7 @@ authors = [
8
8
  { name = "Edimedia Mutoke", email = "eddycondor07@gmail.com" }
9
9
  ]
10
10
  requires-python = ">=3.12"
11
- keywords = ["django", "utilities", "jwt", "s3", "audit", "logging", "celery", "structlog"]
11
+ keywords = ["django", "utilities", "jwt", "audit", "logging", "celery", "structlog"]
12
12
  classifiers = [
13
13
  "Development Status :: 4 - Beta",
14
14
  "Framework :: Django",
@@ -30,7 +30,6 @@ dependencies = [
30
30
  "django-extensions>=4.1",
31
31
  "django-ninja>=1.5.0",
32
32
  "django-ninja-extra>=0.30.6",
33
- "django-storages[s3]>=1.14.6",
34
33
  "django-structlog[celery]>=10.0.0",
35
34
  "jwcrypto>=1.5.6",
36
35
  "pydantic-settings>=2.12.0",
@@ -2,7 +2,6 @@
2
2
 
3
3
  This package provides:
4
4
  - JWT authentication with JWKS support
5
- - S3 storage backends (static, media, private, logs)
6
5
  - Structured logging with correlation IDs
7
6
  - Audit system with S3 export
8
7
  - Celery integration
@@ -11,7 +10,7 @@ This package provides:
11
10
  - Permission management
12
11
  """
13
12
 
14
- __version__ = "0.1.10"
13
+ __version__ = "0.1.12"
15
14
 
16
15
  from oxutils.settings import oxi_settings
17
16
  from oxutils.conf import UTILS_APPS, AUDIT_MIDDLEWARE
@@ -2,7 +2,7 @@
2
2
 
3
3
  import django.db.models.deletion
4
4
  import oxutils.enums.audit
5
- import oxutils.s3.storages
5
+ from oxutils.logger import get_log_storage
6
6
  from django.db import migrations, models
7
7
 
8
8
 
@@ -22,7 +22,7 @@ class Migration(migrations.Migration):
22
22
  ('updated_at', models.DateTimeField(auto_now=True, help_text='Date and time when this record was last updated')),
23
23
  ('last_export_date', models.DateTimeField(null=True)),
24
24
  ('status', models.CharField(choices=[(oxutils.enums.audit.ExportStatus['FAILED'], 'Failed'), (oxutils.enums.audit.ExportStatus['PENDING'], 'Pending'), (oxutils.enums.audit.ExportStatus['SUCCESS'], 'Success')], default=oxutils.enums.audit.ExportStatus['PENDING'])),
25
- ('data', models.FileField(storage=oxutils.s3.storages.LogStorage(), upload_to='')),
25
+ ('data', models.FileField(storage=get_log_storage, upload_to='')),
26
26
  ('size', models.BigIntegerField()),
27
27
  ],
28
28
  options={
@@ -3,7 +3,7 @@ from django.utils import timezone
3
3
  from django.db import models, transaction
4
4
  from oxutils.enums.audit import ExportStatus
5
5
  from oxutils.models.base import TimestampMixin
6
- from oxutils.s3.storages import LogStorage
6
+ from oxutils.logger import get_log_storage
7
7
 
8
8
 
9
9
 
@@ -38,7 +38,7 @@ class LogExportState(TimestampMixin):
38
38
  (ExportStatus.SUCCESS, _('Success'))
39
39
  )
40
40
  )
41
- data = models.FileField(storage=LogStorage())
41
+ data = models.FileField(storage=get_log_storage)
42
42
  size = models.BigIntegerField()
43
43
 
44
44
  @classmethod
@@ -1,5 +1,5 @@
1
1
  import os
2
- from typing import Dict, Any, Optional, Type, Tuple
2
+ from typing import Dict, Any, Optional, Type, Tuple, List
3
3
  from django.utils.translation import gettext_lazy as _
4
4
  from django.http import HttpRequest
5
5
  from django.contrib.auth.models import AbstractUser
@@ -0,0 +1,10 @@
1
+ from django.core.files.storage import storages, default_storage
2
+
3
+
4
+ def get_log_storage():
5
+ try:
6
+ return storages['logs']
7
+ except:
8
+ pass
9
+
10
+ return default_storage
@@ -1,9 +1,8 @@
1
- from django.conf import settings
2
1
  from cacheops import cached_as, cached
3
2
  from oxutils.oxiliere.utils import (
4
3
  get_tenant_model,
5
4
  get_tenant_user_model,
6
- get_system_tenant_schema_name
5
+ get_system_tenant_oxi_id
7
6
  )
8
7
 
9
8
 
@@ -33,5 +32,4 @@ def get_tenant_user(oxi_org_id: str, oxi_user_id: str):
33
32
 
34
33
  @cached(timeout=60*15)
35
34
  def get_system_tenant():
36
- schema_name = get_system_tenant_schema_name()
37
- return get_tenant_model().objects.get(schema_name=schema_name)
35
+ return get_tenant_model().objects.get(oxi_id=get_system_tenant_oxi_id())
@@ -1,10 +1,10 @@
1
1
  import contextvars
2
- from oxutils.oxiliere.utils import get_system_tenant_schema_name
2
+ from oxutils.oxiliere.utils import get_system_tenant_oxi_id
3
3
 
4
4
 
5
5
  current_tenant_schema_name: contextvars.ContextVar[str] = contextvars.ContextVar(
6
6
  "current_tenant_schema_name",
7
- default=get_system_tenant_schema_name()
7
+ default=f"[oxi_id] {get_system_tenant_oxi_id()}"
8
8
  )
9
9
 
10
10
 
@@ -14,5 +14,3 @@ def get_current_tenant_schema_name() -> str:
14
14
 
15
15
  def set_current_tenant_schema_name(schema_name: str):
16
16
  current_tenant_schema_name.set(schema_name)
17
-
18
-
@@ -1,11 +1,11 @@
1
1
  import uuid
2
2
  from django.core.management.base import BaseCommand
3
3
  from django.conf import settings
4
- from django.db import transaction
4
+ from django.db import transaction, connection
5
5
  from django.contrib.auth import get_user_model
6
6
  from django_tenants.utils import (
7
7
  get_tenant_model,
8
- get_tenant_domain_model
8
+ get_tenant_domain_model,
9
9
  )
10
10
  from oxutils.oxiliere.utils import (
11
11
  oxid_to_schema_name,
@@ -16,7 +16,7 @@ from oxutils.oxiliere.constants import (
16
16
  OXI_SYSTEM_DOMAIN,
17
17
  OXI_SYSTEM_OWNER_EMAIL
18
18
  )
19
-
19
+ from oxutils.oxiliere.authorization import grant_manager_access_to_owners
20
20
 
21
21
 
22
22
 
@@ -38,8 +38,8 @@ class Command(BaseCommand):
38
38
  self.stdout.write(self.style.WARNING(f'Initialisation du tenant système...'))
39
39
 
40
40
  # Vérifier si le tenant système existe déjà
41
- if TenantModel.objects.filter(schema_name=schema_name).exists():
42
- self.stdout.write(self.style.ERROR(f'Le tenant système "{schema_name}" existe déjà!'))
41
+ if TenantModel.objects.filter(oxi_id=system_slug).exists():
42
+ self.stdout.write(self.style.ERROR(f'Le tenant système "{system_slug}" existe déjà!'))
43
43
  return
44
44
 
45
45
  # Créer le tenant système
@@ -62,6 +62,8 @@ class Command(BaseCommand):
62
62
  is_primary=True
63
63
  )
64
64
  self.stdout.write(self.style.SUCCESS(f'✓ Domaine créé: {domain.domain}'))
65
+
66
+ connection.set_tenant(tenant)
65
67
 
66
68
  self.stdout.write(f'Création du superuser: {owner_email}')
67
69
  try:
@@ -88,6 +90,11 @@ class Command(BaseCommand):
88
90
  )
89
91
  if created:
90
92
  self.stdout.write(self.style.SUCCESS(f'✓ Superuser lié au tenant système'))
93
+ try:
94
+ grant_manager_access_to_owners(tenant)
95
+ self.stdout.write(self.style.SUCCESS(f'✓ Droits mis en place'))
96
+ except Exception as e:
97
+ self.stdout.write(self.style.ERROR(f'Erreur lors de la mise en place des droits: {str(e)}'))
91
98
  else:
92
99
  self.stdout.write(self.style.WARNING(f'⚠ Liaison existe déjà'))
93
100
 
@@ -23,14 +23,10 @@ def get_tenant_user_model() -> Any:
23
23
  return get_model('TENANT_USER_MODEL')
24
24
 
25
25
  def is_system_tenant(tenant: Any) -> bool:
26
- return tenant.schema_name == get_system_tenant_schema_name()
26
+ return tenant.oxi_id == get_system_tenant_oxi_id()
27
27
 
28
- def get_system_tenant_schema_name():
29
- system_schema_name = oxid_to_schema_name(
30
- getattr(settings, 'OXI_SYSTEM_TENANT', OXI_SYSTEM_TENANT)
31
- )
32
-
33
- return system_schema_name
28
+ def get_system_tenant_oxi_id():
29
+ return getattr(settings, 'OXI_SYSTEM_TENANT', OXI_SYSTEM_TENANT)
34
30
 
35
31
  def oxid_to_schema_name(oxid: str) -> str:
36
32
  """
@@ -0,0 +1,76 @@
1
+ from typing import Optional
2
+ from pydantic import Field
3
+ from pydantic_settings import BaseSettings, SettingsConfigDict
4
+
5
+
6
+
7
+
8
+ __all__ = [
9
+ 'oxi_settings',
10
+ ]
11
+
12
+
13
+
14
+ class OxUtilsSettings(BaseSettings):
15
+ model_config = SettingsConfigDict(
16
+ validate_assignment=True,
17
+ extra="ignore",
18
+ env_prefix='OXI_'
19
+ )
20
+
21
+ # Service
22
+ service_name: Optional[str] = 'Oxutils'
23
+ site_name: Optional[str] = 'Oxiliere'
24
+ site_domain: Optional[str] = 'oxiliere.com'
25
+ multitenancy: bool = Field(False)
26
+
27
+ # Auth JWT Settings (JWT_SIGNING_KEY)
28
+ jwt_signing_key: Optional[str] = None
29
+ jwt_verifying_key: Optional[str] = None
30
+ jwt_jwks_url: Optional[str] = None
31
+ jwt_access_token_key: str = Field('access')
32
+ jwt_org_access_token_key: str = Field('org_access')
33
+ jwt_service_token_key: str = Field('service')
34
+ jwt_algorithm: Optional[str] = Field('RS256')
35
+ jwt_access_token_lifetime: int = Field(15) # minutes
36
+ jwt_service_token_lifetime: int = Field(3) # minutes
37
+ jwt_org_access_token_lifetime: int = Field(60) # minutes
38
+
39
+
40
+ # AuditLog
41
+ log_access: bool = Field(False)
42
+ retention_delay: int = Field(7) # one week
43
+
44
+ # logger
45
+ log_file_path: Optional[str] = Field('logs/oxiliere.log')
46
+
47
+ def model_post_init(self, __context):
48
+ """Called after model initialization to perform validation."""
49
+ self._validate_jwt_keys()
50
+
51
+ def _validate_jwt_keys(self):
52
+ """Validate JWT key files if configured."""
53
+ import os
54
+
55
+ if self.jwt_signing_key:
56
+ if not os.path.exists(self.jwt_signing_key):
57
+ raise ValueError(
58
+ f"JWT signing key file not found at: {self.jwt_signing_key}"
59
+ )
60
+ if not os.path.isfile(self.jwt_signing_key):
61
+ raise ValueError(
62
+ f"JWT signing key path is not a file: {self.jwt_signing_key}"
63
+ )
64
+
65
+ if self.jwt_verifying_key:
66
+ if not os.path.exists(self.jwt_verifying_key):
67
+ raise ValueError(
68
+ f"JWT verifying key file not found at: {self.jwt_verifying_key}"
69
+ )
70
+ if not os.path.isfile(self.jwt_verifying_key):
71
+ raise ValueError(
72
+ f"JWT verifying key path is not a file: {self.jwt_verifying_key}"
73
+ )
74
+
75
+
76
+ oxi_settings = OxUtilsSettings()
@@ -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')
@@ -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,264 +0,0 @@
1
- from typing import Optional
2
- from pydantic import Field, model_validator
3
- from pydantic_settings import BaseSettings, SettingsConfigDict
4
- from django.core.exceptions import ImproperlyConfigured
5
-
6
-
7
-
8
-
9
- __all__ = [
10
- 'oxi_settings',
11
- ]
12
-
13
-
14
-
15
- class OxUtilsSettings(BaseSettings):
16
- model_config = SettingsConfigDict(
17
- validate_assignment=True,
18
- extra="ignore",
19
- env_prefix='OXI_'
20
- )
21
-
22
- # Service
23
- service_name: Optional[str] = 'Oxutils'
24
- site_name: Optional[str] = 'Oxiliere'
25
- site_domain: Optional[str] = 'oxiliere.com'
26
- multitenancy: bool = Field(False)
27
-
28
- # Auth JWT Settings (JWT_SIGNING_KEY)
29
- jwt_signing_key: Optional[str] = None
30
- jwt_verifying_key: Optional[str] = None
31
- jwt_jwks_url: Optional[str] = None
32
- jwt_access_token_key: str = Field('access')
33
- jwt_org_access_token_key: str = Field('org_access')
34
- jwt_service_token_key: str = Field('service')
35
- jwt_algorithm: Optional[str] = Field('RS256')
36
- jwt_access_token_lifetime: int = Field(15) # minutes
37
- jwt_service_token_lifetime: int = Field(3) # minutes
38
- jwt_org_access_token_lifetime: int = Field(60) # minutes
39
-
40
-
41
- # AuditLog
42
- log_access: bool = Field(False)
43
- retention_delay: int = Field(7) # one week
44
-
45
- # logger
46
- log_file_path: Optional[str] = Field('logs/oxiliere.log')
47
-
48
- # Static S3
49
- use_static_s3: bool = Field(False)
50
- static_access_key_id: Optional[str] = None
51
- static_secret_access_key: Optional[str] = None
52
- static_storage_bucket_name: Optional[str] = None
53
- static_default_acl: str = Field('public-read')
54
- static_s3_custom_domain: Optional[str] = None
55
- static_location: str = Field('static')
56
- static_storage: str = Field('oxutils.s3.storages.StaticStorage')
57
-
58
- # Default S3 for media
59
- use_default_s3: bool = Field(False)
60
- use_static_s3_as_default: bool = Field(False)
61
- default_s3_access_key_id: Optional[str] = None
62
- default_s3_secret_access_key: Optional[str] = None
63
- default_s3_storage_bucket_name: Optional[str] = None
64
- default_s3_default_acl: str = Field('public-read')
65
- default_s3_custom_domain: Optional[str] = None
66
- default_s3_location: str = Field('media')
67
- default_s3_storage: str = Field('oxutils.s3.storages.PublicMediaStorage')
68
-
69
- # Private S3 for sensible data
70
- use_private_s3: bool = Field(False)
71
- private_s3_access_key_id: Optional[str] = None
72
- private_s3_secret_access_key: Optional[str] = None
73
- private_s3_storage_bucket_name: Optional[str] = None
74
- private_s3_default_acl: str = Field('private')
75
- private_s3_custom_domain: Optional[str] = None
76
- private_s3_location: str = Field('private')
77
- private_s3_storage: str = Field('oxutils.s3.storages.PrivateMediaStorage')
78
-
79
- # Log S3
80
- use_log_s3: bool = Field(False)
81
- use_private_s3_as_log: bool = Field(False)
82
- log_s3_access_key_id: Optional[str] = None
83
- log_s3_secret_access_key: Optional[str] = None
84
- log_s3_storage_bucket_name: Optional[str] = None
85
- log_s3_default_acl: str = Field('private')
86
- log_s3_custom_domain: Optional[str] = None
87
- log_s3_location: str = Field('oxi_logs')
88
- log_s3_storage: str = Field('oxutils.s3.storages.LogStorage')
89
-
90
-
91
- @model_validator(mode='after')
92
- def validate_s3_configurations(self):
93
- """Validate S3 and JWT configurations when enabled."""
94
- # Validate JWT keys if present
95
- self._validate_jwt_keys()
96
-
97
- # Validate static S3
98
- if self.use_static_s3:
99
- self._validate_s3_config(
100
- 'static',
101
- self.static_access_key_id,
102
- self.static_secret_access_key,
103
- self.static_storage_bucket_name,
104
- self.static_s3_custom_domain
105
- )
106
-
107
- # Validate default S3
108
- if self.use_default_s3:
109
- if not self.use_static_s3_as_default:
110
- self._validate_s3_config(
111
- 'default',
112
- self.default_s3_access_key_id,
113
- self.default_s3_secret_access_key,
114
- self.default_s3_storage_bucket_name,
115
- self.default_s3_custom_domain
116
- )
117
- elif not self.use_static_s3:
118
- raise ValueError(
119
- "OXI_USE_STATIC_S3_AS_DEFAULT requires OXI_USE_STATIC_S3 to be True"
120
- )
121
-
122
- # Validate private S3
123
- if self.use_private_s3:
124
- self._validate_s3_config(
125
- 'private',
126
- self.private_s3_access_key_id,
127
- self.private_s3_secret_access_key,
128
- self.private_s3_storage_bucket_name,
129
- self.private_s3_custom_domain
130
- )
131
-
132
- # Validate log S3
133
- if self.use_log_s3:
134
- if not self.use_private_s3_as_log:
135
- self._validate_s3_config(
136
- 'log',
137
- self.log_s3_access_key_id,
138
- self.log_s3_secret_access_key,
139
- self.log_s3_storage_bucket_name,
140
- self.log_s3_custom_domain
141
- )
142
- elif not self.use_private_s3:
143
- raise ValueError(
144
- "OXI_USE_PRIVATE_S3_AS_LOG requires OXI_USE_PRIVATE_S3 to be True"
145
- )
146
-
147
- return self
148
-
149
- def _validate_jwt_keys(self):
150
- """Validate JWT key files if configured."""
151
- import os
152
-
153
- if self.jwt_signing_key:
154
- if not os.path.exists(self.jwt_signing_key):
155
- raise ValueError(
156
- f"JWT signing key file not found at: {self.jwt_signing_key}"
157
- )
158
- if not os.path.isfile(self.jwt_signing_key):
159
- raise ValueError(
160
- f"JWT signing key path is not a file: {self.jwt_signing_key}"
161
- )
162
-
163
- if self.jwt_verifying_key:
164
- if not os.path.exists(self.jwt_verifying_key):
165
- raise ValueError(
166
- f"JWT verifying key file not found at: {self.jwt_verifying_key}"
167
- )
168
- if not os.path.isfile(self.jwt_verifying_key):
169
- raise ValueError(
170
- f"JWT verifying key path is not a file: {self.jwt_verifying_key}"
171
- )
172
-
173
- def _validate_s3_config(self, name: str, access_key: Optional[str],
174
- secret_key: Optional[str], bucket: Optional[str],
175
- domain: Optional[str]):
176
- """Validate required S3 configuration fields."""
177
- missing_fields = []
178
- if not access_key:
179
- missing_fields.append(f'OXI_{name.upper()}_S3_ACCESS_KEY_ID')
180
- if not secret_key:
181
- missing_fields.append(f'OXI_{name.upper()}_S3_SECRET_ACCESS_KEY')
182
- if not bucket:
183
- missing_fields.append(f'OXI_{name.upper()}_S3_STORAGE_BUCKET_NAME')
184
- if not domain:
185
- missing_fields.append(f'OXI_{name.upper()}_S3_CUSTOM_DOMAIN')
186
-
187
- if missing_fields:
188
- raise ValueError(
189
- f"Missing required {name} S3 configuration: {', '.join(missing_fields)}"
190
- )
191
-
192
- def get_static_storage_url(self) -> str:
193
- """Get static storage URL."""
194
- if not self.use_static_s3:
195
- raise ImproperlyConfigured(
196
- "Static S3 is not enabled. Set OXI_USE_STATIC_S3=True."
197
- )
198
- return f'https://{self.static_s3_custom_domain}/{self.static_location}/'
199
-
200
- def get_default_storage_url(self) -> str:
201
- """Get default storage URL."""
202
- if self.use_default_s3:
203
- if self.use_static_s3_as_default:
204
- # Use static S3 credentials but keep default_s3 specific values (location, etc.)
205
- domain = self.static_s3_custom_domain
206
- else:
207
- domain = self.default_s3_custom_domain
208
- return f'https://{domain}/{self.default_s3_location}/'
209
-
210
- raise ImproperlyConfigured(
211
- "Default S3 is not enabled. Set OXI_USE_DEFAULT_S3=True."
212
- )
213
-
214
- def get_private_storage_url(self) -> str:
215
- """Get private storage URL."""
216
- if not self.use_private_s3:
217
- raise ImproperlyConfigured(
218
- "Private S3 is not enabled. Set OXI_USE_PRIVATE_S3=True."
219
- )
220
- return f'https://{self.private_s3_custom_domain}/{self.private_s3_location}/'
221
-
222
- def get_log_storage_url(self) -> str:
223
- """Get log storage URL."""
224
- if not self.use_log_s3:
225
- raise ImproperlyConfigured(
226
- "Log S3 is not enabled. Set OXI_USE_LOG_S3=True."
227
- )
228
- if self.use_private_s3_as_log:
229
- # Use private S3 credentials but keep log_s3 specific values (location, etc.)
230
- domain = self.private_s3_custom_domain
231
- else:
232
- domain = self.log_s3_custom_domain
233
- return f'https://{domain}/{self.log_s3_location}/{self.service_name}/'
234
-
235
-
236
- def write_django_settings(self, django_settings_module):
237
- """
238
- Configure Django settings for S3 storages if enabled.
239
-
240
- Sets:
241
- 1. STATIC_URL & STATICFILES_STORAGE (if use_static_s3)
242
- 2. MEDIA_URL & DEFAULT_FILE_STORAGE (if use_default_s3)
243
- 3. PRIVATE_MEDIA_LOCATION & PRIVATE_FILE_STORAGE (if use_private_s3)
244
-
245
- Args:
246
- django_settings_module: The Django settings module to update.
247
- """
248
- # Configure static storage
249
- if self.use_static_s3:
250
- django_settings_module.STATIC_URL = self.get_static_storage_url()
251
- django_settings_module.STATICFILES_STORAGE = self.static_storage
252
-
253
- # Configure default/media storage
254
- if self.use_default_s3:
255
- django_settings_module.MEDIA_URL = self.get_default_storage_url()
256
- django_settings_module.DEFAULT_FILE_STORAGE = self.default_s3_storage
257
-
258
- # Configure private storage
259
- if self.use_private_s3:
260
- django_settings_module.PRIVATE_MEDIA_LOCATION = self.private_s3_location
261
- django_settings_module.PRIVATE_FILE_STORAGE = self.private_s3_storage
262
-
263
-
264
- oxi_settings = OxUtilsSettings()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes