accrete 0.0.57__py3-none-any.whl → 0.0.59__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.
@@ -100,7 +100,6 @@ def default_table_context(model: Type[Model], params: dict, queryset=None, **kwa
100
100
  return ctx
101
101
 
102
102
 
103
-
104
103
  @dataclass
105
104
  class ListContext(Context):
106
105
 
@@ -158,7 +158,9 @@ class Filter:
158
158
  'PositiveSmallIntegerField': self.int_param,
159
159
  'DateTimeField': self.date_time_param,
160
160
  'DateField': self.date_param,
161
- 'ForeignKey': self.foreign_key_param
161
+ 'ForeignKey': self.foreign_key_param,
162
+ 'FileField': self.file_param,
163
+ 'ImageField': self.file_param
162
164
  }
163
165
 
164
166
  def parse_choices(self, choices):
@@ -269,6 +271,9 @@ class Filter:
269
271
  return self.null_param(key, value)
270
272
  return ''
271
273
 
274
+ def file_param(self, key, value):
275
+ return self.null_param(key, value)
276
+
272
277
  def null_param(self, key, value):
273
278
  options = self.parse_choices([
274
279
  ('true', _('True')),
@@ -24,3 +24,7 @@ function setDropDown(el) {
24
24
  }
25
25
  })
26
26
  }
27
+
28
+ function removeModal(modalId) {
29
+ document.getElementById(modalId).remove()
30
+ }
@@ -6,7 +6,7 @@
6
6
  <div id="form-content" class="column p-0 is-8-desktop">
7
7
  <div class="box mt-2">
8
8
  {% if form.is_saved is False %}
9
- {% include 'ui/partials/form_errors.html' with show_field_errors=True %}
9
+ {% include 'ui/partials/form_errors.html' %}
10
10
  {% endif %}
11
11
  {% block form %}{% endblock %}
12
12
  </div>
@@ -9,28 +9,26 @@
9
9
  <p>{{ form.save_error|safe }}</p>
10
10
  <p>Error ID: {{ form.save_error_id }}</p>
11
11
  {% endif %}
12
- {% if show_field_errors %}
13
- {% for f in form %}
14
- {% if f.errors %}
15
- <label>
16
- <span class="is-underlined">{{ f.label_tag }}</span>
17
- <span class="is-size-7">{{ f.errors }}</span>
18
- </label>
19
- {% endif %}
20
- {% endfor %}
21
- {% for formset in form.inline_forms %}
22
- {% for inline_form in formset %}
23
- {% for field in inline_form %}
24
- {% if field.errors %}
25
- <label>
26
- <span class="is-underlined">{{ field.label_tag }}</span>
27
- <span class="is-size-7">{{ field.errors }}</span>
28
- </label>
29
- {% endif %}
30
- {% endfor %}
12
+ {% for f in form %}
13
+ {% if f.errors %}
14
+ <label>
15
+ <span class="is-underlined">{{ f.label_tag }}</span>
16
+ <span class="is-size-7">{{ f.errors }}</span>
17
+ </label>
18
+ {% endif %}
19
+ {% endfor %}
20
+ {% for formset in form.inline_forms %}
21
+ {% for inline_form in formset %}
22
+ {% for field in inline_form %}
23
+ {% if field.errors %}
24
+ <label>
25
+ <span class="is-underlined">{{ field.label_tag }}</span>
26
+ <span class="is-size-7">{{ field.errors }}</span>
27
+ </label>
28
+ {% endif %}
31
29
  {% endfor %}
32
30
  {% endfor %}
33
- {% endif %}
31
+ {% endfor %}
34
32
  </div>
35
33
  </div>
36
34
  </div>
