accrete 0.0.23__py3-none-any.whl → 0.0.25__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.
@@ -97,8 +97,8 @@
97
97
  >
98
98
  {% else %}
99
99
  <a class="button is-fullwidth {{ action.class_list|join:' ' }}"
100
- href="{{ action.url }}{{ querystring|default_if_none:'?' }}{% if page %}&page={{ page.number }}{% endif %}{{ action.query_params }}"
101
- {% for attr in action.attrs %}{{ attr }}{% endfor %}
100
+ href="{{ action.url }}{{ url_params|default_if_none:'?' }}{% if page %}&page={{ page.number }}{% endif %}{{ action.query_params }}"
101
+ {% for attr, val in action.attrs %}{{ attr }}="{{ val }}"{% endfor %}
102
102
  >{{ action.name }}
103
103
  </a>
104
104
  {% endif %}
@@ -144,20 +144,20 @@
144
144
 
145
145
  {% if filter_terms %}
146
146
  <div id="filter-modal" class="modal">
147
- <div class="modal-background filter-modal-close" onclick="closeFilterModal()"></div>
147
+ <div class="modal-background filter-modal-close" onclick="hideFilterModal()"></div>
148
148
  <div class="modal-card" style="height: 100%">
149
149
  <header class="modal-card-head">
150
150
  <p class="modal-card-title">
151
151
  {% block search_modal_title %}{% translate 'Filter' %}{% endblock %}</p>
152
- <button class="delete filter-modal-close" aria-label="close" onclick="closeFilterModal()"></button>
152
+ <button class="delete filter-modal-close" aria-label="close" onclick="hideFilterModal()"></button>
153
153
  </header>
154
154
  <section id="modal-content" class="modal-card-body px-0">
155
155
  </section>
156
156
  <footer class="modal-card-foot">
157
- <button class="button is-fullwidth mr-1"
158
- onclick="resetFilter()">{% translate 'Reset' %}</button>
159
157
  <button id="applyFilterFromModalButton"
160
- class="button is-fullwidth is-success ml-1" onclick="apply()">{% translate 'Filter' %}</button>
158
+ class="button is-fullwidth is-success ml-1"
159
+ onclick="hideFilterModal()"
160
+ >{% translate 'Filter' %}</button>
161
161
  </footer>
162
162
  </div>
163
163
  </div>
@@ -4,15 +4,20 @@
4
4
  {% load accrete_ui %}
5
5
 
6
6
  <div id="query-block" class="panel-block pt-0" style="position: relative; display: inline-block; width: 100%">
7
- <div id="query-apply" hx-get="" hx-trigger="click" hx-replace-url="true" hx-select-oob="#content,#list-pagination,#panel-actions,#header-actions,#query-apply"></div>
8
- <div id="query-tags" class="is-flex-direction-column is-flex-grow-1 is-multiline mb-1" data-or-label="{% translate 'OR' %}"></div>
7
+ <div id="query-apply" hx-get="" hx-trigger="click" hx-replace-url="true"
8
+ hx-select-oob="#content,#list-pagination,#panel-actions,#header-actions,#query-apply">
9
+
10
+ </div>
11
+ <div id="query-tags" class="is-flex-direction-column is-flex-grow-1 is-multiline mb-1"
12
+ data-or-label="{% translate 'OR' %}" data-and-label="{% translate 'AND' %}" data-xor-label="{% translate 'XOR' %}">
13
+ </div>
9
14
 
10
15
  <div class="field has-addons level mb-1">
11
- <p id="query-operation" class="control">
16
+ <p id="query-operation" class="control" style="display: flex; flex-direction: column; align-self: flex-start">
12
17
  <span class="select">
13
18
  <select id="query-operation-select" aria-label="Select Operation">
14
- <option value="and">{% translate 'AND' %}</option>
15
- <option value="or">{% translate 'OR' %}</option>
19
+ <option value="&">{% translate 'AND' %}</option>
20
+ <option value="|">{% translate 'OR' %}</option>
16
21
  </select>
17
22
  </span>
18
23
  </p>
@@ -20,7 +25,7 @@
20
25
  <div id="query-notification-parameter" class="notification is-warning is-light has-text-centered py-2 m-0 is-hidden">
21
26
  <p>{% translate 'Select a parameter' %}</p>
22
27
  </div>
23
- <p id="query-text" class="notification py-2 px-1 m-0 is-hidden" style="word-break: break-word"></p>
28
+ <p id="query-label" class="notification py-2 px-1 m-0 is-hidden" style="word-break: break-word"></p>
24
29
  </div>
25
30
  </div>
26
31
 
@@ -32,6 +37,7 @@
32
37
  class="input"
33
38
  placeholder="Enter a search term"
34
39
  data-default-term="{{ default_filter_term }}"
40
+ onkeyup="inputConfirm()"
35
41
  >
36
42
  </p>
37
43
  <p id="query-input-select-control" class="control is-expanded is-hidden">
@@ -39,11 +45,11 @@
39
45
  <select id="query-input-select" aria-label="query-input-select"></select>
40
46
  </span>
41
47
  </p>
42
- <p id="query-input-apply" class="control"><button class="button">&#x21D2;</button></p>
48
+ <p id="query-input-apply" class="control" onclick="applyInput()"><button class="button">&#x21D2;</button></p>
43
49
  </div>
44
50
 
45
51
 
46
- <div id="query-params-dropdown" class="box mt-1 mx-0 p-1 is-hidden" tabindex="-1" style="z-index: 10; background: white; word-break: break-word; position: inherit">
52
+ <div id="query-params-dropdown" class="box mt-1 mx-0 p-1 is-hidden" tabindex="-1" style="z-index: 10; background: white; word-break: break-word; position: inherit; max-height: 300px; overflow-y: auto" onclick="toggleParams()">
47
53
  {{ filter_terms|render_query_params }}
48
54
  </div>
49
- </div>
55
+ </div>
@@ -7,7 +7,7 @@
7
7
  <nav id="breadcrumbs" class="breadcrumb" aria-label="breadcrumbs" style="white-space: unset; word-break: break-word">
8
8
  <ul>
9
9
  {% for crumb in breadcrumbs %}
10
- <li><a class="is-underlined" href="{{ crumb.url|default_if_none:'#' }}{{ querystring }}" aria-current="page">{{ crumb.name }}</a></li>
10
+ <li><a class="is-underlined" href="{{ crumb.url|default_if_none:'#' }}{{ url_params }}" aria-current="page">{{ crumb.name }}</a></li>
11
11
  {% endfor %}
12
12
  <li class="is-active"><a aria-current="page">{{ title }}</a></li>
13
13
  </ul>
@@ -37,7 +37,7 @@
37
37
  >
38
38
  {% else %}
39
39
  <a class="button mr-2 {{ action.class_list|join:' ' }}"
40
- href="{{ action.url }}{{ querystring|default_if_none:'?' }}{% if page %}&page={{ page.number }}{% endif %}{{ action.query_params }}"
40
+ href="{{ action.url }}{{ url_params|default_if_none:'?' }}{% if page %}&page={{ page.number }}{% endif %}{{ action.query_params }}"
41
41
  {% for attr in action.attrs %}{{ attr }}{% endfor %}
42
42
  >{{ action.name }}
43
43
  </a>
@@ -46,7 +46,9 @@
46
46
  </div>
47
47
  {% if filter_terms %}
48
48
  <div class="is-flex ml-2 py-1 pr-3">
49
- <button id="modal-filter-button" class="button has-icon"><i class="icon-filter"></i></button>
49
+ <button id="modal-filter-button" class="button has-icon" onclick="showFilterModal()">
50
+ <i class="icon-filter"></i>
51
+ </button>
50
52
  </div>
51
53
  {% endif %}
52
54
  </div>
@@ -1,7 +1,7 @@
1
1
  <div id="detail-pagination" class="field has-addons" style="width: 100%">
2
2
  <p class="control">
3
3
  <button class="button"
4
- hx-get="{{ previous_object_url }}{{ querystring }}"
4
+ hx-get="{{ previous_object_url }}{{ url_params }}"
5
5
  hx-replace-url="true"
6
6
  hx-select-oob="#content,#detail-pagination,#panel-actions,#header-actions,#breadcrumbs"
7
7
  ><
@@ -14,7 +14,7 @@
14
14
  </button>
15
15
  </p>
16
16
  <p class="control">
17
- <button class="button" hx-get="{{ next_object_url }}{{ querystring }}"
17
+ <button class="button" hx-get="{{ next_object_url }}{{ url_params }}"
18
18
  hx-replace-url="true"
19
19
  hx-select-oob="#content,#detail-pagination,#panel-actions,#header-actions,#breadcrumbs"
20
20
  >>
@@ -2,7 +2,7 @@
2
2
  <div id="list-pagination" class="field has-addons" style="min-width: 100%; max-width: 100%">
3
3
  <p class="control">
4
4
  <button class="button"
5
- hx-get="{{ querystring }}&page={% if page.has_previous %}{{ page.previous_page_number }}{% else %}{{ paginator.num_pages }}{% endif %}"
5
+ hx-get="{{ url_params }}&page={% if page.has_previous %}{{ page.previous_page_number }}{% else %}{{ paginator.num_pages }}{% endif %}"
6
6
  hx-replace-url="true"
7
7
  hx-select-oob="#content,#list-pagination,#panel-actions,#header-actions,#breadcrumbs"
8
8
  >
@@ -18,7 +18,7 @@
18
18
  </p>
19
19
  <p class="control">
20
20
  <button id="list-pagination-next-button" class="button"
21
- hx-get="{{ querystring }}&page={% if page.has_next %}{{ page.next_page_number }}{% else %}1{% endif %}"
21
+ hx-get="{{ url_params }}&page={% if page.has_next %}{{ page.next_page_number }}{% else %}1{% endif %}"
22
22
  hx-replace-url="true"
