Skip to content

Commit ec469e1

Browse files
authored
Merge pull request #982 from weni-ai/feature/add-marketing-role-permission
feat: add marketing role permission
2 parents 3eaab84 + a9fe1b5 commit ec469e1

File tree

5 files changed

+207
-5
lines changed

5 files changed

+207
-5
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Generated by Django 3.2.23 on 2025-12-03 18:00
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("common", "0093_project_language"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="organizationauthorization",
15+
name="role",
16+
field=models.PositiveIntegerField(
17+
choices=[
18+
(0, "not set"),
19+
(2, "contributor"),
20+
(3, "admin"),
21+
(1, "viewer"),
22+
(4, "financial"),
23+
(5, "support"),
24+
(6, "marketing"),
25+
],
26+
default=0,
27+
verbose_name="role",
28+
),
29+
),
30+
migrations.AlterField(
31+
model_name="projectauthorization",
32+
name="role",
33+
field=models.PositiveIntegerField(
34+
choices=[
35+
(0, "not set"),
36+
(1, "viewer"),
37+
(2, "contributor"),
38+
(3, "moderator"),
39+
(4, "support"),
40+
(5, "Chat user"),
41+
(6, "marketing"),
42+
],
43+
default=0,
44+
verbose_name="role",
45+
),
46+
),
47+
migrations.AlterField(
48+
model_name="requestpermissionorganization",
49+
name="role",
50+
field=models.PositiveIntegerField(
51+
choices=[
52+
(0, "not set"),
53+
(2, "contributor"),
54+
(3, "admin"),
55+
(1, "viewer"),
56+
(4, "financial"),
57+
(5, "support"),
58+
(6, "marketing"),
59+
],
60+
default=0,
61+
verbose_name="role",
62+
),
63+
),
64+
migrations.AlterField(
65+
model_name="requestpermissionproject",
66+
name="role",
67+
field=models.PositiveIntegerField(
68+
choices=[
69+
(0, "not set"),
70+
(1, "viewer"),
71+
(2, "contributor"),
72+
(3, "moderator"),
73+
(4, "support"),
74+
(5, "Chat user"),
75+
(6, "marketing"),
76+
],
77+
default=0,
78+
verbose_name="role",
79+
),
80+
),
81+
]

connect/common/models.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,11 @@ def create_ai_organization(self, user_email: str):
301301

302302

303303
class OrganizationLevelRole(Enum):
304-
NOTHING, VIEWER, CONTRIBUTOR, ADMIN, FINANCIAL, SUPPORT = list(range(6))
304+
NOTHING, VIEWER, CONTRIBUTOR, ADMIN, FINANCIAL, SUPPORT, MARKETING = list(range(7))
305305

306306

307307
class OrganizationRole(Enum):
308-
NOT_SETTED, VIEWER, CONTRIBUTOR, ADMIN, FINANCIAL, SUPPORT = list(range(6))
308+
NOT_SETTED, VIEWER, CONTRIBUTOR, ADMIN, FINANCIAL, SUPPORT, MARKETING = list(range(7))
309309

310310

311311
class OrganizationAuthorization(models.Model):
@@ -321,6 +321,7 @@ class Meta:
321321
(OrganizationRole.VIEWER.value, _("viewer")),
322322
(OrganizationRole.FINANCIAL.value, _("financial")),
323323
(OrganizationRole.SUPPORT.value, _("support")),
324+
(OrganizationRole.MARKETING.value, _("marketing")),
324325
]
325326

326327
uuid = models.UUIDField(
@@ -359,6 +360,9 @@ def level(self):
359360
if self.role == OrganizationRole.SUPPORT.value:
360361
return OrganizationLevelRole.SUPPORT.value
361362

363+
if self.role == OrganizationRole.MARKETING.value:
364+
return OrganizationLevelRole.MARKETING.value
365+
362366
@property
363367
def can_read(self):
364368
return self.level in [
@@ -367,6 +371,7 @@ def can_read(self):
367371
OrganizationLevelRole.ADMIN.value,
368372
OrganizationLevelRole.VIEWER.value,
369373
OrganizationLevelRole.SUPPORT.value,
374+
OrganizationLevelRole.MARKETING.value,
370375
]
371376

372377
@property
@@ -375,13 +380,15 @@ def can_contribute(self):
375380
OrganizationLevelRole.CONTRIBUTOR.value,
376381
OrganizationLevelRole.ADMIN.value,
377382
OrganizationLevelRole.SUPPORT.value,
383+
OrganizationLevelRole.MARKETING.value,
378384
]
379385

380386
@property
381387
def can_write(self):
382388
return self.level in [
383389
OrganizationLevelRole.ADMIN.value,
384390
OrganizationLevelRole.SUPPORT.value,
391+
OrganizationLevelRole.MARKETING.value,
385392
]
386393

