Skip to content

Commit 92bde05

Browse files
committed
Add User Permission Level Code
1 parent fc46734 commit 92bde05

32 files changed

+531
-19
lines changed

Backend/EcommerceInventory/EcommerceInventory/Helpers.py

+30-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
from django.forms.models import model_to_dict
77
from functools import wraps
88
from django.db.models import Q
9-
from django.db import models
9+
from django.db import connection, models
1010
from rest_framework import serializers
11+
from django.urls.resolvers import URLPattern,get_resolver,URLResolver
12+
from django.core.serializers import serialize
13+
import json
1114

1215
def getDynamicFormModels():
1316
return {
@@ -249,4 +252,29 @@ def to_representation(self,obj):
249252
return representation
250253

251254
cls.to_representation=to_representation
252-
return cls
255+
return cls
256+
257+
def list_project_urls(patterns,parent_pattern=''):
258+
url_list=[]
259+
for pattern in patterns:
260+
if isinstance(pattern,URLPattern):
261+
url_list.append("/"+parent_pattern+str(pattern.pattern))
262+
elif isinstance(pattern,URLResolver):
263+
url_list.extend(list_project_urls(pattern.url_patterns,parent_pattern+str(pattern.pattern)))
264+
return url_list
265+
266+
def convertModeltoJSON(model):
267+
serialized_model=serialize('json',model)
268+
serializers_data=json.loads(serialized_model)
269+
modelItems=[]
270+
for data in serializers_data:
271+
data['fields']['id']=data['pk']
272+
modelItems.append(data['fields'])
273+
return modelItems
274+
275+
276+
def executeQuery(query,params):
277+
with connection.cursor() as cursor:
278+
cursor.execute(query,params)
279+
columns=[col[0] for col in cursor.description]
280+
return [dict(zip(columns,row)) for row in cursor.fetchall()]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from django.http import JsonResponse
2+
from UserServices.models import ModuleUrls, UserPermissions
3+
from rest_framework_simplejwt.authentication import JWTAuthentication
4+
import re
5+
from django.db.models import Q
6+
7+
class PermissionMiddleware:
8+
def __init__(self, get_response):
9+
self.get_response = get_response
10+
11+
def __call__(self, request):
12+
response = self.get_response(request)
13+
14+
current_url = request.path
15+
if current_url in urlToSkip():
16+
return response
17+
18+
jwt_auth=JWTAuthentication()
19+
try:
20+
user,token=jwt_auth.authenticate(request)
21+
if not user:
22+
return JsonResponse({'message':'Unauthorized'},status=401)
23+
except:
24+
return JsonResponse({'message':'Unauthorized'},status=401)
25+
26+
# Skip Permission Logic for Super Admin and Top Domain Level User
27+
if user.role=='Super Admin' or user.domain_user_id.id==user.id:
28+
return response
29+
30+
module=find_matching_module(current_url)
31+
32+
if not module:
33+
return JsonResponse({'message':'Module not Exist'},status=400)
34+
35+
36+
permission=UserPermissions.objects.filter(user=user.id,module=module.module).first()
37+
if not permission or permission.is_permission==False:
38+
return JsonResponse({'message':'Permission Denied'},status=403)
39+
40+
41+
return response
42+
43+
44+
def urlToSkip():
45+
modules=ModuleUrls.objects.filter(module__isnull=True).values_list('url',flat=True)
46+
return modules
47+
48+
def find_matching_module(url):
49+
regex_pattern=re.sub(r'\d+','[^\/]+',url.replace('/','\/'))
50+
51+
match_patter=ModuleUrls.objects.filter(Q(url__iregex=f'^{regex_pattern}$')).first()
52+
return match_patter

Backend/EcommerceInventory/EcommerceInventory/settings.py

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
'django.contrib.messages.middleware.MessageMiddleware',
6060
'django.middleware.clickjacking.XFrameOptionsMiddleware',
6161
'corsheaders.middleware.CorsMiddleware',
62+
'EcommerceInventory.middleware.PermissionMiddleware.PermissionMiddleware',
6263
]
6364

