From 887cff7fd3275ce8b2a5988369a1606dfbf7b759 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Thu, 26 Aug 2021 13:32:15 +0430 Subject: [PATCH 001/439] Build: build base of project --- manage.py | 22 ++++++++ snapp_food/__init__.py | 0 snapp_food/asgi.py | 16 ++++++ snapp_food/settings.py | 123 +++++++++++++++++++++++++++++++++++++++++ snapp_food/urls.py | 21 +++++++ snapp_food/wsgi.py | 16 ++++++ 6 files changed, 198 insertions(+) create mode 100755 manage.py create mode 100644 snapp_food/__init__.py create mode 100644 snapp_food/asgi.py create mode 100644 snapp_food/settings.py create mode 100644 snapp_food/urls.py create mode 100644 snapp_food/wsgi.py diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..1a179c9 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'snapp_food.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/snapp_food/__init__.py b/snapp_food/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/snapp_food/asgi.py b/snapp_food/asgi.py new file mode 100644 index 0000000..5c30968 --- /dev/null +++ b/snapp_food/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for snapp_food project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'snapp_food.settings') + +application = get_asgi_application() diff --git a/snapp_food/settings.py b/snapp_food/settings.py new file mode 100644 index 0000000..88b5e70 --- /dev/null +++ b/snapp_food/settings.py @@ -0,0 +1,123 @@ +""" +Django settings for snapp_food project. + +Generated by 'django-admin startproject' using Django 3.2. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.2/ref/settings/ +""" + +from pathlib import Path +from local_settings import * +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ + + + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'snapp_food.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'snapp_food.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': DB_NAME, + 'USER': DB_USER, + 'PASSWORD': DB_PASSWORD, + 'HOST': DB_HOST, + 'PORT': DB_PORT, + } +} + + +# Password validation +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Asia/Tehran' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.2/howto/static-files/ + +STATIC_URL = '/static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/snapp_food/urls.py b/snapp_food/urls.py new file mode 100644 index 0000000..7f88547 --- /dev/null +++ b/snapp_food/urls.py @@ -0,0 +1,21 @@ +"""snapp_food URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] diff --git a/snapp_food/wsgi.py b/snapp_food/wsgi.py new file mode 100644 index 0000000..5bcd78e --- /dev/null +++ b/snapp_food/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for snapp_food project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'snapp_food.settings') + +application = get_wsgi_application() From 91a6905315c43cfb89145d763aee46b007fe5104 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Thu, 26 Aug 2021 13:32:55 +0430 Subject: [PATCH 002/439] Chore(gitignore): update the gitignore for .idea files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b6e4761..a8d9f1d 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ coverage.xml # Translations *.mo *.pot +.idea/ # Django stuff: *.log From e13a1b9c1db753d698afb7237a68a8de51562422 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Thu, 26 Aug 2021 14:23:31 +0430 Subject: [PATCH 003/439] Docs(readme): make a document for project --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0adb466..9616d3c 100644 --- a/README.md +++ b/README.md @@ -1 +1,48 @@ -# snapp_food \ No newline at end of file +Snapp Food clone +--- +**This project is going to be a clone of sanpp food with Python and Django framework.** + +--- + +## What is sanpp food? + +It’s actually a service which users can order food very easily and restaurant managers can register their services so +that other people can use them. + +As I said this is going to be a clone of this service , clearly It’s not going to implement all the features + +--- + +## The goal of this project: + +The main purpose of this project is being an acceptable resume and also a good practice of Django framework + +--- + +## Features: + +- [ ] We will have two type of users in this project : 1 - Customer 2 - Service Provider +- [ ] Each service provider can provide different services such as (restaurant, fast food, confectionery, supermarket, + …) +- [ ] Each service will be able to have a menu containing different items +- [ ] Each service will be able to have custom categories for the items of the menu +- [ ] Each service provider must specify the supported areas for the item delivery for the service +- [ ] Each service provider can add discount on some of their items for a limited time +- [ ] Each service will have active days and hours +- [ ] Each customer can have different addresses +- [ ] Each customer will be able to see the services(only the supported services in their area) +- [ ] Each customer can add items to their cart(note : Each cart can only contain items from one specific service, that + means adding items from different services causes multiple carts) +- [ ] Each customer will be able to add comment for the items which was in their cart after the order was delivered( + note: customers will be able to add one comment for an item after each successful order) +- [ ] Each item will have a score based on its comments +- [ ] Each user will be to see the status of the order after the payment has been successful + +--- + +## Architecture of the project: + +The project is based on the MVT architecture of the Django framework, so we will use SSR(server side rendering) + +--- + From 9439df2cdb73eb492e7652d1c26f6d6d53d4aaaa Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 12:36:48 +0430 Subject: [PATCH 004/439] Add(library): create library package --- library/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 library/__init__.py diff --git a/library/__init__.py b/library/__init__.py new file mode 100644 index 0000000..e69de29 From 119bc22e50cb76d40ab4db9ca5767bb47cdde4ef Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 12:37:47 +0430 Subject: [PATCH 005/439] Add(library): create models.py --- library/models.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 library/models.py diff --git a/library/models.py b/library/models.py new file mode 100644 index 0000000..e69de29 From 85246f776f142ddede27efc05fdd60ee2ae08a3d Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 12:40:16 +0430 Subject: [PATCH 006/439] Update(library): add BaseModel --- library/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/models.py b/library/models.py index e69de29..c3fe5f6 100644 --- a/library/models.py +++ b/library/models.py @@ -0,0 +1,9 @@ +from django.db import models + + +class BaseModel(models.Model): + created_time = models.DateTimeField(verbose_name='created time', auto_now_add=True) + modified_time = models.DateTimeField(verbose_name='modified time', auto_now=True) + + class Meta: + abstract = True From 869537e2236291fcb01d32dc6d6db39ba19c356f Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 12:52:29 +0430 Subject: [PATCH 007/439] Add(accounts): create accounts app --- accounts/__init__.py | 0 accounts/admin.py | 3 +++ accounts/apps.py | 6 ++++++ accounts/migrations/__init__.py | 0 accounts/models.py | 3 +++ accounts/tests.py | 3 +++ accounts/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 accounts/__init__.py create mode 100644 accounts/admin.py create mode 100644 accounts/apps.py create mode 100644 accounts/migrations/__init__.py create mode 100644 accounts/models.py create mode 100644 accounts/tests.py create mode 100644 accounts/views.py diff --git a/accounts/__init__.py b/accounts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounts/admin.py b/accounts/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/accounts/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/accounts/apps.py b/accounts/apps.py new file mode 100644 index 0000000..3e3c765 --- /dev/null +++ b/accounts/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'accounts' diff --git a/accounts/migrations/__init__.py b/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounts/models.py b/accounts/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/accounts/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/accounts/tests.py b/accounts/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/accounts/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/accounts/views.py b/accounts/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/accounts/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From 3b9cd9762d8580dfdaa849fadef409581363f4f4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 13:28:10 +0430 Subject: [PATCH 008/439] Update(accounts/models): create customer model --- accounts/models.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/accounts/models.py b/accounts/models.py index 71a8362..85d8b9f 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,3 +1,38 @@ +from django.contrib.auth.base_user import AbstractBaseUser +from django.contrib.auth.models import PermissionsMixin from django.db import models +from django.utils import timezone +from django.utils.translation import ugettext_lazy as _ -# Create your models here. + +class Customer(AbstractBaseUser, PermissionsMixin): + phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) + first_name = models.CharField(_('first name'), max_length=150, blank=True) + last_name = models.CharField(_('last name'), max_length=150, blank=True) + is_staff = models.BooleanField( + _('staff status'), + default=False, + help_text=_('Designates whether the user can log into this admin site.'), + ) + is_active = models.BooleanField( + _('active'), + default=True, + help_text=_( + 'Designates whether this user should be treated as active. ' + 'Unselect this instead of deleting accounts.' + ), + ) + date_joined = models.DateTimeField(_('date joined'), default=timezone.now) + + USERNAME_FIELD = 'phone_number' + REQUIRED_FIELDS = [] + + @property + def full_name(self): + full_name = '%s %s' % (self.first_name, self.last_name) + return full_name.strip() + + class Meta: + verbose_name = _('customer') + verbose_name_plural = _('customers') + db_table = 'customer' From b539ec84496267ccfe11ab80cf0da2ecf121df6b Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 13:33:44 +0430 Subject: [PATCH 009/439] Update(accounts/models): create ServiceProvider model --- accounts/models.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/accounts/models.py b/accounts/models.py index 85d8b9f..f9a3472 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,5 +1,5 @@ from django.contrib.auth.base_user import AbstractBaseUser -from django.contrib.auth.models import PermissionsMixin +from django.contrib.auth.models import PermissionsMixin, AbstractUser from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ @@ -36,3 +36,13 @@ class Meta: verbose_name = _('customer') verbose_name_plural = _('customers') db_table = 'customer' + + +class ServiceProvider(AbstractUser): + email = models.EmailField(_('email address'), blank=True, unique=True) + phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) + + class Meta: + verbose_name = _('service provider') + verbose_name_plural = _('service providers') + db_table = 'service_provider' From a292732ff8446428b175975b7e9aa00dff67550c Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 13:39:18 +0430 Subject: [PATCH 010/439] Update(accounts/models): create CustomerManager class --- accounts/models.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/accounts/models.py b/accounts/models.py index f9a3472..167ac0a 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,10 +1,39 @@ from django.contrib.auth.base_user import AbstractBaseUser -from django.contrib.auth.models import PermissionsMixin, AbstractUser +from django.contrib.auth.hashers import make_password +from django.contrib.auth.models import PermissionsMixin, AbstractUser, UserManager from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ +class CustomerManager(UserManager): + def _create_user(self, phone_number, password, **extra_fields): + + if not phone_number: + raise ValueError('The given phone must be set') + + user = self.model(phone_number=phone_number, **extra_fields) + user.password = make_password(password) + user.save(using=self._db) + return user + + def create_user(self, phone_number, password=None, **extra_fields): + extra_fields.setdefault('is_staff', False) + extra_fields.setdefault('is_superuser', False) + return self._create_user(phone_number, password, **extra_fields) + + def create_superuser(self, phone_number, password=None, **extra_fields): + extra_fields.setdefault('is_staff', True) + extra_fields.setdefault('is_superuser', True) + + if extra_fields.get('is_staff') is not True: + raise ValueError('Superuser must have is_staff=True.') + if extra_fields.get('is_superuser') is not True: + raise ValueError('Superuser must have is_superuser=True.') + + return self._create_user(phone_number, password, **extra_fields) + + class Customer(AbstractBaseUser, PermissionsMixin): phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) first_name = models.CharField(_('first name'), max_length=150, blank=True) From a9645424418cd60d384fd0ec5a2227475f79ed3d Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 13:42:34 +0430 Subject: [PATCH 011/439] Update(accounts/models): assing CustomerManger to Customer --- accounts/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/accounts/models.py b/accounts/models.py index 167ac0a..c64adfc 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -55,6 +55,7 @@ class Customer(AbstractBaseUser, PermissionsMixin): USERNAME_FIELD = 'phone_number' REQUIRED_FIELDS = [] + objects = CustomerManager() @property def full_name(self): From 0ea8c145acf6c9461af3a862906a1ad3e3c93c3a Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 14:01:15 +0430 Subject: [PATCH 012/439] fix(settings): fix import error for local_settings --- snapp_food/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 88b5e70..d12b9ef 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -11,7 +11,7 @@ """ from pathlib import Path -from local_settings import * +from snapp_food.local_settings import * # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent From 1b738871b447a9f53b745b5f8183baee84cd6dfd Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 14:25:51 +0430 Subject: [PATCH 013/439] Update(accounts/models): create User model --- accounts/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/accounts/models.py b/accounts/models.py index c64adfc..615b2fb 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -6,6 +6,13 @@ from django.utils.translation import ugettext_lazy as _ +class User(AbstractUser): + class Meta: + verbose_name = _('user') + verbose_name_plural = _('users') + db_table = 'user' + + class CustomerManager(UserManager): def _create_user(self, phone_number, password, **extra_fields): From ea6d2d5300ff42cf129c0131c2a405c996f09044 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 14:31:32 +0430 Subject: [PATCH 014/439] Todo(accounts/models): add one todo in User class --- accounts/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/accounts/models.py b/accounts/models.py index 615b2fb..a019339 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -7,6 +7,8 @@ class User(AbstractUser): + # TODO : AUTH_USER_MODEL must be changed to this model in settings + class Meta: verbose_name = _('user') verbose_name_plural = _('users') From 74c9e8c1df3f22b36ac820f38ff57645db2645e7 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 15:30:53 +0430 Subject: [PATCH 015/439] Update(accounts/admin): register accounts models to admin panel --- accounts/admin.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/accounts/admin.py b/accounts/admin.py index 8c38f3f..12ad204 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -1,3 +1,26 @@ from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from django.utils.translation import gettext as _ -# Register your models here. +from accounts.models import User, Customer, ServiceProvider + + +@admin.register(User) +class CustomUserAdmin(UserAdmin): + pass + + +@admin.register(Customer) +class CustomerAdmin(admin.ModelAdmin): + list_display = ('phone_number', 'first_name', 'last_name', 'date_joined', 'is_active') + list_filter = ('is_active', 'date_joined') + search_fields = ('phone_number',) + + +@admin.register(ServiceProvider) +class ServiceProviderAdmin(UserAdmin): + list_display = UserAdmin.list_display + ('phone_number',) + search_fields = UserAdmin.search_fields + ('phone_number',) + fieldsets = UserAdmin.fieldsets + ( + (_("Phone number"), {'fields': ('phone_number',)}), + ) From fea7e7a33c9aaefdd4ffb27a5fe2db119caf85ed Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 15:45:40 +0430 Subject: [PATCH 016/439] Comment(accounts/models): add a comment in User model --- accounts/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/accounts/models.py b/accounts/models.py index a019339..e7fb438 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -7,6 +7,7 @@ class User(AbstractUser): + # this model is used for admins and superusers # TODO : AUTH_USER_MODEL must be changed to this model in settings class Meta: From 00f8c997824a95b7bf42d181a000f07ef554c51c Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 15:46:28 +0430 Subject: [PATCH 017/439] Add(item): create item app --- item/__init__.py | 0 item/admin.py | 3 +++ item/apps.py | 6 ++++++ item/migrations/__init__.py | 0 item/models.py | 3 +++ item/tests.py | 3 +++ item/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 item/__init__.py create mode 100644 item/admin.py create mode 100644 item/apps.py create mode 100644 item/migrations/__init__.py create mode 100644 item/models.py create mode 100644 item/tests.py create mode 100644 item/views.py diff --git a/item/__init__.py b/item/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/item/admin.py b/item/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/item/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/item/apps.py b/item/apps.py new file mode 100644 index 0000000..f290658 --- /dev/null +++ b/item/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ItemConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'item' diff --git a/item/migrations/__init__.py b/item/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/item/models.py b/item/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/item/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/item/tests.py b/item/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/item/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/item/views.py b/item/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/item/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From a3377a8073fed83701be3ef6f5ac1a8865f713a4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 15:56:48 +0430 Subject: [PATCH 018/439] Update(item/models): create Item model --- item/models.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/item/models.py b/item/models.py index 71a8362..228e3ed 100644 --- a/item/models.py +++ b/item/models.py @@ -1,3 +1,20 @@ from django.db import models +from django.utils.translation import gettext as _ -# Create your models here. +from library.models import BaseModel + + +class Item(BaseModel): + upc = models.BigIntegerField(unique=True, db_index=True) + name = models.CharField(verbose_name=_('name'), max_length=50) + description = models.TextField(verbose_name=_('description'), blank=True) + price = models.IntegerField(verbose_name=_('price')) + image = models.ImageField(verbose_name=_('image'), blank=True, null=True, upload_to='items/') + + # TODO-1: Service model must be created for the relation + # TODO-2 : ServiceCategory must be created for the relation + + class Meta: + verbose_name = _('item') + verbose_name_plural = _('items') + db_table = 'item' From be85a024954e21c1a2dfd862a7454cdb7d81976c Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:09:06 +0430 Subject: [PATCH 019/439] Update(item/models): create ItemLine model --- item/models.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/item/models.py b/item/models.py index 228e3ed..a3e7278 100644 --- a/item/models.py +++ b/item/models.py @@ -18,3 +18,14 @@ class Meta: verbose_name = _('item') verbose_name_plural = _('items') db_table = 'item' + + +class ItemLine(BaseModel): + item = models.OneToOneField(Item, related_name='line', on_delete=models.CASCADE) + quantity = models.PositiveIntegerField(default=0) + + class Meta: + verbose_name = _('item line') + verbose_name_plural = _('item lines') + db_table = 'item_line' + From 4aa7c603072b3610616f36bb90f686e0987179e4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:12:25 +0430 Subject: [PATCH 020/439] Feat(item/models): add str method and stock property to Item mdoel --- item/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/item/models.py b/item/models.py index a3e7278..afaa3e5 100644 --- a/item/models.py +++ b/item/models.py @@ -19,6 +19,13 @@ class Meta: verbose_name_plural = _('items') db_table = 'item' + def __str__(self): + return self.name + + @property + def stock(self): + return self.line.quantity + class ItemLine(BaseModel): item = models.OneToOneField(Item, related_name='line', on_delete=models.CASCADE) @@ -28,4 +35,3 @@ class Meta: verbose_name = _('item line') verbose_name_plural = _('item lines') db_table = 'item_line' - From 8017f35fcebd0b69f6594d36384e5489650381a7 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:14:26 +0430 Subject: [PATCH 021/439] Feat(accounts/models): add str method to Customer model --- accounts/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/accounts/models.py b/accounts/models.py index e7fb438..c283c4c 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -72,6 +72,9 @@ def full_name(self): full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() + def __str__(self): + return f"{self.full_name} - {self.phone_number}" + class Meta: verbose_name = _('customer') verbose_name_plural = _('customers') From 99f0092848f65e41ee1d2af3ad2d03e74fe8e170 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:17:24 +0430 Subject: [PATCH 022/439] Feat(item/models): add available field to Item --- item/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/item/models.py b/item/models.py index afaa3e5..9d8af1f 100644 --- a/item/models.py +++ b/item/models.py @@ -6,6 +6,7 @@ class Item(BaseModel): upc = models.BigIntegerField(unique=True, db_index=True) + available = models.BooleanField(default=True) name = models.CharField(verbose_name=_('name'), max_length=50) description = models.TextField(verbose_name=_('description'), blank=True) price = models.IntegerField(verbose_name=_('price')) From 507288ad57dc4ab564e3579af6cb5194c7c7aa3d Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:19:30 +0430 Subject: [PATCH 023/439] Add(item/models): add ItemManager fot Item model --- item/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/item/models.py b/item/models.py index 9d8af1f..e400683 100644 --- a/item/models.py +++ b/item/models.py @@ -4,6 +4,11 @@ from library.models import BaseModel +class ItemManager(models.Manager): + def available(self): + return self.get_queryset().first(available=True) + + class Item(BaseModel): upc = models.BigIntegerField(unique=True, db_index=True) available = models.BooleanField(default=True) @@ -12,6 +17,8 @@ class Item(BaseModel): price = models.IntegerField(verbose_name=_('price')) image = models.ImageField(verbose_name=_('image'), blank=True, null=True, upload_to='items/') + objects = ItemManager() + # TODO-1: Service model must be created for the relation # TODO-2 : ServiceCategory must be created for the relation From 21e8ba806e3b663b0e9dad71147b4aed4fc42122 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:23:47 +0430 Subject: [PATCH 024/439] Add(item/admin): register Item model to admin panel --- item/admin.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/item/admin.py b/item/admin.py index 8c38f3f..cf811d6 100644 --- a/item/admin.py +++ b/item/admin.py @@ -1,3 +1,11 @@ from django.contrib import admin -# Register your models here. +from item.models import Item + + +@admin.register(Item) +class Item(admin.ModelAdmin): + list_display = ('name', 'upc', 'price', 'stock', 'available') + list_editable = ('available',) + list_filter = ('available', 'created_time') + search_fields = ('upc', 'name') From 15134a81bf186c43694c939822085a6510d0654d Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:25:51 +0430 Subject: [PATCH 025/439] Add(cart): create cart app --- cart/__init__.py | 0 cart/admin.py | 3 +++ cart/apps.py | 6 ++++++ cart/migrations/__init__.py | 0 cart/models.py | 3 +++ cart/tests.py | 3 +++ cart/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 cart/__init__.py create mode 100644 cart/admin.py create mode 100644 cart/apps.py create mode 100644 cart/migrations/__init__.py create mode 100644 cart/models.py create mode 100644 cart/tests.py create mode 100644 cart/views.py diff --git a/cart/__init__.py b/cart/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cart/admin.py b/cart/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/cart/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cart/apps.py b/cart/apps.py new file mode 100644 index 0000000..f3e3ec9 --- /dev/null +++ b/cart/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CartConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'cart' diff --git a/cart/migrations/__init__.py b/cart/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cart/models.py b/cart/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/cart/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/cart/tests.py b/cart/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/cart/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cart/views.py b/cart/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/cart/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From 2ba1d1115a3bb46fffde80b4bfc52985f31ca334 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:34:31 +0430 Subject: [PATCH 026/439] Add(cart/models): create Cart model --- cart/models.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cart/models.py b/cart/models.py index 71a8362..9dd3e5a 100644 --- a/cart/models.py +++ b/cart/models.py @@ -1,3 +1,15 @@ from django.db import models +from django.utils.translation import gettext as _ +from accounts.models import Customer +from library.models import BaseModel -# Create your models here. + +class Cart(BaseModel): + customer = models.ForeignKey(Customer, verbose_name=_('customer'), null=True, blank=True, related_name='carts', + on_delete=models.CASCADE) + is_paid = models.BooleanField(default=False, verbose_name=_('is paid')) + + # TODO-1: Invoice model must be created for the relation + + def __str__(self): + return f"{self.customer} - {'Paid' if self.is_paid else 'Not paid'}" From 8b4142156d4371611d0cc9198b71ac923a2e1559 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:39:28 +0430 Subject: [PATCH 027/439] Add(cart/models): create CartLine model --- cart/models.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cart/models.py b/cart/models.py index 9dd3e5a..8e43c53 100644 --- a/cart/models.py +++ b/cart/models.py @@ -1,6 +1,7 @@ from django.db import models from django.utils.translation import gettext as _ from accounts.models import Customer +from item.models import Item from library.models import BaseModel @@ -13,3 +14,12 @@ class Cart(BaseModel): def __str__(self): return f"{self.customer} - {'Paid' if self.is_paid else 'Not paid'}" + + +class CartLine(BaseModel): + item = models.ForeignKey(Item, verbose_name=_('item'), related_name='lines', on_delete=models.SET_NULL) + cart = models.ForeignKey(Cart, verbose_name=_('cart'), related_name='lines', on_delete=models.CASCADE) + quantity = models.PositiveIntegerField(default=1, verbose_name=_('quantity')) + + def __str__(self): + return f"{self.item} - {self.quantity}" From d654bf759f4e65d93411e9b1e922fc0a5c86564e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:40:34 +0430 Subject: [PATCH 028/439] Fix(item/admin): change the class name to ItemAdmin --- item/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/item/admin.py b/item/admin.py index cf811d6..2325eb4 100644 --- a/item/admin.py +++ b/item/admin.py @@ -4,7 +4,7 @@ @admin.register(Item) -class Item(admin.ModelAdmin): +class ItemAdmin(admin.ModelAdmin): list_display = ('name', 'upc', 'price', 'stock', 'available') list_editable = ('available',) list_filter = ('available', 'created_time') From f8a4519f3a865964876935c6431e936f71d43e32 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:45:37 +0430 Subject: [PATCH 029/439] Add(cart/admin): register Cart and CartLine to admin panel --- cart/admin.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cart/admin.py b/cart/admin.py index 8c38f3f..9db535e 100644 --- a/cart/admin.py +++ b/cart/admin.py @@ -1,3 +1,16 @@ from django.contrib import admin -# Register your models here. +from cart.models import Cart, CartLine + + +class CartLineInline(admin.TabularInline): + model = CartLine + extra = 0 + + +@admin.register(Cart) +class CartAdmin(admin.ModelAdmin): + list_display = ('customer', 'is_paid') + list_filter = ('is_paid',) + search_fields = ('customer__phone_number',) + inlines = [CartLineInline] From bdbe3e12bde9081de950e21fbee54199f3b2c4d5 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:47:46 +0430 Subject: [PATCH 030/439] Update(item/models): add verbous name for upc and available in Item --- item/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/item/models.py b/item/models.py index e400683..ae52d1e 100644 --- a/item/models.py +++ b/item/models.py @@ -10,8 +10,8 @@ def available(self): class Item(BaseModel): - upc = models.BigIntegerField(unique=True, db_index=True) - available = models.BooleanField(default=True) + upc = models.BigIntegerField(verbose_name=_('upc'), unique=True, db_index=True) + available = models.BooleanField(verbose_name=_('available'), default=True) name = models.CharField(verbose_name=_('name'), max_length=50) description = models.TextField(verbose_name=_('description'), blank=True) price = models.IntegerField(verbose_name=_('price')) From 337dfd398e6a37a0bdbc9026acf98567e417ab81 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:50:16 +0430 Subject: [PATCH 031/439] Add(payment): create payment app --- payment/__init__.py | 0 payment/admin.py | 3 +++ payment/apps.py | 6 ++++++ payment/migrations/__init__.py | 0 payment/models.py | 3 +++ payment/tests.py | 3 +++ payment/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 payment/__init__.py create mode 100644 payment/admin.py create mode 100644 payment/apps.py create mode 100644 payment/migrations/__init__.py create mode 100644 payment/models.py create mode 100644 payment/tests.py create mode 100644 payment/views.py diff --git a/payment/__init__.py b/payment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/payment/admin.py b/payment/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/payment/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/payment/apps.py b/payment/apps.py new file mode 100644 index 0000000..b4a45c3 --- /dev/null +++ b/payment/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PaymentConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'payment' diff --git a/payment/migrations/__init__.py b/payment/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/payment/models.py b/payment/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/payment/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/payment/tests.py b/payment/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/payment/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/payment/views.py b/payment/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/payment/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From 39c248ccad5abc6139fc490ba77aa4c234456a43 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 16:55:00 +0430 Subject: [PATCH 032/439] Update(cart/models): add class Meta for Cart and CartLine --- cart/models.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cart/models.py b/cart/models.py index 8e43c53..9841b48 100644 --- a/cart/models.py +++ b/cart/models.py @@ -15,6 +15,11 @@ class Cart(BaseModel): def __str__(self): return f"{self.customer} - {'Paid' if self.is_paid else 'Not paid'}" + class Meta: + verbose_name = _('cart') + verbose_name_plural = _('carts') + db_table = 'cart' + class CartLine(BaseModel): item = models.ForeignKey(Item, verbose_name=_('item'), related_name='lines', on_delete=models.SET_NULL) @@ -23,3 +28,8 @@ class CartLine(BaseModel): def __str__(self): return f"{self.item} - {self.quantity}" + + class Meta: + verbose_name = _('cart line') + verbose_name_plural = _('cart lines') + db_table = 'cart_line' From e53bbd1b5ffb313a42dbc51b8619c16e84c97c52 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 17:04:52 +0430 Subject: [PATCH 033/439] Add(payment/models): add Invoice model --- payment/models.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/payment/models.py b/payment/models.py index 71a8362..568dfa6 100644 --- a/payment/models.py +++ b/payment/models.py @@ -1,3 +1,18 @@ from django.db import models +from django.utils.translation import gettext as _ +from accounts.models import Customer +from library.models import BaseModel -# Create your models here. + +class Invoice(BaseModel): + customer = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='invoices', + on_delete=models.SET_NULL) + price = models.IntegerField(verbose_name=_('price')) + is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) + + # TODO: Address must be created for relation + + class Meta: + verbose_name = _('invoice') + verbose_name_plural = _('invoices') + db_table = 'invoice' From 766084fccea73ffe99eb5339adbe699aa9c83943 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 17:09:05 +0430 Subject: [PATCH 034/439] Add(payment/models): add Payment model --- payment/models.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/payment/models.py b/payment/models.py index 568dfa6..c419d78 100644 --- a/payment/models.py +++ b/payment/models.py @@ -16,3 +16,15 @@ class Meta: verbose_name = _('invoice') verbose_name_plural = _('invoices') db_table = 'invoice' + + +class Payment(BaseModel): + uuid = models.UUIDField(unique=True, verbose_name=_('uuid')) + invoice = models.OneToOneField(Invoice, verbose_name=_('invoice'), related_name='payment', on_delete=models.CASCADE) + price = models.IntegerField(verbose_name=_('price')) + is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) + + class Meta: + verbose_name = _('payment') + verbose_name_plural = _('payments') + db_table = 'payment' From 86ad98228ded98076926ff0b22b6047bc7d71553 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 17:11:22 +0430 Subject: [PATCH 035/439] Feat(payment/models): add str method for Invoice, Payment --- payment/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/payment/models.py b/payment/models.py index c419d78..26f36f6 100644 --- a/payment/models.py +++ b/payment/models.py @@ -17,6 +17,9 @@ class Meta: verbose_name_plural = _('invoices') db_table = 'invoice' + def __str__(self): + return f"{self.customer} - {self.price} - {'Paid' if self.is_paid else 'Not paid'}" + class Payment(BaseModel): uuid = models.UUIDField(unique=True, verbose_name=_('uuid')) @@ -28,3 +31,6 @@ class Meta: verbose_name = _('payment') verbose_name_plural = _('payments') db_table = 'payment' + + def __str__(self): + return f"{self.price} - {'Paid' if self.is_paid else 'Not paid'}" From 994944c65218f5de10100be0ee56281de756d576 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 17:15:47 +0430 Subject: [PATCH 036/439] Add(payment/admin): register Invoice, Admin to admin panel --- payment/admin.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/payment/admin.py b/payment/admin.py index 8c38f3f..7e18605 100644 --- a/payment/admin.py +++ b/payment/admin.py @@ -1,3 +1,17 @@ from django.contrib import admin -# Register your models here. +from payment.models import Invoice, Payment + + +@admin.register(Invoice) +class InvoiceAdmin(admin.ModelAdmin): + list_display = ('customer', 'price', 'is_paid') + list_filter = ('is_paid',) + search_fields = ('customer__phone_number',) + + +@admin.register(Payment) +class PaymentAdmin(admin.ModelAdmin): + list_display = ('uuid', 'price', 'is_paid') + list_filter = ('is_paid',) + search_fields = ('uuid',) From fefc464f456c5599a145735da93a4e91ac6e74d7 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 17:19:54 +0430 Subject: [PATCH 037/439] Update(cart/models): add invoice relation to Cart model --- cart/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cart/models.py b/cart/models.py index 9841b48..98df402 100644 --- a/cart/models.py +++ b/cart/models.py @@ -3,14 +3,14 @@ from accounts.models import Customer from item.models import Item from library.models import BaseModel +from payment.models import Invoice class Cart(BaseModel): customer = models.ForeignKey(Customer, verbose_name=_('customer'), null=True, blank=True, related_name='carts', on_delete=models.CASCADE) is_paid = models.BooleanField(default=False, verbose_name=_('is paid')) - - # TODO-1: Invoice model must be created for the relation + invoice = models.OneToOneField(Invoice, verbose_name=_('invoice'), related_name='cart', on_delete=models.PROTECT) def __str__(self): return f"{self.customer} - {'Paid' if self.is_paid else 'Not paid'}" From fba2625d2376c392a412c0b3588adf07eac53441 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 17:20:55 +0430 Subject: [PATCH 038/439] Update(cart/models): add null, blank True for invoic of cart --- cart/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cart/models.py b/cart/models.py index 98df402..6c39dc0 100644 --- a/cart/models.py +++ b/cart/models.py @@ -10,7 +10,8 @@ class Cart(BaseModel): customer = models.ForeignKey(Customer, verbose_name=_('customer'), null=True, blank=True, related_name='carts', on_delete=models.CASCADE) is_paid = models.BooleanField(default=False, verbose_name=_('is paid')) - invoice = models.OneToOneField(Invoice, verbose_name=_('invoice'), related_name='cart', on_delete=models.PROTECT) + invoice = models.OneToOneField(Invoice, verbose_name=_('invoice'), related_name='cart', on_delete=models.PROTECT, + null=True, blank=True) def __str__(self): return f"{self.customer} - {'Paid' if self.is_paid else 'Not paid'}" From 921366bfc2ee4d9aff86d29c4ae7945789fe4ac4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 17:22:25 +0430 Subject: [PATCH 039/439] Update(payment/models): add null, blank True for customer of invoice --- payment/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/payment/models.py b/payment/models.py index 26f36f6..a2558d8 100644 --- a/payment/models.py +++ b/payment/models.py @@ -6,7 +6,7 @@ class Invoice(BaseModel): customer = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='invoices', - on_delete=models.SET_NULL) + on_delete=models.SET_NULL, null=True, blank=True) price = models.IntegerField(verbose_name=_('price')) is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) From eff96af66e7f1035bca3af9540108a9e2473caed Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 11:23:32 +0430 Subject: [PATCH 040/439] Fix(setting): fix import local setting --- snapp_food/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 88b5e70..d12b9ef 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -11,7 +11,7 @@ """ from pathlib import Path -from local_settings import * +from snapp_food.local_settings import * # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent From 90832ba3ec15140dc8c68125fc32e197b7238e47 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 12:36:48 +0430 Subject: [PATCH 041/439] Add(library): create library package --- library/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 library/__init__.py diff --git a/library/__init__.py b/library/__init__.py new file mode 100644 index 0000000..e69de29 From b31c4357a6d006197a7e01822cddc7ee92564436 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 12:37:47 +0430 Subject: [PATCH 042/439] Add(library): create models.py --- library/models.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 library/models.py diff --git a/library/models.py b/library/models.py new file mode 100644 index 0000000..e69de29 From a830a3998fadc8774a869d5c11fc18e325d7725e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 12:40:16 +0430 Subject: [PATCH 043/439] Update(library): add BaseModel --- library/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/models.py b/library/models.py index e69de29..c3fe5f6 100644 --- a/library/models.py +++ b/library/models.py @@ -0,0 +1,9 @@ +from django.db import models + + +class BaseModel(models.Model): + created_time = models.DateTimeField(verbose_name='created time', auto_now_add=True) + modified_time = models.DateTimeField(verbose_name='modified time', auto_now=True) + + class Meta: + abstract = True From 5b550e1da44bdbd13b30c08009a44996688d5e42 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 18:19:11 +0430 Subject: [PATCH 044/439] Add(address): add address app into project --- address/__init__.py | 0 address/admin.py | 3 +++ address/apps.py | 6 ++++++ address/migrations/__init__.py | 0 address/models.py | 3 +++ address/tests.py | 3 +++ address/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 address/__init__.py create mode 100644 address/admin.py create mode 100644 address/apps.py create mode 100644 address/migrations/__init__.py create mode 100644 address/models.py create mode 100644 address/tests.py create mode 100644 address/views.py diff --git a/address/__init__.py b/address/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/address/admin.py b/address/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/address/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/address/apps.py b/address/apps.py new file mode 100644 index 0000000..572d7e0 --- /dev/null +++ b/address/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AddressConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'address' diff --git a/address/migrations/__init__.py b/address/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/address/models.py b/address/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/address/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/address/tests.py b/address/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/address/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/address/views.py b/address/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/address/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From 10030776d46d7f69a48cf63a94b830c45f1dbd67 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 18:21:11 +0430 Subject: [PATCH 045/439] Update(settings): add address app in intsall apps --- snapp_food/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index d12b9ef..711abde 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -31,6 +31,8 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + + 'address.apps.AddressConfig' ] MIDDLEWARE = [ From 0b96e4816b4a68882fac439a615177f30b0aa8e3 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 18:40:39 +0430 Subject: [PATCH 046/439] Add(address/models): create address models --- address/models.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/address/models.py b/address/models.py index 71a8362..0d9a4a4 100644 --- a/address/models.py +++ b/address/models.py @@ -1,3 +1,60 @@ from django.db import models +from library.models import BaseModel +from django.utils.translation import ugettext_lazy as _ -# Create your models here. + +class State(BaseModel): + name = models.CharField(max_length=20, verbose_name=_('name')) + slug = models.SlugField(max_length=25, verbose_name=_('slug'), allow_unicode=True) + + def __str__(self): + return self.name + + class Meta: + verbose_name = _('State') + verbose_name_plural = _('States') + db_table = 'state' + + +class City(BaseModel): + name = models.CharField(max_length=20, verbose_name=_('name')) + slug = models.SlugField(max_length=25, verbose_name=_('slug'), allow_unicode=True) + state = models.ForeignKey(State, verbose_name=_('state'), related_name='cities', on_delete=models.CASCADE) + + def __str__(self): + return f'{self.state} - {self.name}' + + class Meta: + verbose_name = _('City') + verbose_name_plural = _('Cities') + db_table = 'city' + + +class Area(BaseModel): + name = models.CharField(max_length=20, verbose_name=_('name')) + slug = models.SlugField(max_length=25, verbose_name=_('slug'), allow_unicode=True) + city = models.ForeignKey(City, verbose_name=_('city'), related_name='areas', on_delete=models.CASCADE) + + def __str__(self): + return f'{self.city} - {self.name})' + + class Meta: + verbose_name = _('Area') + verbose_name_plural = _('Areas') + db_table = 'area' + + +class Address(BaseModel): + state = models.ForeignKey(State, verbose_name=_('state'), related_name='addresses', on_delete=models.CASCADE) + city = models.ForeignKey(City, verbose_name=_('city'), related_name='addresses', on_delete=models.CASCADE) + area = models.ForeignKey(Area, verbose_name=_('area'), related_name='addresses', on_delete=models.CASCADE) + floor = models.SmallIntegerField(verbose_name=_('floor')) + plaque = models.SmallIntegerField(verbose_name=_('plaque')) + + def __str__(self): + return f'{self.area} - {self.floor} - {self.plaque}' + + class Meta: + verbose_name = _('Address') + verbose_name_plural = _('Addresses') + db_table = 'address' From 905ea02be8d7664bd7d2225157951b434c28f1a6 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 18:51:02 +0430 Subject: [PATCH 047/439] Refactor(settings): use pep8 in this file --- snapp_food/settings.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 711abde..8ccb7b4 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -12,16 +12,14 @@ from pathlib import Path from snapp_food.local_settings import * + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ - - # Application definition INSTALLED_APPS = [ @@ -65,7 +63,6 @@ WSGI_APPLICATION = 'snapp_food.wsgi.application' - # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases @@ -80,7 +77,6 @@ } } - # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators @@ -99,7 +95,6 @@ }, ] - # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ @@ -113,7 +108,6 @@ USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ From 8f03e6590f2fc1e8aab06620601f65db78130a50 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 18:52:54 +0430 Subject: [PATCH 048/439] Add(address/admin): create address admin models --- address/admin.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/address/admin.py b/address/admin.py index 8c38f3f..c3d4c03 100644 --- a/address/admin.py +++ b/address/admin.py @@ -1,3 +1,29 @@ from django.contrib import admin +from .models import State, City, Area, Address -# Register your models here. + +@admin.register(State) +class StateAdmin(admin.ModelAdmin): + list_display = ('name', 'slug') + search_fields = ('name',) + + +@admin.register(City) +class CityAdmin(admin.ModelAdmin): + list_display = ('name', 'slug', 'state') + list_filter = ('state',) + search_fields = ('name',) + + +@admin.register(Area) +class AreaAdmin(admin.ModelAdmin): + list_display = ('name', 'slug', 'city') + list_filter = ('city',) + search_fields = ('name',) + + +@admin.register(Address) +class Address(admin.ModelAdmin): + list_display = ('state', 'city', 'area', 'floor', 'plaque') + list_filter = ('state', 'city') + search_fields = ('area', 'floor', 'plaque') From a9bbf1ce59a4c9c53f26dcada503714cd00bde31 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 18:55:18 +0430 Subject: [PATCH 049/439] Add(service): add service app into project --- service/__init__.py | 0 service/admin.py | 3 +++ service/apps.py | 6 ++++++ service/migrations/__init__.py | 0 service/models.py | 3 +++ service/tests.py | 3 +++ service/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 service/__init__.py create mode 100644 service/admin.py create mode 100644 service/apps.py create mode 100644 service/migrations/__init__.py create mode 100644 service/models.py create mode 100644 service/tests.py create mode 100644 service/views.py diff --git a/service/__init__.py b/service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/service/admin.py b/service/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/service/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/service/apps.py b/service/apps.py new file mode 100644 index 0000000..8d0ae67 --- /dev/null +++ b/service/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ServiceConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'service' diff --git a/service/migrations/__init__.py b/service/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/service/models.py b/service/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/service/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/service/tests.py b/service/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/service/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/service/views.py b/service/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/service/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From 247fbe3eeb8ecae24fdc4f08e3a5edd5e53981ef Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 19:05:06 +0430 Subject: [PATCH 050/439] Add(settings): add service app in install apps --- snapp_food/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 8ccb7b4..d50b318 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -30,6 +30,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', + 'service.apps.ServiceConfig' 'address.apps.AddressConfig' ] From 0e38749e6c4c66332912b0b96d36dab6f014a111 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 19:55:46 +0430 Subject: [PATCH 051/439] Add(service/models): create service models --- service/models.py | 110 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/service/models.py b/service/models.py index 71a8362..2ed9579 100644 --- a/service/models.py +++ b/service/models.py @@ -1,3 +1,111 @@ from django.db import models +from library.models import BaseModel +from django.utils.translation import ugettext_lazy as _ +from address.models import Address, Area +import uuid -# Create your models here. + +class Service(BaseModel): + RESTAURANT = 0 + CAFE = 1 + CONFECTIONERY = 2 + SUPERMARKET = 3 + + SERVICE_TYPES = ( + (RESTAURANT, _('restaurant')), + (CAFE, _('cafe')), + (CONFECTIONERY, _('confectionery')), + (SUPERMARKET, _('supermarket')), + ) + + uuid = models.UUIDField(default=uuid.uuid4, verbose_name=_('uuid')) + # TODO-1: add foreign key to service provide here + name = models.CharField(max_length=40, verbose_name=_('name')) + service_type = models.PositiveSmallIntegerField(verbose_name=_('service type'), choices=SERVICE_TYPES) + minimum_purchase = models.DecimalField(max_digits=9, decimal_places=0, verbose_name=_('minimum purchase')) + address = models.ForeignKey(Address, verbose_name=_('address'), related_name='services', on_delete=models.SET_NULL) + + def __str__(self): + return f'{self.name} - {self.get_service_type_display()}' + + class Meta: + verbose_name = _('Service') + verbose_name_plural = _('Services') + db_table = 'service' + + +class ServiceCategory(BaseModel): + name = models.CharField(max_length=30, verbose_name=_('name')) + slug = models.SlugField(max_length=35, verbose_name=_('slug'), allow_unicode=True) + service = models.ForeignKey(Service, verbose_name=_('service'), related_name='categories', on_delete=models.CASCADE) + + def __str__(self): + return f'{self.name} - {self.service.name}' + + class Meta: + verbose_name = _('ServiceCategory') + verbose_name_plural = _('ServiceCategories') + db_table = 'service_category' + + +class DeliveryArea(BaseModel): + service = models.ForeignKey( + Service, verbose_name=_('service'), related_name='delivery_areas', on_delete=models.CASCADE + ) + area = models.ForeignKey(Area, verbose_name=_('area'), related_name='delivery_areas', on_delete=models.CASCADE) + + def __str__(self): + return f'{self.service.name} - {self.area}' + + class Meta: + verbose_name = _('DeliveryArea') + verbose_name_plural = _('DeliveryAreas') + db_table = 'delivery_area' + + +class AvailableTime(BaseModel): + SAT_DAY = 0 + SUN_DAY = 1 + MON_DAY = 2 + TUE_DAY = 3 + WED_DAY = 4 + THU_DAY = 5 + FRI_DAY = 6 + + DAYS = ( + (SAT_DAY, _('saturday')), + (SUN_DAY, _('sunday')), + (MON_DAY, _('monday')), + (TUE_DAY, _('tuesday')), + (WED_DAY, _('wednesday')), + (THU_DAY, _('thursday')), + (FRI_DAY, _('friday')) + ) + day = models.PositiveSmallIntegerField(verbose_name=_('day'), choices=DAYS) + open_time = models.DateTimeField(verbose_name=_('open time')) + close_time = models.DateTimeField(verbose_name=_('close time')) + close_day = models.BooleanField(verbose_name=_('close day'), blank=True, null=True) + + def __str__(self): + return f'{self.get_day_display()} - ' \ + f'{self.close_day if self.close_time else self.open_time and "-" and self.close_time}' + + class Meta: + verbose_name = _('AvailableTime') + verbose_name_plural = _('AvailableTimes') + db_table = 'available_time' + + +class ServiceAvailableTime(BaseModel): + service = models.ForeignKey( + Service, verbose_name=_('service'), related_name='available_times', on_delete=models.CASCADE + ) + available_time = models.ForeignKey(AvailableTime, verbose_name=_('available time'), on_delete=models.PROTECT) + + def __str__(self): + return f'{self.service.name} - {self.available_time.open_time} - {self.available_time.close_time}' + + class Meta: + verbose_name = _('ServiceAvailableTime') + verbose_name_plural = _('ServiceAvailableTimes') + db_table = 'service_available_time' From 340c358bf91ee2d0880c5d0d3084d37b513446f3 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 20:04:06 +0430 Subject: [PATCH 052/439] Add(service/admin): create service admin models --- service/admin.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/service/admin.py b/service/admin.py index 8c38f3f..f1ba98c 100644 --- a/service/admin.py +++ b/service/admin.py @@ -1,3 +1,34 @@ from django.contrib import admin +from .models import Service, ServiceCategory, DeliveryArea, ServiceAvailableTime, AvailableTime -# Register your models here. + +@admin.register(Service) +class ServiceAdmin(admin.ModelAdmin): + list_display = ('uuid', 'name', 'service_type', 'minimum_purchase', 'address') + list_filter = ('service_type',) + search_fields = ('name',) + + +@admin.register(ServiceCategory) +class ServiceCategoryAdmin(admin.ModelAdmin): + list_display = ('name', 'slug', 'service') + search_fields = ('name', 'service') + + +@admin.register(DeliveryArea) +class DeliveryAreaAdmin(admin.ModelAdmin): + list_display = ('service', 'area') + search_fields = ('service', 'area') + + +@admin.register(ServiceAvailableTime) +class ServiceAvailableTimeAdmin(admin.ModelAdmin): + list_display = ('service', 'available_time') + list_filter = ('available_time',) + search_fields = ('service',) + + +@admin.register(AvailableTime) +class AvailableTimeAdmin(admin.ModelAdmin): + list_display = ('day', 'open_time', 'close_time', 'close_day') + list_filter = ('day', 'close_time') From cb7bbd8ad636bd80f5783733113783bf24bf9429 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 20:05:39 +0430 Subject: [PATCH 053/439] Update(address/models): update the str method of models --- address/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/address/models.py b/address/models.py index 0d9a4a4..062cf9a 100644 --- a/address/models.py +++ b/address/models.py @@ -36,7 +36,7 @@ class Area(BaseModel): city = models.ForeignKey(City, verbose_name=_('city'), related_name='areas', on_delete=models.CASCADE) def __str__(self): - return f'{self.city} - {self.name})' + return f'{self.city.name} - {self.name})' class Meta: verbose_name = _('Area') From be35ff1c732062ed3ef7a985dbaa68f4b509bcf2 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 20:12:17 +0430 Subject: [PATCH 054/439] Add(order) add order app into project --- order/__init__.py | 0 order/admin.py | 3 +++ order/apps.py | 6 ++++++ order/migrations/__init__.py | 0 order/models.py | 3 +++ order/tests.py | 3 +++ order/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 order/__init__.py create mode 100644 order/admin.py create mode 100644 order/apps.py create mode 100644 order/migrations/__init__.py create mode 100644 order/models.py create mode 100644 order/tests.py create mode 100644 order/views.py diff --git a/order/__init__.py b/order/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/order/admin.py b/order/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/order/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/order/apps.py b/order/apps.py new file mode 100644 index 0000000..42888e4 --- /dev/null +++ b/order/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class OrderConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'order' diff --git a/order/migrations/__init__.py b/order/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/order/models.py b/order/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/order/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/order/tests.py b/order/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/order/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/order/views.py b/order/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/order/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From 7fe3d01df31ef8a31ac4c0409a161b39e5ed064c Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 20:29:56 +0430 Subject: [PATCH 055/439] Add(settings): add order app into install apps --- snapp_food/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index d50b318..775db29 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -30,7 +30,8 @@ 'django.contrib.messages', 'django.contrib.staticfiles', - 'service.apps.ServiceConfig' + 'service.apps.ServiceConfig', + 'order.apps.OrderConfig', 'address.apps.AddressConfig' ] From be5147357e841ca85aa9d183d21661882c731105 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 20:31:22 +0430 Subject: [PATCH 056/439] Add(order/model): create order models --- order/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/order/models.py b/order/models.py index 71a8362..4c71af1 100644 --- a/order/models.py +++ b/order/models.py @@ -1,3 +1,9 @@ from django.db import models +from library.models import BaseModel +from django.utils.translation import ugettext_lazy as _ -# Create your models here. + +class Order(BaseModel): + # TODO-1: add foreign key to invoice here + # TODO-2: add status here + is_delivered = models.BooleanField(verbose_name=_('is delivered'), default=False) From 001afe029a2d8a0524d2bb42fecce16725556de0 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Fri, 27 Aug 2021 20:34:49 +0430 Subject: [PATCH 057/439] Add(order/admin): create order admin models --- order/admin.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/order/admin.py b/order/admin.py index 8c38f3f..2129664 100644 --- a/order/admin.py +++ b/order/admin.py @@ -1,3 +1,9 @@ from django.contrib import admin -# Register your models here. +from .models import Order + + +@admin.register(Order) +class OrderAdmin(admin.ModelAdmin): + # TODO-1: after done todos the model order, add the fields here + pass From ca46fd37f37e8b782f27e467a21ac2cb8a196361 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 22:01:14 +0430 Subject: [PATCH 058/439] Fix(models): capitalize all of the model verbous names --- accounts/models.py | 12 ++++++------ cart/models.py | 8 ++++---- item/models.py | 8 ++++---- payment/models.py | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/accounts/models.py b/accounts/models.py index c283c4c..db32241 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -11,8 +11,8 @@ class User(AbstractUser): # TODO : AUTH_USER_MODEL must be changed to this model in settings class Meta: - verbose_name = _('user') - verbose_name_plural = _('users') + verbose_name = _('User') + verbose_name_plural = _('Users') db_table = 'user' @@ -76,8 +76,8 @@ def __str__(self): return f"{self.full_name} - {self.phone_number}" class Meta: - verbose_name = _('customer') - verbose_name_plural = _('customers') + verbose_name = _('Customer') + verbose_name_plural = _('Customers') db_table = 'customer' @@ -86,6 +86,6 @@ class ServiceProvider(AbstractUser): phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) class Meta: - verbose_name = _('service provider') - verbose_name_plural = _('service providers') + verbose_name = _('Service provider') + verbose_name_plural = _('Service providers') db_table = 'service_provider' diff --git a/cart/models.py b/cart/models.py index 6c39dc0..1f173d4 100644 --- a/cart/models.py +++ b/cart/models.py @@ -17,8 +17,8 @@ def __str__(self): return f"{self.customer} - {'Paid' if self.is_paid else 'Not paid'}" class Meta: - verbose_name = _('cart') - verbose_name_plural = _('carts') + verbose_name = _('Cart') + verbose_name_plural = _('Carts') db_table = 'cart' @@ -31,6 +31,6 @@ def __str__(self): return f"{self.item} - {self.quantity}" class Meta: - verbose_name = _('cart line') - verbose_name_plural = _('cart lines') + verbose_name = _('Cart line') + verbose_name_plural = _('Cart lines') db_table = 'cart_line' diff --git a/item/models.py b/item/models.py index ae52d1e..e18ecf9 100644 --- a/item/models.py +++ b/item/models.py @@ -23,8 +23,8 @@ class Item(BaseModel): # TODO-2 : ServiceCategory must be created for the relation class Meta: - verbose_name = _('item') - verbose_name_plural = _('items') + verbose_name = _('Item') + verbose_name_plural = _('Items') db_table = 'item' def __str__(self): @@ -40,6 +40,6 @@ class ItemLine(BaseModel): quantity = models.PositiveIntegerField(default=0) class Meta: - verbose_name = _('item line') - verbose_name_plural = _('item lines') + verbose_name = _('Item line') + verbose_name_plural = _('Item lines') db_table = 'item_line' diff --git a/payment/models.py b/payment/models.py index a2558d8..bef26c4 100644 --- a/payment/models.py +++ b/payment/models.py @@ -13,8 +13,8 @@ class Invoice(BaseModel): # TODO: Address must be created for relation class Meta: - verbose_name = _('invoice') - verbose_name_plural = _('invoices') + verbose_name = _('Invoice') + verbose_name_plural = _('Invoices') db_table = 'invoice' def __str__(self): @@ -28,8 +28,8 @@ class Payment(BaseModel): is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) class Meta: - verbose_name = _('payment') - verbose_name_plural = _('payments') + verbose_name = _('Payment') + verbose_name_plural = _('Payments') db_table = 'payment' def __str__(self): From f1a0b9b34f14510fb667af5c3a049cabd058b886 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 22:04:34 +0430 Subject: [PATCH 059/439] Update(item/models): add verbous_name for ItemLine fields --- item/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/item/models.py b/item/models.py index e18ecf9..7493880 100644 --- a/item/models.py +++ b/item/models.py @@ -36,8 +36,8 @@ def stock(self): class ItemLine(BaseModel): - item = models.OneToOneField(Item, related_name='line', on_delete=models.CASCADE) - quantity = models.PositiveIntegerField(default=0) + item = models.OneToOneField(Item, verbose_name=_('item'), related_name='line', on_delete=models.CASCADE) + quantity = models.PositiveIntegerField(default=0, verbose_name=_('quantity')) class Meta: verbose_name = _('Item line') From b4681be7b3e830abec9efb4556080e681a562859 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 22:14:06 +0430 Subject: [PATCH 060/439] Update(payment/admin): add created_time filter for invoice, payment admin --- payment/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/payment/admin.py b/payment/admin.py index 7e18605..1eb61dc 100644 --- a/payment/admin.py +++ b/payment/admin.py @@ -6,12 +6,12 @@ @admin.register(Invoice) class InvoiceAdmin(admin.ModelAdmin): list_display = ('customer', 'price', 'is_paid') - list_filter = ('is_paid',) + list_filter = ('is_paid', 'crated_time') search_fields = ('customer__phone_number',) @admin.register(Payment) class PaymentAdmin(admin.ModelAdmin): list_display = ('uuid', 'price', 'is_paid') - list_filter = ('is_paid',) + list_filter = ('is_paid', 'created_time') search_fields = ('uuid',) From c38f0a65ec7060986e3a97a35bf941d90c44b452 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Fri, 27 Aug 2021 23:53:08 +0430 Subject: [PATCH 061/439] Add(settings): add new apps to installed apps --- snapp_food/settings.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index d12b9ef..c66e9f0 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -12,16 +12,14 @@ from pathlib import Path from snapp_food.local_settings import * + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ - - # Application definition INSTALLED_APPS = [ @@ -31,6 +29,10 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'accounts.apps.AccountsConfig', + 'item.apps.ItemConfig', + 'cart.apps.CartConfig', + 'payment.apps.PaymentConfig', ] MIDDLEWARE = [ @@ -63,7 +65,6 @@ WSGI_APPLICATION = 'snapp_food.wsgi.application' - # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases @@ -78,7 +79,6 @@ } } - # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators @@ -97,7 +97,6 @@ }, ] - # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ @@ -111,7 +110,6 @@ USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ From 7215fcb0fd5abf214689a07ca8b6dfe5c9795ba9 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 13:27:03 +0430 Subject: [PATCH 062/439] Fix(item/models): fix available method of ItemManager --- item/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/item/models.py b/item/models.py index 7493880..1ed4e74 100644 --- a/item/models.py +++ b/item/models.py @@ -6,7 +6,7 @@ class ItemManager(models.Manager): def available(self): - return self.get_queryset().first(available=True) + return self.get_queryset().filter(available=True) class Item(BaseModel): From f0cc8953a23edc72ba4544be59922384e2733329 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 13:52:43 +0430 Subject: [PATCH 063/439] Update(settings): change AUTH_USER_MODEL to accounts.User --- accounts/models.py | 1 - snapp_food/settings.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/models.py b/accounts/models.py index db32241..971779c 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -8,7 +8,6 @@ class User(AbstractUser): # this model is used for admins and superusers - # TODO : AUTH_USER_MODEL must be changed to this model in settings class Meta: verbose_name = _('User') diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 6871886..98cdfb2 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -29,7 +29,7 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - + 'service.apps.ServiceConfig', 'order.apps.OrderConfig', 'address.apps.AddressConfig' @@ -124,3 +124,4 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +AUTH_USER_MODEL = 'accounts.User' From d56441d07c5dc1327f90f7a59e117d4fcbf2e006 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 14:21:48 +0430 Subject: [PATCH 064/439] Update(item/models): add service and category relation for Item model --- item/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/item/models.py b/item/models.py index 1ed4e74..3e3da34 100644 --- a/item/models.py +++ b/item/models.py @@ -2,6 +2,7 @@ from django.utils.translation import gettext as _ from library.models import BaseModel +from service.models import Service, ServiceCategory class ItemManager(models.Manager): @@ -16,12 +17,11 @@ class Item(BaseModel): description = models.TextField(verbose_name=_('description'), blank=True) price = models.IntegerField(verbose_name=_('price')) image = models.ImageField(verbose_name=_('image'), blank=True, null=True, upload_to='items/') - + service = models.ForeignKey(Service, verbose_name=_('service'), related_name='items', on_delete=models.CASCADE) + category = models.ForeignKey(ServiceCategory, verbose_name=_('category'), related_name='items', + on_delete=models.CASCADE) objects = ItemManager() - # TODO-1: Service model must be created for the relation - # TODO-2 : ServiceCategory must be created for the relation - class Meta: verbose_name = _('Item') verbose_name_plural = _('Items') From 7beb40d9260a686e02e592dde3ffccd7bc260f8b Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 14:25:40 +0430 Subject: [PATCH 065/439] Update(invoice/models): add address relation for Invoice model --- payment/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/payment/models.py b/payment/models.py index bef26c4..6e1816f 100644 --- a/payment/models.py +++ b/payment/models.py @@ -1,6 +1,7 @@ from django.db import models from django.utils.translation import gettext as _ from accounts.models import Customer +from address.models import Address from library.models import BaseModel @@ -9,8 +10,8 @@ class Invoice(BaseModel): on_delete=models.SET_NULL, null=True, blank=True) price = models.IntegerField(verbose_name=_('price')) is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) - - # TODO: Address must be created for relation + address = models.ForeignKey(Address, verbose_name=_('address'), related_name='invoices', on_delete=models.SET_NULL, + null=True, blank=True) class Meta: verbose_name = _('Invoice') From 69c2973e08480085e6371f1186490b3bdb08e813 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 14:27:14 +0430 Subject: [PATCH 066/439] Fix(address/admin): change the name of address model admin --- address/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/address/admin.py b/address/admin.py index c3d4c03..fe22121 100644 --- a/address/admin.py +++ b/address/admin.py @@ -23,7 +23,7 @@ class AreaAdmin(admin.ModelAdmin): @admin.register(Address) -class Address(admin.ModelAdmin): +class AddressAdmin(admin.ModelAdmin): list_display = ('state', 'city', 'area', 'floor', 'plaque') list_filter = ('state', 'city') search_fields = ('area', 'floor', 'plaque') From 91fd43e2e31d5f5d3fdc2f41aef765a82bc94aae Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 14:29:30 +0430 Subject: [PATCH 067/439] Update(item/admin): add service, category to list_display --- item/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/item/admin.py b/item/admin.py index 2325eb4..1568bd9 100644 --- a/item/admin.py +++ b/item/admin.py @@ -5,7 +5,7 @@ @admin.register(Item) class ItemAdmin(admin.ModelAdmin): - list_display = ('name', 'upc', 'price', 'stock', 'available') + list_display = ('name', 'upc', 'service', 'category', 'price', 'stock', 'available') list_editable = ('available',) list_filter = ('available', 'created_time') search_fields = ('upc', 'name') From 9000548bc0faf33d74d0d09003b4961e5192feb9 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 14:31:16 +0430 Subject: [PATCH 068/439] Update(payment/admin): add address to list_display of InvoiceAdmin --- payment/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/payment/admin.py b/payment/admin.py index 1eb61dc..888cfd2 100644 --- a/payment/admin.py +++ b/payment/admin.py @@ -5,7 +5,7 @@ @admin.register(Invoice) class InvoiceAdmin(admin.ModelAdmin): - list_display = ('customer', 'price', 'is_paid') + list_display = ('customer', 'price', 'is_paid', 'address') list_filter = ('is_paid', 'crated_time') search_fields = ('customer__phone_number',) From c1ee2b6a047f18e835ddf175c85217c9372cfa49 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sat, 28 Aug 2021 16:26:02 +0430 Subject: [PATCH 069/439] Typo(accounts/models): fix a typo in error message --- accounts/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/models.py b/accounts/models.py index 971779c..1ce5eb1 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -19,7 +19,7 @@ class CustomerManager(UserManager): def _create_user(self, phone_number, password, **extra_fields): if not phone_number: - raise ValueError('The given phone must be set') + raise ValueError('The given phone_number must be set') user = self.model(phone_number=phone_number, **extra_fields) user.password = make_password(password) From a3c854f7b0e3a51801465a943329edd1cb443bda Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sat, 28 Aug 2021 17:48:25 +0430 Subject: [PATCH 070/439] Update(service/models): add service provide field to model --- service/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/service/models.py b/service/models.py index 2ed9579..ad3d428 100644 --- a/service/models.py +++ b/service/models.py @@ -1,4 +1,6 @@ from django.db import models + +from accounts.models import ServiceProvider from library.models import BaseModel from django.utils.translation import ugettext_lazy as _ from address.models import Address, Area @@ -19,7 +21,9 @@ class Service(BaseModel): ) uuid = models.UUIDField(default=uuid.uuid4, verbose_name=_('uuid')) - # TODO-1: add foreign key to service provide here + service_provider = models.ForeignKey( + ServiceProvider, verbose_name=_('service provider'), related_name='services', on_delete=models.CASCADE + ) name = models.CharField(max_length=40, verbose_name=_('name')) service_type = models.PositiveSmallIntegerField(verbose_name=_('service type'), choices=SERVICE_TYPES) minimum_purchase = models.DecimalField(max_digits=9, decimal_places=0, verbose_name=_('minimum purchase')) From 991ee51b1801fc4ba2a79c8555c4cf007e2a5970 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sat, 28 Aug 2021 17:49:53 +0430 Subject: [PATCH 071/439] Update(order/models): add invoice, status field in model --- order/models.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/order/models.py b/order/models.py index 4c71af1..14f7caf 100644 --- a/order/models.py +++ b/order/models.py @@ -2,8 +2,17 @@ from library.models import BaseModel from django.utils.translation import ugettext_lazy as _ +from payment.models import Invoice + class Order(BaseModel): - # TODO-1: add foreign key to invoice here - # TODO-2: add status here + PREPARING_FOOD = 0 + SENDING = 1 + + STATUS = ( + (PREPARING_FOOD, _('preparing food')), + (PREPARING_FOOD, _('sending')), + ) + invoice = models.ForeignKey(Invoice, verbose_name=_('invoice'), related_name='orders', on_delete=models.PROTECT) + status = models.PositiveSmallIntegerField(verbose_name=_('status'), choices=STATUS) is_delivered = models.BooleanField(verbose_name=_('is delivered'), default=False) From a46f6c5bfc57c40f7a60bd617e7ab18a1758e147 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sat, 28 Aug 2021 17:51:11 +0430 Subject: [PATCH 072/439] Update(order/admin): update admin model and add filter and display field --- order/admin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/order/admin.py b/order/admin.py index 2129664..f4555a0 100644 --- a/order/admin.py +++ b/order/admin.py @@ -5,5 +5,6 @@ @admin.register(Order) class OrderAdmin(admin.ModelAdmin): - # TODO-1: after done todos the model order, add the fields here - pass + list_display = ('invoice', 'status', 'is_delivered') + list_filter = ('status', 'is_delivered') + search_fields = ('invoice',) From 5c491ae595d5d461548cf7686779951b83376a92 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:14:18 +0430 Subject: [PATCH 073/439] Delte(account/models): remove the User model and use django default User --- accounts/admin.py | 7 +------ accounts/models.py | 9 --------- snapp_food/settings.py | 3 +-- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/accounts/admin.py b/accounts/admin.py index 12ad204..6a8a820 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -2,12 +2,7 @@ from django.contrib.auth.admin import UserAdmin from django.utils.translation import gettext as _ -from accounts.models import User, Customer, ServiceProvider - - -@admin.register(User) -class CustomUserAdmin(UserAdmin): - pass +from accounts.models import Customer, ServiceProvider @admin.register(Customer) diff --git a/accounts/models.py b/accounts/models.py index 1ce5eb1..26b203e 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -6,15 +6,6 @@ from django.utils.translation import ugettext_lazy as _ -class User(AbstractUser): - # this model is used for admins and superusers - - class Meta: - verbose_name = _('User') - verbose_name_plural = _('Users') - db_table = 'user' - - class CustomerManager(UserManager): def _create_user(self, phone_number, password, **extra_fields): diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 98cdfb2..4ba5010 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -32,7 +32,7 @@ 'service.apps.ServiceConfig', 'order.apps.OrderConfig', - 'address.apps.AddressConfig' + 'address.apps.AddressConfig', 'accounts.apps.AccountsConfig', 'item.apps.ItemConfig', 'cart.apps.CartConfig', @@ -124,4 +124,3 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -AUTH_USER_MODEL = 'accounts.User' From 618dad01ad4bdbeacf07e398749cc8f46aa19494 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:20:26 +0430 Subject: [PATCH 074/439] Update(accounts/models): change the super model of ServiceProvider to AbstractBaseUser --- accounts/models.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/accounts/models.py b/accounts/models.py index 26b203e..6ec0c9f 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,6 +1,7 @@ from django.contrib.auth.base_user import AbstractBaseUser from django.contrib.auth.hashers import make_password from django.contrib.auth.models import PermissionsMixin, AbstractUser, UserManager +from django.contrib.auth.validators import UnicodeUsernameValidator from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ @@ -71,9 +72,40 @@ class Meta: db_table = 'customer' -class ServiceProvider(AbstractUser): +class ServiceProvider(AbstractBaseUser): + username_validator = UnicodeUsernameValidator() + username = models.CharField( + _('username'), + max_length=150, + unique=True, + help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'), + validators=[username_validator], + error_messages={ + 'unique': _("A user with that username already exists."), + }, + ) email = models.EmailField(_('email address'), blank=True, unique=True) phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) + is_staff = models.BooleanField( + _('staff status'), + default=False, + help_text=_('Designates whether the user can log into this admin site.'), + ) + is_active = models.BooleanField( + _('active'), + default=True, + help_text=_( + 'Designates whether this user should be treated as active. ' + 'Unselect this instead of deleting accounts.' + ), + ) + date_joined = models.DateTimeField(_('date joined'), default=timezone.now) + + objects = UserManager() + + EMAIL_FIELD = 'email' + USERNAME_FIELD = 'username' + REQUIRED_FIELDS = ['email'] class Meta: verbose_name = _('Service provider') From 57a4f88804b180416feed4113f8a5b457d4b144e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:23:30 +0430 Subject: [PATCH 075/439] Update(account/admin): change the ServiceProviderAdmin mdoel --- accounts/admin.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/accounts/admin.py b/accounts/admin.py index 6a8a820..46d08c9 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -1,6 +1,5 @@ from django.contrib import admin -from django.contrib.auth.admin import UserAdmin -from django.utils.translation import gettext as _ + from accounts.models import Customer, ServiceProvider @@ -13,9 +12,7 @@ class CustomerAdmin(admin.ModelAdmin): @admin.register(ServiceProvider) -class ServiceProviderAdmin(UserAdmin): - list_display = UserAdmin.list_display + ('phone_number',) - search_fields = UserAdmin.search_fields + ('phone_number',) - fieldsets = UserAdmin.fieldsets + ( - (_("Phone number"), {'fields': ('phone_number',)}), - ) +class ServiceProviderAdmin(admin.ModelAdmin): + list_display = ('username', 'email', 'phone_number', 'date_joined', 'is_active') + list_filter = ('is_active', 'date_joined') + search_fields = ('username', 'phone_number') From 3cc5462f44607b93d36730745229717e1ad50220 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:25:14 +0430 Subject: [PATCH 076/439] Add(requirements): create requirements.txt file --- requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1f3178d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +asgiref==3.4.1 +Django==3.2 +Pillow==8.3.1 +psycopg2-binary==2.9.1 +pytz==2021.1 +sqlparse==0.4.1 From 4cc3ddcd4892397973b81f2dc6dbbd25968a9dde Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:27:06 +0430 Subject: [PATCH 077/439] Update(accounts/models): remove PermissionMixin from Customer super models --- accounts/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/models.py b/accounts/models.py index 6ec0c9f..9a858fd 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -35,7 +35,7 @@ def create_superuser(self, phone_number, password=None, **extra_fields): return self._create_user(phone_number, password, **extra_fields) -class Customer(AbstractBaseUser, PermissionsMixin): +class Customer(AbstractBaseUser): phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) first_name = models.CharField(_('first name'), max_length=150, blank=True) last_name = models.CharField(_('last name'), max_length=150, blank=True) From f77032cebf5503d1c4d3ff6e4aa2920014501b05 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:28:10 +0430 Subject: [PATCH 078/439] Typo(payment/admin): fix a typo for created_time field --- payment/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/payment/admin.py b/payment/admin.py index 888cfd2..d39dade 100644 --- a/payment/admin.py +++ b/payment/admin.py @@ -6,7 +6,7 @@ @admin.register(Invoice) class InvoiceAdmin(admin.ModelAdmin): list_display = ('customer', 'price', 'is_paid', 'address') - list_filter = ('is_paid', 'crated_time') + list_filter = ('is_paid', 'created_time') search_fields = ('customer__phone_number',) From b09f7c082a15ae98f9774bc1f017544a6419bc3a Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:31:27 +0430 Subject: [PATCH 079/439] Update(service/models, cart/models): add null=true for relations --- cart/models.py | 2 +- service/models.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cart/models.py b/cart/models.py index 1f173d4..3cf5e1e 100644 --- a/cart/models.py +++ b/cart/models.py @@ -23,7 +23,7 @@ class Meta: class CartLine(BaseModel): - item = models.ForeignKey(Item, verbose_name=_('item'), related_name='lines', on_delete=models.SET_NULL) + item = models.ForeignKey(Item, verbose_name=_('item'), related_name='lines', on_delete=models.SET_NULL, null=True) cart = models.ForeignKey(Cart, verbose_name=_('cart'), related_name='lines', on_delete=models.CASCADE) quantity = models.PositiveIntegerField(default=1, verbose_name=_('quantity')) diff --git a/service/models.py b/service/models.py index ad3d428..217b349 100644 --- a/service/models.py +++ b/service/models.py @@ -27,7 +27,8 @@ class Service(BaseModel): name = models.CharField(max_length=40, verbose_name=_('name')) service_type = models.PositiveSmallIntegerField(verbose_name=_('service type'), choices=SERVICE_TYPES) minimum_purchase = models.DecimalField(max_digits=9, decimal_places=0, verbose_name=_('minimum purchase')) - address = models.ForeignKey(Address, verbose_name=_('address'), related_name='services', on_delete=models.SET_NULL) + address = models.ForeignKey(Address, verbose_name=_('address'), related_name='services', on_delete=models.SET_NULL, + null=True) def __str__(self): return f'{self.name} - {self.get_service_type_display()}' From a303cc0b9f2c5937cccbd980760a42d4d69d0fdd Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:33:17 +0430 Subject: [PATCH 080/439] Update(payment/models): remove blank=true from customer field --- payment/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/payment/models.py b/payment/models.py index 6e1816f..ec01e71 100644 --- a/payment/models.py +++ b/payment/models.py @@ -7,7 +7,7 @@ class Invoice(BaseModel): customer = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='invoices', - on_delete=models.SET_NULL, null=True, blank=True) + on_delete=models.SET_NULL, null=True) price = models.IntegerField(verbose_name=_('price')) is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) address = models.ForeignKey(Address, verbose_name=_('address'), related_name='invoices', on_delete=models.SET_NULL, From d7367c658b44f1ef5450835700048af7c182bbab Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 00:36:15 +0430 Subject: [PATCH 081/439] Feat(cart/models): add price field for CartLine model and override save method --- cart/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cart/models.py b/cart/models.py index 3cf5e1e..bb7cf82 100644 --- a/cart/models.py +++ b/cart/models.py @@ -26,6 +26,11 @@ class CartLine(BaseModel): item = models.ForeignKey(Item, verbose_name=_('item'), related_name='lines', on_delete=models.SET_NULL, null=True) cart = models.ForeignKey(Cart, verbose_name=_('cart'), related_name='lines', on_delete=models.CASCADE) quantity = models.PositiveIntegerField(default=1, verbose_name=_('quantity')) + price = models.IntegerField(verbose_name=_('price'), default=0) + + def save(self, **kwargs): + self.price = self.item.price * self.quantity + return super().save(**kwargs) def __str__(self): return f"{self.item} - {self.quantity}" From d522198d9fcc60db45ad3df289e48e42415c3c1c Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 01:01:18 +0430 Subject: [PATCH 082/439] Update(service, payment): modify uuid field in service, payment models --- payment/models.py | 3 ++- service/models.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/payment/models.py b/payment/models.py index ec01e71..e1ba1e1 100644 --- a/payment/models.py +++ b/payment/models.py @@ -3,6 +3,7 @@ from accounts.models import Customer from address.models import Address from library.models import BaseModel +import uuid class Invoice(BaseModel): @@ -23,7 +24,7 @@ def __str__(self): class Payment(BaseModel): - uuid = models.UUIDField(unique=True, verbose_name=_('uuid')) + uuid = models.UUIDField(unique=True, verbose_name=_('uuid'), db_index=True, default=uuid.uuid4) invoice = models.OneToOneField(Invoice, verbose_name=_('invoice'), related_name='payment', on_delete=models.CASCADE) price = models.IntegerField(verbose_name=_('price')) is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) diff --git a/service/models.py b/service/models.py index 217b349..d8b57ed 100644 --- a/service/models.py +++ b/service/models.py @@ -20,7 +20,7 @@ class Service(BaseModel): (SUPERMARKET, _('supermarket')), ) - uuid = models.UUIDField(default=uuid.uuid4, verbose_name=_('uuid')) + uuid = models.UUIDField(default=uuid.uuid4, verbose_name=_('uuid'), unique=True, db_index=True) service_provider = models.ForeignKey( ServiceProvider, verbose_name=_('service provider'), related_name='services', on_delete=models.CASCADE ) From ad3da1ec7d73184f1fdecd2851cd87f05c68a249 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 01:44:45 +0430 Subject: [PATCH 083/439] Migrations(migrations): add migrations --- accounts/migrations/0001_initial.py | 62 +++++++++++++++++ address/migrations/0001_initial.py | 80 ++++++++++++++++++++++ cart/migrations/0001_initial.py | 51 ++++++++++++++ item/migrations/0001_initial.py | 52 +++++++++++++++ order/migrations/0001_initial.py | 30 +++++++++ payment/migrations/0001_initial.py | 52 +++++++++++++++ service/migrations/0001_initial.py | 100 ++++++++++++++++++++++++++++ 7 files changed, 427 insertions(+) create mode 100644 accounts/migrations/0001_initial.py create mode 100644 address/migrations/0001_initial.py create mode 100644 cart/migrations/0001_initial.py create mode 100644 item/migrations/0001_initial.py create mode 100644 order/migrations/0001_initial.py create mode 100644 payment/migrations/0001_initial.py create mode 100644 service/migrations/0001_initial.py diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..6a7d712 --- /dev/null +++ b/accounts/migrations/0001_initial.py @@ -0,0 +1,62 @@ +# Generated by Django 3.2 on 2021-08-28 20:31 + +import accounts.models +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Customer', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('phone_number', models.CharField(max_length=13, unique=True, verbose_name='phone number')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ], + options={ + 'verbose_name': 'Customer', + 'verbose_name_plural': 'Customers', + 'db_table': 'customer', + }, + managers=[ + ('objects', accounts.models.CustomerManager()), + ], + ), + migrations.CreateModel( + name='ServiceProvider', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('email', models.EmailField(blank=True, max_length=254, unique=True, verbose_name='email address')), + ('phone_number', models.CharField(max_length=13, unique=True, verbose_name='phone number')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ], + options={ + 'verbose_name': 'Service provider', + 'verbose_name_plural': 'Service providers', + 'db_table': 'service_provider', + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/address/migrations/0001_initial.py b/address/migrations/0001_initial.py new file mode 100644 index 0000000..57ac86c --- /dev/null +++ b/address/migrations/0001_initial.py @@ -0,0 +1,80 @@ +# Generated by Django 3.2 on 2021-08-28 20:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='State', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('name', models.CharField(max_length=20, verbose_name='name')), + ('slug', models.SlugField(allow_unicode=True, max_length=25, verbose_name='slug')), + ], + options={ + 'verbose_name': 'State', + 'verbose_name_plural': 'States', + 'db_table': 'state', + }, + ), + migrations.CreateModel( + name='City', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('name', models.CharField(max_length=20, verbose_name='name')), + ('slug', models.SlugField(allow_unicode=True, max_length=25, verbose_name='slug')), + ('state', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cities', to='address.state', verbose_name='state')), + ], + options={ + 'verbose_name': 'City', + 'verbose_name_plural': 'Cities', + 'db_table': 'city', + }, + ), + migrations.CreateModel( + name='Area', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('name', models.CharField(max_length=20, verbose_name='name')), + ('slug', models.SlugField(allow_unicode=True, max_length=25, verbose_name='slug')), + ('city', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='areas', to='address.city', verbose_name='city')), + ], + options={ + 'verbose_name': 'Area', + 'verbose_name_plural': 'Areas', + 'db_table': 'area', + }, + ), + migrations.CreateModel( + name='Address', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('floor', models.SmallIntegerField(verbose_name='floor')), + ('plaque', models.SmallIntegerField(verbose_name='plaque')), + ('area', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='addresses', to='address.area', verbose_name='area')), + ('city', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='addresses', to='address.city', verbose_name='city')), + ('state', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='addresses', to='address.state', verbose_name='state')), + ], + options={ + 'verbose_name': 'Address', + 'verbose_name_plural': 'Addresses', + 'db_table': 'address', + }, + ), + ] diff --git a/cart/migrations/0001_initial.py b/cart/migrations/0001_initial.py new file mode 100644 index 0000000..050fefe --- /dev/null +++ b/cart/migrations/0001_initial.py @@ -0,0 +1,51 @@ +# Generated by Django 3.2 on 2021-08-28 20:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('accounts', '0001_initial'), + ('payment', '0001_initial'), + ('item', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Cart', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('is_paid', models.BooleanField(default=False, verbose_name='is paid')), + ('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='carts', to='accounts.customer', verbose_name='customer')), + ('invoice', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='cart', to='payment.invoice', verbose_name='invoice')), + ], + options={ + 'verbose_name': 'Cart', + 'verbose_name_plural': 'Carts', + 'db_table': 'cart', + }, + ), + migrations.CreateModel( + name='CartLine', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('quantity', models.PositiveIntegerField(default=1, verbose_name='quantity')), + ('price', models.IntegerField(default=0, verbose_name='price')), + ('cart', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lines', to='cart.cart', verbose_name='cart')), + ('item', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='lines', to='item.item', verbose_name='item')), + ], + options={ + 'verbose_name': 'Cart line', + 'verbose_name_plural': 'Cart lines', + 'db_table': 'cart_line', + }, + ), + ] diff --git a/item/migrations/0001_initial.py b/item/migrations/0001_initial.py new file mode 100644 index 0000000..7c50bbb --- /dev/null +++ b/item/migrations/0001_initial.py @@ -0,0 +1,52 @@ +# Generated by Django 3.2 on 2021-08-28 20:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('service', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Item', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('upc', models.BigIntegerField(db_index=True, unique=True, verbose_name='upc')), + ('available', models.BooleanField(default=True, verbose_name='available')), + ('name', models.CharField(max_length=50, verbose_name='name')), + ('description', models.TextField(blank=True, verbose_name='description')), + ('price', models.IntegerField(verbose_name='price')), + ('image', models.ImageField(blank=True, null=True, upload_to='items/', verbose_name='image')), + ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='service.servicecategory', verbose_name='category')), + ('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='service.service', verbose_name='service')), + ], + options={ + 'verbose_name': 'Item', + 'verbose_name_plural': 'Items', + 'db_table': 'item', + }, + ), + migrations.CreateModel( + name='ItemLine', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('quantity', models.PositiveIntegerField(default=0, verbose_name='quantity')), + ('item', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='line', to='item.item', verbose_name='item')), + ], + options={ + 'verbose_name': 'Item line', + 'verbose_name_plural': 'Item lines', + 'db_table': 'item_line', + }, + ), + ] diff --git a/order/migrations/0001_initial.py b/order/migrations/0001_initial.py new file mode 100644 index 0000000..a389fbb --- /dev/null +++ b/order/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 3.2 on 2021-08-28 20:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('payment', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Order', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('status', models.PositiveSmallIntegerField(choices=[(0, 'preparing food'), (0, 'sending')], verbose_name='status')), + ('is_delivered', models.BooleanField(default=False, verbose_name='is delivered')), + ('invoice', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='orders', to='payment.invoice', verbose_name='invoice')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/payment/migrations/0001_initial.py b/payment/migrations/0001_initial.py new file mode 100644 index 0000000..a281ac2 --- /dev/null +++ b/payment/migrations/0001_initial.py @@ -0,0 +1,52 @@ +# Generated by Django 3.2 on 2021-08-28 20:31 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('accounts', '0001_initial'), + ('address', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Invoice', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('price', models.IntegerField(verbose_name='price')), + ('is_paid', models.BooleanField(default=False, verbose_name='is paid')), + ('address', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoices', to='address.address', verbose_name='address')), + ('customer', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoices', to='accounts.customer', verbose_name='customer')), + ], + options={ + 'verbose_name': 'Invoice', + 'verbose_name_plural': 'Invoices', + 'db_table': 'invoice', + }, + ), + migrations.CreateModel( + name='Payment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, unique=True, verbose_name='uuid')), + ('price', models.IntegerField(verbose_name='price')), + ('is_paid', models.BooleanField(default=False, verbose_name='is paid')), + ('invoice', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='payment', to='payment.invoice', verbose_name='invoice')), + ], + options={ + 'verbose_name': 'Payment', + 'verbose_name_plural': 'Payments', + 'db_table': 'payment', + }, + ), + ] diff --git a/service/migrations/0001_initial.py b/service/migrations/0001_initial.py new file mode 100644 index 0000000..307ff2b --- /dev/null +++ b/service/migrations/0001_initial.py @@ -0,0 +1,100 @@ +# Generated by Django 3.2 on 2021-08-28 20:31 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('accounts', '0001_initial'), + ('address', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='AvailableTime', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('day', models.PositiveSmallIntegerField(choices=[(0, 'saturday'), (1, 'sunday'), (2, 'monday'), (3, 'tuesday'), (4, 'wednesday'), (5, 'thursday'), (6, 'friday')], verbose_name='day')), + ('open_time', models.DateTimeField(verbose_name='open time')), + ('close_time', models.DateTimeField(verbose_name='close time')), + ('close_day', models.BooleanField(blank=True, null=True, verbose_name='close day')), + ], + options={ + 'verbose_name': 'AvailableTime', + 'verbose_name_plural': 'AvailableTimes', + 'db_table': 'available_time', + }, + ), + migrations.CreateModel( + name='Service', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, unique=True, verbose_name='uuid')), + ('name', models.CharField(max_length=40, verbose_name='name')), + ('service_type', models.PositiveSmallIntegerField(choices=[(0, 'restaurant'), (1, 'cafe'), (2, 'confectionery'), (3, 'supermarket')], verbose_name='service type')), + ('minimum_purchase', models.DecimalField(decimal_places=0, max_digits=9, verbose_name='minimum purchase')), + ('address', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='services', to='address.address', verbose_name='address')), + ('service_provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='services', to='accounts.serviceprovider', verbose_name='service provider')), + ], + options={ + 'verbose_name': 'Service', + 'verbose_name_plural': 'Services', + 'db_table': 'service', + }, + ), + migrations.CreateModel( + name='ServiceCategory', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('name', models.CharField(max_length=30, verbose_name='name')), + ('slug', models.SlugField(allow_unicode=True, max_length=35, verbose_name='slug')), + ('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='categories', to='service.service', verbose_name='service')), + ], + options={ + 'verbose_name': 'ServiceCategory', + 'verbose_name_plural': 'ServiceCategories', + 'db_table': 'service_category', + }, + ), + migrations.CreateModel( + name='ServiceAvailableTime', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('available_time', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='service.availabletime', verbose_name='available time')), + ('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='available_times', to='service.service', verbose_name='service')), + ], + options={ + 'verbose_name': 'ServiceAvailableTime', + 'verbose_name_plural': 'ServiceAvailableTimes', + 'db_table': 'service_available_time', + }, + ), + migrations.CreateModel( + name='DeliveryArea', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('area', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='delivery_areas', to='address.area', verbose_name='area')), + ('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='delivery_areas', to='service.service', verbose_name='service')), + ], + options={ + 'verbose_name': 'DeliveryArea', + 'verbose_name_plural': 'DeliveryAreas', + 'db_table': 'delivery_area', + }, + ), + ] From d6969133e21f2c585fba15472e1ba38312924ad4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 12:41:09 +0430 Subject: [PATCH 084/439] Add(accounts/authenticate): create authenticate.py --- accounts/authenticate.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 accounts/authenticate.py diff --git a/accounts/authenticate.py b/accounts/authenticate.py new file mode 100644 index 0000000..e69de29 From a53aebfaeddc33eed8b0c53ad46f415a003989c4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 12:58:47 +0430 Subject: [PATCH 085/439] Feat(accounts/authenticate): add PhoneNumberPasswordBackend for customer --- accounts/authenticate.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/accounts/authenticate.py b/accounts/authenticate.py index e69de29..9e00bf5 100644 --- a/accounts/authenticate.py +++ b/accounts/authenticate.py @@ -0,0 +1,15 @@ +from django.contrib.auth.backends import BaseBackend +from accounts.models import Customer + + +class PhoneNumberPasswordBackend(BaseBackend): + def authenticate(self, request, phone_number=None, password=None): + try: + customer = Customer.objects.get(phone_number=phone_number) + except Customer.DoesNotExist: + return None + else: + if password: # if the password is sent via the form + if customer.check_password(password): + return customer + return customer From 4b53fc5dd6a9a8b8c4bd47ddfbc4e7085dbbb407 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 13:00:54 +0430 Subject: [PATCH 086/439] Update(settings): add PhoneNumberPasswordBackend to settings --- snapp_food/settings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 4ba5010..1471eda 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -124,3 +124,7 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', + 'accounts.authenticate.PhoneNumberPasswordBackend' +] From d45bf2c7df122ea31dfcca1ba6733ec46b9fbd30 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 13:03:44 +0430 Subject: [PATCH 087/439] Update(accounts/authenticate): add get_user method to PhoneNumberPasswordBackend --- accounts/authenticate.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/accounts/authenticate.py b/accounts/authenticate.py index 9e00bf5..36a82bf 100644 --- a/accounts/authenticate.py +++ b/accounts/authenticate.py @@ -13,3 +13,11 @@ def authenticate(self, request, phone_number=None, password=None): if customer.check_password(password): return customer return customer + + def get_user(self, user_id): + try: + customer = Customer.objects.get(pk=user_id) + except Customer.DoesNotExist: + return None + else: + return customer From 6951137b1a468f5c5c2947f4fe78ab8f57a30302 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 13:46:35 +0430 Subject: [PATCH 088/439] Add(accounts/authenticate): create authenticate file --- accounts/authenticate.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 accounts/authenticate.py diff --git a/accounts/authenticate.py b/accounts/authenticate.py new file mode 100644 index 0000000..e69de29 From 08db3202f12e02795a5fb6a43593714f24e67f58 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 13:57:06 +0430 Subject: [PATCH 089/439] Add(accounts/authenticate): create authentication for service provide --- accounts/authenticate.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/accounts/authenticate.py b/accounts/authenticate.py index e69de29..f92d21a 100644 --- a/accounts/authenticate.py +++ b/accounts/authenticate.py @@ -0,0 +1,21 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.backends import BaseBackend +from django.db.models import Q + +User = get_user_model() + + +class ServiceProviderAuthentication(BaseBackend): + def authenticate(self, request, username_email=None, password=None): + try: + user = User.objects.get(Q(username=username_email) | Q(email=username_email), password=password) + return user + + except User.DoesNotExist: + return None + + def get_user(self, user_id): + try: + return User.objects.get(pk=user_id) + except User.DoesNotExist: + return None From f0188f0aaf3799fde97ce4f09315aeef9427812c Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 14:02:12 +0430 Subject: [PATCH 090/439] Update(settings): add authentication to auth_backends --- snapp_food/settings.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 4ba5010..64813a4 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -124,3 +124,8 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', + 'accounts.authenticate.ServiceProviderAuthentication', +) From 621e3fa523caaf63e64f5c81fdb595f4033599c9 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:03:33 +0430 Subject: [PATCH 091/439] Add(accounts/urls): create urls file for accounts --- accounts/urls.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 accounts/urls.py diff --git a/accounts/urls.py b/accounts/urls.py new file mode 100644 index 0000000..e69de29 From d6529be6393f361aa1a4f144c8383c4bb25c1619 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:04:02 +0430 Subject: [PATCH 092/439] Add(accounts/urls): create url for service provider registration --- accounts/urls.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/accounts/urls.py b/accounts/urls.py index e69de29..f12632e 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from .views import ServiceProviderRegistrationView + +app_name = 'accounts' +urlpatterns = [ + path( + 'seviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' + ), +] From 6abde71bb127e2886c40f4a73dcaf2db20aa59db Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:05:05 +0430 Subject: [PATCH 093/439] Add(snapp_food/urls): including urls account file --- snapp_food/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snapp_food/urls.py b/snapp_food/urls.py index 7f88547..53acf68 100644 --- a/snapp_food/urls.py +++ b/snapp_food/urls.py @@ -14,8 +14,9 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), + path('accounts/', include('accounts.urls', namespace='accounts')), ] From 38e7df5ccc60bfc0f0d9213c6837e6aee3e9ba6b Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:06:32 +0430 Subject: [PATCH 094/439] Add(accounts/forms): create forms file for accounts app --- accounts/forms.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 accounts/forms.py diff --git a/accounts/forms.py b/accounts/forms.py new file mode 100644 index 0000000..e69de29 From 09ddb287bb1b0018cf77de1a9a4d04ab6fc340df Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:08:27 +0430 Subject: [PATCH 095/439] Add(accounts/forms): create service provider registration form --- accounts/forms.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index e69de29..fe6d713 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -0,0 +1,33 @@ +from django import forms +from django.core.exceptions import ValidationError + +from accounts.models import ServiceProvider + + +class ServiceProviderRegistrationForm(forms.ModelForm): + username = forms.CharField( + max_length=30, + min_length=4, + widget=forms.TextInput( + attrs={ + 'placeholder': 'Username', + 'class': 'form-control'} + ) + ) + confirm_password = forms.CharField( + widget=forms.PasswordInput( + attrs={ + 'placeholder': 'Confirm Password', + 'class': 'form-control'} + ) + ) + + class Meta: + model = ServiceProvider + fields = ('username', 'email', 'phone_number', 'password', 'confirm_password') + widgets = { + 'email': forms.EmailInput(attrs={'placeholder': 'Email', 'class': 'form-control'}), + 'phone_number': forms.TextInput(attrs={'placeholder': 'Phone Number', 'class': 'form-control'}), + 'password': forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}), + } + From 87634dfce1295981ab212871379f1114ed6f5d35 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:10:44 +0430 Subject: [PATCH 096/439] Add(accounts/templates): create base template for registration form --- accounts/templates/accounts/registration.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 accounts/templates/accounts/registration.html diff --git a/accounts/templates/accounts/registration.html b/accounts/templates/accounts/registration.html new file mode 100644 index 0000000..a5a11af --- /dev/null +++ b/accounts/templates/accounts/registration.html @@ -0,0 +1,14 @@ + + + + + Service Provider Registration + + +
+ {% csrf_token %} + {{ form.as_p }} + +
+ + \ No newline at end of file From 3d596ced4d9d4d50b0808e17708c88605c7a2798 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:11:35 +0430 Subject: [PATCH 097/439] Update(settings): update templates directory in settings --- snapp_food/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snapp_food/settings.py b/snapp_food/settings.py index 64813a4..a87d35c 100644 --- a/snapp_food/settings.py +++ b/snapp_food/settings.py @@ -10,6 +10,7 @@ https://docs.djangoproject.com/en/3.2/ref/settings/ """ +import os from pathlib import Path from snapp_food.local_settings import * @@ -55,7 +56,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [os.path.join(BASE_DIR, 'templates/')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ From a0aa78041375cd63eaaf7324d322d2925ccb5c67 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:12:25 +0430 Subject: [PATCH 098/439] Add(accounts/view): create service provider registration view --- accounts/views.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 91ea44a..53fdec5 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,3 +1,16 @@ -from django.shortcuts import render +from django.contrib.auth.hashers import make_password +from django.urls import reverse_lazy +from django.views.generic import FormView +from .forms import ServiceProviderRegistrationForm -# Create your views here. + +class ServiceProviderRegistrationView(FormView): + form_class = ServiceProviderRegistrationForm + template_name = 'accounts/registration.html' + success_url = reverse_lazy('') + + def form_valid(self, form): + instance = form.save(commit=False) + instance.password = make_password(instance.password) + instance.save() + return self.form_valid(form) From bd9219942085412138cb3dbfd9b7a4a3d78d85e2 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:13:10 +0430 Subject: [PATCH 099/439] Update(accounts/forms): update and add clean fields for service provider registration form --- accounts/forms.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index fe6d713..ea1e59c 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -31,3 +31,28 @@ class Meta: 'password': forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}), } + def clean_username(self): + if ServiceProvider.objects.filter(username=self.cleaned_data['username']).exists(): + raise ValidationError('There is a username!') + return self.cleaned_data['username'] + + def clean_email(self): + if ServiceProvider.objects.filter(email=self.cleaned_data['email']).exists(): + raise ValidationError('There is a email!') + return self.cleaned_data['email'] + + def clean_phone_number(self): + phone = self.cleaned_data['phone_number'] + + if phone.startswith('98') and len(phone) == 12: + if ServiceProvider.objects.filter(email=self.cleaned_data['phone_number']).exists(): + raise ValidationError('There is a phone_number!') + else: + return self.cleaned_data['phone_number'] + else: + raise ValidationError('phone_number invalid!') + + def clean_confirm_password(self): + if self.cleaned_data['password'] != self.cleaned_data['confirm_password']: + raise ValidationError('passwords not equal!') + return self.cleaned_data['confirm_password'] From ed324a1fcf1b4e019be5bb94b27f55ba2be2a6d9 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:19:54 +0430 Subject: [PATCH 100/439] Add(accounts/templates): create login template file --- accounts/templates/accounts/login.html | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 accounts/templates/accounts/login.html diff --git a/accounts/templates/accounts/login.html b/accounts/templates/accounts/login.html new file mode 100644 index 0000000..4820b21 --- /dev/null +++ b/accounts/templates/accounts/login.html @@ -0,0 +1,10 @@ + + + + + Service Provider Login + + + + + \ No newline at end of file From dee4fa467bd171be3cd044776327721f7993f7f0 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:21:32 +0430 Subject: [PATCH 101/439] Refactor(accounts/templates): rename login template file --- .../accounts/{login.html => service_provider_login.html} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename accounts/templates/accounts/{login.html => service_provider_login.html} (100%) diff --git a/accounts/templates/accounts/login.html b/accounts/templates/accounts/service_provider_login.html similarity index 100% rename from accounts/templates/accounts/login.html rename to accounts/templates/accounts/service_provider_login.html From 8ce7aa65424c6e23c1149c511a773b64bc4d93f1 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 15:22:04 +0430 Subject: [PATCH 102/439] Refactor(accounts/templates): rename registration template file --- .../{registration.html => service_provider_registration.html} | 0 accounts/views.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename accounts/templates/accounts/{registration.html => service_provider_registration.html} (100%) diff --git a/accounts/templates/accounts/registration.html b/accounts/templates/accounts/service_provider_registration.html similarity index 100% rename from accounts/templates/accounts/registration.html rename to accounts/templates/accounts/service_provider_registration.html diff --git a/accounts/views.py b/accounts/views.py index 53fdec5..dfecdcf 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -6,7 +6,7 @@ class ServiceProviderRegistrationView(FormView): form_class = ServiceProviderRegistrationForm - template_name = 'accounts/registration.html' + template_name = 'accounts/service_provider_registration.html' success_url = reverse_lazy('') def form_valid(self, form): From d7e2645d001755c174dcb666d78dce5a22668523 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 15:28:21 +0430 Subject: [PATCH 103/439] Add: create accounts/forms.py --- accounts/forms.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 accounts/forms.py diff --git a/accounts/forms.py b/accounts/forms.py new file mode 100644 index 0000000..e69de29 From 2013be3874013e0e1dc71821beeb056d04c01811 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 15:38:59 +0430 Subject: [PATCH 104/439] Add(account/forms): create CustomerLoginRegisterForm class --- accounts/forms.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index e69de29..a40ccd0 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -0,0 +1,13 @@ +from django import forms +from django.core.validators import int_list_validator +from django.utils.translation import gettext_lazy as _ + + +class CustomerLoginRegisterForm(forms.Form): + phone_number = forms.CharField(max_length=10, + min_length=10, + validators=[int_list_validator(message=_('only digits are accepted'))], + error_messages={'min_length': _('phone number must have 10 digits')}, + widget=forms.TextInput( + attrs={'class': 'form-control', 'placeholder': 'phone number'}) + ) From 01277fbd5e7346c7fea9f6256efaa42cda2a1108 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 15:48:57 +0430 Subject: [PATCH 105/439] Add(account/forms): create CustomerCodeConfirmForm class --- accounts/forms.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index a40ccd0..c7da25d 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -11,3 +11,15 @@ class CustomerLoginRegisterForm(forms.Form): widget=forms.TextInput( attrs={'class': 'form-control', 'placeholder': 'phone number'}) ) + + +class CustomerCodeConfirmForm(forms.Form): + class ConfirmationPhoneNumberForm(forms.Form): + code = forms.CharField( + widget=forms.TextInput( + attrs={ + 'class': 'form-control', + 'placeholder': _('confirmation code') + } + ) + ) From 04a9f24e9bc5bc84946516f10599ee8ce7c679df Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 15:51:19 +0430 Subject: [PATCH 106/439] Add(account/forms): create CustomerPasswordForm class --- accounts/forms.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index c7da25d..cfec135 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -14,12 +14,22 @@ class CustomerLoginRegisterForm(forms.Form): class CustomerCodeConfirmForm(forms.Form): - class ConfirmationPhoneNumberForm(forms.Form): - code = forms.CharField( - widget=forms.TextInput( - attrs={ - 'class': 'form-control', - 'placeholder': _('confirmation code') - } - ) + code = forms.CharField( + widget=forms.TextInput( + attrs={ + 'class': 'form-control', + 'placeholder': _('confirmation code') + } ) + ) + + +class CustomerPasswordForm(forms.Form): + password = forms.CharField( + widget=forms.PasswordInput( + attrs={ + 'class': 'form-control', + 'placeholder': _('password') + } + ) + ) From 5652247ae54cf98523f2d95d0f9e184837e12cd4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 16:03:42 +0430 Subject: [PATCH 107/439] Add: create accounts/utils.py --- accounts/utils.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 accounts/utils.py diff --git a/accounts/utils.py b/accounts/utils.py new file mode 100644 index 0000000..e69de29 From 14990f5894350b257e334d035bfbb360d0c43b66 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 16:09:21 +0430 Subject: [PATCH 108/439] Add(accounts/utils): add two functions for phone number code --- accounts/utils.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/accounts/utils.py b/accounts/utils.py index e69de29..2c75cbb 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -0,0 +1,23 @@ +from datetime import datetime, timedelta +from random import randint + + +def check_expire_time(request): + try: + expire_time = datetime.strptime(request.session['created-time'], '%Y-%m-%d %H:%M:%S') + except KeyError: + expire_time = None + + if expire_time: + now = datetime.strptime(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S') + if (now - expire_time) > timedelta(minutes=2): + del request.session['code'] + del request.session['created-time'] + + +def set_phone_number_session(request, phone_number): + request.session['phone_number'] = phone_number + request.session['code'] = randint(1000, 9999) + request.session['created_time'] = str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + print(request.session['code']) + print(request.session['created_time']) From fcc79548ae7d979548b3270883520e197762138a Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 16:20:22 +0430 Subject: [PATCH 109/439] Add(accounts/views): add CustomerLoginRegisterView class view --- accounts/views.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 91ea44a..0aa5369 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,3 +1,18 @@ -from django.shortcuts import render +from django.views.generic import FormView +from accounts.forms import CustomerLoginRegisterForm +from accounts.models import Customer -# Create your views here. + +class CustomerLoginRegisterView(FormView): + form_class = CustomerLoginRegisterForm + template_name = None + + def form_valid(self, form): + try: + Customer.objects.get(phone_number=form.changed_data['phone_number']) + except Customer.DoesNotExist: + self.success_url = None + else: + self.success_url = None + + return super().form_valid(form) From 0887d63af7259056c5024ad3ac6864aa7cb2f926 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 16:45:45 +0430 Subject: [PATCH 110/439] Add(accounts/views): add CustomerPhoneNumberConfirmView class view --- accounts/views.py | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 0aa5369..2ce077c 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,6 +1,9 @@ +from django.contrib import messages from django.views.generic import FormView -from accounts.forms import CustomerLoginRegisterForm +from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm from accounts.models import Customer +from accounts.utils import check_expire_time +from django.contrib.auth import authenticate, login class CustomerLoginRegisterView(FormView): @@ -16,3 +19,40 @@ def form_valid(self, form): self.success_url = None return super().form_valid(form) + + +class CustomerPhoneNumberConfirmView(FormView): + form_class = CustomerCodeConfirmForm + template_name = None + success_url = None + + def dispatch(self, request, *args, **kwargs): + check_expire_time(request) + return super().dispatch(request, *args, **kwargs) + + def form_valid(self, form): + phone_number = '98' + self.request.session['phone_number'] + form_code = int(form.changed_data['code']) + session_code = self.request.get('code', None) + + if session_code: + if session_code == form_code: + Customer.objects.get_or_create(phone_number=phone_number) + self.delete_confirm_code() + customer = authenticate(phone_number=phone_number) + if customer: + login(self.request, customer) + messages.info(self.request, 'Login success', 'success') + return super().form_valid(form) + else: + return super().form_valid(form) + + else: + messages.info(self.request, 'The code is incorrect!', 'danger') + return + else: + messages.info(self.request, 'The code is invalid! Enter your phone number again', 'danger') + return + + def delete_confirm_code(self): + del self.request.session['code'] From 26203091a8a3e8bcf038cd5619093238444dc8da Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:47:13 +0430 Subject: [PATCH 111/439] Refactor(accounts/urls): rename part of serviceprovider url --- accounts/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/urls.py b/accounts/urls.py index f12632e..2e93ccf 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -4,6 +4,6 @@ app_name = 'accounts' urlpatterns = [ path( - 'seviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' + 'serviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' ), ] From f95f5622eab7aa454908141e19414af224a06945 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:49:03 +0430 Subject: [PATCH 112/439] Update(accounts/urls): add new url for service provider login --- accounts/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accounts/urls.py b/accounts/urls.py index 2e93ccf..0ed355b 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,9 +1,10 @@ from django.urls import path -from .views import ServiceProviderRegistrationView +from .views import ServiceProviderRegistrationView, ServiceProviderLoginView app_name = 'accounts' urlpatterns = [ path( 'serviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' ), + path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), ] From bde2a2d5151b5076aafd5dce2ab8140782ab3cb4 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:49:49 +0430 Subject: [PATCH 113/439] Update(accounts/views): update success url field in service provider registeration view --- accounts/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index dfecdcf..e29cbd3 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -7,7 +7,7 @@ class ServiceProviderRegistrationView(FormView): form_class = ServiceProviderRegistrationForm template_name = 'accounts/service_provider_registration.html' - success_url = reverse_lazy('') + success_url = reverse_lazy('accounts:service-provider-login') def form_valid(self, form): instance = form.save(commit=False) From a66ff877d263e43ad8bf6bff3bfef17538722aad Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:52:39 +0430 Subject: [PATCH 114/439] Add(accounts/forms): create service provider login form --- accounts/forms.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index ea1e59c..26d9cc9 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -1,5 +1,7 @@ from django import forms +from django.contrib.auth import authenticate from django.core.exceptions import ValidationError +from django.db.models import Q from accounts.models import ServiceProvider @@ -56,3 +58,25 @@ def clean_confirm_password(self): if self.cleaned_data['password'] != self.cleaned_data['confirm_password']: raise ValidationError('passwords not equal!') return self.cleaned_data['confirm_password'] + + +class ServiceProviderLoginForm(forms.Form): + username = forms.CharField( + min_length=4, + widget=forms.TextInput( + attrs={ + 'placeholder': 'Username, Email, Phone Number', + 'class': 'form-control'} + ) + ) + + password = forms.CharField( + max_length=30, + min_length=4, + widget=forms.PasswordInput( + attrs={ + 'placeholder': 'Password', + 'class': 'form-control'} + ) + ) + From ec5bf4a177007db7c14ca8fe2cf09785232a8e2b Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:53:37 +0430 Subject: [PATCH 115/439] Update(accounts/forms): edit clean method in service provider login form --- accounts/forms.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index 26d9cc9..90fce67 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -80,3 +80,18 @@ class ServiceProviderLoginForm(forms.Form): ) ) + def clean(self): + cleaned_data = super().clean() + + username = cleaned_data['username'] + user = ServiceProvider.objects.filter( + Q(username=username) | + Q(email=username) | + Q(phone_number=username), + ).first() + + if user and user.check_password(cleaned_data['password']): + cleaned_data['user'] = user + return cleaned_data + + raise ValidationError('username or password invalid!') From 3b49b13a8679de425e971def828a00c6e9262536 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:54:20 +0430 Subject: [PATCH 116/439] Add(accounts/views): create service provider login view --- accounts/views.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index e29cbd3..70bc334 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,7 +1,8 @@ +from django.contrib.auth import authenticate, login from django.contrib.auth.hashers import make_password from django.urls import reverse_lazy from django.views.generic import FormView -from .forms import ServiceProviderRegistrationForm +from .forms import ServiceProviderRegistrationForm, ServiceProviderLoginForm class ServiceProviderRegistrationView(FormView): @@ -14,3 +15,16 @@ def form_valid(self, form): instance.password = make_password(instance.password) instance.save() return self.form_valid(form) + + +class ServiceProviderLoginView(FormView): + form_class = ServiceProviderLoginForm + template_name = 'accounts/service_provider_login.html' + success_url = reverse_lazy('') + + def form_valid(self, form): + user = form.cleaned_data['user'] + user_authenticated = authenticate(username=user.username, password=user.password) + if user_authenticated: + login(self.request, user_authenticated) + return self.form_valid(form) From c8841a0e6b17f913ef63bdb3622009ace68135d0 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:55:16 +0430 Subject: [PATCH 117/439] Style(accounts/templates): add form tag to login template file --- accounts/templates/accounts/service_provider_login.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/accounts/templates/accounts/service_provider_login.html b/accounts/templates/accounts/service_provider_login.html index 4820b21..5e62f51 100644 --- a/accounts/templates/accounts/service_provider_login.html +++ b/accounts/templates/accounts/service_provider_login.html @@ -5,6 +5,10 @@ Service Provider Login - +
+ {% csrf_token %} + {{ form.as_p }} + +
\ No newline at end of file From 86d097ca7355a20ab9ee840fc90be1481986b150 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:55:51 +0430 Subject: [PATCH 118/439] Fix(accounts/authenticate): fix the bug in service provider authentication --- accounts/authenticate.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/accounts/authenticate.py b/accounts/authenticate.py index f92d21a..7c38167 100644 --- a/accounts/authenticate.py +++ b/accounts/authenticate.py @@ -1,17 +1,16 @@ from django.contrib.auth import get_user_model from django.contrib.auth.backends import BaseBackend -from django.db.models import Q -User = get_user_model() +from accounts.models import ServiceProvider class ServiceProviderAuthentication(BaseBackend): - def authenticate(self, request, username_email=None, password=None): + def authenticate(self, request, username=None, password=None): try: - user = User.objects.get(Q(username=username_email) | Q(email=username_email), password=password) + user = ServiceProvider.objects.get(username=username, password=password) return user - except User.DoesNotExist: + except ServiceProvider.DoesNotExist: return None def get_user(self, user_id): From d41b58d1b464108cacc4e8e72cef309f6017ef0f Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 16:57:21 +0430 Subject: [PATCH 119/439] Add(accounts/urls): add service provider logout url --- accounts/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/accounts/urls.py b/accounts/urls.py index 0ed355b..a42e5ab 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -7,4 +7,5 @@ 'serviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' ), path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), + path('serviceprovider/logout/', name='service-provider-logout') ] From 63f215406d8c9874300b91376af8f5b33c32358a Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 17:21:50 +0430 Subject: [PATCH 120/439] Add(accounts/views): add CustomerPasswordConfirmView class view --- accounts/views.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 2ce077c..4c0d341 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,6 +1,6 @@ from django.contrib import messages from django.views.generic import FormView -from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm +from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm from accounts.models import Customer from accounts.utils import check_expire_time from django.contrib.auth import authenticate, login @@ -56,3 +56,23 @@ def form_valid(self, form): def delete_confirm_code(self): del self.request.session['code'] + + +class CustomerPasswordConfirmView(FormView): + form_class = CustomerPasswordForm + template_name = None + success_url = None + + def form_valid(self, form): + phone_number = self.request.session['phone_number'] + password = form.changed_data['password'] + customer = authenticate(phone_number=phone_number, password=password) + + if customer: + login(self.request, customer) + messages.info(self.request, 'Login success', 'success') + super().form_valid(form) + + else: + messages.info(self.request, 'Your password is incorrect!', 'danger') + return From 8d253e32ebec02f3e84cad4f097eb60d02610ddb Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 17:31:01 +0430 Subject: [PATCH 121/439] Fix(accounts/authentication): fix the get_user method in service provider authentication --- accounts/authenticate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/authenticate.py b/accounts/authenticate.py index 7c38167..ac0e4b2 100644 --- a/accounts/authenticate.py +++ b/accounts/authenticate.py @@ -15,6 +15,6 @@ def authenticate(self, request, username=None, password=None): def get_user(self, user_id): try: - return User.objects.get(pk=user_id) - except User.DoesNotExist: + return ServiceProvider.objects.get(pk=user_id) + except ServiceProvider.DoesNotExist: return None From 9bed978bdedb025754a3cdf527b76119d31725aa Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 17:32:00 +0430 Subject: [PATCH 122/439] Refactor(accounts/authentication): use pep8 in file --- accounts/authenticate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/accounts/authenticate.py b/accounts/authenticate.py index ac0e4b2..a8611b4 100644 --- a/accounts/authenticate.py +++ b/accounts/authenticate.py @@ -1,4 +1,3 @@ -from django.contrib.auth import get_user_model from django.contrib.auth.backends import BaseBackend from accounts.models import ServiceProvider From 1a2c596d6e3ff8f60af37275ae581eb7a0eea144 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 17:36:19 +0430 Subject: [PATCH 123/439] Add(accounts/templates): add templates for login and register process --- accounts/templates/accounts/base.html | 22 +++++++++++++++++++ .../templates/accounts/login_register.html | 22 +++++++++++++++++++ .../templates/accounts/password_confirm.html | 22 +++++++++++++++++++ .../accounts/phone_number_confirm.html | 22 +++++++++++++++++++ accounts/views.py | 6 ++--- 5 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 accounts/templates/accounts/base.html create mode 100644 accounts/templates/accounts/login_register.html create mode 100644 accounts/templates/accounts/password_confirm.html create mode 100644 accounts/templates/accounts/phone_number_confirm.html diff --git a/accounts/templates/accounts/base.html b/accounts/templates/accounts/base.html new file mode 100644 index 0000000..0dd635f --- /dev/null +++ b/accounts/templates/accounts/base.html @@ -0,0 +1,22 @@ + + + + + + + + + + {% block title %} {% endblock %} + + +
+ {% block content %} + {% endblock %} +
+ + + \ No newline at end of file diff --git a/accounts/templates/accounts/login_register.html b/accounts/templates/accounts/login_register.html new file mode 100644 index 0000000..6538a94 --- /dev/null +++ b/accounts/templates/accounts/login_register.html @@ -0,0 +1,22 @@ +{% extends 'accounts/base.html' %} + +{% block content %} +

Register - Login

+
+ {% csrf_token %} + {% for field in form %} + +
+

{{ field }}

+ {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% if form.errors %} + {% block form_error %} {% endblock %} + {% endif %} + + +
+{% endblock %} \ No newline at end of file diff --git a/accounts/templates/accounts/password_confirm.html b/accounts/templates/accounts/password_confirm.html new file mode 100644 index 0000000..101fab4 --- /dev/null +++ b/accounts/templates/accounts/password_confirm.html @@ -0,0 +1,22 @@ +{% extends 'accounts/base.html' %} + +{% block content %} +

Confirm your password

+
+ {% csrf_token %} + {% for field in form %} + +
+

{{ field }}

+ {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% if form.errors %} + {% block form_error %} {% endblock %} + {% endif %} + + +
+{% endblock %} \ No newline at end of file diff --git a/accounts/templates/accounts/phone_number_confirm.html b/accounts/templates/accounts/phone_number_confirm.html new file mode 100644 index 0000000..a3b730c --- /dev/null +++ b/accounts/templates/accounts/phone_number_confirm.html @@ -0,0 +1,22 @@ +{% extends 'accounts/base.html' %} + +{% block content %} +

Confirm your phone number

+
+ {% csrf_token %} + {% for field in form %} + +
+

{{ field }}

