Skip to content

Commit 1b98c97

Browse files
committed
adds no_implicit_role to always force a profile manager to accept requests
1 parent 5f6ec8d commit 1b98c97

File tree

13 files changed

+129
-37
lines changed

13 files changed

+129
-37
lines changed

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@
6161
# built documents.
6262
#
6363
# The short X.Y version.
64-
version = '1.1'
64+
version = '1.2'
6565
# The full version, including alpha/beta/rc tags.
66-
release = '1.1.7-dev'
66+
release = '1.2.0-dev'
6767

6868
# The language for content autogenerated by Sphinx. Refer to documentation
6969
# for a list of supported languages.

saas/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2025, DjaoDjin inc.
1+
# Copyright (c) 2026, DjaoDjin inc.
22
# All rights reserved.
33
#
44
# Redistribution and use in source and binary forms, with or without
@@ -26,4 +26,4 @@
2626
PEP 386-compliant version number for the saas django app.
2727
"""
2828

29-
__version__ = '1.1.7-dev'
29+
__version__ = '1.2.0-dev'

saas/api/agreements.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2025, DjaoDjin inc.
1+
# Copyright (c) 2026, DjaoDjin inc.
22
# All rights reserved.
33
#
44
# Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,8 @@
3030
from rest_framework.response import Response
3131

3232
from .serializers import (AgreementSerializer, AgreementCreateSerializer,
33-
AgreementDetailSerializer, AgreementUpdateSerializer)
33+
AgreementDetailSerializer, AgreementUpdateSerializer,
34+
PrivacyCookiesSerializer)
3435
from .. import settings
3536
from ..docs import extend_schema, OpenApiResponse
3637
from ..filters import OrderingFilter, SearchFilter
@@ -181,7 +182,7 @@ def create(self, request, *args, **kwargs):
181182
headers=headers)
182183

183184

184-
class AgreementDetailAPIView(generics.RetrieveAPIView):
185+
class AgreementDetailAPIView(CreateModelMixin, generics.RetrieveAPIView):
185186
"""
186187
Retrieves a legal agreement
187188
@@ -214,6 +215,13 @@ class AgreementDetailAPIView(generics.RetrieveAPIView):
214215
lookup_field = 'slug'
215216
lookup_url_kwarg = 'agreement'
216217

218+
def get_serializer_class(self):
219+
if self.request.method.lower() in ('post',):
220+
return PrivacyCookiesSerializer
221+
return super(AgreementDetailAPIView, self).get_serializer_class()
222+
223+
@extend_schema(responses={
224+
200: OpenApiResponse(AgreementDetailSerializer)})
217225
def post(self, request, *args, **kwargs):
218226
"""
219227
Update privacy settings
@@ -255,8 +263,7 @@ def post(self, request, *args, **kwargs):
255263
return self.get(request, *args, **kwargs)
256264

257265

258-
class AgreementUpdateAPIView(UpdateModelMixin, DestroyModelMixin,
259-
AgreementDetailAPIView):
266+
class AgreementUpdateAPIView(generics.RetrieveUpdateDestroyAPIView):
260267
"""
261268
Retrieves a legal agreement (broker)
262269
@@ -285,6 +292,8 @@ class AgreementUpdateAPIView(UpdateModelMixin, DestroyModelMixin,
285292
}
286293
"""
287294
serializer_class = AgreementDetailSerializer
295+
queryset = Agreement.objects.all()
296+
lookup_field = 'slug'
288297
lookup_url_kwarg = 'document'
289298

290299
def get_serializer_class(self):

saas/api/serializers.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2025, DjaoDjin inc.
1+
# Copyright (c) 2026, DjaoDjin inc.
22
# All rights reserved.
33
#
44
# Redistribution and use in source and binary forms, with or without
@@ -430,6 +430,17 @@ class MetricsSerializer(NoModelSerializer):
430430
help_text=_("Data series"))
431431

432432

433+
class PrivacyCookiesSerializer(NoModelSerializer):
434+
# matches `settings.PRIVACY_COOKIES_ENABLED`
435+
436+
analytics = serializers.BooleanField(required=False,
437+
help_text=_("True when analytics cookies are enabled"))
438+
social_media = serializers.BooleanField(required=False,
439+
help_text=_("True when social_media cookies are enabled"))
440+
advertising = serializers.BooleanField(required=False,
441+
help_text=_("True when advertising cookies are enabled"))
442+
443+
433444
class RefundChargeItemSerializer(NoModelSerializer):
434445
"""
435446
One item to refund on a `Charge`.
@@ -535,6 +546,8 @@ class OrganizationDetailSerializer(OrganizationSerializer):
535546
help_text=_("Zip/Postal code"))
536547
country = CountryField(required=False, allow_blank=True,
537548
help_text=_("Country as 2-letter code (ISO 3166-1)"))
549+
no_implicit_role = serializers.BooleanField(required=False, default=False,
550+
help_text=_("When `True`, the profile does not allow implicit roles"))
538551
is_bulk_buyer = serializers.BooleanField(required=False, default=False,
539552
help_text=_("Enable GroupBuy"))
540553
extra = ExtraField(required=False, allow_null=True,
@@ -548,8 +561,8 @@ class Meta(OrganizationSerializer.Meta):
548561
fields = OrganizationSerializer.Meta.fields + (
549562
'full_name', 'created_at', 'email', 'phone',
550563
'street_address', 'locality', 'region', 'postal_code', 'country',
551-
'default_timezone', 'is_provider', 'is_bulk_buyer', 'extra',
552-
'detail')
564+
'default_timezone', 'no_implicit_role', 'is_provider',
565+
'is_bulk_buyer', 'extra', 'detail')
553566
read_only_fields = ('created_at', 'detail')
554567