387394
@property
@@ -401,6 +408,7 @@ def can_contribute_billing(self):
401408
OrganizationLevelRole.ADMIN.value,
402409
OrganizationLevelRole.FINANCIAL.value,
403410
OrganizationLevelRole.SUPPORT.value,
411+
OrganizationLevelRole.MARKETING.value,
404412
]
405413

406414
@property
@@ -877,11 +885,11 @@ def level(self):
877885

878886

879887
class ProjectRole(Enum):
880-
NOT_SETTED, VIEWER, CONTRIBUTOR, MODERATOR, SUPPORT, CHAT_USER = list(range(6))
888+
NOT_SETTED, VIEWER, CONTRIBUTOR, MODERATOR, SUPPORT, CHAT_USER, MARKETING = list(range(7))
881889

882890

883891
class ProjectRoleLevel(Enum):
884-
NOTHING, VIEWER, CONTRIBUTOR, MODERATOR, SUPPORT, CHAT_USER = list(range(6))
892+
NOTHING, VIEWER, CONTRIBUTOR, MODERATOR, SUPPORT, CHAT_USER, MARKETING = list(range(7))
885893

886894

887895
class ProjectAuthorization(models.Model):
@@ -895,6 +903,7 @@ class Meta:
895903
(ProjectRole.MODERATOR.value, _("moderator")),
896904
(ProjectRole.SUPPORT.value, _("support")),
897905
(ProjectRole.CHAT_USER.value, _("Chat user")),
906+
(ProjectRole.MARKETING.value, _("marketing")),
898907
]
899908
uuid = models.UUIDField(
900909
_("UUID"), primary_key=True, default=uuid4.uuid4, editable=False
@@ -932,19 +941,23 @@ def level(self):
932941
return ProjectRoleLevel.VIEWER.value
933942
elif self.role == ProjectRole.SUPPORT.value:
934943
return ProjectRoleLevel.SUPPORT.value
944+
elif self.role == ProjectRole.MARKETING.value:
945+
return ProjectRoleLevel.MARKETING.value
935946

936947
@property
937948
def is_moderator(self):
938949
return self.level in [
939950
ProjectRoleLevel.MODERATOR.value,
940951
ProjectRoleLevel.SUPPORT.value,
952+
ProjectRoleLevel.MARKETING.value,
941953
]
942954

943955
@property
944956
def can_write(self):
945957
return self.level in [
946958
ProjectRoleLevel.MODERATOR.value,
947959
ProjectRoleLevel.SUPPORT.value,
960+
ProjectRoleLevel.MARKETING.value,
948961
]
949962

950963
@property
@@ -955,6 +968,7 @@ def can_read(self):
955968
ProjectRoleLevel.VIEWER.value,
956969
ProjectRoleLevel.SUPPORT.value,
957970
ProjectRoleLevel.CHAT_USER.value,
971+
ProjectRoleLevel.MARKETING.value,
958972
]
959973

960974
@property
@@ -963,6 +977,7 @@ def can_contribute(self):
963977
ProjectRoleLevel.MODERATOR.value,
964978
ProjectRoleLevel.CONTRIBUTOR.value,
965979
ProjectRoleLevel.SUPPORT.value,
980+
ProjectRoleLevel.MARKETING.value,
966981
]
967982

968983

connect/sentry/apps.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ def ready(self) -> None:
1616
if not settings.USE_SENTRY:
1717
return
1818

19-
if settings.USE_SENTRY:
2019
sentry_sdk.init(
2120
dsn=settings.SENTRY_URL,
2221
integrations=[DjangoIntegration()],

connect/usecases/authorizations/tests.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
RequestPermissionProject,
1414
OrganizationAuthorization,
1515
ProjectAuthorization,
16+
OrganizationRole,
17+
ProjectRole,
1618
)
1719

1820
from connect.usecases.authorizations.create import CreateAuthorizationUseCase
@@ -423,3 +425,107 @@ def test_create_org(self):
423425

424426
self.request_permission_project(data)
425427
self.assertEquals(ProjectAuthorization.objects.count(), 2)
428+
429+
430+
class MarketingRoleTestCase(TestCase, TestCaseSetUp):
431+
"""Tests for the MARKETING role (role=6) at organization and project levels."""
432+
433+
def setUp(self):
434+
self.superuser = User.objects.create(
435+
email="super@test.user", username="superuser"
436+
)
437+
self.user = User.objects.create(
438+
email="marketing@test.user", username="MarketingTestUser", has_2fa=True
439+
)
440+
self.org = Organization.objects.create(
441+
name="Marketing test org",
442+
description="Marketing test org",
443+
inteligence_organization=1,
444+
organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY,
445+
organization_billing__plan=BillingPlan.PLAN_TRIAL,
446+
)
447+
self.project = self.org.project.create(name="Marketing test project")
448+
449+
def test_marketing_role_value(self):
450+
"""Test that MARKETING role has correct enum value."""
451+
self.assertEqual(OrganizationRole.MARKETING.value, 6)
452+
self.assertEqual(ProjectRole.MARKETING.value, 6)
453+
454+
def test_marketing_org_authorization_properties(self):
455+
"""Test that MARKETING role has correct permission properties at org level."""
456+
role = OrganizationRole.MARKETING.value
457+
self.create_auth(self.user, self.org, role)
458+
authorization = self.org.authorizations.get(user=self.user)
459+
460+
self.assertEqual(authorization.role, 6)
461+
self.assertTrue(authorization.can_read)
462+
self.assertTrue(authorization.can_contribute)
463+
self.assertTrue(authorization.can_write)
464+
self.assertFalse(authorization.is_admin)
465+
466+
def test_marketing_role_maps_to_project(self):
467+
"""Test that MARKETING org role propagates correctly to project."""
468+
role = OrganizationRole.MARKETING.value
469+
self.create_auth(self.user, self.org, role, publish_message=False)
470+
471+
project_auth = self.project.get_user_authorization(self.user)
472+
self.assertEqual(project_auth.role, ProjectRole.MARKETING.value)
473+
474+
def test_marketing_project_authorization_properties(self):
475+
"""Test that MARKETING role has correct permission properties at project level."""
476+
role = OrganizationRole.MARKETING.value
477+
self.create_auth(self.user, self.org, role, publish_message=False)
478+
479+
project_auth = self.project.get_user_authorization(self.user)
480+
481+
self.assertEqual(project_auth.role, 6)
482+
self.assertTrue(project_auth.can_read)
483+
self.assertTrue(project_auth.can_contribute)
484+
self.assertTrue(project_auth.can_write)
485+
self.assertTrue(project_auth.is_moderator)
486+
self.assertFalse(project_auth.is_admin)
487+
488+
def test_update_to_marketing_role(self):
489+
"""Test updating an existing authorization to MARKETING role."""
490+
# First create with CONTRIBUTOR role
491+
initial_role = OrganizationRole.CONTRIBUTOR.value
492+
self.create_auth(self.user, self.org, initial_role)
493+
494+
# Update to MARKETING role
495+
update_role = OrganizationRole.MARKETING.value
496+
auth_dto = UpdateAuthorizationDTO(
497+
user_email=self.user.email,
498+
org_uuid=str(self.org.uuid),
499+
role=update_role,
500+
request_user=self.superuser.email,
501+
)
502+
503+
usecase = UpdateAuthorizationUseCase(message_publisher=MockRabbitMQPublisher())
504+
authorization = usecase.update_authorization(auth_dto)
505+
506+
project_auth = self.project.get_user_authorization(self.user)
507+
508+
self.assertEqual(authorization.role, update_role)
509+
self.assertEqual(project_auth.role, ProjectRole.MARKETING.value)
510+
511+
def test_create_marketing_authorization_for_single_project(self):
512+
"""Test creating MARKETING authorization for a single project."""
513+
# First create superuser auth to have permission
514+
self.org.authorizations.create(user=self.superuser, role=OrganizationRole.ADMIN.value)
515+
ProjectAuthorization.objects.create(
516+
user=self.superuser,
517+
project=self.project,
518+
role=ProjectRole.MODERATOR.value,
519+
)
520+
521+
role = ProjectRole.MARKETING.value
522+
auth_dto = CreateProjectAuthorizationDTO(
523+
user_email=self.user.email,
524+
project_uuid=str(self.project.uuid),
525+
role=role,
526+
created_by_email=self.superuser.email,
527+
)
528+
usecase = CreateAuthorizationUseCase(MockRabbitMQPublisher())
529+
project_auth = usecase.create_authorization_for_a_single_project(auth_dto)
530+
531+
self.assertEqual(project_auth.role, role)

connect/usecases/authorizations/usecase.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class AuthorizationUseCase:
2121
OrganizationRole.ADMIN.value: ProjectRole.MODERATOR.value,
2222
OrganizationRole.CONTRIBUTOR.value: ProjectRole.CONTRIBUTOR.value,
2323
OrganizationRole.SUPPORT.value: ProjectRole.SUPPORT.value,
24+
OrganizationRole.MARKETING.value: ProjectRole.MARKETING.value,
2425
}
2526

2627
def __init__(

0 commit comments

Comments
 (0)