23
23
  hx-select-oob="#content,#list-pagination,#panel-actions,#header-actions,#breadcrumbs"
24
24
  >
@@ -2,6 +2,7 @@
2
2
 
3
3
  {% with val=obj|get_attr:field.name|default_if_none:'---' %}
4
4
  <td style="text-align: {{ field.alignment.value }}" {% if val|length > field.truncate_after %}title="{{ val }}"{% endif %}>
5
+ <span class="responsive-heading has-text-weight-light" style="margin-right: .2rem">{{ field.label }}:</span>
5
6
  {{ field.prefix }}
6
7
  {% block td_content %}
7
8
  {% if field.truncate_after > 0 %}
@@ -14,9 +14,9 @@
14
14
  {% block table_header_row %}
15
15
  <tr>
16
16
  {% block table_header %}
17
- <th>{{ obj_label }}</th>
17
+ <th>{{ object_label }}</th>
18
18
  {% for field in fields %}
19
- <th style="text-align: {% firstof field.header_alignment.value field.alignment.value %}">{{ field.label }}</th>
19
+ <th style="text-align: {% firstof field.header_alignment.value field.alignment.value %}">{{ field.label }}{% if field.header_info %}({{ field.header_info }}){% endif %}</th>
20
20
  {% endfor %}
21
21
  {% if unselect_button %}
22
22
  <th></th>
@@ -29,18 +29,20 @@
29
29
  {% for obj in page %}
30
30
  {% block table_data_row %}
31
31
  <tr {% if forloop.last and page.has_next %}
32
- hx-get="{{ querystring }}&page={{ page.next_page_number }}"
33
- hx-trigger="intersect once"
34
- hx-select="tbody > tr"
35
- hx-select-oob="#list-pagination-end-index,#list-pagination-next-button"
36
- hx-swap="afterend"
37
- {% endif %}>
32
+ hx-get="{{ url_params }}&page={{ page.next_page_number }}"
33
+ hx-trigger="intersect once"
34
+ hx-select="tbody > tr"
35
+ hx-select-oob="#list-pagination-end-index,#list-pagination-next-button"
36
+ hx-swap="afterend"
37
+ {% endif %}>
38
38
  {% block table_data %}
39
- <td class="responsive-heading has-text-weight-light">{{ obj_label }}:</td>
40
- <td><a class="is-underlined" href="{{ obj.get_absolute_url }}{{ querystring }}&page={{ page.number }}">{{ obj }}</a></td>
39
+ <td><a class="is-underlined" href="{{ obj.get_absolute_url }}{{ url_params }}&page={{ page.number }}">{{ obj }}</a></td>
41
40
  {% for field in fields %}
42
- <td class="responsive-heading has-text-weight-light">{{ field.label }}:</td>
43
- {% include 'ui/partials/table_field'|add:field.field_type.value|add:'.html' %}
41
+ {% if field.template %}
42
+ {% include field.template %}
43
+ {% else %}
44
+ {% include 'ui/partials/table_field'|add:field.field_type.value|add:'.html' %}
45
+ {% endif %}
44
46
  {% endfor %}
45
47
  {% if unselect_button %}
46
48
  <td><button class="button is-small has-icon p-0 is-pulled-right" onclick="unselectSingleObject({{ obj.pk }})"><i class="icon-delete-filter"></i></button></td>
@@ -49,11 +49,16 @@ class UserManager(BaseUserManager):
49
49
 
50
50
 
51
51
  class User(AbstractBaseUser, PermissionsMixin):
52
+
52
53
  class Meta:
53
54
  db_table = 'accrete_user'
54
55
  verbose_name = _('User')
55
56
  verbose_name_plural = _('Users')
56
57
 
58
+ filter_exclude = [
59
+ 'password'
60
+ ]
61
+
57
62
  username_validator = UnicodeUsernameValidator()
58
63
 
59
64
  username = models.CharField(
@@ -5,7 +5,7 @@ from django.contrib.auth.decorators import login_required
5
5
  from django.shortcuts import redirect, render, reverse
6
6
  from django.utils.translation import gettext_lazy as _
7
7
 
8
- from accrete.shortcuts import save_form
8
+ from accrete.forms import save_form
9
9
  from accrete.contrib.ui import FormContext, DetailContext, ClientAction
10
10
  from .forms import UserForm
11
11
 
accrete/forms.py CHANGED
@@ -3,13 +3,9 @@ from uuid import uuid4
3
3
  from functools import partial
4
4
 
5
5
  from django import forms
6
- from django.utils import timezone
7
- from django.utils.translation import gettext_lazy as _
8
6
  from django.contrib.auth import get_user_model
9
7
  from django.db import transaction
10
8
  from accrete.tenant import get_tenant
11
- from accrete.models import Tenant
12
- from accrete.queries import is_member
13
9
 
14
10
  _logger = logging.getLogger(__name__)
15
11
  User = get_user_model()
@@ -64,6 +60,12 @@ class One2ManyModelForm(forms.ModelForm):
64
60
  Product.objects.all(),
65
61
  label=_('Product')
66
62
  )