6465
REST_FRAMEWORK={

Backend/EcommerceInventory/EcommerceInventory/urls.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from EcommerceInventory import settings
2222
from UserServices.Controller.DynamicFormController import DynamicFormController
2323
from UserServices.Controller.SuperAdminDynamicFormController import SuperAdminDynamicFormController
24-
from UserServices.Controller.SidebarController import ModuleView
24+
from UserServices.Controller.SidebarController import ModuleUrlsListAPIView, ModuleView
2525
from django.conf.urls.static import static
2626

2727

@@ -31,6 +31,7 @@
3131
path('api/getForm/<str:modelName>/',DynamicFormController.as_view(),name='dynamicForm'),
3232
path('api/getForm/<str:modelName>/<str:id>/',DynamicFormController.as_view(),name='dynamicForm'),
3333
path('api/superAdminForm/<str:modelName>/',SuperAdminDynamicFormController.as_view(),name='superadmindynamicForm'),
34+
path('api/moduleUrls/',ModuleUrlsListAPIView.as_view(),name='moduleUrls_superadmin'),
3435
path('api/getMenus/',ModuleView.as_view(),name='sidebarmenu'),
3536
path('api/products/',include('ProductServices.urls')),
3637
path('api/inventory/',include('InventoryServices.urls')),
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,75 @@
11
import json
2-
from EcommerceInventory.Helpers import renderResponse
3-
from UserServices.models import Modules
2+
3+
from django.urls import get_resolver
4+
from EcommerceInventory.Helpers import convertModeltoJSON, list_project_urls, renderResponse
5+
from UserServices.models import ModuleUrls, Modules, UserPermissions
46
from rest_framework import generics
57
from django.core.serializers import serialize
8+
from rest_framework.views import APIView
9+
from rest_framework_simplejwt.authentication import JWTAuthentication
10+
from rest_framework.permissions import IsAuthenticated
11+
from EcommerceInventory.permission import IsSuperAdmin
12+
613

714
class ModuleView(generics.CreateAPIView):
15+
authentication_classes = [JWTAuthentication]
16+
permission_classes = [IsAuthenticated]
817

918
def get(self,request):
10-
menus=Modules.objects.filter(is_menu=True,parent_id=None,is_active=True).order_by('display_order')
19+
permission_module_ids=[]
20+
#Return all Modules for Super Admin and Top Domain Level User
21+
if request.user.role=='Super Admin' or request.user.domain_user_id.id==request.user.id:
22+
menus=Modules.objects.filter(is_menu=True,parent_id=None,is_active=True).order_by('display_order')
23+
else:
24+
permission_module_ids=UserPermissions.objects.filter(user=request.user.id,is_permission=True).values_list('module_id',flat=True)
25+
menus=Modules.objects.filter(is_menu=True,parent_id=None,is_active=True).filter(id__in=permission_module_ids).order_by('display_order')
1126

1227
serialized_menus=serialize('json',menus)
1328
serialized_menus=json.loads(serialized_menus)
1429

1530
cleaned_menus=[]
1631
for menu in serialized_menus:
1732
menu['fields']['id']=menu['pk']
18-
menu['fields']['submenus']=Modules.objects.filter(parent_id=menu['pk'],is_active=True,is_menu=True).order_by('display_order').values('id','module_name','module_icon','is_menu','is_active','parent_id','display_order','module_url','module_description')
33+
if request.user.role=='Super Admin' or request.user.domain_user_id.id==request.user.id:
34+
menu['fields']['submenus']=Modules.objects.filter(parent_id=menu['pk'],is_active=True,is_menu=True).order_by('display_order').values('id','module_name','module_icon','is_menu','is_active','parent_id','display_order','module_url','module_description')
35+
else:
36+
menu['fields']['submenus']=Modules.objects.filter(parent_id=menu['pk'],is_active=True,is_menu=True).filter(id__in=permission_module_ids).order_by('display_order').values('id','module_name','module_icon','is_menu','is_active','parent_id','display_order','module_url','module_description')
1937
cleaned_menus.append(menu['fields'])
2038

39+
if request.user.role=='Super Admin':
40+
cleaned_menus.append({'id':0,'module_name':'Manage Module Urls','module_icon':'','is_menu':True,'is_active':True,'parent_id':None,'display_order':0,'module_url':'/manage/moduleUrls','module_description':'Module Urls','submenus':[]})
41+
2142
return renderResponse(data=cleaned_menus,message='All Modules',status=200)
22-
43+
44+
45+
class ModuleUrlsListAPIView(APIView):
46+
authentication_classes = [JWTAuthentication]
47+
permission_classes = [IsAuthenticated,IsSuperAdmin]
48+
49+
def get(self,request):
50+
urls=ModuleUrls.objects.all()
51+
urlJson=convertModeltoJSON(urls)
52+
53+
urlconf=get_resolver()
54+
urlsProject=list_project_urls(urlconf.url_patterns)
55+
56+
modules=Modules.objects.all()
57+
modulesJson=convertModeltoJSON(modules)
58+
modulesJson.insert(0,{'id':0,'module_name':'Skip Permission'})
59+
60+
return renderResponse(data={'moduleUrls':urlJson,'project_urls':urlsProject,'modules':modulesJson},message='All Module Urls',status=200)
61+
62+
def post(self,request):
63+
data=request.data
64+
for item in data:
65+
if item['url']!=None:
66+
if 'id' in item and item['id'] and item['id']!=0:
67+
moduleUrls=ModuleUrls.objects.get(id=item['id'])
68+
moduleUrls.url=item['url']
69+
else:
70+
moduleUrls=ModuleUrls(url=item['url'])
71+
72+
if item['module']!=0 and item['module']!=None:
73+
moduleUrls.module=Modules.objects.get(id=item['module'])
74+
moduleUrls.save()
75+
return renderResponse(data={},message='Module Urls Updated',status=200)

Backend/EcommerceInventory/UserServices/Controller/UserController.py

+63-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from EcommerceInventory.Helpers import CommonListAPIMixin, CommonListAPIMixinWithFilter, CustomPageNumberPagination, createParsedCreatedAtUpdatedAt, renderResponse
2-
from UserServices.models import Users
1+
from EcommerceInventory.Helpers import CommonListAPIMixin, CommonListAPIMixinWithFilter, CustomPageNumberPagination, createParsedCreatedAtUpdatedAt, executeQuery, renderResponse
2+
from UserServices.models import Modules, UserPermissions, Users
33
from rest_framework.views import APIView
44
from rest_framework.permissions import IsAuthenticated
55
from rest_framework_simplejwt.authentication import JWTAuthentication
@@ -60,3 +60,64 @@ def get_queryset(self):
6060

6161
def perform_update(self,serializer):
6262
serializer.save()
63+
64+
65+
class UserPermissionsView(APIView):
66+
permission_classes = [IsAuthenticated]
67+
authentication_classes = [JWTAuthentication]
68+
def get(self,request,pk):
69+
query='''
70+
SELECT
71+
userservices_modules.module_name,
72+
userservices_modules.id as module_id,
73+
userservices_modules.parent_id_id,
74+
COALESCE(userservices_userpermissions.is_permission,0) as is_permission,
75+
userservices_userpermissions.user_id,
76+
userservices_userpermissions.domain_user_id_id
77+
FROM
78+
`userservices_modules`
79+
left join
80+
userservices_userpermissions
81+
on
82+
userservices_userpermissions.module_id=userservices_modules.id and
83+
userservices_userpermissions.user_id=%s;
84+
'''
85+
86+
permissions=executeQuery(query,[pk])
87+
88+
permissionList={}
89+
for permission in permissions:
90+
if permission['parent_id_id']==None:
91+
permission['children']=[]
92+
permissionList[permission['module_id']]=permission
93+
94+
for permission in permissions:
95+
if permission['parent_id_id']!=None:
96+
permissionList[permission['parent_id_id']]['children'].append(permission)
97+
98+
permissionList=permissionList.values()
99+
return renderResponse(data=permissionList,message="User Permissions",status=200)
100+
101+
def post(self,request,pk):
102+
data=request.data
103+
for item in data:
104+
if 'id' in item and item['id']!=None:
105+
permission=UserPermissions.objects.get(id=item['id'])
106+
permission.is_permission=item['is_permission']
107+
else:
108+
module=Modules.objects.get(id=item['module_id'])
109+
permission=UserPermissions(module=module,user_id=pk,is_permission=item['is_permission'])
110+
111+
permission.save()
112+
113+
if 'children' in item:
114+
for child in item['children']:
115+
if 'id' in child and child['id']!=None:
116+
permission=UserPermissions.objects.get(id=child['id'])
117+
permission.is_permission=child['is_permission']
118+
else:
119+
module=Modules.objects.get(id=child['module_id'])
120+
permission=UserPermissions(module=module,user_id=pk,is_permission=child['is_permission'])
121+
122+
permission.save()
123+
return renderResponse(data=[],message="Permissions Updated",status=200)
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Generated by Django 5.0.6 on 2024-08-11 07:16
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('UserServices', '0006_alter_users_profile_pic'),
11+
]
12+
13+
operations = [
14+
migrations.RenameField(
15+
model_name='userpermissions',
16+
old_name='is_add',
17+
new_name='is_permission',
18+
),
19+
migrations.RemoveField(
20+
model_name='userpermissions',
21+
name='is_delete',
22+
),
23+
migrations.RemoveField(
24+
model_name='userpermissions',
25+
name='is_edit',
26+
),
27+
migrations.RemoveField(
28+
model_name='userpermissions',
29+
name='is_view',
30+
),
31+
migrations.CreateModel(
32+
name='ModuleUrls',
33+
fields=[
34+
('id', models.AutoField(primary_key=True, serialize=False)),
35+
('url', models.CharField(max_length=255)),
36+
('created_at', models.DateTimeField(auto_now_add=True)),
37+
('updated_at', models.DateTimeField(auto_now=True)),
38+
('module', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='UserServices.modules')),
39+
],
40+
),
41+
]