@@ -0,0 +1,33 @@
1
+ {% load i18n %}
2
+
3
+ <div id="modal-{{ form_id }}" class="modal {% block modal_form_class %}is-active{% endblock %}">
4
+ <div class="modal-background" onclick="removeModal('modal-{{ form_id }}')"></div>
5
+ <div class="modal-card">
6
+ <header class="modal-card-head">
7
+ <p class="modal-card-title">
8
+ {% block modal_title %}{% endblock %}
9
+ </p>
10
+ <button class="delete filter-modal-close" aria-label="close" onclick="removeModal('modal-{{ form_id }}')"></button>
11
+ </header>
12
+ <section id="modal-content" class="modal-card-body">
13
+ {% if form.is_saved is False %}
14
+ {% include 'ui/partials/form_errors.html' %}
15
+ {% endif %}
16
+ {% block modal_content %}{% endblock %}
17
+ </section>
18
+ <footer class="modal-card-foot">
19
+ {% block modal_footer %}
20
+ <div class="buttons" style="width: 100%">
21
+ {% block modal_buttons %}
22
+ <button class="button is-success" type="submit" form="{{ form_id }}">
23
+ {% translate 'Save' %}
24
+ </button>
25
+ <button class="button" onclick="removeModal('modal-{{ form_id }}')">
26
+ {% translate 'Discard' %}
27
+ </button>
28
+ {% endblock %}
29
+ </div>
30
+ {% endblock %}
31
+ </footer>
32
+ </div>
33
+ </div>
accrete/middleware.py CHANGED
@@ -82,10 +82,12 @@ class HtmxRedirectMiddleware(MiddlewareMixin):
82
82
  @staticmethod
83
83
  def process_response(request, response):
84
84
  is_htmx = request.headers.get('HX-Request', 'false') == 'true'
85
- is_redirect = isinstance(
86
- response, (HttpResponseRedirect, HttpResponsePermanentRedirect)
87
- )
88
- if is_htmx and is_redirect:
89
- response['HX-Redirect'] = response['Location']
85
+ if not is_htmx:
86
+ return response
87
+ is_redirect = isinstance(response, HttpResponseRedirect)
88
+ is_permanent_redirect = isinstance(response, HttpResponsePermanentRedirect)
89
+ if is_redirect or is_permanent_redirect:
90
90
  response.status_code = 200
91
+ header = 'HX-Location' if is_redirect else 'HX-Redirect'
92
+ response[header] = response['Location']
91
93
  return response
accrete/storage.py ADDED
@@ -0,0 +1,37 @@
1
+ import os
2
+ from urllib.parse import urljoin
3
+ from django.core.files.storage import FileSystemStorage
4
+ from django.utils.encoding import filepath_to_uri
5
+ from django.utils.deconstruct import deconstructible
6
+ from django.conf import settings
7
+ from accrete.tenant import get_tenant
8
+
9
+
10
+ @deconstructible(path="django.core.files.storage.FileSystemStorage")
11
+ class TenantFileSystemStorage(FileSystemStorage):
12
+
13
+ @property
14
+ def base_location(self):
15
+ tenant = get_tenant()
16
+ base_dir = f'{settings.MEDIA_ROOT}/{tenant.id}'
17
+ os.makedirs(os.path.dirname(base_dir), exist_ok=True)
18
+ return base_dir
19
+
20
+ @property
21
+ def location(self):
22
+ return os.path.abspath(self.base_location)
23
+
24
+ @property
25
+ def base_url(self):
26
+ if self._base_url is not None and not self._base_url.endswith("/"):
27
+ self._base_url += "/"
28
+ res = self._value_or_setting(self._base_url, f'{settings.MEDIA_URL.strip("/")}/{get_tenant().id}')
29
+ return res
30
+
31
+ def url(self, name):
32
+ if self.base_url is None:
33
+ raise ValueError("This file is not accessible via a URL.")
34
+ url = filepath_to_uri(name)
35
+ if url is not None:
36
+ url = url.lstrip("/")
37
+ return urljoin(f'/{self.base_url}/', url)
accrete/utils/forms.py CHANGED
@@ -8,14 +8,14 @@ from django.forms import BaseFormSet
8
8
  _logger = logging.getLogger(__name__)
9
9
 
10
10
 
11
- def save_form(form, reraise=False):
11
+ def save_form(form, commit=True, reraise=False):
12
12
  form.is_saved = False
13
13
  form.save_error = None
14
14
  form.save_error_id = None
15
15
  try:
16
16
  if form.is_valid():
17
17
  with transaction.atomic():
18
- form.save()
18
+ form.save(commit=commit)
19
19
  form.is_saved = True
20
20
  except Exception as e:
21
21
  form.save_error = repr(e)
@@ -27,7 +27,7 @@ def save_form(form, reraise=False):
27
27
  return form
28
28
 
29
29
 
30
- def save_forms(form, inline_formsets: list = None, reraise: bool = False):
30
+ def save_forms(form, inline_formsets: list = None, commit=True, reraise: bool = False):
31
31
 
32
32
  def handle_error(error):
33
33
  form.save_error = repr(error)
@@ -56,9 +56,9 @@ def save_forms(form, inline_formsets: list = None, reraise: bool = False):
56
56
 
57
57
  try:
58
58
  with transaction.atomic():
59
- form.save()
59
+ form.save(commit=commit)
60
60
  for inline_formset in inline_formsets:
61
- inline_formset.save()
61
+ inline_formset.save(commit=commit)
62
62
  except Exception as e:
63
63
  handle_error(e)
64
64
  if reraise:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: accrete
3
- Version: 0.0.57
3
+ Version: 0.0.59
4
4
  Summary: Django Shared Schema Multi Tenant
5
5
  Author-email: Benedikt Jilek <benedikt.jilek@pm.me>
6
6
  License: Copyright (c) 2023 Benedikt Jilek
@@ -5,8 +5,9 @@ accrete/apps.py,sha256=F7ynMLHJr_6bRujWtZVUzCliY2CGKiDvyUmL4F68L2E,146
5
5
  accrete/config.py,sha256=eJUbvyBO3DvAD6xkVKjTAzlXy7V7EK9bVyb91girfUs,299
6
6
  accrete/forms.py,sha256=2vUh80qNvPDD8Zl3agKBSJEQeY7bXVLOx_SAB34wf8E,1359
7
7
  accrete/managers.py,sha256=CaIJLeBry4NYIXaVUrdUjp7zx4sEWgv-1-ssI1m-EOs,1156
8
- accrete/middleware.py,sha256=bUsvhdVdUlbqB-Hd5Y5w6WL8rO8It1VSGA5EZaEPA3o,3266
8
+ accrete/middleware.py,sha256=IABs2pAV-kXjp3n5_Wsc7reXGjU5FhmCbvFB8cC4ZRM,3422
9
9
  accrete/models.py,sha256=grvRNXg0ZYAJU3KAIX-svuZXeXlfqP4qEJ00nlbV594,5145
10
+ accrete/storage.py,sha256=z7pHdQFw0hFGrrbfqIh7KFxabQ_JGqoPebmiX9TLmeU,1254
10
11
  accrete/tenant.py,sha256=g3ZuTrQr2zqmIopNBRQeCmHEK2R3dlUme_hOV765J6U,1778
11
12
  accrete/tests.py,sha256=Agltbzwwh5htvq_Qi9vqvxutzmg_GwgPS_N19xJZRlw,7197
12
13
  accrete/views.py,sha256=9-sgCFe_CyG-wllAcIOLujyueiq66C-zg0U7Uf5Y2wU,2954
@@ -35,9 +36,9 @@ accrete/contrib/system_mail/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
35
36
  accrete/contrib/ui/__init__.py,sha256=aeRSerct2JWpztNoxWDZXi7FzJhfxptVMVAZl4Sdzqs,504
36
37
  accrete/contrib/ui/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
37
38
  accrete/contrib/ui/apps.py,sha256=E0ao2ox6PQ3ldfeR17FXJUUJuGiWjm2DPCxHbPXGzls,152
38
- accrete/contrib/ui/context.py,sha256=jVD7w9QIIA2qh04UrO9rYDDrY-0Osr6FLggMlGxvztI,8364
39
+ accrete/contrib/ui/context.py,sha256=tb4x_G4VsIa1LKIWl-CvLVtEd_DCbrClA-0Wmnne9bc,8363
39
40
  accrete/contrib/ui/elements.py,sha256=0F5q0-XLdAWQjdYLMQt6RXqz4xPD_ECrhs0kcBfYkvo,1856
40
- accrete/contrib/ui/filter.py,sha256=L7sBpmk454kaSZIQXe9hNj1Xbna8hJ2P-YTvmM7T5FE,12243
41
+ accrete/contrib/ui/filter.py,sha256=UAIkUNKu2nVQLafwZlkQu4PDfOPyFM61e_mE7OWRhYs,12410
41
42
  accrete/contrib/ui/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
42
43
  accrete/contrib/ui/urls.py,sha256=TUBlz_CGs9InTZoxM78GSnucA73I8knoh_obt12RUHM,186
43
44
  accrete/contrib/ui/views.py,sha256=WpBKMsxFFG8eG4IN7TW_TPE6i3OFF7gnLDTK7JMKti8,191
@@ -144,7 +145,7 @@ accrete/contrib/ui/static/icons/Logo.svg,sha256=hGZuxrAa-LRpFavFiF8Lnc7X9OQcqmb6
144
145
  accrete/contrib/ui/static/icons/accrete.svg,sha256=CWHJKIgk3hxL7xIaFSz2j1cK-eF1TroCbjcF58bgOIs,1024
145
146
  accrete/contrib/ui/static/js/filter.js,sha256=-8yGsI4juzA9ZkUS4Qrto4s5Wq4teRLyZfJm5dySm7o,24613
146
147
  accrete/contrib/ui/static/js/htmx.min.js,sha256=s73PXHQYl6U2SLEgf_8EaaDWGQFCm6H26I-Y69hOZp4,47755
147
- accrete/contrib/ui/static/js/ui.js,sha256=pJm5Wc2bg9Bu0PWafz1cHpGrM5so4U11MkCKdstxUms,1015
148
+ accrete/contrib/ui/static/js/ui.js,sha256=VO2kcfav1aTuqlz4YJl2sZkPD-vsm259yQb12GrNMxo,1096
148
149
  accrete/contrib/ui/static/webfonts/fa-brands-400.ttf,sha256=VlbVlrxZcWWkIYL2eyufF9KuR6nj7xsEK5pylzlzBwU,207972
149
150
  accrete/contrib/ui/static/webfonts/fa-brands-400.woff2,sha256=OokkzVIDooYocWrttc7wlD2kw7ROP_zukKsGOHtBxJA,117372
150
151
  accrete/contrib/ui/static/webfonts/fa-regular-400.ttf,sha256=XQLcm4WOPIWnlPh-N5hX9P7cTibPFQAXFKmg4LHSKU0,68004
@@ -162,14 +163,15 @@ accrete/contrib/ui/templates/django/forms/widgets/text.html,sha256=MSmLlQc7PsPoD
162
163
  accrete/contrib/ui/templates/django/forms/widgets/textarea.html,sha256=c9BTedqb3IkXLyVYd0p9pR8DFnsXCNGoxVBWZTk_Fic,278
163
164
  accrete/contrib/ui/templates/ui/dashboard.html,sha256=udnwiSJEcn2wMaJfTs4P0Y20FU79VguK_9Lq4K2BqtM,160
164
165
  accrete/contrib/ui/templates/ui/detail.html,sha256=b1HC1QCGooo6tLh7fLhEDPau1tIOzscLXP6R_PN758I,1093
165
- accrete/contrib/ui/templates/ui/form.html,sha256=cd6VUNzfIZH2_iudQa_EkqsPaBjyTam4Fm-Kgh8YpkY,655
166
+ accrete/contrib/ui/templates/ui/form.html,sha256=mlrMsxUOn5RkyROLYBHWzdWckN8Cg-2-ynD0SRmuXSM,627
166
167
  accrete/contrib/ui/templates/ui/layout.html,sha256=f8K0KDlh_eDz0UKH0IB34dBjPtDiNgsuPgysK-DYLgE,14792
167
168
  accrete/contrib/ui/templates/ui/list.html,sha256=6jmChhCpj6iuSqAG7X_eD5ZjVvwU4cyynmvoH0-juTk,1740