+ {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% if form.errors %} + {% block form_error %} {% endblock %} + {% endif %} + + +
+{% endblock %} \ No newline at end of file diff --git a/accounts/views.py b/accounts/views.py index 4c0d341..230d2d7 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -8,7 +8,7 @@ class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm - template_name = None + template_name = 'accounts/login_register.html' def form_valid(self, form): try: @@ -23,7 +23,7 @@ def form_valid(self, form): class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm - template_name = None + template_name = 'accounts/phone_number_confirm.html' success_url = None def dispatch(self, request, *args, **kwargs): @@ -60,7 +60,7 @@ def delete_confirm_code(self): class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm - template_name = None + template_name = 'accounts/password_confirm.html' success_url = None def form_valid(self, form): From d0e2d583279c388a63920275625e89e8144e865e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 17:41:35 +0430 Subject: [PATCH 124/439] Add(accounts/urls): create urls.py and add urlpatterns --- accounts/urls.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 accounts/urls.py diff --git a/accounts/urls.py b/accounts/urls.py new file mode 100644 index 0000000..5a175b5 --- /dev/null +++ b/accounts/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView + +app_name = 'accounts' + +urlpatterns = [ + path('login-register/', CustomerLoginRegisterView.as_view(), name='login-register'), + path('code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='code-confirm'), + path('password-confirm/', CustomerPasswordConfirmView.as_view(), name='password-confirm'), +] From aa6f9a55ce8b62b54470e9c957721cb73672d8f1 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 17:42:52 +0430 Subject: [PATCH 125/439] Update(snapp_food/urls): include accounts.urls --- snapp_food/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snapp_food/urls.py b/snapp_food/urls.py index 7f88547..d99ab63 100644 --- a/snapp_food/urls.py +++ b/snapp_food/urls.py @@ -14,8 +14,9 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), + path('accounts', include('accounts.urls')), ] From 570e517af92e0d8cb3747e3c2a0fad96c7bb6ddd Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 17:47:30 +0430 Subject: [PATCH 126/439] Update(accounts/views): change the success_url of CustomerLoginRegisterView --- accounts/views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 230d2d7..02c9651 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,4 +1,5 @@ from django.contrib import messages +from django.urls import reverse_lazy from django.views.generic import FormView from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm from accounts.models import Customer @@ -9,14 +10,16 @@ class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm template_name = 'accounts/login_register.html' + success_url = reverse_lazy('accounts:code-confirm') def form_valid(self, form): try: - Customer.objects.get(phone_number=form.changed_data['phone_number']) + customer = Customer.objects.get(phone_number=form.changed_data['phone_number']) except Customer.DoesNotExist: - self.success_url = None + pass else: - self.success_url = None + if customer.password: + self.success_url = reverse_lazy('accounts:password-confirm') return super().form_valid(form) From e4b2a845c43204140b0cd45b16c957ae52590054 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 17:57:17 +0430 Subject: [PATCH 127/439] Add(accounts): create profile view, template and url --- accounts/templates/accounts/profile.html | 6 ++++++ accounts/urls.py | 5 ++++- accounts/views.py | 6 +++++- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 accounts/templates/accounts/profile.html diff --git a/accounts/templates/accounts/profile.html b/accounts/templates/accounts/profile.html new file mode 100644 index 0000000..d555e6a --- /dev/null +++ b/accounts/templates/accounts/profile.html @@ -0,0 +1,6 @@ +{% extends 'accounts/base.html' %} + +{% block content %} +

Profile

+

Phone number : {{ request.user.phone_number }}

+{% endblock %} \ No newline at end of file diff --git a/accounts/urls.py b/accounts/urls.py index 5a175b5..2bfeb75 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,5 +1,6 @@ from django.urls import path -from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView +from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView, \ + ProfileView app_name = 'accounts' @@ -7,4 +8,6 @@ path('login-register/', CustomerLoginRegisterView.as_view(), name='login-register'), path('code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='code-confirm'), path('password-confirm/', CustomerPasswordConfirmView.as_view(), name='password-confirm'), + path('profile/', ProfileView.as_view(), name='profile'), + ] diff --git a/accounts/views.py b/accounts/views.py index 02c9651..d521551 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,12 +1,16 @@ from django.contrib import messages from django.urls import reverse_lazy -from django.views.generic import FormView +from django.views.generic import FormView, TemplateView from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm from accounts.models import Customer from accounts.utils import check_expire_time from django.contrib.auth import authenticate, login +class ProfileView(TemplateView): + template_name = 'accounts/profile.html' + + class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm template_name = 'accounts/login_register.html' From 3a9adccc250c88fc3b0b537f4668a1ceef0b0ada Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:00:32 +0430 Subject: [PATCH 128/439] Update(accounts/views): add success_url and redirects for CustomerPhoneNumberConfirmView --- accounts/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index d521551..cc427ed 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,4 +1,5 @@ from django.contrib import messages +from django.shortcuts import redirect from django.urls import reverse_lazy from django.views.generic import FormView, TemplateView from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm @@ -31,7 +32,7 @@ def form_valid(self, form): class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm template_name = 'accounts/phone_number_confirm.html' - success_url = None + success_url = reverse_lazy('accounts:profile') def dispatch(self, request, *args, **kwargs): check_expire_time(request) @@ -56,10 +57,10 @@ def form_valid(self, form): else: messages.info(self.request, 'The code is incorrect!', 'danger') - return + return redirect('accounts:code-confirm') else: messages.info(self.request, 'The code is invalid! Enter your phone number again', 'danger') - return + return redirect('accounts:login-register') def delete_confirm_code(self): del self.request.session['code'] From dbe087e16046222ceb47f4a49931ee9f93beb609 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:01:42 +0430 Subject: [PATCH 129/439] Update(accounts/views): add success_url and redirects for CustomerPasswordConfirmView --- accounts/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index cc427ed..0ca1881 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -69,7 +69,7 @@ def delete_confirm_code(self): class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm template_name = 'accounts/password_confirm.html' - success_url = None + success_url = reverse_lazy('accounts:profile') def form_valid(self, form): phone_number = self.request.session['phone_number'] @@ -83,4 +83,4 @@ def form_valid(self, form): else: messages.info(self.request, 'Your password is incorrect!', 'danger') - return + return redirect('accounts:password-confirm') From bbe1434c0ddfe98c17beac2529cd2977f733a77f Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:04:09 +0430 Subject: [PATCH 130/439] Fix(snapp_food/settings): add missing / for accounts path --- snapp_food/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapp_food/urls.py b/snapp_food/urls.py index d99ab63..ee78b57 100644 --- a/snapp_food/urls.py +++ b/snapp_food/urls.py @@ -18,5 +18,5 @@ urlpatterns = [ path('admin/', admin.site.urls), - path('accounts', include('accounts.urls')), + path('accounts/', include('accounts.urls')), ] From d5738bfd9b83c0cab568d6db364d889f19b6c655 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:10:03 +0430 Subject: [PATCH 131/439] Fix(accounts/views): fix a typo in form_valid of CustomerLoginRegisterView --- accounts/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 0ca1881..d05976a 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -19,7 +19,7 @@ class CustomerLoginRegisterView(FormView): def form_valid(self, form): try: - customer = Customer.objects.get(phone_number=form.changed_data['phone_number']) + customer = Customer.objects.get(phone_number=form.cleaned_data['phone_number']) except Customer.DoesNotExist: pass else: From 133eecc5a57923136f68a06c50695906bb12c834 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:13:08 +0430 Subject: [PATCH 132/439] Update(accounts/views): add setting phone_numbers session in CustomerLoginRegisterView --- accounts/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index d05976a..963ad60 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -4,7 +4,7 @@ from django.views.generic import FormView, TemplateView from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm from accounts.models import Customer -from accounts.utils import check_expire_time +from accounts.utils import check_expire_time, set_phone_number_session from django.contrib.auth import authenticate, login @@ -21,10 +21,12 @@ def form_valid(self, form): try: customer = Customer.objects.get(phone_number=form.cleaned_data['phone_number']) except Customer.DoesNotExist: - pass + set_phone_number_session(self.request, form.cleaned_data['phone_number']) else: if customer.password: self.success_url = reverse_lazy('accounts:password-confirm') + else: + set_phone_number_session(self.request, form.cleaned_data['phone_number']) return super().form_valid(form) From 0a1db552f3236fc0e78d32455567a45122c20f4a Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:17:31 +0430 Subject: [PATCH 133/439] Fix(accounts/views): fix a typo for changed_data to cleaned_data --- accounts/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 963ad60..7ffc255 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -42,7 +42,7 @@ def dispatch(self, request, *args, **kwargs): def form_valid(self, form): phone_number = '98' + self.request.session['phone_number'] - form_code = int(form.changed_data['code']) + form_code = int(form.cleaned_data['code']) session_code = self.request.get('code', None) if session_code: @@ -75,7 +75,7 @@ class CustomerPasswordConfirmView(FormView): def form_valid(self, form): phone_number = self.request.session['phone_number'] - password = form.changed_data['password'] + password = form.cleaned_data['password'] customer = authenticate(phone_number=phone_number, password=password) if customer: From 90b2e6fc7f82c9d3c2abf1c875b958e9f55b8b4d Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:31:01 +0430 Subject: [PATCH 134/439] Fix(accounts/view): fix a typo in form_valid of CustomerPhoneNumberConfirmView --- accounts/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 7ffc255..f6ed3c1 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -43,7 +43,7 @@ def dispatch(self, request, *args, **kwargs): def form_valid(self, form): phone_number = '98' + self.request.session['phone_number'] form_code = int(form.cleaned_data['code']) - session_code = self.request.get('code', None) + session_code = self.request.session.get('code', None) if session_code: if session_code == form_code: From 1ce8522bc19a6c3508c8aeb2a22795236305600e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:42:14 +0430 Subject: [PATCH 135/439] Update(accounts/forms): add int_list_validator for CustomerCodeConfirmForm --- accounts/forms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/accounts/forms.py b/accounts/forms.py index cfec135..9d67db9 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -15,6 +15,7 @@ class CustomerLoginRegisterForm(forms.Form): class CustomerCodeConfirmForm(forms.Form): code = forms.CharField( + validators=[int_list_validator(message=_('only digits are accepted'))], widget=forms.TextInput( attrs={ 'class': 'form-control', From 3491a457b7648d7383f59a923e6596ddc1d7d11d Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 18:52:49 +0430 Subject: [PATCH 136/439] Add(accounts/views): create logout view for users --- accounts/views.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 70bc334..a72b74a 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,7 +1,7 @@ -from django.contrib.auth import authenticate, login +from django.contrib.auth import authenticate, login, logout from django.contrib.auth.hashers import make_password from django.urls import reverse_lazy -from django.views.generic import FormView +from django.views.generic import FormView, RedirectView from .forms import ServiceProviderRegistrationForm, ServiceProviderLoginForm @@ -28,3 +28,10 @@ def form_valid(self, form): if user_authenticated: login(self.request, user_authenticated) return self.form_valid(form) + + +class UserLogoutView(RedirectView): + def get(self, request, *args, **kwargs): + if self.request.user.is_authenticated(): + logout(self.request) + return super().get(request, *args, **kwargs) From 3f6bfbc2f23e093cac2800db543269dc77a00f52 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 18:53:32 +0430 Subject: [PATCH 137/439] Update(accounts/urls): update user logout url --- accounts/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/urls.py b/accounts/urls.py index a42e5ab..aa95408 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from .views import ServiceProviderRegistrationView, ServiceProviderLoginView +from .views import ServiceProviderRegistrationView, ServiceProviderLoginView, UserLogoutView app_name = 'accounts' urlpatterns = [ @@ -7,5 +7,5 @@ 'serviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' ), path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), - path('serviceprovider/logout/', name='service-provider-logout') + path('user/logout/', UserLogoutView.as_view(), name='user-logout') ] From b9cb1b2e19bb8e27a66a4b4e9822bf7f75d5a771 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 18:59:39 +0430 Subject: [PATCH 138/439] Fix(accounts/view): fix a bug for getting customer in CustomerLoginRegisterView --- accounts/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index f6ed3c1..839d798 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -19,7 +19,7 @@ class CustomerLoginRegisterView(FormView): def form_valid(self, form): try: - customer = Customer.objects.get(phone_number=form.cleaned_data['phone_number']) + customer = Customer.objects.get(phone_number='98' + form.cleaned_data['phone_number']) except Customer.DoesNotExist: set_phone_number_session(self.request, form.cleaned_data['phone_number']) else: From e7bf645a27632a861ee20ed439ed117f2ad63b47 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:08:43 +0430 Subject: [PATCH 139/439] Fix(accounts/views): fix form_valid bug in service provider login view --- accounts/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index a72b74a..76a1649 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -20,14 +20,14 @@ def form_valid(self, form): class ServiceProviderLoginView(FormView): form_class = ServiceProviderLoginForm template_name = 'accounts/service_provider_login.html' - success_url = reverse_lazy('') + success_url = reverse_lazy('accounts:service-provider-profile') def form_valid(self, form): user = form.cleaned_data['user'] user_authenticated = authenticate(username=user.username, password=user.password) if user_authenticated: login(self.request, user_authenticated) - return self.form_valid(form) + return super().form_valid(form) class UserLogoutView(RedirectView): From c2c476f3f04579997ddad4ea94b541163faab6e1 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:11:05 +0430 Subject: [PATCH 140/439] Add(accounts/templates): create service provider profile remplate --- .../accounts/service_provider_profile.html | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 accounts/templates/accounts/service_provider_profile.html diff --git a/accounts/templates/accounts/service_provider_profile.html b/accounts/templates/accounts/service_provider_profile.html new file mode 100644 index 0000000..7e81dc6 --- /dev/null +++ b/accounts/templates/accounts/service_provider_profile.html @@ -0,0 +1,13 @@ + + + + + Service Provider Profile + + +

Your Profile

+

your username: {{ request.user.username }}

+

your email: {{ request.user.email }}

+

your phone number: {{ request.user.phone_number }}

+ + \ No newline at end of file From f97d41b6bc7fe6055f1cb1b31a987fc2953fc803 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:11:44 +0430 Subject: [PATCH 141/439] Add(accounts/views): create service provider profile view --- accounts/views.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 76a1649..44c7d6e 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,7 +1,7 @@ from django.contrib.auth import authenticate, login, logout from django.contrib.auth.hashers import make_password from django.urls import reverse_lazy -from django.views.generic import FormView, RedirectView +from django.views.generic import FormView, RedirectView, TemplateView from .forms import ServiceProviderRegistrationForm, ServiceProviderLoginForm @@ -30,6 +30,10 @@ def form_valid(self, form): return super().form_valid(form) +class ServiceProviderProfileView(TemplateView): + template_name = 'accounts/service_provider_profile.html' + + class UserLogoutView(RedirectView): def get(self, request, *args, **kwargs): if self.request.user.is_authenticated(): From 914d4f17ccc41da5adc66e400d17d8b1e21eba54 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:12:16 +0430 Subject: [PATCH 142/439] Add(accounts/urls): create service provider profile url --- accounts/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accounts/urls.py b/accounts/urls.py index aa95408..3a93246 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from .views import ServiceProviderRegistrationView, ServiceProviderLoginView, UserLogoutView +from .views import ServiceProviderRegistrationView, ServiceProviderLoginView, UserLogoutView, ServiceProviderProfileView app_name = 'accounts' urlpatterns = [ @@ -7,5 +7,6 @@ 'serviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' ), path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), + path('serviceprovider/profile/', ServiceProviderProfileView.as_view(), name='service-provider-profile'), path('user/logout/', UserLogoutView.as_view(), name='user-logout') ] From a878f818059fa63cbee9bdbf3296775abd3023d7 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:13:04 +0430 Subject: [PATCH 143/439] Fix(accounts/views): fix form_valid bug in service provider registration view --- accounts/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 44c7d6e..203699b 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -14,7 +14,7 @@ def form_valid(self, form): instance = form.save(commit=False) instance.password = make_password(instance.password) instance.save() - return self.form_valid(form) + return super().form_valid(form) class ServiceProviderLoginView(FormView): From ef54d277b3aa8a67a3894e2452640d4fd951c217 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 19:19:30 +0430 Subject: [PATCH 144/439] Clean(accounts/views): clean code in CustomerLoginRegisterView form_valid --- accounts/authenticate.py | 2 ++ accounts/views.py | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/accounts/authenticate.py b/accounts/authenticate.py index 36a82bf..754a6d7 100644 --- a/accounts/authenticate.py +++ b/accounts/authenticate.py @@ -12,6 +12,8 @@ def authenticate(self, request, phone_number=None, password=None): if password: # if the password is sent via the form if customer.check_password(password): return customer + else: + return None return customer def get_user(self, user_id): diff --git a/accounts/views.py b/accounts/views.py index 839d798..230d92c 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -18,15 +18,17 @@ class CustomerLoginRegisterView(FormView): success_url = reverse_lazy('accounts:code-confirm') def form_valid(self, form): + phone_number = form.cleaned_data['phone_number'] try: - customer = Customer.objects.get(phone_number='98' + form.cleaned_data['phone_number']) + customer = Customer.objects.get(phone_number='98' + phone_number) except Customer.DoesNotExist: - set_phone_number_session(self.request, form.cleaned_data['phone_number']) + set_phone_number_session(self.request, phone_number) else: if customer.password: self.success_url = reverse_lazy('accounts:password-confirm') + self.request.session['phone_number'] = phone_number else: - set_phone_number_session(self.request, form.cleaned_data['phone_number']) + set_phone_number_session(self.request, phone_number) return super().form_valid(form) From cb98f98760650551aeff6c9c2be2e8f4d7f3965e Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:20:55 +0430 Subject: [PATCH 145/439] Refactor(accounts/views): remove some clean_s service provider registration form --- accounts/forms.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index 90fce67..64c3f48 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -33,24 +33,11 @@ class Meta: 'password': forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}), } - def clean_username(self): - if ServiceProvider.objects.filter(username=self.cleaned_data['username']).exists(): - raise ValidationError('There is a username!') - return self.cleaned_data['username'] - - def clean_email(self): - if ServiceProvider.objects.filter(email=self.cleaned_data['email']).exists(): - raise ValidationError('There is a email!') - return self.cleaned_data['email'] - def clean_phone_number(self): phone = self.cleaned_data['phone_number'] if phone.startswith('98') and len(phone) == 12: - if ServiceProvider.objects.filter(email=self.cleaned_data['phone_number']).exists(): - raise ValidationError('There is a phone_number!') - else: - return self.cleaned_data['phone_number'] + return self.cleaned_data['phone_number'] else: raise ValidationError('phone_number invalid!') From 32a12f00e33763c6dc4c7a706f0675397e8f8e0f Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 19:52:25 +0430 Subject: [PATCH 146/439] Refactor(accounts/urls): add customer/ for customer urls --- accounts/urls.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/accounts/urls.py b/accounts/urls.py index 2bfeb75..bad9c4c 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -5,9 +5,8 @@ app_name = 'accounts' urlpatterns = [ - path('login-register/', CustomerLoginRegisterView.as_view(), name='login-register'), - path('code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='code-confirm'), - path('password-confirm/', CustomerPasswordConfirmView.as_view(), name='password-confirm'), - path('profile/', ProfileView.as_view(), name='profile'), - + path('customer/login-register/', CustomerLoginRegisterView.as_view(), name='login-register'), + path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='code-confirm'), + path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='password-confirm'), + path('customer/profile/', ProfileView.as_view(), name='profile'), ] From 2e6fbf0e0339879e2b397b14f65e365e5bd55c4e Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:52:01 +0430 Subject: [PATCH 147/439] Fix(accounts/views): fix is authenticated bug in logout view and rename login view --- accounts/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 203699b..5225d44 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -34,8 +34,8 @@ class ServiceProviderProfileView(TemplateView): template_name = 'accounts/service_provider_profile.html' -class UserLogoutView(RedirectView): +class LogoutView(RedirectView): def get(self, request, *args, **kwargs): - if self.request.user.is_authenticated(): + if self.request.user.is_authenticated: logout(self.request) return super().get(request, *args, **kwargs) From c0d0d7f1f02662042d9e03864283bfebd66a1d62 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 19:54:17 +0430 Subject: [PATCH 148/439] Update(accounts/templates): move customer templates to its dir --- .../templates/accounts/{ => customer}/login_register.html | 0 .../accounts/{ => customer}/password_confirm.html | 0 .../accounts/{ => customer}/phone_number_confirm.html | 0 accounts/templates/accounts/{ => customer}/profile.html | 0 accounts/views.py | 8 ++++---- 5 files changed, 4 insertions(+), 4 deletions(-) rename accounts/templates/accounts/{ => customer}/login_register.html (100%) rename accounts/templates/accounts/{ => customer}/password_confirm.html (100%) rename accounts/templates/accounts/{ => customer}/phone_number_confirm.html (100%) rename accounts/templates/accounts/{ => customer}/profile.html (100%) diff --git a/accounts/templates/accounts/login_register.html b/accounts/templates/accounts/customer/login_register.html similarity index 100% rename from accounts/templates/accounts/login_register.html rename to accounts/templates/accounts/customer/login_register.html diff --git a/accounts/templates/accounts/password_confirm.html b/accounts/templates/accounts/customer/password_confirm.html similarity index 100% rename from accounts/templates/accounts/password_confirm.html rename to accounts/templates/accounts/customer/password_confirm.html diff --git a/accounts/templates/accounts/phone_number_confirm.html b/accounts/templates/accounts/customer/phone_number_confirm.html similarity index 100% rename from accounts/templates/accounts/phone_number_confirm.html rename to accounts/templates/accounts/customer/phone_number_confirm.html diff --git a/accounts/templates/accounts/profile.html b/accounts/templates/accounts/customer/profile.html similarity index 100% rename from accounts/templates/accounts/profile.html rename to accounts/templates/accounts/customer/profile.html diff --git a/accounts/views.py b/accounts/views.py index 230d92c..a3387b2 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -9,12 +9,12 @@ class ProfileView(TemplateView): - template_name = 'accounts/profile.html' + template_name = 'accounts/customer/profile.html' class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm - template_name = 'accounts/login_register.html' + template_name = 'accounts/customer/login_register.html' success_url = reverse_lazy('accounts:code-confirm') def form_valid(self, form): @@ -35,7 +35,7 @@ def form_valid(self, form): class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm - template_name = 'accounts/phone_number_confirm.html' + template_name = 'accounts/customer/phone_number_confirm.html' success_url = reverse_lazy('accounts:profile') def dispatch(self, request, *args, **kwargs): @@ -72,7 +72,7 @@ def delete_confirm_code(self): class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm - template_name = 'accounts/password_confirm.html' + template_name = 'accounts/customer/password_confirm.html' success_url = reverse_lazy('accounts:profile') def form_valid(self, form): From 522a8e3283b7078c655065d751f4d4decd85c6bf Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 19:58:31 +0430 Subject: [PATCH 149/439] Refactor(accounts/urls): change logout url --- accounts/forms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/accounts/forms.py b/accounts/forms.py index 64c3f48..7ff2fa5 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -1,5 +1,4 @@ from django import forms -from django.contrib.auth import authenticate from django.core.exceptions import ValidationError from django.db.models import Q From 295f2836a76610a82f1e91b5f9896eecd7c966ab Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 20:04:18 +0430 Subject: [PATCH 150/439] Refactore(accounts/templates): rename all service provider templates --- .../{service_provider_login.html => service_provider/login.html} | 0 .../profile.html} | 0 .../registration.html} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename accounts/templates/accounts/{service_provider_login.html => service_provider/login.html} (100%) rename accounts/templates/accounts/{service_provider_profile.html => service_provider/profile.html} (100%) rename accounts/templates/accounts/{service_provider_registration.html => service_provider/registration.html} (100%) diff --git a/accounts/templates/accounts/service_provider_login.html b/accounts/templates/accounts/service_provider/login.html similarity index 100% rename from accounts/templates/accounts/service_provider_login.html rename to accounts/templates/accounts/service_provider/login.html diff --git a/accounts/templates/accounts/service_provider_profile.html b/accounts/templates/accounts/service_provider/profile.html similarity index 100% rename from accounts/templates/accounts/service_provider_profile.html rename to accounts/templates/accounts/service_provider/profile.html diff --git a/accounts/templates/accounts/service_provider_registration.html b/accounts/templates/accounts/service_provider/registration.html similarity index 100% rename from accounts/templates/accounts/service_provider_registration.html rename to accounts/templates/accounts/service_provider/registration.html From 0e25ce2a95df8616324d48a337090c146a097780 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 20:05:54 +0430 Subject: [PATCH 151/439] Update(accounts/views): update all template_name views path --- accounts/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 5225d44..378b499 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -7,7 +7,7 @@ class ServiceProviderRegistrationView(FormView): form_class = ServiceProviderRegistrationForm - template_name = 'accounts/service_provider_registration.html' + template_name = 'accounts/service_provider/registration.html' success_url = reverse_lazy('accounts:service-provider-login') def form_valid(self, form): @@ -19,7 +19,7 @@ def form_valid(self, form): class ServiceProviderLoginView(FormView): form_class = ServiceProviderLoginForm - template_name = 'accounts/service_provider_login.html' + template_name = 'accounts/service_provider/login.html' success_url = reverse_lazy('accounts:service-provider-profile') def form_valid(self, form): @@ -31,7 +31,7 @@ def form_valid(self, form): class ServiceProviderProfileView(TemplateView): - template_name = 'accounts/service_provider_profile.html' + template_name = 'accounts/service_provider/profile.html' class LogoutView(RedirectView): From 4d71af747668b259afc68ba845514facae698019 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 20:10:26 +0430 Subject: [PATCH 152/439] Update(accounts/admin): add create method to CustomerManager --- accounts/models.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/accounts/models.py b/accounts/models.py index 9a858fd..9b00790 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -9,7 +9,6 @@ class CustomerManager(UserManager): def _create_user(self, phone_number, password, **extra_fields): - if not phone_number: raise ValueError('The given phone_number must be set') @@ -20,19 +19,10 @@ def _create_user(self, phone_number, password, **extra_fields): def create_user(self, phone_number, password=None, **extra_fields): extra_fields.setdefault('is_staff', False) - extra_fields.setdefault('is_superuser', False) return self._create_user(phone_number, password, **extra_fields) - def create_superuser(self, phone_number, password=None, **extra_fields): - extra_fields.setdefault('is_staff', True) - extra_fields.setdefault('is_superuser', True) - - if extra_fields.get('is_staff') is not True: - raise ValueError('Superuser must have is_staff=True.') - if extra_fields.get('is_superuser') is not True: - raise ValueError('Superuser must have is_superuser=True.') - - return self._create_user(phone_number, password, **extra_fields) + def create(self, phone_number, password=None, **extra_fields): + return self.create_user(phone_number, password, **extra_fields) class Customer(AbstractBaseUser): From c3a87e0ce4d0483efb120c697bffb9cb53f0004a Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 20:45:14 +0430 Subject: [PATCH 153/439] Update(accounts/forms, views): change the format of phone_number --- accounts/forms.py | 6 +++--- accounts/views.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index 9d67db9..3a4f35f 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -4,10 +4,10 @@ class CustomerLoginRegisterForm(forms.Form): - phone_number = forms.CharField(max_length=10, - min_length=10, + phone_number = forms.CharField(max_length=11, + min_length=11, validators=[int_list_validator(message=_('only digits are accepted'))], - error_messages={'min_length': _('phone number must have 10 digits')}, + error_messages={'min_length': _('phone number must have 11 digits')}, widget=forms.TextInput( attrs={'class': 'form-control', 'placeholder': 'phone number'}) ) diff --git a/accounts/views.py b/accounts/views.py index a3387b2..1c06c31 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -20,7 +20,7 @@ class CustomerLoginRegisterView(FormView): def form_valid(self, form): phone_number = form.cleaned_data['phone_number'] try: - customer = Customer.objects.get(phone_number='98' + phone_number) + customer = Customer.objects.get(phone_number=phone_number) except Customer.DoesNotExist: set_phone_number_session(self.request, phone_number) else: @@ -43,7 +43,7 @@ def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def form_valid(self, form): - phone_number = '98' + self.request.session['phone_number'] + phone_number = self.request.session['phone_number'] form_code = int(form.cleaned_data['code']) session_code = self.request.session.get('code', None) @@ -83,7 +83,7 @@ def form_valid(self, form): if customer: login(self.request, customer) messages.info(self.request, 'Login success', 'success') - super().form_valid(form) + return super().form_valid(form) else: messages.info(self.request, 'Your password is incorrect!', 'danger') From db292d18e4a75e600c4959d9ca9938094606baf8 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 21:27:32 +0430 Subject: [PATCH 154/439] Update(accounts): all functions implemented --- accounts/forms.py | 1 + accounts/urls.py | 1 + accounts/views.py | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index 3a4f35f..18d9b05 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -1,4 +1,5 @@ from django import forms + from django.core.validators import int_list_validator from django.utils.translation import gettext_lazy as _ diff --git a/accounts/urls.py b/accounts/urls.py index bad9c4c..16d9d47 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -9,4 +9,5 @@ path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='code-confirm'), path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='password-confirm'), path('customer/profile/', ProfileView.as_view(), name='profile'), + ] diff --git a/accounts/views.py b/accounts/views.py index 1c06c31..d6a46d8 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,6 +1,8 @@ from django.contrib import messages +from django.contrib.auth.decorators import login_required from django.shortcuts import redirect from django.urls import reverse_lazy +from django.utils.decorators import method_decorator from django.views.generic import FormView, TemplateView from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm from accounts.models import Customer @@ -8,6 +10,7 @@ from django.contrib.auth import authenticate, login +@method_decorator(login_required, name='dispatch') class ProfileView(TemplateView): template_name = 'accounts/customer/profile.html' @@ -88,3 +91,5 @@ def form_valid(self, form): else: messages.info(self.request, 'Your password is incorrect!', 'danger') return redirect('accounts:password-confirm') + + From bc2c8073b46c2013e4ffaa268e71663782630fe7 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 21:29:51 +0430 Subject: [PATCH 155/439] Refactor(accounts): add customer to all customer url names --- accounts/urls.py | 8 ++++---- accounts/views.py | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/accounts/urls.py b/accounts/urls.py index 16d9d47..51c636a 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -5,9 +5,9 @@ app_name = 'accounts' urlpatterns = [ - path('customer/login-register/', CustomerLoginRegisterView.as_view(), name='login-register'), - path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='code-confirm'), - path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='password-confirm'), - path('customer/profile/', ProfileView.as_view(), name='profile'), + path('customer/login-register/', CustomerLoginRegisterView.as_view(), name='customer-login-register'), + path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='customer-code-confirm'), + path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='customer-password-confirm'), + path('customer/profile/', ProfileView.as_view(), name='customer-profile'), ] diff --git a/accounts/views.py b/accounts/views.py index d6a46d8..17100e1 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -18,7 +18,7 @@ class ProfileView(TemplateView): class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm template_name = 'accounts/customer/login_register.html' - success_url = reverse_lazy('accounts:code-confirm') + success_url = reverse_lazy('customer-code-confirm') def form_valid(self, form): phone_number = form.cleaned_data['phone_number'] @@ -28,7 +28,7 @@ def form_valid(self, form): set_phone_number_session(self.request, phone_number) else: if customer.password: - self.success_url = reverse_lazy('accounts:password-confirm') + self.success_url = reverse_lazy('customer-password-confirm') self.request.session['phone_number'] = phone_number else: set_phone_number_session(self.request, phone_number) @@ -39,7 +39,7 @@ def form_valid(self, form): class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm template_name = 'accounts/customer/phone_number_confirm.html' - success_url = reverse_lazy('accounts:profile') + success_url = reverse_lazy('customer-profile') def dispatch(self, request, *args, **kwargs): check_expire_time(request) @@ -64,10 +64,10 @@ def form_valid(self, form): else: messages.info(self.request, 'The code is incorrect!', 'danger') - return redirect('accounts:code-confirm') + return redirect('customer-code-confirm') else: messages.info(self.request, 'The code is invalid! Enter your phone number again', 'danger') - return redirect('accounts:login-register') + return redirect('customer-login-register') def delete_confirm_code(self): del self.request.session['code'] @@ -76,7 +76,7 @@ def delete_confirm_code(self): class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm template_name = 'accounts/customer/password_confirm.html' - success_url = reverse_lazy('accounts:profile') + success_url = reverse_lazy('customer-profile') def form_valid(self, form): phone_number = self.request.session['phone_number'] @@ -90,6 +90,6 @@ def form_valid(self, form): else: messages.info(self.request, 'Your password is incorrect!', 'danger') - return redirect('accounts:password-confirm') + return redirect('customer-password-confirm') From cf0e3cb4cace420e2a9ca35e1538b75434a1e7be Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 21:49:53 +0430 Subject: [PATCH 156/439] Fix(accounts/views): chnage the url names in all views --- accounts/views.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 17100e1..0453589 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -18,7 +18,7 @@ class ProfileView(TemplateView): class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm template_name = 'accounts/customer/login_register.html' - success_url = reverse_lazy('customer-code-confirm') + success_url = reverse_lazy('accounts:customer-code-confirm') def form_valid(self, form): phone_number = form.cleaned_data['phone_number'] @@ -28,7 +28,7 @@ def form_valid(self, form): set_phone_number_session(self.request, phone_number) else: if customer.password: - self.success_url = reverse_lazy('customer-password-confirm') + self.success_url = reverse_lazy('accounts:customer-password-confirm') self.request.session['phone_number'] = phone_number else: set_phone_number_session(self.request, phone_number) @@ -39,7 +39,7 @@ def form_valid(self, form): class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm template_name = 'accounts/customer/phone_number_confirm.html' - success_url = reverse_lazy('customer-profile') + success_url = reverse_lazy('accounts:customer-profile') def dispatch(self, request, *args, **kwargs): check_expire_time(request) @@ -64,10 +64,10 @@ def form_valid(self, form): else: messages.info(self.request, 'The code is incorrect!', 'danger') - return redirect('customer-code-confirm') + return redirect('accounts:customer-code-confirm') else: messages.info(self.request, 'The code is invalid! Enter your phone number again', 'danger') - return redirect('customer-login-register') + return redirect('accounts:customer-login-register') def delete_confirm_code(self): del self.request.session['code'] @@ -76,7 +76,7 @@ def delete_confirm_code(self): class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm template_name = 'accounts/customer/password_confirm.html' - success_url = reverse_lazy('customer-profile') + success_url = reverse_lazy('accounts:customer-profile') def form_valid(self, form): phone_number = self.request.session['phone_number'] @@ -90,6 +90,6 @@ def form_valid(self, form): else: messages.info(self.request, 'Your password is incorrect!', 'danger') - return redirect('customer-password-confirm') + return redirect('accounts:customer-password-confirm') From 6bd35318e1c267fcab66fc89b3d77d830e4eeb54 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 21:56:16 +0430 Subject: [PATCH 157/439] Add(accounts/forms): create CustomerPasswordSetForm class --- accounts/forms.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index 18d9b05..88566ef 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -1,8 +1,12 @@ from django import forms +from django.contrib.auth import password_validation +from django.core.exceptions import ValidationError from django.core.validators import int_list_validator from django.utils.translation import gettext_lazy as _ +from accounts.models import Customer + class CustomerLoginRegisterForm(forms.Form): phone_number = forms.CharField(max_length=11, @@ -35,3 +39,39 @@ class CustomerPasswordForm(forms.Form): } ) ) + + +class CustomerPasswordSetForm(forms.ModelForm): + password = forms.CharField( + label=_("Password"), + strip=False, + widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}), + help_text=password_validation.password_validators_help_text_html(), + ) + password2 = forms.CharField( + label=_("Password confirmation"), + widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}), + strip=False, + help_text=_("Enter the same password as before, for verification."), + ) + + class Meta: + model = Customer + fields = ('password',) + + def clean_password2(self): + password = self.cleaned_data.get("password") + password2 = self.cleaned_data.get("password2") + if password and password2 and password != password2: + raise ValidationError( + self.error_messages['password_mismatch'], + code='password_mismatch', + ) + return password2 + + def save(self, commit=True): + customer = super().save(commit=False) + customer.set_password(self.cleaned_data["password1"]) + if commit: + customer.save() + return customer From 52c975549afb488bb648daf4f3571b62a6553641 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 22:12:57 +0430 Subject: [PATCH 158/439] Add(accounts): add set password functionality --- accounts/forms.py | 5 ++++- .../accounts/customer/password_set.html | 22 +++++++++++++++++++ .../templates/accounts/customer/profile.html | 3 +++ accounts/urls.py | 3 ++- accounts/views.py | 11 ++++++++-- 5 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 accounts/templates/accounts/customer/password_set.html diff --git a/accounts/forms.py b/accounts/forms.py index 88566ef..f48ffb6 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -42,6 +42,9 @@ class CustomerPasswordForm(forms.Form): class CustomerPasswordSetForm(forms.ModelForm): + error_messages = { + 'password_mismatch': _('The two password fields didn’t match.'), + } password = forms.CharField( label=_("Password"), strip=False, @@ -71,7 +74,7 @@ def clean_password2(self): def save(self, commit=True): customer = super().save(commit=False) - customer.set_password(self.cleaned_data["password1"]) + customer.set_password(self.cleaned_data["password"]) if commit: customer.save() return customer diff --git a/accounts/templates/accounts/customer/password_set.html b/accounts/templates/accounts/customer/password_set.html new file mode 100644 index 0000000..17f93c5 --- /dev/null +++ b/accounts/templates/accounts/customer/password_set.html @@ -0,0 +1,22 @@ +{% extends 'accounts/base.html' %} + +{% block content %} +

Set Password

+
+ {% csrf_token %} + {% for field in form %} + +
+

{{ field }}

+ {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% if form.errors %} + {% block form_error %} {% endblock %} + {% endif %} + + +
+{% endblock %} \ No newline at end of file diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index d555e6a..5c00bad 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -3,4 +3,7 @@ {% block content %}

Profile

Phone number : {{ request.user.phone_number }}

+ {% if not request.user.password %} + Set password + {% endif %} {% endblock %} \ No newline at end of file diff --git a/accounts/urls.py b/accounts/urls.py index 51c636a..84a6d2c 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,6 +1,6 @@ from django.urls import path from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView, \ - ProfileView + ProfileView, CustomerSetPasswordView app_name = 'accounts' @@ -9,5 +9,6 @@ path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='customer-code-confirm'), path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='customer-password-confirm'), path('customer/profile/', ProfileView.as_view(), name='customer-profile'), + path('customer//set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), ] diff --git a/accounts/views.py b/accounts/views.py index 0453589..d544b38 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -3,8 +3,9 @@ from django.shortcuts import redirect from django.urls import reverse_lazy from django.utils.decorators import method_decorator -from django.views.generic import FormView, TemplateView -from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm +from django.views.generic import FormView, TemplateView, UpdateView +from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm, \ + CustomerPasswordSetForm from accounts.models import Customer from accounts.utils import check_expire_time, set_phone_number_session from django.contrib.auth import authenticate, login @@ -93,3 +94,9 @@ def form_valid(self, form): return redirect('accounts:customer-password-confirm') +@method_decorator(login_required, name='dispatch') +class CustomerSetPasswordView(UpdateView): + model = Customer + form_class = CustomerPasswordSetForm + success_url = reverse_lazy('accounts:customer-login-register') + template_name = 'accounts/customer/password_set.html' From a993f0fb6934316e2b34654a0dc2137b91b84570 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 22:59:45 +0430 Subject: [PATCH 159/439] Update(accounts/admin): override save_model method of CustomerAdmin --- accounts/admin.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/accounts/admin.py b/accounts/admin.py index 46d08c9..c87f9ef 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin - +from django.contrib.auth.hashers import make_password from accounts.models import Customer, ServiceProvider @@ -10,6 +10,10 @@ class CustomerAdmin(admin.ModelAdmin): list_filter = ('is_active', 'date_joined') search_fields = ('phone_number',) + def save_model(self, request, obj, form, change): + obj.password = make_password(form.cleaned_data['password']) + return super().save_model(request, obj, form, change) + @admin.register(ServiceProvider) class ServiceProviderAdmin(admin.ModelAdmin): From a16945df80ace545e78248de3dea827044589f59 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:03:40 +0430 Subject: [PATCH 160/439] Fix(aacounts/urls): fix the name view url --- accounts/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/urls.py b/accounts/urls.py index 3a93246..2f16bc3 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from .views import ServiceProviderRegistrationView, ServiceProviderLoginView, UserLogoutView, ServiceProviderProfileView +from .views import ServiceProviderRegistrationView, ServiceProviderLoginView, LogoutView, ServiceProviderProfileView app_name = 'accounts' urlpatterns = [ @@ -8,5 +8,5 @@ ), path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), path('serviceprovider/profile/', ServiceProviderProfileView.as_view(), name='service-provider-profile'), - path('user/logout/', UserLogoutView.as_view(), name='user-logout') + path('user/logout/', LogoutView.as_view(), name='user-logout') ] From 9387b4960ea1aa4f93a71df52cd5d4b57a8b6c82 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:04:15 +0430 Subject: [PATCH 161/439] Update(accounts/views): add decorator for service provider registration view --- accounts/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/accounts/views.py b/accounts/views.py index 378b499..06bdc34 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,10 +1,12 @@ from django.contrib.auth import authenticate, login, logout from django.contrib.auth.hashers import make_password from django.urls import reverse_lazy +from django.views.decorators.http import require_http_methods from django.views.generic import FormView, RedirectView, TemplateView from .forms import ServiceProviderRegistrationForm, ServiceProviderLoginForm +@require_http_methods(['POST', 'GET']) class ServiceProviderRegistrationView(FormView): form_class = ServiceProviderRegistrationForm template_name = 'accounts/service_provider/registration.html' From c8b6b0875e9b5a9161b0dc750b8de63380483fe2 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:06:07 +0430 Subject: [PATCH 162/439] Update(accounts/views): update decorator for service provider registration view --- accounts/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 06bdc34..2d485fd 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,12 +1,13 @@ from django.contrib.auth import authenticate, login, logout from django.contrib.auth.hashers import make_password from django.urls import reverse_lazy +from django.utils.decorators import method_decorator from django.views.decorators.http import require_http_methods from django.views.generic import FormView, RedirectView, TemplateView from .forms import ServiceProviderRegistrationForm, ServiceProviderLoginForm -@require_http_methods(['POST', 'GET']) +@method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') class ServiceProviderRegistrationView(FormView): form_class = ServiceProviderRegistrationForm template_name = 'accounts/service_provider/registration.html' From 52046688e1fc3f11f331886a2f0167f814d89a9c Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:06:40 +0430 Subject: [PATCH 163/439] Update(accounts/views): add decorator for service provider login view --- accounts/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/accounts/views.py b/accounts/views.py index 2d485fd..cd1fcc1 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -20,6 +20,7 @@ def form_valid(self, form): return super().form_valid(form) +@method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') class ServiceProviderLoginView(FormView): form_class = ServiceProviderLoginForm template_name = 'accounts/service_provider/login.html' From efd5226855f2fbe6b5921f54220b9e528de8d913 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:09:09 +0430 Subject: [PATCH 164/439] Update(accounts/views): add decorator to service provider profile view --- accounts/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/accounts/views.py b/accounts/views.py index cd1fcc1..a49453c 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,4 +1,5 @@ from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.decorators import login_required from django.contrib.auth.hashers import make_password from django.urls import reverse_lazy from django.utils.decorators import method_decorator @@ -34,6 +35,7 @@ def form_valid(self, form): return super().form_valid(form) +@method_decorator(login_required(), name='dispatch') class ServiceProviderProfileView(TemplateView): template_name = 'accounts/service_provider/profile.html' From db68987ae5ae090737840fdbafbbd1f1141a9fd9 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 23:09:12 +0430 Subject: [PATCH 165/439] Update(accounts/views): add require_http_methods decorator for views --- accounts/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/accounts/views.py b/accounts/views.py index d544b38..2955a17 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -3,6 +3,7 @@ from django.shortcuts import redirect from django.urls import reverse_lazy from django.utils.decorators import method_decorator +from django.views.decorators.http import require_http_methods from django.views.generic import FormView, TemplateView, UpdateView from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm, \ CustomerPasswordSetForm @@ -11,11 +12,13 @@ from django.contrib.auth import authenticate, login +@method_decorator(require_http_methods(['GET']), name='dispatch') @method_decorator(login_required, name='dispatch') class ProfileView(TemplateView): template_name = 'accounts/customer/profile.html' +@method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm template_name = 'accounts/customer/login_register.html' @@ -37,6 +40,7 @@ def form_valid(self, form): return super().form_valid(form) +@method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm template_name = 'accounts/customer/phone_number_confirm.html' @@ -74,6 +78,7 @@ def delete_confirm_code(self): del self.request.session['code'] +@method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm template_name = 'accounts/customer/password_confirm.html' @@ -94,6 +99,7 @@ def form_valid(self, form): return redirect('accounts:customer-password-confirm') +@method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required, name='dispatch') class CustomerSetPasswordView(UpdateView): model = Customer From 240f012fac506feeefbe56a723833c2e60c14599 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:26:55 +0430 Subject: [PATCH 166/439] Delete(accounts/views): delete logout view --- accounts/views.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index a49453c..b51680f 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -35,13 +35,6 @@ def form_valid(self, form): return super().form_valid(form) -@method_decorator(login_required(), name='dispatch') +@method_decorator(login_required, name='dispatch') class ServiceProviderProfileView(TemplateView): template_name = 'accounts/service_provider/profile.html' - - -class LogoutView(RedirectView): - def get(self, request, *args, **kwargs): - if self.request.user.is_authenticated: - logout(self.request) - return super().get(request, *args, **kwargs) From 79b42e7619869e4e6c1a86a025e24c2d5929a80f Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:27:51 +0430 Subject: [PATCH 167/439] Update(accounts/urls): use django logout view instead of my logout view --- accounts/urls.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accounts/urls.py b/accounts/urls.py index 2f16bc3..0673581 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,6 +1,6 @@ -from django.urls import path -from .views import ServiceProviderRegistrationView, ServiceProviderLoginView, LogoutView, ServiceProviderProfileView - +from django.urls import path, reverse_lazy +from .views import ServiceProviderRegistrationView, ServiceProviderLoginView, ServiceProviderProfileView +from django.contrib.auth.views import LogoutView app_name = 'accounts' urlpatterns = [ path( @@ -8,5 +8,5 @@ ), path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), path('serviceprovider/profile/', ServiceProviderProfileView.as_view(), name='service-provider-profile'), - path('user/logout/', LogoutView.as_view(), name='user-logout') + path('logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:service-provider-login')), name='logout') ] From a00549fa8620bb8d444dac07ebba790b534d0ef9 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:36:59 +0430 Subject: [PATCH 168/439] Style(accounts/templates): create base templates for accounts templates --- accounts/templates/accounts/base.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 accounts/templates/accounts/base.html diff --git a/accounts/templates/accounts/base.html b/accounts/templates/accounts/base.html new file mode 100644 index 0000000..0dd635f --- /dev/null +++ b/accounts/templates/accounts/base.html @@ -0,0 +1,22 @@ + + + + + + + + + + {% block title %} {% endblock %} + + +
+ {% block content %} + {% endblock %} +
+ + + \ No newline at end of file From 3000ae8d64777dfd64efce956e82131562ede734 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Sun, 29 Aug 2021 23:39:59 +0430 Subject: [PATCH 169/439] Update(accounts/templates): add title for all acounts templates --- accounts/templates/accounts/customer/login_register.html | 2 +- accounts/templates/accounts/customer/password_confirm.html | 2 +- accounts/templates/accounts/customer/password_set.html | 2 +- accounts/templates/accounts/customer/phone_number_confirm.html | 2 +- accounts/templates/accounts/customer/profile.html | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/accounts/templates/accounts/customer/login_register.html b/accounts/templates/accounts/customer/login_register.html index 6538a94..d31e4da 100644 --- a/accounts/templates/accounts/customer/login_register.html +++ b/accounts/templates/accounts/customer/login_register.html @@ -1,5 +1,5 @@ {% extends 'accounts/base.html' %} - +{% block title %} Login - Register {% endblock %} {% block content %}