555568

saas/api/transactions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ def post(self, request, *args, **kwargs):
571571
.. code-block:: json
572572
573573
{
574-
"plan": "basic",
574+
"plan": "premium",
575575
"use": "requests"
576576
}
577577

saas/forms.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ class OrganizationForm(PostalFormMixin, forms.ModelForm):
189189
class Meta:
190190
model = get_organization_model()
191191
fields = ('slug', 'full_name', 'email', 'phone', 'country',
192-
'region', 'locality', 'street_address', 'postal_code')
192+
'region', 'locality', 'street_address', 'postal_code',
193+
'no_implicit_role')
193194
widgets = {'country': forms.widgets.Select(choices=countries)}
194195

195196
def __init__(self, *args, **kwargs):

saas/migrations/0006_0_3_0.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Migration(migrations.Migration):
2929
('created_at', models.DateTimeField(auto_now_add=True,
3030
help_text='Date/time of creation (in ISO format)')),
3131
('use_amount', models.PositiveIntegerField(default=0,
32-
help_text='Amount of the use charge in plan currency unit')),
32+
help_text='Amount per unit defined by the provider of the use charge in plan currency unit (ex: $0.01/request)')),
3333
('extra', models.TextField(null=True)),
3434
],
3535
bases=(saas.utils.SlugTitleMixin, models.Model),

saas/migrations/0022_v1_2_0.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.27 on 2026-02-14 15:59
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('saas', '0021_v1_0_0'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='organization',
15+
name='no_implicit_role',
16+
field=models.BooleanField(default=False, help_text='The profile does not allow implicit roles'),
17+
),
18+
]

saas/models.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2025, DjaoDjin inc.
1+
# Copyright (c) 2026, DjaoDjin inc.
22
# All rights reserved.
33
#
44
# Redistribution and use in source and binary forms, with or without
@@ -168,7 +168,8 @@ def accessible_by(self, user, role_descr=None, includes_personal=True):
168168
def find_candidates_by_domain(self, domain):
169169
if domain and domain[0] != '@':
170170
domain = '@' + domain
171-
return self.filter(is_active=True, email__endswith=domain)
171+
return self.filter(is_active=True, email__endswith=domain).exclude(
172+
no_implicit_role=True)
172173

173174
def find_candidates(self, full_name, user=None):
174175
"""
@@ -285,6 +286,9 @@ class AbstractOrganization(models.Model):
285286
is_provider = models.BooleanField(default=False,
286287
help_text=_("The profile can fulfill the provider side"\
287288
" of a subscription."))
289+
no_implicit_role = models.BooleanField(default=False,
290+
help_text=_("The profile does not allow implicit roles"))
291+
288292
default_timezone = models.CharField(
289293
max_length=100, default=settings.TIME_ZONE,
290294
help_text=_("Timezone to use when reporting metrics"))

saas/static/js/djaodjin-resources-vue.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const DESC_SORT_PRE = '-';
2222

2323
/** Displays notification messages to the user
2424
25-
requires `jQuery`, showErrorMessages
25+
requires `jQuery`, djaodjin-resources.js exports
2626
optional toastr
2727
*/
2828
var messagesMixin = {
@@ -111,7 +111,10 @@ var paramsMixin = {
111111
computed: {
112112
_start_at: {
113113
get: function() {
114-
return this.asDateInputField(this.params.start_at);
114+
if( this.params.start_at ) {
115+
return this.asDateInputField(this.params.start_at);
116+
}
117+
return null;
115118
},
116119
set: function(newVal) {
117120
if( newVal ) {
@@ -135,7 +138,10 @@ var paramsMixin = {
135138
//
136139
// const dateValue = moment(this.params.ends_at).add(1,'days');
137140
// return dateValue.isValid() ? dateValue.format("YYYY-MM-DD") : null;
138-
return this.asDateInputField(this.params.ends_at);
141+
if( this.params.ends_at ) {
142+
return this.asDateInputField(this.params.ends_at);
143+
}
144+
return null;
139145
},
140146
set: function(newVal) {
141147
if( newVal ) {

0 commit comments

Comments
 (0)