From 40ae30e6e20ac8009a6b1dc193316cfebe2f94a6 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Sun, 10 Mar 2024 03:03:50 +0330 Subject: [PATCH 01/46] create-dev --- .gitignore | 285 ++++++++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 3 + 2 files changed, 288 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f5a046 --- /dev/null +++ b/.gitignore @@ -0,0 +1,285 @@ +# Created by https://www.toptal.com/developers/gitignore/api/django,python,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=django,python,visualstudiocode + +### Django ### +*.log +*.pot +*.pyc +__pycache__/ +local_settings.py +db.sqlite3 +db.sqlite3-journal +media + +# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ +# in your Git repository. Update and uncomment the following line accordingly. +# /staticfiles/ + +### Django.Python Stack ### +# Byte-compiled / optimized / DLL files +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo + +# Django stuff: + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python ### +# Byte-compiled / optimized / DLL files + +# C extensions + +# Distribution / packaging + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. + +# Installer logs + +# Unit test / coverage reports + +# Translations + +# Django stuff: + +# Flask stuff: + +# Scrapy stuff: + +# Sphinx documentation + +# PyBuilder + +# Jupyter Notebook + +# IPython + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm + +# Celery stuff + +# SageMath parsed files + +# Environments + +# Spyder project settings + +# Rope project settings + +# mkdocs documentation + +# mypy + +# Pyre type checker + +# pytype static type analyzer + +# Cython debug symbols + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/django,python,visualstudiocode diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cee4243 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "iis.configDir": "" +} \ No newline at end of file From f4a79889a84012301f7fbf365e2b2edd068790c9 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 13 Mar 2024 04:48:32 +0330 Subject: [PATCH 02/46] fit/UserModle --- BackEnd/.vscode/settings.json | 3 + BackEnd/BackEnd/__init__.py | 0 BackEnd/BackEnd/asgi.py | 16 +++ BackEnd/BackEnd/settings.py | 134 ++++++++++++++++++ BackEnd/BackEnd/urls.py | 23 +++ BackEnd/BackEnd/wsgi.py | 16 +++ BackEnd/accounts/__init__.py | 0 BackEnd/accounts/admin.py | 69 +++++++++ BackEnd/accounts/apps.py | 6 + BackEnd/accounts/migrations/0001_initial.py | 48 +++++++ .../migrations/0002_remove_user_datee.py | 14 ++ BackEnd/accounts/migrations/__init__.py | 0 BackEnd/accounts/models.py | 100 +++++++++++++ BackEnd/accounts/serializers.py | 7 + BackEnd/accounts/tests.py | 3 + BackEnd/accounts/urls.py | 5 + BackEnd/accounts/views.py | 3 + BackEnd/manage.py | 22 +++ 18 files changed, 469 insertions(+) create mode 100644 BackEnd/.vscode/settings.json create mode 100644 BackEnd/BackEnd/__init__.py create mode 100644 BackEnd/BackEnd/asgi.py create mode 100644 BackEnd/BackEnd/settings.py create mode 100644 BackEnd/BackEnd/urls.py create mode 100644 BackEnd/BackEnd/wsgi.py create mode 100644 BackEnd/accounts/__init__.py create mode 100644 BackEnd/accounts/admin.py create mode 100644 BackEnd/accounts/apps.py create mode 100644 BackEnd/accounts/migrations/0001_initial.py create mode 100644 BackEnd/accounts/migrations/0002_remove_user_datee.py create mode 100644 BackEnd/accounts/migrations/__init__.py create mode 100644 BackEnd/accounts/models.py create mode 100644 BackEnd/accounts/serializers.py create mode 100644 BackEnd/accounts/tests.py create mode 100644 BackEnd/accounts/urls.py create mode 100644 BackEnd/accounts/views.py create mode 100644 BackEnd/manage.py diff --git a/BackEnd/.vscode/settings.json b/BackEnd/.vscode/settings.json new file mode 100644 index 0000000..cee4243 --- /dev/null +++ b/BackEnd/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "iis.configDir": "" +} \ No newline at end of file diff --git a/BackEnd/BackEnd/__init__.py b/BackEnd/BackEnd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/BackEnd/asgi.py b/BackEnd/BackEnd/asgi.py new file mode 100644 index 0000000..4a251ee --- /dev/null +++ b/BackEnd/BackEnd/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for BackEnd 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/5.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BackEnd.settings") + +application = get_asgi_application() diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py new file mode 100644 index 0000000..1d4c1c4 --- /dev/null +++ b/BackEnd/BackEnd/settings.py @@ -0,0 +1,134 @@ +""" +Django settings for BackEnd project. + +Generated by 'django-admin startproject' using Django 5.0.3. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.0/ref/settings/ +""" + +from pathlib import Path + +# 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/5.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-#zdhi36fsv(lx#%swqp(l9)0dctgcmwqc__*6h5$9gk@sqxn-e" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES' : [ + 'rest_framework.permissions.AllowAny' + ], + # 'DEFAULT_AUTHENTICATION_CLASSES' : [ + # 'rest_framework_simplejwt.authentication.JWTAuthentication', + # ] +} +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "accounts", + "rest_framework", +] + +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 = "BackEnd.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 = "BackEnd.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/5.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.0/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/5.0/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.0/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +AUTH_USER_MODEL = 'accounts.User' +AUTH_PROFILE_MODULE = 'accounts.User' + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.RemoteUserBackend', + 'django.contrib.auth.backends.ModelBackend', +) \ No newline at end of file diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py new file mode 100644 index 0000000..de8fa15 --- /dev/null +++ b/BackEnd/BackEnd/urls.py @@ -0,0 +1,23 @@ +""" +URL configuration for BackEnd project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.0/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 , include + +urlpatterns = [ + path("admin/", admin.site.urls), + # path("accounts/" , include("accounts.urls")) +] diff --git a/BackEnd/BackEnd/wsgi.py b/BackEnd/BackEnd/wsgi.py new file mode 100644 index 0000000..feb5fb1 --- /dev/null +++ b/BackEnd/BackEnd/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for BackEnd 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/5.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BackEnd.settings") + +application = get_wsgi_application() diff --git a/BackEnd/accounts/__init__.py b/BackEnd/accounts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/accounts/admin.py b/BackEnd/accounts/admin.py new file mode 100644 index 0000000..ffa2a97 --- /dev/null +++ b/BackEnd/accounts/admin.py @@ -0,0 +1,69 @@ +from django.contrib import admin +from django.contrib.auth.models import Group +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.forms import ReadOnlyPasswordHashField +from django.core.exceptions import ValidationError +from django import forms +from .models import User + + +class UserCreationForm(forms.ModelForm): + password1 = forms.CharField(label='Password', widget=forms.PasswordInput) + password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) + + class Meta: + model = User + fields = ('email', 'date_of_birth', 'gender' , 'firstname' , 'lastname') + + def clean_password2(self): + # Check that the two password entries match + password1 = self.cleaned_data.get("password1") + password2 = self.cleaned_data.get("password2") + if password1 and password2 and password1 != password2: + raise ValidationError("Passwords don't match") + return password2 + + def save(self, commit=True): + # Save the provided password in hashed format + user = super().save(commit=False) + user.set_password(self.cleaned_data["password1"]) + if commit: + user.save() + return user + + +class UserChangeForm(forms.ModelForm): + password = ReadOnlyPasswordHashField() + + class Meta: + model = User + fields = ('firstname' , 'lastname' , 'gender','email', 'password', 'date_of_birth', 'is_active', 'is_admin') + + def clean_password(self): + return self.initial["password"] + + +class UserAdmin(BaseUserAdmin): + form = UserChangeForm + add_form= UserCreationForm + list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active') #'is_email_verified' + list_filter = ('is_admin' , 'email' ,'firstname', 'lastname') + fieldsets=( + (None, {'fields': ('email', 'password')}), + ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender')}), + ('Permissions', {'fields': ( 'is_admin', 'is_active', )}), #'is_email_verified' + ) + + add_fieldsets = ( + (None, { + 'classes': ('wide',), + 'fields': ('email', 'date_of_birth', 'password1', 'password2', 'is_active' ), + }), + ) + + search_fields = ('email',) + ordering = ('email',) + filter_horizontal = () + +admin.site.register(User, UserAdmin) + diff --git a/BackEnd/accounts/apps.py b/BackEnd/accounts/apps.py new file mode 100644 index 0000000..0cb51e6 --- /dev/null +++ b/BackEnd/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/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..cebdce7 --- /dev/null +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 5.0.3 on 2024-03-12 23:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="User", + 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" + ), + ), + ("firstname", models.CharField(max_length=20)), + ("lastname", models.CharField(max_length=30)), + ("email", models.EmailField(max_length=255, unique=True)), + ("datee", models.DateField()), + ("date_of_birth", models.DateField()), + ("is_active", models.BooleanField(default=True)), + ("is_admin", models.BooleanField(default=False)), + ( + "gender", + models.CharField( + choices=[("F", "Female"), ("M", "Male")], max_length=1 + ), + ), + ], + options={"abstract": False,}, + ), + ] diff --git a/BackEnd/accounts/migrations/0002_remove_user_datee.py b/BackEnd/accounts/migrations/0002_remove_user_datee.py new file mode 100644 index 0000000..8fb0aa6 --- /dev/null +++ b/BackEnd/accounts/migrations/0002_remove_user_datee.py @@ -0,0 +1,14 @@ +# Generated by Django 5.0.3 on 2024-03-12 23:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0001_initial"), + ] + + operations = [ + migrations.RemoveField(model_name="user", name="datee",), + ] diff --git a/BackEnd/accounts/migrations/__init__.py b/BackEnd/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py new file mode 100644 index 0000000..383fe91 --- /dev/null +++ b/BackEnd/accounts/models.py @@ -0,0 +1,100 @@ +from django.db import models +from django.contrib.contenttypes.fields import GenericRelation +from django.core.validators import MinLengthValidator, MaxLengthValidator +from django.db import models +from django.contrib.auth.models import AbstractBaseUser , BaseUserManager +import datetime + + +class UserManager(BaseUserManager): + def create_user(self , email , firstname , lastname , gender , date_of_birth, password=None ) : + """ + Creates and saves a User with the given email, + data of birth and password + """ + if not email: + raise ValueError('User must have an email address') + + user = self.model( + email = self.normalize_email(email), + date_of_birth = date_of_birth, + firstname = firstname , + lastname = lastname, + gender= gender, + ) + + user.set_password(password) + user.save(using=self._db) + return user + + def create_superuser(self , email , firstname , lastname , gender , date_of_birth , password=None): + """ + Creates and saves a superuser with the given email, birthdat + and password. + """ + + user = self.create_user( + email=email, + password=password, + date_of_birth=date_of_birth, + firstname = firstname , + lastname = lastname, + gender= gender, + ) + + user.is_admin = True + user.is_superuser = True + user.save(using=self._db) + return user + + def get_by_natural_key(self, email): + return self.get(email=email) + +class User(AbstractBaseUser): + GENDER_Male = 'M' + GENDER_Female = 'F' + GENDER_CHOICES = [ + (GENDER_Female, 'Female'), + (GENDER_Male, 'Male'), + ] + + firstname = models.CharField(max_length=20 ) + lastname = models.CharField(max_length=30 ) + email = models.EmailField( + max_length= 255 , + unique = True, + ) + USERNAME_FIELD = 'email' + REQUIRED_FIELDS = ['date_of_birth' , 'firstname' , 'lastname' , 'gender'] + date_of_birth= models.DateField() + gender = models.CharField(max_length=1, choices=GENDER_CHOICES) + is_active = models.BooleanField(default=True) + is_admin = models.BooleanField(default=False) + objects = UserManager() + # verification_code = models.CharField(max_length=4, null=True, blank=True) + # verification_tries_count = models.IntegerField(default=0) + # last_verification_sent = models.DateTimeField(null=True, blank=True, default=datetime.now) + # has_verification_tries_reset = models.BooleanField(default=False) + + def __str__(self): + return self.email + + def has_perm(self , perm , obj=None ): + "Does the user have a specific permisision?" + return True + + def has_module_perms(self, app_label): + "Does the user have permissions to view the app `app_label`?" + # Simplest possible answer: Yes, always + return True + + @property + def is_staff(self): + "Is the user a member of staff?" + # Simplest possible answer: All admins are staff + return self.is_admin + + + + + \ No newline at end of file diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py new file mode 100644 index 0000000..732182a --- /dev/null +++ b/BackEnd/accounts/serializers.py @@ -0,0 +1,7 @@ +from rest_framework import serializers +from accounts.models import User + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" ] diff --git a/BackEnd/accounts/tests.py b/BackEnd/accounts/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BackEnd/accounts/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BackEnd/accounts/urls.py b/BackEnd/accounts/urls.py new file mode 100644 index 0000000..023fbb2 --- /dev/null +++ b/BackEnd/accounts/urls.py @@ -0,0 +1,5 @@ + + +urlpatterns = [ + +] \ No newline at end of file diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/BackEnd/accounts/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/BackEnd/manage.py b/BackEnd/manage.py new file mode 100644 index 0000000..62c39b8 --- /dev/null +++ b/BackEnd/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", "BackEnd.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() From 9f3549da0586254a63cd168f02256c71e13700b7 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 13 Mar 2024 04:53:04 +0330 Subject: [PATCH 03/46] fir/UserModel --- requirements.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..675344b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +asgiref==3.7.2 +certifi==2024.2.2 +charset-normalizer==3.3.2 +Django==5.0.3 +djangorestframework==3.14.0 +djangorestframework-simplejwt==5.3.1 +idna==3.6 +PyJWT==2.8.0 +pytz==2024.1 +requests==2.31.0 +sqlparse==0.4.4 +typing_extensions==4.10.0 +tzdata==2024.1 +urllib3==2.2.1 From 4ada1653e183b765c9d7c0ec465401c7fbb1b173 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Sun, 17 Mar 2024 11:14:48 +0330 Subject: [PATCH 04/46] feat/signup --- BackEnd/BackEnd/settings.py | 27 ++- BackEnd/BackEnd/urls.py | 20 ++- ...r_has_verification_tries_reset_and_more.py | 43 +++++ BackEnd/accounts/models.py | 14 +- BackEnd/accounts/serializers.py | 67 ++++++++ BackEnd/accounts/urls.py | 6 +- BackEnd/accounts/utils.py | 33 ++++ BackEnd/accounts/views.py | 156 +++++++++++++++++- BackEnd/templates/active_email.html | 68 ++++++++ BackEnd/templates/successfull_activation.html | 31 ++++ BackEnd/templates/varify_email.html | 57 +++++++ BackEnd/utils/email.py | 72 ++++++++ BackEnd/utils/project_variables.py | 1 + client.py | 5 + 14 files changed, 587 insertions(+), 13 deletions(-) create mode 100644 BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py create mode 100644 BackEnd/accounts/utils.py create mode 100644 BackEnd/templates/active_email.html create mode 100644 BackEnd/templates/successfull_activation.html create mode 100644 BackEnd/templates/varify_email.html create mode 100644 BackEnd/utils/email.py create mode 100644 BackEnd/utils/project_variables.py create mode 100644 client.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 1d4c1c4..1bcc461 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -11,27 +11,42 @@ """ from pathlib import Path +from environs import Env +import os + +# Environment Variables # 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/5.0/howto/deployment/checklist/ - # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = "django-insecure-#zdhi36fsv(lx#%swqp(l9)0dctgcmwqc__*6h5$9gk@sqxn-e" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True +env = Env() +env.read_env() + +# Setting Website URL +# WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') +BASE_URL = 'http://localhost:8000/' +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_HOST_USER = 'eniakgroupiust@gmail.com'#env.str('EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = 'otawrhfscdedswzd'# '%_giw.9?5=3aNQr'#env.str('EMAIL_HOST_PASSWORD') +EMAIL_PORT = 587 +EMAIL_USE_TLS = True +REDIS_HOST = os.environ.get('REDIS_HOST', '127.0.0.1') +CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] ALLOWED_HOSTS = [] - REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES' : [ 'rest_framework.permissions.AllowAny' ], + 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' , # 'DEFAULT_AUTHENTICATION_CLASSES' : [ # 'rest_framework_simplejwt.authentication.JWTAuthentication', # ] @@ -47,6 +62,8 @@ "django.contrib.staticfiles", "accounts", "rest_framework", + "rest_framework_swagger", + "drf_yasg", ] MIDDLEWARE = [ @@ -64,7 +81,7 @@ TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], + "DIRS": [BASE_DIR / 'templates'], "APP_DIRS": True, "OPTIONS": { "context_processors": [ diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index de8fa15..f914282 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -16,8 +16,26 @@ """ from django.contrib import admin from django.urls import path , include +from drf_yasg.views import get_schema_view +from rest_framework import permissions +from drf_yasg import openapi + +schema_view = get_schema_view( + openapi.Info( + title="API", + default_version='v1', + description="API", + terms_of_service="https://www.google.com/policies/terms/", + contact=openapi.Contact(email="contact#snippets.local"), + license=openapi.License(name="BSD License"), + ), + public=True, + permission_classes=[permissions.AllowAny, ], +) urlpatterns = [ path("admin/", admin.site.urls), - # path("accounts/" , include("accounts.urls")) + path("accounts/" , include("accounts.urls")), + path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), + path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ] diff --git a/BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py b/BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py new file mode 100644 index 0000000..9beea32 --- /dev/null +++ b/BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 5.0.3 on 2024-03-15 10:30 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0002_remove_user_datee"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="has_verification_tries_reset", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="user", + name="is_email_verified", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 15, 14, 0, 36, 7496), + null=True, + ), + ), + migrations.AddField( + model_name="user", + name="verification_code", + field=models.CharField(blank=True, max_length=4, null=True), + ), + migrations.AddField( + model_name="user", + name="verification_tries_count", + field=models.IntegerField(default=0), + ), + ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index 383fe91..a6b7219 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -3,7 +3,7 @@ from django.core.validators import MinLengthValidator, MaxLengthValidator from django.db import models from django.contrib.auth.models import AbstractBaseUser , BaseUserManager -import datetime +from datetime import datetime class UserManager(BaseUserManager): @@ -71,10 +71,14 @@ class User(AbstractBaseUser): is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) objects = UserManager() - # verification_code = models.CharField(max_length=4, null=True, blank=True) - # verification_tries_count = models.IntegerField(default=0) - # last_verification_sent = models.DateTimeField(null=True, blank=True, default=datetime.now) - # has_verification_tries_reset = models.BooleanField(default=False) + + + # email varification + is_email_verified = models.BooleanField(default=False) + verification_code = models.CharField(max_length=4, null=True, blank=True) + verification_tries_count = models.IntegerField(default=0) + last_verification_sent = models.DateTimeField(null=True, blank=True, default=datetime.now()) + has_verification_tries_reset = models.BooleanField(default=False) def __str__(self): return self.email diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 732182a..bf5d186 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -1,7 +1,74 @@ from rest_framework import serializers from accounts.models import User +from django.contrib.auth.password_validation import validate_password +from django.contrib.auth import password_validation +import utils.project_variables as project_variables class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" ] + + +class SignUpSerializer(serializers.ModelSerializer): + password2 = serializers.CharField(style={"input_type": "password"}, write_only=True) + password1 = serializers.CharField( + style={'input_type': 'password'}, + validators=[password_validation.validate_password], + write_only=True + ) + + class Meta: + model = User + fields = ('email', 'date_of_birth', 'password1', 'password2' # 'id', i do not know whether its needed or not + , 'gender' , 'firstname' , 'lastname') + extra_kwargs = { + 'password1': {'write_only': True}, + 'password2': {'write_only': True}, + } + + def validate_email(self, value): + print("validate email") + user = User.objects.filter(email__iexact=value) + if user.exists(): + user = user.first() + if user.is_email_verified: + raise serializers.ValidationError("Email already exists.") + if user.verification_tries_count >= project_variables.MAX_VERIFICATION_TRIES: + raise serializers.ValidationError("You have reached the maximum number of registration tries.") + if user.username != self.initial_data.get('username'): + raise serializers.ValidationError("Email already exists.") + return str.lower(value) + + def validate_password2(self, value): + if value != self.initial_data.get('password1'): + raise serializers.ValidationError('Passwords must match.') + return value + + def validate_password1(self, value): + if value != self.initial_data.get('password2'): + raise serializers.ValidationError('Passwords must match.') + password_validation.validate_password(value) + return value + + +class ActivationConfirmSerializer(serializers.Serializer): + verification_code = serializers.CharField(max_length=4, min_length=4) + + +class ActivationResendSerializer(serializers.Serializer): + email = serializers.EmailField(required=True) + + def validate(self, attrs): + email = attrs.get('email', None) + + try: + user = User.objects.get(email__iexact=email) + except User.DoesNotExist: + raise serializers.ValidationError({"detail": "user does not exist."}) + + if user.is_email_verified: + raise serializers.ValidationError({"detail": "user is already verified."}) + + attrs['user'] = user + return attrs \ No newline at end of file diff --git a/BackEnd/accounts/urls.py b/BackEnd/accounts/urls.py index 023fbb2..adc6f42 100644 --- a/BackEnd/accounts/urls.py +++ b/BackEnd/accounts/urls.py @@ -1,5 +1,9 @@ +from .views import * +from django.urls import path urlpatterns = [ - + path('signup/' , SignUpView.as_view() , name='signup' ) , + path('activation_confirm//', ActivationConfirmView.as_view(), name='activation_confirm'), + path('activation-resend/', ActivationResend.as_view(), name='activation-resend'), ] \ No newline at end of file diff --git a/BackEnd/accounts/utils.py b/BackEnd/accounts/utils.py new file mode 100644 index 0000000..8404b30 --- /dev/null +++ b/BackEnd/accounts/utils.py @@ -0,0 +1,33 @@ +from rest_framework_simplejwt.tokens import RefreshToken +from django.core.mail import EmailMessage +import threading +from .models import User + +def generate_tokens(user_id): + refresh = RefreshToken.for_user(User.objects.get(id=user_id)) + return { + 'refresh': str(refresh), + 'access': str(refresh.access_token), + } + +class EmailThread(threading.Thread): + def __init__(self, email_handler ,subject,recipient_list, verification_token, registration_tries, show_text , token ): + super().__init__() + self.email_handler = email_handler + self.subject = subject + self.recipient_list = recipient_list + self.verification_token = verification_token + self.registration_tries = registration_tries + self.show_text = show_text + self.access_token = token + + def run(self): + self.email_handler.send_verification_message( + subject=self.subject, + recipient_list=self.recipient_list, + verification_token=self.verification_token, + registration_tries=self.registration_tries, + show_text=self.show_text , + token = self.access_token + ) + print(f"Email sent to {self.recipient_list}") \ No newline at end of file diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 91ea44a..e7ab3b4 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -1,3 +1,157 @@ +from django.http import HttpResponse +from django.contrib.auth.hashers import make_password +from rest_framework import status +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.generics import CreateAPIView , GenericAPIView +from .serializers import SignUpSerializer , UserSerializer , ActivationConfirmSerializer ,ActivationResendSerializer +from .models import User +from datetime import datetime +from django.contrib.sites.shortcuts import get_current_site +from .utils import generate_tokens , EmailThread +import random +from django.conf import settings +import utils.email as email_handler +import jwt +from jwt.exceptions import ExpiredSignatureError, InvalidSignatureError from django.shortcuts import render +from django.views.decorators.csrf import csrf_protect + + + +class SignUpView(CreateAPIView): + serializer_class = SignUpSerializer + def post(self,request ) : + serializer = SignUpSerializer(data=request.data) + serializer.is_valid(raise_exception=False) + validated_data = serializer.validated_data + email = str.lower(validated_data['email']) + # verification code + verification_code = str(random.randint(1000, 9999)) + user = User.objects.filter(email__iexact = email ) + # if user signup before and not verified + if user.exists() and user.is_email_varified == False: + user = user.first() + user.gender = validated_data['gender'] + user.firstname = validated_data['firstname'] + user.lastname = validated_data['lastname'] + user.date_of_birth = validated_data['date_of_birth'] , + user.verification_code = verification_code + user.verification_tries_count += 1 + user.last_verification_sent = datetime.now() + user.save() + else : + user = User.objects.create( + email = email, + firstname = validated_data['firstname'], + lastname = validated_data['lastname'], + gender = validated_data['gender'], + date_of_birth = validated_data['date_of_birth'] , + password = make_password( validated_data['password1']) , + verification_code=verification_code, + verification_tries_count=1, + last_verification_sent=datetime.now(), + ) + # varify email + token = generate_tokens(user.id)["access"] + subject = 'تایید ایمیل ثبت نام' + show_text = user.has_verification_tries_reset or user.verification_tries_count > 1 + # sending email verification with thread + email_thread = EmailThread(email_handler, subject=subject, + recipient_list=[user.email], + verification_token=verification_code, + registration_tries=user.verification_tries_count, + show_text=show_text , + token = token ) + + email_thread.start() + user_data = { + "user": UserSerializer(user).data, + "message": "User created successfully. Please check your email to activate your account.", + "code": verification_code, + "url": f'{settings.WEBSITE_URL}/accounts/activation-confirm/{token}/', + "token": token, + } + return Response(user_data, status=status.HTTP_201_CREATED) + + + + +class ActivationConfirmView(GenericAPIView): + serializer_class = ActivationConfirmSerializer + permission_classes = [] + + def get(self, request, *args, **kwargs): + return render(request, 'varify_email.html') + + @csrf_protect + def post(self, request, token): + token = self.validate_token(token) + print(request.data) + if not token: + return Response({'message': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) + + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + + user = self.get_user_from_token(token) + if not user: + return Response({'message': 'Invalid user'}, status=status.HTTP_400_BAD_REQUEST) + + if request.data.get('verification_code') != user.verification_code: + return Response({'message': 'Invalid code'}, status=status.HTTP_400_BAD_REQUEST) + + user.is_email_verified = True + user.verification_code = None + user.save() + return Response('successfull_activation.html', status=status.HTTP_200_OK) + + def get_user_from_token(self, token): + try: + payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) + user_id = payload.get('user_id') + return User.objects.filter(id=user_id).first() + except ExpiredSignatureError: + return None + + + def validate_token(self, token): + try: + jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) + return token + except ExpiredSignatureError: + return None + except InvalidSignatureError: + return None + + + +class ActivationResend(GenericAPIView): + serializer_class = ActivationResendSerializer + permission_classes = [] + def post(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(): + user = serializer.validated_data['user'] + subject = 'تایید ایمیل ثبت نام' + verification_code = str(random.randint(1000, 9999)) + user.verification_tries_count += 1 + user.verification_code = verification_code + user.last_verification_sent = datetime.now() + user.save() + show_text = user.has_verification_tries_reset or user.verification_tries_count > 1 + token = generate_tokens(user)["access"] + email_handler.send_verification_message(subject=subject, + recipient_list=[user.email], + verification_token=verification_code, + registration_tries=user.verification_tries_count, + show_text=show_text) + return Response({ + "message": "email sent", + "url": f'{settings.WEBSITE_URL}/accounts/activation-confirm/{token}', + }, status=status.HTTP_200_OK) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + -# Create your views here. diff --git a/BackEnd/templates/active_email.html b/BackEnd/templates/active_email.html new file mode 100644 index 0000000..e8ab6a3 --- /dev/null +++ b/BackEnd/templates/active_email.html @@ -0,0 +1,68 @@ +{% autoescape off %} + + + + + + تایید ایمیل + + + +
+

کد تایید ایمیل:

+

{{ email_verification_token }}

+

{{ remaining_text }}

+

برای تایید ایمیل خود بر روی دکمه زیر کلیک کنید:

+ تایید ایمیل +
+ + +{% endautoescape %} + + + + + diff --git a/BackEnd/templates/successfull_activation.html b/BackEnd/templates/successfull_activation.html new file mode 100644 index 0000000..eda5775 --- /dev/null +++ b/BackEnd/templates/successfull_activation.html @@ -0,0 +1,31 @@ + + + + + + فعال‌سازی موفقیت‌آمیز + + + +
+

ایمیل شما با موفقیت تایید شد

+
+ + diff --git a/BackEnd/templates/varify_email.html b/BackEnd/templates/varify_email.html new file mode 100644 index 0000000..c6f365d --- /dev/null +++ b/BackEnd/templates/varify_email.html @@ -0,0 +1,57 @@ +{% autoescape off %} + + + + + + کد تایید + + + +
+ + +

+ + + +
+ + +{% endautoescape %} + diff --git a/BackEnd/utils/email.py b/BackEnd/utils/email.py new file mode 100644 index 0000000..d537140 --- /dev/null +++ b/BackEnd/utils/email.py @@ -0,0 +1,72 @@ +from django.conf import settings +from django.core.mail import EmailMultiAlternatives +from django.template.loader import render_to_string +from BackEnd.settings import EMAIL_HOST +from . import project_variables +import json + + +def send_verification_message(subject, recipient_list, verification_token, registration_tries, show_text , token): + remaining_registration_tries = project_variables.MAX_VERIFICATION_TRIES - registration_tries + + if show_text: + if remaining_registration_tries < project_variables.MAX_VERIFICATION_TRIES: + remaining_text = f'تا کنون به تعداد {registration_tries}بار، ' \ + f'درخواست ثبت نام داشته اید. به تعداد {remaining_registration_tries} ' \ + f'دفعۀ دیگر میتوانید برای دریافت کد تایید، درخواست نمایید. ' \ + f'بعد از آن، پس از 12 ساعت انتظار، می توانید ' \ + f'برای باری دیگر، برای دریافت کد تایید، درخواست خود را در سامانه ثبت کنید.' + else: + remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ + 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' + else: + remaining_text = '' + + context = { + 'email_verification_token': verification_token, + 'remaining_text': remaining_text, + 'varification_link' : token , + } + + html_message = render_to_string( 'active_email.html', context= context ) #'activation_template.html' + email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) + email.attach_alternative(html_message, "text/html" ) #"text/html") + email.send() + + +# def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries): +# remaining_verification_tries = project_variables.MAX_VERIFICATION_TRIES - verification_tries +# if remaining_verification_tries < project_variables.MAX_VERIFICATION_TRIES: +# remaining_text = f'تا کنون به تعداد {verification_tries}بار، ' \ +# f'درخواست تغییر رمز عبور داشته اید. به تعداد {remaining_verification_tries} ' \ +# f'دفعۀ دیگر می توانید برای دریافت کد تایید، درخواست نمایید. ' \ +# f'بعد از آن، پس از 12 ساعت انتظار، می توانید ' \ +# f'برای باری دیگر، برای دریافت کد تایید، درخواست خود را در سامانه ثبت کنید.' +# else: +# remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ +# 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' +# context = { +# 'email_verification_token': verification_token, +# 'remaining_text': remaining_text, +# # 'image_bg': f'{settings.WEBSITE_URL}/static/Back-End/ResetPassword_BG_2.png', +# # 'image_icon': f'{settings.WEBSITE_URL}/static/Back-End/kat_1.png', +# # 'image_header': f'{settings.WEBSITE_URL}/static/Back-End/Reset_password-bro.png', +# } +# html_message = render_to_string('forget_password.html', context) +# email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) +# email.attach_alternative(html_message, "text/html") +# email.send() + + +# def send_modification_message(subject, recipient_list, message): +# message_lines = message.split('\n') +# context = { +# 'message_lines': message_lines, +# # 'image_icon': f'{settings.WEBSITE_URL}/static/Back-End/kat_1.png', +# # 'image_header': f'{settings.WEBSITE_URL}/static/Back-End/announcement.png', +# # 'image_footer': f'{settings.WEBSITE_URL}/static/Back-End/feedback.png', +# } +# html_message = render_to_string('modifications.html', context) +# email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) +# email.attach_alternative(html_message, "text/html") +# email.send() diff --git a/BackEnd/utils/project_variables.py b/BackEnd/utils/project_variables.py new file mode 100644 index 0000000..cca5de3 --- /dev/null +++ b/BackEnd/utils/project_variables.py @@ -0,0 +1 @@ +MAX_VERIFICATION_TRIES = 5 \ No newline at end of file diff --git a/client.py b/client.py new file mode 100644 index 0000000..052c08c --- /dev/null +++ b/client.py @@ -0,0 +1,5 @@ +import requests + + + +endpoint = "" \ No newline at end of file From 5ace02cf6e55766a8a8cfc5d98521636a6b89adc Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 18 Mar 2024 10:32:06 +0330 Subject: [PATCH 05/46] feat/updateModel --- BackEnd/.vscode/settings.json | 3 - BackEnd/BackEnd/__init__.py | 0 BackEnd/BackEnd/settings.py | 4 +- BackEnd/accounts/__init__.py | 0 BackEnd/accounts/admin.py | 6 +- BackEnd/accounts/migrations/0001_initial.py | 30 ++++++- .../0002_alter_user_last_verification_sent.py | 23 ++++++ .../migrations/0002_remove_user_datee.py | 14 ---- ...email_alter_user_last_verification_sent.py | 26 ++++++ ...r_has_verification_tries_reset_and_more.py | 43 ---------- ...er_user_last_verification_sent_and_more.py | 39 +++++++++ ...email_alter_user_last_verification_sent.py | 28 +++++++ BackEnd/accounts/models.py | 24 +++++- BackEnd/accounts/serializers.py | 46 ++++++++--- BackEnd/accounts/urls.py | 4 +- BackEnd/accounts/views.py | 79 ++++++++++++++++--- BackEnd/templates/active_email.html | 12 --- BackEnd/templates/forget_password.html | 57 +++++++++++++ BackEnd/utils/email.py | 67 +++++----------- 19 files changed, 351 insertions(+), 154 deletions(-) delete mode 100644 BackEnd/.vscode/settings.json delete mode 100644 BackEnd/BackEnd/__init__.py delete mode 100644 BackEnd/accounts/__init__.py create mode 100644 BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0002_remove_user_datee.py create mode 100644 BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py create mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py create mode 100644 BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py create mode 100644 BackEnd/templates/forget_password.html diff --git a/BackEnd/.vscode/settings.json b/BackEnd/.vscode/settings.json deleted file mode 100644 index cee4243..0000000 --- a/BackEnd/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "iis.configDir": "" -} \ No newline at end of file diff --git a/BackEnd/BackEnd/__init__.py b/BackEnd/BackEnd/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 1bcc461..249a03f 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -29,7 +29,7 @@ env.read_env() # Setting Website URL -# WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') +WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') BASE_URL = 'http://localhost:8000/' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' @@ -39,6 +39,7 @@ EMAIL_USE_TLS = True REDIS_HOST = os.environ.get('REDIS_HOST', '127.0.0.1') CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] +SESSION_COOKIE_DOMAIN = "http://localserver:8000" ALLOWED_HOSTS = [] @@ -63,6 +64,7 @@ "accounts", "rest_framework", "rest_framework_swagger", + "phonenumber_field", "drf_yasg", ] diff --git a/BackEnd/accounts/__init__.py b/BackEnd/accounts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/BackEnd/accounts/admin.py b/BackEnd/accounts/admin.py index ffa2a97..2685e0c 100644 --- a/BackEnd/accounts/admin.py +++ b/BackEnd/accounts/admin.py @@ -46,18 +46,18 @@ def clean_password(self): class UserAdmin(BaseUserAdmin): form = UserChangeForm add_form= UserCreationForm - list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active') #'is_email_verified' + list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active' , 'phone_number') #'is_email_verified' list_filter = ('is_admin' , 'email' ,'firstname', 'lastname') fieldsets=( (None, {'fields': ('email', 'password')}), - ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender')}), + ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' , 'phone_number')}), ('Permissions', {'fields': ( 'is_admin', 'is_active', )}), #'is_email_verified' ) add_fieldsets = ( (None, { 'classes': ('wide',), - 'fields': ('email', 'date_of_birth', 'password1', 'password2', 'is_active' ), + 'fields': ('email', 'password1', 'password2', 'is_active' ), # , 'date_of_birth' }), ) diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index cebdce7..b4fe3d7 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,5 +1,7 @@ -# Generated by Django 5.0.3 on 2024-03-12 23:00 +# Generated by Django 5.0.3 on 2024-03-17 21:28 +import datetime +import phonenumber_field.modelfields from django.db import migrations, models @@ -32,16 +34,36 @@ class Migration(migrations.Migration): ("firstname", models.CharField(max_length=20)), ("lastname", models.CharField(max_length=30)), ("email", models.EmailField(max_length=255, unique=True)), - ("datee", models.DateField()), ("date_of_birth", models.DateField()), - ("is_active", models.BooleanField(default=True)), - ("is_admin", models.BooleanField(default=False)), ( "gender", models.CharField( choices=[("F", "Female"), ("M", "Male")], max_length=1 ), ), + ("is_active", models.BooleanField(default=True)), + ("is_admin", models.BooleanField(default=False)), + ( + "phone_number", + phonenumber_field.modelfields.PhoneNumberField( + blank=True, max_length=128, null=True, region="IR", unique=True + ), + ), + ("is_email_verified", models.BooleanField(default=False)), + ( + "verification_code", + models.CharField(blank=True, max_length=4, null=True), + ), + ("verification_tries_count", models.IntegerField(default=0)), + ( + "last_verification_sent", + models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 18, 0, 58, 5, 405953), + null=True, + ), + ), + ("has_verification_tries_reset", models.BooleanField(default=False)), ], options={"abstract": False,}, ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py new file mode 100644 index 0000000..f5da8e9 --- /dev/null +++ b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-17 21:31 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 18, 1, 1, 1, 755346), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0002_remove_user_datee.py b/BackEnd/accounts/migrations/0002_remove_user_datee.py deleted file mode 100644 index 8fb0aa6..0000000 --- a/BackEnd/accounts/migrations/0002_remove_user_datee.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-12 23:02 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0001_initial"), - ] - - operations = [ - migrations.RemoveField(model_name="user", name="datee",), - ] diff --git a/BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py new file mode 100644 index 0000000..ab4333f --- /dev/null +++ b/BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py @@ -0,0 +1,26 @@ +# Generated by Django 5.0.3 on 2024-03-17 22:19 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0002_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", name="email", field=models.EmailField(max_length=255), + ), + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 18, 1, 49, 49, 351782), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py b/BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py deleted file mode 100644 index 9beea32..0000000 --- a/BackEnd/accounts/migrations/0003_user_has_verification_tries_reset_and_more.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-15 10:30 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0002_remove_user_datee"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="has_verification_tries_reset", - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name="user", - name="is_email_verified", - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 15, 14, 0, 36, 7496), - null=True, - ), - ), - migrations.AddField( - model_name="user", - name="verification_code", - field=models.CharField(blank=True, max_length=4, null=True), - ), - migrations.AddField( - model_name="user", - name="verification_tries_count", - field=models.IntegerField(default=0), - ), - ] diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py new file mode 100644 index 0000000..4500806 --- /dev/null +++ b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 5.0.3 on 2024-03-18 02:21 + +import datetime +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0003_alter_user_email_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 18, 5, 50, 59, 784601), + null=True, + ), + ), + migrations.AlterField( + model_name="user", + name="phone_number", + field=models.CharField( + blank=True, + max_length=15, + null=True, + validators=[ + django.core.validators.RegexValidator( + message="Phone number must be in a valid Iranian format.", + regex="^\\+?98[09]\\d{9}$", + ) + ], + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py new file mode 100644 index 0000000..01abd57 --- /dev/null +++ b/BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0.3 on 2024-03-18 05:29 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0004_alter_user_last_verification_sent_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="email", + field=models.EmailField(max_length=255, unique=True), + ), + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 18, 8, 59, 32, 145834), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index a6b7219..31722db 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -4,10 +4,12 @@ from django.db import models from django.contrib.auth.models import AbstractBaseUser , BaseUserManager from datetime import datetime +# from phonenumber_field.modelfields import PhoneNumberField +from django.core.validators import RegexValidator class UserManager(BaseUserManager): - def create_user(self , email , firstname , lastname , gender , date_of_birth, password=None ) : + def create_user(self , email , firstname , phone , lastname , gender , date_of_birth, password=None ) : """ Creates and saves a User with the given email, data of birth and password @@ -21,13 +23,14 @@ def create_user(self , email , firstname , lastname , gender , date_of_birth, pa firstname = firstname , lastname = lastname, gender= gender, + phone_number = phone ) user.set_password(password) user.save(using=self._db) return user - def create_superuser(self , email , firstname , lastname , gender , date_of_birth , password=None): + def create_superuser(self , email , firstname , phone ,lastname , gender , date_of_birth , password=None): """ Creates and saves a superuser with the given email, birthdat and password. @@ -40,6 +43,7 @@ def create_superuser(self , email , firstname , lastname , gender , date_of_birt firstname = firstname , lastname = lastname, gender= gender, + phone=phone ) user.is_admin = True @@ -65,13 +69,24 @@ class User(AbstractBaseUser): unique = True, ) USERNAME_FIELD = 'email' - REQUIRED_FIELDS = ['date_of_birth' , 'firstname' , 'lastname' , 'gender'] + # REQUIRED_FIELDS = ['password'] + objects = UserManager() date_of_birth= models.DateField() gender = models.CharField(max_length=1, choices=GENDER_CHOICES) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) - objects = UserManager() + phone_number_regex = r'^\+?98[09]\d{9}$' + phone_number_validator = RegexValidator( + regex=phone_number_regex, + message="Phone number must be in a valid Iranian format." + ) + phone_number = models.CharField( + max_length=15, # Adjust the length as per your requirement + validators=[phone_number_validator], + blank=True, + null=True + ) # email varification is_email_verified = models.BooleanField(default=False) @@ -80,6 +95,7 @@ class User(AbstractBaseUser): last_verification_sent = models.DateTimeField(null=True, blank=True, default=datetime.now()) has_verification_tries_reset = models.BooleanField(default=False) + def __str__(self): return self.email diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index bf5d186..0979688 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -4,10 +4,10 @@ from django.contrib.auth import password_validation import utils.project_variables as project_variables -class UserSerializer(serializers.ModelSerializer): +class UserSerializer(serializers.Serializer): class Meta: model = User - fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" ] + fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" , "phone_number"] class SignUpSerializer(serializers.ModelSerializer): @@ -20,15 +20,15 @@ class SignUpSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ('email', 'date_of_birth', 'password1', 'password2' # 'id', i do not know whether its needed or not - , 'gender' , 'firstname' , 'lastname') + fields = ('email', 'date_of_birth', 'password1', 'password2' #'id' # i do not know whether its needed or not + , 'gender' , 'firstname' , 'lastname' , 'phone_number') + extra_kwargs = { 'password1': {'write_only': True}, 'password2': {'write_only': True}, } def validate_email(self, value): - print("validate email") user = User.objects.filter(email__iexact=value) if user.exists(): user = user.first() @@ -36,11 +36,18 @@ def validate_email(self, value): raise serializers.ValidationError("Email already exists.") if user.verification_tries_count >= project_variables.MAX_VERIFICATION_TRIES: raise serializers.ValidationError("You have reached the maximum number of registration tries.") - if user.username != self.initial_data.get('username'): - raise serializers.ValidationError("Email already exists.") + # if user.phone_number != self.initial_data.get('phone_number'): + # raise serializers.ValidationError("Email already exists.") return str.lower(value) + + def validate_phone_number(self, attrs): + print("lssssssssssssssssssssssssssssssss") + print(attrs) + return attrs + def validate_password2(self, value): + if value != self.initial_data.get('password1'): raise serializers.ValidationError('Passwords must match.') return value @@ -61,14 +68,33 @@ class ActivationResendSerializer(serializers.Serializer): def validate(self, attrs): email = attrs.get('email', None) - try: user = User.objects.get(email__iexact=email) except User.DoesNotExist: raise serializers.ValidationError({"detail": "user does not exist."}) if user.is_email_verified: - raise serializers.ValidationError({"detail": "user is already verified."}) + raise serializers.ValidationError({"detail": "user with this email is already verified."}) attrs['user'] = user - return attrs \ No newline at end of file + return attrs + + + +class ForgotPasswordSerializer(serializers.Serializer): + email = serializers.EmailField() + + +class ResetPasswordSerializer(serializers.Serializer): + new_password = serializers.CharField(write_only=True, required=True) + confirm_password = serializers.CharField(write_only=True, required=True) + def validate(self, attrs): + new_password = attrs.get('new_password') + confirm_password = attrs.get('confirm_password') + if new_password != confirm_password: + raise serializers.ValidationError("New password and confirm password do not match.") + try: + validate_password(new_password) + except serializers.ValidationError as validation_error: + raise serializers.ValidationError({"new_password": validation_error}) + return attrs diff --git a/BackEnd/accounts/urls.py b/BackEnd/accounts/urls.py index adc6f42..32a29fc 100644 --- a/BackEnd/accounts/urls.py +++ b/BackEnd/accounts/urls.py @@ -5,5 +5,7 @@ urlpatterns = [ path('signup/' , SignUpView.as_view() , name='signup' ) , path('activation_confirm//', ActivationConfirmView.as_view(), name='activation_confirm'), - path('activation-resend/', ActivationResend.as_view(), name='activation-resend'), + path('activation_resend/', ActivationResend.as_view(), name='activation_resend'), + path('forgot_password/' , ForgotPassword.as_view() , name='forgot_password'), + path('reset_password//', ResetPassword.as_view(), name='reset_password'), ] \ No newline at end of file diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index e7ab3b4..2ab8daf 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -5,7 +5,8 @@ from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.generics import CreateAPIView , GenericAPIView -from .serializers import SignUpSerializer , UserSerializer , ActivationConfirmSerializer ,ActivationResendSerializer +from .serializers import SignUpSerializer , UserSerializer , ActivationConfirmSerializer ,ActivationResendSerializer \ + ,ForgotPasswordSerializer , ResetPasswordSerializer from .models import User from datetime import datetime from django.contrib.sites.shortcuts import get_current_site @@ -17,7 +18,7 @@ from jwt.exceptions import ExpiredSignatureError, InvalidSignatureError from django.shortcuts import render from django.views.decorators.csrf import csrf_protect - +from django.utils.decorators import method_decorator class SignUpView(CreateAPIView): @@ -31,7 +32,7 @@ def post(self,request ) : verification_code = str(random.randint(1000, 9999)) user = User.objects.filter(email__iexact = email ) # if user signup before and not verified - if user.exists() and user.is_email_varified == False: + if user.exists() : user = user.first() user.gender = validated_data['gender'] user.firstname = validated_data['firstname'] @@ -67,15 +68,12 @@ def post(self,request ) : email_thread.start() user_data = { - "user": UserSerializer(user).data, + "user": UserSerializer(user).data , "message": "User created successfully. Please check your email to activate your account.", "code": verification_code, - "url": f'{settings.WEBSITE_URL}/accounts/activation-confirm/{token}/', - "token": token, + "url": f'{settings.WEBSITE_URL}/accounts/activation_confirm/{token}/' } return Response(user_data, status=status.HTTP_201_CREATED) - - class ActivationConfirmView(GenericAPIView): @@ -85,13 +83,10 @@ class ActivationConfirmView(GenericAPIView): def get(self, request, *args, **kwargs): return render(request, 'varify_email.html') - @csrf_protect def post(self, request, token): token = self.validate_token(token) - print(request.data) if not token: return Response({'message': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) - serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -107,6 +102,7 @@ def post(self, request, token): user.save() return Response('successfull_activation.html', status=status.HTTP_200_OK) + def get_user_from_token(self, token): try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) @@ -155,3 +151,64 @@ def post(self, request, *args, **kwargs): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) +class ForgotPassword(GenericAPIView) : + serializer_class = ForgotPasswordSerializer + def post(self, request, *args, **kwargs) : + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(): + user = serializer.validated_data['user'] + subject = 'فراموشی رمز عبور' + verification_code = str(random.randint(1000, 9999)) + user.verification_tries_count += 1 + user.verification_code = verification_code + user.last_verification_sent = datetime.now() + user.save() + show_text = user.has_verification_tries_reset or user.verification_tries_count > 1 + token = generate_tokens(user)["access"] + email_handler.send_forget_password_verification_message(subject=subject, + recipient_list=[user.email], + verification_token=verification_code, + verification_tries=user.verification_tries_count) + return Response({ + "message": "email sent", + "url": f'{settings.WEBSITE_URL}/accounts/reset_password/{token}', + "code": verification_code + }, status=status.HTTP_200_OK) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class ResetPassword(GenericAPIView) : + serializer_class = ResetPasswordSerializer + def post(self, request, token ) : + token = self.validate_token(token) + if not token: + return Response({'message': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) + serializer = self.get_serializer(data= request.data ) + serializer.is_valid(raise_exception=True) + user = self.get_user_from_token(token) + if not user: + return Response({'message': 'Invalid user'}, status=status.HTTP_400_BAD_REQUEST) + + if request.data.get('verification_code') != user.verification_code: + return Response({'message': 'Invalid code'}, status=status.HTTP_400_BAD_REQUEST) + user.verification_code = None + user.password = make_password( serializer.validated_data['new_password']) , + user.save() + + def get_user_from_token(self, token): + try: + payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) + user_id = payload.get('user_id') + return User.objects.filter(id=user_id).first() + except ExpiredSignatureError: + return None + + def validate_token(self, token): + try: + jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) + return token + except ExpiredSignatureError: + return None + except InvalidSignatureError: + return None \ No newline at end of file diff --git a/BackEnd/templates/active_email.html b/BackEnd/templates/active_email.html index e8ab6a3..dece3a3 100644 --- a/BackEnd/templates/active_email.html +++ b/BackEnd/templates/active_email.html @@ -54,15 +54,3 @@ {% endautoescape %} - - - diff --git a/BackEnd/templates/forget_password.html b/BackEnd/templates/forget_password.html new file mode 100644 index 0000000..c6f365d --- /dev/null +++ b/BackEnd/templates/forget_password.html @@ -0,0 +1,57 @@ +{% autoescape off %} + + + + + + کد تایید + + + +
+ + +

+ + + +
+ + +{% endautoescape %} + diff --git a/BackEnd/utils/email.py b/BackEnd/utils/email.py index d537140..7574297 100644 --- a/BackEnd/utils/email.py +++ b/BackEnd/utils/email.py @@ -7,24 +7,12 @@ def send_verification_message(subject, recipient_list, verification_token, registration_tries, show_text , token): - remaining_registration_tries = project_variables.MAX_VERIFICATION_TRIES - registration_tries + # remaining_registration_tries = project_variables.MAX_VERIFICATION_TRIES - registration_tries - if show_text: - if remaining_registration_tries < project_variables.MAX_VERIFICATION_TRIES: - remaining_text = f'تا کنون به تعداد {registration_tries}بار، ' \ - f'درخواست ثبت نام داشته اید. به تعداد {remaining_registration_tries} ' \ - f'دفعۀ دیگر میتوانید برای دریافت کد تایید، درخواست نمایید. ' \ - f'بعد از آن، پس از 12 ساعت انتظار، می توانید ' \ - f'برای باری دیگر، برای دریافت کد تایید، درخواست خود را در سامانه ثبت کنید.' - else: - remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ - 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' - else: - remaining_text = '' context = { 'email_verification_token': verification_token, - 'remaining_text': remaining_text, + # 'remaining_text': remaining_text, 'varification_link' : token , } @@ -34,39 +22,22 @@ def send_verification_message(subject, recipient_list, verification_token, regis email.send() -# def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries): -# remaining_verification_tries = project_variables.MAX_VERIFICATION_TRIES - verification_tries -# if remaining_verification_tries < project_variables.MAX_VERIFICATION_TRIES: -# remaining_text = f'تا کنون به تعداد {verification_tries}بار، ' \ -# f'درخواست تغییر رمز عبور داشته اید. به تعداد {remaining_verification_tries} ' \ -# f'دفعۀ دیگر می توانید برای دریافت کد تایید، درخواست نمایید. ' \ -# f'بعد از آن، پس از 12 ساعت انتظار، می توانید ' \ -# f'برای باری دیگر، برای دریافت کد تایید، درخواست خود را در سامانه ثبت کنید.' -# else: -# remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ -# 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' -# context = { -# 'email_verification_token': verification_token, -# 'remaining_text': remaining_text, -# # 'image_bg': f'{settings.WEBSITE_URL}/static/Back-End/ResetPassword_BG_2.png', -# # 'image_icon': f'{settings.WEBSITE_URL}/static/Back-End/kat_1.png', -# # 'image_header': f'{settings.WEBSITE_URL}/static/Back-End/Reset_password-bro.png', -# } -# html_message = render_to_string('forget_password.html', context) -# email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) -# email.attach_alternative(html_message, "text/html") -# email.send() +def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries): + remaining_verification_tries = project_variables.MAX_VERIFICATION_TRIES - verification_tries + if remaining_verification_tries < project_variables.MAX_VERIFICATION_TRIES: + remaining_text = f'تا کنون به تعداد {verification_tries}بار، ' \ + f'درخواست تغییر رمز عبور داشته اید. به تعداد {remaining_verification_tries} ' \ + f'دفعۀ دیگر می توانید برای دریافت کد تایید، درخواست نمایید. ' + else: + remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ + 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' + context = { + 'email_verification_token': verification_token, + 'remaining_text': remaining_text, + } + html_message = render_to_string('forget_password.html', context) + email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) + email.attach_alternative(html_message, "text/html") + email.send() -# def send_modification_message(subject, recipient_list, message): -# message_lines = message.split('\n') -# context = { -# 'message_lines': message_lines, -# # 'image_icon': f'{settings.WEBSITE_URL}/static/Back-End/kat_1.png', -# # 'image_header': f'{settings.WEBSITE_URL}/static/Back-End/announcement.png', -# # 'image_footer': f'{settings.WEBSITE_URL}/static/Back-End/feedback.png', -# } -# html_message = render_to_string('modifications.html', context) -# email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) -# email.attach_alternative(html_message, "text/html") -# email.send() From f4260e066f0c58a20f2f923051c6cf645b9b7430 Mon Sep 17 00:00:00 2001 From: Asma Hamid Date: Mon, 18 Mar 2024 12:42:48 +0330 Subject: [PATCH 06/46] feat/Login-Logout --- BackEnd/BackEnd/settings.py | 29 +++++++++--- BackEnd/BackEnd/urls.py | 2 +- BackEnd/accounts/admin.py | 7 ++- BackEnd/accounts/models.py | 38 ++++++++++++---- BackEnd/accounts/serializers.py | 59 ++++++++++++++++++++++-- BackEnd/accounts/urls.py | 5 ++- BackEnd/accounts/utils.py | 33 ++++++++++++++ BackEnd/accounts/views.py | 72 +++++++++++++++++++++++++++++- BackEnd/utils/email.py | 72 ++++++++++++++++++++++++++++++ BackEnd/utils/project_variables.py | 1 + requirements.txt | 48 ++++++++++++++++++++ 11 files changed, 342 insertions(+), 24 deletions(-) create mode 100644 BackEnd/accounts/utils.py create mode 100644 BackEnd/utils/email.py create mode 100644 BackEnd/utils/project_variables.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 1d4c1c4..249a03f 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -11,27 +11,43 @@ """ from pathlib import Path +from environs import Env +import os + +# Environment Variables # 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/5.0/howto/deployment/checklist/ - # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = "django-insecure-#zdhi36fsv(lx#%swqp(l9)0dctgcmwqc__*6h5$9gk@sqxn-e" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True +env = Env() +env.read_env() + +# Setting Website URL +WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') +BASE_URL = 'http://localhost:8000/' +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_HOST_USER = 'eniakgroupiust@gmail.com'#env.str('EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = 'otawrhfscdedswzd'# '%_giw.9?5=3aNQr'#env.str('EMAIL_HOST_PASSWORD') +EMAIL_PORT = 587 +EMAIL_USE_TLS = True +REDIS_HOST = os.environ.get('REDIS_HOST', '127.0.0.1') +CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] +SESSION_COOKIE_DOMAIN = "http://localserver:8000" ALLOWED_HOSTS = [] - REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES' : [ 'rest_framework.permissions.AllowAny' ], + 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' , # 'DEFAULT_AUTHENTICATION_CLASSES' : [ # 'rest_framework_simplejwt.authentication.JWTAuthentication', # ] @@ -47,6 +63,9 @@ "django.contrib.staticfiles", "accounts", "rest_framework", + "rest_framework_swagger", + "phonenumber_field", + "drf_yasg", ] MIDDLEWARE = [ @@ -64,7 +83,7 @@ TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], + "DIRS": [BASE_DIR / 'templates'], "APP_DIRS": True, "OPTIONS": { "context_processors": [ diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index de8fa15..d0a85fd 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -19,5 +19,5 @@ urlpatterns = [ path("admin/", admin.site.urls), - # path("accounts/" , include("accounts.urls")) + path("accounts/" , include("accounts.urls")) ] diff --git a/BackEnd/accounts/admin.py b/BackEnd/accounts/admin.py index ffa2a97..5929a06 100644 --- a/BackEnd/accounts/admin.py +++ b/BackEnd/accounts/admin.py @@ -46,18 +46,18 @@ def clean_password(self): class UserAdmin(BaseUserAdmin): form = UserChangeForm add_form= UserCreationForm - list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active') #'is_email_verified' + list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active' , 'phone_number') #'is_email_verified' list_filter = ('is_admin' , 'email' ,'firstname', 'lastname') fieldsets=( (None, {'fields': ('email', 'password')}), - ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender')}), + ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' , 'phone_number')}), ('Permissions', {'fields': ( 'is_admin', 'is_active', )}), #'is_email_verified' ) add_fieldsets = ( (None, { 'classes': ('wide',), - 'fields': ('email', 'date_of_birth', 'password1', 'password2', 'is_active' ), + 'fields': ('email', 'password1', 'password2', 'is_active' ), # , 'date_of_birth' }), ) @@ -66,4 +66,3 @@ class UserAdmin(BaseUserAdmin): filter_horizontal = () admin.site.register(User, UserAdmin) - diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index 383fe91..31722db 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -3,11 +3,13 @@ from django.core.validators import MinLengthValidator, MaxLengthValidator from django.db import models from django.contrib.auth.models import AbstractBaseUser , BaseUserManager -import datetime +from datetime import datetime +# from phonenumber_field.modelfields import PhoneNumberField +from django.core.validators import RegexValidator class UserManager(BaseUserManager): - def create_user(self , email , firstname , lastname , gender , date_of_birth, password=None ) : + def create_user(self , email , firstname , phone , lastname , gender , date_of_birth, password=None ) : """ Creates and saves a User with the given email, data of birth and password @@ -21,13 +23,14 @@ def create_user(self , email , firstname , lastname , gender , date_of_birth, pa firstname = firstname , lastname = lastname, gender= gender, + phone_number = phone ) user.set_password(password) user.save(using=self._db) return user - def create_superuser(self , email , firstname , lastname , gender , date_of_birth , password=None): + def create_superuser(self , email , firstname , phone ,lastname , gender , date_of_birth , password=None): """ Creates and saves a superuser with the given email, birthdat and password. @@ -40,6 +43,7 @@ def create_superuser(self , email , firstname , lastname , gender , date_of_birt firstname = firstname , lastname = lastname, gender= gender, + phone=phone ) user.is_admin = True @@ -65,16 +69,32 @@ class User(AbstractBaseUser): unique = True, ) USERNAME_FIELD = 'email' - REQUIRED_FIELDS = ['date_of_birth' , 'firstname' , 'lastname' , 'gender'] + # REQUIRED_FIELDS = ['password'] + objects = UserManager() date_of_birth= models.DateField() gender = models.CharField(max_length=1, choices=GENDER_CHOICES) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) - objects = UserManager() - # verification_code = models.CharField(max_length=4, null=True, blank=True) - # verification_tries_count = models.IntegerField(default=0) - # last_verification_sent = models.DateTimeField(null=True, blank=True, default=datetime.now) - # has_verification_tries_reset = models.BooleanField(default=False) + phone_number_regex = r'^\+?98[09]\d{9}$' + phone_number_validator = RegexValidator( + regex=phone_number_regex, + message="Phone number must be in a valid Iranian format." + ) + + phone_number = models.CharField( + max_length=15, # Adjust the length as per your requirement + validators=[phone_number_validator], + blank=True, + null=True + ) + + # email varification + is_email_verified = models.BooleanField(default=False) + verification_code = models.CharField(max_length=4, null=True, blank=True) + verification_tries_count = models.IntegerField(default=0) + last_verification_sent = models.DateTimeField(null=True, blank=True, default=datetime.now()) + has_verification_tries_reset = models.BooleanField(default=False) + def __str__(self): return self.email diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 732182a..336d963 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -1,7 +1,60 @@ from rest_framework import serializers from accounts.models import User - -class UserSerializer(serializers.ModelSerializer): +from django.contrib.auth.password_validation import validate_password +from django.contrib.auth import password_validation +from django.utils.translation import gettext_lazy as _ +class UserSerializer(serializers.Serializer): class Meta: model = User - fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" ] + fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" , "phone_number"] + + + +class LoginSerializer(serializers.Serializer): + email=serializers.EmailField( + label=_("Email"), + ) + password = serializers.CharField( + label=_("password"), + write_only=True + ) + token = serializers.CharField( + label =_("Token"), + read_only=True + ) + + def validate(self, attrs): + email = attrs.get('email', None) + password = attrs.get('password', None) + + if email and password: + email = self.validate_email(email) + user = User.objects.get(email__iexact=email) + + if not user.check_password(password): + msg = _('Incorrect password.') + raise serializers.ValidationError(msg, code='authorization') + + if not user.is_email_verified: + raise serializers.ValidationError({"detail": "User is not verified."}) + + attrs['user'] = user + else: + msg = _('Must include "email" and "password".') + raise serializers.ValidationError(msg, code='authorization') + + return attrs + + def validate_email(self, value): + msg = _('Email does not exist.') + user_exists = User.objects.filter(email__iexact=value).exists() + + if not user_exists: + raise serializers.ValidationError(msg) + + return str.lower(value) + + +class ForgotPasswordSerializer(serializers.Serializer): + email = serializers.EmailField() + \ No newline at end of file diff --git a/BackEnd/accounts/urls.py b/BackEnd/accounts/urls.py index 023fbb2..3199331 100644 --- a/BackEnd/accounts/urls.py +++ b/BackEnd/accounts/urls.py @@ -1,5 +1,8 @@ +from .views import * +from django.urls import path urlpatterns = [ - + path('Login/',LoginView.as_view(),name='Login'), + path('Logout/',LogoutView.as_view(),name='Logout'), ] \ No newline at end of file diff --git a/BackEnd/accounts/utils.py b/BackEnd/accounts/utils.py new file mode 100644 index 0000000..8404b30 --- /dev/null +++ b/BackEnd/accounts/utils.py @@ -0,0 +1,33 @@ +from rest_framework_simplejwt.tokens import RefreshToken +from django.core.mail import EmailMessage +import threading +from .models import User + +def generate_tokens(user_id): + refresh = RefreshToken.for_user(User.objects.get(id=user_id)) + return { + 'refresh': str(refresh), + 'access': str(refresh.access_token), + } + +class EmailThread(threading.Thread): + def __init__(self, email_handler ,subject,recipient_list, verification_token, registration_tries, show_text , token ): + super().__init__() + self.email_handler = email_handler + self.subject = subject + self.recipient_list = recipient_list + self.verification_token = verification_token + self.registration_tries = registration_tries + self.show_text = show_text + self.access_token = token + + def run(self): + self.email_handler.send_verification_message( + subject=self.subject, + recipient_list=self.recipient_list, + verification_token=self.verification_token, + registration_tries=self.registration_tries, + show_text=self.show_text , + token = self.access_token + ) + print(f"Email sent to {self.recipient_list}") \ No newline at end of file diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 91ea44a..8529157 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -1,3 +1,73 @@ +from django.http import HttpResponse +from django.contrib.auth.hashers import make_password +from rest_framework import status +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.generics import CreateAPIView , GenericAPIView +from .serializers import UserSerializer , LoginSerializer +from .models import User +from datetime import datetime +from django.contrib.sites.shortcuts import get_current_site +from .utils import generate_tokens , EmailThread +import random +from django.conf import settings +import utils.email as email_handler +import jwt +from jwt.exceptions import ExpiredSignatureError, InvalidSignatureError from django.shortcuts import render +from django.views.decorators.csrf import csrf_protect +import random +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.decorators import login_required +from rest_framework_simplejwt.views import TokenObtainPairView +from rest_framework_simplejwt.tokens import RefreshToken +from utils.project_variables import MAX_VERIFICATION_TRIES + + + +class LoginView(TokenObtainPairView): + serializer_class = LoginSerializer + + def post(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = serializer.validated_data['user'] + if user is not None: + tokens = generate_tokens(user.id) + + login(request, user) + + return Response({ + 'refresh': tokens['refresh'], + 'access': tokens['access'], + 'user': UserSerializer(user).data, + }) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class LogoutView(APIView): + permission_classes = [IsAuthenticated] + + def get(self, request): + refresh_token = request.COOKIES.get('token') + + if refresh_token: + try: + token = RefreshToken(refresh_token) + token.blacklist() + except Exception as e: + return Response(data={'detail': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) + + response = Response(data={'detail': 'Logged out successfully'}, status=status.HTTP_200_OK) + response.delete_cookie('refresh_token') + response.delete_cookie('access_token') + return response + + if request.user.is_authenticated: + logout(request) + return Response(data={'detail': 'Logged out successfully'}, status=status.HTTP_200_OK) + + return Response(data={'detail': 'Not logged in'}, status=status.HTTP_400_BAD_REQUEST) -# Create your views here. diff --git a/BackEnd/utils/email.py b/BackEnd/utils/email.py new file mode 100644 index 0000000..2ac5092 --- /dev/null +++ b/BackEnd/utils/email.py @@ -0,0 +1,72 @@ +from django.conf import settings +from django.core.mail import EmailMultiAlternatives +from django.template.loader import render_to_string +from BackEnd.settings import EMAIL_HOST +from . import project_variables +import json + + +def send_verification_message(subject, recipient_list, verification_token, registration_tries, show_text , token): + remaining_registration_tries = project_variables.MAX_VERIFICATION_TRIES - registration_tries + + if show_text: + if remaining_registration_tries < project_variables.MAX_VERIFICATION_TRIES: + remaining_text = f'تا کنون به تعداد {registration_tries}بار، ' \ + f'درخواست ثبت نام داشته اید. به تعداد {remaining_registration_tries} ' \ + f'دفعۀ دیگر میتوانید برای دریافت کد تایید، درخواست نمایید. ' \ + f'بعد از آن، پس از 12 ساعت انتظار، می توانید ' \ + f'برای باری دیگر، برای دریافت کد تایید، درخواست خود را در سامانه ثبت کنید.' + else: + remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ + 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' + else: + remaining_text = '' + + context = { + 'email_verification_token': verification_token, + 'remaining_text': remaining_text, + 'varification_link' : token , + } + + html_message = render_to_string( 'active_email.html', context= context ) #'activation_template.html' + email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) + email.attach_alternative(html_message, "text/html" ) #"text/html") + email.send() + + +def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries): + remaining_verification_tries = project_variables.MAX_VERIFICATION_TRIES - verification_tries + if remaining_verification_tries < project_variables.MAX_VERIFICATION_TRIES: + remaining_text = f'تا کنون به تعداد {verification_tries}بار، ' \ + f'درخواست تغییر رمز عبور داشته اید. به تعداد {remaining_verification_tries} ' \ + f'دفعۀ دیگر می توانید برای دریافت کد تایید، درخواست نمایید. ' \ + f'بعد از آن، پس از 12 ساعت انتظار، می توانید ' \ + f'برای باری دیگر، برای دریافت کد تایید، درخواست خود را در سامانه ثبت کنید.' + else: + remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ + 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' + context = { + 'email_verification_token': verification_token, + 'remaining_text': remaining_text, + # 'image_bg': f'{settings.WEBSITE_URL}/static/Back-End/ResetPassword_BG_2.png', + # 'image_icon': f'{settings.WEBSITE_URL}/static/Back-End/kat_1.png', + # 'image_header': f'{settings.WEBSITE_URL}/static/Back-End/Reset_password-bro.png', + } + html_message = render_to_string('forget_password.html', context) + email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) + email.attach_alternative(html_message, "text/html") + email.send() + + +# def send_modification_message(subject, recipient_list, message): +# message_lines = message.split('\n') +# context = { +# 'message_lines': message_lines, +# # 'image_icon': f'{settings.WEBSITE_URL}/static/Back-End/kat_1.png', +# # 'image_header': f'{settings.WEBSITE_URL}/static/Back-End/announcement.png', +# # 'image_footer': f'{settings.WEBSITE_URL}/static/Back-End/feedback.png', +# } +# html_message = render_to_string('modifications.html', context) +# email = EmailMultiAlternatives(subject, '', EMAIL_HOST, recipient_list) +# email.attach_alternative(html_message, "text/html") +# email.send() diff --git a/BackEnd/utils/project_variables.py b/BackEnd/utils/project_variables.py new file mode 100644 index 0000000..cca5de3 --- /dev/null +++ b/BackEnd/utils/project_variables.py @@ -0,0 +1 @@ +MAX_VERIFICATION_TRIES = 5 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 675344b..44d0eec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,62 @@ asgiref==3.7.2 certifi==2024.2.2 charset-normalizer==3.3.2 +coreapi==2.3.3 +coreschema==0.0.4 Django==5.0.3 +django-rest-swagger==2.2.0 djangorestframework==3.14.0 djangorestframework-simplejwt==5.3.1 +drf-yasg==1.21.7 +environs==11.0.0 idna==3.6 +inflection==0.5.1 +itypes==1.2.0 +Jinja2==3.1.3 +MarkupSafe==2.1.5 +marshmallow==3.21.1 +openapi-codec==1.3.2 +packaging==24.0 PyJWT==2.8.0 +python-dotenv==1.0.1 pytz==2024.1 +PyYAML==6.0.1 requests==2.31.0 +setuptools==69.2.0 +simplejson==3.19.2 sqlparse==0.4.4 typing_extensions==4.10.0 tzdata==2024.1 +uritemplate==4.1.1 +urllib3==2.2.1 +asgiref==3.7.2 +certifi==2024.2.2 +charset-normalizer==3.3.2 +coreapi==2.3.3 +coreschema==0.0.4 +Django==5.0.3 +django-rest-swagger==2.2.0 +djangorestframework==3.14.0 +djangorestframework-simplejwt==5.3.1 +drf-yasg==1.21.7 +environs==11.0.0 +idna==3.6 +inflection==0.5.1 +itypes==1.2.0 +Jinja2==3.1.3 +MarkupSafe==2.1.5 +marshmallow==3.21.1 +openapi-codec==1.3.2 +packaging==24.0 +PyJWT==2.8.0 +python-dotenv==1.0.1 +pytz==2024.1 +PyYAML==6.0.1 +requests==2.31.0 +setuptools==69.2.0 +simplejson==3.19.2 +sqlparse==0.4.4 +typing_extensions==4.10.0 +tzdata==2024.1 +uritemplate==4.1.1 urllib3==2.2.1 From 0d78ffafb94a1199ff8876407f4006665051aeb8 Mon Sep 17 00:00:00 2001 From: Asma Hamid Date: Mon, 18 Mar 2024 13:17:39 +0330 Subject: [PATCH 07/46] feat/update --- BackEnd/accounts/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 336d963..7b4f846 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -16,6 +16,7 @@ class LoginSerializer(serializers.Serializer): ) password = serializers.CharField( label=_("password"), + style={"input_type": "password"}, write_only=True ) token = serializers.CharField( From de6b04100cb10d9e507ba411f57392be12e804cb Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 18 Mar 2024 15:47:33 +0330 Subject: [PATCH 08/46] fix/forgot_passwd --- BackEnd/accounts/admin.py | 4 +-- BackEnd/accounts/serializers.py | 19 +++++++----- BackEnd/accounts/views.py | 55 ++++++++++++++++++--------------- BackEnd/test.txt | 23 ++++++++++++++ BackEnd/utils/email.py | 13 +------- 5 files changed, 67 insertions(+), 47 deletions(-) create mode 100644 BackEnd/test.txt diff --git a/BackEnd/accounts/admin.py b/BackEnd/accounts/admin.py index 2685e0c..6a9410a 100644 --- a/BackEnd/accounts/admin.py +++ b/BackEnd/accounts/admin.py @@ -46,11 +46,11 @@ def clean_password(self): class UserAdmin(BaseUserAdmin): form = UserChangeForm add_form= UserCreationForm - list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active' , 'phone_number') #'is_email_verified' + list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active') #'is_email_verified' 'phone_number' list_filter = ('is_admin' , 'email' ,'firstname', 'lastname') fieldsets=( (None, {'fields': ('email', 'password')}), - ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' , 'phone_number')}), + ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' )}), ## 'phone_number' ('Permissions', {'fields': ( 'is_admin', 'is_active', )}), #'is_email_verified' ) diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 0979688..d083917 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -7,7 +7,7 @@ class UserSerializer(serializers.Serializer): class Meta: model = User - fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" , "phone_number"] + fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" ] #, "phone_number"] class SignUpSerializer(serializers.ModelSerializer): @@ -21,7 +21,7 @@ class SignUpSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('email', 'date_of_birth', 'password1', 'password2' #'id' # i do not know whether its needed or not - , 'gender' , 'firstname' , 'lastname' , 'phone_number') + , 'gender' , 'firstname' , 'lastname') # , 'phone_number') extra_kwargs = { 'password1': {'write_only': True}, @@ -34,18 +34,19 @@ def validate_email(self, value): user = user.first() if user.is_email_verified: raise serializers.ValidationError("Email already exists.") - if user.verification_tries_count >= project_variables.MAX_VERIFICATION_TRIES: - raise serializers.ValidationError("You have reached the maximum number of registration tries.") + # if user.verification_tries_count >= project_variables.MAX_VERIFICATION_TRIES: + # raise serializers.ValidationError("You have reached the maximum number of registration tries.") # if user.phone_number != self.initial_data.get('phone_number'): # raise serializers.ValidationError("Email already exists.") + return str.lower(value) - def validate_phone_number(self, attrs): - print("lssssssssssssssssssssssssssssssss") - print(attrs) - return attrs + # def validate_phone_number(self, attrs): + # print(attrs) + # return attrs + def validate_password2(self, value): if value != self.initial_data.get('password1'): @@ -88,6 +89,8 @@ class ForgotPasswordSerializer(serializers.Serializer): class ResetPasswordSerializer(serializers.Serializer): new_password = serializers.CharField(write_only=True, required=True) confirm_password = serializers.CharField(write_only=True, required=True) + verification_code = serializers.CharField(max_length=4, min_length=4) + def validate(self, attrs): new_password = attrs.get('new_password') confirm_password = attrs.get('confirm_password') diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 2ab8daf..6c22a46 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -25,7 +25,7 @@ class SignUpView(CreateAPIView): serializer_class = SignUpSerializer def post(self,request ) : serializer = SignUpSerializer(data=request.data) - serializer.is_valid(raise_exception=False) + serializer.is_valid(raise_exception=True) validated_data = serializer.validated_data email = str.lower(validated_data['email']) # verification code @@ -71,7 +71,7 @@ def post(self,request ) : "user": UserSerializer(user).data , "message": "User created successfully. Please check your email to activate your account.", "code": verification_code, - "url": f'{settings.WEBSITE_URL}/accounts/activation_confirm/{token}/' + "url": f'{settings.WEBSITE_URL}accounts/activation_confirm/{token}/' } return Response(user_data, status=status.HTTP_201_CREATED) @@ -122,7 +122,6 @@ def validate_token(self, token): return None - class ActivationResend(GenericAPIView): serializer_class = ActivationResendSerializer permission_classes = [] @@ -145,7 +144,7 @@ def post(self, request, *args, **kwargs): show_text=show_text) return Response({ "message": "email sent", - "url": f'{settings.WEBSITE_URL}/accounts/activation-confirm/{token}', + "url": f'{settings.WEBSITE_URL}accounts/activation-confirm/{token}', }, status=status.HTTP_200_OK) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @@ -156,27 +155,31 @@ class ForgotPassword(GenericAPIView) : def post(self, request, *args, **kwargs) : serializer = self.get_serializer(data=request.data) if serializer.is_valid(): - user = serializer.validated_data['user'] - subject = 'فراموشی رمز عبور' - verification_code = str(random.randint(1000, 9999)) - user.verification_tries_count += 1 - user.verification_code = verification_code - user.last_verification_sent = datetime.now() - user.save() - show_text = user.has_verification_tries_reset or user.verification_tries_count > 1 - token = generate_tokens(user)["access"] - email_handler.send_forget_password_verification_message(subject=subject, - recipient_list=[user.email], - verification_token=verification_code, - verification_tries=user.verification_tries_count) - return Response({ - "message": "email sent", - "url": f'{settings.WEBSITE_URL}/accounts/reset_password/{token}', - "code": verification_code - }, status=status.HTTP_200_OK) + email = str.lower(serializer.validated_data['email']) + users = User.objects.filter(email__iexact =email) + if (users.exists() ) : + user = users.first() + subject = 'فراموشی رمز عبور' + verification_code = str(random.randint(1000, 9999)) + user.verification_tries_count += 1 + user.verification_code = verification_code + user.last_verification_sent = datetime.now() + user.save() + token = generate_tokens(user.id)["access"] + email_handler.send_forget_password_verification_message(subject=subject, + recipient_list=[user.email], + verification_token=verification_code, + verification_tries=user.verification_tries_count) + return Response({ + "message": "email sent", + "url": f'{settings.WEBSITE_URL}accounts/reset_password/{token}/', + "code": verification_code + }, status=status.HTTP_200_OK) + else : + return Response( {'message': 'Invalid email'}, status=status.HTTP_400_BAD_REQUEST) else: - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - + return Response(serializer.errors , status=status.HTTP_400_BAD_REQUEST) + class ResetPassword(GenericAPIView) : serializer_class = ResetPasswordSerializer @@ -190,12 +193,14 @@ def post(self, request, token ) : if not user: return Response({'message': 'Invalid user'}, status=status.HTTP_400_BAD_REQUEST) - if request.data.get('verification_code') != user.verification_code: + if serializer.validated_data['verification_code'] != user.verification_code: return Response({'message': 'Invalid code'}, status=status.HTTP_400_BAD_REQUEST) user.verification_code = None user.password = make_password( serializer.validated_data['new_password']) , user.save() + return Response( {"message" : "password successfully update"} , status=status.HTTP_204_NO_CONTENT) + def get_user_from_token(self, token): try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) diff --git a/BackEnd/test.txt b/BackEnd/test.txt new file mode 100644 index 0000000..687976f --- /dev/null +++ b/BackEnd/test.txt @@ -0,0 +1,23 @@ +remaining_registration_tries = project_variables.MAX_VERIFICATION_TRIES - registration_tries + + if show_text: + if remaining_registration_tries < project_variables.MAX_VERIFICATION_TRIES: + remaining_text = f'تا کنون به تعداد {registration_tries}بار، ' \ + f'درخواست ثبت نام داشته اید. به تعداد {remaining_registration_tries} ' \ + f'دفعۀ دیگر میتوانید برای دریافت کد تایید، درخواست نمایید. ' + else: + remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ + 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' + else: + remaining_text = '' + + + +# remaining_verification_tries = project_variables.MAX_VERIFICATION_TRIES - verification_tries + # if remaining_verification_tries < project_variables.MAX_VERIFICATION_TRIES: + # remaining_text = f'تا کنون به تعداد {verification_tries}بار، ' \ + # f'درخواست تغییر رمز عبور داشته اید. به تعداد {remaining_verification_tries} ' \ + # f'دفعۀ دیگر می توانید برای دریافت کد تایید، درخواست نمایید. ' + # else: + # remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ + # 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' \ No newline at end of file diff --git a/BackEnd/utils/email.py b/BackEnd/utils/email.py index 7574297..f4a9dd7 100644 --- a/BackEnd/utils/email.py +++ b/BackEnd/utils/email.py @@ -7,9 +7,7 @@ def send_verification_message(subject, recipient_list, verification_token, registration_tries, show_text , token): - # remaining_registration_tries = project_variables.MAX_VERIFICATION_TRIES - registration_tries - context = { 'email_verification_token': verification_token, # 'remaining_text': remaining_text, @@ -21,19 +19,10 @@ def send_verification_message(subject, recipient_list, verification_token, regis email.attach_alternative(html_message, "text/html" ) #"text/html") email.send() - def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries): - remaining_verification_tries = project_variables.MAX_VERIFICATION_TRIES - verification_tries - if remaining_verification_tries < project_variables.MAX_VERIFICATION_TRIES: - remaining_text = f'تا کنون به تعداد {verification_tries}بار، ' \ - f'درخواست تغییر رمز عبور داشته اید. به تعداد {remaining_verification_tries} ' \ - f'دفعۀ دیگر می توانید برای دریافت کد تایید، درخواست نمایید. ' - else: - remaining_text = 'به سقف مجاز برای ثبت درخواست کد تایید رسیده اید. ' \ - 'پس از 12 ساعت انتظار، می توانید برای باری دیگر، برای دریافت کد تایید، درخواست نمایید.' context = { 'email_verification_token': verification_token, - 'remaining_text': remaining_text, + # 'remaining_text': remaining_text, } html_message = render_to_string('forget_password.html', context) From f5debc6393451632dff0f57c5376db74a11612c3 Mon Sep 17 00:00:00 2001 From: Asma Hamid Date: Mon, 18 Mar 2024 17:59:56 +0330 Subject: [PATCH 09/46] update imports --- BackEnd/accounts/serializers.py | 2 ++ BackEnd/accounts/views.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 7830dd2..503c313 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -3,6 +3,8 @@ from django.contrib.auth.password_validation import validate_password from django.contrib.auth import password_validation import utils.project_variables as project_variables +from django.utils.translation import gettext_lazy as _ + class UserSerializer(serializers.Serializer): class Meta: diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 4f29775..4361273 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -6,7 +6,7 @@ from rest_framework.views import APIView from rest_framework.generics import CreateAPIView , GenericAPIView from .serializers import SignUpSerializer , UserSerializer , ActivationConfirmSerializer ,ActivationResendSerializer \ - ,ForgotPasswordSerializer , ResetPasswordSerializer + ,ForgotPasswordSerializer , ResetPasswordSerializer , LoginSerializer from .models import User from datetime import datetime from django.contrib.sites.shortcuts import get_current_site From 5fcffa6dd3379dc93b2352cd4aea7d8a1affc8b1 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 18 Mar 2024 23:09:59 +0330 Subject: [PATCH 10/46] fix/reset_passwd --- BackEnd/.vscode/settings.json | 3 +++ BackEnd/accounts/serializers.py | 15 ++++++++------- BackEnd/accounts/views.py | 26 +++++++++++++------------- 3 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 BackEnd/.vscode/settings.json diff --git a/BackEnd/.vscode/settings.json b/BackEnd/.vscode/settings.json new file mode 100644 index 0000000..cee4243 --- /dev/null +++ b/BackEnd/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "iis.configDir": "" +} \ No newline at end of file diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 503c313..c2f3252 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -6,11 +6,15 @@ from django.utils.translation import gettext_lazy as _ -class UserSerializer(serializers.Serializer): +class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" ] #, "phone_number"] + def validate(self, attrs): + return super().validate(attrs) + + class SignUpSerializer(serializers.ModelSerializer): password2 = serializers.CharField(style={"input_type": "password"}, write_only=True) password1 = serializers.CharField( @@ -21,7 +25,7 @@ class SignUpSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ('email', 'date_of_birth', 'password1', 'password2' #'id' # i do not know whether its needed or not + fields = ('email', 'date_of_birth', 'password1', 'password2' , 'id' # i do not know whether its needed or not , 'gender' , 'firstname' , 'lastname') # , 'phone_number') extra_kwargs = { @@ -42,12 +46,10 @@ def validate_email(self, value): return str.lower(value) - # def validate_phone_number(self, attrs): # print(attrs) # return attrs - def validate_password2(self, value): if value != self.initial_data.get('password1'): @@ -113,6 +115,7 @@ class LoginSerializer(serializers.Serializer): style={"input_type": "password"}, write_only=True ) + token = serializers.CharField( label =_("Token"), read_only=True @@ -129,16 +132,14 @@ def validate(self, attrs): if not user.check_password(password): msg = _('Incorrect password.') raise serializers.ValidationError(msg, code='authorization') - if not user.is_email_verified: raise serializers.ValidationError({"detail": "User is not verified."}) - attrs['user'] = user else: msg = _('Must include "email" and "password".') raise serializers.ValidationError(msg, code='authorization') - return attrs + def validate_email(self, value): msg = _('Email does not exist.') diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 4361273..c503260 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -142,20 +142,22 @@ def post(self, request, *args, **kwargs): user.last_verification_sent = datetime.now() user.save() show_text = user.has_verification_tries_reset or user.verification_tries_count > 1 - token = generate_tokens(user)["access"] + token = generate_tokens(user.id)["access"] email_handler.send_verification_message(subject=subject, recipient_list=[user.email], verification_token=verification_code, registration_tries=user.verification_tries_count, - show_text=show_text) + show_text=show_text , + token=token) return Response({ "message": "email sent", - "url": f'{settings.WEBSITE_URL}accounts/activation-confirm/{token}', + "url": f'{settings.WEBSITE_URL}accounts/activation_confirm/{token}/', }, status=status.HTTP_200_OK) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + class ForgotPassword(GenericAPIView) : serializer_class = ForgotPasswordSerializer def post(self, request, *args, **kwargs) : @@ -202,7 +204,8 @@ def post(self, request, token ) : if serializer.validated_data['verification_code'] != user.verification_code: return Response({'message': 'Invalid code'}, status=status.HTTP_400_BAD_REQUEST) user.verification_code = None - user.password = make_password( serializer.validated_data['new_password']) , + new_password =serializer.validated_data['new_password'] + user.set_password(new_password) user.save() return Response( {"message" : "password successfully update"} , status=status.HTTP_204_NO_CONTENT) @@ -227,38 +230,35 @@ def validate_token(self, token): class LoginView(TokenObtainPairView): serializer_class = LoginSerializer - def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] if user is not None: tokens = generate_tokens(user.id) - - login(request, user) - + # login(request, user) + login(request, user, backend = 'django.contrib.auth.backends.ModelBackend') + user_serializer= UserSerializer( data= user) + user_serializer.is_valid() + print( user_serializer.data) return Response({ 'refresh': tokens['refresh'], 'access': tokens['access'], - 'user': UserSerializer(user).data, + 'user': user_serializer.validated_data }) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class LogoutView(APIView): permission_classes = [IsAuthenticated] - def get(self, request): refresh_token = request.COOKIES.get('token') - if refresh_token: try: token = RefreshToken(refresh_token) token.blacklist() except Exception as e: return Response(data={'detail': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) - response = Response(data={'detail': 'Logged out successfully'}, status=status.HTTP_200_OK) response.delete_cookie('refresh_token') response.delete_cookie('access_token') From 68f590d62c4213ed742b7bbf3f187817161b00f6 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Tue, 19 Mar 2024 09:12:56 +0330 Subject: [PATCH 11/46] feat/PhoneNumber --- BackEnd/BackEnd/settings.py | 3 +- BackEnd/accounts/admin.py | 12 +++--- .../0006_remove_user_phone_number_and_more.py | 24 ++++++++++++ .../0007_alter_user_last_verification_sent.py | 23 +++++++++++ .../0008_alter_user_last_verification_sent.py | 23 +++++++++++ .../0009_alter_user_last_verification_sent.py | 23 +++++++++++ .../0010_alter_user_last_verification_sent.py | 23 +++++++++++ .../0011_alter_user_last_verification_sent.py | 23 +++++++++++ ...umber_alter_user_last_verification_sent.py | 39 +++++++++++++++++++ .../0013_alter_user_last_verification_sent.py | 23 +++++++++++ .../0014_alter_user_last_verification_sent.py | 23 +++++++++++ .../0015_alter_user_last_verification_sent.py | 23 +++++++++++ .../0016_alter_user_last_verification_sent.py | 23 +++++++++++ .../0017_alter_user_last_verification_sent.py | 23 +++++++++++ .../0018_alter_user_last_verification_sent.py | 23 +++++++++++ .../0019_alter_user_last_verification_sent.py | 23 +++++++++++ .../0020_alter_user_last_verification_sent.py | 23 +++++++++++ .../0021_alter_user_last_verification_sent.py | 23 +++++++++++ BackEnd/accounts/models.py | 22 +++++++---- BackEnd/accounts/serializers.py | 8 ++-- BackEnd/accounts/views.py | 6 ++- BackEnd/templates/active_email.html | 5 +-- 22 files changed, 416 insertions(+), 25 deletions(-) create mode 100644 BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py create mode 100644 BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 249a03f..d7ce9e0 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -64,7 +64,6 @@ "accounts", "rest_framework", "rest_framework_swagger", - "phonenumber_field", "drf_yasg", ] @@ -148,6 +147,6 @@ AUTH_PROFILE_MODULE = 'accounts.User' AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.RemoteUserBackend', 'django.contrib.auth.backends.ModelBackend', + 'django.contrib.auth.backends.RemoteUserBackend', ) \ No newline at end of file diff --git a/BackEnd/accounts/admin.py b/BackEnd/accounts/admin.py index 38a487a..f002c9b 100644 --- a/BackEnd/accounts/admin.py +++ b/BackEnd/accounts/admin.py @@ -13,7 +13,7 @@ class UserCreationForm(forms.ModelForm): class Meta: model = User - fields = ('email', 'date_of_birth', 'gender' , 'firstname' , 'lastname') + fields = ('email', 'date_of_birth', 'gender' , 'firstname' , 'lastname' , 'phone_number') def clean_password2(self): # Check that the two password entries match @@ -37,7 +37,7 @@ class UserChangeForm(forms.ModelForm): class Meta: model = User - fields = ('firstname' , 'lastname' , 'gender','email', 'password', 'date_of_birth', 'is_active', 'is_admin') + fields = ('firstname' , 'lastname' , 'gender','email', 'password', 'date_of_birth', 'is_active', 'is_admin' , 'phone_number') def clean_password(self): return self.initial["password"] @@ -46,12 +46,12 @@ def clean_password(self): class UserAdmin(BaseUserAdmin): form = UserChangeForm add_form= UserCreationForm - list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active') #'is_email_verified' 'phone_number' - list_filter = ('is_admin' , 'email' ,'firstname', 'lastname') + list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active' , 'phone_number') #'is_email_verified' 'phone_number' + list_filter = ('is_admin' , 'email' ,'firstname', 'lastname' , 'phone_number') fieldsets=( (None, {'fields': ('email', 'password')}), - ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' )}), ## 'phone_number' - ('Permissions', {'fields': ( 'is_admin', 'is_active', )}), #'is_email_verified' + ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' ,'phone_number')}), ## 'phone_number' + ('Permissions', {'fields': ( 'is_admin', 'is_active','is_staff','is_email_verified' )}), #'is_email_verified' ) add_fieldsets = ( diff --git a/BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py b/BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py new file mode 100644 index 0000000..24e6d1b --- /dev/null +++ b/BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 5.0.3 on 2024-03-18 20:10 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0005_alter_user_email_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.RemoveField(model_name="user", name="phone_number",), + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 18, 23, 40, 51, 299155), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py new file mode 100644 index 0000000..653ac24 --- /dev/null +++ b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 00:32 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0006_remove_user_phone_number_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 4, 2, 12, 4622), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py new file mode 100644 index 0000000..a2905cf --- /dev/null +++ b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 00:36 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0007_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 4, 6, 21, 961294), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py new file mode 100644 index 0000000..90d31b8 --- /dev/null +++ b/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 00:38 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0008_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 4, 8, 17, 575274), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py new file mode 100644 index 0000000..b9d76ab --- /dev/null +++ b/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 00:39 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0009_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 4, 9, 21, 581054), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py new file mode 100644 index 0000000..c98801a --- /dev/null +++ b/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 00:52 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0010_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 4, 22, 54, 303130), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py new file mode 100644 index 0000000..ebb9bca --- /dev/null +++ b/BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py @@ -0,0 +1,39 @@ +# Generated by Django 5.0.3 on 2024-03-19 03:45 + +import datetime +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0011_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="phone_number", + field=models.CharField( + blank=True, + max_length=15, + null=True, + validators=[ + django.core.validators.RegexValidator( + message="Phone number must be in a valid Iranian format.", + regex="^\\+?98[09]\\d{9}$", + ) + ], + ), + ), + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 7, 15, 53, 124594), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py new file mode 100644 index 0000000..ddc490f --- /dev/null +++ b/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 03:54 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0012_user_phone_number_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 7, 24, 27, 598668), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py new file mode 100644 index 0000000..20db7fa --- /dev/null +++ b/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:03 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0013_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 7, 33, 18, 767684), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py new file mode 100644 index 0000000..aebfc60 --- /dev/null +++ b/BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:04 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0014_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 7, 34, 16, 323872), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py new file mode 100644 index 0000000..de84554 --- /dev/null +++ b/BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:05 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0015_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 7, 35, 14, 973135), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py new file mode 100644 index 0000000..12b9b57 --- /dev/null +++ b/BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:18 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0016_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 7, 48, 25, 258499), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py new file mode 100644 index 0000000..5731912 --- /dev/null +++ b/BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:30 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0017_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 8, 0, 15, 530811), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py new file mode 100644 index 0000000..8468e98 --- /dev/null +++ b/BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:42 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0018_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 8, 12, 6, 88539), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py new file mode 100644 index 0000000..779f2dc --- /dev/null +++ b/BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:56 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0019_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 8, 26, 47, 398552), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py new file mode 100644 index 0000000..caece08 --- /dev/null +++ b/BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-19 04:59 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0020_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 19, 8, 29, 2, 889074), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index 31722db..ba46876 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -4,12 +4,11 @@ from django.db import models from django.contrib.auth.models import AbstractBaseUser , BaseUserManager from datetime import datetime -# from phonenumber_field.modelfields import PhoneNumberField from django.core.validators import RegexValidator - +from django.contrib.auth.hashers import make_password class UserManager(BaseUserManager): - def create_user(self , email , firstname , phone , lastname , gender , date_of_birth, password=None ) : + def create_user(self , email , firstname , lastname , gender , date_of_birth, phone_number ,password=None) : #phone = None """ Creates and saves a User with the given email, data of birth and password @@ -23,19 +22,19 @@ def create_user(self , email , firstname , phone , lastname , gender , date_of_b firstname = firstname , lastname = lastname, gender= gender, - phone_number = phone + phone_number = phone_number ) user.set_password(password) user.save(using=self._db) return user - def create_superuser(self , email , firstname , phone ,lastname , gender , date_of_birth , password=None): + def create_superuser(self , email , firstname ,lastname , gender , phone_number, date_of_birth , password=None): #phone """ Creates and saves a superuser with the given email, birthdat and password. """ - + user = self.create_user( email=email, password=password, @@ -43,17 +42,23 @@ def create_superuser(self , email , firstname , phone ,lastname , gender , date_ firstname = firstname , lastname = lastname, gender= gender, - phone=phone + phone_number=phone_number ) user.is_admin = True user.is_superuser = True + user.is_email_verified = True + user.is_active = True user.save(using=self._db) return user + def save(self, *args, **kwargs): + self.password = make_password(self.password) + def get_by_natural_key(self, email): return self.get(email=email) + class User(AbstractBaseUser): GENDER_Male = 'M' GENDER_Female = 'F' @@ -69,12 +74,13 @@ class User(AbstractBaseUser): unique = True, ) USERNAME_FIELD = 'email' - # REQUIRED_FIELDS = ['password'] + REQUIRED_FIELDS = [ 'firstname', 'lastname', 'gender', 'date_of_birth' , 'phone_number'] objects = UserManager() date_of_birth= models.DateField() gender = models.CharField(max_length=1, choices=GENDER_CHOICES) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) + phone_number_regex = r'^\+?98[09]\d{9}$' phone_number_validator = RegexValidator( regex=phone_number_regex, diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index c2f3252..02c4f54 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -9,7 +9,7 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" ] #, "phone_number"] + fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" , "phone_number" ] #, "phone_number"] def validate(self, attrs): return super().validate(attrs) @@ -26,7 +26,7 @@ class SignUpSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('email', 'date_of_birth', 'password1', 'password2' , 'id' # i do not know whether its needed or not - , 'gender' , 'firstname' , 'lastname') # , 'phone_number') + , 'gender' , 'firstname' , 'lastname' , 'phone_number') # , 'phone_number') extra_kwargs = { 'password1': {'write_only': True}, @@ -41,8 +41,8 @@ def validate_email(self, value): raise serializers.ValidationError("Email already exists.") # if user.verification_tries_count >= project_variables.MAX_VERIFICATION_TRIES: # raise serializers.ValidationError("You have reached the maximum number of registration tries.") - # if user.phone_number != self.initial_data.get('phone_number'): - # raise serializers.ValidationError("Email already exists.") + if user.phone_number != self.initial_data.get('phone_number'): + raise serializers.ValidationError("Email already exists.") return str.lower(value) diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index c503260..2c8e1d3 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -43,7 +43,8 @@ def post(self,request ) : user.gender = validated_data['gender'] user.firstname = validated_data['firstname'] user.lastname = validated_data['lastname'] - user.date_of_birth = validated_data['date_of_birth'] , + user.date_of_birth = validated_data['date_of_birth'] + user.phone_number = validated_data['phone_number'] user.verification_code = verification_code user.verification_tries_count += 1 user.last_verification_sent = datetime.now() @@ -56,6 +57,7 @@ def post(self,request ) : gender = validated_data['gender'], date_of_birth = validated_data['date_of_birth'] , password = make_password( validated_data['password1']) , + phone_number = validated_data['phone_number'] , verification_code=verification_code, verification_tries_count=1, last_verification_sent=datetime.now(), @@ -106,7 +108,7 @@ def post(self, request, token): user.is_email_verified = True user.verification_code = None user.save() - return Response('successfull_activation.html', status=status.HTTP_200_OK) + return Response({'message' : 'successfully verified'}, status=status.HTTP_200_OK) def get_user_from_token(self, token): diff --git a/BackEnd/templates/active_email.html b/BackEnd/templates/active_email.html index dece3a3..b31a139 100644 --- a/BackEnd/templates/active_email.html +++ b/BackEnd/templates/active_email.html @@ -45,9 +45,8 @@

کد تایید ایمیل:

{{ email_verification_token }}

-

{{ remaining_text }}

-

برای تایید ایمیل خود بر روی دکمه زیر کلیک کنید:

- تایید ایمیل +
From d301e1041221865653bbc01fa1c2f7f1a76f32b2 Mon Sep 17 00:00:00 2001 From: Asma Hamid Date: Tue, 19 Mar 2024 09:48:57 +0330 Subject: [PATCH 12/46] feat/loginupdate --- BackEnd/accounts/serializers.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 02c4f54..b38f418 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -3,7 +3,6 @@ from django.contrib.auth.password_validation import validate_password from django.contrib.auth import password_validation import utils.project_variables as project_variables -from django.utils.translation import gettext_lazy as _ class UserSerializer(serializers.ModelSerializer): @@ -108,16 +107,16 @@ def validate(self, attrs): class LoginSerializer(serializers.Serializer): email=serializers.EmailField( - label=_("Email"), + label=("Email"), ) password = serializers.CharField( - label=_("password"), + label=("password"), style={"input_type": "password"}, write_only=True ) token = serializers.CharField( - label =_("Token"), + label =("Token"), read_only=True ) @@ -130,19 +129,19 @@ def validate(self, attrs): user = User.objects.get(email__iexact=email) if not user.check_password(password): - msg = _('Incorrect password.') + msg = ('Incorrect password.') raise serializers.ValidationError(msg, code='authorization') if not user.is_email_verified: raise serializers.ValidationError({"detail": "User is not verified."}) attrs['user'] = user else: - msg = _('Must include "email" and "password".') + msg = ('Must include "email" and "password".') raise serializers.ValidationError(msg, code='authorization') return attrs def validate_email(self, value): - msg = _('Email does not exist.') + msg = ('Email does not exist.') user_exists = User.objects.filter(email__iexact=value).exists() if not user_exists: From 53aa9fbfc4951fbc159e99cced8a5cf7ad9992fa Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 22 Mar 2024 22:45:08 +0330 Subject: [PATCH 13/46] fix/logout --- BackEnd/BackEnd/settings.py | 43 +++++++++++++++-- .../0022_alter_user_last_verification_sent.py | 23 ++++++++++ BackEnd/accounts/views.py | 14 +++--- BackEnd/templates/forget_password.html | 46 +++++++++---------- BackEnd/utils/email.py | 1 + client.py | 5 -- 6 files changed, 91 insertions(+), 41 deletions(-) create mode 100644 BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py delete mode 100644 client.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index d7ce9e0..63a7edc 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -13,6 +13,8 @@ from pathlib import Path from environs import Env import os +import datetime +from datetime import timedelta # Environment Variables @@ -41,16 +43,48 @@ CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] SESSION_COOKIE_DOMAIN = "http://localserver:8000" -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES' : [ 'rest_framework.permissions.AllowAny' ], 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' , - # 'DEFAULT_AUTHENTICATION_CLASSES' : [ - # 'rest_framework_simplejwt.authentication.JWTAuthentication', - # ] + 'DEFAULT_AUTHENTICATION_CLASSES' : [ + 'rest_framework.authentication.SessionAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', + 'rest_framework.authentication.TokenAuthentication', + ] +} + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(days=10), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=10), + 'ROTATE_REFRESH_TOKENS': False, + 'BLACKLIST_AFTER_ROTATION': False, + 'UPDATE_LAST_LOGIN': False, + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUDIENCE': None, + 'ISSUER': None, + 'JWK_URL': None, + 'LEEWAY': 0, + 'AUTH_HEADER_TYPES': ('Bearer',), + 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', + 'USER_ID_FIELD': 'id', + 'USER_ID_CLAIM': 'user_id', + 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', + + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), + 'TOKEN_TYPE_CLAIM': 'token_type', + 'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser', + + 'JTI_CLAIM': 'jti', + + 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', + 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=15), + 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), } # Application definition @@ -64,6 +98,7 @@ "accounts", "rest_framework", "rest_framework_swagger", + "rest_framework_simplejwt.token_blacklist", "drf_yasg", ] diff --git a/BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py new file mode 100644 index 0000000..d829a28 --- /dev/null +++ b/BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-21 22:50 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0021_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 22, 2, 20, 17, 133087), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 2c8e1d3..2d18127 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -2,6 +2,7 @@ from django.contrib.auth.hashers import make_password from rest_framework import status from rest_framework.permissions import IsAuthenticated +from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.generics import CreateAPIView , GenericAPIView @@ -26,7 +27,6 @@ from utils.project_variables import MAX_VERIFICATION_TRIES - class SignUpView(CreateAPIView): serializer_class = SignUpSerializer def post(self,request ) : @@ -240,34 +240,32 @@ def post(self, request, *args, **kwargs): tokens = generate_tokens(user.id) # login(request, user) login(request, user, backend = 'django.contrib.auth.backends.ModelBackend') - user_serializer= UserSerializer( data= user) - user_serializer.is_valid() - print( user_serializer.data) + return Response({ 'refresh': tokens['refresh'], 'access': tokens['access'], - 'user': user_serializer.validated_data + 'user': UserSerializer(user).data }) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class LogoutView(APIView): permission_classes = [IsAuthenticated] - def get(self, request): + def get(self, request): + print(request.COOKIES) refresh_token = request.COOKIES.get('token') if refresh_token: try: token = RefreshToken(refresh_token) token.blacklist() except Exception as e: + return Response(data={'detail': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) response = Response(data={'detail': 'Logged out successfully'}, status=status.HTTP_200_OK) response.delete_cookie('refresh_token') response.delete_cookie('access_token') return response - if request.user.is_authenticated: logout(request) return Response(data={'detail': 'Logged out successfully'}, status=status.HTTP_200_OK) - return Response(data={'detail': 'Not logged in'}, status=status.HTTP_400_BAD_REQUEST) diff --git a/BackEnd/templates/forget_password.html b/BackEnd/templates/forget_password.html index c6f365d..b31a139 100644 --- a/BackEnd/templates/forget_password.html +++ b/BackEnd/templates/forget_password.html @@ -4,9 +4,9 @@ - کد تایید + تایید ایمیل - -
- - -

- - - -
+ +
+

کد تایید ایمیل:

+

{{ email_verification_token }}

+ +
-{% endautoescape %} +{% endautoescape %} + diff --git a/BackEnd/utils/email.py b/BackEnd/utils/email.py index f4a9dd7..ac87c69 100644 --- a/BackEnd/utils/email.py +++ b/BackEnd/utils/email.py @@ -19,6 +19,7 @@ def send_verification_message(subject, recipient_list, verification_token, regis email.attach_alternative(html_message, "text/html" ) #"text/html") email.send() + def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries): context = { 'email_verification_token': verification_token, diff --git a/client.py b/client.py deleted file mode 100644 index 052c08c..0000000 --- a/client.py +++ /dev/null @@ -1,5 +0,0 @@ -import requests - - - -endpoint = "" \ No newline at end of file From 1e00bd5831bb80544e5d15dc9e4bbf2aa54e34a4 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 25 Mar 2024 14:14:15 +0330 Subject: [PATCH 14/46] feat/counseling --- BackEnd/counseling/__init__.py | 0 BackEnd/counseling/admin.py | 3 +++ BackEnd/counseling/apps.py | 6 ++++++ BackEnd/counseling/migrations/__init__.py | 0 BackEnd/counseling/models.py | 3 +++ BackEnd/counseling/tests.py | 3 +++ BackEnd/counseling/views.py | 3 +++ 7 files changed, 18 insertions(+) create mode 100644 BackEnd/counseling/__init__.py create mode 100644 BackEnd/counseling/admin.py create mode 100644 BackEnd/counseling/apps.py create mode 100644 BackEnd/counseling/migrations/__init__.py create mode 100644 BackEnd/counseling/models.py create mode 100644 BackEnd/counseling/tests.py create mode 100644 BackEnd/counseling/views.py diff --git a/BackEnd/counseling/__init__.py b/BackEnd/counseling/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/counseling/admin.py b/BackEnd/counseling/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/BackEnd/counseling/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/BackEnd/counseling/apps.py b/BackEnd/counseling/apps.py new file mode 100644 index 0000000..5906f63 --- /dev/null +++ b/BackEnd/counseling/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CounselingConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "counseling" diff --git a/BackEnd/counseling/migrations/__init__.py b/BackEnd/counseling/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/BackEnd/counseling/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/BackEnd/counseling/tests.py b/BackEnd/counseling/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BackEnd/counseling/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BackEnd/counseling/views.py b/BackEnd/counseling/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/BackEnd/counseling/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From a57d6b13bc976bbee3c9d6d9f2cc37a65c9524d6 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 27 Mar 2024 00:39:18 +0330 Subject: [PATCH 15/46] feat/CompleteInfo --- .gitignore | 195 ++++++++++++++++++ BackEnd/BackEnd/settings.py | 12 +- BackEnd/BackEnd/urls.py | 1 + BackEnd/accounts/admin.py | 13 +- BackEnd/accounts/migrations/0001_initial.py | 30 ++- .../0002_alter_user_last_verification_sent.py | 4 +- ..._of_birth_alter_user_firstname_and_more.py | 47 +++++ ...email_alter_user_last_verification_sent.py | 26 --- ...er_user_last_verification_sent_and_more.py | 39 ---- ...email_alter_user_last_verification_sent.py | 28 --- .../0006_remove_user_phone_number_and_more.py | 24 --- .../0007_alter_user_last_verification_sent.py | 23 --- .../0008_alter_user_last_verification_sent.py | 23 --- .../0009_alter_user_last_verification_sent.py | 23 --- .../0010_alter_user_last_verification_sent.py | 23 --- .../0011_alter_user_last_verification_sent.py | 23 --- ...umber_alter_user_last_verification_sent.py | 39 ---- .../0013_alter_user_last_verification_sent.py | 23 --- .../0014_alter_user_last_verification_sent.py | 23 --- .../0015_alter_user_last_verification_sent.py | 23 --- .../0016_alter_user_last_verification_sent.py | 23 --- .../0017_alter_user_last_verification_sent.py | 23 --- .../0018_alter_user_last_verification_sent.py | 23 --- .../0019_alter_user_last_verification_sent.py | 23 --- .../0020_alter_user_last_verification_sent.py | 23 --- .../0021_alter_user_last_verification_sent.py | 23 --- .../0022_alter_user_last_verification_sent.py | 23 --- BackEnd/accounts/models.py | 54 +++-- BackEnd/accounts/serializers.py | 26 ++- BackEnd/accounts/urls.py | 1 + BackEnd/accounts/views.py | 86 +++++--- BackEnd/counseling/admin.py | 3 + BackEnd/counseling/migrations/0001_initial.py | 79 +++++++ BackEnd/counseling/models.py | 24 ++- BackEnd/counseling/urls.py | 0 requirements.txt | 36 +--- 36 files changed, 509 insertions(+), 603 deletions(-) create mode 100644 BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py delete mode 100644 BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py delete mode 100644 BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py delete mode 100644 BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py create mode 100644 BackEnd/counseling/migrations/0001_initial.py create mode 100644 BackEnd/counseling/urls.py diff --git a/.gitignore b/.gitignore index 8f5a046..8940219 100644 --- a/.gitignore +++ b/.gitignore @@ -283,3 +283,198 @@ pyrightconfig.json .ionide # End of https://www.toptal.com/developers/gitignore/api/django,python,visualstudiocode + + +# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,django +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,django + +### Django ### +*.log +*.pot +*.pyc +__pycache__/ +local_settings.py +db.sqlite3 +db.sqlite3-journal +media + +# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ +# in your Git repository. Update and uncomment the following line accordingly. +# /staticfiles/ + +### Django.Python Stack ### +# Byte-compiled / optimized / DLL files +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo + +# Django stuff: + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,django diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 63a7edc..420e5a8 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -41,8 +41,13 @@ EMAIL_USE_TLS = True REDIS_HOST = os.environ.get('REDIS_HOST', '127.0.0.1') CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] -SESSION_COOKIE_DOMAIN = "http://localserver:8000" +# SESSION_COOKIE_DOMAIN = "http://localserver:8000" + +SESSION_COOKIE_SECURE = False +SESSION_EXPIRE_AT_BROWSER_CLOSE = False + +# SESSION_COOKIE_DOMAIN ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = { @@ -100,6 +105,7 @@ "rest_framework_swagger", "rest_framework_simplejwt.token_blacklist", "drf_yasg", + "counseling", ] MIDDLEWARE = [ @@ -112,6 +118,10 @@ "django.middleware.clickjacking.XFrameOptionsMiddleware", ] + +MEDIA_ROOT = os.path.join(BASE_DIR, "media") +MEDIA_URL = "/media/" + ROOT_URLCONF = "BackEnd.urls" TEMPLATES = [ diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index f914282..0a66b67 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -37,5 +37,6 @@ path("admin/", admin.site.urls), path("accounts/" , include("accounts.urls")), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), + # path('counseling/' , include("counseling.urls")) , path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ] diff --git a/BackEnd/accounts/admin.py b/BackEnd/accounts/admin.py index f002c9b..8f3e17c 100644 --- a/BackEnd/accounts/admin.py +++ b/BackEnd/accounts/admin.py @@ -7,13 +7,14 @@ from .models import User + class UserCreationForm(forms.ModelForm): password1 = forms.CharField(label='Password', widget=forms.PasswordInput) password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) class Meta: model = User - fields = ('email', 'date_of_birth', 'gender' , 'firstname' , 'lastname' , 'phone_number') + fields = ('email', 'date_of_birth', 'gender' , 'firstname' , 'lastname' , 'phone_number' , 'role') def clean_password2(self): # Check that the two password entries match @@ -37,7 +38,7 @@ class UserChangeForm(forms.ModelForm): class Meta: model = User - fields = ('firstname' , 'lastname' , 'gender','email', 'password', 'date_of_birth', 'is_active', 'is_admin' , 'phone_number') + fields = ('firstname' , 'lastname' , 'gender','email', 'password', 'date_of_birth', 'is_active', 'is_admin' , 'phone_number' , 'role') def clean_password(self): return self.initial["password"] @@ -46,12 +47,12 @@ def clean_password(self): class UserAdmin(BaseUserAdmin): form = UserChangeForm add_form= UserCreationForm - list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active' , 'phone_number') #'is_email_verified' 'phone_number' - list_filter = ('is_admin' , 'email' ,'firstname', 'lastname' , 'phone_number') + list_display = ('email' ,'firstname', 'lastname', 'date_of_birth' , 'is_admin' , 'is_active' , 'phone_number' , 'role') #'is_email_verified' 'phone_number' + list_filter = ('is_admin' , 'email' ,'firstname', 'lastname' , 'phone_number' , 'role') fieldsets=( (None, {'fields': ('email', 'password')}), - ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' ,'phone_number')}), ## 'phone_number' - ('Permissions', {'fields': ( 'is_admin', 'is_active','is_staff','is_email_verified' )}), #'is_email_verified' + ('Personal info', {'fields': ('date_of_birth','firstname', 'lastname' ,'gender' ,'phone_number' , 'role')}), ## 'phone_number' + ('Permissions', {'fields': ( 'is_admin', 'is_active','is_email_verified' )}), #'is_email_verified' ) add_fieldsets = ( diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index b4fe3d7..cf77ff5 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,7 +1,7 @@ -# Generated by Django 5.0.3 on 2024-03-17 21:28 +# Generated by Django 5.0.3 on 2024-03-26 07:51 import datetime -import phonenumber_field.modelfields +import django.core.validators from django.db import migrations, models @@ -45,8 +45,28 @@ class Migration(migrations.Migration): ("is_admin", models.BooleanField(default=False)), ( "phone_number", - phonenumber_field.modelfields.PhoneNumberField( - blank=True, max_length=128, null=True, region="IR", unique=True + models.CharField( + blank=True, + max_length=15, + null=True, + validators=[ + django.core.validators.RegexValidator( + message="Phone number must be in a valid Iranian format.", + regex="^\\+?98[09]\\d{9}$", + ) + ], + ), + ), + ( + "role", + models.CharField( + choices=[ + ("user", "User"), + ("doctor", "Doctor"), + ("admin", "Admin"), + ], + default="user", + max_length=255, ), ), ("is_email_verified", models.BooleanField(default=False)), @@ -59,7 +79,7 @@ class Migration(migrations.Migration): "last_verification_sent", models.DateTimeField( blank=True, - default=datetime.datetime(2024, 3, 18, 0, 58, 5, 405953), + default=datetime.datetime(2024, 3, 26, 11, 21, 14, 482484), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py index f5da8e9..7dc0dc6 100644 --- a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py +++ b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-03-17 21:31 +# Generated by Django 5.0.3 on 2024-03-26 07:51 import datetime from django.db import migrations, models @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 3, 18, 1, 1, 1, 755346), + default=datetime.datetime(2024, 3, 26, 11, 21, 19, 671522), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py b/BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py new file mode 100644 index 0000000..3164013 --- /dev/null +++ b/BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py @@ -0,0 +1,47 @@ +# Generated by Django 5.0.3 on 2024-03-26 14:14 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0002_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="date_of_birth", + field=models.DateField(blank=True, null=True), + ), + migrations.AlterField( + model_name="user", + name="firstname", + field=models.CharField(blank=True, max_length=20, null=True), + ), + migrations.AlterField( + model_name="user", + name="gender", + field=models.CharField( + choices=[("F", "Female"), ("M", "Male"), ("B", "Both")], + max_length=1, + null=True, + ), + ), + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 26, 17, 44, 8, 963102), + null=True, + ), + ), + migrations.AlterField( + model_name="user", + name="lastname", + field=models.CharField(blank=True, max_length=30, null=True), + ), + ] diff --git a/BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py deleted file mode 100644 index ab4333f..0000000 --- a/BackEnd/accounts/migrations/0003_alter_user_email_alter_user_last_verification_sent.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-17 22:19 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0002_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", name="email", field=models.EmailField(max_length=255), - ), - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 18, 1, 49, 49, 351782), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py deleted file mode 100644 index 4500806..0000000 --- a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-18 02:21 - -import datetime -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0003_alter_user_email_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 18, 5, 50, 59, 784601), - null=True, - ), - ), - migrations.AlterField( - model_name="user", - name="phone_number", - field=models.CharField( - blank=True, - max_length=15, - null=True, - validators=[ - django.core.validators.RegexValidator( - message="Phone number must be in a valid Iranian format.", - regex="^\\+?98[09]\\d{9}$", - ) - ], - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py deleted file mode 100644 index 01abd57..0000000 --- a/BackEnd/accounts/migrations/0005_alter_user_email_alter_user_last_verification_sent.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-18 05:29 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0004_alter_user_last_verification_sent_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="email", - field=models.EmailField(max_length=255, unique=True), - ), - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 18, 8, 59, 32, 145834), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py b/BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py deleted file mode 100644 index 24e6d1b..0000000 --- a/BackEnd/accounts/migrations/0006_remove_user_phone_number_and_more.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-18 20:10 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0005_alter_user_email_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.RemoveField(model_name="user", name="phone_number",), - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 18, 23, 40, 51, 299155), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py deleted file mode 100644 index 653ac24..0000000 --- a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 00:32 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0006_remove_user_phone_number_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 4, 2, 12, 4622), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py deleted file mode 100644 index a2905cf..0000000 --- a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 00:36 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0007_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 4, 6, 21, 961294), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py deleted file mode 100644 index 90d31b8..0000000 --- a/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 00:38 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0008_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 4, 8, 17, 575274), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py deleted file mode 100644 index b9d76ab..0000000 --- a/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 00:39 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0009_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 4, 9, 21, 581054), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py deleted file mode 100644 index c98801a..0000000 --- a/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 00:52 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0010_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 4, 22, 54, 303130), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py deleted file mode 100644 index ebb9bca..0000000 --- a/BackEnd/accounts/migrations/0012_user_phone_number_alter_user_last_verification_sent.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 03:45 - -import datetime -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0011_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="phone_number", - field=models.CharField( - blank=True, - max_length=15, - null=True, - validators=[ - django.core.validators.RegexValidator( - message="Phone number must be in a valid Iranian format.", - regex="^\\+?98[09]\\d{9}$", - ) - ], - ), - ), - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 7, 15, 53, 124594), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py deleted file mode 100644 index ddc490f..0000000 --- a/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 03:54 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0012_user_phone_number_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 7, 24, 27, 598668), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py deleted file mode 100644 index 20db7fa..0000000 --- a/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:03 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0013_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 7, 33, 18, 767684), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py deleted file mode 100644 index aebfc60..0000000 --- a/BackEnd/accounts/migrations/0015_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:04 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0014_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 7, 34, 16, 323872), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py deleted file mode 100644 index de84554..0000000 --- a/BackEnd/accounts/migrations/0016_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:05 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0015_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 7, 35, 14, 973135), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py deleted file mode 100644 index 12b9b57..0000000 --- a/BackEnd/accounts/migrations/0017_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:18 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0016_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 7, 48, 25, 258499), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py deleted file mode 100644 index 5731912..0000000 --- a/BackEnd/accounts/migrations/0018_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:30 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0017_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 8, 0, 15, 530811), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py deleted file mode 100644 index 8468e98..0000000 --- a/BackEnd/accounts/migrations/0019_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:42 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0018_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 8, 12, 6, 88539), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py deleted file mode 100644 index 779f2dc..0000000 --- a/BackEnd/accounts/migrations/0020_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:56 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0019_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 8, 26, 47, 398552), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py deleted file mode 100644 index caece08..0000000 --- a/BackEnd/accounts/migrations/0021_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-19 04:59 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0020_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 19, 8, 29, 2, 889074), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py deleted file mode 100644 index d829a28..0000000 --- a/BackEnd/accounts/migrations/0022_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-21 22:50 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0021_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 22, 2, 20, 17, 133087), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index ba46876..dc3d1a5 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -29,7 +29,7 @@ def create_user(self , email , firstname , lastname , gender , date_of_birth, ph user.save(using=self._db) return user - def create_superuser(self , email , firstname ,lastname , gender , phone_number, date_of_birth , password=None): #phone + def create_superuser(self , email ,password=None): #phone firstname ,lastname , gender , phone_number, date_of_birth , """ Creates and saves a superuser with the given email, birthdat and password. @@ -38,20 +38,22 @@ def create_superuser(self , email , firstname ,lastname , gender , phone_number, user = self.create_user( email=email, password=password, - date_of_birth=date_of_birth, - firstname = firstname , - lastname = lastname, - gender= gender, - phone_number=phone_number + date_of_birth="2000-3-3", + firstname = "admin" , + lastname = "adminzadeh", + gender= 'B', + phone_number="+989999999999" ) user.is_admin = True user.is_superuser = True user.is_email_verified = True user.is_active = True + user.role = User.TYPE_ADMIN user.save(using=self._db) return user + def save(self, *args, **kwargs): self.password = make_password(self.password) @@ -59,29 +61,42 @@ def get_by_natural_key(self, email): return self.get(email=email) + class User(AbstractBaseUser): GENDER_Male = 'M' GENDER_Female = 'F' + GENDER_BOTH = 'B' GENDER_CHOICES = [ (GENDER_Female, 'Female'), (GENDER_Male, 'Male'), + (GENDER_BOTH , 'Both') ] - firstname = models.CharField(max_length=20 ) - lastname = models.CharField(max_length=30 ) + TYPE_USER = "user" + TYPE_DOCTOR = "doctor" + TYPE_ADMIN = "admin" + + CHOICES = ( + (TYPE_USER , "User") , + (TYPE_DOCTOR , "Doctor") , + (TYPE_ADMIN , "Admin") + ) + + firstname = models.CharField(max_length=20 , blank=True, null = True ) + lastname = models.CharField(max_length=30 , blank=True, null = True ) email = models.EmailField( max_length= 255 , unique = True, ) USERNAME_FIELD = 'email' - REQUIRED_FIELDS = [ 'firstname', 'lastname', 'gender', 'date_of_birth' , 'phone_number'] + objects = UserManager() - date_of_birth= models.DateField() - gender = models.CharField(max_length=1, choices=GENDER_CHOICES) + date_of_birth= models.DateField(blank=True , null = True) + gender = models.CharField(max_length=1, choices=GENDER_CHOICES ,null=True ) # default = GENDER_BOTH, is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) - phone_number_regex = r'^\+?98[09]\d{9}$' + phone_number_regex = r'^(?:\+98|0)(?:\s?)9[0-9]{9}$' phone_number_validator = RegexValidator( regex=phone_number_regex, message="Phone number must be in a valid Iranian format." @@ -93,7 +108,8 @@ class User(AbstractBaseUser): blank=True, null=True ) - + role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) + # email varification is_email_verified = models.BooleanField(default=False) verification_code = models.CharField(max_length=4, null=True, blank=True) @@ -101,6 +117,8 @@ class User(AbstractBaseUser): last_verification_sent = models.DateTimeField(null=True, blank=True, default=datetime.now()) has_verification_tries_reset = models.BooleanField(default=False) + def get_role(self ) : + return self.role def __str__(self): return self.email @@ -120,7 +138,11 @@ def is_staff(self): # Simplest possible answer: All admins are staff return self.is_admin - - - \ No newline at end of file + # profile = GenericRelation(to=Profile, related_query_name='user') + + # def get_default_profile_image(self): + # if self.gender == 'M': + # return 'images/profile_pics/male_default.png' + # else: + # return 'images/profile_pics/female_default.png' \ No newline at end of file diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index b38f418..4c29a4e 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -2,18 +2,29 @@ from accounts.models import User from django.contrib.auth.password_validation import validate_password from django.contrib.auth import password_validation -import utils.project_variables as project_variables class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" , "phone_number" ] #, "phone_number"] + fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" , "phone_number" , "role" ] #, "phone_number"] def validate(self, attrs): return super().validate(attrs) +class CompleteInfoSerializer(serializers.ModelSerializer ) : + + class Meta: + model = User + fields = ['firstname' , 'lastname' , 'phone_number' , 'date_of_birth','gender' ] + + def validate(self, attrs): + return super().validate(attrs) + + + + class SignUpSerializer(serializers.ModelSerializer): password2 = serializers.CharField(style={"input_type": "password"}, write_only=True) password1 = serializers.CharField( @@ -24,9 +35,8 @@ class SignUpSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ('email', 'date_of_birth', 'password1', 'password2' , 'id' # i do not know whether its needed or not - , 'gender' , 'firstname' , 'lastname' , 'phone_number') # , 'phone_number') - + fields = ('email','password1', 'password2' ) + extra_kwargs = { 'password1': {'write_only': True}, 'password2': {'write_only': True}, @@ -38,16 +48,12 @@ def validate_email(self, value): user = user.first() if user.is_email_verified: raise serializers.ValidationError("Email already exists.") - # if user.verification_tries_count >= project_variables.MAX_VERIFICATION_TRIES: - # raise serializers.ValidationError("You have reached the maximum number of registration tries.") if user.phone_number != self.initial_data.get('phone_number'): raise serializers.ValidationError("Email already exists.") return str.lower(value) - # def validate_phone_number(self, attrs): - # print(attrs) - # return attrs + def validate_password2(self, value): diff --git a/BackEnd/accounts/urls.py b/BackEnd/accounts/urls.py index f3c1a17..f557f19 100644 --- a/BackEnd/accounts/urls.py +++ b/BackEnd/accounts/urls.py @@ -8,6 +8,7 @@ path('activation_resend/', ActivationResend.as_view(), name='activation_resend'), path('forgot_password/' , ForgotPassword.as_view() , name='forgot_password'), path('reset_password//', ResetPassword.as_view(), name='reset_password'), + path('complete_info/' , CompleteInfoView.as_view() , name= 'complete_info') , path('Login/',LoginView.as_view(),name='Login'), path('Logout/',LogoutView.as_view(),name='Logout'), ] \ No newline at end of file diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 2d18127..4851af3 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -7,7 +7,7 @@ from rest_framework.views import APIView from rest_framework.generics import CreateAPIView , GenericAPIView from .serializers import SignUpSerializer , UserSerializer , ActivationConfirmSerializer ,ActivationResendSerializer \ - ,ForgotPasswordSerializer , ResetPasswordSerializer , LoginSerializer + ,ForgotPasswordSerializer , ResetPasswordSerializer , LoginSerializer , CompleteInfoSerializer from .models import User from datetime import datetime from django.contrib.sites.shortcuts import get_current_site @@ -25,7 +25,7 @@ from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.tokens import RefreshToken from utils.project_variables import MAX_VERIFICATION_TRIES - +from counseling.models import Pationt class SignUpView(CreateAPIView): serializer_class = SignUpSerializer @@ -37,32 +37,17 @@ def post(self,request ) : # verification code verification_code = str(random.randint(1000, 9999)) user = User.objects.filter(email__iexact = email ) - # if user signup before and not verified - if user.exists() : - user = user.first() - user.gender = validated_data['gender'] - user.firstname = validated_data['firstname'] - user.lastname = validated_data['lastname'] - user.date_of_birth = validated_data['date_of_birth'] - user.phone_number = validated_data['phone_number'] - user.verification_code = verification_code - user.verification_tries_count += 1 - user.last_verification_sent = datetime.now() - user.save() - else : - user = User.objects.create( - email = email, - firstname = validated_data['firstname'], - lastname = validated_data['lastname'], - gender = validated_data['gender'], - date_of_birth = validated_data['date_of_birth'] , - password = make_password( validated_data['password1']) , - phone_number = validated_data['phone_number'] , - verification_code=verification_code, - verification_tries_count=1, - last_verification_sent=datetime.now(), - ) - # varify email + user = User.objects.create( + email = email, + password = make_password( validated_data['password1']) , + verification_code=verification_code, + verification_tries_count=1, + last_verification_sent=datetime.now(), + ) + + # TODO make sure it is locate in right place + Pationt.objects.create( user= user ) + # varify email token = generate_tokens(user.id)["access"] subject = 'تایید ایمیل ثبت نام' show_text = user.has_verification_tries_reset or user.verification_tries_count > 1 @@ -83,6 +68,7 @@ def post(self,request ) : } return Response(user_data, status=status.HTTP_201_CREATED) + class ActivationConfirmView(GenericAPIView): serializer_class = ActivationConfirmSerializer @@ -110,7 +96,6 @@ def post(self, request, token): user.save() return Response({'message' : 'successfully verified'}, status=status.HTTP_200_OK) - def get_user_from_token(self, token): try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) @@ -130,6 +115,7 @@ def validate_token(self, token): return None + class ActivationResend(GenericAPIView): serializer_class = ActivationResendSerializer permission_classes = [] @@ -249,6 +235,27 @@ def post(self, request, *args, **kwargs): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) +class CompleteInfoView(GenericAPIView) : + permission_classes = [IsAuthenticated] + serializer_class = CompleteInfoSerializer + def post( self , request ) : + serializer = CompleteInfoSerializer(data=request.data ) + serializer.is_valid(raise_exception=True) + validated_data = serializer.validated_data + email = str.lower( request.user.email) + user = User.objects.filter( email__iexact = email ) + if not user.exists(): + return Response({'message': 'Invalid user'}, status=status.HTTP_400_BAD_REQUEST) + user = user.first() + user.firstname = validated_data["firstname"] + user.gender = validated_data['gender'] + user.lastname = validated_data['lastname'] + user.date_of_birth = validated_data['date_of_birth'] + user.phone_number = validated_data['phone_number'] + user.save() + return Response(data={'message' : 'successfully updated'}, status=status.HTTP_200_OK) + + class LogoutView(APIView): permission_classes = [IsAuthenticated] def get(self, request): @@ -269,3 +276,24 @@ def get(self, request): logout(request) return Response(data={'detail': 'Logged out successfully'}, status=status.HTTP_200_OK) return Response(data={'detail': 'Not logged in'}, status=status.HTTP_400_BAD_REQUEST) + + + + + + + + +# if user signup before and not verified + # if user.exists() : + # user = user.first() + # user.gender = validated_data['gender'] + # user.firstname = validated_data['firstname'] + # user.lastname = validated_data['lastname'] + # user.date_of_birth = validated_data['date_of_birth'] + # user.phone_number = validated_data['phone_number'] + # user.verification_code = verification_code + # user.verification_tries_count += 1 + # user.last_verification_sent = datetime.now() + # user.save() + # else : \ No newline at end of file diff --git a/BackEnd/counseling/admin.py b/BackEnd/counseling/admin.py index 8c38f3f..2568aa0 100644 --- a/BackEnd/counseling/admin.py +++ b/BackEnd/counseling/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin +from .models import Pationt , Psychiatrist +admin.site.register(Pationt ) +admin.site.register(Psychiatrist) # Register your models here. diff --git a/BackEnd/counseling/migrations/0001_initial.py b/BackEnd/counseling/migrations/0001_initial.py new file mode 100644 index 0000000..5c49cf3 --- /dev/null +++ b/BackEnd/counseling/migrations/0001_initial.py @@ -0,0 +1,79 @@ +# Generated by Django 5.0.3 on 2024-03-26 07:51 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Pationt", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + migrations.CreateModel( + name="Psychiatrist", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "image", + models.ImageField( + default="images/profile_pics/default.png", + upload_to="images/profile_pics", + ), + ), + ( + "type", + models.CharField( + choices=[ + ("individual", "Individual"), + ("couples", "couples"), + ("kids", "Kids"), + ("teen", "Teen"), + ], + default="defualt", + max_length=255, + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 71a8362..723b634 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -1,3 +1,25 @@ from django.db import models +from accounts.models import User -# Create your models here. +class Psychiatrist(models.Model ) : + TYPE_INDIVIDUAL = 'individual' + TYPE_KIDS = "kids" + TYPE_COUPLES = "couples" + TYPE_TEEN = "teen" + TYPE_USER = "defualt" + + CHOICES = ( + (TYPE_INDIVIDUAL , "Individual") , + (TYPE_COUPLES , "couples") , + (TYPE_KIDS , "Kids") , + (TYPE_TEEN , "Teen") + ) + image = models.ImageField(upload_to='images/profile_pics', default='images/profile_pics/default.png') + type = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) + user = models.ForeignKey(User, on_delete=models.CASCADE) + + + +# TODO add fields for pationt +class Pationt( models.Model ) : + user = models.ForeignKey(User, on_delete=models.CASCADE) diff --git a/BackEnd/counseling/urls.py b/BackEnd/counseling/urls.py new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt index 44d0eec..f8c4e5a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,8 @@ charset-normalizer==3.3.2 coreapi==2.3.3 coreschema==0.0.4 Django==5.0.3 +django-environ==0.11.2 +django-phonenumber-field==7.3.0 django-rest-swagger==2.2.0 djangorestframework==3.14.0 djangorestframework-simplejwt==5.3.1 @@ -17,43 +19,13 @@ MarkupSafe==2.1.5 marshmallow==3.21.1 openapi-codec==1.3.2 packaging==24.0 +phonenumbers==8.13.32 +pillow==10.2.0 PyJWT==2.8.0 python-dotenv==1.0.1 pytz==2024.1 PyYAML==6.0.1 requests==2.31.0 -setuptools==69.2.0 -simplejson==3.19.2 -sqlparse==0.4.4 -typing_extensions==4.10.0 -tzdata==2024.1 -uritemplate==4.1.1 -urllib3==2.2.1 -asgiref==3.7.2 -certifi==2024.2.2 -charset-normalizer==3.3.2 -coreapi==2.3.3 -coreschema==0.0.4 -Django==5.0.3 -django-rest-swagger==2.2.0 -djangorestframework==3.14.0 -djangorestframework-simplejwt==5.3.1 -drf-yasg==1.21.7 -environs==11.0.0 -idna==3.6 -inflection==0.5.1 -itypes==1.2.0 -Jinja2==3.1.3 -MarkupSafe==2.1.5 -marshmallow==3.21.1 -openapi-codec==1.3.2 -packaging==24.0 -PyJWT==2.8.0 -python-dotenv==1.0.1 -pytz==2024.1 -PyYAML==6.0.1 -requests==2.31.0 -setuptools==69.2.0 simplejson==3.19.2 sqlparse==0.4.4 typing_extensions==4.10.0 From ece28a3e40dd14bb40bd307e8c5d0bf4d45d3823 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Sun, 31 Mar 2024 11:46:54 +0330 Subject: [PATCH 16/46] feat/DoctorProfile --- BackEnd/BackEnd/settings.py | 9 ++-- BackEnd/BackEnd/urls.py | 2 +- BackEnd/Profile/__init__.py | 0 BackEnd/Profile/admin.py | 4 ++ BackEnd/Profile/apps.py | 10 ++++ BackEnd/Profile/migrations/0001_initial.py | 21 ++++++++ ...octorprofile_delete_psychiatristprofile.py | 49 +++++++++++++++++++ ...ename_doctor_doctorprofile_psychiatrist.py | 16 ++++++ .../0004_rename_doctorprofile_profile.py | 15 ++++++ .../0005_alter_profile_psychiatrist.py | 23 +++++++++ BackEnd/Profile/migrations/__init__.py | 0 BackEnd/Profile/models.py | 42 ++++++++++++++++ BackEnd/Profile/signals.py | 25 ++++++++++ BackEnd/Profile/tests.py | 3 ++ BackEnd/Profile/urls.py | 8 +++ BackEnd/Profile/views.py | 24 +++++++++ ...er_user_last_verification_sent_and_more.py | 39 +++++++++++++++ .../0005_alter_user_last_verification_sent.py | 23 +++++++++ .../0006_alter_user_last_verification_sent.py | 23 +++++++++ .../0007_alter_user_last_verification_sent.py | 23 +++++++++ .../0008_alter_user_last_verification_sent.py | 23 +++++++++ .../0009_alter_user_last_verification_sent.py | 23 +++++++++ .../0010_alter_user_last_verification_sent.py | 23 +++++++++ .../0011_alter_user_last_verification_sent.py | 23 +++++++++ .../0012_alter_user_last_verification_sent.py | 23 +++++++++ .../0013_alter_user_last_verification_sent.py | 23 +++++++++ .../0014_alter_user_last_verification_sent.py | 23 +++++++++ BackEnd/accounts/models.py | 6 +++ ...rename_type_psychiatrist_field_and_more.py | 30 ++++++++++++ ...emove_psychiatrist_description_and_more.py | 28 +++++++++++ BackEnd/counseling/models.py | 26 ++++++++-- 31 files changed, 602 insertions(+), 8 deletions(-) create mode 100644 BackEnd/Profile/__init__.py create mode 100644 BackEnd/Profile/admin.py create mode 100644 BackEnd/Profile/apps.py create mode 100644 BackEnd/Profile/migrations/0001_initial.py create mode 100644 BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py create mode 100644 BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py create mode 100644 BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py create mode 100644 BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py create mode 100644 BackEnd/Profile/migrations/__init__.py create mode 100644 BackEnd/Profile/models.py create mode 100644 BackEnd/Profile/signals.py create mode 100644 BackEnd/Profile/tests.py create mode 100644 BackEnd/Profile/urls.py create mode 100644 BackEnd/Profile/views.py create mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py create mode 100644 BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py create mode 100644 BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py create mode 100644 BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 420e5a8..c8d6307 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -41,11 +41,14 @@ EMAIL_USE_TLS = True REDIS_HOST = os.environ.get('REDIS_HOST', '127.0.0.1') CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] - +# DEFAULT_FILE_STORAGE # SESSION_COOKIE_DOMAIN = "http://localserver:8000" SESSION_COOKIE_SECURE = False SESSION_EXPIRE_AT_BROWSER_CLOSE = False +MEDIA_ROOT = os.path.join(BASE_DIR, "media") +MEDIA_URL = "/media/" + # SESSION_COOKIE_DOMAIN ALLOWED_HOSTS = ['*'] @@ -100,10 +103,12 @@ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + # 'Profile.apps.SignalAppConfig', "accounts", "rest_framework", "rest_framework_swagger", "rest_framework_simplejwt.token_blacklist", + "Profile", "drf_yasg", "counseling", ] @@ -119,8 +124,6 @@ ] -MEDIA_ROOT = os.path.join(BASE_DIR, "media") -MEDIA_URL = "/media/" ROOT_URLCONF = "BackEnd.urls" diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index 0a66b67..2710ec0 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -37,6 +37,6 @@ path("admin/", admin.site.urls), path("accounts/" , include("accounts.urls")), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), - # path('counseling/' , include("counseling.urls")) , + path('profile/' , include("Profile.urls")) , path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ] diff --git a/BackEnd/Profile/__init__.py b/BackEnd/Profile/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/Profile/admin.py b/BackEnd/Profile/admin.py new file mode 100644 index 0000000..bdc2f0d --- /dev/null +++ b/BackEnd/Profile/admin.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from .models import Profile + +admin.site.register( Profile ) diff --git a/BackEnd/Profile/apps.py b/BackEnd/Profile/apps.py new file mode 100644 index 0000000..1c48018 --- /dev/null +++ b/BackEnd/Profile/apps.py @@ -0,0 +1,10 @@ +from django.apps import AppConfig + + +class ProfileConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "Profile" + + def ready(self) : + import Profile.signals + # from signals.signals import save_profile \ No newline at end of file diff --git a/BackEnd/Profile/migrations/0001_initial.py b/BackEnd/Profile/migrations/0001_initial.py new file mode 100644 index 0000000..7db768d --- /dev/null +++ b/BackEnd/Profile/migrations/0001_initial.py @@ -0,0 +1,21 @@ +# Generated by Django 5.0.3 on 2024-03-28 21:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("counseling", "0002_rename_type_psychiatrist_field_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="PsychiatristProfile", + fields=[], + options={"proxy": True, "indexes": [], "constraints": [],}, + bases=("counseling.psychiatrist",), + ), + ] diff --git a/BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py b/BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py new file mode 100644 index 0000000..064ce47 --- /dev/null +++ b/BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py @@ -0,0 +1,49 @@ +# Generated by Django 5.0.3 on 2024-03-29 08:48 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("Profile", "0001_initial"), + ("counseling", "0003_remove_psychiatrist_description_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="DoctorProfile", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("description", models.TextField(blank=True, null=True)), + ("name", models.CharField(blank=True, max_length=50, null=True)), + ( + "image", + models.ImageField( + default="images/profile_pics/default.png", + upload_to="images/profile_pics", + ), + ), + ("profile_type", models.CharField(max_length=10)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("is_private", models.BooleanField(default=False)), + ( + "doctor", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="counseling.psychiatrist", + ), + ), + ], + ), + migrations.DeleteModel(name="PsychiatristProfile",), + ] diff --git a/BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py b/BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py new file mode 100644 index 0000000..ea97715 --- /dev/null +++ b/BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py @@ -0,0 +1,16 @@ +# Generated by Django 5.0.3 on 2024-03-29 09:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("Profile", "0002_doctorprofile_delete_psychiatristprofile"), + ] + + operations = [ + migrations.RenameField( + model_name="doctorprofile", old_name="doctor", new_name="psychiatrist", + ), + ] diff --git a/BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py b/BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py new file mode 100644 index 0000000..63d814d --- /dev/null +++ b/BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py @@ -0,0 +1,15 @@ +# Generated by Django 5.0.3 on 2024-03-29 10:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("Profile", "0003_rename_doctor_doctorprofile_psychiatrist"), + ("counseling", "0003_remove_psychiatrist_description_and_more"), + ] + + operations = [ + migrations.RenameModel(old_name="DoctorProfile", new_name="Profile",), + ] diff --git a/BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py b/BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py new file mode 100644 index 0000000..4ec0b13 --- /dev/null +++ b/BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 15:56 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("Profile", "0004_rename_doctorprofile_profile"), + ("counseling", "0003_remove_psychiatrist_description_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="profile", + name="psychiatrist", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="counseling.psychiatrist", + ), + ), + ] diff --git a/BackEnd/Profile/migrations/__init__.py b/BackEnd/Profile/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/Profile/models.py b/BackEnd/Profile/models.py new file mode 100644 index 0000000..3e0ebf1 --- /dev/null +++ b/BackEnd/Profile/models.py @@ -0,0 +1,42 @@ +from django.db import models +from counseling.models import Psychiatrist +from django.contrib.auth import get_user_model +from django.core.exceptions import ValidationError + +class Profile(models.Model): + psychiatrist = models.OneToOneField(Psychiatrist, on_delete=models.CASCADE) + description = models.TextField(null=True, blank=True) + name = models.CharField(max_length=50, blank=True, null=True) + image = models.ImageField(upload_to='images/profile_pics', default='images/profile_pics/default.png') + profile_type = models.CharField(max_length=10) + created_at = models.DateTimeField(auto_now_add=True) + is_private = models.BooleanField(default=False) + + def __str__(self): + return self.name + + def save(self, *args, **kwargs): + if not isinstance(self.psychiatrist , Psychiatrist): + raise ValidationError('Invalid value for content_object') + self.name = self.determine_name(self.name) + self.description = "default string" + self.profile_type = self.determine_profile_type() + self.image = self.determine_image() + super().save(*args, **kwargs) + + def determine_image(self): + if not self.pk: + return self.psychiatrist.get_profile_image() + print("sljfslfslkfjslfjsdlfjslfjslfjslfjs") + return self.image + + def determine_name(self, name): + if not self.pk: + return self.psychiatrist.get_fullname() + return name + + def determine_profile_type(self): + if not self.pk : + return self.psychiatrist.field + return self.profile_type + diff --git a/BackEnd/Profile/signals.py b/BackEnd/Profile/signals.py new file mode 100644 index 0000000..bfb456b --- /dev/null +++ b/BackEnd/Profile/signals.py @@ -0,0 +1,25 @@ +from django.db.models.signals import post_save, pre_delete ,pre_save +from django.dispatch import receiver +from .models import Profile +from counseling.models import Psychiatrist + + +@receiver(post_save, sender=Psychiatrist ) +def create_profile(sender, instance, created, **kwargs): + if created: + print( "instance ----------->" , instance) + print( " sender------------->" , sender ) + Profile.objects.create(psychiatrist=instance) + + +@receiver(post_save, sender=Psychiatrist) +def save_profile(sender, instance, **kwargs): + instance.profile.save() + + +# @receiver(pre_save, sender=Psychiatrist) +# def checker(sender, instance, **kwargs): +# if instance.id is None: +# pass +# else: +# save_profile(sender = sender , instance = instance , kwargs = kwargs ) \ No newline at end of file diff --git a/BackEnd/Profile/tests.py b/BackEnd/Profile/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BackEnd/Profile/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BackEnd/Profile/urls.py b/BackEnd/Profile/urls.py new file mode 100644 index 0000000..b2af6d5 --- /dev/null +++ b/BackEnd/Profile/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from .views import DoctorProfileViewSet + +urlpatterns = [ + path('doctors/', DoctorProfileViewSet.as_view({'get': 'list', 'post': 'create'}), name='doctor-profiles-list'), + path('doctors//', DoctorProfileViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}), name='doctor-profiles-detail'), + path('doctors/typed/', DoctorProfileViewSet.as_view({'get': 'filter_by_profile_type'}), name='doctor-profiles-filter-by-profile-type'), +] diff --git a/BackEnd/Profile/views.py b/BackEnd/Profile/views.py new file mode 100644 index 0000000..aada713 --- /dev/null +++ b/BackEnd/Profile/views.py @@ -0,0 +1,24 @@ +from rest_framework import viewsets, serializers +from rest_framework.decorators import action +from rest_framework.response import Response +from .models import Profile + +class DoctorProfileSerializer(serializers.ModelSerializer): + class Meta: + model = Profile + fields = '__all__' + + +class DoctorProfileViewSet(viewsets.ModelViewSet): + queryset = Profile.objects.all() + serializer_class = DoctorProfileSerializer + + @action(detail=False, methods=['get']) + def filter_by_profile_type(self, request): + profile_type = request.query_params.get('profile_type') + if profile_type: + queryset = self.queryset.filter(profile_type=profile_type) + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + else: + return Response({"error": "profile_type parameter is required"}, status=400) diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py new file mode 100644 index 0000000..4e3ecf6 --- /dev/null +++ b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 5.0.3 on 2024-03-28 19:55 + +import datetime +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0003_alter_user_date_of_birth_alter_user_firstname_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 28, 23, 25, 2, 58513), + null=True, + ), + ), + migrations.AlterField( + model_name="user", + name="phone_number", + field=models.CharField( + blank=True, + max_length=15, + null=True, + validators=[ + django.core.validators.RegexValidator( + message="Phone number must be in a valid Iranian format.", + regex="^(?:\\+98|0)(?:\\s?)9[0-9]{9}$", + ) + ], + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py new file mode 100644 index 0000000..ec1e568 --- /dev/null +++ b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-28 21:00 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0004_alter_user_last_verification_sent_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 0, 30, 46, 116401), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py new file mode 100644 index 0000000..4730449 --- /dev/null +++ b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 08:48 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0005_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 12, 18, 24, 896034), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py new file mode 100644 index 0000000..edaa88c --- /dev/null +++ b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 09:10 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0006_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 12, 40, 26, 677769), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py new file mode 100644 index 0000000..1711044 --- /dev/null +++ b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 09:13 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0007_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 12, 43, 56, 914113), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py new file mode 100644 index 0000000..ca51bcf --- /dev/null +++ b/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 09:57 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0008_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 13, 27, 38, 408681), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py new file mode 100644 index 0000000..a6dee07 --- /dev/null +++ b/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 10:00 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0009_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 13, 29, 54, 186952), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py new file mode 100644 index 0000000..a49908c --- /dev/null +++ b/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 10:00 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0010_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 13, 30, 27, 367055), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py new file mode 100644 index 0000000..808fceb --- /dev/null +++ b/BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 15:56 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0011_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 19, 26, 52, 147201), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py new file mode 100644 index 0000000..edae336 --- /dev/null +++ b/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 16:02 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0012_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 19, 32, 10, 55759), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py new file mode 100644 index 0000000..7076413 --- /dev/null +++ b/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-03-29 17:33 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0013_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 3, 29, 21, 3, 53, 884072), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index dc3d1a5..61e6f36 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -7,6 +7,7 @@ from django.core.validators import RegexValidator from django.contrib.auth.hashers import make_password + class UserManager(BaseUserManager): def create_user(self , email , firstname , lastname , gender , date_of_birth, phone_number ,password=None) : #phone = None """ @@ -28,6 +29,11 @@ def create_user(self , email , firstname , lastname , gender , date_of_birth, ph user.set_password(password) user.save(using=self._db) return user + + def get_queryset(self) -> models.QuerySet: + return super().get_queryset() + + def create_superuser(self , email ,password=None): #phone firstname ,lastname , gender , phone_number, date_of_birth , """ diff --git a/BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py b/BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py new file mode 100644 index 0000000..9bb8c2a --- /dev/null +++ b/BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 5.0.3 on 2024-03-28 19:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0001_initial"), + ] + + operations = [ + migrations.RenameField( + model_name="psychiatrist", old_name="type", new_name="field", + ), + migrations.AddField( + model_name="psychiatrist", + name="description", + field=models.TextField(blank=True, null=True), + ), + migrations.AlterField( + model_name="psychiatrist", + name="image", + field=models.ImageField( + default="images/doctors/profile_pics/default.png", + null=True, + upload_to="images/doctors/profile_pics", + ), + ), + ] diff --git a/BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py b/BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py new file mode 100644 index 0000000..d1705b7 --- /dev/null +++ b/BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0.3 on 2024-03-29 08:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0002_rename_type_psychiatrist_field_and_more"), + ] + + operations = [ + migrations.RemoveField(model_name="psychiatrist", name="description",), + migrations.AlterField( + model_name="psychiatrist", + name="field", + field=models.CharField( + choices=[ + ("individual", "Individual"), + ("couples", "Couples"), + ("kids", "Kids"), + ("teen", "Teen"), + ], + default="defualt", + max_length=255, + ), + ), + ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 723b634..ffb8b1f 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -1,5 +1,7 @@ from django.db import models from accounts.models import User +from django.conf import settings +from django.contrib.contenttypes.fields import GenericRelation class Psychiatrist(models.Model ) : TYPE_INDIVIDUAL = 'individual' @@ -10,14 +12,30 @@ class Psychiatrist(models.Model ) : CHOICES = ( (TYPE_INDIVIDUAL , "Individual") , - (TYPE_COUPLES , "couples") , + (TYPE_COUPLES , "Couples") , (TYPE_KIDS , "Kids") , (TYPE_TEEN , "Teen") ) - image = models.ImageField(upload_to='images/profile_pics', default='images/profile_pics/default.png') - type = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) + + image = models.ImageField(upload_to='images/doctors/profile_pics', null=True, default='images/doctors/profile_pics/default.png') + field = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) user = models.ForeignKey(User, on_delete=models.CASCADE) - + + def get_default_profile_image(self): + if self.usesr.gender == 'M': + return 'images/doctors/profile_pics/male_default.png' + else: + return 'images/doctors/profile_pics/female_default.png' + + @property + def get_profile_image(self ) : + if not self.image : + return self.get_default_profile_image() + else : + return self.image.url # settings.MEDIA_ROOT + + + def get_fullname(self) : + return self.user.firstname + " " + self.user.lastname # TODO add fields for pationt From 96c1f44b47052a7a51e4b50e2c65bf0068ccb564 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 1 Apr 2024 04:35:38 +0330 Subject: [PATCH 17/46] fix/cors-headers --- BackEnd/BackEnd/settings.py | 10 +++- BackEnd/Profile/migrations/0001_initial.py | 42 +++++++++++++--- ...octorprofile_delete_psychiatristprofile.py | 49 ------------------- ...ename_doctor_doctorprofile_psychiatrist.py | 16 ------ .../0004_rename_doctorprofile_profile.py | 15 ------ .../0005_alter_profile_psychiatrist.py | 23 --------- BackEnd/Profile/models.py | 4 +- BackEnd/accounts/migrations/0001_initial.py | 16 +++--- .../0002_alter_user_last_verification_sent.py | 23 --------- ..._of_birth_alter_user_firstname_and_more.py | 47 ------------------ ...er_user_last_verification_sent_and_more.py | 39 --------------- .../0005_alter_user_last_verification_sent.py | 23 --------- .../0006_alter_user_last_verification_sent.py | 23 --------- .../0007_alter_user_last_verification_sent.py | 23 --------- .../0008_alter_user_last_verification_sent.py | 23 --------- .../0009_alter_user_last_verification_sent.py | 23 --------- .../0010_alter_user_last_verification_sent.py | 23 --------- .../0011_alter_user_last_verification_sent.py | 23 --------- .../0012_alter_user_last_verification_sent.py | 23 --------- .../0013_alter_user_last_verification_sent.py | 23 --------- .../0014_alter_user_last_verification_sent.py | 23 --------- BackEnd/accounts/views.py | 2 + BackEnd/counseling/migrations/0001_initial.py | 11 +++-- ...rename_type_psychiatrist_field_and_more.py | 30 ------------ ...emove_psychiatrist_description_and_more.py | 28 ----------- BackEnd/counseling/models.py | 18 +++++-- 26 files changed, 78 insertions(+), 525 deletions(-) delete mode 100644 BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py delete mode 100644 BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py delete mode 100644 BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py delete mode 100644 BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py delete mode 100644 BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py delete mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py delete mode 100644 BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py delete mode 100644 BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py delete mode 100644 BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index c8d6307..3501dba 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -103,7 +103,7 @@ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", - # 'Profile.apps.SignalAppConfig', + "corsheaders", "accounts", "rest_framework", "rest_framework_swagger", @@ -118,12 +118,20 @@ "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] +CORS_ALLOWED_ORIGINS = [ + # 'CORS_ALLOW_ALL_ORIGINS', + "http://localhost:5173" , + +] + ROOT_URLCONF = "BackEnd.urls" diff --git a/BackEnd/Profile/migrations/0001_initial.py b/BackEnd/Profile/migrations/0001_initial.py index 7db768d..21342c0 100644 --- a/BackEnd/Profile/migrations/0001_initial.py +++ b/BackEnd/Profile/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 5.0.3 on 2024-03-28 21:00 +# Generated by Django 5.0.3 on 2024-04-01 00:14 -from django.db import migrations +import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): @@ -8,14 +9,41 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("counseling", "0002_rename_type_psychiatrist_field_and_more"), + ("counseling", "0001_initial"), ] operations = [ migrations.CreateModel( - name="PsychiatristProfile", - fields=[], - options={"proxy": True, "indexes": [], "constraints": [],}, - bases=("counseling.psychiatrist",), + name="Profile", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("description", models.TextField(blank=True, null=True)), + ("name", models.CharField(blank=True, max_length=50, null=True)), + ( + "image", + models.ImageField( + default="images/profile_pics/default.png", + upload_to="images/profile_pics", + ), + ), + ("profile_type", models.CharField(max_length=10)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("is_private", models.BooleanField(default=False)), + ( + "psychiatrist", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="counseling.psychiatrist", + ), + ), + ], ), ] diff --git a/BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py b/BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py deleted file mode 100644 index 064ce47..0000000 --- a/BackEnd/Profile/migrations/0002_doctorprofile_delete_psychiatristprofile.py +++ /dev/null @@ -1,49 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 08:48 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("Profile", "0001_initial"), - ("counseling", "0003_remove_psychiatrist_description_and_more"), - ] - - operations = [ - migrations.CreateModel( - name="DoctorProfile", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("description", models.TextField(blank=True, null=True)), - ("name", models.CharField(blank=True, max_length=50, null=True)), - ( - "image", - models.ImageField( - default="images/profile_pics/default.png", - upload_to="images/profile_pics", - ), - ), - ("profile_type", models.CharField(max_length=10)), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("is_private", models.BooleanField(default=False)), - ( - "doctor", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="counseling.psychiatrist", - ), - ), - ], - ), - migrations.DeleteModel(name="PsychiatristProfile",), - ] diff --git a/BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py b/BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py deleted file mode 100644 index ea97715..0000000 --- a/BackEnd/Profile/migrations/0003_rename_doctor_doctorprofile_psychiatrist.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 09:57 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("Profile", "0002_doctorprofile_delete_psychiatristprofile"), - ] - - operations = [ - migrations.RenameField( - model_name="doctorprofile", old_name="doctor", new_name="psychiatrist", - ), - ] diff --git a/BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py b/BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py deleted file mode 100644 index 63d814d..0000000 --- a/BackEnd/Profile/migrations/0004_rename_doctorprofile_profile.py +++ /dev/null @@ -1,15 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 10:00 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("Profile", "0003_rename_doctor_doctorprofile_psychiatrist"), - ("counseling", "0003_remove_psychiatrist_description_and_more"), - ] - - operations = [ - migrations.RenameModel(old_name="DoctorProfile", new_name="Profile",), - ] diff --git a/BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py b/BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py deleted file mode 100644 index 4ec0b13..0000000 --- a/BackEnd/Profile/migrations/0005_alter_profile_psychiatrist.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 15:56 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("Profile", "0004_rename_doctorprofile_profile"), - ("counseling", "0003_remove_psychiatrist_description_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="psychiatrist", - field=models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="counseling.psychiatrist", - ), - ), - ] diff --git a/BackEnd/Profile/models.py b/BackEnd/Profile/models.py index 3e0ebf1..7866c9c 100644 --- a/BackEnd/Profile/models.py +++ b/BackEnd/Profile/models.py @@ -19,9 +19,9 @@ def save(self, *args, **kwargs): if not isinstance(self.psychiatrist , Psychiatrist): raise ValidationError('Invalid value for content_object') self.name = self.determine_name(self.name) - self.description = "default string" + # self.description = "default string" self.profile_type = self.determine_profile_type() - self.image = self.determine_image() + # self.image = self.determine_image() super().save(*args, **kwargs) def determine_image(self): diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index cf77ff5..abe5b71 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-03-26 07:51 +# Generated by Django 5.0.3 on 2024-04-01 00:13 import datetime import django.core.validators @@ -31,14 +31,16 @@ class Migration(migrations.Migration): blank=True, null=True, verbose_name="last login" ), ), - ("firstname", models.CharField(max_length=20)), - ("lastname", models.CharField(max_length=30)), + ("firstname", models.CharField(blank=True, max_length=20, null=True)), + ("lastname", models.CharField(blank=True, max_length=30, null=True)), ("email", models.EmailField(max_length=255, unique=True)), - ("date_of_birth", models.DateField()), + ("date_of_birth", models.DateField(blank=True, null=True)), ( "gender", models.CharField( - choices=[("F", "Female"), ("M", "Male")], max_length=1 + choices=[("F", "Female"), ("M", "Male"), ("B", "Both")], + max_length=1, + null=True, ), ), ("is_active", models.BooleanField(default=True)), @@ -52,7 +54,7 @@ class Migration(migrations.Migration): validators=[ django.core.validators.RegexValidator( message="Phone number must be in a valid Iranian format.", - regex="^\\+?98[09]\\d{9}$", + regex="^(?:\\+98|0)(?:\\s?)9[0-9]{9}$", ) ], ), @@ -79,7 +81,7 @@ class Migration(migrations.Migration): "last_verification_sent", models.DateTimeField( blank=True, - default=datetime.datetime(2024, 3, 26, 11, 21, 14, 482484), + default=datetime.datetime(2024, 4, 1, 3, 43, 49, 999854), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py deleted file mode 100644 index 7dc0dc6..0000000 --- a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-26 07:51 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 26, 11, 21, 19, 671522), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py b/BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py deleted file mode 100644 index 3164013..0000000 --- a/BackEnd/accounts/migrations/0003_alter_user_date_of_birth_alter_user_firstname_and_more.py +++ /dev/null @@ -1,47 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-26 14:14 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0002_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="date_of_birth", - field=models.DateField(blank=True, null=True), - ), - migrations.AlterField( - model_name="user", - name="firstname", - field=models.CharField(blank=True, max_length=20, null=True), - ), - migrations.AlterField( - model_name="user", - name="gender", - field=models.CharField( - choices=[("F", "Female"), ("M", "Male"), ("B", "Both")], - max_length=1, - null=True, - ), - ), - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 26, 17, 44, 8, 963102), - null=True, - ), - ), - migrations.AlterField( - model_name="user", - name="lastname", - field=models.CharField(blank=True, max_length=30, null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py deleted file mode 100644 index 4e3ecf6..0000000 --- a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent_and_more.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-28 19:55 - -import datetime -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0003_alter_user_date_of_birth_alter_user_firstname_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 28, 23, 25, 2, 58513), - null=True, - ), - ), - migrations.AlterField( - model_name="user", - name="phone_number", - field=models.CharField( - blank=True, - max_length=15, - null=True, - validators=[ - django.core.validators.RegexValidator( - message="Phone number must be in a valid Iranian format.", - regex="^(?:\\+98|0)(?:\\s?)9[0-9]{9}$", - ) - ], - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py deleted file mode 100644 index ec1e568..0000000 --- a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-28 21:00 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0004_alter_user_last_verification_sent_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 0, 30, 46, 116401), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py deleted file mode 100644 index 4730449..0000000 --- a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 08:48 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0005_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 12, 18, 24, 896034), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py deleted file mode 100644 index edaa88c..0000000 --- a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 09:10 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0006_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 12, 40, 26, 677769), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py deleted file mode 100644 index 1711044..0000000 --- a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 09:13 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0007_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 12, 43, 56, 914113), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py deleted file mode 100644 index ca51bcf..0000000 --- a/BackEnd/accounts/migrations/0009_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 09:57 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0008_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 13, 27, 38, 408681), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py deleted file mode 100644 index a6dee07..0000000 --- a/BackEnd/accounts/migrations/0010_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 10:00 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0009_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 13, 29, 54, 186952), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py deleted file mode 100644 index a49908c..0000000 --- a/BackEnd/accounts/migrations/0011_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 10:00 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0010_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 13, 30, 27, 367055), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py deleted file mode 100644 index 808fceb..0000000 --- a/BackEnd/accounts/migrations/0012_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 15:56 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0011_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 19, 26, 52, 147201), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py deleted file mode 100644 index edae336..0000000 --- a/BackEnd/accounts/migrations/0013_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 16:02 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0012_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 19, 32, 10, 55759), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py deleted file mode 100644 index 7076413..0000000 --- a/BackEnd/accounts/migrations/0014_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 17:33 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0013_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 3, 29, 21, 3, 53, 884072), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 4851af3..9a7c633 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -219,6 +219,8 @@ def validate_token(self, token): class LoginView(TokenObtainPairView): serializer_class = LoginSerializer def post(self, request, *args, **kwargs): + print("this is login request ") + print( request ) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] diff --git a/BackEnd/counseling/migrations/0001_initial.py b/BackEnd/counseling/migrations/0001_initial.py index 5c49cf3..76e59db 100644 --- a/BackEnd/counseling/migrations/0001_initial.py +++ b/BackEnd/counseling/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-03-26 07:51 +# Generated by Django 5.0.3 on 2024-04-01 00:13 import django.db.models.deletion from django.conf import settings @@ -50,16 +50,17 @@ class Migration(migrations.Migration): ( "image", models.ImageField( - default="images/profile_pics/default.png", - upload_to="images/profile_pics", + default="images/doctors/profile_pics/default.png", + null=True, + upload_to="images/doctors/profile_pics", ), ), ( - "type", + "field", models.CharField( choices=[ ("individual", "Individual"), - ("couples", "couples"), + ("couples", "Couples"), ("kids", "Kids"), ("teen", "Teen"), ], diff --git a/BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py b/BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py deleted file mode 100644 index 9bb8c2a..0000000 --- a/BackEnd/counseling/migrations/0002_rename_type_psychiatrist_field_and_more.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-28 19:55 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("counseling", "0001_initial"), - ] - - operations = [ - migrations.RenameField( - model_name="psychiatrist", old_name="type", new_name="field", - ), - migrations.AddField( - model_name="psychiatrist", - name="description", - field=models.TextField(blank=True, null=True), - ), - migrations.AlterField( - model_name="psychiatrist", - name="image", - field=models.ImageField( - default="images/doctors/profile_pics/default.png", - null=True, - upload_to="images/doctors/profile_pics", - ), - ), - ] diff --git a/BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py b/BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py deleted file mode 100644 index d1705b7..0000000 --- a/BackEnd/counseling/migrations/0003_remove_psychiatrist_description_and_more.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-29 08:48 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("counseling", "0002_rename_type_psychiatrist_field_and_more"), - ] - - operations = [ - migrations.RemoveField(model_name="psychiatrist", name="description",), - migrations.AlterField( - model_name="psychiatrist", - name="field", - field=models.CharField( - choices=[ - ("individual", "Individual"), - ("couples", "Couples"), - ("kids", "Kids"), - ("teen", "Teen"), - ], - default="defualt", - max_length=255, - ), - ), - ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index ffb8b1f..af4f026 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -1,7 +1,9 @@ +from typing import Any from django.db import models from accounts.models import User from django.conf import settings from django.contrib.contenttypes.fields import GenericRelation +from django.core.exceptions import ValidationError class Psychiatrist(models.Model ) : TYPE_INDIVIDUAL = 'individual' @@ -9,7 +11,6 @@ class Psychiatrist(models.Model ) : TYPE_COUPLES = "couples" TYPE_TEEN = "teen" TYPE_USER = "defualt" - CHOICES = ( (TYPE_INDIVIDUAL , "Individual") , (TYPE_COUPLES , "Couples") , @@ -17,9 +18,9 @@ class Psychiatrist(models.Model ) : (TYPE_TEEN , "Teen") ) + user = models.ForeignKey(User, on_delete=models.CASCADE ) image = models.ImageField(upload_to='images/doctors/profile_pics', null=True, default='images/doctors/profile_pics/default.png') field = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) - user = models.ForeignKey(User, on_delete=models.CASCADE) def get_default_profile_image(self): if self.usesr.gender == 'M': @@ -27,16 +28,27 @@ def get_default_profile_image(self): else: return 'images/doctors/profile_pics/female_default.png' + def save(self, *args, **kwargs): + if not self.user.role == 'doctor': + self.user.role = User.TYPE_DOCTOR + self.user.save() + super().save(*args, **kwargs) + @property def get_profile_image(self ) : if not self.image : return self.get_default_profile_image() else : - return self.image.url # settings.MEDIA_ROOT + + return self.image.url # settings.MEDIA_ROOT + def get_fullname(self) : return self.user.firstname + " " + self.user.lastname + def save(self, *args, **kwargs): + # Check if there's already a Psychiatrist object associated with this User + if Psychiatrist.objects.filter(user=self.user).exists(): + raise ValidationError("A Psychiatrist object already exists for this User.") + super().save(*args, **kwargs) # TODO add fields for pationt class Pationt( models.Model ) : From 3cf70ccf84468c1528f108542143fb14d2583be5 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 1 Apr 2024 23:45:31 +0330 Subject: [PATCH 18/46] fix/errors --- BackEnd/accounts/serializers.py | 20 +++++++++++--------- BackEnd/accounts/views.py | 5 +---- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 4c29a4e..301a4f0 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -129,29 +129,31 @@ class LoginSerializer(serializers.Serializer): def validate(self, attrs): email = attrs.get('email', None) password = attrs.get('password', None) - if email and password: email = self.validate_email(email) user = User.objects.get(email__iexact=email) - + # self.validate_password(value= password ,user= user ) if not user.check_password(password): - msg = ('Incorrect password.') - raise serializers.ValidationError(msg, code='authorization') + msg = 'Incorrect password.' + raise serializers.ValidationError( { "message" : msg} , code='authorization') if not user.is_email_verified: - raise serializers.ValidationError({"detail": "User is not verified."}) + raise serializers.ValidationError({"message": "User is not verified."}) attrs['user'] = user else: msg = ('Must include "email" and "password".') raise serializers.ValidationError(msg, code='authorization') return attrs - + # def validate_password( self , value ,user) : + # if not user.check_password(value): + # msg = ('Incorrect password.') + # raise serializers.ValidationError(msg, code='authorization') + def validate_email(self, value): - msg = ('Email does not exist.') + msg = 'Email does not exist.' user_exists = User.objects.filter(email__iexact=value).exists() if not user_exists: - raise serializers.ValidationError(msg) - + raise serializers.ValidationError( { "message" : msg} ) return str.lower(value) diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 9a7c633..587f78e 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -219,8 +219,6 @@ def validate_token(self, token): class LoginView(TokenObtainPairView): serializer_class = LoginSerializer def post(self, request, *args, **kwargs): - print("this is login request ") - print( request ) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] @@ -228,13 +226,12 @@ def post(self, request, *args, **kwargs): tokens = generate_tokens(user.id) # login(request, user) login(request, user, backend = 'django.contrib.auth.backends.ModelBackend') - return Response({ 'refresh': tokens['refresh'], 'access': tokens['access'], 'user': UserSerializer(user).data }) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + return Response( {"message" : "there is no user with this email"} , status=status.HTTP_400_BAD_REQUEST) class CompleteInfoView(GenericAPIView) : From 966fe870ad250ba49cc05c63505ce07e6a0145e5 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 1 Apr 2024 23:50:18 +0330 Subject: [PATCH 19/46] fix/errors --- BackEnd/accounts/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 301a4f0..fc975b4 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -80,10 +80,10 @@ def validate(self, attrs): try: user = User.objects.get(email__iexact=email) except User.DoesNotExist: - raise serializers.ValidationError({"detail": "user does not exist."}) + raise serializers.ValidationError({"message": "user does not exist."}) if user.is_email_verified: - raise serializers.ValidationError({"detail": "user with this email is already verified."}) + raise serializers.ValidationError({"message": "user with this email is already verified."}) attrs['user'] = user return attrs From d61622fb94c3ca68affc7d439e2148afb4f21150 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Tue, 2 Apr 2024 05:17:18 +0330 Subject: [PATCH 20/46] fix/image --- BackEnd/BackEnd/settings.py | 8 ++--- .../migrations/0002_alter_profile_image.py | 18 ++++++++++ BackEnd/Profile/models.py | 13 ++++--- BackEnd/Profile/signals.py | 3 +- .../0002_alter_user_last_verification_sent.py | 23 ++++++++++++ BackEnd/accounts/serializers.py | 6 ---- BackEnd/counseling/apps.py | 3 ++ .../0002_alter_psychiatrist_image.py | 18 ++++++++++ .../0003_alter_psychiatrist_image.py | 20 +++++++++++ BackEnd/counseling/models.py | 36 ++++++++++++++----- BackEnd/counseling/signals.py | 9 +++++ BackEnd/templates/forget_password.html | 2 -- 12 files changed, 131 insertions(+), 28 deletions(-) create mode 100644 BackEnd/Profile/migrations/0002_alter_profile_image.py create mode 100644 BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py create mode 100644 BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py create mode 100644 BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py create mode 100644 BackEnd/counseling/signals.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 3501dba..5327952 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -32,7 +32,7 @@ # Setting Website URL WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') -BASE_URL = 'http://localhost:8000/' +# BASE_URL = 'http://localhost:8000/' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST_USER = 'eniakgroupiust@gmail.com'#env.str('EMAIL_HOST_USER') @@ -41,13 +41,11 @@ EMAIL_USE_TLS = True REDIS_HOST = os.environ.get('REDIS_HOST', '127.0.0.1') CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] -# DEFAULT_FILE_STORAGE -# SESSION_COOKIE_DOMAIN = "http://localserver:8000" SESSION_COOKIE_SECURE = False SESSION_EXPIRE_AT_BROWSER_CLOSE = False -MEDIA_ROOT = os.path.join(BASE_DIR, "media") -MEDIA_URL = "/media/" +MEDIA_ROOT = os.path.join(BASE_DIR, "media/") +MEDIA_URL = "media/" # SESSION_COOKIE_DOMAIN diff --git a/BackEnd/Profile/migrations/0002_alter_profile_image.py b/BackEnd/Profile/migrations/0002_alter_profile_image.py new file mode 100644 index 0000000..44ff85e --- /dev/null +++ b/BackEnd/Profile/migrations/0002_alter_profile_image.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.3 on 2024-04-02 01:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("Profile", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="profile", + name="image", + field=models.ImageField(upload_to="images\\doctors\\profile_pics"), + ), + ] diff --git a/BackEnd/Profile/models.py b/BackEnd/Profile/models.py index 7866c9c..f3026ca 100644 --- a/BackEnd/Profile/models.py +++ b/BackEnd/Profile/models.py @@ -7,7 +7,7 @@ class Profile(models.Model): psychiatrist = models.OneToOneField(Psychiatrist, on_delete=models.CASCADE) description = models.TextField(null=True, blank=True) name = models.CharField(max_length=50, blank=True, null=True) - image = models.ImageField(upload_to='images/profile_pics', default='images/profile_pics/default.png') + image = models.ImageField(upload_to='images\doctors\profile_pics') profile_type = models.CharField(max_length=10) created_at = models.DateTimeField(auto_now_add=True) is_private = models.BooleanField(default=False) @@ -19,17 +19,20 @@ def save(self, *args, **kwargs): if not isinstance(self.psychiatrist , Psychiatrist): raise ValidationError('Invalid value for content_object') self.name = self.determine_name(self.name) - # self.description = "default string" self.profile_type = self.determine_profile_type() - # self.image = self.determine_image() + self.image = self.determine_image() + print(self.image) super().save(*args, **kwargs) + def determine_image(self): if not self.pk: - return self.psychiatrist.get_profile_image() - print("sljfslfslkfjslfjsdlfjslfjslfjslfjs") + var = self.psychiatrist.get_profile_image() + print(var) + return var return self.image + def determine_name(self, name): if not self.pk: return self.psychiatrist.get_fullname() diff --git a/BackEnd/Profile/signals.py b/BackEnd/Profile/signals.py index bfb456b..113591e 100644 --- a/BackEnd/Profile/signals.py +++ b/BackEnd/Profile/signals.py @@ -3,7 +3,7 @@ from .models import Profile from counseling.models import Psychiatrist - + @receiver(post_save, sender=Psychiatrist ) def create_profile(sender, instance, created, **kwargs): if created: @@ -11,6 +11,7 @@ def create_profile(sender, instance, created, **kwargs): print( " sender------------->" , sender ) Profile.objects.create(psychiatrist=instance) + @receiver(post_save, sender=Psychiatrist) def save_profile(sender, instance, **kwargs): diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py new file mode 100644 index 0000000..a2b5fa8 --- /dev/null +++ b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-04-02 01:37 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 4, 2, 5, 7, 21, 743773), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index fc975b4..0fe4c5a 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -132,7 +132,6 @@ def validate(self, attrs): if email and password: email = self.validate_email(email) user = User.objects.get(email__iexact=email) - # self.validate_password(value= password ,user= user ) if not user.check_password(password): msg = 'Incorrect password.' raise serializers.ValidationError( { "message" : msg} , code='authorization') @@ -143,11 +142,6 @@ def validate(self, attrs): msg = ('Must include "email" and "password".') raise serializers.ValidationError(msg, code='authorization') return attrs - - # def validate_password( self , value ,user) : - # if not user.check_password(value): - # msg = ('Incorrect password.') - # raise serializers.ValidationError(msg, code='authorization') def validate_email(self, value): msg = 'Email does not exist.' diff --git a/BackEnd/counseling/apps.py b/BackEnd/counseling/apps.py index 5906f63..6c26bd6 100644 --- a/BackEnd/counseling/apps.py +++ b/BackEnd/counseling/apps.py @@ -4,3 +4,6 @@ class CounselingConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "counseling" + + def ready(self) : + import counseling.signals \ No newline at end of file diff --git a/BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py b/BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py new file mode 100644 index 0000000..a66ab01 --- /dev/null +++ b/BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.3 on 2024-04-01 20:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="psychiatrist", + name="image", + field=models.ImageField(null=True, upload_to="images/doctors/profile_pics"), + ), + ] diff --git a/BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py b/BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py new file mode 100644 index 0000000..fd0efff --- /dev/null +++ b/BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py @@ -0,0 +1,20 @@ +# Generated by Django 5.0.3 on 2024-04-01 20:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0002_alter_psychiatrist_image"), + ] + + operations = [ + migrations.AlterField( + model_name="psychiatrist", + name="image", + field=models.ImageField( + blank=True, null=True, upload_to="images/doctors/profile_pics" + ), + ), + ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index af4f026..32d17aa 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -19,14 +19,18 @@ class Psychiatrist(models.Model ) : ) user = models.ForeignKey(User, on_delete=models.CASCADE ) - image = models.ImageField(upload_to='images/doctors/profile_pics', null=True, default='images/doctors/profile_pics/default.png') + image = models.ImageField(upload_to='images/doctors/profile_pics', null=True,blank=True ) #, default='images/doctors/profile_pics/default.png') field = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) def get_default_profile_image(self): - if self.usesr.gender == 'M': - return 'images/doctors/profile_pics/male_default.png' + # print( " in defualt image ") + + if self.user.gender == 'M': + res = settings.MEDIA_URL + 'images/doctors/profile_pics/male_default.png' + return res else: - return 'images/doctors/profile_pics/female_default.png' + res = settings.MEDIA_URL + 'images/doctors/profile_pics/female_default.png' + return res def save(self, *args, **kwargs): if not self.user.role == 'doctor': @@ -34,22 +38,36 @@ def save(self, *args, **kwargs): self.user.save() super().save(*args, **kwargs) - @property + def get_profile_image(self ) : if not self.image : - return self.get_default_profile_image() + var = self.get_default_profile_image() + # print("var ---------------> ", var) + return var else : - return self.image.url # settings.MEDIA_ROOT + + return settings.MEDIA_URL + self.image # settings.MEDIA_ROOT + def get_fullname(self) : - return self.user.firstname + " " + self.user.lastname + return str(self.user.firstname) + " " + str(self.user.lastname) def save(self, *args, **kwargs): - # Check if there's already a Psychiatrist object associated with this User + """ + Check if there's already a Psychiatrist object associated with this User + """ if Psychiatrist.objects.filter(user=self.user).exists(): raise ValidationError("A Psychiatrist object already exists for this User.") super().save(*args, **kwargs) + + # TODO add fields for pationt class Pationt( models.Model ) : user = models.ForeignKey(User, on_delete=models.CASCADE) + + def save(self, *args, **kwargs): + """ + Check if there's already a Pationt object associated with this User + """ + if Pationt.objects.filter(user=self.user).exists(): + raise ValidationError("A Pationt object already exists for this User.") + super().save(*args, **kwargs) diff --git a/BackEnd/counseling/signals.py b/BackEnd/counseling/signals.py new file mode 100644 index 0000000..5f6a0ef --- /dev/null +++ b/BackEnd/counseling/signals.py @@ -0,0 +1,9 @@ +from django.db.models.signals import post_save, pre_delete ,pre_save , post_delete +from django.dispatch import receiver +from counseling.models import Psychiatrist , Pationt + + +@receiver(post_delete , sender= Pationt ) +@receiver(post_delete , sender= Psychiatrist ) +def delete_associated_user( sender , instance , **kwargs ) : + instance.user.delete() \ No newline at end of file diff --git a/BackEnd/templates/forget_password.html b/BackEnd/templates/forget_password.html index b31a139..051ea46 100644 --- a/BackEnd/templates/forget_password.html +++ b/BackEnd/templates/forget_password.html @@ -45,8 +45,6 @@

کد تایید ایمیل:

{{ email_verification_token }}

-
From ee8595fde411b923c58e77600fe765d4a7c150e8 Mon Sep 17 00:00:00 2001 From: Asma Hamid Date: Tue, 2 Apr 2024 11:36:58 +0330 Subject: [PATCH 21/46] feat/connectToDB --- BackEnd/BackEnd/settings.py | 21 ++++++++--- .../0023_alter_user_last_verification_sent.py | 19 ++++++++++ .../0024_alter_user_last_verification_sent.py | 19 ++++++++++ .../0025_alter_user_last_verification_sent.py | 19 ++++++++++ BackEnd/datadump.json | 1 + requirements.txt | 35 +++---------------- 6 files changed, 79 insertions(+), 35 deletions(-) create mode 100644 BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py create mode 100644 BackEnd/datadump.json diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 63a7edc..cd2eddf 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -136,14 +136,27 @@ # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases +# DATABASES = { +# "default": { +# "ENGINE": "django.db.backends.sqlite3", +# "NAME": BASE_DIR / "db.sqlite3", +# } +# } + DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", + + 'default': { + + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'TherapyDB', + 'USER': 'postgres', + 'PASSWORD': 'Hgbr5391', + 'HOST': 'localhost', + 'PORT': '5432', + } } - # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators diff --git a/BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py new file mode 100644 index 0000000..654c653 --- /dev/null +++ b/BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.3 on 2024-03-26 14:17 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0022_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 3, 26, 17, 47, 44, 89992), null=True), + ), + ] diff --git a/BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py new file mode 100644 index 0000000..7733aae --- /dev/null +++ b/BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.3 on 2024-04-02 07:25 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0023_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 2, 10, 55, 41, 864832), null=True), + ), + ] diff --git a/BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py new file mode 100644 index 0000000..fded790 --- /dev/null +++ b/BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.3 on 2024-04-02 08:00 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0024_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 2, 11, 30, 8, 151776), null=True), + ), + ] diff --git a/BackEnd/datadump.json b/BackEnd/datadump.json new file mode 100644 index 0000000..cc611a1 --- /dev/null +++ b/BackEnd/datadump.json @@ -0,0 +1 @@ +[{"model": "auth.permission", "pk": 1, "fields": {"name": "Can add log entry", "content_type": 1, "codename": "add_logentry"}}, {"model": "auth.permission", "pk": 2, "fields": {"name": "Can change log entry", "content_type": 1, "codename": "change_logentry"}}, {"model": "auth.permission", "pk": 3, "fields": {"name": "Can delete log entry", "content_type": 1, "codename": "delete_logentry"}}, {"model": "auth.permission", "pk": 4, "fields": {"name": "Can view log entry", "content_type": 1, "codename": "view_logentry"}}, {"model": "auth.permission", "pk": 5, "fields": {"name": "Can add permission", "content_type": 2, "codename": "add_permission"}}, {"model": "auth.permission", "pk": 6, "fields": {"name": "Can change permission", "content_type": 2, "codename": "change_permission"}}, {"model": "auth.permission", "pk": 7, "fields": {"name": "Can delete permission", "content_type": 2, "codename": "delete_permission"}}, {"model": "auth.permission", "pk": 8, "fields": {"name": "Can view permission", "content_type": 2, "codename": "view_permission"}}, {"model": "auth.permission", "pk": 9, "fields": {"name": "Can add group", "content_type": 3, "codename": "add_group"}}, {"model": "auth.permission", "pk": 10, "fields": {"name": "Can change group", "content_type": 3, "codename": "change_group"}}, {"model": "auth.permission", "pk": 11, "fields": {"name": "Can delete group", "content_type": 3, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 12, "fields": {"name": "Can view group", "content_type": 3, "codename": "view_group"}}, {"model": "auth.permission", "pk": 13, "fields": {"name": "Can add content type", "content_type": 4, "codename": "add_contenttype"}}, {"model": "auth.permission", "pk": 14, "fields": {"name": "Can change content type", "content_type": 4, "codename": "change_contenttype"}}, {"model": "auth.permission", "pk": 15, "fields": {"name": "Can delete content type", "content_type": 4, "codename": "delete_contenttype"}}, {"model": "auth.permission", "pk": 16, "fields": {"name": "Can view content type", "content_type": 4, "codename": "view_contenttype"}}, {"model": "auth.permission", "pk": 17, "fields": {"name": "Can add session", "content_type": 5, "codename": "add_session"}}, {"model": "auth.permission", "pk": 18, "fields": {"name": "Can change session", "content_type": 5, "codename": "change_session"}}, {"model": "auth.permission", "pk": 19, "fields": {"name": "Can delete session", "content_type": 5, "codename": "delete_session"}}, {"model": "auth.permission", "pk": 20, "fields": {"name": "Can view session", "content_type": 5, "codename": "view_session"}}, {"model": "auth.permission", "pk": 21, "fields": {"name": "Can add user", "content_type": 6, "codename": "add_user"}}, {"model": "auth.permission", "pk": 22, "fields": {"name": "Can change user", "content_type": 6, "codename": "change_user"}}, {"model": "auth.permission", "pk": 23, "fields": {"name": "Can delete user", "content_type": 6, "codename": "delete_user"}}, {"model": "auth.permission", "pk": 24, "fields": {"name": "Can view user", "content_type": 6, "codename": "view_user"}}, {"model": "auth.permission", "pk": 25, "fields": {"name": "Can add Token", "content_type": 7, "codename": "add_token"}}, {"model": "auth.permission", "pk": 26, "fields": {"name": "Can change Token", "content_type": 7, "codename": "change_token"}}, {"model": "auth.permission", "pk": 27, "fields": {"name": "Can delete Token", "content_type": 7, "codename": "delete_token"}}, {"model": "auth.permission", "pk": 28, "fields": {"name": "Can view Token", "content_type": 7, "codename": "view_token"}}, {"model": "auth.permission", "pk": 29, "fields": {"name": "Can add token", "content_type": 8, "codename": "add_tokenproxy"}}, {"model": "auth.permission", "pk": 30, "fields": {"name": "Can change token", "content_type": 8, "codename": "change_tokenproxy"}}, {"model": "auth.permission", "pk": 31, "fields": {"name": "Can delete token", "content_type": 8, "codename": "delete_tokenproxy"}}, {"model": "auth.permission", "pk": 32, "fields": {"name": "Can view token", "content_type": 8, "codename": "view_tokenproxy"}}, {"model": "auth.permission", "pk": 33, "fields": {"name": "Can add blacklisted token", "content_type": 9, "codename": "add_blacklistedtoken"}}, {"model": "auth.permission", "pk": 34, "fields": {"name": "Can change blacklisted token", "content_type": 9, "codename": "change_blacklistedtoken"}}, {"model": "auth.permission", "pk": 35, "fields": {"name": "Can delete blacklisted token", "content_type": 9, "codename": "delete_blacklistedtoken"}}, {"model": "auth.permission", "pk": 36, "fields": {"name": "Can view blacklisted token", "content_type": 9, "codename": "view_blacklistedtoken"}}, {"model": "auth.permission", "pk": 37, "fields": {"name": "Can add outstanding token", "content_type": 10, "codename": "add_outstandingtoken"}}, {"model": "auth.permission", "pk": 38, "fields": {"name": "Can change outstanding token", "content_type": 10, "codename": "change_outstandingtoken"}}, {"model": "auth.permission", "pk": 39, "fields": {"name": "Can delete outstanding token", "content_type": 10, "codename": "delete_outstandingtoken"}}, {"model": "auth.permission", "pk": 40, "fields": {"name": "Can view outstanding token", "content_type": 10, "codename": "view_outstandingtoken"}}, {"model": "contenttypes.contenttype", "pk": 1, "fields": {"app_label": "admin", "model": "logentry"}}, {"model": "contenttypes.contenttype", "pk": 2, "fields": {"app_label": "auth", "model": "permission"}}, {"model": "contenttypes.contenttype", "pk": 3, "fields": {"app_label": "auth", "model": "group"}}, {"model": "contenttypes.contenttype", "pk": 4, "fields": {"app_label": "contenttypes", "model": "contenttype"}}, {"model": "contenttypes.contenttype", "pk": 5, "fields": {"app_label": "sessions", "model": "session"}}, {"model": "contenttypes.contenttype", "pk": 6, "fields": {"app_label": "accounts", "model": "user"}}, {"model": "contenttypes.contenttype", "pk": 7, "fields": {"app_label": "authtoken", "model": "token"}}, {"model": "contenttypes.contenttype", "pk": 8, "fields": {"app_label": "authtoken", "model": "tokenproxy"}}, {"model": "contenttypes.contenttype", "pk": 9, "fields": {"app_label": "token_blacklist", "model": "blacklistedtoken"}}, {"model": "contenttypes.contenttype", "pk": 10, "fields": {"app_label": "token_blacklist", "model": "outstandingtoken"}}, {"model": "sessions.session", "pk": "0lj70ow49zmg8h4203ohgenkynhxiplo", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmI6f:m8w11QCH_xRVLvznCt14-gVBseQTD3zo2thGtLJZzow", "expire_date": "2024-04-01T18:53:09.553Z"}}, {"model": "sessions.session", "pk": "18ujp6mzhgspg4zon246sg73h7m91xp2", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKEy:gpg15lkiv1lXfADztJZt7pFqW74E9oJn8unbpmfX7WY", "expire_date": "2024-04-01T21:09:52.105Z"}}, {"model": "sessions.session", "pk": "1khyypdq1153bbezqo56kgsedqcfftba", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmGyG:D8Ob--ulmjK7hTxoig_S5jHo3KeqCDjdspdhELVtHWk", "expire_date": "2024-04-01T17:40:24.225Z"}}, {"model": "sessions.session", "pk": "1zzgz3wim189gqkkdkl2fvddi3rsrv6a", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxs:MSdkkqvNC8oOdftF7yJohkSIxpMMSHbK0hPxtYRat34", "expire_date": "2024-04-01T18:44:04.639Z"}}, {"model": "sessions.session", "pk": "2hea66t8qkawnvejjp0uy076spiqcodx", "fields": {"session_data": "e30:1rmQsi:MVxzm1f9qY2H3n_PuDKxJQax1cETyYB7j5g88BPGRd0", "expire_date": "2024-04-02T04:15:20.818Z"}}, {"model": "sessions.session", "pk": "2l6hrm6fog5gqnzo2kjrthrkdu8ch7op", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJer:XxwF7V8bmJWCXukO46FUlhjA6JIbof1ucprXarZhCmg", "expire_date": "2024-04-01T20:32:33.577Z"}}, {"model": "sessions.session", "pk": "2pm7siyjnncnw8wjxid3lba2liwmwu1x", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHMM:jfNy1Uiw0JPZtDKJd-ihqvSieMknXXD6Yl0kPtvx1oI", "expire_date": "2024-04-01T18:05:18.760Z"}}, {"model": "sessions.session", "pk": "33ly3t3i9xtl83jaj1ofr5rr847xdbuj", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxl:cBbuSkG2_b0NNl158llFPvw4FRTvNwbVcWZzw6iWvvY", "expire_date": "2024-04-01T18:43:57.395Z"}}, {"model": "sessions.session", "pk": "3rq8gkkdx0l8vxiepfa1twzm30goq29j", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmI5n:Iu6M-FyZvHI99q0IgeVREtDSWtdbc4YVLnG3jp1solo", "expire_date": "2024-04-01T18:52:15.400Z"}}, {"model": "sessions.session", "pk": "52omk4l02ulevkl0oullz8ij0kgl4ua7", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmS7Q:jH6RtZCxtNtW6ohNgysvB2ow6aCv2gBCo0OixKCJt14", "expire_date": "2024-04-02T05:34:36.722Z"}}, {"model": "sessions.session", "pk": "52xtu6qb7dlr8ximaet5l4olctag8ecp", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJLJ:6_pqBRON214LEiv3M1HGumYyxTg3od0zpcX4vfaIrNw", "expire_date": "2024-04-01T20:12:21.266Z"}}, {"model": "sessions.session", "pk": "5pobgf7nednfde499h2l7e5bxs35s3wg", "fields": {"session_data": "e30:1rmGny:_tbwk5K1Zy8Vv6MokDYzKDLxlFG9pt0sQ0aAJMFQWxY", "expire_date": "2024-04-01T17:29:46.360Z"}}, {"model": "sessions.session", "pk": "6v4bn3d8u52xfgd2644dsqbkcin1cnu2", "fields": {"session_data": "e30:1rmGpp:gkKxdjRNTL41shLPFHXlJ9NuhK6cg1TbJk47jn7gFsM", "expire_date": "2024-04-01T17:31:41.102Z"}}, {"model": "sessions.session", "pk": "70whw8s2wprqdrckrm6icn22lstbgzba", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmRNa:7UcwwnGGi3s7zd9JBpxCIaPzaXYDUPzp36YqFcRtKjI", "expire_date": "2024-04-02T04:47:14.489Z"}}, {"model": "sessions.session", "pk": "7zsl1wu9qp34ijf9p158pdjc63byi4ap", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmICs:lJBLidVW-eY-FJQgInmjI8jREFBku-1h4UoD_w9j8Ko", "expire_date": "2024-04-01T18:59:34.138Z"}}, {"model": "sessions.session", "pk": "9y7l84csvm09yn79js49cbodluk8tejv", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmI6c:FrRBSo2ZBulK03wIQCQ2M0lBOBUtHvOc_4NsjhB549M", "expire_date": "2024-04-01T18:53:06.420Z"}}, {"model": "sessions.session", "pk": "bluy0olsqj65bubjk8hs4iquxe8zq6uv", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJif:dOmoA7JJ2si0PscFo1Xi6XiwsBlipncrL4a73Y4YtUs", "expire_date": "2024-04-01T20:36:29.682Z"}}, {"model": "sessions.session", "pk": "cyl20f8vpeprr9op685t4hfcnuvdml39", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHwe:NkObck8Ufdp1Z4iyLpNlSL1nxlGaDDOo00ZUiIfozBE", "expire_date": "2024-04-01T18:42:48.900Z"}}, {"model": "sessions.session", "pk": "djn99zjzt7tfgx6opmuzy6f2ar79lidz", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHwU:xleXk9zi8J9VhpRv5tBBpBrgtbdhloDp7FS7PVOkBKw", "expire_date": "2024-04-01T18:42:38.224Z"}}, {"model": "sessions.session", "pk": "eff46udk4lmizr11zi1o5qhzveyjaigx", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHTT:tf6C6k7Xp24HSUTXTkupPmCW3ijGl_4RwzkgxfoWia0", "expire_date": "2024-04-01T18:12:39.632Z"}}, {"model": "sessions.session", "pk": "em22ut8458zap356a1y7bdqd15s5qjkf", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJN2:6x31lIDvU40Y-X_7nQ2mI_2atOrd4d2oJYfX-qP38Go", "expire_date": "2024-04-01T20:14:08.079Z"}}, {"model": "sessions.session", "pk": "fahyct20xswep3kbkzo1i76xdargeq7t", "fields": {"session_data": "e30:1rmSKD:Q_VWuhZPbK5Sy5GyD4ZbZ0JXSJ8tJiq61TYwewESNc0", "expire_date": "2024-04-02T05:47:49.163Z"}}, {"model": "sessions.session", "pk": "ffpglxxj7x3c32c1dujbc8ensa6ohwx6", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKf5:5yqAu6gSl5PzIEaGouI1BK7Elt6jsoq9R1bfaJLJBns", "expire_date": "2024-04-01T21:36:51.485Z"}}, {"model": "sessions.session", "pk": "g5gkz2e9xe9oan8p2tanbhup6lk10s1f", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJ0y:CWZRV8OvA4hkTHQPpdIFXmrjW1Pz1LR-BMWEyVteARg", "expire_date": "2024-04-01T19:51:20.325Z"}}, {"model": "sessions.session", "pk": "gous0i7ru683v3nbo7uzy5136020jul6", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKHM:8XD94fhHFzPgtwrc1NLL-YbyHtEgtjM2GKJ6Y9rdkvo", "expire_date": "2024-04-01T21:12:20.579Z"}}, {"model": "sessions.session", "pk": "gpn8dgeg1q069akdpgh12bk7dz6q7mdj", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJOm:fA1eGYvqeUASmijVsW-ZIM0NrITjw5iyunYWEfm1yBk", "expire_date": "2024-04-01T20:15:56.709Z"}}, {"model": "sessions.session", "pk": "js15kvywxqb3e4lvl01f4rfd5dc5lu7a", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHTu:sSPEKAmCWBMSeSgSQwEmP4ni-lmjTgUqxTq94vf08Wc", "expire_date": "2024-04-01T18:13:06.033Z"}}, {"model": "sessions.session", "pk": "kzyqaapftcq31kqsynl6nwo8l59cwbjd", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHlu:E7Joe9ZMenwc1STYWmZNPWRN8fnmXPFtrSCja0iPaQE", "expire_date": "2024-04-01T18:31:42.325Z"}}, {"model": "sessions.session", "pk": "m7eh8pibhsc620yrmxe00k2keohtyssl", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxU:dfbUfYIsBT1HKvW9nuqx2oVCMPWqPejODqgYC8uXKHQ", "expire_date": "2024-04-01T18:43:40.931Z"}}, {"model": "sessions.session", "pk": "n03gba8gu6nykf115q1ihtqzg3k1e59j", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHFO:WV7nz9Rge6tucvLZ2yejQy2do5j1c4K4054WjT7Oge0", "expire_date": "2024-04-01T17:58:06.577Z"}}, {"model": "sessions.session", "pk": "ns6cqm4npaj25w3ayw55ogkwfsuwghhm", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxa:Tjdsf9X-03fJJJ51h43n9ON5MedoQD1BgZLjoJ0CAEg", "expire_date": "2024-04-01T18:43:46.518Z"}}, {"model": "sessions.session", "pk": "o1qn16dk7am5vngsfxis11sj4q7462qt", "fields": {"session_data": "e30:1rmS7B:lDtc2fHo25QRXljHU-uyd6apCEG2udkGexVq1NhyD9k", "expire_date": "2024-04-02T05:34:21.281Z"}}, {"model": "sessions.session", "pk": "o56rln4oqfa9514pm6cdxvynxqwc6y1y", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJMw:FQL2NefdSnKMqM7ix4qIgnIlU3BhvijY5oCcL4i76jw", "expire_date": "2024-04-01T20:14:02.460Z"}}, {"model": "sessions.session", "pk": "oiuvwczrjipstwx3hfd1hk0itlgcrc9g", "fields": {"session_data": "e30:1rmS70:kVaTpSy-XqOqwqcgEpOZTg2ylxTkW64I7R-r9Gg_pUU", "expire_date": "2024-04-02T05:34:10.436Z"}}, {"model": "sessions.session", "pk": "op8ju3j3vlmos7mgc2lwtcq3wjfa2aq0", "fields": {"session_data": ".eJxVjEsOwiAUAO_C2hC-BVy67xnIe_AqVQNJaVfGuxuSLnQ7M5k3i3DsJR6dtrhmdmWGXX4ZQnpSHSI_oN4bT63u24p8JPy0nc8t0-t2tn-DAr2M7YLK6yR98lZQtoRJAbjFKx2coyAk2QSA5KU2E9ocVJDCYMgYpLcT-3wB8l833w:1rmI9T:SHKsXwZg7STJkrmISBNKddLjtmfXPUAB688SZQGyBmU", "expire_date": "2024-04-01T18:56:03.076Z"}}, {"model": "sessions.session", "pk": "pc9b382q9jenzz0o1vvrnoq6zcu0lese", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmRYd:DvrmvBJZk-0bjA5QtZzh1ZZO0veLFDQpPaqy1r1ubKA", "expire_date": "2024-04-02T04:58:39.264Z"}}, {"model": "sessions.session", "pk": "q5xhv1a9t0wzn8j265vd5p0bg6lbuk52", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHDl:9oei0N1CYbGnCa5ao8xU9gVyVBrIHhmzDvXgvIavu58", "expire_date": "2024-04-01T17:56:25.082Z"}}, {"model": "sessions.session", "pk": "qh5jjeb6uvvpo2uvu1ygs3apffk0xont", "fields": {"session_data": ".eJxVjEsOwiAUAO_C2hC-BVy67xnIe_AqVQNJaVfGuxuSLnQ7M5k3i3DsJR6dtrhmdmWGXX4ZQnpSHSI_oN4bT63u24p8JPy0nc8t0-t2tn-DAr2M7YLK6yR98lZQtoRJAbjFKx2coyAk2QSA5KU2E9ocVJDCYMgYpLcT-3wB8l833w:1rmI9M:YuAGHnkH_da9gEm9iATI_o2X-qj1z6dVa6B92XjGOQo", "expire_date": "2024-04-01T18:55:56.900Z"}}, {"model": "sessions.session", "pk": "r8blbjmv9ztpuxl0eetwfkiaxx3pjmd4", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJUT:u3a5UPsXXcr-Tjb3S7e2OGM7ijyKsIEL1iL2VEnCzZQ", "expire_date": "2024-04-01T20:21:49.722Z"}}, {"model": "sessions.session", "pk": "rcpipm5e3ti6fpt6pbca8wfzkjpctg6e", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKhV:kBtdpAecgCvYgfp28btW6e517fzQMQ6bUB6TqIAX-nY", "expire_date": "2024-04-01T21:39:21.902Z"}}, {"model": "sessions.session", "pk": "tkwnol43aorodcaeouhb3yui29z0gp00", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmQtp:W8vPU_OXwBQz5-IqCvK2goOOPX05Tvv5qG35Y02wMa4", "expire_date": "2024-04-02T04:16:29.095Z"}}, {"model": "sessions.session", "pk": "u8j0fv9u88g4e3cwrftmzso554w6nwt3", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmS7Z:uLlK3e7PovgkD0SGTUfeNyNHMRSKajIL0rmR4V-jRU0", "expire_date": "2024-04-02T05:34:45.359Z"}}, {"model": "sessions.session", "pk": "u9prph4jh4ptvd5rvwoscdlx9i2nf4wg", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHTo:SALCNCFNLKpGUWhLuSCnnOSgctzTejbbMASTdS4FJ1Q", "expire_date": "2024-04-01T18:13:00.209Z"}}, {"model": "sessions.session", "pk": "ulc8j51meav9672gb2ntl4sx2kh2xlll", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmR3c:mjgATakdBRuZngeUSxCaRJuVrQfvfd3e7iNWz0qcMhY", "expire_date": "2024-04-02T04:26:36.099Z"}}, {"model": "sessions.session", "pk": "ver4tb4f9ioa56xaolw5n9rjvn7bemi9", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmSms:3i4qPzE-TwrbwNPlY6-xMkma5kaEo-7XaQLeEe3_EAo", "expire_date": "2024-04-02T06:17:26.143Z"}}, {"model": "sessions.session", "pk": "wky4pklf9hxnmwnu9qrgxgks73pk44xd", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmGtB:iT2iYsJDrXvWkQU5aTtk3cME2aM5b5rBR0L6Gxqy8hc", "expire_date": "2024-04-01T17:35:09.523Z"}}, {"model": "sessions.session", "pk": "wuhh2s4bb8tu7u6xy7z8ltrk8iqvjw0l", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmGvh:N5RGCblZMROGzB0QdEPtYSXykklMQAEF0Ll3TRJeePA", "expire_date": "2024-04-01T17:37:45.076Z"}}, {"model": "sessions.session", "pk": "xilyfd4yg8ysk19yah2wk3n4g1ab9u9r", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHAn:PyF29fTq4vtxvRbdWW-vhFaSeIC85BGuRS1yrqx-GYQ", "expire_date": "2024-04-01T17:53:21.938Z"}}, {"model": "sessions.session", "pk": "yc7qdica8thagwd93zzirt2qldk1k049", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHx4:eQXAGZQL-Gp-krJXlzVz1XoW5Z3iqVBA1flE6LH_ySo", "expire_date": "2024-04-01T18:43:14.254Z"}}, {"model": "sessions.session", "pk": "yk3ofc7pt03hisg314xeqiw635b75nc7", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJJG:AGRzWn9TxAze7foD-DPqXnjnSKR2HocT4RigNug8fkY", "expire_date": "2024-04-01T20:10:14.774Z"}}, {"model": "sessions.session", "pk": "ytuh5jfbam8e1kn5e5l41icoo15l78zr", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmI0A:gGzjvvhvU8DoAZ6GAB7QN2N9jYm_2s2nIvmmgpzczo8", "expire_date": "2024-04-01T18:46:26.804Z"}}, {"model": "sessions.session", "pk": "z5ws47x4rj7aev8djgtoi4u6det5i9te", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmS5C:2VOYW9hiOuIS2Ls_VTnZ2acqGw6z9tpuQXwgcDROfZY", "expire_date": "2024-04-02T05:32:18.484Z"}}, {"model": "accounts.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$720000$3xBZIPeMQloi18hZVD5Cyz$d9sMhoJr7nFBfsFFr2X/uEj1gEn03JQNFe+3SBfL7TM=", "last_login": "2024-03-19T06:17:26.111Z", "firstname": "Amirali", "lastname": "Hamid", "email": "hagixi9797@dovesilo.com", "date_of_birth": "2024-03-14", "gender": "F", "is_active": true, "is_admin": false, "phone_number": null, "is_email_verified": true, "verification_code": null, "verification_tries_count": 1, "last_verification_sent": "2024-03-18T20:55:38.047Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 2, "fields": {"password": "pbkdf2_sha256$720000$94IHJQPRqqEmfxUHzVFDxY$OJu6HHr1vF5bQOGiq8I/jbCDxdYx2xaL2xcieKLjqS4=", "last_login": null, "firstname": "sara", "lastname": "saraee", "email": "hayohin504@azduan.com", "date_of_birth": "2024-03-05", "gender": "F", "is_active": true, "is_admin": false, "phone_number": null, "is_email_verified": false, "verification_code": "8095", "verification_tries_count": 1, "last_verification_sent": "2024-03-18T21:58:45.828Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 3, "fields": {"password": "pbkdf2_sha256$720000$A5jYNIa8CcqGHr2Cuj6Bvl$MpxEJoZ08tD5AfKFIPqmF3kd6TRBQ7PuX40Kjwv6d70=", "last_login": "2024-03-18T18:53:09.537Z", "firstname": "asma", "lastname": "hamid", "email": "asmahamid1382@gmail.com", "date_of_birth": "1382-03-27", "gender": "F", "is_active": true, "is_admin": true, "phone_number": null, "is_email_verified": false, "verification_code": null, "verification_tries_count": 0, "last_verification_sent": "2024-03-18T22:11:13.827Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 4, "fields": {"password": "pbkdf2_sha256$720000$5q8eAOIlk7iTnf0S8ONR4S$QLCRJJiP0L+SO0Vykw/zQ2MAyAJWbE23cTWWQMEkpZc=", "last_login": "2024-03-18T18:56:03.072Z", "firstname": "amir", "lastname": "amiri", "email": "asma_hamid@comp.iust.ac.ir", "date_of_birth": "1382-05-26", "gender": "M", "is_active": true, "is_admin": true, "phone_number": null, "is_email_verified": false, "verification_code": null, "verification_tries_count": 0, "last_verification_sent": "2024-03-18T22:23:54.904Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 5, "fields": {"password": "pbkdf2_sha256$720000$tIVqgZDGjxMtlXveRncdjp$V9J7SPmz7eVv/tv6y5XS0A5IWPFk/rOPuXzO9KGgsKA=", "last_login": null, "firstname": "sian", "lastname": "sinaee", "email": "mibag84210@dovesilo.com", "date_of_birth": "2024-03-13", "gender": "M", "is_active": true, "is_admin": false, "phone_number": null, "is_email_verified": false, "verification_code": "2293", "verification_tries_count": 1, "last_verification_sent": "2024-03-18T23:16:39.742Z", "has_verification_tries_reset": false}}] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 44d0eec..cbdfa78 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ charset-normalizer==3.3.2 coreapi==2.3.3 coreschema==0.0.4 Django==5.0.3 +django-phonenumber-field==7.3.0 django-rest-swagger==2.2.0 djangorestframework==3.14.0 djangorestframework-simplejwt==5.3.1 @@ -17,37 +18,9 @@ MarkupSafe==2.1.5 marshmallow==3.21.1 openapi-codec==1.3.2 packaging==24.0 -PyJWT==2.8.0 -python-dotenv==1.0.1 -pytz==2024.1 -PyYAML==6.0.1 -requests==2.31.0 -setuptools==69.2.0 -simplejson==3.19.2 -sqlparse==0.4.4 -typing_extensions==4.10.0 -tzdata==2024.1 -uritemplate==4.1.1 -urllib3==2.2.1 -asgiref==3.7.2 -certifi==2024.2.2 -charset-normalizer==3.3.2 -coreapi==2.3.3 -coreschema==0.0.4 -Django==5.0.3 -django-rest-swagger==2.2.0 -djangorestframework==3.14.0 -djangorestframework-simplejwt==5.3.1 -drf-yasg==1.21.7 -environs==11.0.0 -idna==3.6 -inflection==0.5.1 -itypes==1.2.0 -Jinja2==3.1.3 -MarkupSafe==2.1.5 -marshmallow==3.21.1 -openapi-codec==1.3.2 -packaging==24.0 +phonenumbers==8.13.32 +psycopg2==2.9.9 +psycopg2-binary==2.9.9 PyJWT==2.8.0 python-dotenv==1.0.1 pytz==2024.1 From ff87d39477ba7643d7c1bdd53cc8a17a0e5a2dd3 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Tue, 2 Apr 2024 15:54:23 +0330 Subject: [PATCH 22/46] fix/doctorImage --- BackEnd/BackEnd/settings.py | 6 +++--- BackEnd/BackEnd/urls.py | 9 +++++++++ BackEnd/counseling/models.py | 21 ++++++++------------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 5327952..56bf755 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -31,7 +31,7 @@ env.read_env() # Setting Website URL -WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') +WEBSITE_URL = 'http://localhost:80ssss00/' #env.str('WEBSITE_URL') # BASE_URL = 'http://localhost:8000/' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' @@ -40,12 +40,12 @@ EMAIL_PORT = 587 EMAIL_USE_TLS = True REDIS_HOST = os.environ.get('REDIS_HOST', '127.0.0.1') -CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] +# CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000/"] SESSION_COOKIE_SECURE = False SESSION_EXPIRE_AT_BROWSER_CLOSE = False -MEDIA_ROOT = os.path.join(BASE_DIR, "media/") MEDIA_URL = "media/" +MEDIA_ROOT = os.path.join(BASE_DIR, MEDIA_URL) # SESSION_COOKIE_DOMAIN diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index 2710ec0..1367aa0 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -19,6 +19,9 @@ from drf_yasg.views import get_schema_view from rest_framework import permissions from drf_yasg import openapi +from django.urls import re_path as url +from django.views.static import serve +from django.conf import settings schema_view = get_schema_view( openapi.Info( @@ -40,3 +43,9 @@ path('profile/' , include("Profile.urls")) , path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ] + + +if settings.DEBUG: + urlpatterns += [ + url(r'^media/(?P.*)$', serve, {'document_root': settings.MEDIA_ROOT}), +] \ No newline at end of file diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 32d17aa..0ef1a6a 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -23,26 +23,18 @@ class Psychiatrist(models.Model ) : field = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) def get_default_profile_image(self): - # print( " in defualt image ") - + if self.user.gender == 'M': - res = settings.MEDIA_URL + 'images/doctors/profile_pics/male_default.png' + res = 'images/doctors/profile_pics/male_default.png' ## settings.MEDIA_URL + return res else: - res = settings.MEDIA_URL + 'images/doctors/profile_pics/female_default.png' + res = 'images/doctors/profile_pics/female_default.png' return res - def save(self, *args, **kwargs): - if not self.user.role == 'doctor': - self.user.role = User.TYPE_DOCTOR - self.user.save() - super().save(*args, **kwargs) - - def get_profile_image(self ) : if not self.image : var = self.get_default_profile_image() - # print("var ---------------> ", var) + return var else : return settings.MEDIA_URL + self.image # settings.MEDIA_ROOT + @@ -54,12 +46,15 @@ def save(self, *args, **kwargs): """ Check if there's already a Psychiatrist object associated with this User """ + print( "hereeeeeeeeeeeeeeeeeeeeeeeeeeee") if Psychiatrist.objects.filter(user=self.user).exists(): raise ValidationError("A Psychiatrist object already exists for this User.") + if not self.user.role == 'doctor': + self.user.role = User.TYPE_DOCTOR + self.user.save() super().save(*args, **kwargs) - # TODO add fields for pationt class Pationt( models.Model ) : user = models.ForeignKey(User, on_delete=models.CASCADE) From 0937a59aec290c51dbe067b542c5a17123d5a1da Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 3 Apr 2024 01:32:42 +0330 Subject: [PATCH 23/46] fix/media --- BackEnd/BackEnd/settings.py | 3 +-- BackEnd/Profile/migrations/0001_initial.py | 10 ++------ .../migrations/0002_alter_profile_image.py | 18 --------------- BackEnd/Profile/signals.py | 1 - BackEnd/accounts/migrations/0001_initial.py | 4 ++-- .../0002_alter_user_last_verification_sent.py | 4 ++-- .../0003_alter_user_last_verification_sent.py | 23 +++++++++++++++++++ .../0023_alter_user_last_verification_sent.py | 19 --------------- .../0024_alter_user_last_verification_sent.py | 19 --------------- .../0025_alter_user_last_verification_sent.py | 19 --------------- BackEnd/counseling/migrations/0001_initial.py | 6 ++--- .../0002_alter_psychiatrist_image.py | 18 --------------- .../0003_alter_psychiatrist_image.py | 20 ---------------- BackEnd/counseling/models.py | 9 ++++---- BackEnd/datadump.json | 2 +- 15 files changed, 38 insertions(+), 137 deletions(-) delete mode 100644 BackEnd/Profile/migrations/0002_alter_profile_image.py create mode 100644 BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py delete mode 100644 BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py delete mode 100644 BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 733c591..c0b4ced 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -45,7 +45,7 @@ SESSION_COOKIE_SECURE = False SESSION_EXPIRE_AT_BROWSER_CLOSE = False MEDIA_URL = "media/" -MEDIA_ROOT = os.path.join(BASE_DIR, MEDIA_URL) +MEDIA_ROOT = os.path.join(BASE_DIR, "media/") # SESSION_COOKIE_DOMAIN @@ -165,7 +165,6 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'TherapyDB', 'USER': 'postgres', diff --git a/BackEnd/Profile/migrations/0001_initial.py b/BackEnd/Profile/migrations/0001_initial.py index 21342c0..6011a34 100644 --- a/BackEnd/Profile/migrations/0001_initial.py +++ b/BackEnd/Profile/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-01 00:14 +# Generated by Django 5.0.3 on 2024-04-02 21:45 import django.db.models.deletion from django.db import migrations, models @@ -27,13 +27,7 @@ class Migration(migrations.Migration): ), ("description", models.TextField(blank=True, null=True)), ("name", models.CharField(blank=True, max_length=50, null=True)), - ( - "image", - models.ImageField( - default="images/profile_pics/default.png", - upload_to="images/profile_pics", - ), - ), + ("image", models.ImageField(upload_to="images\\doctors\\profile_pics")), ("profile_type", models.CharField(max_length=10)), ("created_at", models.DateTimeField(auto_now_add=True)), ("is_private", models.BooleanField(default=False)), diff --git a/BackEnd/Profile/migrations/0002_alter_profile_image.py b/BackEnd/Profile/migrations/0002_alter_profile_image.py deleted file mode 100644 index 44ff85e..0000000 --- a/BackEnd/Profile/migrations/0002_alter_profile_image.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-02 01:37 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("Profile", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="image", - field=models.ImageField(upload_to="images\\doctors\\profile_pics"), - ), - ] diff --git a/BackEnd/Profile/signals.py b/BackEnd/Profile/signals.py index 113591e..fc1cf4e 100644 --- a/BackEnd/Profile/signals.py +++ b/BackEnd/Profile/signals.py @@ -11,7 +11,6 @@ def create_profile(sender, instance, created, **kwargs): print( " sender------------->" , sender ) Profile.objects.create(psychiatrist=instance) - @receiver(post_save, sender=Psychiatrist) def save_profile(sender, instance, **kwargs): diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index abe5b71..cd46441 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-01 00:13 +# Generated by Django 5.0.3 on 2024-04-02 21:45 import datetime import django.core.validators @@ -81,7 +81,7 @@ class Migration(migrations.Migration): "last_verification_sent", models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 1, 3, 43, 49, 999854), + default=datetime.datetime(2024, 4, 3, 1, 15, 12, 435402), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py index a2b5fa8..b70a65b 100644 --- a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py +++ b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-02 01:37 +# Generated by Django 5.0.3 on 2024-04-02 21:45 import datetime from django.db import migrations, models @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 2, 5, 7, 21, 743773), + default=datetime.datetime(2024, 4, 3, 1, 15, 34, 442056), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py new file mode 100644 index 0000000..b513fa9 --- /dev/null +++ b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-04-02 21:46 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0002_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 4, 3, 1, 16, 13, 569335), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py deleted file mode 100644 index 654c653..0000000 --- a/BackEnd/accounts/migrations/0023_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-03-26 14:17 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0022_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 3, 26, 17, 47, 44, 89992), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py deleted file mode 100644 index 7733aae..0000000 --- a/BackEnd/accounts/migrations/0024_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-02 07:25 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0023_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 2, 10, 55, 41, 864832), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py deleted file mode 100644 index fded790..0000000 --- a/BackEnd/accounts/migrations/0025_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-02 08:00 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0024_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 2, 11, 30, 8, 151776), null=True), - ), - ] diff --git a/BackEnd/counseling/migrations/0001_initial.py b/BackEnd/counseling/migrations/0001_initial.py index 76e59db..d5c03f2 100644 --- a/BackEnd/counseling/migrations/0001_initial.py +++ b/BackEnd/counseling/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-01 00:13 +# Generated by Django 5.0.3 on 2024-04-02 21:45 import django.db.models.deletion from django.conf import settings @@ -50,9 +50,7 @@ class Migration(migrations.Migration): ( "image", models.ImageField( - default="images/doctors/profile_pics/default.png", - null=True, - upload_to="images/doctors/profile_pics", + blank=True, null=True, upload_to="images/doctors/profile_pics" ), ), ( diff --git a/BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py b/BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py deleted file mode 100644 index a66ab01..0000000 --- a/BackEnd/counseling/migrations/0002_alter_psychiatrist_image.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-01 20:52 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("counseling", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="psychiatrist", - name="image", - field=models.ImageField(null=True, upload_to="images/doctors/profile_pics"), - ), - ] diff --git a/BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py b/BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py deleted file mode 100644 index fd0efff..0000000 --- a/BackEnd/counseling/migrations/0003_alter_psychiatrist_image.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-01 20:57 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("counseling", "0002_alter_psychiatrist_image"), - ] - - operations = [ - migrations.AlterField( - model_name="psychiatrist", - name="image", - field=models.ImageField( - blank=True, null=True, upload_to="images/doctors/profile_pics" - ), - ), - ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 0ef1a6a..8638bf0 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -34,11 +34,12 @@ def get_default_profile_image(self): def get_profile_image(self ) : if not self.image : var = self.get_default_profile_image() - return var else : - return settings.MEDIA_URL + self.image # settings.MEDIA_ROOT + - + VAR = settings.MEDIA_URL + str(self.image ) + print(VAR) + return VAR + def get_fullname(self) : return str(self.user.firstname) + " " + str(self.user.lastname) @@ -46,7 +47,7 @@ def save(self, *args, **kwargs): """ Check if there's already a Psychiatrist object associated with this User """ - print( "hereeeeeeeeeeeeeeeeeeeeeeeeeeee") + # print( "hereeeeeeeeeeeeeeeeeeeeeeeeeeee") if Psychiatrist.objects.filter(user=self.user).exists(): raise ValidationError("A Psychiatrist object already exists for this User.") if not self.user.role == 'doctor': diff --git a/BackEnd/datadump.json b/BackEnd/datadump.json index cc611a1..8e2f0be 100644 --- a/BackEnd/datadump.json +++ b/BackEnd/datadump.json @@ -1 +1 @@ -[{"model": "auth.permission", "pk": 1, "fields": {"name": "Can add log entry", "content_type": 1, "codename": "add_logentry"}}, {"model": "auth.permission", "pk": 2, "fields": {"name": "Can change log entry", "content_type": 1, "codename": "change_logentry"}}, {"model": "auth.permission", "pk": 3, "fields": {"name": "Can delete log entry", "content_type": 1, "codename": "delete_logentry"}}, {"model": "auth.permission", "pk": 4, "fields": {"name": "Can view log entry", "content_type": 1, "codename": "view_logentry"}}, {"model": "auth.permission", "pk": 5, "fields": {"name": "Can add permission", "content_type": 2, "codename": "add_permission"}}, {"model": "auth.permission", "pk": 6, "fields": {"name": "Can change permission", "content_type": 2, "codename": "change_permission"}}, {"model": "auth.permission", "pk": 7, "fields": {"name": "Can delete permission", "content_type": 2, "codename": "delete_permission"}}, {"model": "auth.permission", "pk": 8, "fields": {"name": "Can view permission", "content_type": 2, "codename": "view_permission"}}, {"model": "auth.permission", "pk": 9, "fields": {"name": "Can add group", "content_type": 3, "codename": "add_group"}}, {"model": "auth.permission", "pk": 10, "fields": {"name": "Can change group", "content_type": 3, "codename": "change_group"}}, {"model": "auth.permission", "pk": 11, "fields": {"name": "Can delete group", "content_type": 3, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 12, "fields": {"name": "Can view group", "content_type": 3, "codename": "view_group"}}, {"model": "auth.permission", "pk": 13, "fields": {"name": "Can add content type", "content_type": 4, "codename": "add_contenttype"}}, {"model": "auth.permission", "pk": 14, "fields": {"name": "Can change content type", "content_type": 4, "codename": "change_contenttype"}}, {"model": "auth.permission", "pk": 15, "fields": {"name": "Can delete content type", "content_type": 4, "codename": "delete_contenttype"}}, {"model": "auth.permission", "pk": 16, "fields": {"name": "Can view content type", "content_type": 4, "codename": "view_contenttype"}}, {"model": "auth.permission", "pk": 17, "fields": {"name": "Can add session", "content_type": 5, "codename": "add_session"}}, {"model": "auth.permission", "pk": 18, "fields": {"name": "Can change session", "content_type": 5, "codename": "change_session"}}, {"model": "auth.permission", "pk": 19, "fields": {"name": "Can delete session", "content_type": 5, "codename": "delete_session"}}, {"model": "auth.permission", "pk": 20, "fields": {"name": "Can view session", "content_type": 5, "codename": "view_session"}}, {"model": "auth.permission", "pk": 21, "fields": {"name": "Can add user", "content_type": 6, "codename": "add_user"}}, {"model": "auth.permission", "pk": 22, "fields": {"name": "Can change user", "content_type": 6, "codename": "change_user"}}, {"model": "auth.permission", "pk": 23, "fields": {"name": "Can delete user", "content_type": 6, "codename": "delete_user"}}, {"model": "auth.permission", "pk": 24, "fields": {"name": "Can view user", "content_type": 6, "codename": "view_user"}}, {"model": "auth.permission", "pk": 25, "fields": {"name": "Can add Token", "content_type": 7, "codename": "add_token"}}, {"model": "auth.permission", "pk": 26, "fields": {"name": "Can change Token", "content_type": 7, "codename": "change_token"}}, {"model": "auth.permission", "pk": 27, "fields": {"name": "Can delete Token", "content_type": 7, "codename": "delete_token"}}, {"model": "auth.permission", "pk": 28, "fields": {"name": "Can view Token", "content_type": 7, "codename": "view_token"}}, {"model": "auth.permission", "pk": 29, "fields": {"name": "Can add token", "content_type": 8, "codename": "add_tokenproxy"}}, {"model": "auth.permission", "pk": 30, "fields": {"name": "Can change token", "content_type": 8, "codename": "change_tokenproxy"}}, {"model": "auth.permission", "pk": 31, "fields": {"name": "Can delete token", "content_type": 8, "codename": "delete_tokenproxy"}}, {"model": "auth.permission", "pk": 32, "fields": {"name": "Can view token", "content_type": 8, "codename": "view_tokenproxy"}}, {"model": "auth.permission", "pk": 33, "fields": {"name": "Can add blacklisted token", "content_type": 9, "codename": "add_blacklistedtoken"}}, {"model": "auth.permission", "pk": 34, "fields": {"name": "Can change blacklisted token", "content_type": 9, "codename": "change_blacklistedtoken"}}, {"model": "auth.permission", "pk": 35, "fields": {"name": "Can delete blacklisted token", "content_type": 9, "codename": "delete_blacklistedtoken"}}, {"model": "auth.permission", "pk": 36, "fields": {"name": "Can view blacklisted token", "content_type": 9, "codename": "view_blacklistedtoken"}}, {"model": "auth.permission", "pk": 37, "fields": {"name": "Can add outstanding token", "content_type": 10, "codename": "add_outstandingtoken"}}, {"model": "auth.permission", "pk": 38, "fields": {"name": "Can change outstanding token", "content_type": 10, "codename": "change_outstandingtoken"}}, {"model": "auth.permission", "pk": 39, "fields": {"name": "Can delete outstanding token", "content_type": 10, "codename": "delete_outstandingtoken"}}, {"model": "auth.permission", "pk": 40, "fields": {"name": "Can view outstanding token", "content_type": 10, "codename": "view_outstandingtoken"}}, {"model": "contenttypes.contenttype", "pk": 1, "fields": {"app_label": "admin", "model": "logentry"}}, {"model": "contenttypes.contenttype", "pk": 2, "fields": {"app_label": "auth", "model": "permission"}}, {"model": "contenttypes.contenttype", "pk": 3, "fields": {"app_label": "auth", "model": "group"}}, {"model": "contenttypes.contenttype", "pk": 4, "fields": {"app_label": "contenttypes", "model": "contenttype"}}, {"model": "contenttypes.contenttype", "pk": 5, "fields": {"app_label": "sessions", "model": "session"}}, {"model": "contenttypes.contenttype", "pk": 6, "fields": {"app_label": "accounts", "model": "user"}}, {"model": "contenttypes.contenttype", "pk": 7, "fields": {"app_label": "authtoken", "model": "token"}}, {"model": "contenttypes.contenttype", "pk": 8, "fields": {"app_label": "authtoken", "model": "tokenproxy"}}, {"model": "contenttypes.contenttype", "pk": 9, "fields": {"app_label": "token_blacklist", "model": "blacklistedtoken"}}, {"model": "contenttypes.contenttype", "pk": 10, "fields": {"app_label": "token_blacklist", "model": "outstandingtoken"}}, {"model": "sessions.session", "pk": "0lj70ow49zmg8h4203ohgenkynhxiplo", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmI6f:m8w11QCH_xRVLvznCt14-gVBseQTD3zo2thGtLJZzow", "expire_date": "2024-04-01T18:53:09.553Z"}}, {"model": "sessions.session", "pk": "18ujp6mzhgspg4zon246sg73h7m91xp2", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKEy:gpg15lkiv1lXfADztJZt7pFqW74E9oJn8unbpmfX7WY", "expire_date": "2024-04-01T21:09:52.105Z"}}, {"model": "sessions.session", "pk": "1khyypdq1153bbezqo56kgsedqcfftba", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmGyG:D8Ob--ulmjK7hTxoig_S5jHo3KeqCDjdspdhELVtHWk", "expire_date": "2024-04-01T17:40:24.225Z"}}, {"model": "sessions.session", "pk": "1zzgz3wim189gqkkdkl2fvddi3rsrv6a", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxs:MSdkkqvNC8oOdftF7yJohkSIxpMMSHbK0hPxtYRat34", "expire_date": "2024-04-01T18:44:04.639Z"}}, {"model": "sessions.session", "pk": "2hea66t8qkawnvejjp0uy076spiqcodx", "fields": {"session_data": "e30:1rmQsi:MVxzm1f9qY2H3n_PuDKxJQax1cETyYB7j5g88BPGRd0", "expire_date": "2024-04-02T04:15:20.818Z"}}, {"model": "sessions.session", "pk": "2l6hrm6fog5gqnzo2kjrthrkdu8ch7op", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJer:XxwF7V8bmJWCXukO46FUlhjA6JIbof1ucprXarZhCmg", "expire_date": "2024-04-01T20:32:33.577Z"}}, {"model": "sessions.session", "pk": "2pm7siyjnncnw8wjxid3lba2liwmwu1x", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHMM:jfNy1Uiw0JPZtDKJd-ihqvSieMknXXD6Yl0kPtvx1oI", "expire_date": "2024-04-01T18:05:18.760Z"}}, {"model": "sessions.session", "pk": "33ly3t3i9xtl83jaj1ofr5rr847xdbuj", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxl:cBbuSkG2_b0NNl158llFPvw4FRTvNwbVcWZzw6iWvvY", "expire_date": "2024-04-01T18:43:57.395Z"}}, {"model": "sessions.session", "pk": "3rq8gkkdx0l8vxiepfa1twzm30goq29j", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmI5n:Iu6M-FyZvHI99q0IgeVREtDSWtdbc4YVLnG3jp1solo", "expire_date": "2024-04-01T18:52:15.400Z"}}, {"model": "sessions.session", "pk": "52omk4l02ulevkl0oullz8ij0kgl4ua7", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmS7Q:jH6RtZCxtNtW6ohNgysvB2ow6aCv2gBCo0OixKCJt14", "expire_date": "2024-04-02T05:34:36.722Z"}}, {"model": "sessions.session", "pk": "52xtu6qb7dlr8ximaet5l4olctag8ecp", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJLJ:6_pqBRON214LEiv3M1HGumYyxTg3od0zpcX4vfaIrNw", "expire_date": "2024-04-01T20:12:21.266Z"}}, {"model": "sessions.session", "pk": "5pobgf7nednfde499h2l7e5bxs35s3wg", "fields": {"session_data": "e30:1rmGny:_tbwk5K1Zy8Vv6MokDYzKDLxlFG9pt0sQ0aAJMFQWxY", "expire_date": "2024-04-01T17:29:46.360Z"}}, {"model": "sessions.session", "pk": "6v4bn3d8u52xfgd2644dsqbkcin1cnu2", "fields": {"session_data": "e30:1rmGpp:gkKxdjRNTL41shLPFHXlJ9NuhK6cg1TbJk47jn7gFsM", "expire_date": "2024-04-01T17:31:41.102Z"}}, {"model": "sessions.session", "pk": "70whw8s2wprqdrckrm6icn22lstbgzba", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmRNa:7UcwwnGGi3s7zd9JBpxCIaPzaXYDUPzp36YqFcRtKjI", "expire_date": "2024-04-02T04:47:14.489Z"}}, {"model": "sessions.session", "pk": "7zsl1wu9qp34ijf9p158pdjc63byi4ap", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmICs:lJBLidVW-eY-FJQgInmjI8jREFBku-1h4UoD_w9j8Ko", "expire_date": "2024-04-01T18:59:34.138Z"}}, {"model": "sessions.session", "pk": "9y7l84csvm09yn79js49cbodluk8tejv", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmI6c:FrRBSo2ZBulK03wIQCQ2M0lBOBUtHvOc_4NsjhB549M", "expire_date": "2024-04-01T18:53:06.420Z"}}, {"model": "sessions.session", "pk": "bluy0olsqj65bubjk8hs4iquxe8zq6uv", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJif:dOmoA7JJ2si0PscFo1Xi6XiwsBlipncrL4a73Y4YtUs", "expire_date": "2024-04-01T20:36:29.682Z"}}, {"model": "sessions.session", "pk": "cyl20f8vpeprr9op685t4hfcnuvdml39", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHwe:NkObck8Ufdp1Z4iyLpNlSL1nxlGaDDOo00ZUiIfozBE", "expire_date": "2024-04-01T18:42:48.900Z"}}, {"model": "sessions.session", "pk": "djn99zjzt7tfgx6opmuzy6f2ar79lidz", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHwU:xleXk9zi8J9VhpRv5tBBpBrgtbdhloDp7FS7PVOkBKw", "expire_date": "2024-04-01T18:42:38.224Z"}}, {"model": "sessions.session", "pk": "eff46udk4lmizr11zi1o5qhzveyjaigx", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHTT:tf6C6k7Xp24HSUTXTkupPmCW3ijGl_4RwzkgxfoWia0", "expire_date": "2024-04-01T18:12:39.632Z"}}, {"model": "sessions.session", "pk": "em22ut8458zap356a1y7bdqd15s5qjkf", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJN2:6x31lIDvU40Y-X_7nQ2mI_2atOrd4d2oJYfX-qP38Go", "expire_date": "2024-04-01T20:14:08.079Z"}}, {"model": "sessions.session", "pk": "fahyct20xswep3kbkzo1i76xdargeq7t", "fields": {"session_data": "e30:1rmSKD:Q_VWuhZPbK5Sy5GyD4ZbZ0JXSJ8tJiq61TYwewESNc0", "expire_date": "2024-04-02T05:47:49.163Z"}}, {"model": "sessions.session", "pk": "ffpglxxj7x3c32c1dujbc8ensa6ohwx6", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKf5:5yqAu6gSl5PzIEaGouI1BK7Elt6jsoq9R1bfaJLJBns", "expire_date": "2024-04-01T21:36:51.485Z"}}, {"model": "sessions.session", "pk": "g5gkz2e9xe9oan8p2tanbhup6lk10s1f", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJ0y:CWZRV8OvA4hkTHQPpdIFXmrjW1Pz1LR-BMWEyVteARg", "expire_date": "2024-04-01T19:51:20.325Z"}}, {"model": "sessions.session", "pk": "gous0i7ru683v3nbo7uzy5136020jul6", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKHM:8XD94fhHFzPgtwrc1NLL-YbyHtEgtjM2GKJ6Y9rdkvo", "expire_date": "2024-04-01T21:12:20.579Z"}}, {"model": "sessions.session", "pk": "gpn8dgeg1q069akdpgh12bk7dz6q7mdj", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJOm:fA1eGYvqeUASmijVsW-ZIM0NrITjw5iyunYWEfm1yBk", "expire_date": "2024-04-01T20:15:56.709Z"}}, {"model": "sessions.session", "pk": "js15kvywxqb3e4lvl01f4rfd5dc5lu7a", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHTu:sSPEKAmCWBMSeSgSQwEmP4ni-lmjTgUqxTq94vf08Wc", "expire_date": "2024-04-01T18:13:06.033Z"}}, {"model": "sessions.session", "pk": "kzyqaapftcq31kqsynl6nwo8l59cwbjd", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHlu:E7Joe9ZMenwc1STYWmZNPWRN8fnmXPFtrSCja0iPaQE", "expire_date": "2024-04-01T18:31:42.325Z"}}, {"model": "sessions.session", "pk": "m7eh8pibhsc620yrmxe00k2keohtyssl", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxU:dfbUfYIsBT1HKvW9nuqx2oVCMPWqPejODqgYC8uXKHQ", "expire_date": "2024-04-01T18:43:40.931Z"}}, {"model": "sessions.session", "pk": "n03gba8gu6nykf115q1ihtqzg3k1e59j", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHFO:WV7nz9Rge6tucvLZ2yejQy2do5j1c4K4054WjT7Oge0", "expire_date": "2024-04-01T17:58:06.577Z"}}, {"model": "sessions.session", "pk": "ns6cqm4npaj25w3ayw55ogkwfsuwghhm", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHxa:Tjdsf9X-03fJJJ51h43n9ON5MedoQD1BgZLjoJ0CAEg", "expire_date": "2024-04-01T18:43:46.518Z"}}, {"model": "sessions.session", "pk": "o1qn16dk7am5vngsfxis11sj4q7462qt", "fields": {"session_data": "e30:1rmS7B:lDtc2fHo25QRXljHU-uyd6apCEG2udkGexVq1NhyD9k", "expire_date": "2024-04-02T05:34:21.281Z"}}, {"model": "sessions.session", "pk": "o56rln4oqfa9514pm6cdxvynxqwc6y1y", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJMw:FQL2NefdSnKMqM7ix4qIgnIlU3BhvijY5oCcL4i76jw", "expire_date": "2024-04-01T20:14:02.460Z"}}, {"model": "sessions.session", "pk": "oiuvwczrjipstwx3hfd1hk0itlgcrc9g", "fields": {"session_data": "e30:1rmS70:kVaTpSy-XqOqwqcgEpOZTg2ylxTkW64I7R-r9Gg_pUU", "expire_date": "2024-04-02T05:34:10.436Z"}}, {"model": "sessions.session", "pk": "op8ju3j3vlmos7mgc2lwtcq3wjfa2aq0", "fields": {"session_data": ".eJxVjEsOwiAUAO_C2hC-BVy67xnIe_AqVQNJaVfGuxuSLnQ7M5k3i3DsJR6dtrhmdmWGXX4ZQnpSHSI_oN4bT63u24p8JPy0nc8t0-t2tn-DAr2M7YLK6yR98lZQtoRJAbjFKx2coyAk2QSA5KU2E9ocVJDCYMgYpLcT-3wB8l833w:1rmI9T:SHKsXwZg7STJkrmISBNKddLjtmfXPUAB688SZQGyBmU", "expire_date": "2024-04-01T18:56:03.076Z"}}, {"model": "sessions.session", "pk": "pc9b382q9jenzz0o1vvrnoq6zcu0lese", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmRYd:DvrmvBJZk-0bjA5QtZzh1ZZO0veLFDQpPaqy1r1ubKA", "expire_date": "2024-04-02T04:58:39.264Z"}}, {"model": "sessions.session", "pk": "q5xhv1a9t0wzn8j265vd5p0bg6lbuk52", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHDl:9oei0N1CYbGnCa5ao8xU9gVyVBrIHhmzDvXgvIavu58", "expire_date": "2024-04-01T17:56:25.082Z"}}, {"model": "sessions.session", "pk": "qh5jjeb6uvvpo2uvu1ygs3apffk0xont", "fields": {"session_data": ".eJxVjEsOwiAUAO_C2hC-BVy67xnIe_AqVQNJaVfGuxuSLnQ7M5k3i3DsJR6dtrhmdmWGXX4ZQnpSHSI_oN4bT63u24p8JPy0nc8t0-t2tn-DAr2M7YLK6yR98lZQtoRJAbjFKx2coyAk2QSA5KU2E9ocVJDCYMgYpLcT-3wB8l833w:1rmI9M:YuAGHnkH_da9gEm9iATI_o2X-qj1z6dVa6B92XjGOQo", "expire_date": "2024-04-01T18:55:56.900Z"}}, {"model": "sessions.session", "pk": "r8blbjmv9ztpuxl0eetwfkiaxx3pjmd4", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJUT:u3a5UPsXXcr-Tjb3S7e2OGM7ijyKsIEL1iL2VEnCzZQ", "expire_date": "2024-04-01T20:21:49.722Z"}}, {"model": "sessions.session", "pk": "rcpipm5e3ti6fpt6pbca8wfzkjpctg6e", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmKhV:kBtdpAecgCvYgfp28btW6e517fzQMQ6bUB6TqIAX-nY", "expire_date": "2024-04-01T21:39:21.902Z"}}, {"model": "sessions.session", "pk": "tkwnol43aorodcaeouhb3yui29z0gp00", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmQtp:W8vPU_OXwBQz5-IqCvK2goOOPX05Tvv5qG35Y02wMa4", "expire_date": "2024-04-02T04:16:29.095Z"}}, {"model": "sessions.session", "pk": "u8j0fv9u88g4e3cwrftmzso554w6nwt3", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmS7Z:uLlK3e7PovgkD0SGTUfeNyNHMRSKajIL0rmR4V-jRU0", "expire_date": "2024-04-02T05:34:45.359Z"}}, {"model": "sessions.session", "pk": "u9prph4jh4ptvd5rvwoscdlx9i2nf4wg", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHTo:SALCNCFNLKpGUWhLuSCnnOSgctzTejbbMASTdS4FJ1Q", "expire_date": "2024-04-01T18:13:00.209Z"}}, {"model": "sessions.session", "pk": "ulc8j51meav9672gb2ntl4sx2kh2xlll", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmR3c:mjgATakdBRuZngeUSxCaRJuVrQfvfd3e7iNWz0qcMhY", "expire_date": "2024-04-02T04:26:36.099Z"}}, {"model": "sessions.session", "pk": "ver4tb4f9ioa56xaolw5n9rjvn7bemi9", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmSms:3i4qPzE-TwrbwNPlY6-xMkma5kaEo-7XaQLeEe3_EAo", "expire_date": "2024-04-02T06:17:26.143Z"}}, {"model": "sessions.session", "pk": "wky4pklf9hxnmwnu9qrgxgks73pk44xd", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmGtB:iT2iYsJDrXvWkQU5aTtk3cME2aM5b5rBR0L6Gxqy8hc", "expire_date": "2024-04-01T17:35:09.523Z"}}, {"model": "sessions.session", "pk": "wuhh2s4bb8tu7u6xy7z8ltrk8iqvjw0l", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmGvh:N5RGCblZMROGzB0QdEPtYSXykklMQAEF0Ll3TRJeePA", "expire_date": "2024-04-01T17:37:45.076Z"}}, {"model": "sessions.session", "pk": "xilyfd4yg8ysk19yah2wk3n4g1ab9u9r", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmHAn:PyF29fTq4vtxvRbdWW-vhFaSeIC85BGuRS1yrqx-GYQ", "expire_date": "2024-04-01T17:53:21.938Z"}}, {"model": "sessions.session", "pk": "yc7qdica8thagwd93zzirt2qldk1k049", "fields": {"session_data": ".eJxVjDkOwjAQAP_iGlm-D0r6vMHa9YEDyJbipEL8HVlKAe3MaN4kwLHXcIy8hTWRK5Hk8ssQ4jO3KdID2r3T2Nu-rUhnQk876NJTft3O9m9QYdS51d4AA-0lcsc0587ZnIpVTlpuCxcWY5RFZGEUKESv0BYpBTPIYhaKfL65uDcN:1rmHx4:eQXAGZQL-Gp-krJXlzVz1XoW5Z3iqVBA1flE6LH_ySo", "expire_date": "2024-04-01T18:43:14.254Z"}}, {"model": "sessions.session", "pk": "yk3ofc7pt03hisg314xeqiw635b75nc7", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmJJG:AGRzWn9TxAze7foD-DPqXnjnSKR2HocT4RigNug8fkY", "expire_date": "2024-04-01T20:10:14.774Z"}}, {"model": "sessions.session", "pk": "ytuh5jfbam8e1kn5e5l41icoo15l78zr", "fields": {"session_data": ".eJxVjEEOwiAQRe_C2pChUDq4dO8ZCDCDVA0kpV0Z765NutDtf-_9l_BhW4vfOi9-JnEWSpx-txjSg-sO6B7qrcnU6rrMUe6KPGiX10b8vBzu30EJvXxrnXPKBIrMpJViIjTj6NAicKIJIBgABHQ0op0yR2sjmoFV1CoTu0G8P-DfN64:1rmI0A:gGzjvvhvU8DoAZ6GAB7QN2N9jYm_2s2nIvmmgpzczo8", "expire_date": "2024-04-01T18:46:26.804Z"}}, {"model": "sessions.session", "pk": "z5ws47x4rj7aev8djgtoi4u6det5i9te", "fields": {"session_data": ".eJxVijsOwjAMQO-SmcFufg4jHCRKYltBCJBIMyHuDkgdyvg-L5PLXHueQ575wuZo0Bz2rpZ2lfsvnOdYH7fTxn9TL6N_D6valAHZRYsozOS8TxQIpHEEKA6AgBJ7ClGlhlDJLYLVorKkxbw_h3QtLw:1rmS5C:2VOYW9hiOuIS2Ls_VTnZ2acqGw6z9tpuQXwgcDROfZY", "expire_date": "2024-04-02T05:32:18.484Z"}}, {"model": "accounts.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$720000$3xBZIPeMQloi18hZVD5Cyz$d9sMhoJr7nFBfsFFr2X/uEj1gEn03JQNFe+3SBfL7TM=", "last_login": "2024-03-19T06:17:26.111Z", "firstname": "Amirali", "lastname": "Hamid", "email": "hagixi9797@dovesilo.com", "date_of_birth": "2024-03-14", "gender": "F", "is_active": true, "is_admin": false, "phone_number": null, "is_email_verified": true, "verification_code": null, "verification_tries_count": 1, "last_verification_sent": "2024-03-18T20:55:38.047Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 2, "fields": {"password": "pbkdf2_sha256$720000$94IHJQPRqqEmfxUHzVFDxY$OJu6HHr1vF5bQOGiq8I/jbCDxdYx2xaL2xcieKLjqS4=", "last_login": null, "firstname": "sara", "lastname": "saraee", "email": "hayohin504@azduan.com", "date_of_birth": "2024-03-05", "gender": "F", "is_active": true, "is_admin": false, "phone_number": null, "is_email_verified": false, "verification_code": "8095", "verification_tries_count": 1, "last_verification_sent": "2024-03-18T21:58:45.828Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 3, "fields": {"password": "pbkdf2_sha256$720000$A5jYNIa8CcqGHr2Cuj6Bvl$MpxEJoZ08tD5AfKFIPqmF3kd6TRBQ7PuX40Kjwv6d70=", "last_login": "2024-03-18T18:53:09.537Z", "firstname": "asma", "lastname": "hamid", "email": "asmahamid1382@gmail.com", "date_of_birth": "1382-03-27", "gender": "F", "is_active": true, "is_admin": true, "phone_number": null, "is_email_verified": false, "verification_code": null, "verification_tries_count": 0, "last_verification_sent": "2024-03-18T22:11:13.827Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 4, "fields": {"password": "pbkdf2_sha256$720000$5q8eAOIlk7iTnf0S8ONR4S$QLCRJJiP0L+SO0Vykw/zQ2MAyAJWbE23cTWWQMEkpZc=", "last_login": "2024-03-18T18:56:03.072Z", "firstname": "amir", "lastname": "amiri", "email": "asma_hamid@comp.iust.ac.ir", "date_of_birth": "1382-05-26", "gender": "M", "is_active": true, "is_admin": true, "phone_number": null, "is_email_verified": false, "verification_code": null, "verification_tries_count": 0, "last_verification_sent": "2024-03-18T22:23:54.904Z", "has_verification_tries_reset": false}}, {"model": "accounts.user", "pk": 5, "fields": {"password": "pbkdf2_sha256$720000$tIVqgZDGjxMtlXveRncdjp$V9J7SPmz7eVv/tv6y5XS0A5IWPFk/rOPuXzO9KGgsKA=", "last_login": null, "firstname": "sian", "lastname": "sinaee", "email": "mibag84210@dovesilo.com", "date_of_birth": "2024-03-13", "gender": "M", "is_active": true, "is_admin": false, "phone_number": null, "is_email_verified": false, "verification_code": "2293", "verification_tries_count": 1, "last_verification_sent": "2024-03-18T23:16:39.742Z", "has_verification_tries_reset": false}}] \ No newline at end of file +[ \ No newline at end of file From e2a083a32b33c9bdee047445a19b4c1e9a3e32b9 Mon Sep 17 00:00:00 2001 From: Asma Hamid Date: Wed, 3 Apr 2024 14:28:18 +0330 Subject: [PATCH 24/46] feat/HomePage/statistics --- BackEnd/BackEnd/urls.py | 1 + BackEnd/HomePage/__init__.py | 0 BackEnd/HomePage/admin.py | 3 ++ BackEnd/HomePage/apps.py | 6 ++++ BackEnd/HomePage/migrations/__init__.py | 0 BackEnd/HomePage/models.py | 3 ++ BackEnd/HomePage/serializers.py | 10 ++++++ BackEnd/HomePage/tests.py | 3 ++ BackEnd/HomePage/urls.py | 11 +++++++ BackEnd/HomePage/views.py | 33 +++++++++++++++++++ .../0004_alter_user_last_verification_sent.py | 19 +++++++++++ .../0005_alter_user_last_verification_sent.py | 19 +++++++++++ .../0006_alter_user_last_verification_sent.py | 19 +++++++++++ .../0007_alter_user_last_verification_sent.py | 19 +++++++++++ ..._last_verification_sent_alter_user_role.py | 24 ++++++++++++++ BackEnd/accounts/models.py | 8 +++-- BackEnd/counseling/models.py | 10 ++++-- 17 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 BackEnd/HomePage/__init__.py create mode 100644 BackEnd/HomePage/admin.py create mode 100644 BackEnd/HomePage/apps.py create mode 100644 BackEnd/HomePage/migrations/__init__.py create mode 100644 BackEnd/HomePage/models.py create mode 100644 BackEnd/HomePage/serializers.py create mode 100644 BackEnd/HomePage/tests.py create mode 100644 BackEnd/HomePage/urls.py create mode 100644 BackEnd/HomePage/views.py create mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index 1367aa0..61973ab 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -39,6 +39,7 @@ urlpatterns = [ path("admin/", admin.site.urls), path("accounts/" , include("accounts.urls")), + path("HomePage/" , include("HomePage.urls")), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('profile/' , include("Profile.urls")) , path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), diff --git a/BackEnd/HomePage/__init__.py b/BackEnd/HomePage/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/HomePage/admin.py b/BackEnd/HomePage/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/BackEnd/HomePage/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/BackEnd/HomePage/apps.py b/BackEnd/HomePage/apps.py new file mode 100644 index 0000000..c87dea3 --- /dev/null +++ b/BackEnd/HomePage/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class HomepageConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'HomePage' diff --git a/BackEnd/HomePage/migrations/__init__.py b/BackEnd/HomePage/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/HomePage/models.py b/BackEnd/HomePage/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/BackEnd/HomePage/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/BackEnd/HomePage/serializers.py b/BackEnd/HomePage/serializers.py new file mode 100644 index 0000000..6347d11 --- /dev/null +++ b/BackEnd/HomePage/serializers.py @@ -0,0 +1,10 @@ + +from rest_framework import serializers + +class DoctorCountSerializer(serializers.Serializer): + doctor_count = serializers.IntegerField() + +class PationtCountSerializer(serializers.Serializer): + Pationt_count = serializers.IntegerField() + + diff --git a/BackEnd/HomePage/tests.py b/BackEnd/HomePage/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BackEnd/HomePage/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BackEnd/HomePage/urls.py b/BackEnd/HomePage/urls.py new file mode 100644 index 0000000..330db91 --- /dev/null +++ b/BackEnd/HomePage/urls.py @@ -0,0 +1,11 @@ +from .views import * +from django.urls import path + + +urlpatterns = [ + # path('PationtCount/' , PationtCountView.as_view() , name='PationtCount' ) , + # path('DoctorCount/' , DoctorCountView.as_view() , name='DoctorCount' ) , + path('count/',CountView.as_view(),name='count'), + + +] \ No newline at end of file diff --git a/BackEnd/HomePage/views.py b/BackEnd/HomePage/views.py new file mode 100644 index 0000000..d2dddff --- /dev/null +++ b/BackEnd/HomePage/views.py @@ -0,0 +1,33 @@ + +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status +from counseling.models import Psychiatrist,Pationt +from .serializers import DoctorCountSerializer, PationtCountSerializer + +# class DoctorCountView(APIView): +# def get(self, request): +# doctor_count = Psychiatrist.objects.count() +# serializer = DoctorCountSerializer({'doctor_count': doctor_count}) +# return Response(serializer.data, status=status.HTTP_200_OK) + +# class PationtCountView(APIView): +# def get(self, request): +# Pationt_count = Pationt.objects.count() +# serializer = PationtCountSerializer({'Pationt_count': Pationt_count}) +# return Response(serializer.data, status=status.HTTP_200_OK) + + +class CountView(APIView): + def get(self, request): + doctor_count = Psychiatrist.objects.count() + Pationt_count = Pationt.objects.count() + + doctor_serializer = DoctorCountSerializer({'doctor_count': doctor_count}) + Pationt_serializer = PationtCountSerializer({'Pationt_count': Pationt_count}) + + data = { + 'doctor_data': doctor_serializer.data, + 'Pationt_data': Pationt_serializer.data + } + return Response(data, status=status.HTTP_200_OK) \ No newline at end of file diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py new file mode 100644 index 0000000..84864c5 --- /dev/null +++ b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.3 on 2024-04-03 08:12 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0003_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 11, 42, 3, 330257), null=True), + ), + ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py new file mode 100644 index 0000000..a960b27 --- /dev/null +++ b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.3 on 2024-04-03 08:23 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0004_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 11, 53, 7, 161534), null=True), + ), + ] diff --git a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py new file mode 100644 index 0000000..19070ac --- /dev/null +++ b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.3 on 2024-04-03 08:40 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0005_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 12, 10, 10, 971551), null=True), + ), + ] diff --git a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py new file mode 100644 index 0000000..8dc57be --- /dev/null +++ b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.3 on 2024-04-03 08:41 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0006_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 12, 11, 35, 122061), null=True), + ), + ] diff --git a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py new file mode 100644 index 0000000..42392be --- /dev/null +++ b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py @@ -0,0 +1,24 @@ +# Generated by Django 5.0.3 on 2024-04-03 10:00 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0007_alter_user_last_verification_sent'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='last_verification_sent', + field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 13, 30, 36, 686277), null=True), + ), + migrations.AlterField( + model_name='user', + name='role', + field=models.CharField(choices=[('user', 'User'), ('doctor', 'Doctor'), ('admin', 'Admin')], default='user', max_length=255, unique=True), + ), + ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index 61e6f36..1291b10 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -114,7 +114,7 @@ class User(AbstractBaseUser): blank=True, null=True ) - role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) + role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER,unique=True) # email varification is_email_verified = models.BooleanField(default=False) @@ -151,4 +151,8 @@ def is_staff(self): # if self.gender == 'M': # return 'images/profile_pics/male_default.png' # else: - # return 'images/profile_pics/female_default.png' \ No newline at end of file + # return 'images/profile_pics/female_default.png' + +# class Role(models.Model): +# user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='role') +# role = models.CharField(max_length=255, choices=User.CHOICES, default=User.TYPE_USER) \ No newline at end of file diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 8638bf0..17866ce 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -5,6 +5,7 @@ from django.contrib.contenttypes.fields import GenericRelation from django.core.exceptions import ValidationError + class Psychiatrist(models.Model ) : TYPE_INDIVIDUAL = 'individual' TYPE_KIDS = "kids" @@ -47,16 +48,18 @@ def save(self, *args, **kwargs): """ Check if there's already a Psychiatrist object associated with this User """ - # print( "hereeeeeeeeeeeeeeeeeeeeeeeeeeee") if Psychiatrist.objects.filter(user=self.user).exists(): raise ValidationError("A Psychiatrist object already exists for this User.") + if Pationt.objects.filter(user=self.user).exists(): + pationt = Pationt.objects.get(user=self.user) + pationt.delete() if not self.user.role == 'doctor': self.user.role = User.TYPE_DOCTOR self.user.save() super().save(*args, **kwargs) -# TODO add fields for pationt + class Pationt( models.Model ) : user = models.ForeignKey(User, on_delete=models.CASCADE) @@ -67,3 +70,6 @@ def save(self, *args, **kwargs): if Pationt.objects.filter(user=self.user).exists(): raise ValidationError("A Pationt object already exists for this User.") super().save(*args, **kwargs) + + + From cf45cf9d2a8d0afd653879fb62cabab4dda37811 Mon Sep 17 00:00:00 2001 From: Asma Hamid Date: Wed, 3 Apr 2024 16:37:06 +0330 Subject: [PATCH 25/46] feat/changepassword --- BackEnd/accounts/serializers.py | 19 +++++++++++++++++++ BackEnd/accounts/urls.py | 2 ++ BackEnd/accounts/views.py | 25 ++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index 0fe4c5a..f716336 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -2,6 +2,8 @@ from accounts.models import User from django.contrib.auth.password_validation import validate_password from django.contrib.auth import password_validation +from django.core import exceptions as exception + class UserSerializer(serializers.ModelSerializer): @@ -93,6 +95,23 @@ def validate(self, attrs): class ForgotPasswordSerializer(serializers.Serializer): email = serializers.EmailField() +class ChangePasswordSerializer(serializers.Serializer): + old_password = serializers.CharField(required=True, write_only=True) + new_password = serializers.CharField(required=True, write_only=True) + new_password1 = serializers.CharField(required=True, write_only=True) + + def validate(self, attrs): + if attrs['new_password'] != attrs['new_password1']: + raise serializers.ValidationError({ + 'new_password1': ['Passwords must match.'], + }) + try: + validate_password(attrs['new_password']) + except exception.ValidationError as e: + raise serializers.ValidationError({ + 'new_password': list(e.messages) + }) + return attrs class ResetPasswordSerializer(serializers.Serializer): new_password = serializers.CharField(write_only=True, required=True) diff --git a/BackEnd/accounts/urls.py b/BackEnd/accounts/urls.py index f557f19..8f217bc 100644 --- a/BackEnd/accounts/urls.py +++ b/BackEnd/accounts/urls.py @@ -11,4 +11,6 @@ path('complete_info/' , CompleteInfoView.as_view() , name= 'complete_info') , path('Login/',LoginView.as_view(),name='Login'), path('Logout/',LogoutView.as_view(),name='Logout'), + path('change_password/' , ChangePasswordView.as_view() , name='change_password'), + ] \ No newline at end of file diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 587f78e..054e5a3 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -7,7 +7,7 @@ from rest_framework.views import APIView from rest_framework.generics import CreateAPIView , GenericAPIView from .serializers import SignUpSerializer , UserSerializer , ActivationConfirmSerializer ,ActivationResendSerializer \ - ,ForgotPasswordSerializer , ResetPasswordSerializer , LoginSerializer , CompleteInfoSerializer + ,ForgotPasswordSerializer , ResetPasswordSerializer , LoginSerializer , CompleteInfoSerializer ,ChangePasswordSerializer from .models import User from datetime import datetime from django.contrib.sites.shortcuts import get_current_site @@ -145,6 +145,29 @@ def post(self, request, *args, **kwargs): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) +class ChangePasswordView(GenericAPIView): + serializer_class = ChangePasswordSerializer + permission_classes = [IsAuthenticated] + + def post(self, request): + serializer = self.serializer_class(data=request.data, context={'request': request}) + if serializer.is_valid(): + user = request.user + old_password = serializer.validated_data['old_password'] + new_password = serializer.validated_data['new_password'] + + # Check if the current password matches the user's actual password + if not user.check_password(old_password): + return Response({'error': 'Invalid current password.'}, status=status.HTTP_400_BAD_REQUEST) + + # Change the user's password + user.set_password(new_password) + user.save() + + return Response({'message': 'Password changed successfully.'}, status=status.HTTP_200_OK) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + class ForgotPassword(GenericAPIView) : serializer_class = ForgotPasswordSerializer From 9019c2a3ce5c1d9f776401e71e371cbca1333a67 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Thu, 4 Apr 2024 03:40:33 +0330 Subject: [PATCH 26/46] fix/resendVerification --- BackEnd/accounts/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 054e5a3..16531c1 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -140,6 +140,7 @@ def post(self, request, *args, **kwargs): return Response({ "message": "email sent", "url": f'{settings.WEBSITE_URL}accounts/activation_confirm/{token}/', + "code" : verification_code }, status=status.HTTP_200_OK) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @@ -153,6 +154,7 @@ def post(self, request): serializer = self.serializer_class(data=request.data, context={'request': request}) if serializer.is_valid(): user = request.user + print(user.email ) old_password = serializer.validated_data['old_password'] new_password = serializer.validated_data['new_password'] From 69aee5085f25040324c7ae5a9d4fb4208adb0e39 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Sun, 7 Apr 2024 01:57:57 +0330 Subject: [PATCH 27/46] feat/user_retrieve --- BackEnd/BackEnd/settings.py | 1 + BackEnd/accounts/serializers.py | 3 +-- BackEnd/accounts/urls.py | 2 +- BackEnd/accounts/views.py | 38 ++++++++++++++++----------------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index c0b4ced..b93eb6e 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -175,6 +175,7 @@ } } + # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators diff --git a/BackEnd/accounts/serializers.py b/BackEnd/accounts/serializers.py index f716336..24b700b 100644 --- a/BackEnd/accounts/serializers.py +++ b/BackEnd/accounts/serializers.py @@ -9,7 +9,7 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "id" , "phone_number" , "role" ] #, "phone_number"] + fields = ["date_of_birth", "email" ,"gender","firstname" ,"lastname" , "phone_number" , "id" ] #, "phone_number"] , "role" def validate(self, attrs): return super().validate(attrs) @@ -26,7 +26,6 @@ def validate(self, attrs): - class SignUpSerializer(serializers.ModelSerializer): password2 = serializers.CharField(style={"input_type": "password"}, write_only=True) password1 = serializers.CharField( diff --git a/BackEnd/accounts/urls.py b/BackEnd/accounts/urls.py index 8f217bc..e96971f 100644 --- a/BackEnd/accounts/urls.py +++ b/BackEnd/accounts/urls.py @@ -12,5 +12,5 @@ path('Login/',LoginView.as_view(),name='Login'), path('Logout/',LogoutView.as_view(),name='Logout'), path('change_password/' , ChangePasswordView.as_view() , name='change_password'), - + path('get_user/' , RetrieveUserData.as_view() , name='get_user') ] \ No newline at end of file diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 16531c1..2c6ec30 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -257,7 +257,25 @@ def post(self, request, *args, **kwargs): 'user': UserSerializer(user).data }) return Response( {"message" : "there is no user with this email"} , status=status.HTTP_400_BAD_REQUEST) + + +class RetrieveUserData(GenericAPIView) : + permission_classes = [IsAuthenticated] + def get(self , request ) : + print( request.headers["Authorization"] ) + if not hasattr(request, 'user'): + return Response({'message': 'request does not have proper authentication tokens'}, status=status.HTTP_400_BAD_REQUEST) + email = str.lower(request.user.email) + user = User.objects.filter( email__iexact = email ) + if not user.exists() : + return Response({'message': 'Invalid user'}, status=status.HTTP_400_BAD_REQUEST) + user = user.first() + data = { + "user" : UserSerializer(user).data + } + return Response( data= data , status=status.HTTP_200_OK) + class CompleteInfoView(GenericAPIView) : permission_classes = [IsAuthenticated] @@ -280,6 +298,7 @@ def post( self , request ) : return Response(data={'message' : 'successfully updated'}, status=status.HTTP_200_OK) + class LogoutView(APIView): permission_classes = [IsAuthenticated] def get(self, request): @@ -302,22 +321,3 @@ def get(self, request): return Response(data={'detail': 'Not logged in'}, status=status.HTTP_400_BAD_REQUEST) - - - - - - -# if user signup before and not verified - # if user.exists() : - # user = user.first() - # user.gender = validated_data['gender'] - # user.firstname = validated_data['firstname'] - # user.lastname = validated_data['lastname'] - # user.date_of_birth = validated_data['date_of_birth'] - # user.phone_number = validated_data['phone_number'] - # user.verification_code = verification_code - # user.verification_tries_count += 1 - # user.last_verification_sent = datetime.now() - # user.save() - # else : \ No newline at end of file From 1d6fa814ab207e493bed9ffe1d25193d322daced Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 8 Apr 2024 12:33:37 +0330 Subject: [PATCH 28/46] feat/reserve --- BackEnd/BackEnd/settings.py | 1 + BackEnd/BackEnd/urls.py | 1 + BackEnd/Profile/migrations/0001_initial.py | 2 +- BackEnd/Profile/signals.py | 2 + BackEnd/accounts/migrations/0001_initial.py | 5 +- .../0002_alter_user_last_verification_sent.py | 4 +- .../0003_alter_user_last_verification_sent.py | 23 --- .../0004_alter_user_last_verification_sent.py | 19 --- .../0005_alter_user_last_verification_sent.py | 19 --- .../0006_alter_user_last_verification_sent.py | 19 --- .../0007_alter_user_last_verification_sent.py | 19 --- ..._last_verification_sent_alter_user_role.py | 24 --- BackEnd/counseling/migrations/0001_initial.py | 2 +- BackEnd/counseling/models.py | 5 +- BackEnd/reservation/__init__.py | 0 BackEnd/reservation/admin.py | 4 + BackEnd/reservation/apps.py | 6 + .../reservation/migrations/0001_initial.py | 68 +++++++++ BackEnd/reservation/migrations/__init__.py | 0 BackEnd/reservation/models.py | 33 ++++ BackEnd/reservation/serializer.py | 20 +++ BackEnd/reservation/tests.py | 3 + BackEnd/reservation/urls.py | 7 + BackEnd/reservation/views.py | 142 ++++++++++++++++++ 24 files changed, 298 insertions(+), 130 deletions(-) delete mode 100644 BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py create mode 100644 BackEnd/reservation/__init__.py create mode 100644 BackEnd/reservation/admin.py create mode 100644 BackEnd/reservation/apps.py create mode 100644 BackEnd/reservation/migrations/0001_initial.py create mode 100644 BackEnd/reservation/migrations/__init__.py create mode 100644 BackEnd/reservation/models.py create mode 100644 BackEnd/reservation/serializer.py create mode 100644 BackEnd/reservation/tests.py create mode 100644 BackEnd/reservation/urls.py create mode 100644 BackEnd/reservation/views.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index b93eb6e..5f4a009 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -109,6 +109,7 @@ "Profile", "drf_yasg", "counseling", + "reservation", ] MIDDLEWARE = [ diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index 61973ab..8673cf0 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -40,6 +40,7 @@ path("admin/", admin.site.urls), path("accounts/" , include("accounts.urls")), path("HomePage/" , include("HomePage.urls")), + path("reserve/" ,include("reservation.urls") ) , path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('profile/' , include("Profile.urls")) , path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), diff --git a/BackEnd/Profile/migrations/0001_initial.py b/BackEnd/Profile/migrations/0001_initial.py index 6011a34..621f713 100644 --- a/BackEnd/Profile/migrations/0001_initial.py +++ b/BackEnd/Profile/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:45 +# Generated by Django 5.0.3 on 2024-04-08 07:27 import django.db.models.deletion from django.db import migrations, models diff --git a/BackEnd/Profile/signals.py b/BackEnd/Profile/signals.py index fc1cf4e..81daea2 100644 --- a/BackEnd/Profile/signals.py +++ b/BackEnd/Profile/signals.py @@ -14,6 +14,8 @@ def create_profile(sender, instance, created, **kwargs): @receiver(post_save, sender=Psychiatrist) def save_profile(sender, instance, **kwargs): + if not instance.profile : + Profile.objects.create(psychiatrist=instance) instance.profile.save() diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index cd46441..a3a6899 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:45 +# Generated by Django 5.0.3 on 2024-04-08 07:27 import datetime import django.core.validators @@ -69,6 +69,7 @@ class Migration(migrations.Migration): ], default="user", max_length=255, + unique=True, ), ), ("is_email_verified", models.BooleanField(default=False)), @@ -81,7 +82,7 @@ class Migration(migrations.Migration): "last_verification_sent", models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 3, 1, 15, 12, 435402), + default=datetime.datetime(2024, 4, 8, 10, 57, 32, 809243), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py index b70a65b..db31cb6 100644 --- a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py +++ b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:45 +# Generated by Django 5.0.3 on 2024-04-08 07:28 import datetime from django.db import migrations, models @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 3, 1, 15, 34, 442056), + default=datetime.datetime(2024, 4, 8, 10, 58, 5, 142932), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py deleted file mode 100644 index b513fa9..0000000 --- a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:46 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0002_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 4, 3, 1, 16, 13, 569335), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py deleted file mode 100644 index 84864c5..0000000 --- a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:12 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0003_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 11, 42, 3, 330257), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py deleted file mode 100644 index a960b27..0000000 --- a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:23 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0004_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 11, 53, 7, 161534), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py deleted file mode 100644 index 19070ac..0000000 --- a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:40 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0005_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 12, 10, 10, 971551), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py deleted file mode 100644 index 8dc57be..0000000 --- a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:41 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0006_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 12, 11, 35, 122061), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py deleted file mode 100644 index 42392be..0000000 --- a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 10:00 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0007_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 13, 30, 36, 686277), null=True), - ), - migrations.AlterField( - model_name='user', - name='role', - field=models.CharField(choices=[('user', 'User'), ('doctor', 'Doctor'), ('admin', 'Admin')], default='user', max_length=255, unique=True), - ), - ] diff --git a/BackEnd/counseling/migrations/0001_initial.py b/BackEnd/counseling/migrations/0001_initial.py index d5c03f2..f8a323a 100644 --- a/BackEnd/counseling/migrations/0001_initial.py +++ b/BackEnd/counseling/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:45 +# Generated by Django 5.0.3 on 2024-04-08 07:27 import django.db.models.deletion from django.conf import settings diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 17866ce..3d11938 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -48,9 +48,11 @@ def save(self, *args, **kwargs): """ Check if there's already a Psychiatrist object associated with this User """ + if self.user.role == 'doctor' : + return super().save(*args, **kwargs) if Psychiatrist.objects.filter(user=self.user).exists(): raise ValidationError("A Psychiatrist object already exists for this User.") - if Pationt.objects.filter(user=self.user).exists(): + if Pationt.objects.filter(user=self.user).exists() : pationt = Pationt.objects.get(user=self.user) pationt.delete() if not self.user.role == 'doctor': @@ -62,6 +64,7 @@ def save(self, *args, **kwargs): class Pationt( models.Model ) : user = models.ForeignKey(User, on_delete=models.CASCADE) + # psychiatrist = models.ManyToManyField(Psychiatrist , through="Reservation" ) def save(self, *args, **kwargs): """ diff --git a/BackEnd/reservation/__init__.py b/BackEnd/reservation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/reservation/admin.py b/BackEnd/reservation/admin.py new file mode 100644 index 0000000..22db211 --- /dev/null +++ b/BackEnd/reservation/admin.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from .models import Reservation +admin.site.register( Reservation) +# Register your models here. diff --git a/BackEnd/reservation/apps.py b/BackEnd/reservation/apps.py new file mode 100644 index 0000000..058a964 --- /dev/null +++ b/BackEnd/reservation/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ReservationConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "reservation" diff --git a/BackEnd/reservation/migrations/0001_initial.py b/BackEnd/reservation/migrations/0001_initial.py new file mode 100644 index 0000000..04c4117 --- /dev/null +++ b/BackEnd/reservation/migrations/0001_initial.py @@ -0,0 +1,68 @@ +# Generated by Django 5.0.3 on 2024-04-08 07:27 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("counseling", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="Reservation", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date", models.DateField()), + ("time", models.TimeField()), + ( + "type", + models.CharField(choices=[("حضوری", "حضوری"), ("مجازی", "مجازی")]), + ), + ( + "day", + models.CharField( + choices=[ + ("شنبه", "شنبه"), + ("یک\u200cشنبه", "یک\u200cشنبه"), + ("دو\u200cشنبه", "دو\u200cشنبه"), + ("سه\u200cشنبه", "سه\u200cشنبه"), + ("چهار\u200cشنبه", "چهار\u200cشنبه"), + ("پنج\u200cشنبه", "پنج\u200cشنبه"), + ("جمعه", "جمعه"), + ], + max_length=10, + ), + ), + ( + "pationt", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="pationt_reservations", + to="counseling.pationt", + ), + ), + ( + "psychiatrist", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="psychiatrist_reservations", + to="counseling.psychiatrist", + ), + ), + ], + options={"unique_together": {("date", "time")},}, + ), + ] diff --git a/BackEnd/reservation/migrations/__init__.py b/BackEnd/reservation/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/reservation/models.py b/BackEnd/reservation/models.py new file mode 100644 index 0000000..11b7276 --- /dev/null +++ b/BackEnd/reservation/models.py @@ -0,0 +1,33 @@ +from typing import Iterable +from django.db import models +from counseling.models import Psychiatrist , Pationt + + +class Reservation(models.Model) : + DAY_CHOICES = [ + ('شنبه', 'شنبه'), + ('یک‌شنبه', 'یک‌شنبه'), + ('دو‌شنبه', 'دو‌شنبه'), + ('سه‌شنبه', 'سه‌شنبه'), + ('چهار‌شنبه', 'چهار‌شنبه'), + ('پنج‌شنبه', 'پنج‌شنبه'), + ('جمعه', 'جمعه'), + ] + + RESERVE_CHOICES = [ + ('حضوری' , 'حضوری') , + ( 'مجازی' , 'مجازی') + ] + + psychiatrist = models.ForeignKey(Psychiatrist, on_delete=models.CASCADE, related_name='psychiatrist_reservations') + pationt = models.ForeignKey(Pationt, on_delete=models.CASCADE, related_name='pationt_reservations') + date = models.DateField() + time = models.TimeField() + type = models.CharField(choices=RESERVE_CHOICES) + day = models.CharField(max_length=10, choices=DAY_CHOICES) + + class Meta: + unique_together = ['date', 'time'] + + def save(self, *args, **kwargs) : + return super().save() \ No newline at end of file diff --git a/BackEnd/reservation/serializer.py b/BackEnd/reservation/serializer.py new file mode 100644 index 0000000..1424c2d --- /dev/null +++ b/BackEnd/reservation/serializer.py @@ -0,0 +1,20 @@ +from rest_framework import serializers +from accounts.models import User +from django.contrib.auth.password_validation import validate_password +from django.contrib.auth import password_validation +from django.core import exceptions as exception +from .models import Reservation +from datetime import date + +class ReserveSerializer(serializers.Serializer ) : + + class Meta : + model = Reservation + fields = ["day" , "type" , "date" , "time" , "id"] + + + def validate_date(self, attrs): + if date.today > attrs : + return serializers.ValidationError("date is not accessable") + return attrs + \ No newline at end of file diff --git a/BackEnd/reservation/tests.py b/BackEnd/reservation/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BackEnd/reservation/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BackEnd/reservation/urls.py b/BackEnd/reservation/urls.py new file mode 100644 index 0000000..3c7a53b --- /dev/null +++ b/BackEnd/reservation/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from .views import * + +urlpatterns = [ + path("create/" , ReservationView.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}) , name="create") , + path("delete//" , ReservationView.as_view({'delete': 'destroy'}) , name="delete") , +] \ No newline at end of file diff --git a/BackEnd/reservation/views.py b/BackEnd/reservation/views.py new file mode 100644 index 0000000..c8aed83 --- /dev/null +++ b/BackEnd/reservation/views.py @@ -0,0 +1,142 @@ +from django.shortcuts import render +from rest_framework import viewsets, serializers +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework import status +from counseling.models import Pationt , Psychiatrist +from .serializer import ReserveSerializer +from .models import Reservation + + + +class ReservationView(viewsets.ModelViewSet ) : + """ + A viewset for reservation that provides `create()`, `retrieve()`, `update()`, + `partial_update()`, `destroy()` and `list()` actions. + """ + permission_classes = [IsAuthenticated] + serializer_class = ReserveSerializer + + def create(self, request, *args, **kwargs): + serializer = self.serializer_class( data= request.data ) + serializer.is_valid(raise_exception=True) + + if not hasattr(request, 'user'): + return Response({'message': 'user is not loged in'}, status=status.HTTP_400_BAD_REQUEST) + + doctor = request.data.get('doctor_id') + Pationt = Pationt.objects.filter( user = request.user ) + reserve = Reservation.objects.create( + date = serializer.validated_data["date"] , + type = serializer.validated_data["type"] , + time = serializer.validated_data["time"] , + day = serializer.validated_data["day"] , + psychiatrist = doctor , + Pationt = Pationt + ) + + response = { + "reserve" : ReserveSerializer(reserve).data , + "message" : "reservation successfully created" + } + return Response( data=response , status=status.HTTP_201_CREATED) + + + def destroy(self, request, *args, **kwargs): + try: + reservation_id = kwargs.get('pk') + reservation = Reservation.objects.get(id=reservation_id) + reservation.delete() + return Response({"message": "Reservation successfully deleted"}, status=status.HTTP_204_NO_CONTENT) + except Reservation.DoesNotExist: + return Response({"message": "Reservation not found"}, status=status.HTTP_404_NOT_FOUND) + + + def retrieve(self, request, *args, **kwargs): + + return super().retrieve(request, *args, **kwargs) + + + + # def update(self, request, *args, **kwargs): + # return super().update(request, *args, **kwargs) + +# an example : +# class CalendarViewSet(viewsets.ModelViewSet): +# permission_classes = [IsDoctor] + +# def create(self, request): +# Pationt = get_object_or_404(Pationt, ssn=request.data.get('ssn')) +# user = request.user +# doctor = Doctor.objects.get(user=user) +# calendar_serializer = CalendarSerializer(data=request.data) +# calendar_serializer.is_valid(raise_exception=True) +# calendar = calendar_serializer.create(calendar_serializer.validated_data) +# calendar.Pationt = Pationt +# calendar.doctor = doctor +# calendar.save() +# return Response({'message': 'event created successfully'}, status=status.HTTP_200_OK) + +# def list_month(self, request): +# queryset = Calendar.objects.all() +# month = request.data.get('month') +# year = request.data.get('year') +# queryset = queryset.filter(date__year=year, date__month=month) +# serializer = CalendarSerializer(queryset, many=True) +# return Response(serializer.data) + +# def list_week(self, request): +# queryset = Calendar.objects.all() +# day = int(request.data.get('day')) +# month = int(request.data.get('month')) +# year = int(request.data.get('year')) +# steps = 7 +# saturday = datetime(year=year, month=month, day=day).date() +# delta = timedelta(days=7) +# number_of_days_month = cd.monthrange(year, month)[1] +# days_date = {} +# if day + steps - 1 <= number_of_days_month: +# queryset = queryset.filter(date__year=year, date__month=month, date__day__gte=day, +# date__day__lte=day + steps - 1) +# else: +# q1 = queryset.filter(date__year=year, date__month=month, date__day__gte=day, +# date__day__lte=number_of_days_month) +# q2 = [] +# if month != 12: +# q2 = queryset.filter(date__year=year, date__month=(month + 1) % 12, +# date__day__lte=(day + steps - 1) % number_of_days_month) +# else: +# q2 = queryset.filter(date__year=year + 1, date__month=(month + 1) % 12, +# date__day__lte=(day + steps - 1) % number_of_days_month) +# queryset = q1.union(q2, all=True) +# date_dict = {} +# for event in queryset: +# if event.date in date_dict.keys(): +# date_dict[event.date].append( +# {'title': event.event_type, +# 'Pationt_fullname': event.Pationt.first_name + ' ' + event.Pationt.last_name, +# 'ssn': event.Pationt.ssn, +# 'startTime': event.start_time.hour, 'endTime': event.end_time.hour, +# 'image': event.Pationt.picture.url, +# 'day': event.day, 'gender': event.Pationt.gender, 'birth_date': event.Pationt.birth_date, +# 'disease_title': event.Pationt.disease.first().title if event.Pationt.disease.exists() else None}) +# continue +# date_dict[event.date] = [ +# {'title': event.event_type, +# 'Pationt_fullname': event.Pationt.first_name + ' ' + event.Pationt.last_name, +# 'ssn': event.Pationt.ssn, +# 'startTime': event.start_time.hour, 'endTime': event.end_time.hour, 'image': event.Pationt.picture.url, +# 'day': event.day, 'gender': event.Pationt.gender, 'birth_date': event.Pationt.birth_date, +# 'disease_title': event.Pationt.disease.first().title if event.Pationt.disease.exists() else None}] + +# day_list = ['شنبه', 'یک‌شنبه', 'دو‌شنبه', 'سه‌شنبه', 'چهار‌شنبه', 'پنج‌شنبه', 'جمعه', ] +# output = [] +# for key in date_dict.keys(): +# inner_dict = {'date': key, 'day': date_dict[key][0]['day'], 'schedule': date_dict[key]} +# output.append(inner_dict) + +# for de in range(7): +# if saturday + timedelta(de) not in date_dict.keys(): +# output.append({'date': saturday + timedelta(de), 'day': day_list[de], 'schedule': []}) + +# return Response(sorted(output, key=lambda x: x['date'])) From a10797d5c78a36802fe50c06d823e708c25d9b6e Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Mon, 8 Apr 2024 18:16:58 +0330 Subject: [PATCH 29/46] . --- .../migrations/0002_alter_reservation_day.py | 30 +++++++++++++++++++ BackEnd/reservation/models.py | 18 +++++++++-- BackEnd/reservation/serializer.py | 8 +++-- BackEnd/reservation/views.py | 4 ++- 4 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 BackEnd/reservation/migrations/0002_alter_reservation_day.py diff --git a/BackEnd/reservation/migrations/0002_alter_reservation_day.py b/BackEnd/reservation/migrations/0002_alter_reservation_day.py new file mode 100644 index 0000000..77f5b64 --- /dev/null +++ b/BackEnd/reservation/migrations/0002_alter_reservation_day.py @@ -0,0 +1,30 @@ +# Generated by Django 5.0.3 on 2024-04-08 11:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("reservation", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="reservation", + name="day", + field=models.CharField( + blank=True, + choices=[ + ("شنبه", "شنبه"), + ("یک\u200cشنبه", "یک\u200cشنبه"), + ("دو\u200cشنبه", "دو\u200cشنبه"), + ("سه\u200cشنبه", "سه\u200cشنبه"), + ("چهار\u200cشنبه", "چهار\u200cشنبه"), + ("پنج\u200cشنبه", "پنج\u200cشنبه"), + ("جمعه", "جمعه"), + ], + max_length=10, + ), + ), + ] diff --git a/BackEnd/reservation/models.py b/BackEnd/reservation/models.py index 11b7276..b2fabbd 100644 --- a/BackEnd/reservation/models.py +++ b/BackEnd/reservation/models.py @@ -1,7 +1,7 @@ from typing import Iterable from django.db import models from counseling.models import Psychiatrist , Pationt - +from datetime import date class Reservation(models.Model) : DAY_CHOICES = [ @@ -24,10 +24,24 @@ class Reservation(models.Model) : date = models.DateField() time = models.TimeField() type = models.CharField(choices=RESERVE_CHOICES) - day = models.CharField(max_length=10, choices=DAY_CHOICES) + day = models.CharField(max_length=10, choices=DAY_CHOICES , blank=True ) + class Meta: unique_together = ['date', 'time'] def save(self, *args, **kwargs) : + day_dict = { + 0 : 'دوشنبه' , + 1 : 'سه شنبه' , + 2 : 'چهارشنبه' , + 3 : 'پنج‌شنبه' , + 4 : 'جمعه' , + 5 : 'شنبه' , + 6 : 'یکشنبه' + } + if not self.day: + day_num = date.today().weekday() + self.date = day_dict[day_num] + return super().save() \ No newline at end of file diff --git a/BackEnd/reservation/serializer.py b/BackEnd/reservation/serializer.py index 1424c2d..8a09841 100644 --- a/BackEnd/reservation/serializer.py +++ b/BackEnd/reservation/serializer.py @@ -6,8 +6,8 @@ from .models import Reservation from datetime import date -class ReserveSerializer(serializers.Serializer ) : +class ReserveSerializer(serializers.Serializer ) : class Meta : model = Reservation fields = ["day" , "type" , "date" , "time" , "id"] @@ -17,4 +17,8 @@ def validate_date(self, attrs): if date.today > attrs : return serializers.ValidationError("date is not accessable") return attrs - \ No newline at end of file + + +class RetrieveDays( serializers.Serializer ) : + pass + \ No newline at end of file diff --git a/BackEnd/reservation/views.py b/BackEnd/reservation/views.py index c8aed83..7578d92 100644 --- a/BackEnd/reservation/views.py +++ b/BackEnd/reservation/views.py @@ -53,11 +53,13 @@ def destroy(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs): - + # serializer = + # start_date = return super().retrieve(request, *args, **kwargs) + # def update(self, request, *args, **kwargs): # return super().update(request, *args, **kwargs) From 15c6f60e5041890c6a5ff452a1acf3d9e8eb558b Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Tue, 9 Apr 2024 08:16:45 +0330 Subject: [PATCH 30/46] feat/Tellbot --- BackEnd/telegrambot/__init__.py | 0 BackEnd/telegrambot/admin.py | 3 +++ BackEnd/telegrambot/apps.py | 6 ++++++ BackEnd/telegrambot/credentials.py | 4 ++++ BackEnd/telegrambot/migrations/__init__.py | 0 BackEnd/telegrambot/models.py | 3 +++ BackEnd/telegrambot/tests.py | 3 +++ BackEnd/telegrambot/urls.py | 7 +++++++ BackEnd/telegrambot/views.py | 22 ++++++++++++++++++++++ 9 files changed, 48 insertions(+) create mode 100644 BackEnd/telegrambot/__init__.py create mode 100644 BackEnd/telegrambot/admin.py create mode 100644 BackEnd/telegrambot/apps.py create mode 100644 BackEnd/telegrambot/credentials.py create mode 100644 BackEnd/telegrambot/migrations/__init__.py create mode 100644 BackEnd/telegrambot/models.py create mode 100644 BackEnd/telegrambot/tests.py create mode 100644 BackEnd/telegrambot/urls.py create mode 100644 BackEnd/telegrambot/views.py diff --git a/BackEnd/telegrambot/__init__.py b/BackEnd/telegrambot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/telegrambot/admin.py b/BackEnd/telegrambot/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/BackEnd/telegrambot/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/BackEnd/telegrambot/apps.py b/BackEnd/telegrambot/apps.py new file mode 100644 index 0000000..36be1df --- /dev/null +++ b/BackEnd/telegrambot/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TelegrambotConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "telegrambot" diff --git a/BackEnd/telegrambot/credentials.py b/BackEnd/telegrambot/credentials.py new file mode 100644 index 0000000..257e796 --- /dev/null +++ b/BackEnd/telegrambot/credentials.py @@ -0,0 +1,4 @@ +TOKEN = '6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So' +TELEGRAM_API_URL = f'https://api.telegram.org/bot{TOKEN}/' + + diff --git a/BackEnd/telegrambot/migrations/__init__.py b/BackEnd/telegrambot/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/telegrambot/models.py b/BackEnd/telegrambot/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/BackEnd/telegrambot/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/BackEnd/telegrambot/tests.py b/BackEnd/telegrambot/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BackEnd/telegrambot/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BackEnd/telegrambot/urls.py b/BackEnd/telegrambot/urls.py new file mode 100644 index 0000000..bc24339 --- /dev/null +++ b/BackEnd/telegrambot/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('getpost/', views.telegram_bot, name='telegram_bot'), +] + diff --git a/BackEnd/telegrambot/views.py b/BackEnd/telegrambot/views.py new file mode 100644 index 0000000..67b9281 --- /dev/null +++ b/BackEnd/telegrambot/views.py @@ -0,0 +1,22 @@ +from django.shortcuts import render + +# Create your views here. +import json +import requests +from django.http import HttpResponse +from django.views.decorators.csrf import csrf_exempt +from .credentials import TELEGRAM_API_URL + +@csrf_exempt +def telegram_bot(request): + if request.method == 'POST': + message = json.loads(request.body.decode('utf-8')) + chat_id = message['message']['chat']['id'] + text = message['message']['text'] + send_message("sendMessage", { + 'chat_id': f'your message {text}' + }) + return HttpResponse('ok') + +def send_message(method, data): + return requests.post(TELEGRAM_API_URL + method, data) \ No newline at end of file From c56fec63e8ff75c7e501a81a8c05674259f4158b Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Tue, 9 Apr 2024 23:52:57 +0330 Subject: [PATCH 31/46] feat/reserve --- ..._last_verification_sent_alter_user_role.py | 32 ++++ BackEnd/accounts/models.py | 15 +- BackEnd/reservation/models.py | 5 +- BackEnd/reservation/serializer.py | 14 +- BackEnd/reservation/urls.py | 7 +- BackEnd/reservation/views.py | 146 +++++++----------- 6 files changed, 107 insertions(+), 112 deletions(-) create mode 100644 BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py diff --git a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py new file mode 100644 index 0000000..ad9f85b --- /dev/null +++ b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py @@ -0,0 +1,32 @@ +# Generated by Django 5.0.3 on 2024-04-09 06:20 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0002_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 4, 9, 9, 49, 59, 946301), + null=True, + ), + ), + migrations.AlterField( + model_name="user", + name="role", + field=models.CharField( + choices=[("user", "User"), ("doctor", "Doctor"), ("admin", "Admin")], + default="user", + max_length=255, + ), + ), + ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index 1291b10..0aff6b0 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -114,8 +114,8 @@ class User(AbstractBaseUser): blank=True, null=True ) - role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER,unique=True) + role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER ) # email varification is_email_verified = models.BooleanField(default=False) verification_code = models.CharField(max_length=4, null=True, blank=True) @@ -144,15 +144,4 @@ def is_staff(self): # Simplest possible answer: All admins are staff return self.is_admin - - # profile = GenericRelation(to=Profile, related_query_name='user') - - # def get_default_profile_image(self): - # if self.gender == 'M': - # return 'images/profile_pics/male_default.png' - # else: - # return 'images/profile_pics/female_default.png' - -# class Role(models.Model): -# user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='role') -# role = models.CharField(max_length=255, choices=User.CHOICES, default=User.TYPE_USER) \ No newline at end of file + \ No newline at end of file diff --git a/BackEnd/reservation/models.py b/BackEnd/reservation/models.py index b2fabbd..266b2bc 100644 --- a/BackEnd/reservation/models.py +++ b/BackEnd/reservation/models.py @@ -26,7 +26,6 @@ class Reservation(models.Model) : type = models.CharField(choices=RESERVE_CHOICES) day = models.CharField(max_length=10, choices=DAY_CHOICES , blank=True ) - class Meta: unique_together = ['date', 'time'] @@ -40,8 +39,8 @@ def save(self, *args, **kwargs) : 5 : 'شنبه' , 6 : 'یکشنبه' } + if not self.day: day_num = date.today().weekday() - self.date = day_dict[day_num] - + self.day = day_dict[day_num] return super().save() \ No newline at end of file diff --git a/BackEnd/reservation/serializer.py b/BackEnd/reservation/serializer.py index 8a09841..eaac01d 100644 --- a/BackEnd/reservation/serializer.py +++ b/BackEnd/reservation/serializer.py @@ -17,8 +17,12 @@ def validate_date(self, attrs): if date.today > attrs : return serializers.ValidationError("date is not accessable") return attrs - - -class RetrieveDays( serializers.Serializer ) : - pass - \ No newline at end of file + +class DaySerializer(serializers.Serializer) : + date = serializers.DateField() + doctor_id = serializers.IntegerField() + +class BetweenDatesSerializer(serializers.Serializer): + start_date = serializers.DateField() + end_date = serializers.DateField() + doctor_id = serializers.IntegerField() \ No newline at end of file diff --git a/BackEnd/reservation/urls.py b/BackEnd/reservation/urls.py index 3c7a53b..18d8407 100644 --- a/BackEnd/reservation/urls.py +++ b/BackEnd/reservation/urls.py @@ -2,6 +2,9 @@ from .views import * urlpatterns = [ - path("create/" , ReservationView.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}) , name="create") , + path("create/" , ReservationView.as_view({'post':'create'}) , name="create") , path("delete//" , ReservationView.as_view({'delete': 'destroy'}) , name="delete") , -] \ No newline at end of file + path("between_dates/", ReservationView.as_view({'get': 'between_dates'}), name="between_dates"), + path("last_month/" ,ReservationView.as_view({'get' : 'list_month'}),name="last_month" ), + path("last_week/" , ReservationView.as_view({'get' : 'last_week'}) , name="last_week") +] diff --git a/BackEnd/reservation/views.py b/BackEnd/reservation/views.py index 7578d92..2e60515 100644 --- a/BackEnd/reservation/views.py +++ b/BackEnd/reservation/views.py @@ -6,6 +6,9 @@ from counseling.models import Pationt , Psychiatrist from .serializer import ReserveSerializer from .models import Reservation +from django.utils import timezone +from django.core.exceptions import ObjectDoesNotExist +from datetime import date @@ -25,14 +28,14 @@ def create(self, request, *args, **kwargs): return Response({'message': 'user is not loged in'}, status=status.HTTP_400_BAD_REQUEST) doctor = request.data.get('doctor_id') - Pationt = Pationt.objects.filter( user = request.user ) + pationt = Pationt.objects.filter( user = request.user ) reserve = Reservation.objects.create( date = serializer.validated_data["date"] , type = serializer.validated_data["type"] , time = serializer.validated_data["time"] , day = serializer.validated_data["day"] , psychiatrist = doctor , - Pationt = Pationt + Pationt = pationt ) response = { @@ -51,94 +54,59 @@ def destroy(self, request, *args, **kwargs): except Reservation.DoesNotExist: return Response({"message": "Reservation not found"}, status=status.HTTP_404_NOT_FOUND) - - def retrieve(self, request, *args, **kwargs): - # serializer = - # start_date = - return super().retrieve(request, *args, **kwargs) + + def list_month(self, request): + queryset = Reservation.objects.all() + month = request.data.get('month') + year = request.data.get('year') + queryset = queryset.filter(date__year=year, date__month=month) + serializer = ReserveSerializer(queryset, many=True) + return Response(serializer.data , status=status.HTTP_200_OK) + + def last_week( self , request ) : + # get the date of saturday + # day_dict = { + # 0 : 'شنبه' , + # 1 : 'یکشنبه', + # 2 : 'دوشنبه' , + # 3 : 'سه شنبه' , + # 4 : 'چهارشنبه' , + # 5 : 'پنج‌شنبه' , + # 6 : 'جمعه' + # } + serializer = self.get_serializer(data=request.query_params) + serializer.is_valid(raise_exception=True) + date1 = serializer.validated_data['date'] + doctor = serializer.validated_data['doctor_id'] + day = (date1.weekday() + 2)%7 + saturday = date( day= date1.day- day , month=date1.month , year=date1.year) + thirsday = date( day= saturday.day+5 , month=saturday.month , year=saturday.year) + reservations = Reservation.objects.filter(date__range=[saturday, thirsday], psychiatrist=doctor) + serializer = ReserveSerializer(reservations, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + def between_dates(self, request): + serializer = self.get_serializer(data=request.query_params) + serializer.is_valid(raise_exception=True) + + start_date = serializer.validated_data['start_date'] + end_date = serializer.validated_data['end_date'] + doctor_id = serializer.validated_data['doctor_id'] + try: + doctor = Psychiatrist.objects.get(id=doctor_id) + except ObjectDoesNotExist: + return Response({"message": "Doctor not found"}, status=status.HTTP_404_NOT_FOUND) - # def update(self, request, *args, **kwargs): - # return super().update(request, *args, **kwargs) - -# an example : -# class CalendarViewSet(viewsets.ModelViewSet): -# permission_classes = [IsDoctor] - -# def create(self, request): -# Pationt = get_object_or_404(Pationt, ssn=request.data.get('ssn')) -# user = request.user -# doctor = Doctor.objects.get(user=user) -# calendar_serializer = CalendarSerializer(data=request.data) -# calendar_serializer.is_valid(raise_exception=True) -# calendar = calendar_serializer.create(calendar_serializer.validated_data) -# calendar.Pationt = Pationt -# calendar.doctor = doctor -# calendar.save() -# return Response({'message': 'event created successfully'}, status=status.HTTP_200_OK) - -# def list_month(self, request): -# queryset = Calendar.objects.all() -# month = request.data.get('month') -# year = request.data.get('year') -# queryset = queryset.filter(date__year=year, date__month=month) -# serializer = CalendarSerializer(queryset, many=True) -# return Response(serializer.data) - -# def list_week(self, request): -# queryset = Calendar.objects.all() -# day = int(request.data.get('day')) -# month = int(request.data.get('month')) -# year = int(request.data.get('year')) -# steps = 7 -# saturday = datetime(year=year, month=month, day=day).date() -# delta = timedelta(days=7) -# number_of_days_month = cd.monthrange(year, month)[1] -# days_date = {} -# if day + steps - 1 <= number_of_days_month: -# queryset = queryset.filter(date__year=year, date__month=month, date__day__gte=day, -# date__day__lte=day + steps - 1) -# else: -# q1 = queryset.filter(date__year=year, date__month=month, date__day__gte=day, -# date__day__lte=number_of_days_month) -# q2 = [] -# if month != 12: -# q2 = queryset.filter(date__year=year, date__month=(month + 1) % 12, -# date__day__lte=(day + steps - 1) % number_of_days_month) -# else: -# q2 = queryset.filter(date__year=year + 1, date__month=(month + 1) % 12, -# date__day__lte=(day + steps - 1) % number_of_days_month) -# queryset = q1.union(q2, all=True) -# date_dict = {} -# for event in queryset: -# if event.date in date_dict.keys(): -# date_dict[event.date].append( -# {'title': event.event_type, -# 'Pationt_fullname': event.Pationt.first_name + ' ' + event.Pationt.last_name, -# 'ssn': event.Pationt.ssn, -# 'startTime': event.start_time.hour, 'endTime': event.end_time.hour, -# 'image': event.Pationt.picture.url, -# 'day': event.day, 'gender': event.Pationt.gender, 'birth_date': event.Pationt.birth_date, -# 'disease_title': event.Pationt.disease.first().title if event.Pationt.disease.exists() else None}) -# continue -# date_dict[event.date] = [ -# {'title': event.event_type, -# 'Pationt_fullname': event.Pationt.first_name + ' ' + event.Pationt.last_name, -# 'ssn': event.Pationt.ssn, -# 'startTime': event.start_time.hour, 'endTime': event.end_time.hour, 'image': event.Pationt.picture.url, -# 'day': event.day, 'gender': event.Pationt.gender, 'birth_date': event.Pationt.birth_date, -# 'disease_title': event.Pationt.disease.first().title if event.Pationt.disease.exists() else None}] - -# day_list = ['شنبه', 'یک‌شنبه', 'دو‌شنبه', 'سه‌شنبه', 'چهار‌شنبه', 'پنج‌شنبه', 'جمعه', ] -# output = [] -# for key in date_dict.keys(): -# inner_dict = {'date': key, 'day': date_dict[key][0]['day'], 'schedule': date_dict[key]} -# output.append(inner_dict) - -# for de in range(7): -# if saturday + timedelta(de) not in date_dict.keys(): -# output.append({'date': saturday + timedelta(de), 'day': day_list[de], 'schedule': []}) - -# return Response(sorted(output, key=lambda x: x['date'])) + if not start_date or not end_date: + return Response({"message": "Both start_date and end_date are required"}, status=status.HTTP_400_BAD_REQUEST) + try: + start_date = timezone.datetime.strptime(start_date, "%Y-%m-%d").date() + end_date = timezone.datetime.strptime(end_date, "%Y-%m-%d").date() + except ValueError: + return Response({"message": "Invalid date format. Use YYYY-MM-DD."}, status=status.HTTP_400_BAD_REQUEST) + + reservations = Reservation.objects.filter(date__range=[start_date, end_date], psychiatrist=doctor) + serializer = ReserveSerializer(reservations, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) \ No newline at end of file From 3e6c9812141bb73ec0aa917e2c0150eee63f0e4e Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 10 Apr 2024 22:02:51 +0330 Subject: [PATCH 32/46] m --- BackEnd/.iis/applicationhost.config | 906 ++++++++++++++++++++++++++++ BackEnd/BackEnd/settings.py | 3 +- BackEnd/telegrambot/credentials.py | 3 +- BackEnd/telegrambot/views.py | 61 +- 4 files changed, 951 insertions(+), 22 deletions(-) create mode 100644 BackEnd/.iis/applicationhost.config diff --git a/BackEnd/.iis/applicationhost.config b/BackEnd/.iis/applicationhost.config new file mode 100644 index 0000000..18beaf0 --- /dev/null +++ b/BackEnd/.iis/applicationhost.config @@ -0,0 +1,906 @@ + + + + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + +
+
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index b93eb6e..cabb2bb 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -49,7 +49,7 @@ # SESSION_COOKIE_DOMAIN -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = ['*' ,'127.0.0.1' ,'84bf-5-62-211-211.ngrok-free.app'] REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES' : [ @@ -109,6 +109,7 @@ "Profile", "drf_yasg", "counseling", + "django_tgbot" ] MIDDLEWARE = [ diff --git a/BackEnd/telegrambot/credentials.py b/BackEnd/telegrambot/credentials.py index 257e796..af43fcd 100644 --- a/BackEnd/telegrambot/credentials.py +++ b/BackEnd/telegrambot/credentials.py @@ -1,4 +1,5 @@ TOKEN = '6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So' TELEGRAM_API_URL = f'https://api.telegram.org/bot{TOKEN}/' - +# curl -X POST "https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=84bf-5-62-211-211.ngrok-free.app/webhook" +# https://github.com/Ali-Toosi/django-tgbot \ No newline at end of file diff --git a/BackEnd/telegrambot/views.py b/BackEnd/telegrambot/views.py index 67b9281..ae98039 100644 --- a/BackEnd/telegrambot/views.py +++ b/BackEnd/telegrambot/views.py @@ -1,22 +1,43 @@ from django.shortcuts import render +import os +from .credentials import TELEGRAM_API_URL , TOKEN -# Create your views here. -import json -import requests -from django.http import HttpResponse -from django.views.decorators.csrf import csrf_exempt -from .credentials import TELEGRAM_API_URL - -@csrf_exempt -def telegram_bot(request): - if request.method == 'POST': - message = json.loads(request.body.decode('utf-8')) - chat_id = message['message']['chat']['id'] - text = message['message']['text'] - send_message("sendMessage", { - 'chat_id': f'your message {text}' - }) - return HttpResponse('ok') - -def send_message(method, data): - return requests.post(TELEGRAM_API_URL + method, data) \ No newline at end of file +import telebot + +# BOT_TOKEN = os.environ.get('BOT_TOKEN') + +bot = telebot.TeleBot(TOKEN) + + +@bot.message_handler(commands=['start', 'hello']) +def send_welcome(message): + bot.reply_to(message, "Howdy, how are you doing?") + + +@bot.message_handler(func=lambda msg: True) +def echo_all(message): + bot.reply_to(message, message.text) + + + +bot.infinity_polling() + + # Create your views here. +# import json +# import requests +# from django.http import HttpResponse +# from django.views.decorators.csrf import csrf_exempt + +# @csrf_exempt +# def telegram_bot(request): +# if request.method == 'POST': +# message = json.loads(request.body.decode('utf-8')) +# chat_id = message['message']['chat']['id'] +# text = message['message']['text'] +# send_message("sendMessage", { +# 'chat_id': f'your message {text}' +# }) +# return HttpResponse('ok') + +# def send_message(method, data): +# return requests.post(TELEGRAM_API_URL + method, data) From bd8f84d629f15f102672068c95a04dc93440b13a Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 10 Apr 2024 22:06:53 +0330 Subject: [PATCH 33/46] fix --- .../0004_alter_user_last_verification_sent.py | 23 +++++++++++++++++++ .../0005_alter_user_last_verification_sent.py | 23 +++++++++++++++++++ .../migrations/0003_alter_reservation_type.py | 20 ++++++++++++++++ BackEnd/reservation/models.py | 2 +- 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py create mode 100644 BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py create mode 100644 BackEnd/reservation/migrations/0003_alter_reservation_type.py diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py new file mode 100644 index 0000000..2812bc1 --- /dev/null +++ b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-04-10 18:33 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0003_alter_user_last_verification_sent_alter_user_role"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 4, 10, 22, 3, 26, 462247), + null=True, + ), + ), + ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py new file mode 100644 index 0000000..e3cd8cf --- /dev/null +++ b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-04-10 18:35 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0004_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 4, 10, 22, 5, 47, 853997), + null=True, + ), + ), + ] diff --git a/BackEnd/reservation/migrations/0003_alter_reservation_type.py b/BackEnd/reservation/migrations/0003_alter_reservation_type.py new file mode 100644 index 0000000..463f212 --- /dev/null +++ b/BackEnd/reservation/migrations/0003_alter_reservation_type.py @@ -0,0 +1,20 @@ +# Generated by Django 5.0.3 on 2024-04-10 18:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("reservation", "0002_alter_reservation_day"), + ] + + operations = [ + migrations.AlterField( + model_name="reservation", + name="type", + field=models.CharField( + choices=[("حضوری", "حضوری"), ("مجازی", "مجازی")], max_length=15 + ), + ), + ] diff --git a/BackEnd/reservation/models.py b/BackEnd/reservation/models.py index 266b2bc..f40b436 100644 --- a/BackEnd/reservation/models.py +++ b/BackEnd/reservation/models.py @@ -23,7 +23,7 @@ class Reservation(models.Model) : pationt = models.ForeignKey(Pationt, on_delete=models.CASCADE, related_name='pationt_reservations') date = models.DateField() time = models.TimeField() - type = models.CharField(choices=RESERVE_CHOICES) + type = models.CharField(max_length=15 ,choices=RESERVE_CHOICES) day = models.CharField(max_length=10, choices=DAY_CHOICES , blank=True ) class Meta: From 3bacfabe1b6094d683a9abf44763753b7311f654 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 12 Apr 2024 13:15:35 +0330 Subject: [PATCH 34/46] fix/threpytests --- BackEnd/BackEnd/settings.py | 3 +- BackEnd/BackEnd/urls.py | 1 + BackEnd/TherapyTests/__init__.py | 0 BackEnd/TherapyTests/admin.py | 3 ++ BackEnd/TherapyTests/apps.py | 6 +++ .../TherapyTests/migrations/0001_initial.py | 38 +++++++++++++ BackEnd/TherapyTests/migrations/__init__.py | 0 BackEnd/TherapyTests/models.py | 9 ++++ BackEnd/TherapyTests/tests.py | 3 ++ BackEnd/TherapyTests/urls.py | 6 +++ BackEnd/TherapyTests/views.py | 47 ++++++++++++++++ BackEnd/utils/therapy_tests.py | 54 +++++++++++++++++++ 12 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 BackEnd/TherapyTests/__init__.py create mode 100644 BackEnd/TherapyTests/admin.py create mode 100644 BackEnd/TherapyTests/apps.py create mode 100644 BackEnd/TherapyTests/migrations/0001_initial.py create mode 100644 BackEnd/TherapyTests/migrations/__init__.py create mode 100644 BackEnd/TherapyTests/models.py create mode 100644 BackEnd/TherapyTests/tests.py create mode 100644 BackEnd/TherapyTests/urls.py create mode 100644 BackEnd/TherapyTests/views.py create mode 100644 BackEnd/utils/therapy_tests.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 5f4a009..df47f6a 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -17,8 +17,8 @@ from datetime import timedelta # Environment Variables - # Build paths inside the project like this: BASE_DIR / 'subdir'. + BASE_DIR = Path(__file__).resolve().parent.parent @@ -110,6 +110,7 @@ "drf_yasg", "counseling", "reservation", + "TherapyTests", ] MIDDLEWARE = [ diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index 8673cf0..d7f3817 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -44,6 +44,7 @@ path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('profile/' , include("Profile.urls")) , path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), + path('TherapyTests/' , include("TherapyTests.urls")), ] diff --git a/BackEnd/TherapyTests/__init__.py b/BackEnd/TherapyTests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/TherapyTests/admin.py b/BackEnd/TherapyTests/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/BackEnd/TherapyTests/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/BackEnd/TherapyTests/apps.py b/BackEnd/TherapyTests/apps.py new file mode 100644 index 0000000..a981d7b --- /dev/null +++ b/BackEnd/TherapyTests/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TherapytestsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "TherapyTests" diff --git a/BackEnd/TherapyTests/migrations/0001_initial.py b/BackEnd/TherapyTests/migrations/0001_initial.py new file mode 100644 index 0000000..f11985f --- /dev/null +++ b/BackEnd/TherapyTests/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 5.0.3 on 2024-04-11 16:58 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("counseling", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="TherapyTests", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("MBTItest", models.CharField(blank=True, max_length=6)), + ( + "pationt", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="counseling.pationt", + ), + ), + ], + ), + ] diff --git a/BackEnd/TherapyTests/migrations/__init__.py b/BackEnd/TherapyTests/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/TherapyTests/models.py b/BackEnd/TherapyTests/models.py new file mode 100644 index 0000000..d6d039d --- /dev/null +++ b/BackEnd/TherapyTests/models.py @@ -0,0 +1,9 @@ +from django.db import models +from counseling.models import Pationt + +class TherapyTests(models.Model) : + pationt = models.ForeignKey(Pationt , on_delete=models.CASCADE ) + MBTItest = models.CharField( max_length=6 , blank=True ) + + + diff --git a/BackEnd/TherapyTests/tests.py b/BackEnd/TherapyTests/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BackEnd/TherapyTests/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BackEnd/TherapyTests/urls.py b/BackEnd/TherapyTests/urls.py new file mode 100644 index 0000000..6746a6a --- /dev/null +++ b/BackEnd/TherapyTests/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from .views import * + +urlpatterns = [ + path( 'MBTI/' , GetMBTItest.as_view({'post' : 'create' , 'get' : 'retrieve'}) , name='MBTI') , +] \ No newline at end of file diff --git a/BackEnd/TherapyTests/views.py b/BackEnd/TherapyTests/views.py new file mode 100644 index 0000000..b0f4d7f --- /dev/null +++ b/BackEnd/TherapyTests/views.py @@ -0,0 +1,47 @@ +from django.shortcuts import render +from rest_framework import viewsets, serializers +from rest_framework.decorators import action +from rest_framework.response import Response +from rest_framework.permissions import IsAuthenticated +from utils.therapy_tests import GetMBTIresults +from counseling.models import Pationt +from .models import TherapyTests +from rest_framework import status +import json +from django.http.request import QueryDict + +class GetMBTItest(viewsets.ModelViewSet) : + permission_classes = [IsAuthenticated ] + + def create(self, request, *args, **kwargs): + udata = request.data + + data = {} + for key in udata.keys() : + data[int(key)] = udata[key] + + user = request.user + pationt = Pationt.objects.filter(user = user).first() + mbti = GetMBTIresults( data , user.gender ) + print(mbti) + old_test = TherapyTests.objects.filter( pationt = pationt ).first() + if old_test : + old_test.MBTItest = mbti['final'] + old_test.save() + return Response( {'message' : 'test`s results was successfullly updated'} , status=status.HTTP_200_OK ) + else : + test = TherapyTests.objects.create( + pationt = pationt , + MBTItest = mbti['final'] + ) + return Response( {'message' : 'test`s results was successfullly registered'} , status=status.HTTP_200_OK ) + + + def retrieve(self, request, *args, **kwargs): + user = request.user + pationt = Pationt.objects.filter(user = user ).first() + print(pationt) + # mbti = pationt.therapytests + mbti = TherapyTests.objects.filter( pationt = pationt ).first() + return Response( {"type" : mbti.MBTItest} , status=status.HTTP_200_OK ) + diff --git a/BackEnd/utils/therapy_tests.py b/BackEnd/utils/therapy_tests.py new file mode 100644 index 0000000..88cb95f --- /dev/null +++ b/BackEnd/utils/therapy_tests.py @@ -0,0 +1,54 @@ +# create mbti tests +def GetMBTIresults(data, gender ) : + colomn1 = [ data[7*i + 1] for i in range(10)] + colomn2 = [ data[7*i + 2] for i in range(10)] + colomn3 = [ data[7*i + 3] for i in range(10)] + colomn4 = [ data[7*i + 4] for i in range(10)] + colomn5 = [ data[7*i + 5] for i in range(10)] + colomn6 = [ data[7*i + 6] for i in range(10)] + colomn7 = [ data[7*i + 7] for i in range(10)] + # E , I + E = colomn1.count('a')*10 + I = colomn1.count('b')*10 + # S , N + S = (colomn2.count('a') + colomn3.count('a'))*5 + N = (colomn2.count('b') + colomn3.count('b'))*5 + # T , F + T = (colomn4.count('a') + colomn5.count('a'))*5 + F = (colomn4.count('b') + colomn5.count('b'))*5 + # J , P + J = (colomn6.count('a') + colomn7.count('a'))*5 + P = (colomn6.count('b') + colomn7.count('b'))*5 + + e_i = 'I' + print('E ' ,E , 'I ' , I ) + if E > I : + e_i = 'E' + + s_n = 'N' + if S > N : + s_n = 'S' + if T > F : + t_f = 'T' + elif T == F and gender == 'M' : + t_f = 'T' + else : + t_f = 'F' + + j_p = 'P' + if J > P : + j_p = 'J' + + result = { + 'E' : E , + 'I' : I , + 'S' : S , + 'N' : N , + 'T' : T , + 'F' : F , + 'J' : J , + 'P' : P , + 'final' : e_i+s_n + t_f+ j_p + } + + return result \ No newline at end of file From 991cf9b9f03b5cf3dabf89ab450c89eece1b222a Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 12 Apr 2024 22:24:36 +0330 Subject: [PATCH 35/46] feat/telegrambot --- BackEnd/BackEnd/settings.py | 5 +- BackEnd/BackEnd/urls.py | 1 + BackEnd/accounts/migrations/0001_initial.py | 4 +- .../0002_alter_user_last_verification_sent.py | 23 ---- .../0003_alter_user_last_verification_sent.py | 23 ---- .../0004_alter_user_last_verification_sent.py | 19 --- .../0005_alter_user_last_verification_sent.py | 19 --- .../0006_alter_user_last_verification_sent.py | 19 --- .../0007_alter_user_last_verification_sent.py | 19 --- ..._last_verification_sent_alter_user_role.py | 24 ---- BackEnd/accounts/models.py | 2 +- BackEnd/telegrambot/admin.py | 2 + BackEnd/telegrambot/credentials.py | 7 +- .../telegrambot/migrations/0001_initial.py | 44 +++++++ BackEnd/telegrambot/models.py | 8 +- BackEnd/telegrambot/tests.py | 14 +- BackEnd/telegrambot/urls.py | 1 + BackEnd/telegrambot/views.py | 124 +++++++++++++----- 18 files changed, 173 insertions(+), 185 deletions(-) delete mode 100644 BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py create mode 100644 BackEnd/telegrambot/migrations/0001_initial.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index cabb2bb..f4d7768 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -49,7 +49,7 @@ # SESSION_COOKIE_DOMAIN -ALLOWED_HOSTS = ['*' ,'127.0.0.1' ,'84bf-5-62-211-211.ngrok-free.app'] +ALLOWED_HOSTS = ['*' ,'127.0.0.1' ,'cb3f-37-156-157-110.ngrok-free.app'] REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES' : [ @@ -109,7 +109,8 @@ "Profile", "drf_yasg", "counseling", - "django_tgbot" + "django_tgbot", + "telegrambot", ] MIDDLEWARE = [ diff --git a/BackEnd/BackEnd/urls.py b/BackEnd/BackEnd/urls.py index 61973ab..b2c6def 100644 --- a/BackEnd/BackEnd/urls.py +++ b/BackEnd/BackEnd/urls.py @@ -42,6 +42,7 @@ path("HomePage/" , include("HomePage.urls")), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('profile/' , include("Profile.urls")) , + path('telegrambot/' , include("telegrambot.urls")), path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ] diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index cd46441..82193a2 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:45 +# Generated by Django 5.0.3 on 2024-04-12 18:15 import datetime import django.core.validators @@ -81,7 +81,7 @@ class Migration(migrations.Migration): "last_verification_sent", models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 3, 1, 15, 12, 435402), + default=datetime.datetime(2024, 4, 12, 21, 45, 34, 237168), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py deleted file mode 100644 index b70a65b..0000000 --- a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:45 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 4, 3, 1, 15, 34, 442056), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py deleted file mode 100644 index b513fa9..0000000 --- a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-02 21:46 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0002_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 4, 3, 1, 16, 13, 569335), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py deleted file mode 100644 index 84864c5..0000000 --- a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:12 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0003_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 11, 42, 3, 330257), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py deleted file mode 100644 index a960b27..0000000 --- a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:23 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0004_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 11, 53, 7, 161534), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py deleted file mode 100644 index 19070ac..0000000 --- a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:40 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0005_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 12, 10, 10, 971551), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py deleted file mode 100644 index 8dc57be..0000000 --- a/BackEnd/accounts/migrations/0007_alter_user_last_verification_sent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 08:41 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0006_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 12, 11, 35, 122061), null=True), - ), - ] diff --git a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py b/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py deleted file mode 100644 index 42392be..0000000 --- a/BackEnd/accounts/migrations/0008_alter_user_last_verification_sent_alter_user_role.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-03 10:00 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0007_alter_user_last_verification_sent'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_verification_sent', - field=models.DateTimeField(blank=True, default=datetime.datetime(2024, 4, 3, 13, 30, 36, 686277), null=True), - ), - migrations.AlterField( - model_name='user', - name='role', - field=models.CharField(choices=[('user', 'User'), ('doctor', 'Doctor'), ('admin', 'Admin')], default='user', max_length=255, unique=True), - ), - ] diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index 1291b10..51bf2dd 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -114,7 +114,7 @@ class User(AbstractBaseUser): blank=True, null=True ) - role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER,unique=True) + role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) # email varification is_email_verified = models.BooleanField(default=False) diff --git a/BackEnd/telegrambot/admin.py b/BackEnd/telegrambot/admin.py index 8c38f3f..884e440 100644 --- a/BackEnd/telegrambot/admin.py +++ b/BackEnd/telegrambot/admin.py @@ -1,3 +1,5 @@ from django.contrib import admin +from .models import TelegramAccount +admin.site.register( TelegramAccount ) # Register your models here. diff --git a/BackEnd/telegrambot/credentials.py b/BackEnd/telegrambot/credentials.py index af43fcd..7e48af8 100644 --- a/BackEnd/telegrambot/credentials.py +++ b/BackEnd/telegrambot/credentials.py @@ -1,5 +1,8 @@ TOKEN = '6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So' + +URL = 'https://0fa4-194-225-232-244.ngrok-free.app/getpost/' TELEGRAM_API_URL = f'https://api.telegram.org/bot{TOKEN}/' -# curl -X POST "https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=84bf-5-62-211-211.ngrok-free.app/webhook" -# https://github.com/Ali-Toosi/django-tgbot \ No newline at end of file + +# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://33e3-37-156-157-110.ngrok-free.app +# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://0fa4-194-225-232-244.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file diff --git a/BackEnd/telegrambot/migrations/0001_initial.py b/BackEnd/telegrambot/migrations/0001_initial.py new file mode 100644 index 0000000..3ba022f --- /dev/null +++ b/BackEnd/telegrambot/migrations/0001_initial.py @@ -0,0 +1,44 @@ +# Generated by Django 5.0.3 on 2024-04-12 18:15 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="TelegramAccount", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("is_varify", models.BooleanField(default=False)), + ("chat_id", models.CharField(max_length=15, unique=True)), + ( + "varification_code", + models.CharField(blank=True, max_length=4, null=True), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/BackEnd/telegrambot/models.py b/BackEnd/telegrambot/models.py index 71a8362..6d7bab3 100644 --- a/BackEnd/telegrambot/models.py +++ b/BackEnd/telegrambot/models.py @@ -1,3 +1,9 @@ from django.db import models - +from accounts.models import User # Create your models here. +class TelegramAccount(models.Model) : + user = models.ForeignKey(User , on_delete=models.CASCADE ) + is_varify = models.BooleanField(default=False ) + chat_id = models.CharField( unique= True , max_length=15 ) + varification_code = models.CharField( max_length=4 , blank=True , null=True ) + \ No newline at end of file diff --git a/BackEnd/telegrambot/tests.py b/BackEnd/telegrambot/tests.py index 7ce503c..c36d4ba 100644 --- a/BackEnd/telegrambot/tests.py +++ b/BackEnd/telegrambot/tests.py @@ -1,3 +1,15 @@ from django.test import TestCase +import re + +email_pattern = r"email\s*/\s*([^<>@\s]+@[^<>@\s]+\.[^<>@\s]+)" + +# text = "email / hslfj@gmail.com" +text = "email / another@example.com email / ano33ther@example.com" + + +match = re.search( email_pattern , text ) + +if match : + print( match.groups(2)) + -# Create your tests here. diff --git a/BackEnd/telegrambot/urls.py b/BackEnd/telegrambot/urls.py index bc24339..fd09b1b 100644 --- a/BackEnd/telegrambot/urls.py +++ b/BackEnd/telegrambot/urls.py @@ -3,5 +3,6 @@ urlpatterns = [ path('getpost/', views.telegram_bot, name='telegram_bot'), + # path('setwebhook/', views.setwebhook, name='setwebhook'), ] diff --git a/BackEnd/telegrambot/views.py b/BackEnd/telegrambot/views.py index ae98039..9412bdd 100644 --- a/BackEnd/telegrambot/views.py +++ b/BackEnd/telegrambot/views.py @@ -1,43 +1,107 @@ -from django.shortcuts import render -import os -from .credentials import TELEGRAM_API_URL , TOKEN +import json +import re +import requests +from django.http import HttpResponse, HttpResponseBadRequest +from django.views.decorators.csrf import csrf_exempt +from .credentials import TELEGRAM_API_URL, URL +from accounts.models import User +from counseling.models import Pationt, Psychiatrist +import utils.email as email_handler +from rest_framework.response import Response +from .models import TelegramAccount +import random +from rest_framework import status -import telebot +email_pattern = r"email\s*/\s*([^<>@\s]+@[^<>@\s]+\.[^<>@\s]+)" +code_pattern = r"code\s*/\s*(\d{4})" -# BOT_TOKEN = os.environ.get('BOT_TOKEN') +def set_webhook(request): + response = requests.post(TELEGRAM_API_URL + "setWebhook?url=" + URL).json() + return HttpResponse(f"{response}") -bot = telebot.TeleBot(TOKEN) +@csrf_exempt +def telegram_bot(request): + if request.method == 'POST': + update = json.loads(request.body.decode('utf-8')) + handle_update(update) + return HttpResponse('ok') + else: + return HttpResponseBadRequest('Bad Request') +def handle_update(update): + chat_id = update['message']['chat']['id'] + text = update['message']['text'] + + if text == "/start": + handle_start_command(chat_id) + elif text == "/verify": + handle_verify_command(chat_id) + else: + handle_other_commands(chat_id, text) -@bot.message_handler(commands=['start', 'hello']) -def send_welcome(message): - bot.reply_to(message, "Howdy, how are you doing?") +def handle_start_command(chat_id): + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'به بات تلگرام اینیاک خوش آمدید. برای تایید حساب خود گزینه verify را از منو انتخاب کنید.' + }) +def handle_verify_command(chat_id): + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'لطفا ایمیلتان را به صورت روبه رو وارد کنید \n email/<ایمیل >' + }) -@bot.message_handler(func=lambda msg: True) -def echo_all(message): - bot.reply_to(message, message.text) +def handle_other_commands(chat_id ,text ): + match_email = re.search(email_pattern, text) + match_code = re.search(code_pattern, text) + if match_email: + user = User.objects.filter(email__iexact = text ).first() + if not user : + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'ایمیل داده شده در میان کاربران موجود نمی باشد. لطفا ایمیل صحیح را وارد نمایید.' + }) + return Response({"message" : "this email does not exist."} , status=status.HTTP_400_BAD_REQUEST) + else : + tel_account = TelegramAccount.objects.create( + user = user , + varification_code = str(random.randint(1000, 9999)) , + chat_id = chat_id + ) + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'کد تایید ارسال شده به ایمیلتان را به صورت روبه رو وارد کنید\n code/ <کد>.' + }) -bot.infinity_polling() + elif match_code: + tel_account = TelegramAccount.objects.filter(chat_id = chat_id ).first() + if not tel_account : + return Response({"message" : "this chat_id is not varified by the Enic bot!"} , status=status.HTTP_400_BAD_REQUEST) + else : + if tel_account.varification_code != text : + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'کد وارد شده درست نمی باشد یا با فرمت خواسته شده وارد نشده.' + }) + return Response({"message" : "varification code did not match"} , status=status.HTTP_400_BAD_REQUEST) + else : + tel_account.is_varify = True + tel_account.varification_code = '' + tel_account.save() - # Create your views here. -# import json -# import requests -# from django.http import HttpResponse -# from django.views.decorators.csrf import csrf_exempt + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'حساب شما با موفقیت تایید شد. رزروهای شما از طریق بات تلگرام به شما اطلاع رسانی خواهد شد.' + }) -# @csrf_exempt -# def telegram_bot(request): -# if request.method == 'POST': -# message = json.loads(request.body.decode('utf-8')) -# chat_id = message['message']['chat']['id'] -# text = message['message']['text'] -# send_message("sendMessage", { -# 'chat_id': f'your message {text}' -# }) -# return HttpResponse('ok') + else: + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'این پیام پشتیبانی نمیشود' + }) -# def send_message(method, data): -# return requests.post(TELEGRAM_API_URL + method, data) + +def send_message(method, data): + return requests.post(TELEGRAM_API_URL + method, data) From 1a3becbcc6c1154d0a81f4f6339efc9c6df9fafe Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 12 Apr 2024 22:30:01 +0330 Subject: [PATCH 36/46] feat/telegrambot --- BackEnd/telegrambot/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/BackEnd/telegrambot/admin.py b/BackEnd/telegrambot/admin.py index 884e440..bcecbcc 100644 --- a/BackEnd/telegrambot/admin.py +++ b/BackEnd/telegrambot/admin.py @@ -3,3 +3,4 @@ admin.site.register( TelegramAccount ) # Register your models here. +# mnmnmnmn \ No newline at end of file From e21a20f4c290618f6f23e58d5643759ea485810c Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 12 Apr 2024 22:49:14 +0330 Subject: [PATCH 37/46] feat/telegrambot --- BackEnd/accounts/models.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/BackEnd/accounts/models.py b/BackEnd/accounts/models.py index 51bf2dd..0aff6b0 100644 --- a/BackEnd/accounts/models.py +++ b/BackEnd/accounts/models.py @@ -114,8 +114,8 @@ class User(AbstractBaseUser): blank=True, null=True ) - role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) + role = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER ) # email varification is_email_verified = models.BooleanField(default=False) verification_code = models.CharField(max_length=4, null=True, blank=True) @@ -144,15 +144,4 @@ def is_staff(self): # Simplest possible answer: All admins are staff return self.is_admin - - # profile = GenericRelation(to=Profile, related_query_name='user') - - # def get_default_profile_image(self): - # if self.gender == 'M': - # return 'images/profile_pics/male_default.png' - # else: - # return 'images/profile_pics/female_default.png' - -# class Role(models.Model): -# user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='role') -# role = models.CharField(max_length=255, choices=User.CHOICES, default=User.TYPE_USER) \ No newline at end of file + \ No newline at end of file From a4ba8c171d1708a99e42cf18fe0efe274e6f95d7 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 12 Apr 2024 22:53:50 +0330 Subject: [PATCH 38/46] fix/confilict --- BackEnd/BackEnd/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index f4d7768..d6de530 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -49,7 +49,7 @@ # SESSION_COOKIE_DOMAIN -ALLOWED_HOSTS = ['*' ,'127.0.0.1' ,'cb3f-37-156-157-110.ngrok-free.app'] +ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES' : [ From f29154a51fbf50cf09d0e184c4fd3cf28a81376c Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 12 Apr 2024 22:54:48 +0330 Subject: [PATCH 39/46] fix/confilict --- BackEnd/BackEnd/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index 5f4a009..d6de530 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -109,7 +109,8 @@ "Profile", "drf_yasg", "counseling", - "reservation", + "django_tgbot", + "telegrambot", ] MIDDLEWARE = [ From 0dcf58ecb61602fe0a85f63147f6cb8a911bce05 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 17 Apr 2024 13:54:38 +0330 Subject: [PATCH 40/46] fix/bot --- BackEnd/BackEnd/settings.py | 12 ++- BackEnd/Profile/models.py | 1 - BackEnd/accounts/migrations/0001_initial.py | 13 +-- .../0002_alter_user_last_verification_sent.py | 4 +- ...0003_alter_user_last_verification_sent.py} | 13 +-- .../0004_alter_user_last_verification_sent.py | 6 +- .../0005_alter_user_last_verification_sent.py | 4 +- .../0006_alter_user_last_verification_sent.py | 23 +++++ ...ramaccount_psychiatrist_telegramaccount.py | 33 +++++++ BackEnd/counseling/models.py | 7 +- BackEnd/manage.py | 40 +++++++++ BackEnd/telegrambot/bot.py | 52 +++++++++++ BackEnd/telegrambot/credentials.py | 4 +- BackEnd/telegrambot/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/start_bot.py | 66 ++++++++++++++ .../0002_remove_telegramaccount_user.py | 14 +++ BackEnd/telegrambot/models.py | 5 +- BackEnd/telegrambot/views.py | 86 ++++++++++++++++--- BackEnd/utils/email.py | 5 +- 20 files changed, 334 insertions(+), 54 deletions(-) rename BackEnd/accounts/migrations/{0003_alter_user_last_verification_sent_alter_user_role.py => 0003_alter_user_last_verification_sent.py} (51%) create mode 100644 BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py create mode 100644 BackEnd/counseling/migrations/0002_pationt_telegramaccount_psychiatrist_telegramaccount.py create mode 100644 BackEnd/telegrambot/bot.py create mode 100644 BackEnd/telegrambot/management/__init__.py create mode 100644 BackEnd/telegrambot/management/commands/__init__.py create mode 100644 BackEnd/telegrambot/management/commands/start_bot.py create mode 100644 BackEnd/telegrambot/migrations/0002_remove_telegramaccount_user.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index d6de530..af98987 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -31,7 +31,7 @@ env.read_env() # Setting Website URL -WEBSITE_URL = 'http://localhost:80ssss00/' #env.str('WEBSITE_URL') +WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') # BASE_URL = 'http://localhost:8000/' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' @@ -102,16 +102,20 @@ "django.contrib.messages", "django.contrib.staticfiles", "corsheaders", + "telegrambot", "accounts", + "reservation", "rest_framework", "rest_framework_swagger", "rest_framework_simplejwt.token_blacklist", "Profile", "drf_yasg", "counseling", - "django_tgbot", - "telegrambot", + # "django_tgbot", + "background_task", + 'django.contrib.sites' , ] +SITE_ID = 1 MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", @@ -196,7 +200,7 @@ LANGUAGE_CODE = "en-us" -TIME_ZONE = "UTC" +TIME_ZONE = 'Asia/Tehran' USE_I18N = True diff --git a/BackEnd/Profile/models.py b/BackEnd/Profile/models.py index f3026ca..a1e13fc 100644 --- a/BackEnd/Profile/models.py +++ b/BackEnd/Profile/models.py @@ -21,7 +21,6 @@ def save(self, *args, **kwargs): self.name = self.determine_name(self.name) self.profile_type = self.determine_profile_type() self.image = self.determine_image() - print(self.image) super().save(*args, **kwargs) diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index 996d4f5..e32d677 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,8 +1,4 @@ -<<<<<<< HEAD -# Generated by Django 5.0.3 on 2024-04-12 18:15 -======= -# Generated by Django 5.0.3 on 2024-04-08 07:27 ->>>>>>> dev +# Generated by Django 5.0.3 on 2024-04-14 06:56 import datetime import django.core.validators @@ -73,7 +69,6 @@ class Migration(migrations.Migration): ], default="user", max_length=255, - unique=True, ), ), ("is_email_verified", models.BooleanField(default=False)), @@ -86,11 +81,7 @@ class Migration(migrations.Migration): "last_verification_sent", models.DateTimeField( blank=True, -<<<<<<< HEAD - default=datetime.datetime(2024, 4, 12, 21, 45, 34, 237168), -======= - default=datetime.datetime(2024, 4, 8, 10, 57, 32, 809243), ->>>>>>> dev + default=datetime.datetime(2024, 4, 14, 10, 26, 48, 131829), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py index db31cb6..e90cca1 100644 --- a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py +++ b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-08 07:28 +# Generated by Django 5.0.3 on 2024-04-14 06:58 import datetime from django.db import migrations, models @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 8, 10, 58, 5, 142932), + default=datetime.datetime(2024, 4, 14, 10, 28, 2, 616472), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py similarity index 51% rename from BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py rename to BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py index ad9f85b..eb0191c 100644 --- a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py +++ b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-09 06:20 +# Generated by Django 5.0.3 on 2024-04-16 02:05 import datetime from django.db import migrations, models @@ -16,17 +16,8 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 9, 9, 49, 59, 946301), + default=datetime.datetime(2024, 4, 16, 5, 35, 38, 697110), null=True, ), ), - migrations.AlterField( - model_name="user", - name="role", - field=models.CharField( - choices=[("user", "User"), ("doctor", "Doctor"), ("admin", "Admin")], - default="user", - max_length=255, - ), - ), ] diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py index 2812bc1..d722c6a 100644 --- a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py +++ b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-10 18:33 +# Generated by Django 5.0.3 on 2024-04-16 02:06 import datetime from django.db import migrations, models @@ -7,7 +7,7 @@ class Migration(migrations.Migration): dependencies = [ - ("accounts", "0003_alter_user_last_verification_sent_alter_user_role"), + ("accounts", "0003_alter_user_last_verification_sent"), ] operations = [ @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 10, 22, 3, 26, 462247), + default=datetime.datetime(2024, 4, 16, 5, 36, 5, 433083), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py index e3cd8cf..4406742 100644 --- a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py +++ b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-10 18:35 +# Generated by Django 5.0.3 on 2024-04-16 02:22 import datetime from django.db import migrations, models @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 10, 22, 5, 47, 853997), + default=datetime.datetime(2024, 4, 16, 5, 52, 27, 638776), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py new file mode 100644 index 0000000..83e890c --- /dev/null +++ b/BackEnd/accounts/migrations/0006_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-04-16 02:22 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0005_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 4, 16, 5, 52, 54, 649665), + null=True, + ), + ), + ] diff --git a/BackEnd/counseling/migrations/0002_pationt_telegramaccount_psychiatrist_telegramaccount.py b/BackEnd/counseling/migrations/0002_pationt_telegramaccount_psychiatrist_telegramaccount.py new file mode 100644 index 0000000..f45365d --- /dev/null +++ b/BackEnd/counseling/migrations/0002_pationt_telegramaccount_psychiatrist_telegramaccount.py @@ -0,0 +1,33 @@ +# Generated by Django 5.0.3 on 2024-04-14 06:56 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0001_initial"), + ("telegrambot", "0002_remove_telegramaccount_user"), + ] + + operations = [ + migrations.AddField( + model_name="pationt", + name="telegramAccount", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="telegrambot.telegramaccount", + ), + ), + migrations.AddField( + model_name="psychiatrist", + name="telegramAccount", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="telegrambot.telegramaccount", + ), + ), + ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 3d11938..98e91a4 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -4,7 +4,7 @@ from django.conf import settings from django.contrib.contenttypes.fields import GenericRelation from django.core.exceptions import ValidationError - +from telegrambot.models import TelegramAccount class Psychiatrist(models.Model ) : TYPE_INDIVIDUAL = 'individual' @@ -18,7 +18,9 @@ class Psychiatrist(models.Model ) : (TYPE_KIDS , "Kids") , (TYPE_TEEN , "Teen") ) + telegramAccount = models.OneToOneField(TelegramAccount , on_delete=models.CASCADE,null=True ,blank=True ) + # telegram account = models.one to one ( telegram account ) user = models.ForeignKey(User, on_delete=models.CASCADE ) image = models.ImageField(upload_to='images/doctors/profile_pics', null=True,blank=True ) #, default='images/doctors/profile_pics/default.png') field = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) @@ -64,8 +66,7 @@ def save(self, *args, **kwargs): class Pationt( models.Model ) : user = models.ForeignKey(User, on_delete=models.CASCADE) - # psychiatrist = models.ManyToManyField(Psychiatrist , through="Reservation" ) - + telegramAccount = models.OneToOneField(TelegramAccount , on_delete=models.CASCADE,null=True , blank=True ) def save(self, *args, **kwargs): """ Check if there's already a Pationt object associated with this User diff --git a/BackEnd/manage.py b/BackEnd/manage.py index 62c39b8..1733f6f 100644 --- a/BackEnd/manage.py +++ b/BackEnd/manage.py @@ -2,6 +2,16 @@ """Django's command-line utility for administrative tasks.""" import os import sys +import multiprocessing +from django.core.management import call_command +from django.core.management.commands.runserver import Command as RunServerCommand +# from django.core.management import execute_from_command_line + +# def run_send_daily_message(): +# """Function to run the send_daily_message management command.""" +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BackEnd.settings") +# from django.core.management import call_command +# call_command("start_bot") def main(): @@ -9,14 +19,44 @@ def main(): os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BackEnd.settings") try: from django.core.management import execute_from_command_line + # send_daily_message_process = multiprocessing.Process(target=run_send_daily_message) + # send_daily_message_process.start() + # execute_from_command_line(sys.argv) + # send_daily_message_process.join() + 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() + + + +# class Command(RunServerCommand): +# def handle(self, *args, **options): +# # Define a function to run your management command +# def run_tasks(): + +# os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'BackEnd.settings') +# call_command('command') + +# # Create a separate process for running the management command +# process = multiprocessing.Process(target=run_tasks) +# process.start() + +# # Run the Django development server as usual +# super().handle(*args, **options) + +# if __name__ == "__main__": +# from django.core.management import execute_from_command_line +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BackEnd.settings") +# print("lsjdfljflf") +# execute_from_command_line(sys.argv) + diff --git a/BackEnd/telegrambot/bot.py b/BackEnd/telegrambot/bot.py new file mode 100644 index 0000000..d3e8ec8 --- /dev/null +++ b/BackEnd/telegrambot/bot.py @@ -0,0 +1,52 @@ +import requests +from .credentials import TELEGRAM_API_URL, URL , TOKEN +from telegram.ext import Updater +import datetime +from reservation.models import Reservation +from datetime import time + +def send_message(method, data): + return requests.post(TELEGRAM_API_URL + method, data) + + +def send_daily_message(context): + """Function to send daily message to all users. + """ + print("here") + reserves = Reservation.objects.all() + # accounts = TelegramAccount.objects.all() + for reserve in reserves : + p = reserve.pationt + d = reserve.psychiatrist + accountP = p.telegramAccount + accountD = d.telegramAccount + doctor_msg = 'شما امروز در ساعت فلان یک ملاقات با بیمار بنام فلان دارید.' + patient_msg = 'شما امروز با دکتر فلانی در زمان فلان یک ملاقات دارید.' + send_message("sendMessage", { + 'chat_id': accountD.chat_id, + 'text': doctor_msg + }) + + send_message("sendMessage", { + 'chat_id': accountP.chat_id, + 'text': patient_msg + }) + +def main(): + # Initialize the updater and job queue + updater = Updater(token=TOKEN , use_context=True) + job_queue = updater.job_queue + + # Add the daily job to the job queue + job_queue.run_daily(send_daily_message, time(hour=8 , minute=0 , second=0), context='your_chat_id') + # Start the bot + updater.start_polling() + updater.idle() + +if __name__ == '__main__': + main() + + + + + diff --git a/BackEnd/telegrambot/credentials.py b/BackEnd/telegrambot/credentials.py index 7e48af8..47c8e2c 100644 --- a/BackEnd/telegrambot/credentials.py +++ b/BackEnd/telegrambot/credentials.py @@ -1,8 +1,8 @@ TOKEN = '6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So' -URL = 'https://0fa4-194-225-232-244.ngrok-free.app/getpost/' +URL = 'https://5065-37-156-155-20.ngrok-free.app/getpost/' TELEGRAM_API_URL = f'https://api.telegram.org/bot{TOKEN}/' # https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://33e3-37-156-157-110.ngrok-free.app -# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://0fa4-194-225-232-244.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file +# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://f96f-194-225-232-203.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file diff --git a/BackEnd/telegrambot/management/__init__.py b/BackEnd/telegrambot/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/telegrambot/management/commands/__init__.py b/BackEnd/telegrambot/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BackEnd/telegrambot/management/commands/start_bot.py b/BackEnd/telegrambot/management/commands/start_bot.py new file mode 100644 index 0000000..2c2884b --- /dev/null +++ b/BackEnd/telegrambot/management/commands/start_bot.py @@ -0,0 +1,66 @@ +import subprocess +from django.core.management.base import BaseCommand +import requests +from telegrambot.credentials import TELEGRAM_API_URL, URL , TOKEN +from telegram.ext import Updater +import datetime +from reservation.models import Reservation +from datetime import time + +class Command(BaseCommand): + __name__ = "command" + help = 'Starts the Telegram bot process' + def handle(self, *args, **options): + updater = Updater(token=TOKEN , use_context=True) + job_queue = updater.job_queue + job_queue.run_daily(self.send_daily_message, time(hour=8 , minute=0 , second=0)) + + updater.start_polling() + updater.idle() + + + def send_message(self, method, data): + return requests.post(TELEGRAM_API_URL + method, data) + + + def send_daily_message(self ): + """Function to send daily message to all users. + """ + print("here") + reserves = Reservation.objects.all() + # accounts = TelegramAccount.objects.all() + for reserve in reserves : + p = reserve.pationt + d = reserve.psychiatrist + accountP = p.telegramAccount + accountD = d.telegramAccount + doctor_msg = 'شما امروز در ساعت فلان یک ملاقات با بیمار بنام فلان دارید.' + patient_msg = 'شما امروز با دکتر فلانی در زمان فلان یک ملاقات دارید.' + self.send_message("sendMessage", { + 'chat_id': accountD.chat_id, + 'text': doctor_msg + }) + + self.send_message("sendMessage", { + 'chat_id': accountP.chat_id, + 'text': patient_msg + }) + +# def main(): +# # Initialize the updater and job queue +# updater = Updater(token=TOKEN , use_context=True) +# job_queue = updater.job_queue + +# # Add the daily job to the job queue +# job_queue.run_daily(send_daily_message, time(hour=8 , minute=0 , second=0), context='your_chat_id') +# # Start the bot +# updater.start_polling() +# updater.idle() + +# if __name__ == '__main__': +# main() + + + + + diff --git a/BackEnd/telegrambot/migrations/0002_remove_telegramaccount_user.py b/BackEnd/telegrambot/migrations/0002_remove_telegramaccount_user.py new file mode 100644 index 0000000..6602853 --- /dev/null +++ b/BackEnd/telegrambot/migrations/0002_remove_telegramaccount_user.py @@ -0,0 +1,14 @@ +# Generated by Django 5.0.3 on 2024-04-14 06:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("telegrambot", "0001_initial"), + ] + + operations = [ + migrations.RemoveField(model_name="telegramaccount", name="user",), + ] diff --git a/BackEnd/telegrambot/models.py b/BackEnd/telegrambot/models.py index 6d7bab3..8bd8402 100644 --- a/BackEnd/telegrambot/models.py +++ b/BackEnd/telegrambot/models.py @@ -1,9 +1,12 @@ +from typing import Iterable from django.db import models from accounts.models import User # Create your models here. class TelegramAccount(models.Model) : - user = models.ForeignKey(User , on_delete=models.CASCADE ) + # user = models.ForeignKey(User , on_delete=models.CASCADE ) is_varify = models.BooleanField(default=False ) chat_id = models.CharField( unique= True , max_length=15 ) varification_code = models.CharField( max_length=4 , blank=True , null=True ) + + \ No newline at end of file diff --git a/BackEnd/telegrambot/views.py b/BackEnd/telegrambot/views.py index 9412bdd..f1e0861 100644 --- a/BackEnd/telegrambot/views.py +++ b/BackEnd/telegrambot/views.py @@ -3,14 +3,18 @@ import requests from django.http import HttpResponse, HttpResponseBadRequest from django.views.decorators.csrf import csrf_exempt -from .credentials import TELEGRAM_API_URL, URL +from .models import TelegramAccount +from .credentials import TELEGRAM_API_URL, URL , TOKEN from accounts.models import User from counseling.models import Pationt, Psychiatrist import utils.email as email_handler from rest_framework.response import Response -from .models import TelegramAccount import random from rest_framework import status +from telegram.ext import Updater , CallbackContext +import datetime +from reservation.models import Reservation +from datetime import time email_pattern = r"email\s*/\s*([^<>@\s]+@[^<>@\s]+\.[^<>@\s]+)" code_pattern = r"code\s*/\s*(\d{4})" @@ -35,8 +39,17 @@ def handle_update(update): if text == "/start": handle_start_command(chat_id) elif text == "/verify": + tel_chat = TelegramAccount.objects.filter( chat_id = chat_id ) + if tel_chat : + if tel_chat.is_varify : + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'این اکانت قبلا تایید شده.' + }) + return Response({"message" : "this email does not exist."} , status=status.HTTP_400_BAD_REQUEST) handle_verify_command(chat_id) else: + handle_other_commands(chat_id, text) def handle_start_command(chat_id): @@ -56,31 +69,74 @@ def handle_other_commands(chat_id ,text ): match_code = re.search(code_pattern, text) if match_email: - user = User.objects.filter(email__iexact = text ).first() + email = match_email.group(1) + print("email ------> " , email ) + user = User.objects.filter(email__iexact = email.strip() ).first() + tel_chat = TelegramAccount.objects.filter( chat_id = chat_id ) + if tel_chat : + if tel_chat.first().is_varify : + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'این اکانت قبلا تایید شده.' + }) + return Response({"message" : "this email does not exist."} , status=status.HTTP_400_BAD_REQUEST) + if not user : send_message("sendMessage", { 'chat_id': chat_id, 'text': 'ایمیل داده شده در میان کاربران موجود نمی باشد. لطفا ایمیل صحیح را وارد نمایید.' }) return Response({"message" : "this email does not exist."} , status=status.HTTP_400_BAD_REQUEST) - else : - tel_account = TelegramAccount.objects.create( - user = user , - varification_code = str(random.randint(1000, 9999)) , - chat_id = chat_id - ) - + + elif ( user.is_email_verified == False) : send_message("sendMessage", { - 'chat_id': chat_id, - 'text': 'کد تایید ارسال شده به ایمیلتان را به صورت روبه رو وارد کنید\n code/ <کد>.' + 'chat_id': chat_id, + 'text': 'ایمیل شما توسط سایت تایید نشده است. لطفا ابتدا ایمیل خود را در سایت کلنیک تایید کنید.' }) + return Response({"message" : "this email does not varifyed in app."} , status=status.HTTP_400_BAD_REQUEST) + + else : + + + acc = TelegramAccount.objects.filter( chat_id = chat_id ) + if not acc.exists() : + verification_code = str(random.randint(1000, 9999)) + tel_account = TelegramAccount.objects.create( + varification_code = verification_code , + chat_id = chat_id + ) + + if user.role == "doctor" : + doctor = Psychiatrist.objects.filter( user == user ) + if not doctor : + return Response({"message" : "there is no doctor with this email ."} , status=status.HTTP_400_BAD_REQUEST) + doctor = doctor.first() + doctor.telegramAccount = tel_account + elif user.role == "user" : + patient = Pationt.objects.filter( user == user ) + if not patient : + return Response({"message" : "there is no patient with this email ."} , status=status.HTTP_400_BAD_REQUEST) + patient = patient.first() + patient.telegramAccount = tel_account + + email_handler.send_telegram_account_verification_message( + subject='تایید اکانت تلگرام' , + recipient_list=[user.email ] , + verification_token= verification_code , + ) + + send_message("sendMessage", { + 'chat_id': chat_id, + 'text': 'کد تایید ارسال شده به ایمیلتان را به صورت روبه رو وارد کنید\n code/ <کد>.' + }) elif match_code: tel_account = TelegramAccount.objects.filter(chat_id = chat_id ).first() if not tel_account : return Response({"message" : "this chat_id is not varified by the Enic bot!"} , status=status.HTTP_400_BAD_REQUEST) else : - if tel_account.varification_code != text : + code = match_code.group(1) + if tel_account.varification_code != code : send_message("sendMessage", { 'chat_id': chat_id, 'text': 'کد وارد شده درست نمی باشد یا با فرمت خواسته شده وارد نشده.' @@ -105,3 +161,7 @@ def handle_other_commands(chat_id ,text ): def send_message(method, data): return requests.post(TELEGRAM_API_URL + method, data) + + + + diff --git a/BackEnd/utils/email.py b/BackEnd/utils/email.py index ac87c69..4328df4 100644 --- a/BackEnd/utils/email.py +++ b/BackEnd/utils/email.py @@ -20,7 +20,7 @@ def send_verification_message(subject, recipient_list, verification_token, regis email.send() -def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries): +def send_forget_password_verification_message(subject, recipient_list, verification_token, verification_tries=None): context = { 'email_verification_token': verification_token, # 'remaining_text': remaining_text, @@ -31,3 +31,6 @@ def send_forget_password_verification_message(subject, recipient_list, verificat email.attach_alternative(html_message, "text/html") email.send() +def send_telegram_account_verification_message(subject, recipient_list, verification_token): + send_forget_password_verification_message( subject= subject , recipient_list= recipient_list , verification_token=verification_token ) + From 03d23b06b0c090cf0e266e9d708d873d35c80e2f Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Wed, 17 Apr 2024 13:56:24 +0330 Subject: [PATCH 41/46] fix/url --- BackEnd/BackEnd/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index d6de530..ef8a81c 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -31,7 +31,7 @@ env.read_env() # Setting Website URL -WEBSITE_URL = 'http://localhost:80ssss00/' #env.str('WEBSITE_URL') +WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') # BASE_URL = 'http://localhost:8000/' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' From 426ea56f61a135610c90f9ddb6aca45684b85e19 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Thu, 18 Apr 2024 01:57:14 +0330 Subject: [PATCH 42/46] feat/glasserTest --- BackEnd/BackEnd/settings.py | 2 +- BackEnd/Profile/views.py | 3 +- BackEnd/TherapyTests/admin.py | 4 +- ...02_glassertest_therapytests_glassertest.py | 42 ++++++++++++ BackEnd/TherapyTests/models.py | 15 ++++- BackEnd/TherapyTests/urls.py | 4 +- BackEnd/TherapyTests/views.py | 64 ++++++++++++++++++- BackEnd/accounts/migrations/0001_initial.py | 5 +- .../0002_alter_user_last_verification_sent.py | 4 +- ..._last_verification_sent_alter_user_role.py | 32 ---------- .../0004_alter_user_last_verification_sent.py | 23 ------- .../0005_alter_user_last_verification_sent.py | 23 ------- BackEnd/utils/therapy_tests.py | 23 ++++++- 13 files changed, 152 insertions(+), 92 deletions(-) create mode 100644 BackEnd/TherapyTests/migrations/0002_glassertest_therapytests_glassertest.py delete mode 100644 BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py delete mode 100644 BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py delete mode 100644 BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py diff --git a/BackEnd/BackEnd/settings.py b/BackEnd/BackEnd/settings.py index df47f6a..0307174 100644 --- a/BackEnd/BackEnd/settings.py +++ b/BackEnd/BackEnd/settings.py @@ -31,7 +31,7 @@ env.read_env() # Setting Website URL -WEBSITE_URL = 'http://localhost:80ssss00/' #env.str('WEBSITE_URL') +WEBSITE_URL = 'http://localhost:8000/' #env.str('WEBSITE_URL') # BASE_URL = 'http://localhost:8000/' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' diff --git a/BackEnd/Profile/views.py b/BackEnd/Profile/views.py index aada713..c9ef431 100644 --- a/BackEnd/Profile/views.py +++ b/BackEnd/Profile/views.py @@ -8,7 +8,6 @@ class Meta: model = Profile fields = '__all__' - class DoctorProfileViewSet(viewsets.ModelViewSet): queryset = Profile.objects.all() serializer_class = DoctorProfileSerializer @@ -22,3 +21,5 @@ def filter_by_profile_type(self, request): return Response(serializer.data) else: return Response({"error": "profile_type parameter is required"}, status=400) + + diff --git a/BackEnd/TherapyTests/admin.py b/BackEnd/TherapyTests/admin.py index 8c38f3f..14ca498 100644 --- a/BackEnd/TherapyTests/admin.py +++ b/BackEnd/TherapyTests/admin.py @@ -1,3 +1,5 @@ from django.contrib import admin - +from .models import TherapyTests , GlasserTest +admin.site.register(TherapyTests) +admin.site.register(GlasserTest) # Register your models here. diff --git a/BackEnd/TherapyTests/migrations/0002_glassertest_therapytests_glassertest.py b/BackEnd/TherapyTests/migrations/0002_glassertest_therapytests_glassertest.py new file mode 100644 index 0000000..64ef32a --- /dev/null +++ b/BackEnd/TherapyTests/migrations/0002_glassertest_therapytests_glassertest.py @@ -0,0 +1,42 @@ +# Generated by Django 5.0.3 on 2024-04-17 20:58 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("TherapyTests", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="GlasserTest", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("love", models.FloatField(default=0.0)), + ("survive", models.FloatField(default=0.0)), + ("freedom", models.FloatField(default=0.0)), + ("power", models.FloatField(default=0.0)), + ("fun", models.FloatField(default=0.0)), + ], + ), + migrations.AddField( + model_name="therapytests", + name="glasserTest", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + to="TherapyTests.glassertest", + ), + ), + ] diff --git a/BackEnd/TherapyTests/models.py b/BackEnd/TherapyTests/models.py index d6d039d..d261630 100644 --- a/BackEnd/TherapyTests/models.py +++ b/BackEnd/TherapyTests/models.py @@ -1,9 +1,22 @@ from django.db import models from counseling.models import Pationt +# نیاز به بقا +# نیاز به عشق و تعلق خاطر +# نیاز به آزادی +# نیاز به قدرت +# نیاز به تفریح + +class GlasserTest(models.Model) : + love = models.FloatField( default=0.0 ) + survive = models.FloatField( default=0.0 ) + freedom = models.FloatField( default=0.0 ) + power = models.FloatField( default=0.0 ) + fun = models.FloatField( default=0.0 ) + class TherapyTests(models.Model) : pationt = models.ForeignKey(Pationt , on_delete=models.CASCADE ) MBTItest = models.CharField( max_length=6 , blank=True ) + glasserTest = models.ForeignKey( GlasserTest , on_delete=models.DO_NOTHING , null=True) - diff --git a/BackEnd/TherapyTests/urls.py b/BackEnd/TherapyTests/urls.py index 6746a6a..1bdab6a 100644 --- a/BackEnd/TherapyTests/urls.py +++ b/BackEnd/TherapyTests/urls.py @@ -2,5 +2,7 @@ from .views import * urlpatterns = [ - path( 'MBTI/' , GetMBTItest.as_view({'post' : 'create' , 'get' : 'retrieve'}) , name='MBTI') , + path( 'MBTI/' , GetMBTItest.as_view({'post' : 'create' , 'get' : 'retrieve'}) , name='MBTI') , + path('glasser/' , GlasserTestView.as_view({'post' : 'create' , 'get' : 'retrieve'}) , name='glasser') , + path('tests/' , ThrepayTestsView.as_view({"get" : "get"}) , name="patient_tests") ] \ No newline at end of file diff --git a/BackEnd/TherapyTests/views.py b/BackEnd/TherapyTests/views.py index b0f4d7f..dc0303a 100644 --- a/BackEnd/TherapyTests/views.py +++ b/BackEnd/TherapyTests/views.py @@ -3,13 +3,71 @@ from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated -from utils.therapy_tests import GetMBTIresults +from utils.therapy_tests import GetMBTIresults ,GlasserResults from counseling.models import Pationt -from .models import TherapyTests +from .models import TherapyTests , GlasserTest from rest_framework import status import json from django.http.request import QueryDict +class ThrepayTestsView(viewsets.ModelViewSet ) : + permission_classes = [IsAuthenticated] + def get( self , request ) : + user = request.user + pationt = Pationt.objects.filter(user = user ).first() + if not pationt : + Response({"message" : "there is not patient"} , status=status.HTTP_400_BAD_REQUEST ) + test = TherapyTests.objects.filter( pationt = pationt ).first() + if not test : + Response({"message" : "this user hasn't take any tests!"} , status=status.HTTP_400_BAD_REQUEST) + + return Response( {"TherapTests" : test} , status=status.HTTP_200_OK ) + + +class GlasserTestView(viewsets.ModelViewSet ) : + permission_classes = [IsAuthenticated] + def create( self, request , *args , **kwargs ) : + req_data = {} + d = request.data["data"] + data = json.loads(d) + for key in data.keys() : + print(data[key]) + req_data[key] = data[key] + data[key] + print( req_data ) + if not req_data : + return Response({"message" : "test's results could not be empty!!!"} , status=status.HTTP_400_BAD_REQUEST) + categories = GlasserResults( data=req_data ) + glasser = GlasserTest.objects.create( + love = categories["love"] , + survive = categories["survive"] , + freedom = categories["freedom"] , + power = categories["power"] , + fun = categories["fun"] + ) + user = request.user + pationt = Pationt.objects.filter(user = user).first() + old_test = TherapyTests.objects.filter( pationt = pationt ).first() + if old_test : + old_test.glasserTest = glasser + old_test.save() + return Response( {'message' : 'test`s results was successfullly updated'} , status=status.HTTP_200_OK ) + else : + test = TherapyTests.objects.create( + pationt = pationt , + glasserTest = glasser + ) + return Response( {'message' : 'test`s results was successfullly registered'} , status=status.HTTP_200_OK ) + + + def retrieve(self, request, *args, **kwargs): + user = request.user + pationt = Pationt.objects.filter(user = user ).first() + print(pationt) + mbti = TherapyTests.objects.filter( pationt = pationt ).first() + return Response( {"glasser" : mbti.glasserTest} , status=status.HTTP_200_OK ) + + class GetMBTItest(viewsets.ModelViewSet) : permission_classes = [IsAuthenticated ] @@ -23,7 +81,7 @@ def create(self, request, *args, **kwargs): user = request.user pationt = Pationt.objects.filter(user = user).first() mbti = GetMBTIresults( data , user.gender ) - print(mbti) + old_test = TherapyTests.objects.filter( pationt = pationt ).first() if old_test : old_test.MBTItest = mbti['final'] diff --git a/BackEnd/accounts/migrations/0001_initial.py b/BackEnd/accounts/migrations/0001_initial.py index a3a6899..c810965 100644 --- a/BackEnd/accounts/migrations/0001_initial.py +++ b/BackEnd/accounts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-08 07:27 +# Generated by Django 5.0.3 on 2024-04-17 20:58 import datetime import django.core.validators @@ -69,7 +69,6 @@ class Migration(migrations.Migration): ], default="user", max_length=255, - unique=True, ), ), ("is_email_verified", models.BooleanField(default=False)), @@ -82,7 +81,7 @@ class Migration(migrations.Migration): "last_verification_sent", models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 8, 10, 57, 32, 809243), + default=datetime.datetime(2024, 4, 18, 0, 28, 53, 286324), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py index db31cb6..5ea25dc 100644 --- a/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py +++ b/BackEnd/accounts/migrations/0002_alter_user_last_verification_sent.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-04-08 07:28 +# Generated by Django 5.0.3 on 2024-04-17 20:58 import datetime from django.db import migrations, models @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name="last_verification_sent", field=models.DateTimeField( blank=True, - default=datetime.datetime(2024, 4, 8, 10, 58, 5, 142932), + default=datetime.datetime(2024, 4, 18, 0, 28, 58, 537727), null=True, ), ), diff --git a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py deleted file mode 100644 index ad9f85b..0000000 --- a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent_alter_user_role.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-09 06:20 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0002_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 4, 9, 9, 49, 59, 946301), - null=True, - ), - ), - migrations.AlterField( - model_name="user", - name="role", - field=models.CharField( - choices=[("user", "User"), ("doctor", "Doctor"), ("admin", "Admin")], - default="user", - max_length=255, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py deleted file mode 100644 index 2812bc1..0000000 --- a/BackEnd/accounts/migrations/0004_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-10 18:33 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0003_alter_user_last_verification_sent_alter_user_role"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 4, 10, 22, 3, 26, 462247), - null=True, - ), - ), - ] diff --git a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py deleted file mode 100644 index e3cd8cf..0000000 --- a/BackEnd/accounts/migrations/0005_alter_user_last_verification_sent.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.0.3 on 2024-04-10 18:35 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0004_alter_user_last_verification_sent"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="last_verification_sent", - field=models.DateTimeField( - blank=True, - default=datetime.datetime(2024, 4, 10, 22, 5, 47, 853997), - null=True, - ), - ), - ] diff --git a/BackEnd/utils/therapy_tests.py b/BackEnd/utils/therapy_tests.py index 88cb95f..92ebabc 100644 --- a/BackEnd/utils/therapy_tests.py +++ b/BackEnd/utils/therapy_tests.py @@ -1,4 +1,25 @@ -# create mbti tests + +def GlasserResults(data ) : + # data = { + # 1 : { + # "category" : 2 , + # "res" : 4 + # }, + # 2 : { + # "category" : 2 , + # "res" : 4 + # } + # } + + categories_score = {} + for value in data.values() : + if value["category"] not in categories_score.keys() : + categories_score[ value["category"]] = value["res"] + else : + categories_score[ value["category"]] += value["res"] + return categories_score + + def GetMBTIresults(data, gender ) : colomn1 = [ data[7*i + 1] for i in range(10)] colomn2 = [ data[7*i + 2] for i in range(10)] From ee96234e7cf8321d181f6ecbd12d3bf29e7a8229 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 19 Apr 2024 11:59:05 +0330 Subject: [PATCH 43/46] fix/telNotif --- ...gramaccount_alter_pationt_user_and_more.py | 46 ++++++++++++ .../0004_alter_psychiatrist_user.py | 28 +++++++ BackEnd/counseling/models.py | 21 +++--- ...er_reservation_unique_together_and_more.py | 35 +++++++++ BackEnd/reservation/models.py | 45 ++++++++--- BackEnd/telegrambot/credentials.py | 4 +- .../management/commands/start_bot.py | 75 ++++++++----------- BackEnd/telegrambot/views.py | 25 ++++--- 8 files changed, 203 insertions(+), 76 deletions(-) create mode 100644 BackEnd/counseling/migrations/0003_alter_pationt_telegramaccount_alter_pationt_user_and_more.py create mode 100644 BackEnd/counseling/migrations/0004_alter_psychiatrist_user.py create mode 100644 BackEnd/reservation/migrations/0004_alter_reservation_unique_together_and_more.py diff --git a/BackEnd/counseling/migrations/0003_alter_pationt_telegramaccount_alter_pationt_user_and_more.py b/BackEnd/counseling/migrations/0003_alter_pationt_telegramaccount_alter_pationt_user_and_more.py new file mode 100644 index 0000000..c7ff48c --- /dev/null +++ b/BackEnd/counseling/migrations/0003_alter_pationt_telegramaccount_alter_pationt_user_and_more.py @@ -0,0 +1,46 @@ +# Generated by Django 5.0.3 on 2024-04-18 07:47 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0002_pationt_telegramaccount_psychiatrist_telegramaccount"), + ("telegrambot", "0002_remove_telegramaccount_user"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name="pationt", + name="telegramAccount", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="telegrambot.telegramaccount", + ), + ), + migrations.AlterField( + model_name="pationt", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + unique=True, + ), + ), + migrations.AlterField( + model_name="psychiatrist", + name="telegramAccount", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="telegrambot.telegramaccount", + ), + ), + ] diff --git a/BackEnd/counseling/migrations/0004_alter_psychiatrist_user.py b/BackEnd/counseling/migrations/0004_alter_psychiatrist_user.py new file mode 100644 index 0000000..b1ce41d --- /dev/null +++ b/BackEnd/counseling/migrations/0004_alter_psychiatrist_user.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0.3 on 2024-04-18 07:49 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ( + "counseling", + "0003_alter_pationt_telegramaccount_alter_pationt_user_and_more", + ), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name="psychiatrist", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + unique=True, + ), + ), + ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 98e91a4..26fc6ad 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -21,7 +21,7 @@ class Psychiatrist(models.Model ) : telegramAccount = models.OneToOneField(TelegramAccount , on_delete=models.CASCADE,null=True ,blank=True ) # telegram account = models.one to one ( telegram account ) - user = models.ForeignKey(User, on_delete=models.CASCADE ) + user = models.ForeignKey(User, on_delete=models.CASCADE , unique=True ) image = models.ImageField(upload_to='images/doctors/profile_pics', null=True,blank=True ) #, default='images/doctors/profile_pics/default.png') field = models.CharField( max_length=255, choices=CHOICES , default=TYPE_USER) @@ -50,13 +50,8 @@ def save(self, *args, **kwargs): """ Check if there's already a Psychiatrist object associated with this User """ - if self.user.role == 'doctor' : - return super().save(*args, **kwargs) - if Psychiatrist.objects.filter(user=self.user).exists(): - raise ValidationError("A Psychiatrist object already exists for this User.") if Pationt.objects.filter(user=self.user).exists() : - pationt = Pationt.objects.get(user=self.user) - pationt.delete() + raise ValidationError("a patient could not be register as a doctor") if not self.user.role == 'doctor': self.user.role = User.TYPE_DOCTOR self.user.save() @@ -65,15 +60,19 @@ def save(self, *args, **kwargs): class Pationt( models.Model ) : - user = models.ForeignKey(User, on_delete=models.CASCADE) + user = models.ForeignKey(User, on_delete=models.CASCADE , unique=True ) telegramAccount = models.OneToOneField(TelegramAccount , on_delete=models.CASCADE,null=True , blank=True ) def save(self, *args, **kwargs): """ Check if there's already a Pationt object associated with this User """ - if Pationt.objects.filter(user=self.user).exists(): - raise ValidationError("A Pationt object already exists for this User.") - super().save(*args, **kwargs) + # if Pationt.objects.filter(user=self.user).exists() and self.user.role == User.TYPE_USER : + # return super().save(*args, **kwargs) + # if Pationt.objects.filter(user=self.user).exists() : + # raise ValidationError("A Pationt object already exists for this User.") + if Psychiatrist.objects.filter(user=self.user).exists() : + raise ValidationError("a doctor could not be register as a patient") + return super().save(*args, **kwargs) diff --git a/BackEnd/reservation/migrations/0004_alter_reservation_unique_together_and_more.py b/BackEnd/reservation/migrations/0004_alter_reservation_unique_together_and_more.py new file mode 100644 index 0000000..99faccf --- /dev/null +++ b/BackEnd/reservation/migrations/0004_alter_reservation_unique_together_and_more.py @@ -0,0 +1,35 @@ +# Generated by Django 5.0.3 on 2024-04-18 10:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0004_alter_psychiatrist_user"), + ("reservation", "0003_alter_reservation_type"), + ] + + operations = [ + migrations.AlterUniqueTogether( + name="reservation", + unique_together={("date", "time", "pationt", "psychiatrist")}, + ), + migrations.AlterField( + model_name="reservation", + name="day", + field=models.CharField( + blank=True, + choices=[ + ("شنبه", "شنبه"), + ("یکشنبه", "یک\u200cشنبه"), + ("دوشنبه", "دو\u200cشنبه"), + ("سه\u200cشنبه", "سه\u200cشنبه"), + ("چهارشنبه", "چهار\u200cشنبه"), + ("پنج\u200cشنبه", "پنج\u200cشنبه"), + ("جمعه", "جمعه"), + ], + max_length=10, + ), + ), + ] diff --git a/BackEnd/reservation/models.py b/BackEnd/reservation/models.py index f40b436..557d85a 100644 --- a/BackEnd/reservation/models.py +++ b/BackEnd/reservation/models.py @@ -4,19 +4,29 @@ from datetime import date class Reservation(models.Model) : + DAY0 = 'شنبه' + DAY1 = 'یکشنبه' + DAY2 = 'دوشنبه' + DAY3 = 'سه‌شنبه' + DAY4 = 'چهارشنبه' + DAY5 = 'پنج‌شنبه' + DAY6 = 'جمعه' + DAY_CHOICES = [ - ('شنبه', 'شنبه'), - ('یک‌شنبه', 'یک‌شنبه'), - ('دو‌شنبه', 'دو‌شنبه'), - ('سه‌شنبه', 'سه‌شنبه'), - ('چهار‌شنبه', 'چهار‌شنبه'), - ('پنج‌شنبه', 'پنج‌شنبه'), - ('جمعه', 'جمعه'), + (DAY0 , 'شنبه' ), + ( DAY1, 'یک‌شنبه'), + ( DAY2 ,'دو‌شنبه'), + (DAY3 ,'سه‌شنبه'), + (DAY4 ,'چهار‌شنبه'), + (DAY5 , 'پنج‌شنبه'), + (DAY6 ,'جمعه') ] + REMOTE = 'مجازی' + INPERSON = 'حضوری' RESERVE_CHOICES = [ - ('حضوری' , 'حضوری') , - ( 'مجازی' , 'مجازی') + (INPERSON , 'حضوری') , + ( REMOTE , 'مجازی') ] psychiatrist = models.ForeignKey(Psychiatrist, on_delete=models.CASCADE, related_name='psychiatrist_reservations') @@ -27,7 +37,7 @@ class Reservation(models.Model) : day = models.CharField(max_length=10, choices=DAY_CHOICES , blank=True ) class Meta: - unique_together = ['date', 'time'] + unique_together = ['date', 'time' , 'pationt' , 'psychiatrist'] def save(self, *args, **kwargs) : day_dict = { @@ -42,5 +52,18 @@ def save(self, *args, **kwargs) : if not self.day: day_num = date.today().weekday() - self.day = day_dict[day_num] + if day_dict[day_num] == self.DAY0 : + self.day = self.DAY0 + elif day_dict[day_num] == self.DAY1 : + self.day = self.DAY1 + elif day_dict[day_num] == self.DAY2 : + self.day = self.DAY2 + elif day_dict[day_num] == self.DAY3 : + self.day = self.DAY3 + elif day_dict[day_num] == self.DAY4 : + self.day = self.DAY4 + elif day_dict[day_num] == self.DAY5 : + self.day = self.DAY5 + else : + self.day = self.DAY6 return super().save() \ No newline at end of file diff --git a/BackEnd/telegrambot/credentials.py b/BackEnd/telegrambot/credentials.py index 47c8e2c..00e05ad 100644 --- a/BackEnd/telegrambot/credentials.py +++ b/BackEnd/telegrambot/credentials.py @@ -1,8 +1,8 @@ TOKEN = '6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So' -URL = 'https://5065-37-156-155-20.ngrok-free.app/getpost/' +URL = 'https://8417-194-225-232-94.ngrok-free.app/getpost/' TELEGRAM_API_URL = f'https://api.telegram.org/bot{TOKEN}/' # https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://33e3-37-156-157-110.ngrok-free.app -# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://f96f-194-225-232-203.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file +# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://8417-194-225-232-94.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file diff --git a/BackEnd/telegrambot/management/commands/start_bot.py b/BackEnd/telegrambot/management/commands/start_bot.py index 2c2884b..80f17b9 100644 --- a/BackEnd/telegrambot/management/commands/start_bot.py +++ b/BackEnd/telegrambot/management/commands/start_bot.py @@ -8,57 +8,48 @@ from datetime import time class Command(BaseCommand): - __name__ = "command" + __name__ = "start_bot" help = 'Starts the Telegram bot process' def handle(self, *args, **options): - updater = Updater(token=TOKEN , use_context=True) - job_queue = updater.job_queue - job_queue.run_daily(self.send_daily_message, time(hour=8 , minute=0 , second=0)) - - updater.start_polling() - updater.idle() - + q = Reservation.objects.all() + # updater = Updater(TOKEN) #token=TOKEN , use_context=True + # job_queue = updater.job_queue + # job_queue.run_daily(self.send_daily_message, time(hour=13 , minute=0 , second=0)) + self.send_daily_message() + # updater.start_polling() + # updater.idle() def send_message(self, method, data): return requests.post(TELEGRAM_API_URL + method, data) - def send_daily_message(self ): """Function to send daily message to all users. """ - print("here") - reserves = Reservation.objects.all() - # accounts = TelegramAccount.objects.all() - for reserve in reserves : - p = reserve.pationt - d = reserve.psychiatrist - accountP = p.telegramAccount - accountD = d.telegramAccount - doctor_msg = 'شما امروز در ساعت فلان یک ملاقات با بیمار بنام فلان دارید.' - patient_msg = 'شما امروز با دکتر فلانی در زمان فلان یک ملاقات دارید.' - self.send_message("sendMessage", { - 'chat_id': accountD.chat_id, - 'text': doctor_msg - }) - - self.send_message("sendMessage", { - 'chat_id': accountP.chat_id, - 'text': patient_msg - }) - -# def main(): -# # Initialize the updater and job queue -# updater = Updater(token=TOKEN , use_context=True) -# job_queue = updater.job_queue - -# # Add the daily job to the job queue -# job_queue.run_daily(send_daily_message, time(hour=8 , minute=0 , second=0), context='your_chat_id') -# # Start the bot -# updater.start_polling() -# updater.idle() - -# if __name__ == '__main__': -# main() + today = datetime.date.today() + reserves = Reservation.objects.filter( date = today ) + if reserves.exists() : + for reserve in reserves : + p = reserve.pationt + d = reserve.psychiatrist + accountP = p.telegramAccount + accountD = d.telegramAccount + + if accountD : + doctor_msg = f'شما امروز یک رزرو با اطلاعات زیر دارید.\n زمان :{reserve.time} ' + + self.send_message("sendMessage", { + 'chat_id': accountD.chat_id, + 'text': doctor_msg + }) + if accountP : + print("doctor account : " , accountP.chat_id) + patient_msg = f'پیام یادآوری: \n نوبت رزرو شده شامل اطلاعات زیر است : \n زمان : {reserve.time} \n دکتر : {d.get_fullname()}' + self.send_message("sendMessage", { + 'chat_id': accountP.chat_id, + 'text': patient_msg + }) + else : + print("there is no reservation") diff --git a/BackEnd/telegrambot/views.py b/BackEnd/telegrambot/views.py index f1e0861..8be7c28 100644 --- a/BackEnd/telegrambot/views.py +++ b/BackEnd/telegrambot/views.py @@ -35,11 +35,11 @@ def telegram_bot(request): def handle_update(update): chat_id = update['message']['chat']['id'] text = update['message']['text'] - + print( "chat id ----------------> " , chat_id ) if text == "/start": handle_start_command(chat_id) elif text == "/verify": - tel_chat = TelegramAccount.objects.filter( chat_id = chat_id ) + tel_chat = TelegramAccount.objects.filter( chat_id = chat_id ).first() if tel_chat : if tel_chat.is_varify : send_message("sendMessage", { @@ -67,11 +67,7 @@ def handle_verify_command(chat_id): def handle_other_commands(chat_id ,text ): match_email = re.search(email_pattern, text) match_code = re.search(code_pattern, text) - - if match_email: - email = match_email.group(1) - print("email ------> " , email ) - user = User.objects.filter(email__iexact = email.strip() ).first() + if match_email or match_code : tel_chat = TelegramAccount.objects.filter( chat_id = chat_id ) if tel_chat : if tel_chat.first().is_varify : @@ -81,6 +77,11 @@ def handle_other_commands(chat_id ,text ): }) return Response({"message" : "this email does not exist."} , status=status.HTTP_400_BAD_REQUEST) + if match_email: + email = match_email.group(1) + print("email ------> " , email ) + user = User.objects.filter(email__iexact = email.strip() ).first() + if not user : send_message("sendMessage", { 'chat_id': chat_id, @@ -107,24 +108,28 @@ def handle_other_commands(chat_id ,text ): ) if user.role == "doctor" : - doctor = Psychiatrist.objects.filter( user == user ) + doctor = Psychiatrist.objects.filter( user = user ) if not doctor : return Response({"message" : "there is no doctor with this email ."} , status=status.HTTP_400_BAD_REQUEST) doctor = doctor.first() doctor.telegramAccount = tel_account elif user.role == "user" : - patient = Pationt.objects.filter( user == user ) + patient = Pationt.objects.filter( user = user ) + print("117") if not patient : return Response({"message" : "there is no patient with this email ."} , status=status.HTTP_400_BAD_REQUEST) patient = patient.first() + print( patient.pk) patient.telegramAccount = tel_account + patient.save() + print("118") email_handler.send_telegram_account_verification_message( subject='تایید اکانت تلگرام' , recipient_list=[user.email ] , verification_token= verification_code , ) - + print("128") send_message("sendMessage", { 'chat_id': chat_id, 'text': 'کد تایید ارسال شده به ایمیلتان را به صورت روبه رو وارد کنید\n code/ <کد>.' From ad387e2cec21a9c4640a34f5e97a41709288bc7c Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 19 Apr 2024 12:20:12 +0330 Subject: [PATCH 44/46] fix/doctorChoices --- .../0003_alter_user_last_verification_sent.py | 23 ++++++++++++++++ .../0004_alter_psychiatrist_field.py | 27 +++++++++++++++++++ .../0005_alter_psychiatrist_field.py | 27 +++++++++++++++++++ BackEnd/counseling/models.py | 16 +++++------ 4 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py create mode 100644 BackEnd/counseling/migrations/0004_alter_psychiatrist_field.py create mode 100644 BackEnd/counseling/migrations/0005_alter_psychiatrist_field.py diff --git a/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py new file mode 100644 index 0000000..13d3f2d --- /dev/null +++ b/BackEnd/accounts/migrations/0003_alter_user_last_verification_sent.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.3 on 2024-04-19 08:49 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0002_alter_user_last_verification_sent"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="last_verification_sent", + field=models.DateTimeField( + blank=True, + default=datetime.datetime(2024, 4, 19, 12, 19, 51, 747477), + null=True, + ), + ), + ] diff --git a/BackEnd/counseling/migrations/0004_alter_psychiatrist_field.py b/BackEnd/counseling/migrations/0004_alter_psychiatrist_field.py new file mode 100644 index 0000000..c47cea3 --- /dev/null +++ b/BackEnd/counseling/migrations/0004_alter_psychiatrist_field.py @@ -0,0 +1,27 @@ +# Generated by Django 5.0.3 on 2024-04-19 08:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0003_alter_psychiatrist_image"), + ] + + operations = [ + migrations.AlterField( + model_name="psychiatrist", + name="field", + field=models.CharField( + choices=[ + ("individual", "فردی"), + ("couples", "زوج"), + ("kids", "کودک"), + ("teen", "نوجوان"), + ], + default="defualt", + max_length=255, + ), + ), + ] diff --git a/BackEnd/counseling/migrations/0005_alter_psychiatrist_field.py b/BackEnd/counseling/migrations/0005_alter_psychiatrist_field.py new file mode 100644 index 0000000..3e7e1ce --- /dev/null +++ b/BackEnd/counseling/migrations/0005_alter_psychiatrist_field.py @@ -0,0 +1,27 @@ +# Generated by Django 5.0.3 on 2024-04-19 08:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("counseling", "0004_alter_psychiatrist_field"), + ] + + operations = [ + migrations.AlterField( + model_name="psychiatrist", + name="field", + field=models.CharField( + choices=[ + ("فردی", "فردی"), + ("زوج", "زوج"), + ("کودک", "کودک"), + ("نوجوان", "نوجوان"), + ], + default="defualt", + max_length=255, + ), + ), + ] diff --git a/BackEnd/counseling/models.py b/BackEnd/counseling/models.py index 0ef1a6a..67abd75 100644 --- a/BackEnd/counseling/models.py +++ b/BackEnd/counseling/models.py @@ -6,16 +6,16 @@ from django.core.exceptions import ValidationError class Psychiatrist(models.Model ) : - TYPE_INDIVIDUAL = 'individual' - TYPE_KIDS = "kids" - TYPE_COUPLES = "couples" - TYPE_TEEN = "teen" + TYPE_INDIVIDUAL = "فردی" + TYPE_KIDS = "کودک" + TYPE_COUPLES = "زوج" + TYPE_TEEN = "نوجوان" TYPE_USER = "defualt" CHOICES = ( - (TYPE_INDIVIDUAL , "Individual") , - (TYPE_COUPLES , "Couples") , - (TYPE_KIDS , "Kids") , - (TYPE_TEEN , "Teen") + (TYPE_INDIVIDUAL , "فردی") , + (TYPE_COUPLES , "زوج") , + (TYPE_KIDS , "کودک") , + (TYPE_TEEN , "نوجوان") ) user = models.ForeignKey(User, on_delete=models.CASCADE ) From cb6d6a7060796f9faecbdb9fe31df27b2a122313 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 19 Apr 2024 13:35:45 +0330 Subject: [PATCH 45/46] fix/telegramNotif --- BackEnd/accounts/views.py | 1 + BackEnd/telegrambot/credentials.py | 8 ++++---- BackEnd/telegrambot/urls.py | 4 +++- BackEnd/telegrambot/views.py | 7 ++++++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/BackEnd/accounts/views.py b/BackEnd/accounts/views.py index 2c6ec30..6268d60 100644 --- a/BackEnd/accounts/views.py +++ b/BackEnd/accounts/views.py @@ -262,6 +262,7 @@ def post(self, request, *args, **kwargs): class RetrieveUserData(GenericAPIView) : permission_classes = [IsAuthenticated] + serializer_class = UserSerializer def get(self , request ) : print( request.headers["Authorization"] ) if not hasattr(request, 'user'): diff --git a/BackEnd/telegrambot/credentials.py b/BackEnd/telegrambot/credentials.py index 00e05ad..c47eef1 100644 --- a/BackEnd/telegrambot/credentials.py +++ b/BackEnd/telegrambot/credentials.py @@ -1,8 +1,8 @@ TOKEN = '6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So' - -URL = 'https://8417-194-225-232-94.ngrok-free.app/getpost/' +NGROK = 'https://a882-37-44-62-110.ngrok-free.app' +URL = f'{NGROK}/getpost/' TELEGRAM_API_URL = f'https://api.telegram.org/bot{TOKEN}/' - +WEB_HOOK_URL = f'{TELEGRAM_API_URL}/setWebhook?url={NGROK}/telegrambot/getpost/' # https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://33e3-37-156-157-110.ngrok-free.app -# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://8417-194-225-232-94.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file +# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://a882-37-44-62-110.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file diff --git a/BackEnd/telegrambot/urls.py b/BackEnd/telegrambot/urls.py index fd09b1b..9205ab7 100644 --- a/BackEnd/telegrambot/urls.py +++ b/BackEnd/telegrambot/urls.py @@ -1,8 +1,10 @@ from django.urls import path from . import views + urlpatterns = [ path('getpost/', views.telegram_bot, name='telegram_bot'), - # path('setwebhook/', views.setwebhook, name='setwebhook'), + path('setwebhook/', views.setwebhook, name='setwebhook'), ] +# telegrambot/setwebhook/ \ No newline at end of file diff --git a/BackEnd/telegrambot/views.py b/BackEnd/telegrambot/views.py index 8be7c28..e84d80a 100644 --- a/BackEnd/telegrambot/views.py +++ b/BackEnd/telegrambot/views.py @@ -4,7 +4,7 @@ from django.http import HttpResponse, HttpResponseBadRequest from django.views.decorators.csrf import csrf_exempt from .models import TelegramAccount -from .credentials import TELEGRAM_API_URL, URL , TOKEN +from .credentials import TELEGRAM_API_URL, URL , TOKEN , WEB_HOOK_URL from accounts.models import User from counseling.models import Pationt, Psychiatrist import utils.email as email_handler @@ -164,6 +164,11 @@ def handle_other_commands(chat_id ,text ): }) +def setwebhook(request) : + if request.method == 'GET' : + return requests.get(url=WEB_HOOK_URL ) + + def send_message(method, data): return requests.post(TELEGRAM_API_URL + method, data) From 19bd204d42b632344c506a9e6e118063dc91eaa7 Mon Sep 17 00:00:00 2001 From: zahra alizadeh Date: Fri, 19 Apr 2024 13:36:57 +0330 Subject: [PATCH 46/46] fix/telegramNotif --- BackEnd/telegrambot/credentials.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BackEnd/telegrambot/credentials.py b/BackEnd/telegrambot/credentials.py index c47eef1..591045e 100644 --- a/BackEnd/telegrambot/credentials.py +++ b/BackEnd/telegrambot/credentials.py @@ -5,4 +5,5 @@ WEB_HOOK_URL = f'{TELEGRAM_API_URL}/setWebhook?url={NGROK}/telegrambot/getpost/' # https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://33e3-37-156-157-110.ngrok-free.app -# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://a882-37-44-62-110.ngrok-free.app/telegrambot/getpost/ \ No newline at end of file +# https://api.telegram.org/bot6800635126:AAGV8Ev4Wf4qsq4lPa-Vm-dcYNsoQ19h1So/setWebhook?url=https://a882-37-44-62-110.ngrok-free.app/telegrambot/getpost/ +# /////////// \ No newline at end of file