Register - Login

diff --git a/accounts/templates/accounts/customer/password_confirm.html b/accounts/templates/accounts/customer/password_confirm.html index 101fab4..b37682c 100644 --- a/accounts/templates/accounts/customer/password_confirm.html +++ b/accounts/templates/accounts/customer/password_confirm.html @@ -1,5 +1,5 @@ {% extends 'accounts/base.html' %} - +{% block title %} Password Confirm {% endblock %} {% block content %}

Confirm your password

diff --git a/accounts/templates/accounts/customer/password_set.html b/accounts/templates/accounts/customer/password_set.html index 17f93c5..7c49adb 100644 --- a/accounts/templates/accounts/customer/password_set.html +++ b/accounts/templates/accounts/customer/password_set.html @@ -1,5 +1,5 @@ {% extends 'accounts/base.html' %} - +{% block title %} Password Set {% endblock %} {% block content %}

Set Password

diff --git a/accounts/templates/accounts/customer/phone_number_confirm.html b/accounts/templates/accounts/customer/phone_number_confirm.html index a3b730c..675a140 100644 --- a/accounts/templates/accounts/customer/phone_number_confirm.html +++ b/accounts/templates/accounts/customer/phone_number_confirm.html @@ -1,5 +1,5 @@ {% extends 'accounts/base.html' %} - +{% block title %} Phone number confirm {% endblock %} {% block content %}

