Skip to content

Commit b0a791b

Browse files
committed
Added Complete Product Service, Add Review,Manage Reviews,Add Question,Manage Product Question and Edit Product Question and Shimmer Image Effect
1 parent c2adb13 commit b0a791b

27 files changed

+841
-99
lines changed

Backend/EcommerceInventory/EcommerceInventory/Helpers.py

+53-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
from rest_framework.exceptions import AuthenticationFailed,NotAuthenticated,PermissionDenied
55
from rest_framework.pagination import PageNumberPagination
66
from django.forms.models import model_to_dict
7+
from functools import wraps
8+
from django.db.models import Q
9+
from django.db import models
710

811
def getDynamicFormModels():
912
return {
@@ -107,4 +110,53 @@ def custom_exception_handler(exc, context):
107110

108111
class CustomPageNumberPagination(PageNumberPagination):
109112
page_size_query_param='pageSize'
110-
max_page_size=100
113+
max_page_size=100
114+
115+
116+
class CommonListAPIMixin:
117+
serializer_class=None
118+
pagination_class=CustomPageNumberPagination
119+
120+
def get_queryset(self):
121+
raise NotImplementedError('get_queryset method not implemented')
122+
123+
def common_list_decorator(serializer_class):
124+
def decorator(list_method):
125+
@wraps(list_method)
126+
def wrapped_list_method(self,request,*args,**kwargs):
127+
queryset=self.get_queryset()
128+
search_query=self.request.query_params.get('search',None)
129+
130+
if search_query:
131+
search_conditions=Q()
132+
133+
for field in serializer_class.Meta.model._meta.get_fields():
134+
if isinstance(field,(models.CharField,models.TextField)):
135+
search_conditions|=Q(**{f"{field.name}__icontains":search_query})
136+
queryset=queryset.filter(search_conditions)
137+
138+
ordering=self.request.query_params.get('ordering',None)
139+
140+
if ordering:
141+
queryset=queryset.order_by(ordering)
142+
143+
page=self.paginate_queryset(queryset)
144+
145+
if page is not None:
146+
serializer=self.get_serializer(page,many=True)
147+
data=serializer.data
148+
total_pages=self.paginator.page.paginator.num_pages
149+
current_page=self.paginator.page.number
150+
page_size=self.paginator.page.paginator.per_page
151+
total_items=self.paginator.page.paginator.count
152+
else:
153+
serializer=self.get_serializer(queryset,many=True)
154+
data=serializer.data
155+
total_pages=1
156+
current_page=1
157+
page_size=len(data)
158+
total_items=len(data)
159+
160+
return renderResponse(data={'data':data,'totalPages':total_pages,'currentPage':current_page,'pageSize':page_size,'totalItems':total_items},message='Data Retrieved Successfully',status=200)
161+
return wrapped_list_method
162+
return decorator
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from EcommerceInventory.Helpers import CustomPageNumberPagination, renderResponse
1+
from EcommerceInventory.Helpers import CommonListAPIMixin, CustomPageNumberPagination, renderResponse
22
from ProductServices.models import Categories
33
from rest_framework import generics
44
from rest_framework import serializers
@@ -33,46 +33,12 @@ class CategoryListView(generics.ListAPIView):
3333
serializer_class = CategorySerializer
3434
authentication_classes = [JWTAuthentication]
3535
permission_classes = [IsAuthenticated]
36-
pagination_class = CustomPageNumberPagination
3736

3837

3938
def get_queryset(self):
4039
queryset=Categories.objects.filter(parent_id__isnull=True).filter(domain_user_id=self.request.user.domain_user_id.id)
41-
search_query=self.request.query_params.get('search',None)
42-
43-
if search_query:
44-
search_conditions=Q()
45-
46-
for field in Categories._meta.get_fields():
47-
if isinstance(field,(models.CharField,models.TextField)):
48-
search_conditions|=Q(**{f"{field.name}__icontains":search_query})
49-
queryset=queryset.filter(search_conditions)
50-
51-
ordering=self.request.query_params.get('ordering',None)
52-
53-
if ordering:
54-
queryset=queryset.order_by(ordering)
55-
5640
return queryset
57-
58-
def list(self,request,*args,**kwargs):
59-
queryset=self.filter_queryset(self.get_queryset())
60-
61-
page=self.paginate_queryset(queryset)
6241

63-
if page is not None:
64-
serializer=self.get_serializer(page,many=True)
65-
data=serializer.data
66-
total_pages=self.paginator.page.paginator.num_pages
67-
current_page=self.paginator.page.number
68-
page_size=self.paginator.page.paginator.per_page
69-
total_items=self.paginator.page.paginator.count
70-
else:
71-
serializer=self.get_serializer(queryset,many=True)
72-
data=serializer.data
73-
total_pages=1
74-
current_page=1
75-
page_size=len(data)
76-
total_items=len(data)
77-
78-
return renderResponse(data={'data':data,'totalPages':total_pages,'currentPage':current_page,'pageSize':page_size,'totalItems':total_items},message='Categories Retrieved Successfully',status=200)
42+
@CommonListAPIMixin.common_list_decorator(CategorySerializer)
43+
def list(self,request,*args,**kwargs):
44+
return super().list(request,*args,**kwargs)
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,35 @@
1-
from EcommerceInventory.Helpers import CustomPageNumberPagination, renderResponse
2-
from ProductServices.models import Products
1+
from UserServices.models import Users
2+
from EcommerceInventory.Helpers import CommonListAPIMixin, CustomPageNumberPagination, renderResponse
3+
from ProductServices.models import ProductQuestions, ProductReviews, Products
34
from rest_framework import generics
45
from rest_framework import serializers
56
from rest_framework.permissions import IsAuthenticated
67
from rest_framework_simplejwt.authentication import JWTAuthentication
78
from django.db.models import Q
89
from django.db import models
910

11+
class ProductReviewSerializer(serializers.ModelSerializer):
12+
review_user_id=serializers.SerializerMethodField()
13+
class Meta:
14+
model=ProductReviews
15+
fields='__all__'
16+
17+
def get_review_user_id(self,obj):
18+
return "#"+str(obj.review_user_id.id)+" "+obj.review_user_id.username
19+
20+
class ProductQuestionSerializer(serializers.ModelSerializer):
21+
question_user_id=serializers.SerializerMethodField()
22+
answer_user_id=serializers.SerializerMethodField()
23+
class Meta:
24+
model=ProductQuestions
25+
fields='__all__'
26+
27+
def get_question_user_id(self,obj):
28+
return "#"+str(obj.question_user_id.id)+" "+obj.question_user_id.username
29+
30+
def get_answer_user_id(self,obj):
31+
return "#"+str(obj.answer_user_id.id)+" "+obj.answer_user_id.username
32+
1033
class ProductSerializer(serializers.ModelSerializer):
1134
category_id=serializers.SerializerMethodField()
1235
domain_user_id=serializers.SerializerMethodField()
@@ -33,41 +56,91 @@ class ProductListView(generics.ListAPIView):
3356

3457
def get_queryset(self):
3558
queryset=Products.objects.filter(domain_user_id=self.request.user.domain_user_id.id)
36-
search_query=self.request.query_params.get('search',None)
37-
38-
if search_query:
39-
search_conditions=Q()
59+
return queryset
60+
61+
@CommonListAPIMixin.common_list_decorator(ProductSerializer)
62+
def list(self,request,*args,**kwargs):
63+
return super().list(request,*args,**kwargs)
4064

41-
for field in Products._meta.get_fields():
42-
if isinstance(field,(models.CharField,models.TextField)):
43-
search_conditions|=Q(**{f"{field.name}__icontains":search_query})
44-
queryset=queryset.filter(search_conditions)
4565

46-
ordering=self.request.query_params.get('ordering',None)
66+
class ProductReviewListView(generics.ListAPIView):
67+
serializer_class = ProductReviewSerializer
68+
authentication_classes = [JWTAuthentication]
69+
permission_classes = [IsAuthenticated]
70+
pagination_class = CustomPageNumberPagination
4771

48-
if ordering:
49-
queryset=queryset.order_by(ordering)
72+
def get_queryset(self):
73+
queryset=ProductReviews.objects.filter(domain_user_id=self.request.user.domain_user_id.id,product_id=self.kwargs['product_id'])
74+
return queryset
75+
76+
@CommonListAPIMixin.common_list_decorator(ProductReviewSerializer)
77+
def list(self,request,*args,**kwargs):
78+
return super().list(request,*args,**kwargs)
79+
80+
class ProductQuestionsListView(generics.ListAPIView):
81+
serializer_class = ProductQuestionSerializer
82+
authentication_classes = [JWTAuthentication]
83+
permission_classes = [IsAuthenticated]
84+
pagination_class = CustomPageNumberPagination
5085

86+
def get_queryset(self):
87+
queryset=ProductQuestions.objects.filter(domain_user_id=self.request.user.domain_user_id.id,product_id=self.kwargs['product_id'])
5188
return queryset
5289

90+
@CommonListAPIMixin.common_list_decorator(ProductQuestionSerializer)
5391
def list(self,request,*args,**kwargs):
54-
queryset=self.filter_queryset(self.get_queryset())
92+
return super().list(request,*args,**kwargs)
93+
5594

56-
page=self.paginate_queryset(queryset)
95+
class CreateProductReviewView(generics.CreateAPIView):
96+
serializer_class = ProductReviewSerializer
97+
authentication_classes = [JWTAuthentication]
98+
permission_classes = [IsAuthenticated]
99+
100+
def perform_create(self,serializer):
101+
if self.request.data.get('review_user_id'):
102+
serializer.save(domain_user_id=self.request.user.domain_user_id,review_user_id=Users.objects.get(id=int(self.request.data.get('review_user_id'))),product_id=Products.objects.get(id=self.kwargs['product_id']))
103+
else:
104+
serializer.save(domain_user_id=self.request.user.domain_user_id,product_id=Products.objects.get(id=self.kwargs['product_id']),review_user_id=self.request.user)
105+
106+
class CreateProductQuestionsView(generics.CreateAPIView):
107+
serializer_class = ProductQuestionSerializer
108+
authentication_classes = [JWTAuthentication]
109+
permission_classes = [IsAuthenticated]
110+
111+
def perform_create(self,serializer):
112+
if self.request.data.get('question_user_id') and self.request.data.get('answer_user_id'):
113+
serializer.save(domain_user_id=self.request.user.domain_user_id,question_user_id=Users.objects.get(id=int(self.request.data.get('question_user_id'))),answer_user_id=Users.objects.get(id=int(self.request.data.get('answer_user_id'))),product_id=Products.objects.get(id=self.kwargs['product_id']))
114+
else:
115+
serializer.save(domain_user_id=self.request.user.domain_user_id,product_id=Products.objects.get(id=self.kwargs['product_id']),question_user_id=self.request.user,answer_user_id=self.request.user)
116+
117+
118+
119+
class UpdateProductReviewView(generics.UpdateAPIView):
120+
serializer_class = ProductReviewSerializer
121+
authentication_classes = [JWTAuthentication]
122+
permission_classes = [IsAuthenticated]
123+
124+
def get_queryset(self):
125+
return ProductReviews.objects.filter(domain_user_id=self.request.user.domain_user_id.id,product_id=self.kwargs['product_id'],id=self.kwargs['pk'])
126+
127+
def perform_update(self,serializer):
128+
serializer.save()
129+
130+
131+
class UpdateProductQuestionsView(generics.UpdateAPIView):
132+
serializer_class = ProductQuestionSerializer
133+
authentication_classes = [JWTAuthentication]
134+
permission_classes = [IsAuthenticated]
135+
136+
def get_queryset(self):
137+
return ProductQuestions.objects.filter(domain_user_id=self.request.user.domain_user_id.id,product_id=self.kwargs['product_id'],id=self.kwargs['pk'])
57138

58-
if page is not None:
59-
serializer=self.get_serializer(page,many=True)
60-
data=serializer.data
61-
total_pages=self.paginator.page.paginator.num_pages
62-
current_page=self.paginator.page.number
63-
page_size=self.paginator.page.paginator.per_page
64-
total_items=self.paginator.page.paginator.count
139+
def perform_update(self,serializer):
140+
if self.request.data.get('answer'):
141+
if self.request.data.get('answer_user_id'):
142+
serializer.save(answer_user_id=Users.objects.get(id=int(self.request.data.get('answer_user_id'))))
143+
else:
144+
serializer.save(answer_user_id=self.request.user)
65145
else:
66-
serializer=self.get_serializer(queryset,many=True)
67-
data=serializer.data
68-
total_pages=1
69-
current_page=1
70-
page_size=len(data)
71-
total_items=len(data)
72-
73-
return renderResponse(data={'data':data,'totalPages':total_pages,'currentPage':current_page,'pageSize':page_size,'totalItems':total_items},message='Products Retrieved Successfully',status=200)
146+
serializer.save()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.0.6 on 2024-07-18 11:54
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('ProductServices', '0004_alter_categories_name'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='categories',
15+
name='image',
16+
field=models.JSONField(blank=True, null=True),
17+
),
18+
]

