Skip to content

Commit

Permalink
Merge pull request #36 from rkshaon/shaon
Browse files Browse the repository at this point in the history
frontend, backend
  • Loading branch information
rkshaon authored Jul 24, 2024
2 parents d999f23 + 89a85ac commit 8857a6d
Show file tree
Hide file tree
Showing 20 changed files with 289 additions and 81 deletions.
1 change: 1 addition & 0 deletions backend/ecommerce/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@

SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': datetime.timedelta(hours=1),
# 'ACCESS_TOKEN_LIFETIME': datetime.timedelta(minutes=1),
}


Expand Down
28 changes: 18 additions & 10 deletions backend/user_api/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin

from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import BaseUserManager
from django.contrib.auth.models import PermissionsMixin


class UserManager(BaseUserManager):
Expand All @@ -10,7 +11,6 @@ def create_user(self, email, password=None, **extra_fields):
user.set_password(password)
user.save()
return user


def create_superuser(self, email, password=None, **extra_fields):
user = self.create_user(email, password, **extra_fields)
Expand All @@ -26,10 +26,23 @@ class User(AbstractBaseUser, PermissionsMixin):
('vendor', 'Vendor'),
('admin', 'Admin'),
)

name = models.CharField(
max_length=255,
blank=True,
null=True
)
picture = models.ImageField(
upload_to='profile',
null=True,
blank=True
)
email = models.EmailField(unique=True)
username = models.CharField(max_length=50, unique=True)
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='customer')
role = models.CharField(
max_length=20,
choices=ROLE_CHOICES,
default='customer'
)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)

Expand All @@ -38,10 +51,5 @@ class User(AbstractBaseUser, PermissionsMixin):
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'role']

# def save(self, *args, **kwargs):
# if not self.pk:
# self.set_password(self.password)
# super().save(*args, **kwargs)

def __str__(self):
return self.email
8 changes: 5 additions & 3 deletions backend/user_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
from user_api.models import User



class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'username', 'role', 'password')
fields = (
'id', 'email', 'username',
'role', 'password', 'name',
'picture',
)
extra_kwargs = {'password': {'write_only': True}}


def create(self, validated_data):
user = User.objects.create_user(
email=validated_data['email'],
Expand Down
5 changes: 5 additions & 0 deletions backend/user_api/urls/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@
v1_view.UserProfileView.as_view(),
name='profile',
),
path(
'changepassword',
v1_view.ChangeUserPasswordView.as_view(),
name='change_password',
)
]
38 changes: 38 additions & 0 deletions backend/user_api/views/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,41 @@ def post(self, request):
class UserProfileView(APIView):
def get(self, request, *args, **kwargs):
return Response(UserSerializer(request.user).data)


@authentication_classes([SessionAuthentication, JWTAuthentication])
@permission_classes([IsAuthenticated])
class ChangeUserPasswordView(APIView):
def put(self, request, *args, **kwargs):
old_password = request.data.get('old_password', None)
new_password = request.data.get('new_password', None)

if not old_password or not new_password:
return Response({
'errors': [
'Old password or new password can not be empty',
]
}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)

user = request.user

if not user.check_password(old_password):
return Response({
'errors': [
'Old password does not matched!',
]
}, status=status.HTTP_400_BAD_REQUEST)

if old_password == new_password:
return Response({
'errors': [
'Old password is used!',
]
}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)

user.set_password(new_password)
user.save()

return Response({
'message': 'Password updated.'
}, status=status.HTTP_202_ACCEPTED)
2 changes: 1 addition & 1 deletion frontend/src/components/admin/page/AdminAccountingPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div>Accounting Page</div>
<div class="container mt-5">Accounting Page</div>
</template>

<script>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/admin/page/AdminCustomerPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div>Customer Page</div>
<div class="container mt-5">Customer Page</div>
</template>

<script>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/admin/page/AdminDashboardPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div>Dashboard Page</div>
<div class="container mt-5">Dashboard Page</div>
</template>

<script>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/admin/page/AdminInventoryPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div>Inventory Page</div>
<div class="container mt-5">Inventory Page</div>
</template>

<script>
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/admin/page/AdminOrderPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<template>
<div>Order Page</div>
<div class="container mt-5">
Order Page
</div>
</template>

<script>
Expand Down
36 changes: 31 additions & 5 deletions frontend/src/components/admin/page/AdminProfilePage.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
<template>
<div class="container mt-5">
<h2>{{ profileData.name }}</h2>
<img alt="Profile Picture" />
<p>Email: {{ profileData.email }}</p>
<p>Username: {{ profileData.username }}</p>
<button class="btn btn-warning">Change Password</button>
<div class="row">
<div class="col-4">
<AdminProfileCardComponent :profileData="profileData" class="mb-3" />
</div>
</div>
<AdminChangePasswordModal ref="changePasswordModal" />
<AdminUpdateUserProfileModal :profileData="profileData" ref="updateModalForUser" />
<button type="button" class="btn btn-warning" @click="showChangePasswordModal">
Change Password
</button>
<button type="button" class="btn btn-info" @click="showUpdateProfileModal">
Edit Profile
</button>
</div>
</template>