Confirm your phone number

diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index 5c00bad..86a9301 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -1,5 +1,5 @@ {% extends 'accounts/base.html' %} - +{% block title %} Profile {% endblock %} {% block content %}

Profile

Phone number : {{ request.user.phone_number }}

From fb3638c79f2b1150645007eb9a0f13d2fbe95aad Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:51:43 +0430 Subject: [PATCH 170/439] Fix(accounts/views): fix login required decorator --- accounts/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index b51680f..5b34ef0 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,10 +1,10 @@ -from django.contrib.auth import authenticate, login, logout +from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import login_required from django.contrib.auth.hashers import make_password from django.urls import reverse_lazy from django.utils.decorators import method_decorator from django.views.decorators.http import require_http_methods -from django.views.generic import FormView, RedirectView, TemplateView +from django.views.generic import FormView, TemplateView from .forms import ServiceProviderRegistrationForm, ServiceProviderLoginForm @@ -35,6 +35,6 @@ def form_valid(self, form): return super().form_valid(form) -@method_decorator(login_required, name='dispatch') +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') class ServiceProviderProfileView(TemplateView): template_name = 'accounts/service_provider/profile.html' From fe2d723003ab7725a802a780dd1caf546fa3f828 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Sun, 29 Aug 2021 23:53:15 +0430 Subject: [PATCH 171/439] Style(accounts/templates): refactor templates --- .../accounts/service_provider/login.html | 14 ++++-------- .../accounts/service_provider/profile.html | 12 +++------- .../service_provider/registration.html | 22 +++++++------------ 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/accounts/templates/accounts/service_provider/login.html b/accounts/templates/accounts/service_provider/login.html index 5e62f51..3a9ada0 100644 --- a/accounts/templates/accounts/service_provider/login.html +++ b/accounts/templates/accounts/service_provider/login.html @@ -1,14 +1,8 @@ - - - - - Service Provider Login - - +{% extends 'accounts/base.html' %} +{% block content %} {% csrf_token %} {{ form.as_p }} - + - - \ No newline at end of file +{% endblock %} diff --git a/accounts/templates/accounts/service_provider/profile.html b/accounts/templates/accounts/service_provider/profile.html index 7e81dc6..b37989e 100644 --- a/accounts/templates/accounts/service_provider/profile.html +++ b/accounts/templates/accounts/service_provider/profile.html @@ -1,13 +1,7 @@ - - - - - Service Provider Profile - - +{% extends 'accounts/base.html' %} +{% block content %}

Your Profile

your username: {{ request.user.username }}

your email: {{ request.user.email }}

your phone number: {{ request.user.phone_number }}

- - \ No newline at end of file +{% endblock %} diff --git a/accounts/templates/accounts/service_provider/registration.html b/accounts/templates/accounts/service_provider/registration.html index a5a11af..3a9ada0 100644 --- a/accounts/templates/accounts/service_provider/registration.html +++ b/accounts/templates/accounts/service_provider/registration.html @@ -1,14 +1,8 @@ - - - - - Service Provider Registration - - -
- {% csrf_token %} - {{ form.as_p }} - -
- - \ No newline at end of file +{% extends 'accounts/base.html' %} +{% block content %} +
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} From 8fc76686e4ba08a97483965ef4234cf8f9e0c4b0 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 00:51:44 +0430 Subject: [PATCH 172/439] Update(accounts/views): add login_url for login_required decorator for customer views --- accounts/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 6bcc82a..2d5fd47 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -15,7 +15,7 @@ @method_decorator(require_http_methods(['GET']), name='dispatch') -@method_decorator(login_required, name='dispatch') +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') class ProfileView(TemplateView): template_name = 'accounts/customer/profile.html' @@ -102,7 +102,7 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') -@method_decorator(login_required, name='dispatch') +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') class CustomerSetPasswordView(UpdateView): model = Customer form_class = CustomerPasswordSetForm From 821e48fef18eec6ce381dcffe099e76e5aeae8c7 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 00:53:52 +0430 Subject: [PATCH 173/439] Update(accounts/templates): add messages in accounts/base.html --- accounts/templates/accounts/base.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/accounts/templates/accounts/base.html b/accounts/templates/accounts/base.html index 0dd635f..8a93e4f 100644 --- a/accounts/templates/accounts/base.html +++ b/accounts/templates/accounts/base.html @@ -14,6 +14,11 @@
+ {% if messages %} + {% for message in messages %} + + {% endfor %} + {% endif %} {% block content %} {% endblock %}
From 0559408b038da851c6cfae682cf73635303c68d5 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 00:56:04 +0430 Subject: [PATCH 174/439] Update(accounts/templates): add some styles for customer/profile.html --- accounts/templates/accounts/customer/profile.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index 86a9301..b683f5a 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -1,8 +1,11 @@ {% extends 'accounts/base.html' %} {% block title %} Profile {% endblock %} {% block content %} -

Profile

+

Profile

Phone number : {{ request.user.phone_number }}

+

First name : {{ request.user.first_name }}

+

Last name : {{ request.user.last_name }}

+ {% if not request.user.password %} Set password {% endif %} From 67ee63aceb2135df8a6c20915003ec38f8a66bc5 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 01:03:22 +0430 Subject: [PATCH 175/439] Add(accounts/utils): create check_is_not_authenticated function --- accounts/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/accounts/utils.py b/accounts/utils.py index 2c75cbb..c8411f4 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -21,3 +21,7 @@ def set_phone_number_session(request, phone_number): request.session['created_time'] = str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) print(request.session['code']) print(request.session['created_time']) + + +def check_is_not_authenticated(user): + return not user.is_authnticated From 28d05ce8174e435ab0b51dec11fa99c25e4fd6ef Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 01:12:28 +0430 Subject: [PATCH 176/439] Fix(accounts/utils): fix a typo in check_is_not_authenticated --- accounts/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/utils.py b/accounts/utils.py index c8411f4..d194fe3 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -24,4 +24,4 @@ def set_phone_number_session(request, phone_number): def check_is_not_authenticated(user): - return not user.is_authnticated + return not user.is_authenticated From 003c47c49d308009cfc21ecd3978fac574c04ecc Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 11:22:39 +0430 Subject: [PATCH 177/439] Update(accounts/urls): seprate customer and serviceprovider logout urls --- accounts/urls.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/accounts/urls.py b/accounts/urls.py index b458894..6f7c54f 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -13,10 +13,13 @@ path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='customer-password-confirm'), path('customer/profile/', ProfileView.as_view(), name='customer-profile'), path('customer//set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), + path('customer/logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:customer-login-register')), + name='customer-logout'), path( 'serviceprovider/registration/', ServiceProviderRegistrationView.as_view(), name='service-provider-registration' ), path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), path('serviceprovider/profile/', ServiceProviderProfileView.as_view(), name='service-provider-profile'), - path('logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:service-provider-login')), name='logout'), + path('serviceprovider/logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:service-provider-login')), + name='service-provider-logout'), ] From 047547f744c454311a1814c6a5b980bca793269a Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 11:28:43 +0430 Subject: [PATCH 178/439] Update(accounts/views): add user_test decorator for views --- accounts/views.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 2d5fd47..fada511 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_required, user_passes_test as user_test from django.shortcuts import redirect from django.urls import reverse_lazy from django.utils.decorators import method_decorator @@ -11,7 +11,7 @@ from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm, \ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm from accounts.models import Customer -from accounts.utils import check_expire_time, set_phone_number_session +from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated @method_decorator(require_http_methods(['GET']), name='dispatch') @@ -21,6 +21,7 @@ class ProfileView(TemplateView): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile'))) class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm template_name = 'accounts/customer/login_register.html' @@ -43,6 +44,7 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile'))) class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm template_name = 'accounts/customer/phone_number_confirm.html' @@ -81,6 +83,7 @@ def delete_confirm_code(self): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile'))) class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm template_name = 'accounts/customer/password_confirm.html' @@ -111,6 +114,7 @@ class CustomerSetPasswordView(UpdateView): @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile'))) class ServiceProviderRegistrationView(FormView): form_class = ServiceProviderRegistrationForm template_name = 'accounts/service_provider/registration.html' @@ -124,6 +128,7 @@ def form_valid(self, form): @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile'))) class ServiceProviderLoginView(FormView): form_class = ServiceProviderLoginForm template_name = 'accounts/service_provider/login.html' @@ -137,6 +142,7 @@ def form_valid(self, form): return super().form_valid(form) +@method_decorator(require_http_methods(['GET']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') class ServiceProviderProfileView(TemplateView): template_name = 'accounts/service_provider/profile.html' From 47fb0f08b3067ad85b4dffebf2ef160405edef4c Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 11:58:30 +0430 Subject: [PATCH 179/439] Update(accounts/urls): add customer profile update url --- accounts/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accounts/urls.py b/accounts/urls.py index 6f7c54f..8965ee8 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -3,7 +3,7 @@ from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView, \ ProfileView, CustomerSetPasswordView, ServiceProviderRegistrationView, ServiceProviderLoginView, \ - ServiceProviderProfileView + ServiceProviderProfileView, CustomerProfileUpdateView app_name = 'accounts' @@ -12,6 +12,7 @@ path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='customer-code-confirm'), path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='customer-password-confirm'), path('customer/profile/', ProfileView.as_view(), name='customer-profile'), + path('customer//profile-update/', CustomerProfileUpdateView, name='customer-profile-update'), path('customer//set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), path('customer/logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:customer-login-register')), name='customer-logout'), From ca990c066cde8ce520d353c2eb85e1da48da8263 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 12:01:53 +0430 Subject: [PATCH 180/439] Add(accounts/forms): add CustomerProfileUpdateForm class --- accounts/forms.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/accounts/forms.py b/accounts/forms.py index ba84545..e4e1ae1 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -80,6 +80,12 @@ def save(self, commit=True): return customer +class CustomerProfileUpdateForm(forms.ModelForm): + class Meta: + model = Customer + fields = ('first_name', 'last_name') + + class ServiceProviderRegistrationForm(forms.ModelForm): username = forms.CharField( max_length=30, From ec9185b5dc02f0991262374dd860272c2db54352 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 12:03:42 +0430 Subject: [PATCH 181/439] Add(address/urls): create address urls file --- address/urls.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 address/urls.py diff --git a/address/urls.py b/address/urls.py new file mode 100644 index 0000000..5fb9dab --- /dev/null +++ b/address/urls.py @@ -0,0 +1,6 @@ +from django.urls import path + +app_name = 'address' + +urlpatterns = [ +] From 2ab2c2e7d3e206c090a6f038a6c6797995704485 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 12:04:30 +0430 Subject: [PATCH 182/439] Update(urls): including address urls --- snapp_food/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/snapp_food/urls.py b/snapp_food/urls.py index 53acf68..785804f 100644 --- a/snapp_food/urls.py +++ b/snapp_food/urls.py @@ -19,4 +19,5 @@ urlpatterns = [ path('admin/', admin.site.urls), path('accounts/', include('accounts.urls', namespace='accounts')), + path('address/', include('address.urls', namespace='address')), ] From 796aa7ced7764c3182adc8df1f820a4bd4d3a2b4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 12:05:36 +0430 Subject: [PATCH 183/439] Add(accounts/views): add CustomerProfileUpdateView class --- accounts/views.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index fada511..3f7a1f9 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -9,7 +9,7 @@ from django.contrib.auth.hashers import make_password from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm, \ - CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm + CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated @@ -113,6 +113,15 @@ class CustomerSetPasswordView(UpdateView): template_name = 'accounts/customer/password_set.html' +@method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +class CustomerProfileUpdateView(UpdateView): + model = Customer + form_class = CustomerProfileUpdateForm + success_url = reverse_lazy('accounts:customer-profile') + template_name = None + + @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') @method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile'))) class ServiceProviderRegistrationView(FormView): From c88152b05927742ba6de7502ce285f90385aa766 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 12:07:36 +0430 Subject: [PATCH 184/439] Style(address/templates): create address templates --- address/templates/address/create.html | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 address/templates/address/create.html diff --git a/address/templates/address/create.html b/address/templates/address/create.html new file mode 100644 index 0000000..566549b --- /dev/null +++ b/address/templates/address/create.html @@ -0,0 +1,10 @@ + + + + + Title + + + + + \ No newline at end of file From bb299f8f8a3dba7a3817122dffaacbb06d026819 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 12:40:50 +0430 Subject: [PATCH 185/439] Fix(address/models): create new address class --- address/models.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/address/models.py b/address/models.py index 062cf9a..86f402c 100644 --- a/address/models.py +++ b/address/models.py @@ -1,4 +1,6 @@ from django.db import models + +from accounts.models import Customer from library.models import BaseModel from django.utils.translation import ugettext_lazy as _ @@ -44,17 +46,35 @@ class Meta: db_table = 'area' -class Address(BaseModel): +class BaseAddress(BaseModel): state = models.ForeignKey(State, verbose_name=_('state'), related_name='addresses', on_delete=models.CASCADE) city = models.ForeignKey(City, verbose_name=_('city'), related_name='addresses', on_delete=models.CASCADE) area = models.ForeignKey(Area, verbose_name=_('area'), related_name='addresses', on_delete=models.CASCADE) floor = models.SmallIntegerField(verbose_name=_('floor')) plaque = models.SmallIntegerField(verbose_name=_('plaque')) + class Meta: + abstract = True + + +class CustomerAddress(BaseAddress): + user = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='addresses', on_delete=models.CASCADE) + + def __str__(self): + return f'{self.user} - {self.city} - {self.area}' + + class Meta: + verbose_name = _('CustomerAddress') + verbose_name_plural = _('CustomerAddresses') + db_table = 'customer_address' + + +class ServiceAddress(BaseAddress): + def __str__(self): - return f'{self.area} - {self.floor} - {self.plaque}' + return f'{self.city} - {self.area}' class Meta: - verbose_name = _('Address') - verbose_name_plural = _('Addresses') - db_table = 'address' + verbose_name = _('ServiceAddress') + verbose_name_plural = _('ServiceAddresses') + db_table = 'service_address' From 243ddf8f20064a67c209df0715a713c8da9b5cc1 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 12:51:11 +0430 Subject: [PATCH 186/439] Add(accounts/utils): add check_user_pk function --- accounts/utils.py | 34 ++++++++++++++++++++++++++++++++++ accounts/views.py | 19 ++++++++++++------- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/accounts/utils.py b/accounts/utils.py index d194fe3..b85523f 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -1,5 +1,11 @@ from datetime import datetime, timedelta +from functools import wraps from random import randint +from urllib.parse import urlparse + +from django.conf import settings +from django.contrib.auth import REDIRECT_FIELD_NAME +from django.shortcuts import resolve_url def check_expire_time(request): @@ -23,5 +29,33 @@ def set_phone_number_session(request, phone_number): print(request.session['created_time']) +def user_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): + def decorator(view_func): + @wraps(view_func) + def _wrapped_view(request, *args, **kwargs): + if test_func(request.user, *args, **kwargs): + return view_func(request, *args, **kwargs) + path = request.build_absolute_uri() + resolved_login_url = resolve_url(login_url or settings.LOGIN_URL) + # If the login url is the same scheme and net location then just + # use the path as the "next" url. + login_scheme, login_netloc = urlparse(resolved_login_url)[:2] + current_scheme, current_netloc = urlparse(path)[:2] + if ((not login_scheme or login_scheme == current_scheme) and + (not login_netloc or login_netloc == current_netloc)): + path = request.get_full_path() + from django.contrib.auth.views import redirect_to_login + return redirect_to_login( + path, resolved_login_url, redirect_field_name) + + return _wrapped_view + + return decorator + + def check_is_not_authenticated(user): return not user.is_authenticated + + +def check_user_pk(user, **kwargs): + return user.pk == kwargs['pk'] diff --git a/accounts/views.py b/accounts/views.py index 3f7a1f9..cb9a174 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required, user_passes_test as user_test +from django.contrib.auth.decorators import login_required from django.shortcuts import redirect from django.urls import reverse_lazy from django.utils.decorators import method_decorator @@ -11,7 +11,7 @@ from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm, \ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer -from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated +from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, user_test @method_decorator(require_http_methods(['GET']), name='dispatch') @@ -21,7 +21,8 @@ class ProfileView(TemplateView): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') -@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile'))) +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile')), + name='dispatch') class CustomerLoginRegisterView(FormView): form_class = CustomerLoginRegisterForm template_name = 'accounts/customer/login_register.html' @@ -44,7 +45,8 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') -@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile'))) +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile')), + name='dispatch') class CustomerPhoneNumberConfirmView(FormView): form_class = CustomerCodeConfirmForm template_name = 'accounts/customer/phone_number_confirm.html' @@ -83,7 +85,8 @@ def delete_confirm_code(self): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') -@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile'))) +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:customer-profile')), + name='dispatch') class CustomerPasswordConfirmView(FormView): form_class = CustomerPasswordForm template_name = 'accounts/customer/password_confirm.html' @@ -123,7 +126,8 @@ class CustomerProfileUpdateView(UpdateView): @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') -@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile'))) +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile')), + name='dispatch') class ServiceProviderRegistrationView(FormView): form_class = ServiceProviderRegistrationForm template_name = 'accounts/service_provider/registration.html' @@ -137,7 +141,8 @@ def form_valid(self, form): @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') -@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile'))) +@method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile')), + name='dispatch') class ServiceProviderLoginView(FormView): form_class = ServiceProviderLoginForm template_name = 'accounts/service_provider/login.html' From 9c5dac46d5e7b99949ac69e499dc4317c840140b Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 12:58:03 +0430 Subject: [PATCH 187/439] Add(accounts/utils): add can_set_password function --- accounts/utils.py | 4 ++++ accounts/views.py | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/accounts/utils.py b/accounts/utils.py index b85523f..427ec8d 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -57,5 +57,9 @@ def check_is_not_authenticated(user): return not user.is_authenticated +def can_set_password(user, **kwargs): + return user.pk == kwargs['pk'] and not user.password + + def check_user_pk(user, **kwargs): return user.pk == kwargs['pk'] diff --git a/accounts/views.py b/accounts/views.py index cb9a174..890126f 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -11,7 +11,8 @@ from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm, \ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer -from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, user_test +from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, user_test, \ + can_set_password @method_decorator(require_http_methods(['GET']), name='dispatch') @@ -109,6 +110,7 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +@method_decorator(user_test(can_set_password, login_url=reverse_lazy('accounts:customer-profile')), name='dispatch') class CustomerSetPasswordView(UpdateView): model = Customer form_class = CustomerPasswordSetForm From 2a4520927a7b32c019d892d6ba223c823f7f530b Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:03:29 +0430 Subject: [PATCH 188/439] Add(address/forms): create address forms --- address/forms.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 address/forms.py diff --git a/address/forms.py b/address/forms.py new file mode 100644 index 0000000..e69de29 From a423f639bab4d58ed418b7b11e00ce03a6238c25 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:04:39 +0430 Subject: [PATCH 189/439] Fix(models, admins): fix relations to address model and edit admin and models --- address/admin.py | 11 +++++++++-- address/models.py | 23 +++++++++++------------ payment/models.py | 4 ++-- service/models.py | 4 ++-- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/address/admin.py b/address/admin.py index fe22121..d5ca293 100644 --- a/address/admin.py +++ b/address/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import State, City, Area, Address +from .models import State, City, Area, ServiceAddress, CustomerAddress @admin.register(State) @@ -22,8 +22,15 @@ class AreaAdmin(admin.ModelAdmin): search_fields = ('name',) -@admin.register(Address) +@admin.register(ServiceAddress) class AddressAdmin(admin.ModelAdmin): list_display = ('state', 'city', 'area', 'floor', 'plaque') list_filter = ('state', 'city') search_fields = ('area', 'floor', 'plaque') + + +@admin.register(CustomerAddress) +class AddressAdmin(admin.ModelAdmin): + list_display = ('user', 'state', 'city', 'area', 'floor', 'plaque') + list_filter = ('state', 'city') + search_fields = ('area', 'floor', 'plaque') diff --git a/address/models.py b/address/models.py index 86f402c..aedea93 100644 --- a/address/models.py +++ b/address/models.py @@ -46,20 +46,14 @@ class Meta: db_table = 'area' -class BaseAddress(BaseModel): - state = models.ForeignKey(State, verbose_name=_('state'), related_name='addresses', on_delete=models.CASCADE) - city = models.ForeignKey(City, verbose_name=_('city'), related_name='addresses', on_delete=models.CASCADE) - area = models.ForeignKey(Area, verbose_name=_('area'), related_name='addresses', on_delete=models.CASCADE) +class CustomerAddress(BaseModel): + user = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='c_addresses', on_delete=models.CASCADE) + state = models.ForeignKey(State, verbose_name=_('state'), related_name='c_addresses', on_delete=models.CASCADE) + city = models.ForeignKey(City, verbose_name=_('city'), related_name='c_addresses', on_delete=models.CASCADE) + area = models.ForeignKey(Area, verbose_name=_('area'), related_name='c_addresses', on_delete=models.CASCADE) floor = models.SmallIntegerField(verbose_name=_('floor')) plaque = models.SmallIntegerField(verbose_name=_('plaque')) - class Meta: - abstract = True - - -class CustomerAddress(BaseAddress): - user = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='addresses', on_delete=models.CASCADE) - def __str__(self): return f'{self.user} - {self.city} - {self.area}' @@ -69,7 +63,12 @@ class Meta: db_table = 'customer_address' -class ServiceAddress(BaseAddress): +class ServiceAddress(BaseModel): + state = models.ForeignKey(State, verbose_name=_('state'), related_name='s_addresses', on_delete=models.CASCADE) + city = models.ForeignKey(City, verbose_name=_('city'), related_name='s_addresses', on_delete=models.CASCADE) + area = models.ForeignKey(Area, verbose_name=_('area'), related_name='s_addresses', on_delete=models.CASCADE) + floor = models.SmallIntegerField(verbose_name=_('floor')) + plaque = models.SmallIntegerField(verbose_name=_('plaque')) def __str__(self): return f'{self.city} - {self.area}' diff --git a/payment/models.py b/payment/models.py index e1ba1e1..028a8d1 100644 --- a/payment/models.py +++ b/payment/models.py @@ -1,7 +1,7 @@ from django.db import models from django.utils.translation import gettext as _ from accounts.models import Customer -from address.models import Address +from address.models import CustomerAddress from library.models import BaseModel import uuid @@ -11,7 +11,7 @@ class Invoice(BaseModel): on_delete=models.SET_NULL, null=True) price = models.IntegerField(verbose_name=_('price')) is_paid = models.BooleanField(verbose_name=_('is paid'), default=False) - address = models.ForeignKey(Address, verbose_name=_('address'), related_name='invoices', on_delete=models.SET_NULL, + address = models.ForeignKey(CustomerAddress, verbose_name=_('address'), related_name='invoices', on_delete=models.SET_NULL, null=True, blank=True) class Meta: diff --git a/service/models.py b/service/models.py index d8b57ed..351643c 100644 --- a/service/models.py +++ b/service/models.py @@ -3,7 +3,7 @@ from accounts.models import ServiceProvider from library.models import BaseModel from django.utils.translation import ugettext_lazy as _ -from address.models import Address, Area +from address.models import ServiceAddress, Area import uuid @@ -27,7 +27,7 @@ class Service(BaseModel): name = models.CharField(max_length=40, verbose_name=_('name')) service_type = models.PositiveSmallIntegerField(verbose_name=_('service type'), choices=SERVICE_TYPES) minimum_purchase = models.DecimalField(max_digits=9, decimal_places=0, verbose_name=_('minimum purchase')) - address = models.ForeignKey(Address, verbose_name=_('address'), related_name='services', on_delete=models.SET_NULL, + address = models.ForeignKey(ServiceAddress, verbose_name=_('address'), related_name='services', on_delete=models.SET_NULL, null=True) def __str__(self): From e79ce5aff38df45f4836e304513261d3e178c888 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 13:15:10 +0430 Subject: [PATCH 190/439] Update(accounts/views, templates): add prfoile-update template --- .../templates/accounts/customer/profile.html | 3 +++ .../accounts/customer/profile_update.html | 22 +++++++++++++++++++ accounts/urls.py | 2 +- accounts/views.py | 5 +++-- 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 accounts/templates/accounts/customer/profile_update.html diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index b683f5a..8812e5b 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -5,8 +5,11 @@

Profile

Phone number : {{ request.user.phone_number }}

First name : {{ request.user.first_name }}

Last name : {{ request.user.last_name }}

+
+ Update profile {% if not request.user.password %} +
Set password {% endif %} {% endblock %} \ No newline at end of file diff --git a/accounts/templates/accounts/customer/profile_update.html b/accounts/templates/accounts/customer/profile_update.html new file mode 100644 index 0000000..2130587 --- /dev/null +++ b/accounts/templates/accounts/customer/profile_update.html @@ -0,0 +1,22 @@ +{% extends 'accounts/base.html' %} +{% block title %} Profile Update {% endblock %} +{% block content %} +

Update your pfoile

+
+ {% csrf_token %} + {% for field in form %} + +
+

{{ field }}

+ {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% if form.errors %} + {% block form_error %} {% endblock %} + {% endif %} + + +
+{% endblock %} \ No newline at end of file diff --git a/accounts/urls.py b/accounts/urls.py index 8965ee8..5f079dc 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -12,7 +12,7 @@ path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='customer-code-confirm'), path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='customer-password-confirm'), path('customer/profile/', ProfileView.as_view(), name='customer-profile'), - path('customer//profile-update/', CustomerProfileUpdateView, name='customer-profile-update'), + path('customer//profile-update/', CustomerProfileUpdateView.as_view(), name='customer-profile-update'), path('customer//set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), path('customer/logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:customer-login-register')), name='customer-logout'), diff --git a/accounts/views.py b/accounts/views.py index 890126f..0ed8bb3 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -12,7 +12,7 @@ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, user_test, \ - can_set_password + can_set_password, check_user_pk @method_decorator(require_http_methods(['GET']), name='dispatch') @@ -120,11 +120,12 @@ class CustomerSetPasswordView(UpdateView): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +@method_decorator(user_test(check_user_pk, login_url=reverse_lazy('accounts:customer-profile')), name='dispatch') class CustomerProfileUpdateView(UpdateView): model = Customer form_class = CustomerProfileUpdateForm success_url = reverse_lazy('accounts:customer-profile') - template_name = None + template_name = 'accounts/customer/profile_update.html' @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') From 254c2c4ab37656cae8881cc46b2f187172c845f9 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:20:24 +0430 Subject: [PATCH 191/439] Update(address/models): update models fields --- address/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/address/models.py b/address/models.py index aedea93..71d9a58 100644 --- a/address/models.py +++ b/address/models.py @@ -51,6 +51,8 @@ class CustomerAddress(BaseModel): state = models.ForeignKey(State, verbose_name=_('state'), related_name='c_addresses', on_delete=models.CASCADE) city = models.ForeignKey(City, verbose_name=_('city'), related_name='c_addresses', on_delete=models.CASCADE) area = models.ForeignKey(Area, verbose_name=_('area'), related_name='c_addresses', on_delete=models.CASCADE) + street = models.TextField() + alley = models.TextField() floor = models.SmallIntegerField(verbose_name=_('floor')) plaque = models.SmallIntegerField(verbose_name=_('plaque')) @@ -67,6 +69,8 @@ class ServiceAddress(BaseModel): state = models.ForeignKey(State, verbose_name=_('state'), related_name='s_addresses', on_delete=models.CASCADE) city = models.ForeignKey(City, verbose_name=_('city'), related_name='s_addresses', on_delete=models.CASCADE) area = models.ForeignKey(Area, verbose_name=_('area'), related_name='s_addresses', on_delete=models.CASCADE) + street = models.TextField() + alley = models.TextField() floor = models.SmallIntegerField(verbose_name=_('floor')) plaque = models.SmallIntegerField(verbose_name=_('plaque')) From c3253f7cd3e1185bb0de737afe27c78e3aac356e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 13:23:32 +0430 Subject: [PATCH 192/439] Update(accounts/templates/customers): add logout button in profile page --- accounts/templates/accounts/customer/profile.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index 8812e5b..acb60b9 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -6,10 +6,13 @@

