Browse Source
feat: implement account role system with custom models, admin integration, and settings
main
feat: implement account role system with custom models, admin integration, and settings
main
9 changed files with 893 additions and 11 deletions
-
1apps/account/admin/__init__.py
-
142apps/account/admin/role.py
-
24apps/account/admin/user.py
-
387apps/account/management/commands/seed_roles.py
-
88apps/account/migrations/0005_role_user_custom_permissions_user_role.py
-
2apps/account/models/__init__.py
-
188apps/account/models/role.py
-
55apps/account/models/user.py
-
15config/settings/base.py
@ -0,0 +1,142 @@ |
|||
from django.contrib import admin |
|||
from django.utils.translation import gettext_lazy as _ |
|||
from unfold.admin import ModelAdmin |
|||
from unfold.decorators import display |
|||
|
|||
from apps.account.models.role import Role, PERMISSION_CATEGORIES |
|||
from utils.admin import project_admin_site |
|||
|
|||
|
|||
class RoleAdmin(ModelAdmin): |
|||
list_display = ('name', 'slug', 'is_default', 'is_system', 'users_count', 'updated_at') |
|||
list_filter = ('is_default', 'is_system') |
|||
search_fields = ('name', 'slug', 'description') |
|||
ordering = ('name',) |
|||
readonly_fields = ('created_at', 'updated_at') |
|||
|
|||
fieldsets = ( |
|||
(None, { |
|||
"fields": ( |
|||
("name", "slug"), |
|||
("is_default", "is_system"), |
|||
"description", |
|||
), |
|||
}), |
|||
(_("Identity & Profiles"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("is_searchable", "can_submit_verification"), |
|||
("can_view_full_profiles", "can_manage_institutions"), |
|||
), |
|||
}), |
|||
(_("Chat & Communications"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_send_direct_messages", "can_create_group_chats"), |
|||
("can_start_video_calls", "can_moderate_chat"), |
|||
("is_chat_muted",), |
|||
), |
|||
}), |
|||
(_("CMS & Articles"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_create_posts", "can_publish_posts_directly"), |
|||
("can_edit_own_posts", "can_delete_own_posts"), |
|||
("can_comment",), |
|||
), |
|||
}), |
|||
(_("LMS & Academics"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_enroll_courses", "can_create_courses"), |
|||
("can_publish_courses", "can_issue_certificates"), |
|||
("can_grade_submissions", "has_premium_lms_access"), |
|||
), |
|||
}), |
|||
(_("Meetings"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_request_meetings", "can_accept_meetings"), |
|||
), |
|||
}), |
|||
(_("Events"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_register_events", "can_create_events"), |
|||
("can_publish_events", "can_checkin_attendees"), |
|||
("can_export_attendee_list",), |
|||
), |
|||
}), |
|||
(_("Community Projects"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_volunteer", "can_create_projects"), |
|||
("can_manage_project_tasks", "can_approve_projects"), |
|||
), |
|||
}), |
|||
(_("Donations & Charity"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_make_donations", "can_create_donation_campaigns"), |
|||
("can_view_donation_reports",), |
|||
), |
|||
}), |
|||
(_("Support & Tickets"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_create_tickets", "can_reply_tickets"), |
|||
("can_manage_tickets",), |
|||
), |
|||
}), |
|||
(_("Dynamic Forms"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_submit_forms", "can_create_forms"), |
|||
("can_export_form_data",), |
|||
), |
|||
}), |
|||
(_("Diplomacy & Institutional"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_view_diplomatic_reports", "can_create_diplomatic_reports"), |
|||
), |
|||
}), |
|||
(_("Administration & Security"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("can_access_admin_panel", "can_manage_users"), |
|||
("can_ban_users", "can_view_analytics"), |
|||
), |
|||
}), |
|||
(_("Metadata"), { |
|||
"classes": ["tab"], |
|||
"fields": ( |
|||
("created_at", "updated_at"), |
|||
), |
|||
}), |
|||
) |
|||
|
|||
@display(description=_("Assigned Users")) |
|||
def users_count(self, obj): |
|||
count = obj.users.count() |
|||
return f"{count} users" |
|||
|
|||
def has_add_permission(self, request): |
|||
return bool(request.user and request.user.is_authenticated and (request.user.is_staff or request.user.is_superuser or request.user.can_access_admin_panel())) |
|||
|
|||
def has_change_permission(self, request, obj=None): |
|||
return bool(request.user and request.user.is_authenticated and (request.user.is_staff or request.user.is_superuser or request.user.can_access_admin_panel())) |
|||
|
|||
def has_delete_permission(self, request, obj=None): |
|||
if obj and getattr(obj, 'is_system', False): |
|||
return False # Protect core default roles from accidental deletion |
|||
return bool(request.user and request.user.is_authenticated and (request.user.is_staff or request.user.is_superuser or request.user.can_access_admin_panel())) |
|||
|
|||
|
|||
# Register in both default and custom admin sites |
|||
try: |
|||
admin.site.register(Role, RoleAdmin) |
|||
except admin.sites.AlreadyRegistered: |
|||
pass |
|||
|
|||
project_admin_site.register(Role, RoleAdmin) |
|||
@ -0,0 +1,387 @@ |
|||
from django.core.management.base import BaseCommand |
|||
from django.db import transaction |
|||
from apps.account.models.role import Role, ALL_PERMISSION_FIELDS |
|||
|
|||
|
|||
DEFAULT_ROLES = [ |
|||
{ |
|||
"name": "User", |
|||
"slug": "user", |
|||
"description": "Standard community member with basic profile, messaging, learning, and participation privileges.", |
|||
"is_default": True, |
|||
"is_system": True, |
|||
"permissions": { |
|||
"is_searchable": True, |
|||
"can_submit_verification": True, |
|||
"can_view_full_profiles": True, |
|||
"can_manage_institutions": False, |
|||
"can_send_direct_messages": True, |
|||
"can_create_group_chats": True, |
|||
"can_start_video_calls": False, |
|||
"can_moderate_chat": False, |
|||
"is_chat_muted": False, |
|||
"can_create_posts": True, |
|||
"can_publish_posts_directly": False, |
|||
"can_edit_own_posts": True, |
|||
"can_delete_own_posts": True, |
|||
"can_comment": True, |
|||
"can_enroll_courses": True, |
|||
"can_create_courses": False, |
|||
"can_publish_courses": False, |
|||
"can_issue_certificates": False, |
|||
"can_grade_submissions": False, |
|||
"has_premium_lms_access": False, |
|||
"can_request_meetings": True, |
|||
"can_accept_meetings": False, |
|||
"can_register_events": True, |
|||
"can_create_events": False, |
|||
"can_publish_events": False, |
|||
"can_checkin_attendees": False, |
|||
"can_export_attendee_list": False, |
|||
"can_volunteer": True, |
|||
"can_create_projects": False, |
|||
"can_manage_project_tasks": False, |
|||
"can_approve_projects": False, |
|||
"can_make_donations": True, |
|||
"can_create_donation_campaigns": False, |
|||
"can_view_donation_reports": False, |
|||
"can_create_tickets": True, |
|||
"can_reply_tickets": True, |
|||
"can_manage_tickets": False, |
|||
"can_submit_forms": True, |
|||
"can_create_forms": False, |
|||
"can_export_form_data": False, |
|||
"can_view_diplomatic_reports": False, |
|||
"can_create_diplomatic_reports": False, |
|||
"can_access_admin_panel": False, |
|||
"can_manage_users": False, |
|||
"can_ban_users": False, |
|||
"can_view_analytics": False, |
|||
} |
|||
}, |
|||
{ |
|||
"name": "Verified User", |
|||
"slug": "verified_user", |
|||
"description": "Verified community member with authenticated identity, video calling, and direct content publishing.", |
|||
"is_default": False, |
|||
"is_system": True, |
|||
"permissions": { |
|||
"is_searchable": True, |
|||
"can_submit_verification": True, |
|||
"can_view_full_profiles": True, |
|||
"can_manage_institutions": False, |
|||
"can_send_direct_messages": True, |
|||
"can_create_group_chats": True, |
|||
"can_start_video_calls": True, |
|||
"can_moderate_chat": False, |
|||
"is_chat_muted": False, |
|||
"can_create_posts": True, |
|||
"can_publish_posts_directly": True, |
|||
"can_edit_own_posts": True, |
|||
"can_delete_own_posts": True, |
|||
"can_comment": True, |
|||
"can_enroll_courses": True, |
|||
"can_create_courses": False, |
|||
"can_publish_courses": False, |
|||
"can_issue_certificates": False, |
|||
"can_grade_submissions": False, |
|||
"has_premium_lms_access": True, |
|||
"can_request_meetings": True, |
|||
"can_accept_meetings": False, |
|||
"can_register_events": True, |
|||
"can_create_events": True, |
|||
"can_publish_events": False, |
|||
"can_checkin_attendees": False, |
|||
"can_export_attendee_list": False, |
|||
"can_volunteer": True, |
|||
"can_create_projects": False, |
|||
"can_manage_project_tasks": False, |
|||
"can_approve_projects": False, |
|||
"can_make_donations": True, |
|||
"can_create_donation_campaigns": False, |
|||
"can_view_donation_reports": False, |
|||
"can_create_tickets": True, |
|||
"can_reply_tickets": True, |
|||
"can_manage_tickets": False, |
|||
"can_submit_forms": True, |
|||
"can_create_forms": False, |
|||
"can_export_form_data": False, |
|||
"can_view_diplomatic_reports": False, |
|||
"can_create_diplomatic_reports": False, |
|||
"can_access_admin_panel": False, |
|||
"can_manage_users": False, |
|||
"can_ban_users": False, |
|||
"can_view_analytics": False, |
|||
} |
|||
}, |
|||
{ |
|||
"name": "Institution Admin", |
|||
"slug": "institution_admin", |
|||
"description": "Administrator of an Islamic center, university, or institution with management over courses, events, meetings, and campaigns.", |
|||
"is_default": False, |
|||
"is_system": True, |
|||
"permissions": { |
|||
"is_searchable": True, |
|||
"can_submit_verification": True, |
|||
"can_view_full_profiles": True, |
|||
"can_manage_institutions": True, |
|||
"can_send_direct_messages": True, |
|||
"can_create_group_chats": True, |
|||
"can_start_video_calls": True, |
|||
"can_moderate_chat": False, |
|||
"is_chat_muted": False, |
|||
"can_create_posts": True, |
|||
"can_publish_posts_directly": True, |
|||
"can_edit_own_posts": True, |
|||
"can_delete_own_posts": True, |
|||
"can_comment": True, |
|||
"can_enroll_courses": True, |
|||
"can_create_courses": True, |
|||
"can_publish_courses": True, |
|||
"can_issue_certificates": True, |
|||
"can_grade_submissions": True, |
|||
"has_premium_lms_access": True, |
|||
"can_request_meetings": True, |
|||
"can_accept_meetings": True, |
|||
"can_register_events": True, |
|||
"can_create_events": True, |
|||
"can_publish_events": True, |
|||
"can_checkin_attendees": True, |
|||
"can_export_attendee_list": True, |
|||
"can_volunteer": True, |
|||
"can_create_projects": True, |
|||
"can_manage_project_tasks": True, |
|||
"can_approve_projects": False, |
|||
"can_make_donations": True, |
|||
"can_create_donation_campaigns": True, |
|||
"can_view_donation_reports": True, |
|||
"can_create_tickets": True, |
|||
"can_reply_tickets": True, |
|||
"can_manage_tickets": False, |
|||
"can_submit_forms": True, |
|||
"can_create_forms": True, |
|||
"can_export_form_data": True, |
|||
"can_view_diplomatic_reports": True, |
|||
"can_create_diplomatic_reports": False, |
|||
"can_access_admin_panel": False, |
|||
"can_manage_users": False, |
|||
"can_ban_users": False, |
|||
"can_view_analytics": False, |
|||
} |
|||
}, |
|||
{ |
|||
"name": "Institution Owner", |
|||
"slug": "institution_owner", |
|||
"description": "Owner / Primary Representative of an institution with full oversight over institutional projects, campaigns, and diplomacy.", |
|||
"is_default": False, |
|||
"is_system": True, |
|||
"permissions": { |
|||
"is_searchable": True, |
|||
"can_submit_verification": True, |
|||
"can_view_full_profiles": True, |
|||
"can_manage_institutions": True, |
|||
"can_send_direct_messages": True, |
|||
"can_create_group_chats": True, |
|||
"can_start_video_calls": True, |
|||
"can_moderate_chat": False, |
|||
"is_chat_muted": False, |
|||
"can_create_posts": True, |
|||
"can_publish_posts_directly": True, |
|||
"can_edit_own_posts": True, |
|||
"can_delete_own_posts": True, |
|||
"can_comment": True, |
|||
"can_enroll_courses": True, |
|||
"can_create_courses": True, |
|||
"can_publish_courses": True, |
|||
"can_issue_certificates": True, |
|||
"can_grade_submissions": True, |
|||
"has_premium_lms_access": True, |
|||
"can_request_meetings": True, |
|||
"can_accept_meetings": True, |
|||
"can_register_events": True, |
|||
"can_create_events": True, |
|||
"can_publish_events": True, |
|||
"can_checkin_attendees": True, |
|||
"can_export_attendee_list": True, |
|||
"can_volunteer": True, |
|||
"can_create_projects": True, |
|||
"can_manage_project_tasks": True, |
|||
"can_approve_projects": True, |
|||
"can_make_donations": True, |
|||
"can_create_donation_campaigns": True, |
|||
"can_view_donation_reports": True, |
|||
"can_create_tickets": True, |
|||
"can_reply_tickets": True, |
|||
"can_manage_tickets": False, |
|||
"can_submit_forms": True, |
|||
"can_create_forms": True, |
|||
"can_export_form_data": True, |
|||
"can_view_diplomatic_reports": True, |
|||
"can_create_diplomatic_reports": True, |
|||
"can_access_admin_panel": False, |
|||
"can_manage_users": False, |
|||
"can_ban_users": False, |
|||
"can_view_analytics": False, |
|||
} |
|||
}, |
|||
{ |
|||
"name": "Content Moderator", |
|||
"slug": "content_moderator", |
|||
"description": "Community moderator responsible for chat safety, content review, and ticket management.", |
|||
"is_default": False, |
|||
"is_system": True, |
|||
"permissions": { |
|||
"is_searchable": True, |
|||
"can_submit_verification": True, |
|||
"can_view_full_profiles": True, |
|||
"can_manage_institutions": False, |
|||
"can_send_direct_messages": True, |
|||
"can_create_group_chats": True, |
|||
"can_start_video_calls": False, |
|||
"can_moderate_chat": True, |
|||
"is_chat_muted": False, |
|||
"can_create_posts": True, |
|||
"can_publish_posts_directly": True, |
|||
"can_edit_own_posts": True, |
|||
"can_delete_own_posts": True, |
|||
"can_comment": True, |
|||
"can_enroll_courses": True, |
|||
"can_create_courses": False, |
|||
"can_publish_courses": False, |
|||
"can_issue_certificates": False, |
|||
"can_grade_submissions": False, |
|||
"has_premium_lms_access": False, |
|||
"can_request_meetings": True, |
|||
"can_accept_meetings": False, |
|||
"can_register_events": True, |
|||
"can_create_events": False, |
|||
"can_publish_events": False, |
|||
"can_checkin_attendees": False, |
|||
"can_export_attendee_list": False, |
|||
"can_volunteer": True, |
|||
"can_create_projects": False, |
|||
"can_manage_project_tasks": False, |
|||
"can_approve_projects": False, |
|||
"can_make_donations": True, |
|||
"can_create_donation_campaigns": False, |
|||
"can_view_donation_reports": False, |
|||
"can_create_tickets": True, |
|||
"can_reply_tickets": True, |
|||
"can_manage_tickets": True, |
|||
"can_submit_forms": True, |
|||
"can_create_forms": False, |
|||
"can_export_form_data": False, |
|||
"can_view_diplomatic_reports": False, |
|||
"can_create_diplomatic_reports": False, |
|||
"can_access_admin_panel": True, |
|||
"can_manage_users": False, |
|||
"can_ban_users": False, |
|||
"can_view_analytics": False, |
|||
} |
|||
}, |
|||
{ |
|||
"name": "Regional Admin", |
|||
"slug": "regional_admin", |
|||
"description": "Regional supervisor with authority over regional institutions, user accounts, and community analytics.", |
|||
"is_default": False, |
|||
"is_system": True, |
|||
"permissions": { |
|||
"is_searchable": True, |
|||
"can_submit_verification": True, |
|||
"can_view_full_profiles": True, |
|||
"can_manage_institutions": True, |
|||
"can_send_direct_messages": True, |
|||
"can_create_group_chats": True, |
|||
"can_start_video_calls": True, |
|||
"can_moderate_chat": True, |
|||
"is_chat_muted": False, |
|||
"can_create_posts": True, |
|||
"can_publish_posts_directly": True, |
|||
"can_edit_own_posts": True, |
|||
"can_delete_own_posts": True, |
|||
"can_comment": True, |
|||
"can_enroll_courses": True, |
|||
"can_create_courses": True, |
|||
"can_publish_courses": True, |
|||
"can_issue_certificates": True, |
|||
"can_grade_submissions": True, |
|||
"has_premium_lms_access": True, |
|||
"can_request_meetings": True, |
|||
"can_accept_meetings": True, |
|||
"can_register_events": True, |
|||
"can_create_events": True, |
|||
"can_publish_events": True, |
|||
"can_checkin_attendees": True, |
|||
"can_export_attendee_list": True, |
|||
"can_volunteer": True, |
|||
"can_create_projects": True, |
|||
"can_manage_project_tasks": True, |
|||
"can_approve_projects": True, |
|||
"can_make_donations": True, |
|||
"can_create_donation_campaigns": True, |
|||
"can_view_donation_reports": True, |
|||
"can_create_tickets": True, |
|||
"can_reply_tickets": True, |
|||
"can_manage_tickets": True, |
|||
"can_submit_forms": True, |
|||
"can_create_forms": True, |
|||
"can_export_form_data": True, |
|||
"can_view_diplomatic_reports": True, |
|||
"can_create_diplomatic_reports": True, |
|||
"can_access_admin_panel": True, |
|||
"can_manage_users": True, |
|||
"can_ban_users": True, |
|||
"can_view_analytics": True, |
|||
} |
|||
}, |
|||
{ |
|||
"name": "Super Administrator", |
|||
"slug": "super_admin", |
|||
"description": "Master administrative role with all permissions, total access control, and full platform authority.", |
|||
"is_default": False, |
|||
"is_system": True, |
|||
"permissions": {perm: (perm != "is_chat_muted") for perm in ALL_PERMISSION_FIELDS} |
|||
}, |
|||
] |
|||
|
|||
|
|||
class Command(BaseCommand): |
|||
help = "Seed the 7 default configurable system roles with their exact permission matrix" |
|||
|
|||
@transaction.atomic |
|||
def handle(self, *args, **options): |
|||
self.stdout.write("Seeding default system roles...") |
|||
created_count = 0 |
|||
updated_count = 0 |
|||
|
|||
for role_data in DEFAULT_ROLES: |
|||
perms = role_data.pop("permissions") |
|||
role, created = Role.objects.get_or_create( |
|||
slug=role_data["slug"], |
|||
defaults={ |
|||
"name": role_data["name"], |
|||
"description": role_data["description"], |
|||
"is_default": role_data["is_default"], |
|||
"is_system": role_data["is_system"], |
|||
**perms |
|||
} |
|||
) |
|||
|
|||
if not created: |
|||
# Update role configuration if existing |
|||
role.name = role_data["name"] |
|||
role.description = role_data["description"] |
|||
role.is_default = role_data["is_default"] |
|||
role.is_system = role_data["is_system"] |
|||
for perm, val in perms.items(): |
|||
setattr(role, perm, val) |
|||
role.save() |
|||
updated_count += 1 |
|||
self.stdout.write(self.style.SUCCESS(f" [✓] Updated role: {role.name} ({role.slug})")) |
|||
else: |
|||
created_count += 1 |
|||
self.stdout.write(self.style.SUCCESS(f" [+] Created role: {role.name} ({role.slug})")) |
|||
|
|||
self.stdout.write(self.style.SUCCESS( |
|||
f"Successfully finished seeding roles: {created_count} created, {updated_count} updated." |
|||
)) |
|||
@ -0,0 +1,88 @@ |
|||
# Generated by Django 4.2.30 on 2026-10-06 12:37 |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('account', '0004_user_address_user_institution_name_user_rank_and_more'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.CreateModel( |
|||
name='Role', |
|||
fields=[ |
|||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|||
('name', models.CharField(max_length=100, unique=True, verbose_name='Role Name')), |
|||
('slug', models.SlugField(blank=True, max_length=100, unique=True, verbose_name='Slug / Identifier')), |
|||
('description', models.TextField(blank=True, verbose_name='Description')), |
|||
('is_default', models.BooleanField(default=False, help_text='Automatically assigned to new registrations if no other role is selected.', verbose_name='Default Role for New Users')), |
|||
('is_system', models.BooleanField(default=False, help_text='Marks default system roles. Admins can configure permissions, but deletion is restricted.', verbose_name='System Core Role')), |
|||
('is_searchable', models.BooleanField(default=True, verbose_name='Appear in User Searches / Directory')), |
|||
('can_submit_verification', models.BooleanField(default=True, verbose_name='Submit Verification Documents')), |
|||
('can_view_full_profiles', models.BooleanField(default=True, verbose_name='View Full Profiles')), |
|||
('can_manage_institutions', models.BooleanField(default=False, verbose_name='Manage Institutions')), |
|||
('can_send_direct_messages', models.BooleanField(default=True, verbose_name='Send Direct Messages')), |
|||
('can_create_group_chats', models.BooleanField(default=True, verbose_name='Create Group Chats')), |
|||
('can_start_video_calls', models.BooleanField(default=False, verbose_name='Start Video Calls')), |
|||
('can_moderate_chat', models.BooleanField(default=False, verbose_name='Moderate Chat Rooms')), |
|||
('is_chat_muted', models.BooleanField(default=False, verbose_name='Chat Muted (Kill-switch)')), |
|||
('can_create_posts', models.BooleanField(default=True, verbose_name='Create Posts')), |
|||
('can_publish_posts_directly', models.BooleanField(default=False, verbose_name='Publish Posts Directly (Bypass Moderation)')), |
|||
('can_edit_own_posts', models.BooleanField(default=True, verbose_name='Edit Own Posts')), |
|||
('can_delete_own_posts', models.BooleanField(default=True, verbose_name='Delete Own Posts')), |
|||
('can_comment', models.BooleanField(default=True, verbose_name='Comment on Posts')), |
|||
('can_enroll_courses', models.BooleanField(default=True, verbose_name='Enroll in Courses')), |
|||
('can_create_courses', models.BooleanField(default=False, verbose_name='Create Courses')), |
|||
('can_publish_courses', models.BooleanField(default=False, verbose_name='Publish Courses Directly')), |
|||
('can_issue_certificates', models.BooleanField(default=False, verbose_name='Issue Certificates')), |
|||
('can_grade_submissions', models.BooleanField(default=False, verbose_name='Grade Submissions')), |
|||
('has_premium_lms_access', models.BooleanField(default=False, verbose_name='Premium LMS Access')), |
|||
('can_request_meetings', models.BooleanField(default=True, verbose_name='Send Meeting Requests')), |
|||
('can_accept_meetings', models.BooleanField(default=False, verbose_name='Accept / Host Meetings')), |
|||
('can_register_events', models.BooleanField(default=True, verbose_name='Register for Events')), |
|||
('can_create_events', models.BooleanField(default=False, verbose_name='Create Events')), |
|||
('can_publish_events', models.BooleanField(default=False, verbose_name='Publish Events Directly')), |
|||
('can_checkin_attendees', models.BooleanField(default=False, verbose_name='Check-in Attendees (Scan Tickets)')), |
|||
('can_export_attendee_list', models.BooleanField(default=False, verbose_name='Export Attendee List')), |
|||
('can_volunteer', models.BooleanField(default=True, verbose_name='Volunteer for Projects')), |
|||
('can_create_projects', models.BooleanField(default=False, verbose_name='Create Projects')), |
|||
('can_manage_project_tasks', models.BooleanField(default=False, verbose_name='Manage Project Tasks')), |
|||
('can_approve_projects', models.BooleanField(default=False, verbose_name='Approve Projects')), |
|||
('can_make_donations', models.BooleanField(default=True, verbose_name='Make Donations')), |
|||
('can_create_donation_campaigns', models.BooleanField(default=False, verbose_name='Create Donation Campaigns')), |
|||
('can_view_donation_reports', models.BooleanField(default=False, verbose_name='View Donation Reports')), |
|||
('can_create_tickets', models.BooleanField(default=True, verbose_name='Create Support Tickets')), |
|||
('can_reply_tickets', models.BooleanField(default=True, verbose_name='Reply to Support Tickets')), |
|||
('can_manage_tickets', models.BooleanField(default=False, verbose_name='Manage Support Tickets')), |
|||
('can_submit_forms', models.BooleanField(default=True, verbose_name='Submit Dynamic Forms')), |
|||
('can_create_forms', models.BooleanField(default=False, verbose_name='Create Dynamic Forms')), |
|||
('can_export_form_data', models.BooleanField(default=False, verbose_name='Export Form Responses')), |
|||
('can_view_diplomatic_reports', models.BooleanField(default=False, verbose_name='View Diplomatic Reports')), |
|||
('can_create_diplomatic_reports', models.BooleanField(default=False, verbose_name='Create Diplomatic Reports')), |
|||
('can_access_admin_panel', models.BooleanField(default=False, verbose_name='Access Admin Panel')), |
|||
('can_manage_users', models.BooleanField(default=False, verbose_name='Manage Users')), |
|||
('can_ban_users', models.BooleanField(default=False, verbose_name='Ban / Suspend Users')), |
|||
('can_view_analytics', models.BooleanField(default=False, verbose_name='View Analytics Dashboard')), |
|||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), |
|||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')), |
|||
], |
|||
options={ |
|||
'verbose_name': 'Role', |
|||
'verbose_name_plural': 'Roles', |
|||
'ordering': ('name',), |
|||
}, |
|||
), |
|||
migrations.AddField( |
|||
model_name='user', |
|||
name='custom_permissions', |
|||
field=models.JSONField(blank=True, default=dict, help_text='Dictionary of permission overrides: {permission_name: True/False}', verbose_name='Custom Permission Overrides'), |
|||
), |
|||
migrations.AddField( |
|||
model_name='user', |
|||
name='role', |
|||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='users', to='account.role', verbose_name='Assigned Role'), |
|||
), |
|||
] |
|||
@ -0,0 +1,188 @@ |
|||
from django.db import models |
|||
from django.utils.text import slugify |
|||
from django.utils.translation import gettext_lazy as _ |
|||
|
|||
|
|||
PERMISSION_CATEGORIES = { |
|||
_("Identity & Profiles"): [ |
|||
"is_searchable", |
|||
"can_submit_verification", |
|||
"can_view_full_profiles", |
|||
"can_manage_institutions", |
|||
], |
|||
_("Chat & Communications"): [ |
|||
"can_send_direct_messages", |
|||
"can_create_group_chats", |
|||
"can_start_video_calls", |
|||
"can_moderate_chat", |
|||
"is_chat_muted", |
|||
], |
|||
_("CMS & Articles"): [ |
|||
"can_create_posts", |
|||
"can_publish_posts_directly", |
|||
"can_edit_own_posts", |
|||
"can_delete_own_posts", |
|||
"can_comment", |
|||
], |
|||
_("LMS & Academics"): [ |
|||
"can_enroll_courses", |
|||
"can_create_courses", |
|||
"can_publish_courses", |
|||
"can_issue_certificates", |
|||
"can_grade_submissions", |
|||
"has_premium_lms_access", |
|||
], |
|||
_("Meetings"): [ |
|||
"can_request_meetings", |
|||
"can_accept_meetings", |
|||
], |
|||
_("Events"): [ |
|||
"can_register_events", |
|||
"can_create_events", |
|||
"can_publish_events", |
|||
"can_checkin_attendees", |
|||
"can_export_attendee_list", |
|||
], |
|||
_("Community Projects"): [ |
|||
"can_volunteer", |
|||
"can_create_projects", |
|||
"can_manage_project_tasks", |
|||
"can_approve_projects", |
|||
], |
|||
_("Donations & Charity"): [ |
|||
"can_make_donations", |
|||
"can_create_donation_campaigns", |
|||
"can_view_donation_reports", |
|||
], |
|||
_("Support & Tickets"): [ |
|||
"can_create_tickets", |
|||
"can_reply_tickets", |
|||
"can_manage_tickets", |
|||
], |
|||
_("Dynamic Forms"): [ |
|||
"can_submit_forms", |
|||
"can_create_forms", |
|||
"can_export_form_data", |
|||
], |
|||
_("Diplomacy & Institutional"): [ |
|||
"can_view_diplomatic_reports", |
|||
"can_create_diplomatic_reports", |
|||
], |
|||
_("Administration & Security"): [ |
|||
"can_access_admin_panel", |
|||
"can_manage_users", |
|||
"can_ban_users", |
|||
"can_view_analytics", |
|||
], |
|||
} |
|||
|
|||
ALL_PERMISSION_FIELDS = [perm for perms in PERMISSION_CATEGORIES.values() for perm in perms] |
|||
|
|||
|
|||
class Role(models.Model): |
|||
name = models.CharField(max_length=100, unique=True, verbose_name=_("Role Name")) |
|||
slug = models.SlugField(max_length=100, unique=True, blank=True, verbose_name=_("Slug / Identifier")) |
|||
description = models.TextField(blank=True, verbose_name=_("Description")) |
|||
is_default = models.BooleanField( |
|||
default=False, |
|||
verbose_name=_("Default Role for New Users"), |
|||
help_text=_("Automatically assigned to new registrations if no other role is selected.") |
|||
) |
|||
is_system = models.BooleanField( |
|||
default=False, |
|||
verbose_name=_("System Core Role"), |
|||
help_text=_("Marks default system roles. Admins can configure permissions, but deletion is restricted.") |
|||
) |
|||
|
|||
# 1. Identity & Profiles |
|||
is_searchable = models.BooleanField(default=True, verbose_name=_("Appear in User Searches / Directory")) |
|||
can_submit_verification = models.BooleanField(default=True, verbose_name=_("Submit Verification Documents")) |
|||
can_view_full_profiles = models.BooleanField(default=True, verbose_name=_("View Full Profiles")) |
|||
can_manage_institutions = models.BooleanField(default=False, verbose_name=_("Manage Institutions")) |
|||
|
|||
# 2. Chat & Communications |
|||
can_send_direct_messages = models.BooleanField(default=True, verbose_name=_("Send Direct Messages")) |
|||
can_create_group_chats = models.BooleanField(default=True, verbose_name=_("Create Group Chats")) |
|||
can_start_video_calls = models.BooleanField(default=False, verbose_name=_("Start Video Calls")) |
|||
can_moderate_chat = models.BooleanField(default=False, verbose_name=_("Moderate Chat Rooms")) |
|||
is_chat_muted = models.BooleanField(default=False, verbose_name=_("Chat Muted (Kill-switch)")) |
|||
|
|||
# 3. CMS & Articles |
|||
can_create_posts = models.BooleanField(default=True, verbose_name=_("Create Posts")) |
|||
can_publish_posts_directly = models.BooleanField(default=False, verbose_name=_("Publish Posts Directly (Bypass Moderation)")) |
|||
can_edit_own_posts = models.BooleanField(default=True, verbose_name=_("Edit Own Posts")) |
|||
can_delete_own_posts = models.BooleanField(default=True, verbose_name=_("Delete Own Posts")) |
|||
can_comment = models.BooleanField(default=True, verbose_name=_("Comment on Posts")) |
|||
|
|||
# 4. LMS & Academics |
|||
can_enroll_courses = models.BooleanField(default=True, verbose_name=_("Enroll in Courses")) |
|||
can_create_courses = models.BooleanField(default=False, verbose_name=_("Create Courses")) |
|||
can_publish_courses = models.BooleanField(default=False, verbose_name=_("Publish Courses Directly")) |
|||
can_issue_certificates = models.BooleanField(default=False, verbose_name=_("Issue Certificates")) |
|||
can_grade_submissions = models.BooleanField(default=False, verbose_name=_("Grade Submissions")) |
|||
has_premium_lms_access = models.BooleanField(default=False, verbose_name=_("Premium LMS Access")) |
|||
|
|||
# 5. Meetings |
|||
can_request_meetings = models.BooleanField(default=True, verbose_name=_("Send Meeting Requests")) |
|||
can_accept_meetings = models.BooleanField(default=False, verbose_name=_("Accept / Host Meetings")) |
|||
|
|||
# 6. Events |
|||
can_register_events = models.BooleanField(default=True, verbose_name=_("Register for Events")) |
|||
can_create_events = models.BooleanField(default=False, verbose_name=_("Create Events")) |
|||
can_publish_events = models.BooleanField(default=False, verbose_name=_("Publish Events Directly")) |
|||
can_checkin_attendees = models.BooleanField(default=False, verbose_name=_("Check-in Attendees (Scan Tickets)")) |
|||
can_export_attendee_list = models.BooleanField(default=False, verbose_name=_("Export Attendee List")) |
|||
|
|||
# 7. Community Projects |
|||
can_volunteer = models.BooleanField(default=True, verbose_name=_("Volunteer for Projects")) |
|||
can_create_projects = models.BooleanField(default=False, verbose_name=_("Create Projects")) |
|||
can_manage_project_tasks = models.BooleanField(default=False, verbose_name=_("Manage Project Tasks")) |
|||
can_approve_projects = models.BooleanField(default=False, verbose_name=_("Approve Projects")) |
|||
|
|||
# 8. Donations & Charity |
|||
can_make_donations = models.BooleanField(default=True, verbose_name=_("Make Donations")) |
|||
can_create_donation_campaigns = models.BooleanField(default=False, verbose_name=_("Create Donation Campaigns")) |
|||
can_view_donation_reports = models.BooleanField(default=False, verbose_name=_("View Donation Reports")) |
|||
|
|||
# 9. Support & Tickets |
|||
can_create_tickets = models.BooleanField(default=True, verbose_name=_("Create Support Tickets")) |
|||
can_reply_tickets = models.BooleanField(default=True, verbose_name=_("Reply to Support Tickets")) |
|||
can_manage_tickets = models.BooleanField(default=False, verbose_name=_("Manage Support Tickets")) |
|||
|
|||
# 10. Dynamic Forms |
|||
can_submit_forms = models.BooleanField(default=True, verbose_name=_("Submit Dynamic Forms")) |
|||
can_create_forms = models.BooleanField(default=False, verbose_name=_("Create Dynamic Forms")) |
|||
can_export_form_data = models.BooleanField(default=False, verbose_name=_("Export Form Responses")) |
|||
|
|||
# 11. Diplomacy & Institutional |
|||
can_view_diplomatic_reports = models.BooleanField(default=False, verbose_name=_("View Diplomatic Reports")) |
|||
can_create_diplomatic_reports = models.BooleanField(default=False, verbose_name=_("Create Diplomatic Reports")) |
|||
|
|||
# 12. Administration & Security |
|||
can_access_admin_panel = models.BooleanField(default=False, verbose_name=_("Access Admin Panel")) |
|||
can_manage_users = models.BooleanField(default=False, verbose_name=_("Manage Users")) |
|||
can_ban_users = models.BooleanField(default=False, verbose_name=_("Ban / Suspend Users")) |
|||
can_view_analytics = models.BooleanField(default=False, verbose_name=_("View Analytics Dashboard")) |
|||
|
|||
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At")) |
|||
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At")) |
|||
|
|||
class Meta: |
|||
ordering = ('name',) |
|||
verbose_name = _("Role") |
|||
verbose_name_plural = _("Roles") |
|||
|
|||
def __str__(self): |
|||
return self.name |
|||
|
|||
def save(self, *args, **kwargs): |
|||
if not self.slug: |
|||
self.slug = slugify(self.name) |
|||
if self.is_default: |
|||
# Ensure only one default role exists |
|||
Role.objects.filter(is_default=True).exclude(pk=self.pk).update(is_default=False) |
|||
super().save(*args, **kwargs) |
|||
|
|||
def get_permissions_dict(self): |
|||
"""Returns a dict of all permission flags and their boolean values.""" |
|||
return {perm: getattr(self, perm, False) for perm in ALL_PERMISSION_FIELDS} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue