Added all the functionality of app and admin
This commit is contained in:
46
module_iam/fixtures/iam_actions_fixture.json
Normal file
46
module_iam/fixtures/iam_actions_fixture.json
Normal file
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"model": "module_iam.iamappaction",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "create",
|
||||
"label": "create",
|
||||
"slug": "create",
|
||||
"created_on": "2024-03-10T01:39:43.656133",
|
||||
"modified_on": "2024-03-10T01:39:43.656133"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappaction",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "read",
|
||||
"label": "read",
|
||||
"slug": "read",
|
||||
"created_on": "2024-03-10T01:39:43.656133",
|
||||
"modified_on": "2024-03-10T01:39:43.656133"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappaction",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "update",
|
||||
"label": "update",
|
||||
"slug": "update",
|
||||
"created_on": "2024-03-10T01:39:43.656133",
|
||||
"modified_on": "2024-03-10T01:39:43.656133"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappaction",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "delete",
|
||||
"label": "delete",
|
||||
"slug": "delete",
|
||||
"created_on": "2024-03-10T01:39:43.656133",
|
||||
"modified_on": "2024-03-10T01:39:43.656133"
|
||||
}
|
||||
}
|
||||
]
|
||||
46
module_iam/fixtures/iam_principal_source_fixture.json
Normal file
46
module_iam/fixtures/iam_principal_source_fixture.json
Normal file
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"model": "module_iam.iamprincipalsource",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "app",
|
||||
"label": "app",
|
||||
"slug": "app",
|
||||
"created_on": "2024-03-10T01:39:43.648496",
|
||||
"modified_on": "2024-03-10T01:39:43.648496"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamprincipalsource",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "web",
|
||||
"label": "web",
|
||||
"slug": "web",
|
||||
"created_on": "2024-03-10T01:39:43.648496",
|
||||
"modified_on": "2024-03-10T01:39:43.648496"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamprincipalsource",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "google",
|
||||
"label": "google",
|
||||
"slug": "google",
|
||||
"created_on": "2024-03-10T01:39:43.648496",
|
||||
"modified_on": "2024-03-10T01:39:43.648496"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamprincipalsource",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "apple",
|
||||
"label": "apple",
|
||||
"slug": "apple",
|
||||
"created_on": "2024-03-10T01:39:43.648496",
|
||||
"modified_on": "2024-03-10T01:39:43.648496"
|
||||
}
|
||||
}
|
||||
]
|
||||
35
module_iam/fixtures/iam_principal_type_fixture.json
Normal file
35
module_iam/fixtures/iam_principal_type_fixture.json
Normal file
@@ -0,0 +1,35 @@
|
||||
[
|
||||
{
|
||||
"model": "module_iam.iamprincipaltype",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "admin",
|
||||
"label": "admin",
|
||||
"slug": "admin",
|
||||
"created_on": "2024-03-10T01:39:43.648496",
|
||||
"modified_on": "2024-03-10T01:39:43.648496"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamprincipaltype",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "subadmin",
|
||||
"label": "subadmin",
|
||||
"slug": "subadmin",
|
||||
"created_on": "2024-03-10T01:39:43.648496",
|
||||
"modified_on": "2024-03-10T01:39:43.648496"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamprincipaltype",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "user",
|
||||
"label": "user",
|
||||
"slug": "user",
|
||||
"created_on": "2024-03-10T01:39:43.648496",
|
||||
"modified_on": "2024-03-10T01:39:43.648496"
|
||||
}
|
||||
}
|
||||
]
|
||||
172
module_iam/fixtures/iam_resources_fixture.json
Normal file
172
module_iam/fixtures/iam_resources_fixture.json
Normal file
@@ -0,0 +1,172 @@
|
||||
[
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "manage_dashboard",
|
||||
"label": "manage_dashboard",
|
||||
"slug": "manage_dashboard",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "manage_iam",
|
||||
"label": "manage_iam",
|
||||
"slug": "manage_iam",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "manage_user",
|
||||
"label": "manage_user",
|
||||
"slug": "manage_user",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "manage_support",
|
||||
"label": "manage_support",
|
||||
"slug": "manage_support",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"name": "manage_contact_us",
|
||||
"label": "manage_contact_us",
|
||||
"slug": "manage_contact_us",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"name": "manage_feedback",
|
||||
"label": "manage_feedback",
|
||||
"slug": "manage_feedback",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"name": "manage_cms",
|
||||
"label": "manage_cms",
|
||||
"slug": "manage_cms",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"name": "manage_faqs",
|
||||
"label": "manage_faqs",
|
||||
"slug": "manage_faqs",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 9,
|
||||
"fields": {
|
||||
"name": "manage_tc",
|
||||
"label": "manage_tc",
|
||||
"slug": "manage_tc",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": 10,
|
||||
"fields": {
|
||||
"name": "manage_privacypolicy",
|
||||
"label": "manage_privacypolicy",
|
||||
"slug": "manage_privacypolicy",
|
||||
"created_on": "2024-03-10T01:39:43.657388",
|
||||
"modified_on": "2024-03-10T01:39:43.657388",
|
||||
"action": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
325
module_iam/forms.py
Normal file
325
module_iam/forms.py
Normal file
@@ -0,0 +1,325 @@
|
||||
from typing import Any
|
||||
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core import validators
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from module_project import constants
|
||||
|
||||
from . import models
|
||||
# from .backend import EmailBackend
|
||||
# from phonenumber_field.formfields import PhoneNumberField
|
||||
from .iam_constant import PRINCIPAL_TYPE_ADMIN, PRINCIPAL_TYPE_SUBADMIN
|
||||
from django.contrib.auth import authenticate
|
||||
|
||||
|
||||
class CustomAuthenticationForm(forms.Form):
|
||||
email = forms.EmailField(
|
||||
max_length=254,
|
||||
widget=forms.TextInput(attrs={"autofocus": True}),
|
||||
label=_("Email"),
|
||||
)
|
||||
password = forms.CharField(
|
||||
label=_("Password"),
|
||||
strip=False,
|
||||
widget=forms.PasswordInput(attrs={"autocomplete": "current-password"}),
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
email = self.cleaned_data.get("email")
|
||||
password = self.cleaned_data.get("password")
|
||||
self.user = None
|
||||
if email and password:
|
||||
|
||||
user = authenticate(email=email, password=password)
|
||||
|
||||
if user is None:
|
||||
raise ValidationError({"__all__": [constants.INVALID_EMAIL_PASSWORD]})
|
||||
elif not user.is_active:
|
||||
raise ValidationError({"__all__": [constants.ACCOUNT_DEACTIVATED]})
|
||||
self.user = user
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
class IAmPrincipalForm(forms.ModelForm):
|
||||
password = forms.CharField(
|
||||
widget=forms.PasswordInput(attrs={"autocomplete": "off"}),
|
||||
validators=[
|
||||
validators.MinLengthValidator(
|
||||
limit_value=6, message="Password must be at least 6 characters long. "
|
||||
)
|
||||
],
|
||||
)
|
||||
confirm_password = forms.CharField(
|
||||
widget=forms.PasswordInput(attrs={"autocomplete": "off"})
|
||||
)
|
||||
|
||||
is_active = forms.BooleanField(
|
||||
label="Active",
|
||||
initial=True,
|
||||
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = models.IAmPrincipal
|
||||
fields = [
|
||||
"principal_type",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"password",
|
||||
"confirm_password",
|
||||
"is_active",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get("instance")
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["principal_type"].queryset = models.IAmPrincipalType.objects.filter(
|
||||
active=True, deleted=False
|
||||
)
|
||||
# If it's a create action, exclude 'is_active' field
|
||||
if instance is None:
|
||||
self.fields.pop("is_active", None)
|
||||
else:
|
||||
# Exclude 'password' and 'confirm_password' fields for updates
|
||||
self.fields.pop("password", None)
|
||||
self.fields.pop("confirm_password", None)
|
||||
|
||||
# Make the 'email' field read-only
|
||||
self.fields["email"].widget.attrs["readonly"] = True
|
||||
|
||||
def clean_email(self):
|
||||
email = self.cleaned_data.get("email")
|
||||
# Skip uniqueness validation if it's an update action (instance exists)
|
||||
if self.instance and self.instance.email == email:
|
||||
return email
|
||||
if models.IAmPrincipal.objects.filter(email=email).exists():
|
||||
raise forms.ValidationError(constants.EMAIL_EXISTS)
|
||||
|
||||
return email
|
||||
|
||||
def save(self, commit=True):
|
||||
instance = super().save(commit=False)
|
||||
# Check if it's a new object (create action) or an existing one (update action)
|
||||
if not instance.pk: # pk is None for new objects
|
||||
instance.username = self.cleaned_data["email"]
|
||||
instance.set_password(self.cleaned_data["password"])
|
||||
|
||||
principal_type = self.cleaned_data.get("principal_type")
|
||||
if principal_type is not None:
|
||||
# Set is_superuser and is_staff based on principal_type
|
||||
if principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_ADMIN):
|
||||
instance.is_superuser = True
|
||||
elif principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_SUBADMIN):
|
||||
instance.is_staff = True
|
||||
if commit:
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
class IAmPrincipalProfileForm(forms.ModelForm):
|
||||
GENDER_CHOICES = (
|
||||
("male", "Male"),
|
||||
("female", "Female"),
|
||||
("other", "Other"),
|
||||
)
|
||||
first_name = forms.CharField(required=True)
|
||||
last_name = forms.CharField(required=True)
|
||||
email = forms.EmailField(required=True)
|
||||
password = forms.CharField(
|
||||
widget=forms.PasswordInput(attrs={"autocomplete": "off"})
|
||||
)
|
||||
confirm_password = forms.CharField(
|
||||
widget=forms.PasswordInput(attrs={"autocomplete": "off"})
|
||||
)
|
||||
# date_of_birth = forms.CharField(widget=forms.DateInput(attrs={'type': 'date'}))
|
||||
phone_number = forms.CharField(
|
||||
widget=forms.TextInput(),
|
||||
)
|
||||
# is_staff = forms.BooleanField(
|
||||
# label="Staff Status",
|
||||
# label_suffix="",
|
||||
# initial=True,
|
||||
# required=False,
|
||||
# help_text="Check this box to designate that this user will be assigned permissions in the future.",
|
||||
# )
|
||||
# is_superuser = forms.BooleanField(
|
||||
# label="SuperAdmin Status",
|
||||
# label_suffix="",
|
||||
# required=False,
|
||||
# help_text="Check this box to designates that this user has all permissions without explicitly assigning them.",
|
||||
# )
|
||||
# gender = forms.ChoiceField(choices=GENDER_CHOICES)
|
||||
|
||||
class Meta:
|
||||
model = models.IAmPrincipal
|
||||
fields = [
|
||||
"principal_type",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"password",
|
||||
"confirm_password",
|
||||
# 'gender',
|
||||
# 'date_of_birth',
|
||||
"phone_number",
|
||||
# 'address_line1',
|
||||
# 'address_line2',
|
||||
# 'city',
|
||||
# 'state',
|
||||
# 'country',
|
||||
# 'post_code',
|
||||
# 'profile_photo',
|
||||
# "is_staff",
|
||||
# "is_superuser",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get("instance")
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["principal_type"].queryset = models.IAmPrincipalType.objects.filter(
|
||||
active=True, deleted=False
|
||||
)
|
||||
# self.fields['principal_source'].queryset = models.IAmPrincipalSource.objects.filter(active=True, deleted=False)
|
||||
# Check if an instance is provided and customize the form fields accordingly
|
||||
if instance is not None:
|
||||
# Exclude the 'password' and 'confirm_password' fields
|
||||
self.fields.pop("password", None)
|
||||
self.fields.pop("confirm_password", None)
|
||||
|
||||
# Make the 'email' field read-only
|
||||
self.fields["email"].widget.attrs["readonly"] = True
|
||||
|
||||
# Modify the 'is_superuser' field to be not required
|
||||
# self.fields["is_superuser"].required = False
|
||||
# self.fields["is_staff"].required = False
|
||||
|
||||
# Add or modify the 'is_active' field
|
||||
self.fields["is_active"] = forms.BooleanField(
|
||||
label="Active",
|
||||
initial=instance.is_active,
|
||||
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||
required=False,
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
password = cleaned_data.get("password")
|
||||
confirm_password = cleaned_data.get("confirm_password")
|
||||
|
||||
if password and confirm_password and password != confirm_password:
|
||||
self.add_error("confirm_password", "Password does not match")
|
||||
return cleaned_data
|
||||
|
||||
def save(self, commit=True):
|
||||
user = super().save(commit=False)
|
||||
user.set_password(self.cleaned_data["password"])
|
||||
if commit:
|
||||
user.save()
|
||||
return user
|
||||
|
||||
class ProfileEditForm(forms.ModelForm):
|
||||
gender = forms.ChoiceField(choices=(('Male', 'Male'),('Female', 'Female'),('Other', 'Other')))
|
||||
profile_photo = forms.ImageField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = models.IAmPrincipal
|
||||
fields = [
|
||||
"profile_photo",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"date_of_birth",
|
||||
"gender",
|
||||
"phone_no"
|
||||
]
|
||||
|
||||
|
||||
class IAmPrincipalGroupLinkForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = models.IAmPrincipal
|
||||
fields = [
|
||||
# "principal_type",
|
||||
"email",
|
||||
"principal_group",
|
||||
]
|
||||
|
||||
# principal_type = forms.ModelChoiceField(
|
||||
# label="Principal Type",
|
||||
# queryset=models.IAmPrincipalType.objects.filter(active=True, deleted=False),
|
||||
# widget=forms.widgets.TextInput(attrs={"readonly": True}),
|
||||
# )
|
||||
principal_group = forms.ModelMultipleChoiceField(
|
||||
label="Groups",
|
||||
queryset=models.IAmPrincipalGroup.objects.filter(active=True, deleted=False),
|
||||
required=False,
|
||||
widget=forms.widgets.SelectMultiple(
|
||||
attrs={"class": "form_select js-example-basic-multiple"}
|
||||
),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Make the 'email' field read-only
|
||||
# self.fields['principal_type'].widget.attrs['disabled'] = True
|
||||
self.fields['email'].widget.attrs['readonly'] = True
|
||||
|
||||
|
||||
class IAmPrincipalTypeForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.IAmPrincipalType
|
||||
fields = ["name", "active"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get("instance")
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if instance is None:
|
||||
self.fields.pop("active")
|
||||
|
||||
|
||||
class IAmPrincipalGroupRoleLinkForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.IAmPrincipalGroup
|
||||
fields = ["name", "role", "active"]
|
||||
|
||||
role = forms.ModelMultipleChoiceField(
|
||||
queryset=models.IAmRole.objects.filter(active=True, deleted=False),
|
||||
required=False,
|
||||
widget=forms.widgets.SelectMultiple(
|
||||
attrs={"class": "form-select js-example-basic-multiple"}
|
||||
),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get("instance")
|
||||
# data = kwargs.get('data')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if instance is None:
|
||||
# This is an add operation, exclude the 'active' field
|
||||
self.fields.pop("active")
|
||||
|
||||
|
||||
class IAmPrincipalRoleAppResourceActionLinkForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.IAmRole
|
||||
fields = ["name", "active", "app_resource_action"]
|
||||
required = {"app_resource_action": False}
|
||||
|
||||
app_resource_action = forms.ModelMultipleChoiceField(
|
||||
queryset=models.IAmAppResourceActionLink.objects.all(),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get("instance")
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if instance is None:
|
||||
self.fields.pop("active")
|
||||
@@ -1,25 +1,34 @@
|
||||
|
||||
# principal type constant
|
||||
PRINCIPAL_TYPE_USER = "user"
|
||||
PRINCIPAL_TYPE_ADMIN = "admin"
|
||||
PRINCIPAL_TYPE_SUBADMIN = "subadmin"
|
||||
|
||||
# principal source constant
|
||||
PRINCIPAL_SOURCE_APP = "app"
|
||||
PRINCIPAL_SOURCE_WEB = "web"
|
||||
PRINCIPAL_SOURCE_GOOGLE = "google"
|
||||
PRINCIPAL_SOURCE_APPLE = "apple"
|
||||
|
||||
# app action constant
|
||||
ACTION_CREATE = "create"
|
||||
ACTION_READ = "read"
|
||||
ACTION_UPDATE = "update"
|
||||
ACTION_DELETE = "delete"
|
||||
|
||||
|
||||
RESOURCE_MANAGE_DASHBOARD = "manage_dashboard"
|
||||
RESOURCE_MANAGE_IAM = "manage_iam"
|
||||
RESOURCE_MANAGE_CUSTOMER = "manage_customer"
|
||||
RESOURCE_MANAGE_WALLET = "manage_wallet"
|
||||
RESOURCE_MANAGE_PAYMENT = "manage_payment"
|
||||
RESOURCE_MANAGE_GAMES = "manage_games"
|
||||
RESOURCE_MANAGE_USER = "manage_user"
|
||||
|
||||
RESOURCE_MANAGE_SUPPORT = "manage_support"
|
||||
RESOURCE_MANAGE_CONTACT_US = "manage_contact_us"
|
||||
RESOURCE_MANAGE_TICKET = "manage_ticket"
|
||||
RESOURCE_MANAGE_CMS = "manage_cms"
|
||||
RESOURCE_MANAGE_REPORTS = "manage_reports"
|
||||
RESOURCE_MANAGE_COUPON = "manage_coupon"
|
||||
RESOURCE_MANAGE_FEEDBACK = "manage_feedback"
|
||||
RESOURCE_MANAGE_STOCK = "manage_stock"
|
||||
RESOURCE_MANAGE_NOTIFICATION = "manage_notification"
|
||||
|
||||
RESOURCE_MANAGE_CMS = "manage_cms"
|
||||
RESOURCE_MANAGE_FAQS = "manage_faqs"
|
||||
RESOURCE_MANAGE_T_C = "manage_tc"
|
||||
RESOURCE_MANAGE_PRIVACYPOLICY = "manage_privacypolicy"
|
||||
|
||||
|
||||
# These constants are used solely for managing the active and inactive state of pages
|
||||
60
module_iam/iam_context_processors.py
Normal file
60
module_iam/iam_context_processors.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from .iam_constant import (
|
||||
PRINCIPAL_TYPE_USER,
|
||||
PRINCIPAL_TYPE_ADMIN,
|
||||
PRINCIPAL_TYPE_SUBADMIN,
|
||||
PRINCIPAL_SOURCE_APP,
|
||||
PRINCIPAL_SOURCE_WEB,
|
||||
PRINCIPAL_SOURCE_GOOGLE,
|
||||
PRINCIPAL_SOURCE_APPLE,
|
||||
ACTION_CREATE,
|
||||
ACTION_READ,
|
||||
ACTION_UPDATE,
|
||||
ACTION_DELETE,
|
||||
RESOURCE_MANAGE_DASHBOARD,
|
||||
RESOURCE_MANAGE_IAM,
|
||||
RESOURCE_MANAGE_USER,
|
||||
RESOURCE_MANAGE_SUPPORT,
|
||||
RESOURCE_MANAGE_CONTACT_US,
|
||||
RESOURCE_MANAGE_FEEDBACK,
|
||||
RESOURCE_MANAGE_NOTIFICATION,
|
||||
RESOURCE_MANAGE_CMS,
|
||||
RESOURCE_MANAGE_FAQS,
|
||||
RESOURCE_MANAGE_T_C,
|
||||
RESOURCE_MANAGE_PRIVACYPOLICY,
|
||||
RESOURCE_IAM_PRINCIPAL,
|
||||
RESOURCE_IAM_PRINCIPAL_GROUP,
|
||||
RESOURCE_IAM_GROUP,
|
||||
RESOURCE_IAM_ROLE,
|
||||
)
|
||||
|
||||
def iam_constants_context(request):
|
||||
return {
|
||||
'iam_constants_context': {
|
||||
'PRINCIPAL_TYPE_USER': PRINCIPAL_TYPE_USER,
|
||||
'PRINCIPAL_TYPE_ADMIN': PRINCIPAL_TYPE_ADMIN,
|
||||
'PRINCIPAL_TYPE_SUBADMIN': PRINCIPAL_TYPE_SUBADMIN,
|
||||
'PRINCIPAL_SOURCE_APP': PRINCIPAL_SOURCE_APP,
|
||||
'PRINCIPAL_SOURCE_WEB': PRINCIPAL_SOURCE_WEB,
|
||||
'PRINCIPAL_SOURCE_GOOGLE': PRINCIPAL_SOURCE_GOOGLE,
|
||||
'PRINCIPAL_SOURCE_APPLE': PRINCIPAL_SOURCE_APPLE,
|
||||
'ACTION_CREATE': ACTION_CREATE,
|
||||
'ACTION_READ': ACTION_READ,
|
||||
'ACTION_UPDATE': ACTION_UPDATE,
|
||||
'ACTION_DELETE': ACTION_DELETE,
|
||||
'RESOURCE_MANAGE_DASHBOARD': RESOURCE_MANAGE_DASHBOARD,
|
||||
'RESOURCE_MANAGE_IAM': RESOURCE_MANAGE_IAM,
|
||||
'RESOURCE_MANAGE_USER': RESOURCE_MANAGE_USER,
|
||||
'RESOURCE_MANAGE_SUPPORT': RESOURCE_MANAGE_SUPPORT,
|
||||
'RESOURCE_MANAGE_CONTACT_US': RESOURCE_MANAGE_CONTACT_US,
|
||||
'RESOURCE_MANAGE_FEEDBACK': RESOURCE_MANAGE_FEEDBACK,
|
||||
'RESOURCE_MANAGE_NOTIFICATION': RESOURCE_MANAGE_NOTIFICATION,
|
||||
'RESOURCE_MANAGE_CMS': RESOURCE_MANAGE_CMS,
|
||||
'RESOURCE_MANAGE_FAQS': RESOURCE_MANAGE_FAQS,
|
||||
'RESOURCE_MANAGE_T_C': RESOURCE_MANAGE_T_C,
|
||||
'RESOURCE_MANAGE_PRIVACYPOLICY': RESOURCE_MANAGE_PRIVACYPOLICY,
|
||||
'RESOURCE_IAM_PRINCIPAL': RESOURCE_IAM_PRINCIPAL,
|
||||
'RESOURCE_IAM_PRINCIPAL_GROUP': RESOURCE_IAM_PRINCIPAL_GROUP,
|
||||
'RESOURCE_IAM_GROUP': RESOURCE_IAM_GROUP,
|
||||
'RESOURCE_IAM_ROLE': RESOURCE_IAM_ROLE,
|
||||
}
|
||||
}
|
||||
169
module_iam/iam_fixture_script.py
Normal file
169
module_iam/iam_fixture_script.py
Normal file
@@ -0,0 +1,169 @@
|
||||
from datetime import datetime
|
||||
|
||||
from .iam_constant import (
|
||||
PRINCIPAL_TYPE_USER,
|
||||
PRINCIPAL_TYPE_ADMIN,
|
||||
PRINCIPAL_TYPE_SUBADMIN,
|
||||
PRINCIPAL_SOURCE_APP,
|
||||
PRINCIPAL_SOURCE_WEB,
|
||||
PRINCIPAL_SOURCE_GOOGLE,
|
||||
PRINCIPAL_SOURCE_APPLE,
|
||||
ACTION_CREATE,
|
||||
ACTION_READ,
|
||||
ACTION_UPDATE,
|
||||
ACTION_DELETE,
|
||||
RESOURCE_MANAGE_DASHBOARD,
|
||||
RESOURCE_MANAGE_IAM,
|
||||
RESOURCE_MANAGE_USER,
|
||||
RESOURCE_MANAGE_CONTACT_US,
|
||||
RESOURCE_MANAGE_FEEDBACK,
|
||||
RESOURCE_MANAGE_FAQS,
|
||||
RESOURCE_MANAGE_T_C,
|
||||
RESOURCE_MANAGE_CMS,
|
||||
RESOURCE_MANAGE_PRIVACYPOLICY,
|
||||
RESOURCE_MANAGE_SUPPORT
|
||||
)
|
||||
|
||||
class IAMPrincipalType:
|
||||
ADMIN = PRINCIPAL_TYPE_ADMIN
|
||||
SUBADMIN = PRINCIPAL_TYPE_SUBADMIN
|
||||
USER = PRINCIPAL_TYPE_USER
|
||||
|
||||
categories = [
|
||||
ADMIN,
|
||||
SUBADMIN,
|
||||
USER,
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def create_iam_principal_type_fixture_data():
|
||||
iam_category_fixture_data = []
|
||||
created_on = datetime.now().isoformat()
|
||||
modified_on = datetime.now().isoformat()
|
||||
for idx, category in enumerate(IAMPrincipalType.categories, start=1):
|
||||
iam_category_fixture_data.append(
|
||||
{
|
||||
"model": "module_iam.iamprincipaltype",
|
||||
"pk": idx,
|
||||
"fields": {
|
||||
"name": category,
|
||||
"label": category,
|
||||
"slug": category,
|
||||
"created_on": created_on,
|
||||
"modified_on": modified_on,
|
||||
},
|
||||
}
|
||||
)
|
||||
return iam_category_fixture_data
|
||||
|
||||
class IAMPrincipalSource:
|
||||
source = [
|
||||
PRINCIPAL_SOURCE_APP,
|
||||
PRINCIPAL_SOURCE_WEB,
|
||||
PRINCIPAL_SOURCE_GOOGLE,
|
||||
PRINCIPAL_SOURCE_APPLE
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def create_iam_principal_source_fixture_data():
|
||||
iam_principal_source_fixture_data = []
|
||||
created_on = datetime.now().isoformat()
|
||||
modified_on = datetime.now().isoformat()
|
||||
|
||||
for idx, principal_source in enumerate(IAMPrincipalSource.source, start=1,):
|
||||
iam_principal_source_fixture_data.append(
|
||||
{
|
||||
"model": "module_iam.iamprincipalsource",
|
||||
"pk": idx,
|
||||
"fields": {
|
||||
"name": principal_source,
|
||||
"label": principal_source,
|
||||
"slug": principal_source,
|
||||
"created_on": created_on,
|
||||
"modified_on": modified_on,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return iam_principal_source_fixture_data
|
||||
|
||||
class IAMActions:
|
||||
CREATE = ACTION_CREATE
|
||||
READ = ACTION_READ
|
||||
UPDATE = ACTION_UPDATE
|
||||
DELETE = ACTION_DELETE
|
||||
|
||||
actions = [
|
||||
CREATE,
|
||||
READ,
|
||||
UPDATE,
|
||||
DELETE,
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def create_iam_action_fixture_data():
|
||||
iam_action_fixture_data = []
|
||||
created_on = datetime.now().isoformat()
|
||||
modified_on = datetime.now().isoformat()
|
||||
for idx, action in enumerate(IAMActions.actions, start=1):
|
||||
iam_action_fixture_data.append(
|
||||
{
|
||||
"model": "module_iam.iamappaction",
|
||||
"pk": idx,
|
||||
"fields": {
|
||||
"name": action,
|
||||
"label": action,
|
||||
"slug": action,
|
||||
"created_on": created_on,
|
||||
"modified_on": modified_on,
|
||||
},
|
||||
}
|
||||
)
|
||||
return iam_action_fixture_data
|
||||
|
||||
class IAMResources:
|
||||
DASHBOARD = RESOURCE_MANAGE_DASHBOARD
|
||||
IAM = RESOURCE_MANAGE_IAM
|
||||
USER = RESOURCE_MANAGE_USER
|
||||
SUPPORT = RESOURCE_MANAGE_SUPPORT
|
||||
CONTACT_US = RESOURCE_MANAGE_CONTACT_US
|
||||
FEEDBACK = RESOURCE_MANAGE_FEEDBACK
|
||||
CMS = RESOURCE_MANAGE_CMS
|
||||
FAQS = RESOURCE_MANAGE_FAQS
|
||||
T_C = RESOURCE_MANAGE_T_C
|
||||
PRIVACYPOLICY = RESOURCE_MANAGE_PRIVACYPOLICY
|
||||
|
||||
resources = [
|
||||
DASHBOARD,
|
||||
IAM,
|
||||
USER,
|
||||
SUPPORT,
|
||||
CONTACT_US,
|
||||
FEEDBACK,
|
||||
CMS,
|
||||
FAQS,
|
||||
T_C,
|
||||
PRIVACYPOLICY,
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def create_iam_resource_fixture_data():
|
||||
iam_resource_fixture_data = []
|
||||
created_on = datetime.now().isoformat()
|
||||
modified_on = datetime.now().isoformat()
|
||||
for idx, resource in enumerate(IAMResources.resources, start=1):
|
||||
iam_resource_fixture_data.append(
|
||||
{
|
||||
"model": "module_iam.iamappresource",
|
||||
"pk": idx,
|
||||
"fields": {
|
||||
"name": resource,
|
||||
"label": resource,
|
||||
"slug": resource,
|
||||
"created_on": created_on,
|
||||
"modified_on": modified_on,
|
||||
"action": [1, 2, 3, 4],
|
||||
},
|
||||
}
|
||||
)
|
||||
return iam_resource_fixture_data
|
||||
122
module_iam/management/commands/load_iam_fixture.py
Normal file
122
module_iam/management/commands/load_iam_fixture.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import os
|
||||
import json
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from tqdm import tqdm
|
||||
from django.core.management.base import BaseCommand
|
||||
from module_iam.iam_fixture_script import IAMPrincipalType, IAMActions, IAMResources, IAMPrincipalSource
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Load IAM fixtures data"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
app_name = "module_iam"
|
||||
try:
|
||||
self.stdout.write(self.style.SUCCESS("IAM fixtures data loading started..."))
|
||||
|
||||
# Ensure the fixture directory exists
|
||||
fixture_directory = os.path.join(app_name, "fixtures")
|
||||
if not os.path.exists(fixture_directory):
|
||||
os.makedirs(fixture_directory)
|
||||
|
||||
# Generate IAM category fixture data
|
||||
principal_type_fixture_data = IAMPrincipalType.create_iam_principal_type_fixture_data()
|
||||
|
||||
# Specify the app name and fixture filename for category fixtures
|
||||
categories_fixture_filename = os.path.join(fixture_directory, "iam_principal_type_fixture.json")
|
||||
|
||||
principal_type_fixture_data_list = []
|
||||
with tqdm(total=len(principal_type_fixture_data), desc="Loading IAM principal type fixture") as pbar:
|
||||
for item in principal_type_fixture_data:
|
||||
principal_type_fixture_data_list.append(item)
|
||||
pbar.update(1)
|
||||
|
||||
# Dump category fixture data as JSON
|
||||
with open(categories_fixture_filename, "w") as fixture_file:
|
||||
json.dump(principal_type_fixture_data, fixture_file, indent=4)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"IAM category fixture data has been loaded successfully. Fixture file location: {categories_fixture_filename}")
|
||||
)
|
||||
|
||||
principal_source_fixture_data = IAMPrincipalSource.create_iam_principal_source_fixture_data()
|
||||
|
||||
# Specify the app name and fixture filename for source fixtures
|
||||
source_fixture_filename = os.path.join(fixture_directory, "iam_principal_source_fixture.json")
|
||||
|
||||
principal_source_fixture_data_list = []
|
||||
with tqdm(total=len(principal_source_fixture_data), desc="Loading IAM principal source fixture") as pbar:
|
||||
for item in principal_source_fixture_data:
|
||||
principal_source_fixture_data_list.append(item)
|
||||
pbar.update(1)
|
||||
|
||||
# Dump category fixture data as JSON
|
||||
with open(source_fixture_filename, "w") as fixture_file:
|
||||
json.dump(principal_source_fixture_data, fixture_file, indent=4)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"IAM category fixture data has been loaded successfully. Fixture file location: {categories_fixture_filename}")
|
||||
)
|
||||
|
||||
# Generate IAM action fixture data
|
||||
action_fixture_data = IAMActions.create_iam_action_fixture_data()
|
||||
|
||||
# Specify the fixture filename for action fixtures
|
||||
action_fixture_filename = os.path.join(fixture_directory, "iam_actions_fixture.json")
|
||||
|
||||
action_fixture_data_list = []
|
||||
with tqdm(total=len(action_fixture_data), desc="Loading IAM action fixture") as pbar:
|
||||
for item in action_fixture_data:
|
||||
action_fixture_data_list.append(item)
|
||||
pbar.update(1)
|
||||
|
||||
# Dump action fixture data as JSON
|
||||
with open(action_fixture_filename, "w") as fixture_file:
|
||||
json.dump(action_fixture_data, fixture_file, indent=4)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"IAM action fixture data has been loaded successfully. Fixture file location: {action_fixture_filename}")
|
||||
)
|
||||
|
||||
# Generate IAM resource fixture data
|
||||
resource_fixture_data = IAMResources.create_iam_resource_fixture_data()
|
||||
|
||||
# Specify the fixture filename for resource fixtures
|
||||
resource_fixture_filename = os.path.join(fixture_directory, "iam_resources_fixture.json")
|
||||
|
||||
resource_fixture_data_list = []
|
||||
with tqdm(total=len(resource_fixture_data), desc="Loading IAM resource fixture") as pbar:
|
||||
for item in resource_fixture_data:
|
||||
resource_fixture_data_list.append(item)
|
||||
pbar.update(1)
|
||||
|
||||
# Dump resource fixture data as JSON
|
||||
with open(resource_fixture_filename, "w") as fixture_file:
|
||||
json.dump(resource_fixture_data, fixture_file, indent=4)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"IAM resource fixture data has been loaded successfully. Fixture file location: {resource_fixture_filename}")
|
||||
)
|
||||
|
||||
# Run the loaddata command to load the created fixtures
|
||||
loaddata_command_categories = f"python manage.py loaddata {categories_fixture_filename}"
|
||||
subprocess.run(loaddata_command_categories, shell=True)
|
||||
|
||||
loaddata_command_categories = f"python manage.py loaddata {source_fixture_filename}"
|
||||
subprocess.run(loaddata_command_categories, shell=True)
|
||||
|
||||
loaddata_command_actions = f"python manage.py loaddata {action_fixture_filename}"
|
||||
subprocess.run(loaddata_command_actions, shell=True)
|
||||
|
||||
loaddata_command_resources = f"python manage.py loaddata {resource_fixture_filename}"
|
||||
subprocess.run(loaddata_command_resources, shell=True)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS("IAM fixtures data loading completed successfully.")
|
||||
)
|
||||
except Exception as e:
|
||||
# Handle exceptions here
|
||||
self.stderr.write(
|
||||
self.style.ERROR(f"IAM fixtures data loading failed: {str(e)}")
|
||||
)
|
||||
22
module_iam/migrations/0004_appversion.py
Normal file
22
module_iam/migrations/0004_appversion.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 5.0.2 on 2024-03-11 07:22
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_iam', '0003_alter_iamprincipal_gender'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AppVersion',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('version', models.CharField(max_length=10)),
|
||||
('force_upgrade', models.BooleanField(default=False, help_text='Indicates whether a force upgrade is needed for this app version.')),
|
||||
('recommend_upgrade', models.BooleanField(default=False, help_text='Indicates whether a recommend upgrade is needed for this app version.')),
|
||||
],
|
||||
),
|
||||
]
|
||||
17
module_iam/migrations/0005_alter_appversion_table.py
Normal file
17
module_iam/migrations/0005_alter_appversion_table.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.0.2 on 2024-03-11 07:23
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_iam', '0004_appversion'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelTable(
|
||||
name='appversion',
|
||||
table='app_version',
|
||||
),
|
||||
]
|
||||
19
module_iam/migrations/0006_alter_appversion_version.py
Normal file
19
module_iam/migrations/0006_alter_appversion_version.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.0.2 on 2024-03-11 08:18
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_iam', '0005_alter_appversion_table'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='appversion',
|
||||
name='version',
|
||||
field=models.CharField(max_length=10, validators=[django.core.validators.RegexValidator('^\\d+\\.\\d+\\.\\d+$')]),
|
||||
),
|
||||
]
|
||||
@@ -2,17 +2,28 @@ from collections.abc import Iterable
|
||||
import datetime
|
||||
import random
|
||||
import string
|
||||
|
||||
# from manage_wallets.models import Wallet, Transaction, TransactionStatus, TransactionType
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AbstractUser, BaseUserManager
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.text import slugify
|
||||
|
||||
# from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
from module_project.utils import RandomGenerator
|
||||
from .resource_action import PRINCIPAL_TYPE_USER, PRINCIPAL_TYPE_ADMIN
|
||||
from .iam_constant import (
|
||||
PRINCIPAL_TYPE_USER,
|
||||
PRINCIPAL_TYPE_ADMIN,
|
||||
PRINCIPAL_TYPE_SUBADMIN,
|
||||
PRINCIPAL_SOURCE_APP,
|
||||
PRINCIPAL_SOURCE_APPLE,
|
||||
PRINCIPAL_SOURCE_GOOGLE,
|
||||
PRINCIPAL_SOURCE_WEB,
|
||||
)
|
||||
|
||||
# from .utils import UserContext
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator
|
||||
@@ -102,14 +113,60 @@ class IAmPrincipalType(MasterModel):
|
||||
db_table = "iam_principal_type"
|
||||
|
||||
@classmethod
|
||||
def get_principal_type(cls, type):
|
||||
return cls.objects.filter(name=type).first()
|
||||
def get_principal_type(cls, name):
|
||||
cache_key = f"principal_{name}"
|
||||
principal = cache.get(cache_key)
|
||||
|
||||
if not principal:
|
||||
principal = cls.objects.filter(name=name).first()
|
||||
cache.set(cache_key, principal, timeout=60 * 15) # Cache for 15 minutes
|
||||
|
||||
return principal
|
||||
|
||||
@classmethod
|
||||
def get_principal_user(cls):
|
||||
return cls.get_principal_type(PRINCIPAL_TYPE_USER)
|
||||
|
||||
@classmethod
|
||||
def get_principal_admin(cls):
|
||||
return cls.get_principal_type(PRINCIPAL_TYPE_ADMIN)
|
||||
|
||||
@classmethod
|
||||
def get_principal_subadmin(cls):
|
||||
return cls.get_principal_type(PRINCIPAL_TYPE_SUBADMIN)
|
||||
|
||||
|
||||
class IAmPrincipalSource(MasterModel):
|
||||
class Meta:
|
||||
db_table = "iam_principal_source"
|
||||
|
||||
@classmethod
|
||||
def get_principal_source(cls, name):
|
||||
cache_key = f"principal_{name}"
|
||||
principal = cache.get(cache_key)
|
||||
|
||||
if not principal:
|
||||
principal = cls.objects.filter(name=name).first()
|
||||
cache.set(cache_key, principal, timeout=60 * 15) # Cache for 15 minutes
|
||||
|
||||
return principal
|
||||
|
||||
@classmethod
|
||||
def get_principal_web(cls):
|
||||
return cls.get_principal_source(PRINCIPAL_SOURCE_WEB)
|
||||
|
||||
@classmethod
|
||||
def get_principal_app(cls):
|
||||
return cls.get_principal_source(PRINCIPAL_SOURCE_APP)
|
||||
|
||||
@classmethod
|
||||
def get_principal_google(cls):
|
||||
return cls.get_principal_source(PRINCIPAL_SOURCE_GOOGLE)
|
||||
|
||||
@classmethod
|
||||
def get_principal_apple(cls):
|
||||
return cls.get_principal_source(PRINCIPAL_SOURCE_APPLE)
|
||||
|
||||
|
||||
class IAmAppAction(MasterModel):
|
||||
class Meta:
|
||||
@@ -239,7 +296,7 @@ class IAmPrincipalManager(BaseUserManager):
|
||||
extra_fields.setdefault("is_staff", True)
|
||||
extra_fields.setdefault("is_superuser", True)
|
||||
extra_fields.setdefault("phone_no", "+919978895465")
|
||||
extra_fields.setdefault("gender", "M")
|
||||
extra_fields.setdefault("gender", "Male")
|
||||
extra_fields.setdefault("date_of_birth", timezone.now())
|
||||
extra_fields.setdefault("created_by", None)
|
||||
extra_fields.setdefault("created_on", timezone.now())
|
||||
@@ -298,7 +355,12 @@ class IAmPrincipal(AbstractUser):
|
||||
related_name="principal_groups",
|
||||
)
|
||||
register_complete = models.BooleanField(default=False)
|
||||
player_id = models.CharField(max_length=255, null=True, blank=True, help_text="OneSignal player id for push notification")
|
||||
player_id = models.CharField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="OneSignal player id for push notification",
|
||||
)
|
||||
|
||||
USERNAME_FIELD = "email"
|
||||
REQUIRED_FIELDS = []
|
||||
@@ -367,3 +429,15 @@ class IAmPrincipalBiometric(BaseModel):
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.principal.first_name}:{self.biometric_type}"
|
||||
|
||||
|
||||
class AppVersion(models.Model):
|
||||
version = models.CharField(max_length=10, validators=[RegexValidator(r'^\d+\.\d+\.\d+$')])
|
||||
force_upgrade = models.BooleanField(default=False, help_text='Indicates whether a force upgrade is needed for this app version.')
|
||||
recommend_upgrade = models.BooleanField(default=False, help_text='Indicates whether a recommend upgrade is needed for this app version.')
|
||||
|
||||
class Meta:
|
||||
db_table = "app_version"
|
||||
|
||||
def __str__(self):
|
||||
return self.version
|
||||
@@ -4,5 +4,32 @@ from . import views
|
||||
app_name = "module_iam"
|
||||
|
||||
urlpatterns = [
|
||||
path('dashboard/', views.DashboardView.as_view(), name="dashboard")
|
||||
path('dashboard/', views.DashboardView.as_view(), name="dashboard"),
|
||||
|
||||
|
||||
# path('principal/', views.PrincipalListView.as_view(), name="principal_list"),
|
||||
# path('principal/add/', views.PrincipalCreateOrUpdateView.as_view(), name="principal_add"),
|
||||
# path('principal/edit/<int:pk>', views.PrincipalCreateOrUpdateView.as_view(), name="principal_edit"),
|
||||
# path('principal/delete/<int:pk>', views.PrincipalDeleteView.as_view(), name="principal_delete"),
|
||||
|
||||
path('principal/group/link/', views.PrincipalGroupLinkView.as_view(), name="principal_group_link"),
|
||||
path('principal/group/link/', views.PrincipalGroupLinkAdminListJsonView.as_view(), name="principal_group_link_list"),
|
||||
# path('principal/group/link/edit/<int:pk>/', views.PrincipalGroupLinkEditView.as_view(), name="principal_group_link_edit"),
|
||||
|
||||
|
||||
path('principal/group/', views.PrincipalGroupView.as_view(), name="principal_group"),
|
||||
path('principal/group/list', views.PrincipalGroupListJsonView.as_view(), name="principal_group_list"),
|
||||
path('principal/group/add/', views.PrincipalGroupCreateOrUpdateView.as_view(), name="principal_group_add"),
|
||||
path('principal/group/edit/<int:pk>/', views.PrincipalGroupCreateOrUpdateView.as_view(), name="principal_group_edit"),
|
||||
path('principal/group/action//', views.PrincipalGroupActionView.as_view(), name="principal_group_action"),
|
||||
|
||||
path('principal/role/', views.AppRoleView.as_view(), name="role"),
|
||||
path('principal/role/list/', views.AppRoleListJsonView.as_view(), name="role_list"),
|
||||
path('principal/role/add/', views.AppRoleCreateOrUpdateView.as_view(), name="role_add"),
|
||||
path('principal/role/edit/<int:pk>/', views.AppRoleCreateOrUpdateView.as_view(), name="role_edit"),
|
||||
path('principal/role/action/', views.AppRoleActionView.as_view(), name="role_action"),
|
||||
|
||||
path("profile/", views.PrincipalProfileView.as_view(), name="profile_details"),
|
||||
path("profile/edit/", views.PrincipalProfileEditView.as_view(), name="profile_details_edit")
|
||||
|
||||
]
|
||||
|
||||
@@ -1,7 +1,374 @@
|
||||
from django.shortcuts import render
|
||||
from typing import Any
|
||||
from django.db.models.base import Model as Model
|
||||
from django.db.models.query import QuerySet
|
||||
from django.views import generic
|
||||
import logging
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Q
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.urls import reverse_lazy
|
||||
from module_iam import iam_constant
|
||||
from module_project.mixins import DatatablesMixin
|
||||
from django_datatables_view.base_datatable_view import BaseDatatableView
|
||||
from module_project.mixins import ActionMixin
|
||||
from .forms import (
|
||||
CustomAuthenticationForm,
|
||||
IAmPrincipalForm,
|
||||
IAmPrincipalGroupRoleLinkForm,
|
||||
IAmPrincipalRoleAppResourceActionLinkForm,
|
||||
IAmPrincipalGroupLinkForm,
|
||||
ProfileEditForm
|
||||
)
|
||||
from .models import (
|
||||
IAmPrincipal,
|
||||
IAmPrincipalType,
|
||||
IAmAppResourceActionLink,
|
||||
IAmPrincipalGroup,
|
||||
IAmRole,
|
||||
)
|
||||
|
||||
from module_project import constants
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Create your views here.
|
||||
|
||||
class DashboardView(generic.TemplateView):
|
||||
template_name = "base_structure/layout/dashboard.html"
|
||||
page_name = iam_constant.RESOURCE_MANAGE_DASHBOARD
|
||||
template_name = "base_structure/layout/dashboard.html"
|
||||
|
||||
def get_user_count(self):
|
||||
obj = IAmPrincipal.objects.all()
|
||||
# Count active users
|
||||
active_user_count = obj.filter(is_active=True).count()
|
||||
# Count total users
|
||||
total_user_count = obj.count()
|
||||
return active_user_count, total_user_count
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
active_user_count, total_user_count = self.get_user_count()
|
||||
context['active_user_count'] = active_user_count
|
||||
context['total_user_count'] = total_user_count
|
||||
context['page_name'] = self.page_name
|
||||
return context
|
||||
|
||||
class PrincipalGroupLinkView(LoginRequiredMixin, generic.TemplateView):
|
||||
page_name = iam_constant.RESOURCE_IAM_PRINCIPAL_GROUP
|
||||
model = IAmPrincipal
|
||||
template_name = "module_iam/iam_principal_group_link.html"
|
||||
|
||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
class PrincipalGroupLinkAdminListJsonView(BaseDatatableView):
|
||||
model = IAmPrincipal
|
||||
columns = ["id", "first_name", "email", "principal_type__name", "is_active"],
|
||||
order_columns = ["id", "first_name", "email"]
|
||||
|
||||
def get_initial_queryset(self):
|
||||
deleted_flag = self.request.GET.get('deleted_flag', False)
|
||||
return self.model.objects.filter(deleted=deleted_flag).exclude(principal_type__name=iam_constant.PRINCIPAL_TYPE_USER)
|
||||
|
||||
|
||||
class PrincipalGroupView(LoginRequiredMixin, generic.TemplateView):
|
||||
page_name = iam_constant.RESOURCE_IAM_GROUP
|
||||
model = IAmPrincipalGroup
|
||||
template_name = "module_iam/iam_group.html"
|
||||
|
||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
def filter_queryset(self, qs):
|
||||
search_value = self.request.GET.get("search[value]", None)
|
||||
if search_value:
|
||||
qs = qs.filter(
|
||||
Q(id__icontains=search_value)
|
||||
| Q(name__icontains=search_value)
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
class PrincipalGroupListJsonView(BaseDatatableView):
|
||||
model = IAmPrincipalGroup
|
||||
columns = ["id", "name", "active"]
|
||||
order_columns = ["id", "name", "active"]
|
||||
|
||||
def get_initial_queryset(self):
|
||||
deleted_flag = self.request.GET.get('deleted_flag', False)
|
||||
return self.model.objects.filter(deleted=deleted_flag)
|
||||
|
||||
def filter_queryset(self, qs):
|
||||
search_value = self.request.GET.get("search[value]", None)
|
||||
if search_value:
|
||||
qs = qs.filter(
|
||||
Q(id__icontains=search_value)
|
||||
| Q(name__icontains=search_value)
|
||||
)
|
||||
return qs
|
||||
|
||||
def generate_role_data(self, queryset):
|
||||
roles_data = []
|
||||
for obj in queryset:
|
||||
roles = [{'name': role.name} for role in obj.role.all()]
|
||||
print(f"role data is this {roles}")
|
||||
roles_data.append({
|
||||
'id': obj.id,
|
||||
'name': obj.name,
|
||||
'active': str(obj.active),
|
||||
'roles': roles
|
||||
})
|
||||
return roles_data
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
roles = self.filter_queryset(self.get_initial_queryset())
|
||||
role_data = self.generate_role_data(roles)
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['recordsTotal'] = len(role_data)
|
||||
context['recordsFiltered'] = len(role_data)
|
||||
context['data'] = role_data
|
||||
context['result'] = 'ok'
|
||||
return context
|
||||
|
||||
class PrincipalGroupCreateOrUpdateView(LoginRequiredMixin, generic.View):
|
||||
page_name = iam_constant.RESOURCE_IAM_GROUP
|
||||
page_title = "Principal Group"
|
||||
model = IAmPrincipalGroup
|
||||
template_name = "module_iam/iam_group_add.html"
|
||||
form_class = IAmPrincipalGroupRoleLinkForm
|
||||
success_url = reverse_lazy("module_iam:principal_group")
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
def get_success_message(self):
|
||||
self.success_message = constants.RECORD_CREATED if not self.object else constants.RECORD_UPDATED
|
||||
return self.success_message
|
||||
|
||||
def get_object(self):
|
||||
pk = self.kwargs.get("pk")
|
||||
return get_object_or_404(self.model, pk=pk) if pk else None
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Add" if not self.object else "Edit",
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
form = self.form_class(instance=self.object)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
form = self.form_class(request.POST, instance=self.object)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
form.save()
|
||||
messages.success(self.request, self.get_success_message())
|
||||
return redirect(self.success_url)
|
||||
|
||||
|
||||
class PrincipalGroupActionView(ActionMixin):
|
||||
model = IAmPrincipalGroup
|
||||
|
||||
|
||||
class AppRoleView(LoginRequiredMixin, generic.TemplateView):
|
||||
page_name = iam_constant.RESOURCE_IAM_ROLE
|
||||
model = IAmRole
|
||||
template_name = "module_iam/iam_role.html"
|
||||
|
||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
class AppRoleListJsonView(BaseDatatableView):
|
||||
model = IAmRole
|
||||
columns = ["id", "name", "active", "resources"]
|
||||
order_columns = ["id", "name"]
|
||||
|
||||
def get_initial_queryset(self):
|
||||
deleted_flag = self.request.GET.get('deleted_flag', False)
|
||||
return (
|
||||
super(AppRoleListJsonView, self)
|
||||
.get_initial_queryset()
|
||||
.prefetch_related(
|
||||
"app_resource_action",
|
||||
"app_resource_action__app_resource",
|
||||
"app_resource_action__app_action",
|
||||
)
|
||||
.filter(deleted=deleted_flag)
|
||||
)
|
||||
|
||||
def filter_queryset(self, qs):
|
||||
search_value = self.request.GET.get("search[value]", None)
|
||||
if search_value:
|
||||
qs = qs.filter(
|
||||
Q(id__icontains=search_value)
|
||||
| Q(name__icontains=search_value)
|
||||
| Q(app_resource_action__app_resource__name__icontains=search_value)
|
||||
| Q(app_resource_action__app_action__name__icontains=search_value)
|
||||
)
|
||||
return qs
|
||||
|
||||
def generate_resource_data(self, roles):
|
||||
role_data = []
|
||||
for role in roles:
|
||||
role_info = {
|
||||
"id": role.id,
|
||||
"name": role.name,
|
||||
"active": str(role.active),
|
||||
"resources": {},
|
||||
}
|
||||
|
||||
for link in role.app_resource_action.all():
|
||||
resource = link.app_resource.name
|
||||
action = link.app_action.name
|
||||
if resource in role_info["resources"]:
|
||||
role_info["resources"][resource].append(action)
|
||||
else:
|
||||
role_info["resources"][resource] = [action]
|
||||
role_data.append(role_info)
|
||||
return role_data
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
roles = self.filter_queryset(self.get_initial_queryset())
|
||||
role_data = self.generate_resource_data(roles)
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['recordsTotal'] = len(role_data)
|
||||
context['recordsFiltered'] = len(role_data)
|
||||
context['data'] = role_data
|
||||
context['result'] = 'ok'
|
||||
return context
|
||||
|
||||
|
||||
class AppRoleCreateOrUpdateView(LoginRequiredMixin, generic.View):
|
||||
page_name = iam_constant.RESOURCE_IAM_ROLE
|
||||
model = IAmRole
|
||||
template_name = "module_iam/iam_role_add.html"
|
||||
form_class = IAmPrincipalRoleAppResourceActionLinkForm
|
||||
success_url = reverse_lazy("module_iam:role")
|
||||
success_message = "Saved Successfully"
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
def get_success_message(self):
|
||||
self.success_message = (
|
||||
f"Record {'Created' if not self.object else 'Updated'} Successfully"
|
||||
)
|
||||
return self.success_message
|
||||
|
||||
def get_object(self):
|
||||
pk = self.kwargs.get("pk")
|
||||
return get_object_or_404(self.model, pk=pk) if pk else None
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Add" if not self.object else "Edit",
|
||||
"app_resource_action": IAmAppResourceActionLink.objects.generate_app_resource_action_data(),
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
try:
|
||||
self.object = self.get_object()
|
||||
form = self.form_class(instance=self.object)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
except Exception as e:
|
||||
messages.error(request, str(e))
|
||||
return redirect(self.success_url)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
try:
|
||||
self.object = self.get_object()
|
||||
form = self.form_class(request.POST, instance=self.object)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
form.save()
|
||||
messages.success(self.request, self.get_success_message())
|
||||
return redirect(self.success_url)
|
||||
except Exception as e:
|
||||
messages.error(self.request, str(e))
|
||||
return redirect(self.success_url)
|
||||
|
||||
|
||||
class AppRoleActionView(LoginRequiredMixin, ActionMixin):
|
||||
model = IAmRole
|
||||
|
||||
|
||||
class PrincipalProfileView(LoginRequiredMixin, generic.TemplateView):
|
||||
page_name = iam_constant.RESOURCE_MANAGE_DASHBOARD
|
||||
model = IAmPrincipal
|
||||
template_name = "module_iam/profile_details.html"
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
user = self.request.user.id
|
||||
return get_object_or_404(self.model.objects.select_related("principal_type", "principal_source"), pk=user)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
context["data_obj"] = self.get_object()
|
||||
return context
|
||||
|
||||
class PrincipalProfileEditView(generic.View):
|
||||
page_name = iam_constant.RESOURCE_MANAGE_DASHBOARD
|
||||
model = IAmPrincipal
|
||||
template_name = "module_iam/profile_details_edit.html"
|
||||
form_class = ProfileEditForm
|
||||
success_url = reverse_lazy("module_iam:profile_details")
|
||||
success_message = "Saved Successfully"
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
def get_success_message(self):
|
||||
self.success_message = (
|
||||
f"Record {'Created' if not self.object else 'Updated'} Successfully"
|
||||
)
|
||||
return self.success_message
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
# "page_name": self.page_name,
|
||||
"operation": "Edit",
|
||||
"page_name": self.page_name
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
# try:
|
||||
self.object = self.get_object()
|
||||
form = self.form_class(instance=self.object)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
form = self.form_class(request.POST, request.FILES, instance=self.object)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
form.save()
|
||||
messages.success(self.request, self.get_success_message())
|
||||
return redirect(self.success_url)
|
||||
Reference in New Issue
Block a user