Profile

First name : {{ request.user.first_name }}

Last name : {{ request.user.last_name }}


- Update profile + Update profile

{% if not request.user.password %}
Set password +
{% endif %} + Logout + {% endblock %} \ No newline at end of file From 48d519a01bb2864ffd2262d5b0412e1fd7b4a4a2 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 13:32:15 +0430 Subject: [PATCH 193/439] Add(accounts/views, urls, templates): add change password functionality --- .../accounts/customer/change_password.html | 22 +++++++++++++++++++ .../templates/accounts/customer/profile.html | 4 +++- accounts/urls.py | 3 ++- accounts/views.py | 8 +++++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 accounts/templates/accounts/customer/change_password.html diff --git a/accounts/templates/accounts/customer/change_password.html b/accounts/templates/accounts/customer/change_password.html new file mode 100644 index 0000000..5c71871 --- /dev/null +++ b/accounts/templates/accounts/customer/change_password.html @@ -0,0 +1,22 @@ +{% extends 'accounts/base.html' %} +{% block title %} Change Password {% endblock %} +{% block content %} +

Change your password

+
+ {% csrf_token %} + {% for field in form %} + +
+

{{ field }}

+ {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% if form.errors %} + {% block form_error %} {% endblock %} + {% endif %} + + +
+{% endblock %} \ No newline at end of file diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index acb60b9..ce665fe 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -11,7 +11,9 @@

Profile

{% if not request.user.password %}
Set password -
+ {% else %} + Change password +

{% endif %} Logout diff --git a/accounts/urls.py b/accounts/urls.py index 5f079dc..05b355a 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -3,7 +3,7 @@ from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView, \ ProfileView, CustomerSetPasswordView, ServiceProviderRegistrationView, ServiceProviderLoginView, \ - ServiceProviderProfileView, CustomerProfileUpdateView + ServiceProviderProfileView, CustomerProfileUpdateView, CustomerChangePasswordView app_name = 'accounts' @@ -14,6 +14,7 @@ path('customer/profile/', ProfileView.as_view(), name='customer-profile'), path('customer//profile-update/', CustomerProfileUpdateView.as_view(), name='customer-profile-update'), path('customer//set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), + path('customer/change-password/', CustomerChangePasswordView.as_view(), name='customer-change-password'), path('customer/logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:customer-login-register')), name='customer-logout'), path( diff --git a/accounts/views.py b/accounts/views.py index 0ed8bb3..a71d418 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,5 +1,6 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.contrib.auth.views import PasswordChangeView from django.shortcuts import redirect from django.urls import reverse_lazy from django.utils.decorators import method_decorator @@ -128,6 +129,13 @@ class CustomerProfileUpdateView(UpdateView): template_name = 'accounts/customer/profile_update.html' +@method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +class CustomerChangePasswordView(PasswordChangeView): + template_name = 'accounts/customer/change_password.html' + success_url = reverse_lazy('accounts:customer-profile') + + @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') @method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile')), name='dispatch') From 6004c4545404b3942e8337b304196e4cab13f052 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:45:48 +0430 Subject: [PATCH 194/439] Add(address/forms): create customer address create form --- address/forms.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/address/forms.py b/address/forms.py index e69de29..09bc09e 100644 --- a/address/forms.py +++ b/address/forms.py @@ -0,0 +1,18 @@ +from django import forms + +from address.models import CustomerAddress + + +class CustomerAddressCreateForm(forms.ModelForm): + class Meta: + model = CustomerAddress + fields = ('state', 'city', 'area', 'street', 'alley', 'floor', 'plaque') + widgets = { + 'state': forms.Select(attrs={'class': 'form-control'}), + 'city': forms.Select(attrs={'class': 'form-control'}), + 'area': forms.Select(attrs={'class': 'form-control'}), + 'street': forms.TextInput(attrs={'class': 'form-control'}), + 'alley': forms.TextInput(attrs={'class': 'form-control'}), + 'floor': forms.NumberInput(attrs={'class': 'form-control'}), + 'plaque': forms.NumberInput(attrs={'class': 'form-control'}), + } From 40bf5c70bf426baf62b669adff6c6b86b614d227 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:46:43 +0430 Subject: [PATCH 195/439] Add(address/views): create customer address create view --- address/views.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/address/views.py b/address/views.py index 91ea44a..a76e582 100644 --- a/address/views.py +++ b/address/views.py @@ -1,3 +1,18 @@ -from django.shortcuts import render +from django.urls import reverse_lazy +from django.views.generic import CreateView -# Create your views here. +from address.forms import CustomerAddressCreateForm +from address.models import CustomerAddress + + +class CustomerAddressCreateView(CreateView): + model = CustomerAddress + form_class = CustomerAddressCreateForm + template_name = 'address/create.html' + success_url = reverse_lazy('accounts:customer-profile') + + def form_valid(self, form): + instance = form.save(commit=False) + instance.user = self.request.user + instance.save() + return super().form_valid(form) From 2ff964105018ea8b714f55792fad9bd808ed576d Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:47:22 +0430 Subject: [PATCH 196/439] Add(address/urls): create customer address url --- address/urls.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/address/urls.py b/address/urls.py index 5fb9dab..bc78aa8 100644 --- a/address/urls.py +++ b/address/urls.py @@ -1,6 +1,9 @@ from django.urls import path +from .views import CustomerAddressCreateView + app_name = 'address' urlpatterns = [ + path('customer/create', CustomerAddressCreateView.as_view(), name='customer-address-create') ] From a4798e7480d2f1dd715ca548981d0c4bef2f7d75 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:48:12 +0430 Subject: [PATCH 197/439] Update(address/models): add fields in all address models and refactor code --- address/models.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/address/models.py b/address/models.py index 71d9a58..aa676c3 100644 --- a/address/models.py +++ b/address/models.py @@ -46,15 +46,21 @@ class Meta: db_table = 'area' -class CustomerAddress(BaseModel): +class BaseAddress(BaseModel): + street = models.CharField(max_length=50) + alley = models.CharField(max_length=30) + floor = models.SmallIntegerField(verbose_name=_('floor')) + plaque = models.SmallIntegerField(verbose_name=_('plaque')) + + class Meta: + abstract = True + + +class CustomerAddress(BaseAddress): user = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='c_addresses', on_delete=models.CASCADE) state = models.ForeignKey(State, verbose_name=_('state'), related_name='c_addresses', on_delete=models.CASCADE) city = models.ForeignKey(City, verbose_name=_('city'), related_name='c_addresses', on_delete=models.CASCADE) area = models.ForeignKey(Area, verbose_name=_('area'), related_name='c_addresses', on_delete=models.CASCADE) - street = models.TextField() - alley = models.TextField() - floor = models.SmallIntegerField(verbose_name=_('floor')) - plaque = models.SmallIntegerField(verbose_name=_('plaque')) def __str__(self): return f'{self.user} - {self.city} - {self.area}' @@ -65,14 +71,10 @@ class Meta: db_table = 'customer_address' -class ServiceAddress(BaseModel): +class ServiceAddress(BaseAddress): state = models.ForeignKey(State, verbose_name=_('state'), related_name='s_addresses', on_delete=models.CASCADE) city = models.ForeignKey(City, verbose_name=_('city'), related_name='s_addresses', on_delete=models.CASCADE) area = models.ForeignKey(Area, verbose_name=_('area'), related_name='s_addresses', on_delete=models.CASCADE) - street = models.TextField() - alley = models.TextField() - floor = models.SmallIntegerField(verbose_name=_('floor')) - plaque = models.SmallIntegerField(verbose_name=_('plaque')) def __str__(self): return f'{self.city} - {self.area}' From bd78b64627c11f18a4b5494434b3488109ef20b4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 13:48:23 +0430 Subject: [PATCH 198/439] Add(accounts/views, urls, templates): add change password functionality for serviceprovider --- accounts/templates/accounts/customer/profile.html | 1 + .../accounts/service_provider/change_password.html | 9 +++++++++ .../templates/accounts/service_provider/profile.html | 2 ++ accounts/urls.py | 4 +++- accounts/views.py | 7 +++++++ 5 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 accounts/templates/accounts/service_provider/change_password.html diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index ce665fe..6afe8ce 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -11,6 +11,7 @@

Profile

{% if not request.user.password %}
Set password +

{% else %} Change password

diff --git a/accounts/templates/accounts/service_provider/change_password.html b/accounts/templates/accounts/service_provider/change_password.html new file mode 100644 index 0000000..2589839 --- /dev/null +++ b/accounts/templates/accounts/service_provider/change_password.html @@ -0,0 +1,9 @@ +{% extends 'accounts/base.html' %} +{% block content %} +

Change your password

+
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} \ No newline at end of file diff --git a/accounts/templates/accounts/service_provider/profile.html b/accounts/templates/accounts/service_provider/profile.html index b37989e..f59923b 100644 --- a/accounts/templates/accounts/service_provider/profile.html +++ b/accounts/templates/accounts/service_provider/profile.html @@ -4,4 +4,6 @@

Your Profile

your username: {{ request.user.username }}

your email: {{ request.user.email }}

your phone number: {{ request.user.phone_number }}

+

+ Change password {% endblock %} diff --git a/accounts/urls.py b/accounts/urls.py index 05b355a..3b6b467 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -3,7 +3,7 @@ from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView, \ ProfileView, CustomerSetPasswordView, ServiceProviderRegistrationView, ServiceProviderLoginView, \ - ServiceProviderProfileView, CustomerProfileUpdateView, CustomerChangePasswordView + ServiceProviderProfileView, CustomerProfileUpdateView, CustomerChangePasswordView, ServiceProviderChangePasswordView app_name = 'accounts' @@ -22,6 +22,8 @@ ), path('serviceprovider/login/', ServiceProviderLoginView.as_view(), name='service-provider-login'), path('serviceprovider/profile/', ServiceProviderProfileView.as_view(), name='service-provider-profile'), + path('serviceprovider/change-password/', ServiceProviderChangePasswordView.as_view(), + name='service-provider-change-password'), path('serviceprovider/logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:service-provider-login')), name='service-provider-logout'), ] diff --git a/accounts/views.py b/accounts/views.py index a71d418..4b680c8 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -171,3 +171,10 @@ def form_valid(self, form): @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') class ServiceProviderProfileView(TemplateView): template_name = 'accounts/service_provider/profile.html' + + +@method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +class ServiceProviderChangePasswordView(PasswordChangeView): + template_name = 'accounts/service_provider/change_password.html' + success_url = reverse_lazy('accounts:service-provider-profile') From 78e45c624bb78078eee907da3cbada1c20924775 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:48:52 +0430 Subject: [PATCH 199/439] Style(address/templates): update address templates --- address/templates/address/base.html | 22 ++++++++++++++++++++++ address/templates/address/create.html | 18 ++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 address/templates/address/base.html diff --git a/address/templates/address/base.html b/address/templates/address/base.html new file mode 100644 index 0000000..0dd635f --- /dev/null +++ b/address/templates/address/base.html @@ -0,0 +1,22 @@ + + + + + + + + + + {% block title %} {% endblock %} + + +
+ {% block content %} + {% endblock %} +
+ + + \ No newline at end of file diff --git a/address/templates/address/create.html b/address/templates/address/create.html index 566549b..0b64d4f 100644 --- a/address/templates/address/create.html +++ b/address/templates/address/create.html @@ -1,10 +1,8 @@ - - - - - Title - - - - - \ No newline at end of file +{% extends 'address/base.html' %} +{% block content %} +
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} From ee1b3c8a5ad4c55096d44fb26c8f27774404d504 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 13:49:45 +0430 Subject: [PATCH 200/439] Migrations(address, peyment, service): create new migrations for address models and peyment and service --- address/migrations/0002_auto_20210830_1305.py | 55 +++++++++++++++++++ address/migrations/0003_auto_20210830_1305.py | 55 +++++++++++++++++++ address/migrations/0004_auto_20210830_1327.py | 33 +++++++++++ address/migrations/0005_auto_20210830_1329.py | 33 +++++++++++ .../migrations/0002_alter_invoice_address.py | 20 +++++++ .../migrations/0002_alter_service_address.py | 20 +++++++ 6 files changed, 216 insertions(+) create mode 100644 address/migrations/0002_auto_20210830_1305.py create mode 100644 address/migrations/0003_auto_20210830_1305.py create mode 100644 address/migrations/0004_auto_20210830_1327.py create mode 100644 address/migrations/0005_auto_20210830_1329.py create mode 100644 payment/migrations/0002_alter_invoice_address.py create mode 100644 service/migrations/0002_alter_service_address.py diff --git a/address/migrations/0002_auto_20210830_1305.py b/address/migrations/0002_auto_20210830_1305.py new file mode 100644 index 0000000..7350549 --- /dev/null +++ b/address/migrations/0002_auto_20210830_1305.py @@ -0,0 +1,55 @@ +# Generated by Django 3.2 on 2021-08-30 08:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='CustomerAddress', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('floor', models.SmallIntegerField(verbose_name='floor')), + ('plaque', models.SmallIntegerField(verbose_name='plaque')), + ], + options={ + 'verbose_name': 'CustomerAddress', + 'verbose_name_plural': 'CustomerAddresses', + 'db_table': 'customer_address', + }, + ), + migrations.CreateModel( + name='ServiceAddress', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='created time')), + ('modified_time', models.DateTimeField(auto_now=True, verbose_name='modified time')), + ('floor', models.SmallIntegerField(verbose_name='floor')), + ('plaque', models.SmallIntegerField(verbose_name='plaque')), + ], + options={ + 'verbose_name': 'ServiceAddress', + 'verbose_name_plural': 'ServiceAddresses', + 'db_table': 'service_address', + }, + ), + migrations.RemoveField( + model_name='address', + name='area', + ), + migrations.RemoveField( + model_name='address', + name='city', + ), + migrations.RemoveField( + model_name='address', + name='state', + ), + ] diff --git a/address/migrations/0003_auto_20210830_1305.py b/address/migrations/0003_auto_20210830_1305.py new file mode 100644 index 0000000..b2a0ccc --- /dev/null +++ b/address/migrations/0003_auto_20210830_1305.py @@ -0,0 +1,55 @@ +# Generated by Django 3.2 on 2021-08-30 08:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('service', '0002_alter_service_address'), + ('address', '0002_auto_20210830_1305'), + ('accounts', '0001_initial'), + ('payment', '0002_alter_invoice_address'), + ] + + operations = [ + migrations.DeleteModel( + name='Address', + ), + migrations.AddField( + model_name='serviceaddress', + name='area', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='s_addresses', to='address.area', verbose_name='area'), + ), + migrations.AddField( + model_name='serviceaddress', + name='city', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='s_addresses', to='address.city', verbose_name='city'), + ), + migrations.AddField( + model_name='serviceaddress', + name='state', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='s_addresses', to='address.state', verbose_name='state'), + ), + migrations.AddField( + model_name='customeraddress', + name='area', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='c_addresses', to='address.area', verbose_name='area'), + ), + migrations.AddField( + model_name='customeraddress', + name='city', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='c_addresses', to='address.city', verbose_name='city'), + ), + migrations.AddField( + model_name='customeraddress', + name='state', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='c_addresses', to='address.state', verbose_name='state'), + ), + migrations.AddField( + model_name='customeraddress', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='c_addresses', to='accounts.customer', verbose_name='customer'), + ), + ] diff --git a/address/migrations/0004_auto_20210830_1327.py b/address/migrations/0004_auto_20210830_1327.py new file mode 100644 index 0000000..6577812 --- /dev/null +++ b/address/migrations/0004_auto_20210830_1327.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2 on 2021-08-30 08:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0003_auto_20210830_1305'), + ] + + operations = [ + migrations.AddField( + model_name='customeraddress', + name='alley', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='customeraddress', + name='street', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='serviceaddress', + name='alley', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='serviceaddress', + name='street', + field=models.TextField(blank=True), + ), + ] diff --git a/address/migrations/0005_auto_20210830_1329.py b/address/migrations/0005_auto_20210830_1329.py new file mode 100644 index 0000000..dc9e112 --- /dev/null +++ b/address/migrations/0005_auto_20210830_1329.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2 on 2021-08-30 08:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0004_auto_20210830_1327'), + ] + + operations = [ + migrations.AlterField( + model_name='customeraddress', + name='alley', + field=models.CharField(max_length=30), + ), + migrations.AlterField( + model_name='customeraddress', + name='street', + field=models.CharField(max_length=50), + ), + migrations.AlterField( + model_name='serviceaddress', + name='alley', + field=models.CharField(max_length=30), + ), + migrations.AlterField( + model_name='serviceaddress', + name='street', + field=models.CharField(max_length=50), + ), + ] diff --git a/payment/migrations/0002_alter_invoice_address.py b/payment/migrations/0002_alter_invoice_address.py new file mode 100644 index 0000000..09765ea --- /dev/null +++ b/payment/migrations/0002_alter_invoice_address.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2 on 2021-08-30 08:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0002_auto_20210830_1305'), + ('payment', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='invoice', + name='address', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoices', to='address.customeraddress', verbose_name='address'), + ), + ] diff --git a/service/migrations/0002_alter_service_address.py b/service/migrations/0002_alter_service_address.py new file mode 100644 index 0000000..d26148c --- /dev/null +++ b/service/migrations/0002_alter_service_address.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2 on 2021-08-30 08:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0002_auto_20210830_1305'), + ('service', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='address', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='services', to='address.serviceaddress', verbose_name='address'), + ), + ] From 8f2e1fc004db234c332e237b944067ec6067b8e4 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 16:38:00 +0430 Subject: [PATCH 201/439] Add(accocunts/utils): add is_customer, is_service_provider functions --- accounts/utils.py | 11 +++++++++++ accounts/views.py | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/accounts/utils.py b/accounts/utils.py index 427ec8d..2a6b61d 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -7,6 +7,8 @@ from django.contrib.auth import REDIRECT_FIELD_NAME from django.shortcuts import resolve_url +from accounts.models import Customer, ServiceProvider + def check_expire_time(request): try: @@ -53,6 +55,7 @@ def _wrapped_view(request, *args, **kwargs): return decorator +# TODO: raise 403 in user_tests_functions def check_is_not_authenticated(user): return not user.is_authenticated @@ -63,3 +66,11 @@ def can_set_password(user, **kwargs): def check_user_pk(user, **kwargs): return user.pk == kwargs['pk'] + + +def is_customer(user): + return isinstance(user, Customer) + + +def is_service_provider(user): + return isinstance(user, ServiceProvider) diff --git a/accounts/views.py b/accounts/views.py index 4b680c8..0570757 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -13,11 +13,12 @@ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, user_test, \ - can_set_password, check_user_pk + can_set_password, check_user_pk, is_customer @method_decorator(require_http_methods(['GET']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +@method_decorator(user_test(is_customer), name='dispatch') class ProfileView(TemplateView): template_name = 'accounts/customer/profile.html' From 0602b834166ba273667f3554b86f50fa164c1777 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 17:41:40 +0430 Subject: [PATCH 202/439] Fix(address/models): update the str method --- address/models.py | 2 +- .../templates/address/{create.html => create_update_form.html} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename address/templates/address/{create.html => create_update_form.html} (100%) diff --git a/address/models.py b/address/models.py index aa676c3..8f40f7e 100644 --- a/address/models.py +++ b/address/models.py @@ -38,7 +38,7 @@ class Area(BaseModel): city = models.ForeignKey(City, verbose_name=_('city'), related_name='areas', on_delete=models.CASCADE) def __str__(self): - return f'{self.city.name} - {self.name})' + return f'{self.city.name} - {self.name}' class Meta: verbose_name = _('Area') diff --git a/address/templates/address/create.html b/address/templates/address/create_update_form.html similarity index 100% rename from address/templates/address/create.html rename to address/templates/address/create_update_form.html From d49eefa4a8684ba75b4576c5c10f70aad96103cb Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 17:46:30 +0430 Subject: [PATCH 203/439] Update(address/forms): update fields and widget address create or update form --- address/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/address/forms.py b/address/forms.py index 09bc09e..a41acee 100644 --- a/address/forms.py +++ b/address/forms.py @@ -3,7 +3,7 @@ from address.models import CustomerAddress -class CustomerAddressCreateForm(forms.ModelForm): +class CustomerAddressCreateUpdateForm(forms.ModelForm): class Meta: model = CustomerAddress fields = ('state', 'city', 'area', 'street', 'alley', 'floor', 'plaque') From baa206e897f358da10fd1c1ed4b5c7ca840e2749 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 17:48:16 +0430 Subject: [PATCH 204/439] Add(address/views): create a delete and update view and refactor address create view --- address/views.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/address/views.py b/address/views.py index a76e582..e509e51 100644 --- a/address/views.py +++ b/address/views.py @@ -1,14 +1,17 @@ from django.urls import reverse_lazy -from django.views.generic import CreateView +from django.views.generic import CreateView, UpdateView, DeleteView -from address.forms import CustomerAddressCreateForm +from address.forms import CustomerAddressCreateUpdateForm from address.models import CustomerAddress -class CustomerAddressCreateView(CreateView): +class BaseAddress: model = CustomerAddress - form_class = CustomerAddressCreateForm - template_name = 'address/create.html' + form_class = CustomerAddressCreateUpdateForm + template_name = 'address/create_update_form.html' + + +class CustomerAddressCreateView(BaseAddress, CreateView): success_url = reverse_lazy('accounts:customer-profile') def form_valid(self, form): @@ -16,3 +19,19 @@ def form_valid(self, form): instance.user = self.request.user instance.save() return super().form_valid(form) + + +class CustomerAddressUpdateView(BaseAddress, UpdateView): + success_url = reverse_lazy('accounts:customer-profile') + + def form_valid(self, form): + instance = form.save(commit=False) + instance.user = self.request.user + instance.save() + return super().form_valid(form) + + +class CustomerAddressDeleteView(DeleteView): + model = CustomerAddress + template_name = 'address/delete_form.html' + success_url = reverse_lazy('accounts:customer-profile') From e9024093c22edc34061bddfec577e7ab8ac2d17f Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 17:48:46 +0430 Subject: [PATCH 205/439] Update(address/urls): create a new url for update and delete address --- address/urls.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/address/urls.py b/address/urls.py index bc78aa8..b97ee0f 100644 --- a/address/urls.py +++ b/address/urls.py @@ -1,9 +1,11 @@ from django.urls import path -from .views import CustomerAddressCreateView +from .views import CustomerAddressCreateView, CustomerAddressUpdateView, CustomerAddressDeleteView app_name = 'address' urlpatterns = [ - path('customer/create', CustomerAddressCreateView.as_view(), name='customer-address-create') + path('customer/create', CustomerAddressCreateView.as_view(), name='customer-address-create'), + path('customer/update/', CustomerAddressUpdateView.as_view(), name='customer-address-update'), + path('customer/delete/', CustomerAddressDeleteView.as_view(), name='customer-address-delete'), ] From f5d523df83361d8a0cbdeea23872ac0fc635fd15 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 17:49:15 +0430 Subject: [PATCH 206/439] Style(address/templates): create delete template --- address/templates/address/delete_form.html | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 address/templates/address/delete_form.html diff --git a/address/templates/address/delete_form.html b/address/templates/address/delete_form.html new file mode 100644 index 0000000..47901ce --- /dev/null +++ b/address/templates/address/delete_form.html @@ -0,0 +1,11 @@ +{% extends 'address/base.html' %} +{% block content %} +
+
+ {% csrf_token %} +

Are you sure to delete address ({{ object.state }} | {{ object.area }})?