168
169
  accrete/contrib/ui/templates/ui/table.html,sha256=bdPN2F7e7i3FHcQ18e0HJKkYT64PpxPRALRjcirJKGQ,4243
169
170
  accrete/contrib/ui/templates/ui/partials/filter.html,sha256=2vmeL3980rMmkRnmVtZh9mBHe6S0PTMjaGIN1J6SpNM,7184
170
- accrete/contrib/ui/templates/ui/partials/form_errors.html,sha256=QjfRriD9Z5SlhIFX__nVXqB3rPg4icbG4G02kML8IcQ,1529
171
+ accrete/contrib/ui/templates/ui/partials/form_errors.html,sha256=C5ktasYff2xBTiWfM6QR8qaGKSyK9QufB3B9N77KGpg,1386
171
172
  accrete/contrib/ui/templates/ui/partials/form_modal.html,sha256=E52tFaIL3mcWRBHEamkOL1ZSBsBv08JsYFkoUtlhGgc,1165
172
173
  accrete/contrib/ui/templates/ui/partials/header.html,sha256=5ER9E6c-vwDxuIuMSXL4F_fq2zYY17R_0A0Ao--H4Us,6916
174
+ accrete/contrib/ui/templates/ui/partials/modal_form.html,sha256=wEcpi-WRz20R61gE-qtzZJIrXixjwvaJXX6FsVQrCRE,1451
173
175
  accrete/contrib/ui/templates/ui/partials/onchange_form.html,sha256=K5twTGqRUW1iM2dGtdWntjsJvJVo5EIzKxX2HK-H1yw,160
174
176
  accrete/contrib/ui/templates/ui/partials/pagination_detail.html,sha256=58nA3X7Il0FAD4VcYyr7tTGWRiVf_FN1TkImmKEpKHU,1014
175
177
  accrete/contrib/ui/templates/ui/partials/pagination_list.html,sha256=Eyx1lsk9UIFFYPICL7RuYeUFaKVlmvWVXnFCGR-II7k,1324
@@ -216,10 +218,10 @@ accrete/migrations/0002_initial.py,sha256=dFOM7kdHlx7pVAh8cTDlZMtciN4O9Z547HAzEK
216
218
  accrete/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
217
219
  accrete/utils/__init__.py,sha256=YwEzwjz-E92LHhqeLsQ4167zXHHY1PFG6xcsAofnmBU,192
218
220
  accrete/utils/dates.py,sha256=apM6kt6JhGrKgoT0jfav1W-8AUVTxNc9xt3fJQ2n0JI,1492
219
- accrete/utils/forms.py,sha256=UP6vCCTtXD5MqU2LWbNXtk2ZMMEmoty_tjLCbJlqYsY,2984
221
+ accrete/utils/forms.py,sha256=Lll-DvAhKZDw72XeuCtb4wxQEJNFp7lQWh_Z1GyH3Zk,3049
220
222
  accrete/utils/http.py,sha256=mAtQRgADv7zu1_j7A-EKVyb-oqa5a21i4Gd0QfjzGV0,3540
221
223
  accrete/utils/models.py,sha256=EEhv7-sQVtQD24PEb3XcDUAh3VVhVFoMMLyFrDjGEaI,706
222
- accrete-0.0.57.dist-info/METADATA,sha256=tiRCQAdfWu09ATxMwWIf-lKa09FNZ31qCoicK9-kfi4,4892
223
- accrete-0.0.57.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
224
- accrete-0.0.57.dist-info/licenses/LICENSE,sha256=_7laeMIHnsd3Y2vJEXDYXq_PEXxIcjgJsGt8UIKTRWc,1057
225
- accrete-0.0.57.dist-info/RECORD,,
224
+ accrete-0.0.59.dist-info/METADATA,sha256=na4Zyia9GVHueWMmrOaC1E1sbJmsfLGkEaPVlVzzuzo,4892
225
+ accrete-0.0.59.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
226
+ accrete-0.0.59.dist-info/licenses/LICENSE,sha256=_7laeMIHnsd3Y2vJEXDYXq_PEXxIcjgJsGt8UIKTRWc,1057
227
+ accrete-0.0.59.dist-info/RECORD,,