Backend/EcommerceInventory/UserServices/models.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,18 @@ class UserPermissions(models.Model):
7575
id=models.AutoField(primary_key=True)
7676
user=models.ForeignKey(Users,on_delete=models.CASCADE,related_name='user_permissions_1')
7777
module=models.ForeignKey(Modules,on_delete=models.CASCADE)
78-
is_view=models.BooleanField(default=False)
79-
is_add=models.BooleanField(default=False)
80-
is_edit=models.BooleanField(default=False)
81-
is_delete=models.BooleanField(default=False)
78+
is_permission=models.BooleanField(default=False)
8279
domain_user_id=models.ForeignKey(Users,on_delete=models.CASCADE,blank=True,null=True,related_name='domain_user_id_user_permissions')
8380
created_at=models.DateTimeField(auto_now_add=True)
8481
updated_at=models.DateTimeField(auto_now=True)
8582

83+
class ModuleUrls(models.Model):
84+
id=models.AutoField(primary_key=True)
85+
module=models.ForeignKey(Modules,on_delete=models.CASCADE,blank=True,null=True)
86+
url=models.CharField(max_length=255)
87+
created_at=models.DateTimeField(auto_now_add=True)
88+
updated_at=models.DateTimeField(auto_now=True)
89+
8690
class ActivityLog(models.Model):
8791
id=models.AutoField(primary_key=True)
8892
user=models.ForeignKey(Users,on_delete=models.CASCADE,related_name='user_activity_log')