Backend/EcommerceInventory/ProductServices/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
class Categories(models.Model):
77
id=models.AutoField(primary_key=True)
88
name=models.CharField(max_length=255)
9-
image=models.TextField()
9+
image=models.JSONField(blank=True,null=True)
1010
description=models.TextField()
1111
display_order=models.IntegerField(default=0)
1212
parent_id=models.ForeignKey('self',on_delete=models.CASCADE,blank=True,null=True)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
from .controller.CategoryController import CategoryListView
2-
from .controller.ProductController import ProductListView
2+
from .controller.ProductController import ProductListView,ProductReviewListView,CreateProductReviewView,UpdateProductReviewView,ProductQuestionsListView,CreateProductQuestionsView,UpdateProductQuestionsView
33
from django.urls import path
44

55
urlpatterns = [
66
path('categories/',CategoryListView.as_view(),name='category_list'),
7-
path('',ProductListView.as_view(),name='product_list')
7+
path('',ProductListView.as_view(),name='product_list'),
8+
# Product Review API List,Create,Update
9+
path('productReviews/<str:product_id>/',ProductReviewListView.as_view(),name='product_review_list'),
10+
path('createProductReview/<str:product_id>/',CreateProductReviewView.as_view(),name='product_review_create'),
11+
path('updateProductReview/<str:product_id>/<pk>/',UpdateProductReviewView.as_view(),name='product_review_update'),
12+
#Product Question API List,Create,Update
13+
path('productQuestions/<str:product_id>/',ProductQuestionsListView.as_view(),name='product_question_list'),
14+
path('createProductQuestion/<str:product_id>/',CreateProductQuestionsView.as_view(),name='product_question_create'),
15+
path('updateProductQuestion/<str:product_id>/<pk>/',UpdateProductQuestionsView.as_view(),name='product_question_update'),
816
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from EcommerceInventory.Helpers import renderResponse
2+
from UserServices.models import Users
3+
from rest_framework.views import APIView
4+
from rest_framework.permissions import IsAuthenticated
5+
from rest_framework_simplejwt.authentication import JWTAuthentication
6+
from rest_framework import serializers
7+
8+
class UserSerializer(serializers.ModelSerializer):
9+
class Meta:
10+
model=Users
11+
fields=['id','username','first_name','last_name','email','profile_pic']
12+
13+
class UserListView(APIView):
14+
permission_classes = [IsAuthenticated]
15+
authentication_classes = [JWTAuthentication]
16+
def get(self,request):
17+
users=Users.objects.filter(domain_user_id=request.user.domain_user_id.id)
18+
serializer=UserSerializer(users,many=True)
19+
return renderResponse(data=serializer.data,message="All Users",status=200)
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from django.urls import path
2-
from .Controller import AuthController
2+
from .Controller import AuthController,UserController
33

44
urlpatterns = [
55
path('login/',AuthController.LoginAPIView.as_view(),name='login'),
66
path('signup/',AuthController.SignupAPIView.as_view(),name='signup'),
77
path('publicApi/',AuthController.PublicAPIView.as_view(),name='publicapi'),
88
path('protectedApi/',AuthController.ProtectedAPIView.as_view(),name='protectedapi'),
99
path('superadminurl/',AuthController.SuperAdminCheckApi.as_view(),name='superadminurl'),
10+
path('users/',UserController.UserListView.as_view(),name='user_list'),
1011
]

Frontend/ecommerce_inventory/src/components/FileInputComponents.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const FileInputComponent = ({field}) => {
1414
const [selectedFiles,setSelectedFiles]=useState([]);
1515
const [filePreviews,setFilePreviews]=useState([]);
1616
const [fileUploaded,setFileUploaded]=useState(false);
17-
const [oldFiles,setOldFiles]=useState((checkIsJson(field.default) && Array.isArray(JSON.parse(field.default)))?JSON.parse(field.default):[])
17+
const [oldFiles,setOldFiles]=useState(Array.isArray(field.default)?field.default:[])
1818
const [oldFilePreviews,setOldFilePreviews]=useState([]);
1919
const [newFilesUrl,setNewFilesUrl]=useState([])
2020

@@ -64,7 +64,7 @@ const FileInputComponent = ({field}) => {
6464
const buildFileUrls=()=>{
6565
const finalUrl=[...oldFiles,...newFilesUrl];
6666
if(finalUrl.length>0){
67-
setValue(field.name,JSON.stringify(finalUrl));
67+
setValue(field.name,finalUrl);
6868
}
6969
else{
7070
resetField(field.name);
@@ -136,8 +136,8 @@ const FileInputComponent = ({field}) => {
136136
}
137137
{
138138
selectedFiles.length>0 && !fileUploaded && (
139-
loading?<LinearProgress sx={{width:'100%'}}/>:
140-
<Box mt={2} display="flex" justifyContent="space-between">
139+
loading?<LinearProgress sx={{width:'100%',mb:2}}/>:
140+
<Box mt={2} display="flex" justifyContent="space-between" mb={2}>
141141
<Button onClick={uploadFiles} variant='contained' color='primary'>Upload Files</Button>
142142
<Button onClick={deleteAllFiles} color='primary' variant='contained'>Delete All Files</Button>
143143
</Box>
@@ -160,7 +160,7 @@ const FileInputComponent = ({field}) => {
160160
))
161161
}
162162
{
163-
!!errors[field.name] && <Alert variant="outlined" severity='error' sx={{marginTop:'10px'}}>
163+
!!errors[field.name] && <Alert variant="outlined" severity='error' sx={{marginTop:'10px',marginBottom:'10px'}}>
164164
This Field is Required and Upload the Files if Already Selected
165165
</Alert>
166166
}

0 commit comments

Comments
 (0)