+ +
+ cancel +
+{% endblock %} From c9599bbc58997410fd462559cbb96d65bdb7825f Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 18:09:31 +0430 Subject: [PATCH 207/439] Update(accounts/views, utils): some user_passes_test becom class based --- accounts/urls.py | 4 ++-- accounts/utils.py | 61 +++++++++++++++++++---------------------------- accounts/views.py | 21 ++++++++-------- 3 files changed, 37 insertions(+), 49 deletions(-) diff --git a/accounts/urls.py b/accounts/urls.py index 3b6b467..dc1c209 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -2,7 +2,7 @@ from django.contrib.auth.views import LogoutView from accounts.views import CustomerLoginRegisterView, CustomerPhoneNumberConfirmView, CustomerPasswordConfirmView, \ - ProfileView, CustomerSetPasswordView, ServiceProviderRegistrationView, ServiceProviderLoginView, \ + CustomerProfileView, CustomerSetPasswordView, ServiceProviderRegistrationView, ServiceProviderLoginView, \ ServiceProviderProfileView, CustomerProfileUpdateView, CustomerChangePasswordView, ServiceProviderChangePasswordView app_name = 'accounts' @@ -11,7 +11,7 @@ path('customer/login-register/', CustomerLoginRegisterView.as_view(), name='customer-login-register'), path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='customer-code-confirm'), path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='customer-password-confirm'), - path('customer/profile/', ProfileView.as_view(), name='customer-profile'), + path('customer/profile/', CustomerProfileView.as_view(), name='customer-profile'), path('customer//profile-update/', CustomerProfileUpdateView.as_view(), name='customer-profile-update'), path('customer//set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), path('customer/change-password/', CustomerChangePasswordView.as_view(), name='customer-change-password'), diff --git a/accounts/utils.py b/accounts/utils.py index 2a6b61d..a00acb1 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -1,11 +1,7 @@ from datetime import datetime, timedelta -from functools import wraps from random import randint -from urllib.parse import urlparse -from django.conf import settings -from django.contrib.auth import REDIRECT_FIELD_NAME -from django.shortcuts import resolve_url +from django.contrib.auth.mixins import UserPassesTestMixin from accounts.models import Customer, ServiceProvider @@ -31,46 +27,39 @@ def set_phone_number_session(request, phone_number): print(request.session['created_time']) -def user_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): - def decorator(view_func): - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - if test_func(request.user, *args, **kwargs): - return view_func(request, *args, **kwargs) - path = request.build_absolute_uri() - resolved_login_url = resolve_url(login_url or settings.LOGIN_URL) - # If the login url is the same scheme and net location then just - # use the path as the "next" url. - login_scheme, login_netloc = urlparse(resolved_login_url)[:2] - current_scheme, current_netloc = urlparse(path)[:2] - if ((not login_scheme or login_scheme == current_scheme) and - (not login_netloc or login_netloc == current_netloc)): - path = request.get_full_path() - from django.contrib.auth.views import redirect_to_login - return redirect_to_login( - path, resolved_login_url, redirect_field_name) +def check_is_not_authenticated(user): + return not user.is_authenticated - return _wrapped_view - return decorator +def can_set_password(user): + return not user.password -# TODO: raise 403 in user_tests_functions -def check_is_not_authenticated(user): - return not user.is_authenticated +class IsCustomer(UserPassesTestMixin): + raise_exception = True + + def test_func(self): + return isinstance(self.request.user, Customer) + +class IsServiceProvider(UserPassesTestMixin): + raise_exception = True -def can_set_password(user, **kwargs): - return user.pk == kwargs['pk'] and not user.password + def test_func(self): + return isinstance(self.request.user, ServiceProvider) -def check_user_pk(user, **kwargs): - return user.pk == kwargs['pk'] +class CheckCustomerAccessPk(UserPassesTestMixin): + raise_exception = True + def test_func(self): + user = self.request.user + return isinstance(user, Customer) and user.pk == self.kwargs['pk'] -def is_customer(user): - return isinstance(user, Customer) +class CheckServiceProviderAccessPk(UserPassesTestMixin): + raise_exception = True -def is_service_provider(user): - return isinstance(user, ServiceProvider) + def test_func(self): + user = self.request.user + return isinstance(user, ServiceProvider) and user.pk == self.kwargs['pk'] diff --git a/accounts/views.py b/accounts/views.py index 0570757..23fadda 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_required, user_passes_test as user_test from django.contrib.auth.views import PasswordChangeView from django.shortcuts import redirect from django.urls import reverse_lazy @@ -12,14 +12,13 @@ from accounts.forms import CustomerLoginRegisterForm, CustomerCodeConfirmForm, CustomerPasswordForm, \ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer -from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, user_test, \ - can_set_password, check_user_pk, is_customer +from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, \ + IsCustomer, IsServiceProvider, can_set_password, CheckCustomerAccessPk, CheckServiceProviderAccessPk @method_decorator(require_http_methods(['GET']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -@method_decorator(user_test(is_customer), name='dispatch') -class ProfileView(TemplateView): +class CustomerProfileView(IsCustomer, TemplateView): template_name = 'accounts/customer/profile.html' @@ -113,7 +112,7 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') @method_decorator(user_test(can_set_password, login_url=reverse_lazy('accounts:customer-profile')), name='dispatch') -class CustomerSetPasswordView(UpdateView): +class CustomerSetPasswordView(CheckCustomerAccessPk, UpdateView): model = Customer form_class = CustomerPasswordSetForm success_url = reverse_lazy('accounts:customer-login-register') @@ -122,8 +121,7 @@ class CustomerSetPasswordView(UpdateView): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -@method_decorator(user_test(check_user_pk, login_url=reverse_lazy('accounts:customer-profile')), name='dispatch') -class CustomerProfileUpdateView(UpdateView): +class CustomerProfileUpdateView(CheckCustomerAccessPk, UpdateView): model = Customer form_class = CustomerProfileUpdateForm success_url = reverse_lazy('accounts:customer-profile') @@ -132,7 +130,7 @@ class CustomerProfileUpdateView(UpdateView): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerChangePasswordView(PasswordChangeView): +class CustomerChangePasswordView(IsCustomer, PasswordChangeView): template_name = 'accounts/customer/change_password.html' success_url = reverse_lazy('accounts:customer-profile') @@ -170,12 +168,13 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') -class ServiceProviderProfileView(TemplateView): +class ServiceProviderProfileView(IsServiceProvider, TemplateView): template_name = 'accounts/service_provider/profile.html' + raise_exception = True @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class ServiceProviderChangePasswordView(PasswordChangeView): +class ServiceProviderChangePasswordView(CheckServiceProviderAccessPk, PasswordChangeView): template_name = 'accounts/service_provider/change_password.html' success_url = reverse_lazy('accounts:service-provider-profile') From 5dbe882fdbcd91b3ccfe8f958bda87f10ccb6a83 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 18:18:04 +0430 Subject: [PATCH 208/439] Fix(accounts/views): fix a bug for CustomerSetPasswordView access decorators --- accounts/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index 23fadda..9833503 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -111,13 +111,16 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -@method_decorator(user_test(can_set_password, login_url=reverse_lazy('accounts:customer-profile')), name='dispatch') class CustomerSetPasswordView(CheckCustomerAccessPk, UpdateView): model = Customer form_class = CustomerPasswordSetForm success_url = reverse_lazy('accounts:customer-login-register') template_name = 'accounts/customer/password_set.html' + def test_func(self): + test_result = super().test_func() + return test_result and not self.request.user.password + @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') From 99f314e299232bb195674a1f7f3ef4afba1ee306 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Mon, 30 Aug 2021 18:24:16 +0430 Subject: [PATCH 209/439] Fix(accounts/views): fix a bug for CustomerChangePasswordView access decorators --- accounts/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/accounts/views.py b/accounts/views.py index 9833503..b698356 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -137,6 +137,10 @@ class CustomerChangePasswordView(IsCustomer, PasswordChangeView): template_name = 'accounts/customer/change_password.html' success_url = reverse_lazy('accounts:customer-profile') + def test_func(self): + test_result = super().test_func() + return test_result and self.request.user.password + @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') @method_decorator(user_test(check_is_not_authenticated, login_url=reverse_lazy('accounts:service-provider-profile')), From 5186d06ef925d55b87d8ce7a5781e4fc32dfb092 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 18:57:14 +0430 Subject: [PATCH 210/439] Add(address/forms): create service address create, update form --- address/forms.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/address/forms.py b/address/forms.py index a41acee..5d9d061 100644 --- a/address/forms.py +++ b/address/forms.py @@ -1,18 +1,28 @@ from django import forms -from address.models import CustomerAddress +from address.models import CustomerAddress, ServiceAddress + +base_fields = ('state', 'city', 'area', 'street', 'alley', 'floor', 'plaque') +base_widgets = { + 'state': forms.Select(attrs={'class': 'form-control'}), + 'city': forms.Select(attrs={'class': 'form-control'}), + 'area': forms.Select(attrs={'class': 'form-control'}), + 'street': forms.TextInput(attrs={'class': 'form-control'}), + 'alley': forms.TextInput(attrs={'class': 'form-control'}), + 'floor': forms.NumberInput(attrs={'class': 'form-control'}), + 'plaque': forms.NumberInput(attrs={'class': 'form-control'}), +} class CustomerAddressCreateUpdateForm(forms.ModelForm): class Meta: model = CustomerAddress - fields = ('state', 'city', 'area', 'street', 'alley', 'floor', 'plaque') - widgets = { - 'state': forms.Select(attrs={'class': 'form-control'}), - 'city': forms.Select(attrs={'class': 'form-control'}), - 'area': forms.Select(attrs={'class': 'form-control'}), - 'street': forms.TextInput(attrs={'class': 'form-control'}), - 'alley': forms.TextInput(attrs={'class': 'form-control'}), - 'floor': forms.NumberInput(attrs={'class': 'form-control'}), - 'plaque': forms.NumberInput(attrs={'class': 'form-control'}), - } + fields = base_fields + widgets = base_widgets + + +class ServiceAddressCreateUpdateForm(forms.ModelForm): + class Meta: + model = ServiceAddress + fields = base_fields + widgets = base_widgets From aa3abed08282fc869c8c16ab2fec70e1b81fd2bd Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 18:57:36 +0430 Subject: [PATCH 211/439] Add(address/views): create service create view --- address/views.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/address/views.py b/address/views.py index e509e51..f3f1b39 100644 --- a/address/views.py +++ b/address/views.py @@ -1,8 +1,11 @@ +from django.db import transaction +from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from django.views.generic import CreateView, UpdateView, DeleteView -from address.forms import CustomerAddressCreateUpdateForm -from address.models import CustomerAddress +from address.forms import CustomerAddressCreateUpdateForm, ServiceAddressCreateUpdateForm +from address.models import CustomerAddress, ServiceAddress +from service.models import Service class BaseAddress: @@ -35,3 +38,21 @@ class CustomerAddressDeleteView(DeleteView): model = CustomerAddress template_name = 'address/delete_form.html' success_url = reverse_lazy('accounts:customer-profile') + + +class ServiceAddressCreateView(CreateView): + model = ServiceAddress + form_class = ServiceAddressCreateUpdateForm + template_name = 'address/create_update_form.html' + raise_exception = True + + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + self.service = get_object_or_404(Service, id=self.kwargs['service_pk']) + + def form_valid(self, form): + with transaction.atomic(): + instance = form.save() + self.service.address = instance + self.service.save() + return super().form_valid(form) From 850c3c330dcedb64e34c3b5fd8eb234225882db0 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 19:01:44 +0430 Subject: [PATCH 212/439] Add(address/urls): create service address create url --- address/urls.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/address/urls.py b/address/urls.py index b97ee0f..28cab99 100644 --- a/address/urls.py +++ b/address/urls.py @@ -1,6 +1,7 @@ from django.urls import path -from .views import CustomerAddressCreateView, CustomerAddressUpdateView, CustomerAddressDeleteView +from .views import CustomerAddressCreateView, CustomerAddressUpdateView, CustomerAddressDeleteView, \ + ServiceAddressCreateView app_name = 'address' @@ -8,4 +9,5 @@ path('customer/create', CustomerAddressCreateView.as_view(), name='customer-address-create'), path('customer/update/', CustomerAddressUpdateView.as_view(), name='customer-address-update'), path('customer/delete/', CustomerAddressDeleteView.as_view(), name='customer-address-delete'), + path('service/create/', ServiceAddressCreateView.as_view(), name='service-address-delete'), ] From 098b9073a6721874e60e9d12e3f9025fcee581a8 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 19:08:17 +0430 Subject: [PATCH 213/439] Fix(address/views): add success url field to service address create view --- address/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/address/views.py b/address/views.py index f3f1b39..bfbebaf 100644 --- a/address/views.py +++ b/address/views.py @@ -44,6 +44,7 @@ class ServiceAddressCreateView(CreateView): model = ServiceAddress form_class = ServiceAddressCreateUpdateForm template_name = 'address/create_update_form.html' + success_url = reverse_lazy('accounts:service-provider-profile') raise_exception = True def setup(self, request, *args, **kwargs): From 1062ec2872636360a5dfc5ad7dd43e14b4bea15e Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 19:08:47 +0430 Subject: [PATCH 214/439] Update(address/urls): update service address create url --- address/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/address/urls.py b/address/urls.py index 28cab99..bcd8893 100644 --- a/address/urls.py +++ b/address/urls.py @@ -9,5 +9,5 @@ path('customer/create', CustomerAddressCreateView.as_view(), name='customer-address-create'), path('customer/update/', CustomerAddressUpdateView.as_view(), name='customer-address-update'), path('customer/delete/', CustomerAddressDeleteView.as_view(), name='customer-address-delete'), - path('service/create/', ServiceAddressCreateView.as_view(), name='service-address-delete'), + path('service/create//', ServiceAddressCreateView.as_view(), name='service-address-delete'), ] From 89986684bf72e4de0fc9ce807007e8f8be51681e Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 19:35:20 +0430 Subject: [PATCH 215/439] Add(address/views): create service address update view and refactor service address create view --- address/views.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/address/views.py b/address/views.py index bfbebaf..e97ec5f 100644 --- a/address/views.py +++ b/address/views.py @@ -1,3 +1,4 @@ +from django.contrib.auth.mixins import UserPassesTestMixin from django.db import transaction from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy @@ -57,3 +58,17 @@ def form_valid(self, form): self.service.address = instance self.service.save() return super().form_valid(form) + + +class ServiceAddressUpdateView(UpdateView): + model = ServiceAddress + form_class = ServiceAddressCreateUpdateForm + template_name = 'address/create_update_form.html' + success_url = reverse_lazy('accounts:service-provider-profile') + + def form_valid(self, form): + with transaction.atomic(): + instance = form.save(commit=False) + if self.request.user == instance.services.last().service_provider: + instance.save() + return super().form_valid(form) From b3ac78a1dc06c9b231ec1b4915b0c7b1ad69940a Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Mon, 30 Aug 2021 19:36:02 +0430 Subject: [PATCH 216/439] Add(address/urls): create service address update view --- address/urls.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/address/urls.py b/address/urls.py index bcd8893..9df8ddc 100644 --- a/address/urls.py +++ b/address/urls.py @@ -1,13 +1,16 @@ from django.urls import path from .views import CustomerAddressCreateView, CustomerAddressUpdateView, CustomerAddressDeleteView, \ - ServiceAddressCreateView + ServiceAddressCreateView, ServiceAddressUpdateView app_name = 'address' urlpatterns = [ - path('customer/create', CustomerAddressCreateView.as_view(), name='customer-address-create'), - path('customer/update/', CustomerAddressUpdateView.as_view(), name='customer-address-update'), - path('customer/delete/', CustomerAddressDeleteView.as_view(), name='customer-address-delete'), - path('service/create//', ServiceAddressCreateView.as_view(), name='service-address-delete'), + path('customer/create/', CustomerAddressCreateView.as_view(), name='customer-address-create'), + path('service/create//', ServiceAddressCreateView.as_view(), name='service-address-create'), + + path('customer/update//', CustomerAddressUpdateView.as_view(), name='customer-address-update'), + path('service/update//', ServiceAddressUpdateView.as_view(), name='service-address-update'), + + path('customer/delete//', CustomerAddressDeleteView.as_view(), name='customer-address-delete'), ] From d2defe81a5cb68008cc00388c5f8716bbc742ae5 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 00:00:32 +0430 Subject: [PATCH 217/439] Clean(accounts/views): remove unused import --- accounts/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/views.py b/accounts/views.py index b698356..5a9f44c 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -13,7 +13,7 @@ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, \ - IsCustomer, IsServiceProvider, can_set_password, CheckCustomerAccessPk, CheckServiceProviderAccessPk + IsCustomer, IsServiceProvider, CheckCustomerAccessPk, CheckServiceProviderAccessPk @method_decorator(require_http_methods(['GET']), name='dispatch') From 0308684a49f14c82def64718d49ca1b58ab2de7f Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 00:44:35 +0430 Subject: [PATCH 218/439] Update(accounts/forms): add phone_number validator --- accounts/forms.py | 47 ++++++++++++++++++++++++++++++++++++++--------- accounts/utils.py | 6 ++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index e4e1ae1..73ba6c6 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -6,13 +6,15 @@ from django.utils.translation import gettext_lazy as _ from accounts.models import ServiceProvider, Customer +from accounts.utils import phone_number_validator class CustomerLoginRegisterForm(forms.Form): - phone_number = forms.CharField(max_length=11, - min_length=11, - validators=[int_list_validator(message=_('only digits are accepted'))], - error_messages={'min_length': _('phone number must have 11 digits')}, + phone_number = forms.CharField(max_length=12, + validators=[ + int_list_validator(message=_('only digits are accepted')), + phone_number_validator + ], widget=forms.TextInput( attrs={'class': 'form-control', 'placeholder': 'phone number'}) ) @@ -96,6 +98,14 @@ class ServiceProviderRegistrationForm(forms.ModelForm): 'class': 'form-control'} ) ) + phone_number = forms.CharField(max_length=12, + validators=[ + int_list_validator(message=_('only digits are accepted')), + phone_number_validator + ], + widget=forms.TextInput( + attrs={'class': 'form-control', 'placeholder': 'phone number'}) + ) confirm_password = forms.CharField( widget=forms.PasswordInput( attrs={ @@ -113,13 +123,32 @@ class Meta: 'password': forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}), } - def clean_phone_number(self): - phone = self.cleaned_data['phone_number'] + def clean_username(self): + username = self.cleaned_data['username'] + try: + ServiceProvider.objects.get(username=username) + except ServiceProvider.DoesNotExist: + return username + else: + raise ValidationError(f"username {username} already exists") + + def clean_email(self): + email = self.cleaned_data['email'] + try: + ServiceProvider.objects.get(email=email) + except ServiceProvider.DoesNotExist: + return email + else: + raise ValidationError(f"email {email} already exists") - if phone.startswith('98') and len(phone) == 12: - return self.cleaned_data['phone_number'] + def clean_phone_number(self): + phone_number = self.cleaned_data['phone_number'] + try: + ServiceProvider.objects.get(phone_number=phone_number) + except ServiceProvider.DoesNotExist: + return phone_number else: - raise ValidationError('phone_number invalid!') + raise ValidationError(f"phone_number {phone_number} already exists") def clean_confirm_password(self): if self.cleaned_data['password'] != self.cleaned_data['confirm_password']: diff --git a/accounts/utils.py b/accounts/utils.py index a00acb1..ba93cda 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -2,10 +2,16 @@ from random import randint from django.contrib.auth.mixins import UserPassesTestMixin +from django.core.exceptions import ValidationError from accounts.models import Customer, ServiceProvider +def phone_number_validator(value): + if not value.startswith('98') or len(value) != 12: + raise ValidationError('phone number must be like 98912*******') + + def check_expire_time(request): try: expire_time = datetime.strptime(request.session['created-time'], '%Y-%m-%d %H:%M:%S') From af8752ab9f931f9f31cf3b27987631edc8ccafeb Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 00:46:20 +0430 Subject: [PATCH 219/439] Delete(accounts/forms): remove clean_username , clean_password, clean_email in ServiceProviderRegistrationForm --- accounts/forms.py | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index 73ba6c6..e351ced 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -123,33 +123,6 @@ class Meta: 'password': forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}), } - def clean_username(self): - username = self.cleaned_data['username'] - try: - ServiceProvider.objects.get(username=username) - except ServiceProvider.DoesNotExist: - return username - else: - raise ValidationError(f"username {username} already exists") - - def clean_email(self): - email = self.cleaned_data['email'] - try: - ServiceProvider.objects.get(email=email) - except ServiceProvider.DoesNotExist: - return email - else: - raise ValidationError(f"email {email} already exists") - - def clean_phone_number(self): - phone_number = self.cleaned_data['phone_number'] - try: - ServiceProvider.objects.get(phone_number=phone_number) - except ServiceProvider.DoesNotExist: - return phone_number - else: - raise ValidationError(f"phone_number {phone_number} already exists") - def clean_confirm_password(self): if self.cleaned_data['password'] != self.cleaned_data['confirm_password']: raise ValidationError('passwords not equal!') From 2c1c7abd521a2b4ec5b0b7468ba8bd031760ad0e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 00:47:44 +0430 Subject: [PATCH 220/439] Update(accounts/models): change the max_length of phone_number in both user models --- .../migrations/0002_auto_20210831_0046.py | 23 +++++++++++++++++++ accounts/models.py | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 accounts/migrations/0002_auto_20210831_0046.py diff --git a/accounts/migrations/0002_auto_20210831_0046.py b/accounts/migrations/0002_auto_20210831_0046.py new file mode 100644 index 0000000..1c7f550 --- /dev/null +++ b/accounts/migrations/0002_auto_20210831_0046.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2 on 2021-08-30 20:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='customer', + name='phone_number', + field=models.CharField(max_length=12, unique=True, verbose_name='phone number'), + ), + migrations.AlterField( + model_name='serviceprovider', + name='phone_number', + field=models.CharField(max_length=12, unique=True, verbose_name='phone number'), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index 9b00790..5ef1952 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -26,7 +26,7 @@ def create(self, phone_number, password=None, **extra_fields): class Customer(AbstractBaseUser): - phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) + phone_number = models.CharField(max_length=12, verbose_name=_('phone number'), unique=True) first_name = models.CharField(_('first name'), max_length=150, blank=True) last_name = models.CharField(_('last name'), max_length=150, blank=True) is_staff = models.BooleanField( @@ -75,7 +75,7 @@ class ServiceProvider(AbstractBaseUser): }, ) email = models.EmailField(_('email address'), blank=True, unique=True) - phone_number = models.CharField(max_length=13, verbose_name=_('phone number'), unique=True) + phone_number = models.CharField(max_length=12, verbose_name=_('phone number'), unique=True) is_staff = models.BooleanField( _('staff status'), default=False, From eba728f58e451d4ec3dbd9d6142af049b7882632 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 00:54:36 +0430 Subject: [PATCH 221/439] Update(account/templates/customer): remove
from profile.html --- accounts/templates/accounts/customer/profile.html | 1 - 1 file changed, 1 deletion(-) diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index 6afe8ce..5d5f6f0 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -9,7 +9,6 @@

Profile

Update profile

{% if not request.user.password %} -
Set password

{% else %} From 75373418b314aae1d1e4fea796d3eea96de65832 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 16:17:06 +0430 Subject: [PATCH 222/439] Add(library/utils): add CustomUserPasses class --- library/utils.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 library/utils.py diff --git a/library/utils.py b/library/utils.py new file mode 100644 index 0000000..bc17fa0 --- /dev/null +++ b/library/utils.py @@ -0,0 +1,31 @@ +from abc import ABC + +from django.contrib.auth.mixins import UserPassesTestMixin +from django.core.exceptions import PermissionDenied +from django.http import HttpResponseRedirect + + +class CustomUserPasses(ABC, UserPassesTestMixin): + raise_exception = True + + def handle_no_permission(self, path_url=None, redirect=False): + if redirect: + return HttpResponseRedirect(path_url) + + else: + raise PermissionDenied(self.get_permission_denied_message()) + + def dispatch(self, request, *args, **kwargs): + user_test_result = self.test_func() + + if user_test_result is None: + return super().dispatch(request, *args, **kwargs) + + if isinstance(self.test_func(), tuple): + user_test_bool, redirect, path_url = user_test_result + if not user_test_bool: + return self.handle_no_permission(path_url, redirect) + + if not user_test_result: + return self.handle_no_permission() + return super().dispatch(request, *args, **kwargs) From e8e0e6bdf4392856b8fbe17e57bf007d54bedefa Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 16:24:48 +0430 Subject: [PATCH 223/439] Refactor(address/models, admin): rename the address model field and change admin --- address/admin.py | 6 +++--- address/models.py | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/address/admin.py b/address/admin.py index d5ca293..4934784 100644 --- a/address/admin.py +++ b/address/admin.py @@ -23,14 +23,14 @@ class AreaAdmin(admin.ModelAdmin): @admin.register(ServiceAddress) -class AddressAdmin(admin.ModelAdmin): +class ServiceAddressAdmin(admin.ModelAdmin): list_display = ('state', 'city', 'area', 'floor', 'plaque') list_filter = ('state', 'city') search_fields = ('area', 'floor', 'plaque') @admin.register(CustomerAddress) -class AddressAdmin(admin.ModelAdmin): - list_display = ('user', 'state', 'city', 'area', 'floor', 'plaque') +class CustomerAddressAdmin(admin.ModelAdmin): + list_display = ('customer_user', 'state', 'city', 'area', 'floor', 'plaque') list_filter = ('state', 'city') search_fields = ('area', 'floor', 'plaque') diff --git a/address/models.py b/address/models.py index 8f40f7e..f94f6d1 100644 --- a/address/models.py +++ b/address/models.py @@ -57,13 +57,18 @@ class Meta: class CustomerAddress(BaseAddress): - user = models.ForeignKey(Customer, verbose_name=_('customer'), related_name='c_addresses', on_delete=models.CASCADE) + customer_user = models.ForeignKey( + Customer, + verbose_name=_('customer'), + related_name='c_addresses', + on_delete=models.CASCADE + ) state = models.ForeignKey(State, verbose_name=_('state'), related_name='c_addresses', on_delete=models.CASCADE) city = models.ForeignKey(City, verbose_name=_('city'), related_name='c_addresses', on_delete=models.CASCADE) area = models.ForeignKey(Area, verbose_name=_('area'), related_name='c_addresses', on_delete=models.CASCADE) def __str__(self): - return f'{self.user} - {self.city} - {self.area}' + return f'{self.customer_user} - {self.city} - {self.area}' class Meta: verbose_name = _('CustomerAddress') From 1f1040bac1be0903ff04c0830dd9bae15c080967 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 16:25:44 +0430 Subject: [PATCH 224/439] Fix(service/models): fix the service model field --- service/models.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/service/models.py b/service/models.py index 351643c..5539074 100644 --- a/service/models.py +++ b/service/models.py @@ -22,13 +22,22 @@ class Service(BaseModel): uuid = models.UUIDField(default=uuid.uuid4, verbose_name=_('uuid'), unique=True, db_index=True) service_provider = models.ForeignKey( - ServiceProvider, verbose_name=_('service provider'), related_name='services', on_delete=models.CASCADE + ServiceProvider, + verbose_name=_('service provider'), + related_name='services', + on_delete=models.CASCADE ) name = models.CharField(max_length=40, verbose_name=_('name')) service_type = models.PositiveSmallIntegerField(verbose_name=_('service type'), choices=SERVICE_TYPES) minimum_purchase = models.DecimalField(max_digits=9, decimal_places=0, verbose_name=_('minimum purchase')) - address = models.ForeignKey(ServiceAddress, verbose_name=_('address'), related_name='services', on_delete=models.SET_NULL, - null=True) + + address = models.OneToOneField( + ServiceAddress, + verbose_name=_('address'), + related_name='services', + on_delete=models.SET_NULL, + null=True + ) def __str__(self): return f'{self.name} - {self.get_service_type_display()}' From 00e55e8a6eb75d3dfb41dbfe0a4596c3aebcd43c Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 16:29:04 +0430 Subject: [PATCH 225/439] Fix(service/models): fix the model field --- service/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service/models.py b/service/models.py index 5539074..3af61af 100644 --- a/service/models.py +++ b/service/models.py @@ -36,7 +36,8 @@ class Service(BaseModel): verbose_name=_('address'), related_name='services', on_delete=models.SET_NULL, - null=True + null=True, + blank=True ) def __str__(self): From 2227df6f51cd1c8cac86823dbe1935730c45153c Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 16:29:56 +0430 Subject: [PATCH 226/439] Migrations: create the migrations --- ...name_user_customeraddress_customer_user.py | 18 +++++++++++++++++ .../migrations/0003_alter_service_address.py | 20 +++++++++++++++++++ .../migrations/0004_alter_service_address.py | 20 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 address/migrations/0006_rename_user_customeraddress_customer_user.py create mode 100644 service/migrations/0003_alter_service_address.py create mode 100644 service/migrations/0004_alter_service_address.py diff --git a/address/migrations/0006_rename_user_customeraddress_customer_user.py b/address/migrations/0006_rename_user_customeraddress_customer_user.py new file mode 100644 index 0000000..3b35923 --- /dev/null +++ b/address/migrations/0006_rename_user_customeraddress_customer_user.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2 on 2021-08-31 10:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0005_auto_20210830_1329'), + ] + + operations = [ + migrations.RenameField( + model_name='customeraddress', + old_name='user', + new_name='customer_user', + ), + ] diff --git a/service/migrations/0003_alter_service_address.py b/service/migrations/0003_alter_service_address.py new file mode 100644 index 0000000..972ed47 --- /dev/null +++ b/service/migrations/0003_alter_service_address.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2 on 2021-08-31 11:56 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0006_rename_user_customeraddress_customer_user'), + ('service', '0002_alter_service_address'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='address', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='services', to='address.serviceaddress', verbose_name='address'), + ), + ] diff --git a/service/migrations/0004_alter_service_address.py b/service/migrations/0004_alter_service_address.py new file mode 100644 index 0000000..04a0d58 --- /dev/null +++ b/service/migrations/0004_alter_service_address.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2 on 2021-08-31 11:58 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('address', '0006_rename_user_customeraddress_customer_user'), + ('service', '0003_alter_service_address'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='address', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='services', to='address.serviceaddress', verbose_name='address'), + ), + ] From eafdfc94b0d6130455c0eec7b34a1deddcb32031 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 16:30:30 +0430 Subject: [PATCH 227/439] Add(library/utils): create a custom user passess test --- library/utils.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 library/utils.py diff --git a/library/utils.py b/library/utils.py new file mode 100644 index 0000000..bc17fa0 --- /dev/null +++ b/library/utils.py @@ -0,0 +1,31 @@ +from abc import ABC + +from django.contrib.auth.mixins import UserPassesTestMixin +from django.core.exceptions import PermissionDenied +from django.http import HttpResponseRedirect + + +class CustomUserPasses(ABC, UserPassesTestMixin): + raise_exception = True + + def handle_no_permission(self, path_url=None, redirect=False): + if redirect: + return HttpResponseRedirect(path_url) + + else: + raise PermissionDenied(self.get_permission_denied_message()) + + def dispatch(self, request, *args, **kwargs): + user_test_result = self.test_func() + + if user_test_result is None: + return super().dispatch(request, *args, **kwargs) + + if isinstance(self.test_func(), tuple): + user_test_bool, redirect, path_url = user_test_result + if not user_test_bool: + return self.handle_no_permission(path_url, redirect) + + if not user_test_result: + return self.handle_no_permission() + return super().dispatch(request, *args, **kwargs) From 8c811f707f8033f141476a615d65ff4a685f0a47 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 16:31:19 +0430 Subject: [PATCH 228/439] Update(address/views): use custom passess test in all views --- address/views.py | 57 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/address/views.py b/address/views.py index e97ec5f..01b097c 100644 --- a/address/views.py +++ b/address/views.py @@ -1,11 +1,14 @@ -from django.contrib.auth.mixins import UserPassesTestMixin +from django.contrib.auth.decorators import login_required from django.db import transaction from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy +from django.utils.decorators import method_decorator from django.views.generic import CreateView, UpdateView, DeleteView +from accounts.models import Customer, ServiceProvider from address.forms import CustomerAddressCreateUpdateForm, ServiceAddressCreateUpdateForm from address.models import CustomerAddress, ServiceAddress +from library.utils import CustomUserPasses from service.models import Service @@ -15,9 +18,14 @@ class BaseAddress: template_name = 'address/create_update_form.html' +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') class CustomerAddressCreateView(BaseAddress, CreateView): success_url = reverse_lazy('accounts:customer-profile') + def test_func(self): + if not isinstance(self.request.user, Customer): + return False + def form_valid(self, form): instance = form.save(commit=False) instance.user = self.request.user @@ -25,9 +33,18 @@ def form_valid(self, form): return super().form_valid(form) +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') class CustomerAddressUpdateView(BaseAddress, UpdateView): success_url = reverse_lazy('accounts:customer-profile') + def test_func(self): + if not isinstance(self.request.user, Customer): + return False + + obj = self.get_object() + if obj.services.service_provider != self.request.user: + return False + def form_valid(self, form): instance = form.save(commit=False) instance.user = self.request.user @@ -35,13 +52,23 @@ def form_valid(self, form): return super().form_valid(form) -class CustomerAddressDeleteView(DeleteView): +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +class CustomerAddressDeleteView(CustomUserPasses, DeleteView): model = CustomerAddress template_name = 'address/delete_form.html' success_url = reverse_lazy('accounts:customer-profile') + def test_func(self): + if not isinstance(self.request.user, Customer): + return False + + obj = self.get_object() + if obj.customer_user != self.request.user: + return False + -class ServiceAddressCreateView(CreateView): +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') +class ServiceAddressCreateView(CustomUserPasses, CreateView): model = ServiceAddress form_class = ServiceAddressCreateUpdateForm template_name = 'address/create_update_form.html' @@ -52,6 +79,14 @@ def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) self.service = get_object_or_404(Service, id=self.kwargs['service_pk']) + def test_func(self): + if not isinstance(self.request.user, ServiceProvider): + return False + if self.service.service_provider != self.request.user: + return False + if self.service.address: + return False, True, reverse_lazy('accounts:service-provider-profile') + def form_valid(self, form): with transaction.atomic(): instance = form.save() @@ -60,15 +95,17 @@ def form_valid(self, form): return super().form_valid(form) -class ServiceAddressUpdateView(UpdateView): +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') +class ServiceAddressUpdateView(CustomUserPasses, UpdateView): model = ServiceAddress form_class = ServiceAddressCreateUpdateForm template_name = 'address/create_update_form.html' success_url = reverse_lazy('accounts:service-provider-profile') - def form_valid(self, form): - with transaction.atomic(): - instance = form.save(commit=False) - if self.request.user == instance.services.last().service_provider: - instance.save() - return super().form_valid(form) + def test_func(self): + if not isinstance(self.request.user, ServiceProvider): + return False + + obj = self.get_object() + if obj.services.service_provider != self.request.user: + return False From 82c3cbfab007ba8512f3f65f16ba0f3a6e8ad242 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 16:45:07 +0430 Subject: [PATCH 229/439] Update(accounts.views): use CustomUserPasses in CustomerChangePasswordView, CustomerSetPasswordView --- accounts/views.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 5a9f44c..dfc984c 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -14,6 +14,7 @@ from accounts.models import Customer from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, \ IsCustomer, IsServiceProvider, CheckCustomerAccessPk, CheckServiceProviderAccessPk +from library.utils import CustomUserPasses @method_decorator(require_http_methods(['GET']), name='dispatch') @@ -111,15 +112,21 @@ def form_valid(self, form): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerSetPasswordView(CheckCustomerAccessPk, UpdateView): +class CustomerSetPasswordView(CustomUserPasses, UpdateView): model = Customer form_class = CustomerPasswordSetForm success_url = reverse_lazy('accounts:customer-login-register') template_name = 'accounts/customer/password_set.html' def test_func(self): - test_result = super().test_func() - return test_result and not self.request.user.password + if not isinstance(self.request.user, Customer): + return False + if self.kwargs['pk'] != self.request.user.pk: + return False + if self.request.user.password: + return False, True, reverse_lazy("accounts:customer-change-password") + + return True @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @@ -133,13 +140,16 @@ class CustomerProfileUpdateView(CheckCustomerAccessPk, UpdateView): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerChangePasswordView(IsCustomer, PasswordChangeView): +class CustomerChangePasswordView(CustomUserPasses, PasswordChangeView): template_name = 'accounts/customer/change_password.html' success_url = reverse_lazy('accounts:customer-profile') def test_func(self): - test_result = super().test_func() - return test_result and self.request.user.password + if not isinstance(self.request.user, Customer): + return False + if not self.request.user.password: + return False, True, reverse_lazy("accounts:customer-set-password", kwargs={'pk': self.request.user.pk}) + return True @method_decorator(require_http_methods(['POST', 'GET']), name='dispatch') From cc998e7787068d52afd16d5cb4f1837202a8ae83 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 17:10:06 +0430 Subject: [PATCH 230/439] Fix: fix the custom user passes test --- address/views.py | 5 +++++ library/utils.py | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/address/views.py b/address/views.py index 01b097c..34214a4 100644 --- a/address/views.py +++ b/address/views.py @@ -25,6 +25,7 @@ class CustomerAddressCreateView(BaseAddress, CreateView): def test_func(self): if not isinstance(self.request.user, Customer): return False + return True def form_valid(self, form): instance = form.save(commit=False) @@ -44,6 +45,7 @@ def test_func(self): obj = self.get_object() if obj.services.service_provider != self.request.user: return False + return True def form_valid(self, form): instance = form.save(commit=False) @@ -65,6 +67,7 @@ def test_func(self): obj = self.get_object() if obj.customer_user != self.request.user: return False + return True @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') @@ -86,6 +89,7 @@ def test_func(self): return False if self.service.address: return False, True, reverse_lazy('accounts:service-provider-profile') + return True def form_valid(self, form): with transaction.atomic(): @@ -109,3 +113,4 @@ def test_func(self): obj = self.get_object() if obj.services.service_provider != self.request.user: return False + return True diff --git a/library/utils.py b/library/utils.py index bc17fa0..98b8df5 100644 --- a/library/utils.py +++ b/library/utils.py @@ -18,9 +18,6 @@ def handle_no_permission(self, path_url=None, redirect=False): def dispatch(self, request, *args, **kwargs): user_test_result = self.test_func() - if user_test_result is None: - return super().dispatch(request, *args, **kwargs) - if isinstance(self.test_func(), tuple): user_test_bool, redirect, path_url = user_test_result if not user_test_bool: From e57452934e82da86ae6b59a7a035122822185182 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Tue, 31 Aug 2021 17:16:10 +0430 Subject: [PATCH 231/439] Update(accounts): remove pk place holder from 2 customer urls --- .../templates/accounts/customer/profile.html | 4 ++-- accounts/urls.py | 4 ++-- accounts/utils.py | 16 ---------------- accounts/views.py | 16 ++++++++++------ library/utils.py | 3 --- 5 files changed, 14 insertions(+), 29 deletions(-) diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index 5d5f6f0..0c9338c 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -6,10 +6,10 @@

Profile

First name : {{ request.user.first_name }}

Last name : {{ request.user.last_name }}


- Update profile

+ Update profile

{% if not request.user.password %} - Set password + Set password