Backend/EcommerceInventory/UserServices/urls.py

+1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
path('users/',UserController.UserListView.as_view(),name='user_list'),
1111
path('userlist/',UserController.UserWithFilterListView.as_view(),name='user_list_filter'),
1212
path('updateuser/<pk>/',UserController.UpdateUsers.as_view(),name='update_user'),
13+
path('userpermission/<pk>/',UserController.UserPermissionsView.as_view(),name='user_permission'),
1314
]

Frontend/ecommerce_inventory/src/App.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import ManageProducts from './pages/products/ManageProducts';
1818
import Error404Page from './pages/Error404Page';
1919
import ManageWarhouse from './pages/warehouse/ManageWarehouse';
2020
import ManageUsers from './pages/users/ManageUsers';
21+
import ManageModuleUrls from './pages/module/ManageModuleUrls';
2122

2223
function App() {
2324
const {status,error,items}=useSelector(state=>state.sidebardata);
25+
const {isLoggedIn}=useSelector(state=>state.isLoggedInReducer);
2426
const dispatch=useDispatch();
2527

2628
useEffect(()=>{
@@ -29,6 +31,11 @@ function App() {
2931
}
3032
},[status,dispatch])
3133

34+
useEffect(()=>{
35+
if(isLoggedIn){
36+
dispatch(fetchSidebar());
37+
}
38+
},[isLoggedIn])
3239
const router=createBrowserRouter(
3340
[
3441
{path:"/auth",element:<Auth/>},
@@ -43,7 +50,8 @@ function App() {
4350
{path:"/manage/category",element:<ProtectedRoute element={<ManageCategories/>}/>},
4451
{path:"/manage/product",element:<ProtectedRoute element={<ManageProducts/>}/>},
4552
{path:"/manage/warehouse",element:<ProtectedRoute element={<ManageWarhouse/>}/>},
46-
{path:"/manage/users",element:<ProtectedRoute element={<ManageUsers/>}/>}
53+
{path:"/manage/users",element:<ProtectedRoute element={<ManageUsers/>}/>},
54+
{path:"/manage/moduleurls",element:<ProtectedRoute element={<ManageModuleUrls/>}/>}
4755
]},
4856
]
4957
)

0 commit comments

Comments
 (0)