63
+ },
64
+ 'price': {
65
+ 'field_class': partial(
66
+ forms.FloatField,
67
+ label=_('Price')
68
+ )
67
69
  }
68
70
  }
69
71
  }
@@ -304,4 +306,4 @@ def save_form(form, reraise=False):
304
306
  form.save_error_id = error_id
305
307
  if reraise:
306
308
  raise e
307
- return form
309
+ return form
accrete/models.py CHANGED
@@ -14,6 +14,27 @@ class TenantManager(models.Manager):
14
14
  queryset = queryset.filter(tenant=tenant)
15
15
  return queryset
16
16
 
17
+ def bulk_create(
18
+ self,
19
+ objs,
20
+ batch_size=None,
21
+ ignore_conflicts=False,
22
+ update_conflicts=False,
23
+ update_fields=None,
24
+ unique_fields=None,
25
+ ):
26
+ tenant = get_tenant()
27
+ if tenant is None and not all(obj.tenant_id for obj in objs):
28
+ raise ValueError('Tenant must be set for all objects when calling bulk_create')
29
+ else:
30
+ for obj in objs:
31
+ obj.tenant_id = tenant.pk
32
+ return super().bulk_create(
33
+ objs, batch_size=batch_size, ignore_conflicts=ignore_conflicts,
34
+ update_conflicts=update_conflicts, update_fields=update_fields,
35
+ unique_fields=unique_fields
36
+ )
37
+
17
38
 
18
39
  class TenantModel(models.Model):
19
40
 
accrete/queries.py CHANGED
@@ -16,4 +16,3 @@ def members_for_current_tenant():
16
16
 
17
17
  def all_tenants():
18
18
  return models.Tenant.objects.all()
19
-
accrete/querystring.py ADDED
@@ -0,0 +1,89 @@
1
+ import logging
2
+ import json
3
+ import operator
4
+ from django.db.models import Model, Q, QuerySet
5
+
6
+ _logger = logging.getLogger(__name__)
7
+
8
+
9
+ def filter_querystring(model: type[Model], query_string: str) -> QuerySet:
10
+ return model.objects.filter(parse_querystring(model, query_string))
11
+
12
+
13
+ def parse_querystring(model: type[Model], query_string: str) -> Q:
14
+ """
15
+ param: query_string: JSON serializable string
16
+ [{term: value}, '&', [{term: value}, '|', {~term: value}]]
17
+ Q(term=value) & (Q(term=value) | ~Q(term=value))
18
+ """
19
+
20
+ def get_expression(term: str, value) -> Q:
21
+ invert = False
22
+ if term.startswith('~'):
23
+ invert = True
24
+ term = term[1:]
25
+
26
+ parts = term.split('_a_')
27
+ if len(parts) == 1:
28
+ expression = Q(**{term: value})
29
+ return ~expression if invert else expression
30
+
31
+ rel_path = parts[0].rstrip('__')
32
+ term = parts[1]
33
+ rel_model = get_related_model(rel_path) if rel_path else model
34
+ objects = rel_model.objects.annotate(**{
35
+ annotation['name']: annotation['func']
36
+ for annotation in rel_model.annotations
37
+ }).filter(Q(**{term: value}))
38
+ expression = Q(**{
39
+ f'{rel_path}{"__" if rel_path else ""}id__in': objects.values_list('id', flat=True)
40
+ })
41
+
42
+ return ~expression if invert else expression
43
+
44
+ def get_related_model(rel_path: str):
45
+ related_model = model
46
+ for part in rel_path.split('__'):
47
+ try:
48
+ related_model = related_model._meta.fields_map[part].related_model
49
+ except (AttributeError, KeyError):
50
+ try:
51
+ related_model = getattr(related_model, part).field.related_model
52
+ except AttributeError:
53
+ break
54
+ return related_model
55
+
56
+ def parse_query_block(sub_item) -> Q:
57
+ op = ops['&']
58
+ parsed_query = Q()
59
+ for item in sub_item:
60
+ if isinstance(item, list):
61
+ parsed_query = op(parsed_query, parse_query_block(item))
62
+ op = ops['&']
63
+ elif isinstance(item, dict):
64
+ dict_query = Q()
65
+ for term, value in item.items():
66
+ dict_query = ops['&'](dict_query, get_expression(term, value))
67
+ parsed_query = op(parsed_query, dict_query)
68
+ elif isinstance(item, str):
69
+ if item not in '&|^':
70
+ raise ValueError(
71
+ f'Invalid operator in querystring: {item}.'
72
+ f'Operator must be one of &, |, ^'
73
+ )
74
+ op = ops[item]
75
+
76
+ else:
77
+ raise ValueError(
78
+ f'Unsupported item in querystring: {item}.'
79
+ f'Item must be an instance of list, dict or str'
80
+ )
81
+ return parsed_query
82
+
83
+ query_data = json.loads(query_string)
84
+ if isinstance(query_data, dict):
85
+ query_data = [query_data]
86
+
87
+ ops = {'&': operator.and_, '|': operator.or_, '^': operator.xor}
88
+ query = parse_query_block(query_data)
89
+ return query
accrete/tenant.py CHANGED
@@ -46,3 +46,7 @@ class Unscoped:
46
46
 