{% else %} Change password diff --git a/accounts/urls.py b/accounts/urls.py index dc1c209..ebf8323 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -12,8 +12,8 @@ path('customer/code-confirm/', CustomerPhoneNumberConfirmView.as_view(), name='customer-code-confirm'), path('customer/password-confirm/', CustomerPasswordConfirmView.as_view(), name='customer-password-confirm'), path('customer/profile/', CustomerProfileView.as_view(), name='customer-profile'), - path('customer//profile-update/', CustomerProfileUpdateView.as_view(), name='customer-profile-update'), - path('customer//set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), + path('customer/profile-update/', CustomerProfileUpdateView.as_view(), name='customer-profile-update'), + path('customer/set-password/', CustomerSetPasswordView.as_view(), name='customer-set-password'), path('customer/change-password/', CustomerChangePasswordView.as_view(), name='customer-change-password'), path('customer/logout/', LogoutView.as_view(next_page=reverse_lazy('accounts:customer-login-register')), name='customer-logout'), diff --git a/accounts/utils.py b/accounts/utils.py index ba93cda..ff757c0 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -53,19 +53,3 @@ class IsServiceProvider(UserPassesTestMixin): def test_func(self): return isinstance(self.request.user, ServiceProvider) - - -class CheckCustomerAccessPk(UserPassesTestMixin): - raise_exception = True - - def test_func(self): - user = self.request.user - return isinstance(user, Customer) and user.pk == self.kwargs['pk'] - - -class CheckServiceProviderAccessPk(UserPassesTestMixin): - raise_exception = True - - def test_func(self): - user = self.request.user - return isinstance(user, ServiceProvider) and user.pk == self.kwargs['pk'] diff --git a/accounts/views.py b/accounts/views.py index dfc984c..ba01b70 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -13,7 +13,7 @@ CustomerPasswordSetForm, ServiceProviderRegistrationForm, ServiceProviderLoginForm, CustomerProfileUpdateForm from accounts.models import Customer from accounts.utils import check_expire_time, set_phone_number_session, check_is_not_authenticated, \ - IsCustomer, IsServiceProvider, CheckCustomerAccessPk, CheckServiceProviderAccessPk + IsCustomer, IsServiceProvider from library.utils import CustomUserPasses @@ -121,22 +121,26 @@ class CustomerSetPasswordView(CustomUserPasses, UpdateView): def test_func(self): if not isinstance(self.request.user, Customer): return False - if self.kwargs['pk'] != self.request.user.pk: - return False if self.request.user.password: return False, True, reverse_lazy("accounts:customer-change-password") return True + def get_object(self, queryset=None): + return self.request.user + @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerProfileUpdateView(CheckCustomerAccessPk, UpdateView): +class CustomerProfileUpdateView(IsCustomer, UpdateView): model = Customer form_class = CustomerProfileUpdateForm success_url = reverse_lazy('accounts:customer-profile') template_name = 'accounts/customer/profile_update.html' + def get_object(self, queryset=None): + return self.request.user + @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') @@ -148,7 +152,7 @@ def test_func(self): if not isinstance(self.request.user, Customer): return False if not self.request.user.password: - return False, True, reverse_lazy("accounts:customer-set-password", kwargs={'pk': self.request.user.pk}) + return False, True, reverse_lazy("accounts:customer-set-password") return True @@ -192,6 +196,6 @@ class ServiceProviderProfileView(IsServiceProvider, TemplateView): @method_decorator(require_http_methods(['GET', 'POST']), name='dispatch') @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class ServiceProviderChangePasswordView(CheckServiceProviderAccessPk, PasswordChangeView): +class ServiceProviderChangePasswordView(IsServiceProvider, PasswordChangeView): template_name = 'accounts/service_provider/change_password.html' success_url = reverse_lazy('accounts:service-provider-profile') diff --git a/library/utils.py b/library/utils.py index bc17fa0..98b8df5 100644 --- a/library/utils.py +++ b/library/utils.py @@ -18,9 +18,6 @@ def handle_no_permission(self, path_url=None, redirect=False): def dispatch(self, request, *args, **kwargs): user_test_result = self.test_func() - if user_test_result is None: - return super().dispatch(request, *args, **kwargs) - if isinstance(self.test_func(), tuple): user_test_bool, redirect, path_url = user_test_result if not user_test_bool: From 0eb751e4e67abc57534bdb93bdd988b1ecb16c30 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 17:54:50 +0430 Subject: [PATCH 232/439] Update(address/views): update user passess tests --- address/views.py | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/address/views.py b/address/views.py index 34214a4..e7cb40d 100644 --- a/address/views.py +++ b/address/views.py @@ -5,7 +5,8 @@ from django.utils.decorators import method_decorator from django.views.generic import CreateView, UpdateView, DeleteView -from accounts.models import Customer, ServiceProvider +from accounts.models import ServiceProvider +from accounts.utils import IsCustomer, IsServiceProvider from address.forms import CustomerAddressCreateUpdateForm, ServiceAddressCreateUpdateForm from address.models import CustomerAddress, ServiceAddress from library.utils import CustomUserPasses @@ -19,14 +20,9 @@ class BaseAddress: @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerAddressCreateView(BaseAddress, CreateView): +class CustomerAddressCreateView(BaseAddress, IsCustomer, CreateView): success_url = reverse_lazy('accounts:customer-profile') - def test_func(self): - if not isinstance(self.request.user, Customer): - return False - return True - def form_valid(self, form): instance = form.save(commit=False) instance.user = self.request.user @@ -35,17 +31,13 @@ def form_valid(self, form): @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerAddressUpdateView(BaseAddress, UpdateView): +class CustomerAddressUpdateView(BaseAddress, IsCustomer, UpdateView): success_url = reverse_lazy('accounts:customer-profile') def test_func(self): - if not isinstance(self.request.user, Customer): - return False - + result = super().test_func() obj = self.get_object() - if obj.services.service_provider != self.request.user: - return False - return True + return result and obj.customer_user == self.request.user def form_valid(self, form): instance = form.save(commit=False) @@ -55,19 +47,15 @@ def form_valid(self, form): @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerAddressDeleteView(CustomUserPasses, DeleteView): +class CustomerAddressDeleteView(IsServiceProvider, DeleteView): model = CustomerAddress template_name = 'address/delete_form.html' success_url = reverse_lazy('accounts:customer-profile') def test_func(self): - if not isinstance(self.request.user, Customer): - return False - + result = super().test_func() obj = self.get_object() - if obj.customer_user != self.request.user: - return False - return True + return result and obj.customer_user == self.request.user @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') @@ -100,17 +88,13 @@ def form_valid(self, form): @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') -class ServiceAddressUpdateView(CustomUserPasses, UpdateView): +class ServiceAddressUpdateView(IsServiceProvider, UpdateView): model = ServiceAddress form_class = ServiceAddressCreateUpdateForm template_name = 'address/create_update_form.html' success_url = reverse_lazy('accounts:service-provider-profile') def test_func(self): - if not isinstance(self.request.user, ServiceProvider): - return False - + result = super().test_func() obj = self.get_object() - if obj.services.service_provider != self.request.user: - return False - return True + return result and obj.services.service_provider == self.request.user From 15b9833a83a4ef88949c4bf74073c35df6aa5983 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:19:02 +0430 Subject: [PATCH 233/439] Add(templatetags): add some filter for users --- accounts/templatetags/__init__.py | 0 accounts/templatetags/accounts_tags.py | 19 +++++++++++++++++++ address/templates/address/base.html | 22 ---------------------- 3 files changed, 19 insertions(+), 22 deletions(-) create mode 100644 accounts/templatetags/__init__.py create mode 100644 accounts/templatetags/accounts_tags.py delete mode 100644 address/templates/address/base.html diff --git a/accounts/templatetags/__init__.py b/accounts/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounts/templatetags/accounts_tags.py b/accounts/templatetags/accounts_tags.py new file mode 100644 index 0000000..8559d92 --- /dev/null +++ b/accounts/templatetags/accounts_tags.py @@ -0,0 +1,19 @@ +from django import template + +from accounts.models import Customer, ServiceProvider + +register = template.Library() + + +@register.simple_tag +def is_customer(user): + if isinstance(user, Customer): + return True + return False + + +@register.simple_tag +def is_service_provider(user): + if isinstance(user, ServiceProvider): + return True + return False diff --git a/address/templates/address/base.html b/address/templates/address/base.html deleted file mode 100644 index 0dd635f..0000000 --- a/address/templates/address/base.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - {% block title %} {% endblock %} - - -
- {% block content %} - {% endblock %} -
- - - \ No newline at end of file From 0541e305500631c281ba45c989680237e65289a1 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:19:52 +0430 Subject: [PATCH 234/439] Add(base-templates): create the base templates for project --- templates/base.html | 40 +++++++++++++++++++ templates/inc/customer_navbar.html | 42 ++++++++++++++++++++ templates/inc/service_provider_navbar.html | 45 ++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 templates/base.html create mode 100644 templates/inc/customer_navbar.html create mode 100644 templates/inc/service_provider_navbar.html diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..a2543f4 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,40 @@ +{% load accounts_tags %} + + + + + + + + + + {% block title %} {% endblock %} + + + +{% is_customer request.user as customer_flag %} +{% is_service_provider request.user as service_provider_flag %} + +{% if service_provider_flag %} + {% include 'inc/service_provider_navbar.html' %} +{% elif customer_flag %} + {% include 'inc/customer_navbar.html' %} +{% else %} + {% include 'inc/customer_navbar.html' %} +{% endif %} + +
+ {% if messages %} + {% for message in messages %} + + {% endfor %} + {% endif %} + {% block content %} + {% endblock %} +
+ + + \ No newline at end of file diff --git a/templates/inc/customer_navbar.html b/templates/inc/customer_navbar.html new file mode 100644 index 0000000..53443e2 --- /dev/null +++ b/templates/inc/customer_navbar.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/templates/inc/service_provider_navbar.html b/templates/inc/service_provider_navbar.html new file mode 100644 index 0000000..1ac366b --- /dev/null +++ b/templates/inc/service_provider_navbar.html @@ -0,0 +1,45 @@ + \ No newline at end of file From 21a0d2f6e627179f9153387b52d2ae6a06588962 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:20:58 +0430 Subject: [PATCH 235/439] Add(address/views): create customer address list --- .../templates/address/customer_address_list.html | 13 +++++++++++++ address/views.py | 15 ++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 address/templates/address/customer_address_list.html diff --git a/address/templates/address/customer_address_list.html b/address/templates/address/customer_address_list.html new file mode 100644 index 0000000..7b87af0 --- /dev/null +++ b/address/templates/address/customer_address_list.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} +{% block content %} +
    + {% for address in addresses %} +
  • + {{ address.state.name }} - {{ address.city.name }} - {{ address.area.name }} - {{ address.street }} + - {{ address.alley }} - {{ address.floor }} - {{ address.plaque }} + Update + Delete +
  • + {% endfor %} +
+{% endblock %} diff --git a/address/views.py b/address/views.py index e7cb40d..268f67e 100644 --- a/address/views.py +++ b/address/views.py @@ -3,7 +3,7 @@ from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from django.utils.decorators import method_decorator -from django.views.generic import CreateView, UpdateView, DeleteView +from django.views.generic import CreateView, UpdateView, DeleteView, ListView from accounts.models import ServiceProvider from accounts.utils import IsCustomer, IsServiceProvider @@ -32,7 +32,7 @@ def form_valid(self, form): @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') class CustomerAddressUpdateView(BaseAddress, IsCustomer, UpdateView): - success_url = reverse_lazy('accounts:customer-profile') + success_url = reverse_lazy('address:customer-address-list') def test_func(self): result = super().test_func() @@ -47,7 +47,7 @@ def form_valid(self, form): @method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') -class CustomerAddressDeleteView(IsServiceProvider, DeleteView): +class CustomerAddressDeleteView(IsCustomer, DeleteView): model = CustomerAddress template_name = 'address/delete_form.html' success_url = reverse_lazy('accounts:customer-profile') @@ -98,3 +98,12 @@ def test_func(self): result = super().test_func() obj = self.get_object() return result and obj.services.service_provider == self.request.user + + +class CustomerAddressListView(ListView): + model = CustomerAddress + template_name = 'address/customer_address_list.html' + context_object_name = 'addresses' + + def get_queryset(self): + return super().get_queryset().filter(customer_user=self.request.user) From ca43cc4f5a15cce8077c1aa1320de33a997b0235 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:22:11 +0430 Subject: [PATCH 236/439] Add(address/urls): create customer address list url --- address/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/address/urls.py b/address/urls.py index 9df8ddc..c85a8c8 100644 --- a/address/urls.py +++ b/address/urls.py @@ -1,7 +1,7 @@ from django.urls import path from .views import CustomerAddressCreateView, CustomerAddressUpdateView, CustomerAddressDeleteView, \ - ServiceAddressCreateView, ServiceAddressUpdateView + ServiceAddressCreateView, ServiceAddressUpdateView, CustomerAddressListView app_name = 'address' @@ -13,4 +13,5 @@ path('service/update//', ServiceAddressUpdateView.as_view(), name='service-address-update'), path('customer/delete//', CustomerAddressDeleteView.as_view(), name='customer-address-delete'), + path('customer/list/', CustomerAddressListView.as_view(), name='customer-address-list'), ] From 14cdba7ef84435e30dd24621d8646dea2680747d Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:23:08 +0430 Subject: [PATCH 237/439] Add(urls): add home path url for test --- snapp_food/urls.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snapp_food/urls.py b/snapp_food/urls.py index 785804f..df7d83f 100644 --- a/snapp_food/urls.py +++ b/snapp_food/urls.py @@ -15,9 +15,11 @@ """ from django.contrib import admin from django.urls import path, include +from django.views.generic import TemplateView urlpatterns = [ path('admin/', admin.site.urls), + path('home/', TemplateView.as_view(template_name='base.html'), name='home'), path('accounts/', include('accounts.urls', namespace='accounts')), path('address/', include('address.urls', namespace='address')), ] From 7f975dab01da9b94fe179ab6e5863cfb55d831ba Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:23:56 +0430 Subject: [PATCH 238/439] Style(accounts/templates): style accounts templates --- accounts/templates/accounts/customer/profile.html | 5 +++-- .../templates/accounts/service_provider/profile.html | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index 0c9338c..88b2497 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -1,4 +1,4 @@ -{% extends 'accounts/base.html' %} +{% extends 'base.html' %} {% block title %} Profile {% endblock %} {% block content %}

Profile

@@ -6,6 +6,8 @@

Profile

First name : {{ request.user.first_name }}

Last name : {{ request.user.last_name }}


+ Address list

+ Update profile

{% if not request.user.password %} @@ -15,6 +17,5 @@

Profile

Change password

{% endif %} - Logout {% endblock %} \ No newline at end of file diff --git a/accounts/templates/accounts/service_provider/profile.html b/accounts/templates/accounts/service_provider/profile.html index f59923b..ebe0e15 100644 --- a/accounts/templates/accounts/service_provider/profile.html +++ b/accounts/templates/accounts/service_provider/profile.html @@ -1,9 +1,9 @@ -{% extends 'accounts/base.html' %} +{% extends 'base.html' %} {% block content %} -

Your Profile

-

your username: {{ request.user.username }}

-

your email: {{ request.user.email }}

-

your phone number: {{ request.user.phone_number }}

+

Profile

+

Your username : {{ request.user.username }}

+

Your email : {{ request.user.email }}

+

Your phone number : {{ request.user.phone_number }}



Change password {% endblock %} From 641d3a987b859722ffe231627c729461abb996f3 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:24:11 +0430 Subject: [PATCH 239/439] Style(address/templates): style address templates --- address/templates/address/create_update_form.html | 4 +++- address/templates/address/delete_form.html | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/address/templates/address/create_update_form.html b/address/templates/address/create_update_form.html index 0b64d4f..0312659 100644 --- a/address/templates/address/create_update_form.html +++ b/address/templates/address/create_update_form.html @@ -1,8 +1,10 @@ -{% extends 'address/base.html' %} +{% extends 'base.html' %} {% block content %}
{% csrf_token %} {{ form.as_p }}
+ cancel + {% endblock %} diff --git a/address/templates/address/delete_form.html b/address/templates/address/delete_form.html index 47901ce..452edf9 100644 --- a/address/templates/address/delete_form.html +++ b/address/templates/address/delete_form.html @@ -1,4 +1,4 @@ -{% extends 'address/base.html' %} +{% extends 'base.html' %} {% block content %}
@@ -6,6 +6,6 @@

Are you sure to delete address ({{ object.state }} | {{ object.area }})?

- cancel + cancel
{% endblock %} From 857f23eb17a8c23985234aff3d685b12363e51e3 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:38:08 +0430 Subject: [PATCH 240/439] Fix(address/views): customer create address view fixed --- .../address/customer_address_list.html | 22 ++++++++++++------- address/views.py | 21 +++++++++--------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/address/templates/address/customer_address_list.html b/address/templates/address/customer_address_list.html index 7b87af0..a3e7908 100644 --- a/address/templates/address/customer_address_list.html +++ b/address/templates/address/customer_address_list.html @@ -1,13 +1,19 @@ {% extends 'base.html' %} {% block content %} -
    - {% for address in addresses %} -
  • + Create new address

    + +
      + {% for address in addresses %} +
    • {{ address.state.name }} - {{ address.city.name }} - {{ address.area.name }} - {{ address.street }} - {{ address.alley }} - {{ address.floor }} - {{ address.plaque }} - Update - Delete -
    • - {% endfor %} -
    +
    + Update + Delete +
    +
  • + {% endfor %} +
{% endblock %} diff --git a/address/views.py b/address/views.py index 268f67e..2c4567a 100644 --- a/address/views.py +++ b/address/views.py @@ -25,7 +25,7 @@ class CustomerAddressCreateView(BaseAddress, IsCustomer, CreateView): def form_valid(self, form): instance = form.save(commit=False) - instance.user = self.request.user + instance.customer_user = self.request.user instance.save() return super().form_valid(form) @@ -58,6 +58,16 @@ def test_func(self): return result and obj.customer_user == self.request.user +@method_decorator(login_required(login_url=reverse_lazy('accounts:customer-login-register')), name='dispatch') +class CustomerAddressListView(ListView): + model = CustomerAddress + template_name = 'address/customer_address_list.html' + context_object_name = 'addresses' + + def get_queryset(self): + return super().get_queryset().filter(customer_user=self.request.user) + + @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') class ServiceAddressCreateView(CustomUserPasses, CreateView): model = ServiceAddress @@ -98,12 +108,3 @@ def test_func(self): result = super().test_func() obj = self.get_object() return result and obj.services.service_provider == self.request.user - - -class CustomerAddressListView(ListView): - model = CustomerAddress - template_name = 'address/customer_address_list.html' - context_object_name = 'addresses' - - def get_queryset(self): - return super().get_queryset().filter(customer_user=self.request.user) From f6d78dabf50cdb00e7cafe41713c5215d4aa961d Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Tue, 31 Aug 2021 19:38:46 +0430 Subject: [PATCH 241/439] Style(accouns/templates): update template --- accounts/templates/accounts/customer/profile.html | 1 + 1 file changed, 1 insertion(+) diff --git a/accounts/templates/accounts/customer/profile.html b/accounts/templates/accounts/customer/profile.html index 88b2497..ef45936 100644 --- a/accounts/templates/accounts/customer/profile.html +++ b/accounts/templates/accounts/customer/profile.html @@ -7,6 +7,7 @@

Profile

Last name : {{ request.user.last_name }}


Address list

+ Create new address

Update profile

From aad810f77e813deb36a00845d7f315fe6df9c575 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 08:44:23 +0430 Subject: [PATCH 242/439] Update(item/models): overrider the save method of Item model --- item/models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/item/models.py b/item/models.py index 3e3da34..5d66803 100644 --- a/item/models.py +++ b/item/models.py @@ -30,6 +30,14 @@ class Meta: def __str__(self): return self.name + def save(self, *args, **kwargs): + """ + create a ItemLine instance and map it to this item + when it hasn't any one yet + """ + if not ItemLine.objects.filter(item=self).exists(): + ItemLine.objects.create(item=self) + @property def stock(self): return self.line.quantity From e50103be000e0c7c214251bfe6766b978702e20e Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 08:49:22 +0430 Subject: [PATCH 243/439] (item/urls, snapp_food/urls): add urls to item app and include it to project --- item/urls.py | 5 +++++ snapp_food/urls.py | 1 + 2 files changed, 6 insertions(+) create mode 100644 item/urls.py diff --git a/item/urls.py b/item/urls.py new file mode 100644 index 0000000..4c538ca --- /dev/null +++ b/item/urls.py @@ -0,0 +1,5 @@ +app_name = 'item' + +urlpatterns = [ + +] \ No newline at end of file diff --git a/snapp_food/urls.py b/snapp_food/urls.py index df7d83f..74f4b14 100644 --- a/snapp_food/urls.py +++ b/snapp_food/urls.py @@ -22,4 +22,5 @@ path('home/', TemplateView.as_view(template_name='base.html'), name='home'), path('accounts/', include('accounts.urls', namespace='accounts')), path('address/', include('address.urls', namespace='address')), + path('item/', include('item.urls', namespace='item')) ] From e5a6bf4638e8043f3efae4750ea31c44f1e5e6fa Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 09:50:53 +0430 Subject: [PATCH 244/439] Add(item/views, forms): add CreateItemForm and CreateItemView classes --- item/forms.py | 12 ++++++++++++ item/models.py | 12 ++++++++++-- item/views.py | 19 +++++++++++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 item/forms.py diff --git a/item/forms.py b/item/forms.py new file mode 100644 index 0000000..cca5534 --- /dev/null +++ b/item/forms.py @@ -0,0 +1,12 @@ +from django import forms + +from item.models import Item + + +class ItemCreateForm(forms.ModelForm): + class Meta: + service_id = forms.IntegerField(widget=forms.HiddenInput) + category_id = forms.IntegerField(widget=forms.HiddenInput) + quantity = forms.IntegerField(initial=0) + model = Item + fields = ('name', 'price', 'description', 'available', 'image') diff --git a/item/models.py b/item/models.py index 5d66803..7f94a87 100644 --- a/item/models.py +++ b/item/models.py @@ -1,3 +1,6 @@ +import random +import string + from django.db import models from django.utils.translation import gettext as _ @@ -30,13 +33,18 @@ class Meta: def __str__(self): return self.name - def save(self, *args, **kwargs): + def save(self, force_insert=False, force_update=False, using=None, + update_fields=None): """ - create a ItemLine instance and map it to this item + create an ItemLine instance and map it to this item when it hasn't any one yet """ + if force_insert: + random_digits = ''.join(random.choice(string.digits) for _ in range(5)) + self.upc = int(random_digits) if not ItemLine.objects.filter(item=self).exists(): ItemLine.objects.create(item=self) + return super().save(force_insert, force_update, using, update_fields) @property def stock(self): diff --git a/item/views.py b/item/views.py index 91ea44a..0e3bba6 100644 --- a/item/views.py +++ b/item/views.py @@ -1,3 +1,18 @@ -from django.shortcuts import render +from django.views.generic import FormView -# Create your views here. +from item.forms import ItemCreateForm +from item.models import Item + + +class CreatItemView(FormView): + model = Item + form_class = ItemCreateForm + template_name = 'item/create_form.html' + + def form_valid(self, form): + item = form.save(commit=False) + item.service_id = form.cleaned_data['service_id'] + item.category_id = form.cleaned_data['category_id'] + item.line.quantity += form.cleaned_data['quantity'] + item.save() + return super().form_valid(form) From 150fcdf83a2134422c45ebb87db136711f6abcdc Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 09:54:43 +0430 Subject: [PATCH 245/439] Add(templates/item): add create_form.html --- item/templates/item/create_form.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 item/templates/item/create_form.html diff --git a/item/templates/item/create_form.html b/item/templates/item/create_form.html new file mode 100644 index 0000000..935a4f7 --- /dev/null +++ b/item/templates/item/create_form.html @@ -0,0 +1,22 @@ +{% extends 'base.html' %} +{% block title %} Add item {% endblock %} +{% block content %} +

Add new item

+
+ {% csrf_token %} + {% for field in form %} + +
+

{{ field }}

+ {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% if form.errors %} + {% block form_error %} {% endblock %} + {% endif %} + + +
+{% endblock %} \ No newline at end of file From 719370ba8cf15cdeb7eacdb8e592c4859a7064af Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 10:11:06 +0430 Subject: [PATCH 246/439] Update(item/views): add test_func for CreatItemView --- item/views.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/item/views.py b/item/views.py index 0e3bba6..0eeeae2 100644 --- a/item/views.py +++ b/item/views.py @@ -1,18 +1,36 @@ +from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404 +from django.urls import reverse_lazy +from django.utils.decorators import method_decorator from django.views.generic import FormView +from accounts.utils import IsServiceProvider from item.forms import ItemCreateForm from item.models import Item +from service.models import Service, ServiceCategory -class CreatItemView(FormView): +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') +class CreatItemView(IsServiceProvider, FormView): model = Item form_class = ItemCreateForm template_name = 'item/create_form.html' + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + self.kwargs['service'] = get_object_or_404(Service, id=self.kwargs['service_pk']) + self.kwargs['category'] = get_object_or_404(ServiceCategory, id=self.kwargs['category_pk']) + def form_valid(self, form): item = form.save(commit=False) - item.service_id = form.cleaned_data['service_id'] - item.category_id = form.cleaned_data['category_id'] + item.service = self.kwargs['service'] + item.category = self.kwargs['category'] item.line.quantity += form.cleaned_data['quantity'] item.save() return super().form_valid(form) + + def test_func(self): + result = super().test_func() + service_check = self.kwargs['service'].service_provider == self.request.user + category_check = self.kwargs['category'].service == self.kwargs['service'] + return result and service_check and category_check From f90b0f85e011fbe7543c4a02cb21283132a1d15d Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 10:48:29 +0430 Subject: [PATCH 247/439] Add(item/views, forms): add ItemUpdatForm and ItemUpdateView --- item/forms.py | 15 +++++++++++++-- item/models.py | 1 + item/views.py | 24 +++++++++++++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/item/forms.py b/item/forms.py index cca5534..76e30bc 100644 --- a/item/forms.py +++ b/item/forms.py @@ -1,12 +1,23 @@ from django import forms from item.models import Item +from service.models import ServiceCategory class ItemCreateForm(forms.ModelForm): class Meta: - service_id = forms.IntegerField(widget=forms.HiddenInput) - category_id = forms.IntegerField(widget=forms.HiddenInput) quantity = forms.IntegerField(initial=0) model = Item fields = ('name', 'price', 'description', 'available', 'image') + + +class ItemUpdateForm(forms.ModelForm): + class Meta: + quantity = forms.IntegerField() + model = Item + fields = ('category', 'name', 'price', 'description', 'available', 'image') + + def __init__(self, service=None, *args, **kwargs): + super().__init__(service, *args, **kwargs) + if service: + self.fields['category'].queryset = ServiceCategory.objects.filter(service=service) diff --git a/item/models.py b/item/models.py index 7f94a87..aff603b 100644 --- a/item/models.py +++ b/item/models.py @@ -59,3 +59,4 @@ class Meta: verbose_name = _('Item line') verbose_name_plural = _('Item lines') db_table = 'item_line' + diff --git a/item/views.py b/item/views.py index 0eeeae2..7508052 100644 --- a/item/views.py +++ b/item/views.py @@ -2,16 +2,16 @@ from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from django.utils.decorators import method_decorator -from django.views.generic import FormView +from django.views.generic import FormView, UpdateView from accounts.utils import IsServiceProvider -from item.forms import ItemCreateForm +from item.forms import ItemCreateForm, ItemUpdateForm from item.models import Item from service.models import Service, ServiceCategory @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') -class CreatItemView(IsServiceProvider, FormView): +class ItemCreateView(IsServiceProvider, FormView): model = Item form_class = ItemCreateForm template_name = 'item/create_form.html' @@ -34,3 +34,21 @@ def test_func(self): service_check = self.kwargs['service'].service_provider == self.request.user category_check = self.kwargs['category'].service == self.kwargs['service'] return result and service_check and category_check + + +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') +class ItemUpdateView(IsServiceProvider, UpdateView): + model = Item + template_name = None + + def test_func(self): + result = super().test_func() + return result and self.object.service.service_provider == self.request.user + + def get_form_class(self): + return ItemUpdateForm(service=self.object.service) + + def get_initial(self): + initial = super().get_initial() + initial['quantity'] = self.object.stock + return initial From e93544d2c0badd5a4233e86e8d97816dfc82c4bb Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 10:51:40 +0430 Subject: [PATCH 248/439] Update(item/urls): add update url --- item/urls.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/item/urls.py b/item/urls.py index 4c538ca..b7c5fa7 100644 --- a/item/urls.py +++ b/item/urls.py @@ -1,5 +1,8 @@ +from django.urls import path +from item.views import ItemUpdateView + app_name = 'item' urlpatterns = [ - -] \ No newline at end of file + path('update//', ItemUpdateView.as_view(), name='update'), +] From 3d02ec39ac56e3749ae3e620b52b8dd220b98624 Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 11:12:50 +0430 Subject: [PATCH 249/439] Add(item/views): add ItemDetailView --- item/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/item/views.py b/item/views.py index 7508052..f287e2e 100644 --- a/item/views.py +++ b/item/views.py @@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from django.utils.decorators import method_decorator -from django.views.generic import FormView, UpdateView +from django.views.generic import FormView, UpdateView, DetailView from accounts.utils import IsServiceProvider from item.forms import ItemCreateForm, ItemUpdateForm @@ -52,3 +52,9 @@ def get_initial(self): initial = super().get_initial() initial['quantity'] = self.object.stock return initial + + +class ItemDetailView(DetailView): + model = Item + template_name = None + context_object_name = 'item' From 625d0daedb8fe5d5bcd364757eff0743352b784c Mon Sep 17 00:00:00 2001 From: AmirHossein Bonakdar Date: Wed, 1 Sep 2021 11:16:47 +0430 Subject: [PATCH 250/439] Update(item/views): add get_queryset method to ItemDetailVies --- item/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/item/views.py b/item/views.py index f287e2e..99c1303 100644 --- a/item/views.py +++ b/item/views.py @@ -58,3 +58,6 @@ class ItemDetailView(DetailView): model = Item template_name = None context_object_name = 'item' + + def get_queryset(self): + return Item.objects.available() From e0bc25b42997c7de6408c831068050a29da1bfa7 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 11:32:38 +0430 Subject: [PATCH 251/439] Add(service/forms): create forms file --- service/forms.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 service/forms.py diff --git a/service/forms.py b/service/forms.py new file mode 100644 index 0000000..e69de29 From 32030564f5f24487789e2263291bb277ad091185 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 11:32:57 +0430 Subject: [PATCH 252/439] Add(service/urls): create urls file --- service/urls.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 service/urls.py diff --git a/service/urls.py b/service/urls.py new file mode 100644 index 0000000..e69de29 From b2ce81941542fe425c0f783257308f7a2bd38d7b Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:00:21 +0430 Subject: [PATCH 253/439] Add(urls): including service urls in base urls --- snapp_food/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/snapp_food/urls.py b/snapp_food/urls.py index df7d83f..0f20d9f 100644 --- a/snapp_food/urls.py +++ b/snapp_food/urls.py @@ -21,5 +21,6 @@ path('admin/', admin.site.urls), path('home/', TemplateView.as_view(template_name='base.html'), name='home'), path('accounts/', include('accounts.urls', namespace='accounts')), + path('service/', include('service.urls', namespace='service')), path('address/', include('address.urls', namespace='address')), ] From 0b8160030a6029bb0b16d33c301f54f092895780 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:00:54 +0430 Subject: [PATCH 254/439] Add(service/forms): create service create form --- service/forms.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/service/forms.py b/service/forms.py index e69de29..66de66b 100644 --- a/service/forms.py +++ b/service/forms.py @@ -0,0 +1,14 @@ +from django import forms + +from service.models import Service + + +class ServiceCreateForm(forms.ModelForm): + class Meta: + model = Service + fields = ('name', 'service_type', 'minimum_purchase') + widgets = { + 'name': forms.TextInput(attrs={'class': 'form-control'}), + 'service_type': forms.Select(attrs={'class': 'form-control'}), + 'minimum_purchase': forms.NumberInput(attrs={'class': 'form-control'}), + } From ee59f0f8e9e9a5a1889fd78b32e172edf3a39016 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:02:53 +0430 Subject: [PATCH 255/439] Style(service/templates): make service create template --- service/templates/service/create_form.html | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 service/templates/service/create_form.html diff --git a/service/templates/service/create_form.html b/service/templates/service/create_form.html new file mode 100644 index 0000000..52851e7 --- /dev/null +++ b/service/templates/service/create_form.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} +{% block content %} +
+ {% csrf_token %} + {{ form.as_p }} + +
+ cancel +{% endblock %} From ab67b6e662fcb7419949a6d99e2d1125933e5715 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:03:23 +0430 Subject: [PATCH 256/439] Add(service/views): create service create view --- service/views.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/service/views.py b/service/views.py index 91ea44a..a85e92f 100644 --- a/service/views.py +++ b/service/views.py @@ -1,3 +1,22 @@ -from django.shortcuts import render +from django.contrib.auth.decorators import login_required +from django.urls import reverse_lazy +from django.utils.decorators import method_decorator +from django.views.generic import CreateView -# Create your views here. +from accounts.utils import IsServiceProvider +from service.forms import ServiceCreateForm +from service.models import Service + + +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') +class ServiceCreateView(IsServiceProvider, CreateView): + model = Service + form_class = ServiceCreateForm + template_name = 'service/create_form.html' + success_url = reverse_lazy('accounts:service-provider-profile') + + def form_valid(self, form): + instance = form.save(commit=False) + instance.service_provider = self.request.user + instance.save() + return super().form_valid(form) From 92e8a90314928bef93020ad6aed01095822ae0f8 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:03:48 +0430 Subject: [PATCH 257/439] Add(service/urls): create service create url --- service/urls.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/service/urls.py b/service/urls.py index e69de29..854bf88 100644 --- a/service/urls.py +++ b/service/urls.py @@ -0,0 +1,9 @@ +from django.urls import path + +from .views import ServiceCreateView + +app_name = 'service' + +urlpatterns = ( + path('create/', ServiceCreateView.as_view(), name='service-create'), +) From 097652a22184a0e0a5e102902648d97783518f95 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:18:26 +0430 Subject: [PATCH 258/439] Style(service/templates): create service list template --- service/templates/service/list.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 service/templates/service/list.html diff --git a/service/templates/service/list.html b/service/templates/service/list.html new file mode 100644 index 0000000..b615f9e --- /dev/null +++ b/service/templates/service/list.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} +{% block content %} +
    + {% for service in services %} +
  • + {{ service.name }} +
    + Update + Delete +
    +
  • + {% endfor %} +
+{% endblock %} From c9649f38483924de6a2285e38e5d68b1c0347457 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:25:43 +0430 Subject: [PATCH 259/439] Add(service/views): create service list view --- service/views.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/service/views.py b/service/views.py index a85e92f..59c485c 100644 --- a/service/views.py +++ b/service/views.py @@ -1,7 +1,7 @@ from django.contrib.auth.decorators import login_required from django.urls import reverse_lazy from django.utils.decorators import method_decorator -from django.views.generic import CreateView +from django.views.generic import CreateView, ListView from accounts.utils import IsServiceProvider from service.forms import ServiceCreateForm @@ -20,3 +20,13 @@ def form_valid(self, form): instance.service_provider = self.request.user instance.save() return super().form_valid(form) + + +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') +class ServiceListView(IsServiceProvider, ListView): + model = Service + context_object_name = 'services' + template_name = 'service/list.html' + + def get_queryset(self): + return super().get_queryset().filter(service_provider=self.request.user) From 41d3ab2294937d64094751e600b32744b1cb91f6 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:26:12 +0430 Subject: [PATCH 260/439] Add(service/urls): create service list url --- service/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service/urls.py b/service/urls.py index 854bf88..53afce3 100644 --- a/service/urls.py +++ b/service/urls.py @@ -1,9 +1,10 @@ from django.urls import path -from .views import ServiceCreateView +from .views import ServiceCreateView, ServiceListView app_name = 'service' urlpatterns = ( path('create/', ServiceCreateView.as_view(), name='service-create'), + path('list/', ServiceListView.as_view(), name='service-list'), ) From 5ca6cb9894fca8b48f18bcfcd02aa14acc9386d2 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:46:29 +0430 Subject: [PATCH 261/439] Refactor(service/views): rename service create form --- service/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/forms.py b/service/forms.py index 66de66b..38f91c7 100644 --- a/service/forms.py +++ b/service/forms.py @@ -3,7 +3,7 @@ from service.models import Service -class ServiceCreateForm(forms.ModelForm): +class ServiceCreateUpdateForm(forms.ModelForm): class Meta: model = Service fields = ('name', 'service_type', 'minimum_purchase') From 5b311cc7554f402983b79fbd9a7f6e5f8078a885 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:49:42 +0430 Subject: [PATCH 262/439] Add(service/views): create service update view --- service/views.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/service/views.py b/service/views.py index 59c485c..b33d70d 100644 --- a/service/views.py +++ b/service/views.py @@ -1,17 +1,17 @@ from django.contrib.auth.decorators import login_required from django.urls import reverse_lazy from django.utils.decorators import method_decorator -from django.views.generic import CreateView, ListView +from django.views.generic import CreateView, ListView, UpdateView from accounts.utils import IsServiceProvider -from service.forms import ServiceCreateForm +from service.forms import ServiceCreateUpdateForm from service.models import Service @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') class ServiceCreateView(IsServiceProvider, CreateView): model = Service - form_class = ServiceCreateForm + form_class = ServiceCreateUpdateForm template_name = 'service/create_form.html' success_url = reverse_lazy('accounts:service-provider-profile') @@ -22,6 +22,19 @@ def form_valid(self, form): return super().form_valid(form) +@method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') +class ServiceUpdateView(IsServiceProvider, UpdateView): + model = Service + form_class = ServiceCreateUpdateForm + template_name = 'service/create_form.html' + success_url = reverse_lazy('service:service-list') + + def test_func(self): + result = super().test_func() + obj = self.get_object() + return obj.service_provider == self.request.user and result + + @method_decorator(login_required(login_url=reverse_lazy('accounts:service-provider-login')), name='dispatch') class ServiceListView(IsServiceProvider, ListView): model = Service From b0f922f0a6878b0ef94b5d41c5b4223d5019dc9b Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:52:04 +0430 Subject: [PATCH 263/439] Style(service/templates): refactor templates --- service/templates/service/list.html | 2 +- .../{create_form.html => service_create_update_form.html} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename service/templates/service/{create_form.html => service_create_update_form.html} (100%) diff --git a/service/templates/service/list.html b/service/templates/service/list.html index b615f9e..aab2764 100644 --- a/service/templates/service/list.html +++ b/service/templates/service/list.html @@ -5,7 +5,7 @@
  • {{ service.name }}
  • diff --git a/service/templates/service/create_form.html b/service/templates/service/service_create_update_form.html similarity index 100% rename from service/templates/service/create_form.html rename to service/templates/service/service_create_update_form.html From 54a6b63495874742ea6b8259d188cb4f058f1060 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:52:56 +0430 Subject: [PATCH 264/439] Refactor(service/views): rename template name --- service/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/views.py b/service/views.py index b33d70d..b45cb54 100644 --- a/service/views.py +++ b/service/views.py @@ -12,7 +12,7 @@ class ServiceCreateView(IsServiceProvider, CreateView): model = Service form_class = ServiceCreateUpdateForm - template_name = 'service/create_form.html' + template_name = 'service/service_create_update_form.html' success_url = reverse_lazy('accounts:service-provider-profile') def form_valid(self, form): @@ -26,7 +26,7 @@ def form_valid(self, form): class ServiceUpdateView(IsServiceProvider, UpdateView): model = Service form_class = ServiceCreateUpdateForm - template_name = 'service/create_form.html' + template_name = 'service/service_create_update_form.html' success_url = reverse_lazy('service:service-list') def test_func(self): From 1c713c4066a9e179683c6cd480ebfc2d4df7f758 Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 12:53:23 +0430 Subject: [PATCH 265/439] Add(service/urls): create service update url --- service/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service/urls.py b/service/urls.py index 53afce3..4d1060b 100644 --- a/service/urls.py +++ b/service/urls.py @@ -1,10 +1,11 @@ from django.urls import path -from .views import ServiceCreateView, ServiceListView +from .views import ServiceCreateView, ServiceUpdateView, ServiceListView app_name = 'service' urlpatterns = ( path('create/', ServiceCreateView.as_view(), name='service-create'), + path('update/', ServiceUpdateView.as_view(), name='service-update'), path('list/', ServiceListView.as_view(), name='service-list'), ) From a47f305b6e83a82cbd23176b6aeff3157072753b Mon Sep 17 00:00:00 2001 From: MrMohammadY Date: Wed, 1 Sep 2021 13:06:19 +0430 Subject: [PATCH 266/439] Style(service/templates): update service list templates --- ...ice_create_update_form.html => create_update_form.html} | 2 +- service/templates/service/list.html | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) rename service/templates/service/{service_create_update_form.html => create_update_form.html} (65%) diff --git a/service/templates/service/service_create_update_form.html b/service/templates/service/create_update_form.html similarity index 65% rename from service/templates/service/service_create_update_form.html rename to service/templates/service/create_update_form.html index 52851e7..88347ae 100644 --- a/service/templates/service/service_create_update_form.html +++ b/service/templates/service/create_update_form.html @@ -5,5 +5,5 @@ {{ form.as_p }} - cancel + cancel {% endblock %} diff --git a/service/templates/service/list.html b/service/templates/service/list.html index aab2764..b40b4c4 100644 --- a/service/templates/service/list.html +++ b/service/templates/service/list.html @@ -1,12 +1,15 @@ {% extends 'base.html' %} {% block content %} + Create new service