<script>
import { API_BASE_URL } from '@/config';
import { mapState, mapActions } from 'vuex';
import AdminProfileCardComponent from '@/components/admin/user/AdminProfileCardComponent.vue';
import AdminChangePasswordModal from '@/components/admin/user/AdminChangePasswordModal.vue';
import AdminUpdateUserProfileModal from '@/components/admin/user/AdminUpdateUserProfileModal.vue';
export default {
name: 'AdminProfilePage',
components: {
AdminProfileCardComponent,
AdminUpdateUserProfileModal,
AdminChangePasswordModal,
},
data() {
return {
API_BASE_URL: API_BASE_URL,
Expand All @@ -26,6 +42,16 @@ export default {
},
methods: {
...mapActions('user', ['fetchUserProfile']),
showChangePasswordModal() {
console.log('change password modal clicked');
this.$refs.changePasswordModal.showChangePasswordModal();
},
showUpdateProfileModal() {
console.log('update profile clicked.');
this.$refs.updateModalForUser.showUpdateUserModal();
},
},
created() {
this.fetchUserProfile();
Expand Down
85 changes: 85 additions & 0 deletions frontend/src/components/admin/user/AdminChangePasswordModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<template>
<div class="modal fade" id="changePasswordModal" tabindex="-1" aria-labelledby="changePasswordModalLabel"
aria-hidden="true" ref="changePasswordModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="changePasswordModalLabel">Change Password</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-start">
<form action="">
<div class="mb-3">
<label for="exampleInputText2" class="form-label">Current Password</label>
<input type="text" class="form-control" id="exampleInputText2"
v-model="changePasswordData.currentPassword">
</div>
<div class="mb-3">
<label for="exampleInputText2" class="form-label">New Password</label>
<input type="text" class="form-control" id="exampleInputText2"
v-model="changePasswordData.newPassword">
</div>
<div class="mb-3">
<label for="exampleInputText2" class="form-label">Confirm Password</label>
<input type="text" class="form-control" id="exampleInputText2"
v-model="changePasswordData.confirmPassword">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" @click="confirmUpdate">Save
changes</button>
</div>
</div>
</div>
</div>
</template>

<script>
import { API_BASE_URL } from '@/config';
import { Modal } from 'bootstrap';
import { useToast } from 'vue-toastification';
export default {
name: 'AdminChangePasswordModal.vue',
components: {
},
props: {
},
data() {
return {
API_BASE_URL: API_BASE_URL,
changePasswordData: {
currentPassword: '',
newPassword: '',
confirmPassword: '',
}
}
},
methods: {
async showChangePasswordModal() {
const modalElement = this.$refs.changePasswordModal;
if (modalElement) {
const modal = new Modal(modalElement);
modal.show();
} else {
const toast = useToast();
toast.error("404");
console.log('404');
}
},
async confirmUpdate() {
console.log('Confirm update function called.');
const toast = useToast();
toast.info("work in progress");
const modalElement = this.$refs.changePasswordModal;
const modal = new Modal(modalElement);
modal._hideModal();
},
}
}
</script>
38 changes: 38 additions & 0 deletions frontend/src/components/admin/user/AdminProfileCardComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<div class="card">
<img v-if="profileData.picture" :src="`${API_BASE_URL}${profileData.picture}`" :alt="profileData.name"
class="card-img-top" height="250" width="250" />
<img v-else src="@/assets/loading.gif" alt="Static Photo" class="card-img-top" height="250" width="250">
<h5 class="card-title">{{ profileData.name }}</h5>
<h6 class="card-title">{{ profileData.role }}</h6>
<div class="card-body">
<p class="card-text">
<font-awesome-icon :icon="['fas', 'envelope']" size="lg" />
{{ profileData.email }}
</p>
<p class="card-text">
<font-awesome-icon :icon="['fas', 'envelope']" size="lg" />
{{ profileData.username }}
</p>
</div>
</div>
</template>

<script>
import { API_BASE_URL } from '@/config';
export default {
name: 'AdminProfileCardComponent',
props: {
profileData: {
type: Object,
required: true,
},
},
data() {
return {
API_BASE_URL: API_BASE_URL,
}
},
}
</script>
Loading

0 comments on commit 8857a6d

Please sign in to comment.