47
47
  def __exit__(self, exc_type, exc_val, exc_tb):
48
48
  set_tenant(self.tenant)
49
+
50
+
51
+ def unscoped():
52
+ return Unscoped(get_tenant())
accrete/utils/dates.py CHANGED
@@ -29,10 +29,11 @@ def current_month_start() -> datetime:
29
29
  )
30
30
  return first_day
31
31
 
32
+
32
33
  def current_month_end() -> datetime:
33
34
  now = timezone.now()
34
35
  monthrange = calendar.monthrange(now.year, now.month)
35
36
  last_day = now.replace(
36
37
  day=monthrange[1], hour=23, minute=59, second=59, microsecond=999999
37
38
  )
38
- return last_day
39
+ return last_day
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: accrete
3
- Version: 0.0.23
3
+ Version: 0.0.25
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
@@ -3,12 +3,12 @@ accrete/admin.py,sha256=MUYUmCFlGYPowiXTbwl4_Q6Cq0-neiL53WW4P76JCLs,1174
3
3
  accrete/apps.py,sha256=F7ynMLHJr_6bRujWtZVUzCliY2CGKiDvyUmL4F68L2E,146
4
4
  accrete/config.py,sha256=eJUbvyBO3DvAD6xkVKjTAzlXy7V7EK9bVyb91girfUs,299
5
5
  accrete/decorators.py,sha256=vM8GuDHLzwEpHmTGafG-xwMddKvuYFIhe-FrUJqL1_4,678
6
- accrete/forms.py,sha256=hwUwlfM8v7gPFxH_foN1jIXzYH32GdX-FrPZgh0Qv1Q,11137
6
+ accrete/forms.py,sha256=dvRrDRNMTTls4dNL0UbU3EjE5x7omkqTnyvAXtWIbq0,11172
7
7
  accrete/middleware.py,sha256=ldnMI4Wv9p1JUyFX_sQSa6Hg4MgkXNbKaHqq5aRsD8s,2629
8
- accrete/models.py,sha256=_k8fOYFEOp3WN5rFHNCWDMMJ_H6HGSNiFHPsg2dv2Lg,5229
9
- accrete/queries.py,sha256=U1gmDuFv1h-zf86fygjHLuy-cPurmen5EnQrtZ5hIHc,411
10
- accrete/shortcuts.py,sha256=prs4aGWJ1dAeL4K6QLvP5dRHMsE7rDf0c6N_POCCqjo,237
11
- accrete/tenant.py,sha256=c_5G8qqO0dHAVY3fiN6oDNKQ61APTpcGgZeHLb9Kb8c,1077
8
+ accrete/models.py,sha256=OcxHnmFWity-Pfgj-jOhrxzZ44MdqmLxTH-xwrbtz7w,5974
9
+ accrete/queries.py,sha256=bchiqLzE1DmR9kvQ6Yyog6cNlYK_lxpztQMOx6Hy_0c,410
10
+ accrete/querystring.py,sha256=wSb3sm0HlCsa9KN1EA1O-lrjra6DjnWUixGxNgI3e7U,3130
11
+ accrete/tenant.py,sha256=s-zrNwklLQ4FeTp2wRuJrlMGKFjtcmXNL_GdimbvdPs,1129
12
12
  accrete/tests.py,sha256=Agltbzwwh5htvq_Qi9vqvxutzmg_GwgPS_N19xJZRlw,7197
13
13
  accrete/views.py,sha256=6BERfW0JbB-dllSsDXRGOrcQrytok2JB5ax0RLZEers,2315
14
14
  accrete/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -32,13 +32,13 @@ accrete/contrib/system_mail/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2
32
32
  accrete/contrib/system_mail/views.py,sha256=xc1IQHrsij7j33TUbo-_oewy3vs03pw_etpBWaMYJl0,63
33
33
  accrete/contrib/system_mail/migrations/0001_initial.py,sha256=6cwkkRXGjXvwXoMjjgmWmcPyXSTlUbhW1vMiHObk9MQ,1074
34
34
  accrete/contrib/system_mail/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- accrete/contrib/ui/__init__.py,sha256=FT5qys-ZZCm2a4eLA3vNC-en_TonH-cUn0lPKcR7Puc,301
35
+ accrete/contrib/ui/__init__.py,sha256=uoJqqJzMOpjp3d3Wi3oiobBp2Cw9w57rBiQNBq8stp0,287
36
36
  accrete/contrib/ui/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
37
37
  accrete/contrib/ui/apps.py,sha256=E0ao2ox6PQ3ldfeR17FXJUUJuGiWjm2DPCxHbPXGzls,152
38
- accrete/contrib/ui/components.py,sha256=3S-Mks9z27Aif-RdIlVFdGbriwkx0cnX8T-wrN0Uxfg,893
39
- accrete/contrib/ui/context.py,sha256=Gc9fyheFhePOk9Xhft8X6TH64djAwbOo_FfXJClNoYo,9208
40
- accrete/contrib/ui/filter.py,sha256=GCW_EyFGEhJ2QfQbVcL22NDDASL_LbB0O3dKixvqWFY,11958
41
- accrete/contrib/ui/querystring.py,sha256=y3JzUPCL_refkKN7YuWKAZI71xdaDxcSyvIUVRq-FW8,3352
38
+ accrete/contrib/ui/components.py,sha256=87GGgjPNVLSSkFaS52JBGcmKzAfPWV5jFJozNqlz4rk,966
39
+ accrete/contrib/ui/context.py,sha256=MKKwwOv20tJuO-BF3M2AaRkQAuItyS4ChyC78HCz3mo,9326
40
+ accrete/contrib/ui/filter.py,sha256=YKLXQaaXfpkUIcqBhzL1_LGOBuwGkOmJUKBU1_gX73Y,11749
41
+ accrete/contrib/ui/querystring.py,sha256=InQoEnNu3H9-2wnqLUpn7seQmgJ91_-xKOtVW6WZc_o,708
42
42
  accrete/contrib/ui/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
43
43
  accrete/contrib/ui/urls.py,sha256=TUBlz_CGs9InTZoxM78GSnucA73I8knoh_obt12RUHM,186
44
44
  accrete/contrib/ui/views.py,sha256=WpBKMsxFFG8eG4IN7TW_TPE6i3OFF7gnLDTK7JMKti8,191
@@ -117,14 +117,15 @@ accrete/contrib/ui/static/bulma/sass/utilities/extends.sass,sha256=jb5Ipy_k6hBSF
117
117
  accrete/contrib/ui/static/bulma/sass/utilities/functions.sass,sha256=tRNFJ9yQTS-GZ6ouJ7EIWiFITL7irYR7srzKwzacvUA,4896
118
118
  accrete/contrib/ui/static/bulma/sass/utilities/initial-variables.sass,sha256=JXNQHoF4YlBTUW6WSJ14_38SA9lbk6VkouzYURmlV8g,2691
119
119
  accrete/contrib/ui/static/bulma/sass/utilities/mixins.sass,sha256=oijSh2f1DPqod0W5op9iVEAFbC1huMqBIJmnHRx3exc,6291
120
- accrete/contrib/ui/static/css/accrete.css,sha256=XD_D3iOxgdvPbrCUjDcKZRvffi0JSz1UpRjsD2HvT90,252592
120
+ accrete/contrib/ui/static/css/accrete.css,sha256=A10xtiGZd2RJQH8p386wRSsTeiIHZwyvlem1zaqGK8k,253823
121
121
  accrete/contrib/ui/static/css/accrete.css.bak,sha256=2RErGa8_tm8lFSamfW3UfqPgEVkPDejk2fh8IidW-B0,2359
122
- accrete/contrib/ui/static/css/accrete.css.map,sha256=3A_FCH0faKyNSXtRYMHBk4ZaUmF7KTP115aO79pdMfU,55658
123
- accrete/contrib/ui/static/css/accrete.scss,sha256=YTwuzgnTN-ATPQKg9cKSrE-VRjp2RiI4Wt_9FvN5TLQ,3882
124
- accrete/contrib/ui/static/css/icons.css,sha256=3CsD9CLxOWHwQG6qrIAGc-28o89ef9dwTMaN3syJER8,3462
122
+ accrete/contrib/ui/static/css/accrete.css.map,sha256=DELp-r3Z2CXOdNCyaABMeuqKChiyVqDaf6hFnmVVscw,55921
123
+ accrete/contrib/ui/static/css/accrete.scss,sha256=MMsN9WZ2vnF1_Rr6HCg3_DabOoqhb3dHZFO66F_eJak,5683
124
+ accrete/contrib/ui/static/css/icons.css,sha256=ZaS9ChqKlwvEgrHbRXhplE3JohWEYmJefVnfggx9-gY,4739
125
125
  accrete/contrib/ui/static/icons/Logo.svg,sha256=hGZuxrAa-LRpFavFiF8Lnc7X9OQcqmb6Xl_dxx-27hM,1861
126
126
  accrete/contrib/ui/static/icons/accrete.svg,sha256=CWHJKIgk3hxL7xIaFSz2j1cK-eF1TroCbjcF58bgOIs,1024
127
- accrete/contrib/ui/static/js/filter.js,sha256=C95iOMmpEf6VEk2fyTE2XnTZNtVelTw0L9POnA37Xso,21454
127
+ accrete/contrib/ui/static/js/filter.js,sha256=rcJh4pHuKb0KQpGM7Bn2QzDsNhdP0V5RbouWjQ8A_uM,23650
128
+ accrete/contrib/ui/static/js/filter_old.js,sha256=yBC_Fhb9d40YLGmsfoxW7zQrlQkC8aCeVryaEInwy24,25779
128
129
  accrete/contrib/ui/static/js/list.js,sha256=OX_81ifRmawE-1QBU5Qpq_E6sHiiNwIPleETAn9EOJw,4280
129
130
  accrete/contrib/ui/static/js/navbar.js,sha256=9QGZfPgGWjCBZhZhrRf983hoPnRlwQP-Pl73c2vISYs,628
130
131
  accrete/contrib/ui/static/js/utils.js,sha256=6RKh3EJ57gx5UIjBcSaeZEs7lZdLvyYT9VAQ-WqlKSk,173
@@ -137,17 +138,17 @@ accrete/contrib/ui/templates/django/forms/widgets/text.html,sha256=MSmLlQc7PsPoD
137
138
  accrete/contrib/ui/templates/django/forms/widgets/textarea.html,sha256=c9BTedqb3IkXLyVYd0p9pR8DFnsXCNGoxVBWZTk_Fic,278
138
139
  accrete/contrib/ui/templates/ui/detail.html,sha256=AffbViFC9VtkUyMwEToFKhV_Oh2TM_qPJDSWFVhJAjg,469
139
140
  accrete/contrib/ui/templates/ui/form.html,sha256=HpcZCDU_ur_Zf5gpnH_F8OV6qfOYPl6Ecqg6w5RIayQ,405
140
- accrete/contrib/ui/templates/ui/layout.html,sha256=mwHPHd49QtYh-5ppRNJUAgWC1LSsYh_l4li0vBi1czY,8201
141
+ accrete/contrib/ui/templates/ui/layout.html,sha256=s2OuO4P43RPb27pxo9qW4Fyv1OjI5Gue9olKxCICF7k,8128
141
142
  accrete/contrib/ui/templates/ui/list.html,sha256=KQYdACatxJWHcyBB7sx5yBsV-q-GUL-fCv-iAem7jUg,803
142
- accrete/contrib/ui/templates/ui/table.html,sha256=gmfJUeu49qzd4wPBcR57puRtRuyTB-DE7DmmKwjgz2w,2715
143
- accrete/contrib/ui/templates/ui/partials/filter.html,sha256=t113Z_Lmbj2Sxmzt3OeVt4oJw_xA2H8ooRgC1cv12zc,2296
143
+ accrete/contrib/ui/templates/ui/table.html,sha256=OIPBxDF1LcC9f4j1pXsVty_GNwbNy_oLi6NTzMQyygY,2802
144
+ accrete/contrib/ui/templates/ui/partials/filter.html,sha256=IV__z2NBDga2RgjULEePZsF8Q_XwHrSACEDPGN8FNjk,2601
144
145
  accrete/contrib/ui/templates/ui/partials/form_errors.html,sha256=1_TQvTdiejsn-43YSyp2YfnP52P-MFYb-HGY0DLm4oA,991
145
146
  accrete/contrib/ui/templates/ui/partials/form_modal.html,sha256=FFDfI5qjOCUBSGqDjBXa8tcqN2q94wOOCNFDaiyplHQ,1032
146
- accrete/contrib/ui/templates/ui/partials/header.html,sha256=wqdeky2iBgRDcobGhBAKDQv8wQ6SBTUOos8s_aN7UG0,2629
147
+ accrete/contrib/ui/templates/ui/partials/header.html,sha256=yDM7KK3OpBIpuzCWMa1lDx5nvoNjJfZSwHiSnq4hT4Q,2693
147
148
  accrete/contrib/ui/templates/ui/partials/onchange_form.html,sha256=K5twTGqRUW1iM2dGtdWntjsJvJVo5EIzKxX2HK-H1yw,160
148
- accrete/contrib/ui/templates/ui/partials/pagination_detail.html,sha256=pbq9YwvrIabJW8EG1guFOGNxiRTf80MFK2vsgwGkYtE,940
149
- accrete/contrib/ui/templates/ui/partials/pagination_list.html,sha256=icnSHh-Blm2LrvcoDiy_Yy7yOX2Npnoi45auGYmD7-8,1301
150
- accrete/contrib/ui/templates/ui/partials/table_field.html,sha256=ZuabPAc9vUBQ0hTSIO56rGClo2Lfs6K-luR3gErNTI8,524
149
+ accrete/contrib/ui/templates/ui/partials/pagination_detail.html,sha256=ee5d5wZHLgh8wARvKCVZ68KZf77w107GWNRi9qkpW80,938
150
+ accrete/contrib/ui/templates/ui/partials/pagination_list.html,sha256=zdIHmK5W58IpYlW7QmMVpsh1ufUIxpPrDimq9uqaYFQ,1299
151
+ accrete/contrib/ui/templates/ui/partials/table_field.html,sha256=4oQw0na9UgHP8lo8KttyWBuDhCEeaZ8Vt9jJYJdZ5Gs,641
151
152
  accrete/contrib/ui/templates/ui/partials/table_field_float.html,sha256=GH_jFdpk8wEJXv4QfO6c3URYrZGGLeuSyWwWl2cWxwQ,45
152
153
  accrete/contrib/ui/templates/ui/partials/table_field_monetary.html,sha256=Wtod9vel2dD4vG8lUVLbtls4aU_2EG3p0E1QRRUSH10,166
153
154
  accrete/contrib/ui/templates/ui/partials/table_field_string.html,sha256=GH_jFdpk8wEJXv4QfO6c3URYrZGGLeuSyWwWl2cWxwQ,45
@@ -158,10 +159,10 @@ accrete/contrib/user/admin.py,sha256=YS4iApli7XUaIl9GsEJxys2j8sepX0by88omYHjff-E
158
159
  accrete/contrib/user/apps.py,sha256=oHDrAiHf-G57mZLyxqGJzRY2DbPprGFD-QgyVJG_ruI,156
159
160
  accrete/contrib/user/forms.py,sha256=FDfWiPld5EQMTHCCHTIhDdDjEU0zUBR3jo7l04kfn1c,683
160
161
  accrete/contrib/user/middleware.py,sha256=qblcujwJsthopagyT-hPFq4HsMyGt-VvqZw5TQopBjk,403
161
- accrete/contrib/user/models.py,sha256=xbDt2z03KzyJbd9mea2hRedsdddcn4614cckr_frY9s,3876
162
+ accrete/contrib/user/models.py,sha256=SFEXG9G-XY7Nuss7DT51abDv8BWLHKYJocOhQDI_1Lw,3926
162
163
  accrete/contrib/user/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
163
164
  accrete/contrib/user/urls.py,sha256=pTjnYuSHx3Mlx87uDULoWO1gB0moxTQG7YwXHsa-FTk,316
164
- accrete/contrib/user/views.py,sha256=m-nmRSL3XdeM_9UD_7jlEg_dnPIgDoT6qf0uhPTMI40,1978
165
+ accrete/contrib/user/views.py,sha256=JL0e4cmJSp6_Ukg8TBj_71g_VJNEBTbCAwl_xKEFkTk,1974
165
166
  accrete/contrib/user/locale/de/LC_MESSAGES/django.mo,sha256=p3rgUg6WltAVIMkQsjvjBqTsd_usLhSr1GH4Cyltc2c,433
166
167
  accrete/contrib/user/locale/de/LC_MESSAGES/django.po,sha256=f_Nxpo3HTm2L3f3zoHLfeWsZ-4IQp_EEVSku6TCZSvw,1870
167
168
  accrete/contrib/user/migrations/0001_initial.py,sha256=JWfM9PcMDfkJUdCjLWuWieGs6643qP0KdbCyr5uAZoY,2950
@@ -187,8 +188,8 @@ accrete/migrations/0001_initial.py,sha256=azThbc8otEhxJwo8BIgOt5eC30mxXhKJLBAazZ
187
188
  accrete/migrations/0002_initial.py,sha256=dFOM7kdHlx7pVAh8cTDlZMtciN4O9Z547HAzEKnygZE,1628
188
189
  accrete/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
189
190
  accrete/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
190
- accrete/utils/dates.py,sha256=XI58CqabLCC-Sg6qo5TPWh-pHuuZfDdGDU6KQeAMlGo,1066
191
- accrete-0.0.23.dist-info/METADATA,sha256=bdnglU1DO7FoOvo9ruN2r7cDhsQcRFqkLQJq9v9XG0g,4846
192
- accrete-0.0.23.dist-info/WHEEL,sha256=9QBuHhg6FNW7lppboF2vKVbCGTVzsFykgRQjjlajrhA,87
193
- accrete-0.0.23.dist-info/licenses/LICENSE,sha256=_7laeMIHnsd3Y2vJEXDYXq_PEXxIcjgJsGt8UIKTRWc,1057
194
- accrete-0.0.23.dist-info/RECORD,,
191
+ accrete/utils/dates.py,sha256=yuf8bqhdjOBarxFFl2hqepbbbuFHQgoe2BNar6-4n8g,1068
192
+ accrete-0.0.25.dist-info/METADATA,sha256=jFe1ctW_hvX5Syg23s5hNQxxaVDGqz8X1MlLfZKGpg8,4846
193
+ accrete-0.0.25.dist-info/WHEEL,sha256=mRYSEL3Ih6g5a_CVMIcwiF__0Ae4_gLYh01YFNwiq1k,87
194
+ accrete-0.0.25.dist-info/licenses/LICENSE,sha256=_7laeMIHnsd3Y2vJEXDYXq_PEXxIcjgJsGt8UIKTRWc,1057
195
+ accrete-0.0.25.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.18.0
2
+ Generator: hatchling 1.21.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
accrete/shortcuts.py DELETED
@@ -1,8 +0,0 @@
1
- from .tenant import get_tenant, set_tenant, get_member, set_member, Unscoped
2
- from .decorators import tenant_required
3
- from .views import TenantRequiredMixin
4
- from .forms import save_form
5
-
6
-
7
- def unscoped():
8
- return Unscoped(get_tenant())