From f42a4e31022afa63c4352cff2e53cc77bde143eb Mon Sep 17 00:00:00 2001 From: Neeraj Belsare Date: Tue, 9 Jan 2024 23:52:39 +0530 Subject: [PATCH] API Secrets migrated to AWS --- .gitignore | 6 +- .idea/aws.xml | 3 + .idea/dataSources.xml | 14 +- .idea/sqldialects.xml | 6 + .../Other_Logos_SVG/Apple_logo_black.svg | 0 .../Other_Logos_SVG/Google__G__Logo.svg | 0 .../Other_Logos_SVG/Logo_of_Twitter.svg | 0 .../Logo - Blue Ecstacy.png | Bin .../Logo - Blue Ecstacy.svg | 0 .../Gradient - Cyan Montage.svg | 0 .../Logo - Cyan Montage.png | Bin .../Logo - Purple Satire.png | Bin .../Logo - Purple Satire.svg | 0 .../Logo - Gradient Amethyst No BG.svg | 0 .../Logo - Radiant Amethyst No BG.png | Bin .../Logo - Radiant Amethyst Square.png | Bin .../Logo - Radiant Amethyst.png | Bin .../Logo - Radiant Amethyst.svg | 0 .../Normal - Black/Logo - Normal Black.png | Bin .../Normal - Black/Logo - Normal Black.svg | 0 .../Normal - White/Logo - Normal White.png | Bin .../Normal - White/Logo - Normal White.svg | 0 backend/.idea/.gitignore | 8 - backend/.idea/backend.iml | 28 -- .../inspectionProfiles/profiles_settings.xml | 6 - backend/.idea/misc.xml | 4 - backend/.idea/modules.xml | 8 - backend/Pipfile | 13 - backend/Pipfile.lock | 76 ----- backend/{auth/migrations => }/__init__.py | 0 .../{backend => auth/accounts}/__init__.py | 0 backend/auth/accounts/admin.py | 3 + backend/auth/accounts/apps.py | 6 + .../auth/accounts/migrations/0001_initial.py | 40 +++ backend/auth/accounts/migrations/__init__.py | 0 backend/auth/{ => accounts}/models.py | 1 - backend/auth/accounts/serializers.py | 22 ++ backend/auth/{ => accounts}/tests.py | 0 backend/auth/accounts/views.py | 3 + backend/auth/admin.py | 75 ----- backend/auth/apps.py | 6 - backend/auth/auth/__init__.py | 0 backend/{backend => auth/auth}/asgi.py | 6 +- backend/auth/auth/settings.py | 204 +++++++++++++ backend/auth/auth/urls.py | 10 + backend/{backend => auth/auth}/wsgi.py | 6 +- backend/{ => auth}/manage.py | 4 +- backend/auth/migrations/0001_initial.py | 56 ---- backend/auth/renderers.py | 15 - backend/auth/serializers.py | 143 --------- backend/auth/urls.py | 26 -- backend/auth/utils.py | 14 - backend/auth/views.py | 107 ------- backend/backend/settings.py | 165 ----------- backend/backend/urls.py | 8 - backend/db.sqlite3 | Bin 131072 -> 0 bytes backend/oauth/manage.py | 22 ++ backend/oauth/oauth/__init__.py | 0 backend/oauth/oauth/asgi.py | 16 ++ backend/oauth/oauth/settings.py | 141 +++++++++ backend/oauth/oauth/urls.py | 13 + backend/oauth/oauth/views.py | 0 backend/oauth/oauth/wsgi.py | 16 ++ backend/oauth/requirements.txt | Bin 0 -> 1080 bytes frontend/package-lock.json | 225 ++++++++++----- frontend/package.json | 8 +- frontend/src/App.jsx | 11 +- frontend/src/app/store.jsx | 26 +- frontend/src/pages/Login/Login.jsx | 52 +++- frontend/src/pages/Signup/SignupScreen.jsx | 25 -- frontend/src/services/actions/auth.js | 271 ++++++++++++++++++ frontend/src/services/actions/types.js | 19 ++ frontend/src/services/reducers/auth.js | 96 +++++++ frontend/src/services/reducers/index.js | 6 + 74 files changed, 1136 insertions(+), 903 deletions(-) create mode 100644 .idea/sqldialects.xml rename {Assets => assets}/Other_Logos_SVG/Apple_logo_black.svg (100%) rename {Assets => assets}/Other_Logos_SVG/Google__G__Logo.svg (100%) rename {Assets => assets}/Other_Logos_SVG/Logo_of_Twitter.svg (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.svg (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Cyan Montage/Gradient - Cyan Montage.svg (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Cyan Montage/Logo - Cyan Montage.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.svg (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Gradient Amethyst No BG.svg (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst No BG.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst Square.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.svg (100%) rename {Assets => assets}/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.svg (100%) rename {Assets => assets}/Website Logo/All Schemes/Normal - White/Logo - Normal White.png (100%) rename {Assets => assets}/Website Logo/All Schemes/Normal - White/Logo - Normal White.svg (100%) delete mode 100644 backend/.idea/.gitignore delete mode 100644 backend/.idea/backend.iml delete mode 100644 backend/.idea/inspectionProfiles/profiles_settings.xml delete mode 100644 backend/.idea/misc.xml delete mode 100644 backend/.idea/modules.xml delete mode 100644 backend/Pipfile delete mode 100644 backend/Pipfile.lock rename backend/{auth/migrations => }/__init__.py (100%) rename backend/{backend => auth/accounts}/__init__.py (100%) create mode 100644 backend/auth/accounts/admin.py create mode 100644 backend/auth/accounts/apps.py create mode 100644 backend/auth/accounts/migrations/0001_initial.py create mode 100644 backend/auth/accounts/migrations/__init__.py rename backend/auth/{ => accounts}/models.py (99%) create mode 100644 backend/auth/accounts/serializers.py rename backend/auth/{ => accounts}/tests.py (100%) create mode 100644 backend/auth/accounts/views.py delete mode 100644 backend/auth/admin.py delete mode 100644 backend/auth/apps.py create mode 100644 backend/auth/auth/__init__.py rename backend/{backend => auth/auth}/asgi.py (58%) create mode 100644 backend/auth/auth/settings.py create mode 100644 backend/auth/auth/urls.py rename backend/{backend => auth/auth}/wsgi.py (58%) rename backend/{ => auth}/manage.py (85%) delete mode 100644 backend/auth/migrations/0001_initial.py delete mode 100644 backend/auth/renderers.py delete mode 100644 backend/auth/serializers.py delete mode 100644 backend/auth/urls.py delete mode 100644 backend/auth/utils.py delete mode 100644 backend/auth/views.py delete mode 100644 backend/backend/settings.py delete mode 100644 backend/backend/urls.py delete mode 100644 backend/db.sqlite3 create mode 100644 backend/oauth/manage.py create mode 100644 backend/oauth/oauth/__init__.py create mode 100644 backend/oauth/oauth/asgi.py create mode 100644 backend/oauth/oauth/settings.py create mode 100644 backend/oauth/oauth/urls.py create mode 100644 backend/oauth/oauth/views.py create mode 100644 backend/oauth/oauth/wsgi.py create mode 100644 backend/oauth/requirements.txt create mode 100644 frontend/src/services/actions/auth.js create mode 100644 frontend/src/services/actions/types.js create mode 100644 frontend/src/services/reducers/auth.js create mode 100644 frontend/src/services/reducers/index.js diff --git a/.gitignore b/.gitignore index 24cdedf..278b124 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies -/node_modules +/frontend/node_modules /.pnp .pnp.js @@ -20,4 +20,6 @@ npm-debug.log* yarn-debug.log* -yarn-error.log* \ No newline at end of file +yarn-error.log* +/backend/auth/auth/secrets.py +/.env diff --git a/.idea/aws.xml b/.idea/aws.xml index f466e13..c269cc9 100644 --- a/.idea/aws.xml +++ b/.idea/aws.xml @@ -15,4 +15,7 @@ + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index b29ee76..c28448c 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -1,13 +1,19 @@ - - sqlite.xerial + + postgresql true - org.sqlite.JDBC - jdbc:sqlite:E:\Schwarz\backend\db.sqlite3 + org.postgresql.Driver + jdbc:postgresql://localhost:5432/postgres + + + + + + $ProjectFileDir$ diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..6df4889 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Assets/Other_Logos_SVG/Apple_logo_black.svg b/assets/Other_Logos_SVG/Apple_logo_black.svg similarity index 100% rename from Assets/Other_Logos_SVG/Apple_logo_black.svg rename to assets/Other_Logos_SVG/Apple_logo_black.svg diff --git a/Assets/Other_Logos_SVG/Google__G__Logo.svg b/assets/Other_Logos_SVG/Google__G__Logo.svg similarity index 100% rename from Assets/Other_Logos_SVG/Google__G__Logo.svg rename to assets/Other_Logos_SVG/Google__G__Logo.svg diff --git a/Assets/Other_Logos_SVG/Logo_of_Twitter.svg b/assets/Other_Logos_SVG/Logo_of_Twitter.svg similarity index 100% rename from Assets/Other_Logos_SVG/Logo_of_Twitter.svg rename to assets/Other_Logos_SVG/Logo_of_Twitter.svg diff --git a/Assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.png b/assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.png similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.png rename to assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.png diff --git a/Assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.svg b/assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.svg similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.svg rename to assets/Website Logo/All Schemes/Gradient - Blue Ecstacy/Logo - Blue Ecstacy.svg diff --git a/Assets/Website Logo/All Schemes/Gradient - Cyan Montage/Gradient - Cyan Montage.svg b/assets/Website Logo/All Schemes/Gradient - Cyan Montage/Gradient - Cyan Montage.svg similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Cyan Montage/Gradient - Cyan Montage.svg rename to assets/Website Logo/All Schemes/Gradient - Cyan Montage/Gradient - Cyan Montage.svg diff --git a/Assets/Website Logo/All Schemes/Gradient - Cyan Montage/Logo - Cyan Montage.png b/assets/Website Logo/All Schemes/Gradient - Cyan Montage/Logo - Cyan Montage.png similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Cyan Montage/Logo - Cyan Montage.png rename to assets/Website Logo/All Schemes/Gradient - Cyan Montage/Logo - Cyan Montage.png diff --git a/Assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.png b/assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.png similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.png rename to assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.png diff --git a/Assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.svg b/assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.svg similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.svg rename to assets/Website Logo/All Schemes/Gradient - Purple Satire/Logo - Purple Satire.svg diff --git a/Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Gradient Amethyst No BG.svg b/assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Gradient Amethyst No BG.svg similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Gradient Amethyst No BG.svg rename to assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Gradient Amethyst No BG.svg diff --git a/Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst No BG.png b/assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst No BG.png similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst No BG.png rename to assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst No BG.png diff --git a/Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst Square.png b/assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst Square.png similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst Square.png rename to assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst Square.png diff --git a/Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.png b/assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.png similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.png rename to assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.png diff --git a/Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.svg b/assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.svg similarity index 100% rename from Assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.svg rename to assets/Website Logo/All Schemes/Gradient - Radiant Amethyst(Main)/Logo - Radiant Amethyst.svg diff --git a/Assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.png b/assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.png similarity index 100% rename from Assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.png rename to assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.png diff --git a/Assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.svg b/assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.svg similarity index 100% rename from Assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.svg rename to assets/Website Logo/All Schemes/Normal - Black/Logo - Normal Black.svg diff --git a/Assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.png b/assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.png similarity index 100% rename from Assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.png rename to assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.png diff --git a/Assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.svg b/assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.svg similarity index 100% rename from Assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.svg rename to assets/Website Logo/All Schemes/Normal - White/Logo - Normal White.svg diff --git a/backend/.idea/.gitignore b/backend/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/backend/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/backend/.idea/backend.iml b/backend/.idea/backend.iml deleted file mode 100644 index c243d74..0000000 --- a/backend/.idea/backend.iml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/backend/.idea/inspectionProfiles/profiles_settings.xml b/backend/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/backend/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/backend/.idea/misc.xml b/backend/.idea/misc.xml deleted file mode 100644 index 599bd1a..0000000 --- a/backend/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/backend/.idea/modules.xml b/backend/.idea/modules.xml deleted file mode 100644 index e066844..0000000 --- a/backend/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/backend/Pipfile b/backend/Pipfile deleted file mode 100644 index 2874364..0000000 --- a/backend/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -djangorestframework = "*" -django-cors-headers = "*" - -[dev-packages] - -[requires] -python_version = "3.11" diff --git a/backend/Pipfile.lock b/backend/Pipfile.lock deleted file mode 100644 index 4ea0dd0..0000000 --- a/backend/Pipfile.lock +++ /dev/null @@ -1,76 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "3ebd2936e619a2713a2d77ee1c62f13746bd3f62bef0ea4026510a5cd30941ea" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.11" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "asgiref": { - "hashes": [ - "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e", - "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed" - ], - "markers": "python_version >= '3.7'", - "version": "==3.7.2" - }, - "django": { - "hashes": [ - "sha256:7e4225ec065e0f354ccf7349a22d209de09cc1c074832be9eb84c51c1799c432", - "sha256:860ae6a138a238fc4f22c99b52f3ead982bb4b1aad8c0122bcd8c8a3a02e409d" - ], - "markers": "python_version >= '3.8'", - "version": "==4.2.4" - }, - "django-cors-headers": { - "hashes": [ - "sha256:9ada212b0e2efd4a5e339360ffc869cb21ac5605e810afe69f7308e577ea5bde", - "sha256:f9749c6410fe738278bc2b6ef17f05195bc7b251693c035752d8257026af024f" - ], - "index": "pypi", - "version": "==4.2.0" - }, - "djangorestframework": { - "hashes": [ - "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8", - "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08" - ], - "index": "pypi", - "version": "==3.14.0" - }, - "pytz": { - "hashes": [ - "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588", - "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb" - ], - "version": "==2023.3" - }, - "sqlparse": { - "hashes": [ - "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3", - "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c" - ], - "markers": "python_version >= '3.5'", - "version": "==0.4.4" - }, - "tzdata": { - "hashes": [ - "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", - "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda" - ], - "markers": "sys_platform == 'win32'", - "version": "==2023.3" - } - }, - "develop": {} -} diff --git a/backend/auth/migrations/__init__.py b/backend/__init__.py similarity index 100% rename from backend/auth/migrations/__init__.py rename to backend/__init__.py diff --git a/backend/backend/__init__.py b/backend/auth/accounts/__init__.py similarity index 100% rename from backend/backend/__init__.py rename to backend/auth/accounts/__init__.py diff --git a/backend/auth/accounts/admin.py b/backend/auth/accounts/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/backend/auth/accounts/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/backend/auth/accounts/apps.py b/backend/auth/accounts/apps.py new file mode 100644 index 0000000..3e3c765 --- /dev/null +++ b/backend/auth/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/auth/accounts/migrations/0001_initial.py b/backend/auth/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..080e399 --- /dev/null +++ b/backend/auth/accounts/migrations/0001_initial.py @@ -0,0 +1,40 @@ +# Generated by Django 4.1.10 on 2024-01-01 13:26 + +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')), + ('email', models.EmailField(max_length=255, unique=True, verbose_name='Email')), + ('first_name', models.CharField(max_length=200)), + ('last_name', models.CharField(max_length=200)), + ('age', models.PositiveIntegerField()), + ('gender', models.CharField(max_length=200)), + ('address', models.CharField(max_length=600)), + ('preferred_lang', models.CharField(max_length=200)), + ('company', models.CharField(max_length=200)), + ('job_title', models.CharField(max_length=200)), + ('industry', models.CharField(max_length=400)), + ('experience', models.IntegerField()), + ('is_active', models.BooleanField(default=True)), + ('is_admin', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/backend/auth/accounts/migrations/__init__.py b/backend/auth/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/auth/models.py b/backend/auth/accounts/models.py similarity index 99% rename from backend/auth/models.py rename to backend/auth/accounts/models.py index 8a24e65..84c4a4f 100644 --- a/backend/auth/models.py +++ b/backend/auth/accounts/models.py @@ -18,7 +18,6 @@ def create_user( industry, experience, password=None, - password2=None, ): """ Creates and saves a User with the given email, name, tc and password. diff --git a/backend/auth/accounts/serializers.py b/backend/auth/accounts/serializers.py new file mode 100644 index 0000000..4e6515a --- /dev/null +++ b/backend/auth/accounts/serializers.py @@ -0,0 +1,22 @@ +from djoser.serializers import UserCreateSerializer +from django.contrib.auth import get_user_model + +User = get_user_model() + + +class UserCreateSerializer(UserCreateSerializer): + class Meta(UserCreateSerializer.Meta): + model = User + fields = ('email', + 'first_name', + 'last_name', + 'age', + 'gender', + 'address', + 'preferred_lang', + 'company', + 'job_title', + 'industry', + 'experience', + 'password', + ) diff --git a/backend/auth/tests.py b/backend/auth/accounts/tests.py similarity index 100% rename from backend/auth/tests.py rename to backend/auth/accounts/tests.py diff --git a/backend/auth/accounts/views.py b/backend/auth/accounts/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/backend/auth/accounts/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/backend/auth/admin.py b/backend/auth/admin.py deleted file mode 100644 index 44ef9fb..0000000 --- a/backend/auth/admin.py +++ /dev/null @@ -1,75 +0,0 @@ -from django.contrib import admin -from accounts.models import User -from django.contrib.auth.admin import UserAdmin as BaseUserAdmin - - -class UserModelAdmin(BaseUserAdmin): - # The fields to be used in displaying the User model. - # These override the definitions on the base UserModelAdmin - # that reference specific fields on auth.User. - list_display = ( - "id", - "email", - "first_name", - "last_name", - "age", - "gender", - "address", - "preferred_lang", - "company", - "job_title", - "industry", - "experience", - "is_admin", - ) - list_filter = ("is_admin",) - fieldsets = ( - ("User Credentials", {"fields": ("email", "password")}), - ( - "Personal info", - { - "fields": ( - "first_name", - "last_name", - "age", - "gender", - "address", - "preferred_lang", - ) - }, - ), - ("Work info", {"fields": ("company", "job_title", "industry", "experience")}), - ("Permissions", {"fields": ("is_admin",)}), - ) - # add_fieldsets is not a standard ModelAdmin attribute. UserModelAdmin - # overrides get_fieldsets to use this attribute when creating a user. - add_fieldsets = ( - ( - None, - { - "classes": ("wide",), - "fields": ( - "email", - "first_name", - "last_name", - "age", - "gender", - "address", - "preferred_lang", - "company", - "job_title", - "industry", - "experience", - "password1", - "password2", - ), - }, - ), - ) - search_fields = ("email",) - ordering = ("email", "id") - filter_horizontal = () - - -# Now register the new UserModelAdmin... -admin.site.register(User, UserModelAdmin) diff --git a/backend/auth/apps.py b/backend/auth/apps.py deleted file mode 100644 index ed1a2c2..0000000 --- a/backend/auth/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class AccountsConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "auth" diff --git a/backend/auth/auth/__init__.py b/backend/auth/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/backend/asgi.py b/backend/auth/auth/asgi.py similarity index 58% rename from backend/backend/asgi.py rename to backend/auth/auth/asgi.py index e3a87a9..cbbdc7e 100644 --- a/backend/backend/asgi.py +++ b/backend/auth/auth/asgi.py @@ -1,16 +1,16 @@ """ -ASGI config for backend project. +ASGI config for auth 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/4.2/howto/deployment/asgi/ +https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ """ import os from django.core.asgi import get_asgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'auth.settings') application = get_asgi_application() diff --git a/backend/auth/auth/settings.py b/backend/auth/auth/settings.py new file mode 100644 index 0000000..55e7a51 --- /dev/null +++ b/backend/auth/auth/settings.py @@ -0,0 +1,204 @@ +""" +Django settings for auth project. + +Generated by 'django-admin startproject' using Django 4.1.10. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.1/ref/settings/ +""" +import os.path +from datetime import timedelta +from pathlib import Path +from .secrets import get_secret + +# 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/4.1/howto/deployment/checklist/ + +get_secret() +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-!te*yedg2t@=j72f3xp!nxmu#ns52ubfr+z49q9*d-wdc_a1ow' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'djoser', + 'accounts', +] + +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 = 'auth.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'build')], + '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 = 'auth.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.1/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.environ.get('dbname', ''), + "USER": os.environ.get('username', ''), + "PASSWORD": os.environ.get('password', ''), + "HOST": os.environ.get('host', ''), + "PORT": os.environ.get('port', ''), + } +} + +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = 'schwarzstudios@gmail.com' +EMAIL_HOST_PASSWORD = 'xlsyomssafccnnxa' +EMAIL_USE_TLS = True + +# Password validation +# https://docs.djangoproject.com/en/4.1/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/4.1/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/4.1/howto/static-files/ + +STATIC_URL = 'static/' +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, 'build/static') +] +STATIC_ROOT = os.path.join(BASE_DIR, 'static') + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated' + ], + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), +} + +AUTHENTICATION_BACKENDS = ( + 'social_core.backends.google.GoogleOAuth2', + 'social_core.backends.facebook.FacebookOAuth2', + 'django.contrib.auth.backends.ModelBackend' +) + +SIMPLE_JWT = { + 'AUTH_HEADER_TYPES': ('JWT',), + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), + 'AUTH_TOKEN_CLASSES': ( + 'rest_framework_simplejwt.tokens.AccessToken', + ) +} + +DJOSER = { + 'LOGIN_FIELD': 'email', + 'USER_CREATE_PASSWORD_RETYPE': True, + 'USERNAME_CHANGED_EMAIL_CONFIRMATION': True, + 'PASSWORD_CHANGED_EMAIL_CONFIRMATION': True, + 'SEND_CONFIRMATION_EMAIL': True, + 'SET_USERNAME_RETYPE': True, + 'SET_PASSWORD_RETYPE': True, + 'PASSWORD_RESET_CONFIRM_URL': 'password/reset/confirm/{uid}/{token}', + 'USERNAME_RESET_CONFIRM_URL': 'email/reset/confirm/{uid}/{token}', + 'ACTIVATION_URL': 'activate/{uid}/{token}', + 'SEND_ACTIVATION_EMAIL': True, + 'SOCIAL_AUTH_TOKEN_STRATEGY': 'djoser.social.token.jwt.TokenStrategy', + 'SOCIAL_AUTH_ALLOWED_REDIRECT_URIS': ['http://localhost:8000/google', 'http://localhost:8000/facebook'], + 'SERIALIZERS': { + 'user_create': 'accounts.serializers.UserCreateSerializer', + 'user': 'accounts.serializers.UserCreateSerializer', + 'current_user': 'accounts.serializers.UserCreateSerializer', + 'user_delete': 'djoser.serializers.UserDeleteSerializer', + } +} + +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '[YOUR GOOGLE OAUTH2 API KEY]' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '[YOUR GOOGLE OAUTH2 API SECRET]' +SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth' + '/userinfo.profile', 'openid'] +SOCIAL_AUTH_GOOGLE_OAUTH2_EXTRA_DATA = ['first_name', 'last_name'] + +SOCIAL_AUTH_FACEBOOK_KEY = '[YOUR FACEBOOK API KEY]' +SOCIAL_AUTH_FACEBOOK_SECRET = '[YOUR FACEBOOK API SECRET]' +SOCIAL_AUTH_FACEBOOK_SCOPE = ['email'] +SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = { + 'fields': 'email, first_name, last_name' +} + +# Default primary key field type +# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +AUTH_USER_MODEL = 'accounts.User' diff --git a/backend/auth/auth/urls.py b/backend/auth/auth/urls.py new file mode 100644 index 0000000..5329e70 --- /dev/null +++ b/backend/auth/auth/urls.py @@ -0,0 +1,10 @@ +from django.urls import path, include, re_path +from django.views.generic import TemplateView + +urlpatterns = [ + path('api/', include('djoser.urls')), + path('api/', include('djoser.urls.jwt')), + path('api/', include('djoser.social.urls')), +] + +urlpatterns += [re_path(r'^.*', TemplateView.as_view(template_name='index.html'))] diff --git a/backend/backend/wsgi.py b/backend/auth/auth/wsgi.py similarity index 58% rename from backend/backend/wsgi.py rename to backend/auth/auth/wsgi.py index e35bea4..d93a996 100644 --- a/backend/backend/wsgi.py +++ b/backend/auth/auth/wsgi.py @@ -1,16 +1,16 @@ """ -WSGI config for backend project. +WSGI config for auth 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/4.2/howto/deployment/wsgi/ +https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/ """ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'auth.settings') application = get_wsgi_application() diff --git a/backend/manage.py b/backend/auth/manage.py similarity index 85% rename from backend/manage.py rename to backend/auth/manage.py index 1917e46..ef9a923 100644 --- a/backend/manage.py +++ b/backend/auth/manage.py @@ -6,7 +6,7 @@ def main(): """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'auth.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -18,5 +18,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/backend/auth/migrations/0001_initial.py b/backend/auth/migrations/0001_initial.py deleted file mode 100644 index 8d0e709..0000000 --- a/backend/auth/migrations/0001_initial.py +++ /dev/null @@ -1,56 +0,0 @@ -# Generated by Django 4.1.10 on 2023-09-06 12:06 - -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" - ), - ), - ( - "email", - models.EmailField( - max_length=255, unique=True, verbose_name="Email" - ), - ), - ("first_name", models.CharField(max_length=200)), - ("last_name", models.CharField(max_length=200)), - ("age", models.PositiveIntegerField()), - ("gender", models.CharField(max_length=200)), - ("address", models.CharField(max_length=600)), - ("preferred_lang", models.CharField(max_length=200)), - ("company", models.CharField(max_length=200)), - ("job_title", models.CharField(max_length=200)), - ("industry", models.CharField(max_length=400)), - ("experience", models.IntegerField()), - ("is_active", models.BooleanField(default=True)), - ("is_admin", models.BooleanField(default=False)), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ], - options={ - "abstract": False, - }, - ), - ] diff --git a/backend/auth/renderers.py b/backend/auth/renderers.py deleted file mode 100644 index 242995f..0000000 --- a/backend/auth/renderers.py +++ /dev/null @@ -1,15 +0,0 @@ -from rest_framework import renderers -import json - - -class UserRenderer(renderers.JSONRenderer): - charset = "utf-8" - - def render(self, data, accepted_media_type=None, renderer_context=None): - response = "" - if "ErrorDetail" in str(data): - response = json.dumps({"errors": data}) - else: - response = json.dumps(data) - - return response diff --git a/backend/auth/serializers.py b/backend/auth/serializers.py deleted file mode 100644 index 1feae32..0000000 --- a/backend/auth/serializers.py +++ /dev/null @@ -1,143 +0,0 @@ -from rest_framework import serializers -from accounts.models import User -from django.utils.encoding import smart_str, force_bytes, DjangoUnicodeDecodeError -from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode -from django.contrib.auth.tokens import PasswordResetTokenGenerator -from accounts.utils import Util - - -class UserRegistrationSerializer(serializers.ModelSerializer): - # We are writing this becoz we need confirm password field in our Registratin Request - password2 = serializers.CharField(style={"input_type": "password"}, write_only=True) - - class Meta: - model = User - fields = [ - "email", - "first_name", - "last_name", - "age", - "gender", - "address", - "preferred_lang", - "company", - "job_title", - "industry", - "experience", - "password", - "password2", - ] - extra_kwargs = {"password": {"write_only": True}} - - # Validating Password and Confirm Password while Registration - def validate(self, attrs): - password = attrs.get("password") - password2 = attrs.get("password2") - if password != password2: - raise serializers.ValidationError( - "Password and Confirm Password doesn't match" - ) - return attrs - - def create(self, validate_data): - return User.objects.create_user(**validate_data) - - -class UserLoginSerializer(serializers.ModelSerializer): - email = serializers.EmailField(max_length=255) - - class Meta: - model = User - fields = ["email", "password"] - - -class UserProfileSerializer(serializers.ModelSerializer): - class Meta: - model = User - fields = ["id", "email", "name"] - - -class UserChangePasswordSerializer(serializers.Serializer): - password = serializers.CharField( - max_length=255, style={"input_type": "password"}, write_only=True - ) - password2 = serializers.CharField( - max_length=255, style={"input_type": "password"}, write_only=True - ) - - class Meta: - fields = ["password", "password2"] - - def validate(self, attrs): - password = attrs.get("password") - password2 = attrs.get("password2") - user = self.context.get("user") - if password != password2: - raise serializers.ValidationError( - "Password and Confirm Password doesn't match" - ) - user.set_password(password) - user.save() - return attrs - - -class SendPasswordResetEmailSerializer(serializers.Serializer): - email = serializers.EmailField(max_length=255) - - class Meta: - fields = ["email"] - - def validate(self, attrs): - email = attrs.get("email") - if User.objects.filter(email=email).exists(): - user = User.objects.get(email=email) - uid = urlsafe_base64_encode(force_bytes(user.id)) - print("Encoded UID", uid) - token = PasswordResetTokenGenerator().make_token(user) - print("Password Reset Token", token) - link = "http://localhost:3000/api/user/reset/" + uid + "/" + token - print("Password Reset Link", link) - # Send EMail - body = "Click Following Link to Reset Your Password " + link - data = { - "subject": "Reset Your Password", - "body": body, - "to_email": user.email, - } - # Util.send_email(data) - return attrs - else: - raise serializers.ValidationError("You are not a Registered User") - - -class UserPasswordResetSerializer(serializers.Serializer): - password = serializers.CharField( - max_length=255, style={"input_type": "password"}, write_only=True - ) - password2 = serializers.CharField( - max_length=255, style={"input_type": "password"}, write_only=True - ) - - class Meta: - fields = ["password", "password2"] - - def validate(self, attrs): - try: - password = attrs.get("password") - password2 = attrs.get("password2") - uid = self.context.get("uid") - token = self.context.get("token") - if password != password2: - raise serializers.ValidationError( - "Password and Confirm Password doesn't match" - ) - id = smart_str(urlsafe_base64_decode(uid)) - user = User.objects.get(id=id) - if not PasswordResetTokenGenerator().check_token(user, token): - raise serializers.ValidationError("Token is not Valid or Expired") - user.set_password(password) - user.save() - return attrs - except DjangoUnicodeDecodeError as identifier: - PasswordResetTokenGenerator().check_token(user, token) - raise serializers.ValidationError("Token is not Valid or Expired") diff --git a/backend/auth/urls.py b/backend/auth/urls.py deleted file mode 100644 index 5d6b1d9..0000000 --- a/backend/auth/urls.py +++ /dev/null @@ -1,26 +0,0 @@ -from django.urls import path -from accounts.views import ( - SendPasswordResetEmailView, - UserChangePasswordView, - UserLoginView, - UserProfileView, - UserRegistrationView, - UserPasswordResetView, -) - -urlpatterns = [ - path("register/", UserRegistrationView.as_view(), name="register"), - path("login/", UserLoginView.as_view(), name="login"), - path("profile/", UserProfileView.as_view(), name="profile"), - path("changepassword/", UserChangePasswordView.as_view(), name="changepassword"), - path( - "send-reset-password-email/", - SendPasswordResetEmailView.as_view(), - name="send-reset-password-email", - ), - path( - "reset-password///", - UserPasswordResetView.as_view(), - name="reset-password", - ), -] diff --git a/backend/auth/utils.py b/backend/auth/utils.py deleted file mode 100644 index e3a9b1f..0000000 --- a/backend/auth/utils.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.core.mail import EmailMessage -import os - - -class Util: - @staticmethod - def send_email(data): - email = EmailMessage( - subject=data["subject"], - body=data["body"], - from_email=os.environ.get("EMAIL_FROM"), - to=[data["to_email"]], - ) - email.send() diff --git a/backend/auth/views.py b/backend/auth/views.py deleted file mode 100644 index 30414c5..0000000 --- a/backend/auth/views.py +++ /dev/null @@ -1,107 +0,0 @@ -from rest_framework.response import Response -from rest_framework import status -from rest_framework.views import APIView -from accounts.serializers import ( - SendPasswordResetEmailSerializer, - UserChangePasswordSerializer, - UserLoginSerializer, - UserPasswordResetSerializer, - UserProfileSerializer, - UserRegistrationSerializer, -) -from django.contrib.auth import authenticate -from accounts.renderers import UserRenderer -from rest_framework_simplejwt.tokens import RefreshToken -from rest_framework.permissions import IsAuthenticated - - -# Generate Token Manually -def get_tokens_for_user(user): - refresh = RefreshToken.for_user(user) - return { - "refresh": str(refresh), - "access": str(refresh.access_token), - } - - -class UserRegistrationView(APIView): - renderer_classes = [UserRenderer] - - def post(self, request, format=None): - serializer = UserRegistrationSerializer(data=request.data) - serializer.is_valid(raise_exception=True) - user = serializer.save() - token = get_tokens_for_user(user) - return Response( - {"token": token, "msg": "Registration Successful"}, - status=status.HTTP_201_CREATED, - ) - - -class UserLoginView(APIView): - renderer_classes = [UserRenderer] - - def post(self, request, format=None): - serializer = UserLoginSerializer(data=request.data) - serializer.is_valid(raise_exception=True) - email = serializer.data.get("email") - password = serializer.data.get("password") - user = authenticate(email=email, password=password) - if user is not None: - token = get_tokens_for_user(user) - return Response( - {"token": token, "msg": "Login Success"}, status=status.HTTP_200_OK - ) - else: - return Response( - {"errors": {"non_field_errors": ["Email or Password is not Valid"]}}, - status=status.HTTP_404_NOT_FOUND, - ) - - -class UserProfileView(APIView): - renderer_classes = [UserRenderer] - permission_classes = [IsAuthenticated] - - def get(self, request, format=None): - serializer = UserProfileSerializer(request.user) - return Response(serializer.data, status=status.HTTP_200_OK) - - -class UserChangePasswordView(APIView): - renderer_classes = [UserRenderer] - permission_classes = [IsAuthenticated] - - def post(self, request, format=None): - serializer = UserChangePasswordSerializer( - data=request.data, context={"user": request.user} - ) - serializer.is_valid(raise_exception=True) - return Response( - {"msg": "Password Changed Successfully"}, status=status.HTTP_200_OK - ) - - -class SendPasswordResetEmailView(APIView): - renderer_classes = [UserRenderer] - - def post(self, request, format=None): - serializer = SendPasswordResetEmailSerializer(data=request.data) - serializer.is_valid(raise_exception=True) - return Response( - {"msg": "Password Reset link send. Please check your Email"}, - status=status.HTTP_200_OK, - ) - - -class UserPasswordResetView(APIView): - renderer_classes = [UserRenderer] - - def post(self, request, uid, token, format=None): - serializer = UserPasswordResetSerializer( - data=request.data, context={"uid": uid, "token": token} - ) - serializer.is_valid(raise_exception=True) - return Response( - {"msg": "Password Reset Successfully"}, status=status.HTTP_200_OK - ) diff --git a/backend/backend/settings.py b/backend/backend/settings.py deleted file mode 100644 index 4126b0d..0000000 --- a/backend/backend/settings.py +++ /dev/null @@ -1,165 +0,0 @@ -""" -Django settings for backend project. - -Generated by 'django-admin startproject' using Django 4.2.3. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.2/ref/settings/ -""" - -from pathlib import Path -from datetime import timedelta - -# 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/4.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-^^zp!u$^%7if=h6d_y)00dmo=c(0l2zk*xd$!$ky-6mrj%4%%c" - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", - "corsheaders", - "rest_framework", - "rest_framework_simplejwt", - "auth", -] - -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "corsheaders.middleware.CorsMiddleware", - "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": [BASE_DIR / "templates"], - "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/4.2/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": "backendauth", - "USER": "superuser", - "PASSWORD": "admin-123", - "HOST": "rds-dev-postgresql-auth-ap-south-1.ckgts3lzzpzg.ap-south-1.rds.amazonaws.com", - "PORT": "5432", - } -} - -REST_FRAMEWORK = { - "DEFAULT_AUTHENTICATION_CLASSES": ( - "rest_framework_simplejwt.authentication.JWTAuthentication", - ) -} - -# Password validation -# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/4.2/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/4.2/howto/static-files/ - -STATIC_URL = "static/" - -# Default primary key field type -# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" - -AUTH_USER_MODEL = "auth.User" - -SIMPLE_JWT = { - "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), - "REFRESH_TOKEN_LIFETIME": timedelta(days=1), - "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", - "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer", - "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer", - "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer", - "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer", - "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer", - "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", -} - -CORS_ALLOWED_ORIGINS = [ - "http://localhost:3000", - "http://127.0.0.1:3000", -] diff --git a/backend/backend/urls.py b/backend/backend/urls.py deleted file mode 100644 index 3611eab..0000000 --- a/backend/backend/urls.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.contrib import admin -from django.urls import path, include - -urlpatterns = [ - path("admin/", admin.site.urls), - path("api/user/", include("auth.urls")), - # path('socialmedia/', include('socialmedia.urls')), # Include socialmedia app URLs -] \ No newline at end of file diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 deleted file mode 100644 index 9096e6b25b6b31bb2879866946e599ef695a1727..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131072 zcmeI5ZEPFKdB?dTMT(Nhl_l%w#^;!#?K?BFtX(cCioRZRw9J#`(~B)jwsmc=U6L!B z65m8pFLr>o)cG#Or7h4D3D5#*D4phyA~DT<;k+N4ENpiNS={gO67lA=YD z4{3nT442#&E+tv83)}tE@@jYInP>m=o7vgjXJ)C}x90P8HMm}`7L|HXatt{*&hbVt z=x{hf~btjrku?n*jd<-o=~`P<%B1YOK=TEFF`Z4qE?IfS}k8L)nt907GgS@iDeQIl_~2m z9@a`>l;2_0#iK!dM;2NHlMW(&e8>~{2ob+kld_ZBmi-XnabIrdieKcDzlU=&5oyF9zMZHElnZ3`FK_pC|BO zoZIL1D$%oa93WH9swJhU%7Un*rFcxyYeUcF?_LeM(GguAxg?|pTH-?C{dT>+i#5fk6=EfMbv|Y6PppO%E9pprc~YS{wHjPpS_v+$&d&#L zF3&9_m)C-CrPhMU)s>~WMdETHwYWm0GAFjVmQ!!0mQ#x}soREwYR3o%uhG=rXF+E?CYult@&_)^xrpx7mF_rG6U4ZUi5_I?4wVNDeJzph< z>2BE)a-fA;RPqJ=Nb#6{B$A&Btt;#6ogzt!lBwr+h)Sz|T4H&loG+;aQAhE^V!u0( zI?Fj&cUaphklQtxR1~o%_cwG+yTK9Ls{{LseV#xf!99xW_1kPq`q|YyF*^2oZEC*5 z=vd95>E($xW8VekcrioqNOf9o2@bB% z?1oaxl}#6KP14~Pr}p((@0kRHmT=>`%M&O|T;rqcWV1PxtW+v;K}o9xxk&Cr3UYiZ zot3gun%#!jWa!mknx80a3=j6)ybH0(M$6vTL?0}eEOJ|wb9w@j#O-gh8n?-5v&&_! zc^iu-Q2U}0IT5U@x386Une3CpH+$T)X|J(zYW-zR-P%@58P&4sG?mYic#)oimq^ZV zV~z6!CMUUl#mKIh&sCK=eHhcY=sS8$enTDU$D&5K=+~V{%zWW7_ZQYwlC_ZUxVn&j zV06Ssmcs)#9sFPLpW?IpnExOAKj**d`=Rf%zFl8*@Ee1l9=tPnV&IDd?-Cnj9-zauEb)O zrKlJe;@3~~I!5m%>2o)+kH|`)PDZR)NLCM8$wg&PE~uqk{l2ZINMt%Ly)i^Q&9*#= z@^*zqmnzlr-UGu3PtDFlBoUvE#AkToVWH(g(6lr|3G^xB5E+qa@=u)g6DO;h6Cq(N z5R3I4#nDtGB1&)ih@;yrN7F_}t+3x=f~15P7vCBrem>Ij6W9FgD1|)XQ?8QWTsAAK z)oQsa7fIDAIn^GK7>`Bc$pPYQuH|e>u9BzAd{u45Am|86O(r!Tv87B}K~%chPh7m! zauG9@OAm(1rR{=ks}U11NfO`i5+AL)7NSNUZ8qgf-L@cNJTf(%nCT-PT6HZ*Mh`5` zc?eoD79&5`J;X_?@d~ZRs|Sc!#Pu*wk|aox>+W91h1sMQ|6v#@MZ&jO-f81)j!@AS zWQSK25(MvDZ?7XjG-ZqV5^*8X;4&H9sy<-#OarmylDu9}a&qQ=IZxsOcCLhYG%hBR zF5-$%)?7t&SDGwx)|RPTTNklJOcVttadDyT;=m3;kfH?YWDj9Vaj zW3f0#&|R>iJK#tpV=R_P#C-g3Io$k?gZ~fy%lv2g9sc9|ukd@OE)5$X00JNY0w4ea zAOHd&00JNY0w4ea$09J|a*lJBX*Q>PUguaJ+sUGBgZ<94Ubac2Ipi=S&BS(OCE#>Q zoXwmJ_ehU(qEAa;aSIx=80DOkEo*(I!f-!v?B+l2;J?lPHUCfi=lNeJ8~A_#2!H?x zfB*=900@8p2!H?xfB*&ow&A!U!}%;PSgh z18j?h51b>e(J{8!4j7brPPhVRyeuTpnh-(f|DPKCNeBNm{tx({<;+Zu0)TO1|8}VAb5ywtJ~*N4`U(lrz~i z_q6PSqr~pqxSP)DH#j4kEsOD!#9|`e%TyVjsM^Z3eL*@2eR6~ti?8)+@+{_>L{kRx z4hYSl>9l0fv>G#n$@?GNc&wKSwpdfqM$?zc3m)9rS6xgwee7#XrW-->@&+lnOOx74 z*EBK<@@59L(6qHIG*NW(1LTzp?#u-j71K(lD(LzL$!iqcSlG#q&K@({hi6+M@@537 zZKrnpwuL63X+vIppf;La8$c{Ikw!~RV%suAUJCGDn4|)YW>j9= zhK~QA@}G6^-yx&_e@T>dwixWAU_{vB#L33+}j0}&uxN*)JFFC=xxU-xd8W~~&jKL7T zxkqzIBN~3ci#x-$gB`vh7dOTk;v0jEfGMCc(A=dtVG)Ubc4R$V;br=)0gAqWi<{&+ zgAtzQe$AmCIdC(omH@@XNo4cPP)9~oF#PNWIHvVt;heKA(!_8nE;>%1nBrb z$EO_R2Okgs0T2KI5C8!X009sH0T2KI5CDOL2sEZSpQG`5(tFzXy4RcZRnnW;^@v=% zuS8-~=cNSs3PRz0y_T9^UWwdJ$8YUzW|sCI?iBNd+W95%;mWwct3e(diyH|r`b1%3ReX3HGYC9O-Z%P{avN{u=T6H zoz0hPZ{+A7tGS#h7tI+Xi7SF|IUzejoGvUxEBV#!S!MHWacAqsL#2|tyLvk% z#P6){#;e&|SNEzrQoNA9H@z}+AK*&FLkwajjmC-g-HJS*^`RQn!?at<=VyTyk}B zb9ptjlv+q6voooy!u_{*Z%@P@UcI$-buqDdMch(y((aYDH>2CvXC7|tuI(1D*MH$AE?`AOHd&00JNY0w4eaAOHd&00JQJoDrat{!j7S4*q}m@ALn~e~bSH z|F8U4`LFO_P zeAm(M`lN$D@Be%6SKMFl?GC>0KG}QM^~r(nxBm6~uxE+;gyTz&*DY=azU_WDur$Fn z#C$2M?kU^#`|@^8t;)G-dAm|;uIIDzlp;pd>~z{{aB^ljm0U>$=N7M}?gc~E8JStxih#EzQJhQf^x4|@WeL{jZwNlc+kv?ZcaOvnfsdApR~vMLzS1gGrWLcyDK5b@(fp1?YbvZPWU^8umKOAu(?Mvcd;96IZJso=HV-(=k;_J!l*tV#?0G+_nsHOr z7)&zdQe7?8<@$q)N<~E0qwy&<+B|1Lr$#* z7nfFoi>veV!JEr-3(4iR;9IG+U~+Y3X>O4?T1YLfkTb1y_36yDoO(00oLZbo-8LMG z>ZjML;5C}M%!JG>&aKQP=jYe7ovCZai^35cGayIv93FUu`^smUFNxRBfw}C)T8*h&{RGqHEec zm)Kq%*kA1P1QH4EQCzRzj_VCG@7U|Lsre40V>N@O7u$2I<1AseM{CT4y538Y3zyBQ z+u>f%aI|BD$$jtN1;)m>#-;_R4$;#M+_7Mp+u(F(dk#w;cVKqxz-G}T-fS0ay^oZ` zOYhhhKj@1B} zr=y)s)bwcQ(f`T0db7tJ7$4`>7+9^ptf^buYAK^yHk~Gfmc)zn9K1wwh8t^~Conn5 z?JLY@c0(!U%5pKEt15N+FxIi7$K*HEk$$WiQ7RSvx)X_+FFfY{!kS957V`F27mWYY z{tzD!009sH0T2KI5C8!X009sH0T6hx3HY3|juFRyJNONM#rMa9|K9(N{vY-JcHh_g zhTY#J^8kuHf9PCu{%Oz8aPRlb5VL3Kb$pvlh&Ww)vZ*pJqcE12P`AGWP_VA<)r|uz zMwvDP6t4;Hz*4wdB-$)a7R}oO;^oI3-RNta827MXe360DL-6`qYn0kJ$Y&f=c)S5D zb8tEAO3q=R;)eprJf- z+t=sV94iKS+@U-&fU1p-JKkGG6iGI6L>Jr?eqGqm;(-wDQ8t$9kL)QX(=94^a(L~F1IGyW+s(x z)S=zp^^qr&kVH8~ULw6nizf#tuX`KGwNoo$1oq2N}mHwQkaw zNjvJ{(+1jQ)(6}LL!U*cn9m;5a6!0n{j4WYmbk`8jh9EG5Sff8$OR>>7UUwS`+^*w zN@u04lx7ugquga%`8I|Jdp2E0je;ndwx$p%ACpBcsdFFn1SE;uPZ%$$#+)`9&X}v- z#^PAjuj}htD^1n*$>GM(8RLkpCQHc{^CdcUqCHnK6Pt>vX=Tc4@Um7c^Ic2#{3h6K zGg|c4&|tW6@nugyCUY%s8Cy!*w)1R`rZeianzl+ieTXz;h0&>L8O=|3iIyCp@H;usJDn%+Ut`A<)(b8597-Fs_>mGKCyJASNzWv$3`>X6+mn#PR)>D7{4V@toL zF)3`JckR}hwc>g@9b1oN+JZX9;Xhz*z1O|m1Tv&B zYljtvc_gQdl8C8FRy54OwwC)xj$90@&!ZGT%R{8^j*=<2-Xym_c~tGD!pmY*nMzMd z5&b5E`L-74lvW&@`wd(BcK><6(H^Iuew00JNY0w4eaAOHd&00JNY0wC}V5y12RGgKLn0sVJpe1m|)D&agjYLjGioTB=tc(C2^0&{HZB+=2iIfB*=900@8p2!H?x zfB*=900=x21Pt^4`Da29M1TMYfB*=900@8p2!H?xfB*=900=yB0`&Qx/', socialaccount_views.disconnect, name='socialaccount_disconnect'), +] diff --git a/backend/oauth/oauth/views.py b/backend/oauth/oauth/views.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/oauth/oauth/wsgi.py b/backend/oauth/oauth/wsgi.py new file mode 100644 index 0000000..76a479a --- /dev/null +++ b/backend/oauth/oauth/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for oauth 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/4.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oauth.settings') + +application = get_wsgi_application() diff --git a/backend/oauth/requirements.txt b/backend/oauth/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5378b76da03ad041e7c5f8ae5792e64620cc7a6 GIT binary patch literal 1080 zcmah|%TB{U4D=a^PYG%h+NuX`oH%hn;#``h3FJkRQp(2zGj?{fMIaPyq^!r|@!0wL z+(<8bDWsE~WO9Qikt z*anHDmIhxH?n-h6yw=(?V6A$p`VU$mm3MHLiZcXN zvYT6Z21^aLW@KT6$8@GaJW_Qf-UleiJ=;RozOQrqR=euaUk)`Jp(gh1I-5habL2cT zMdko>EpLjZCSuKp5X(9Bz-H=4g|DMlefhV_-d)!4p70Sf@ zaCJD9wQ8Y?EwFCmI**CRJ-7$rP9EjKN7#w=$?OWX&bNeJ*bap~CeT7voE*Dzol*P5 zHeka|rTcRd)yavxV!LdjwkOO?0@r_HSkGU;DeS>o2K}=({{x!_{{t#Y!873e RrtE<2D)De0$%qJd;TvAwq9p(T literal 0 HcmV?d00001 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9a44b66..0b6887a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,17 +8,21 @@ "name": "frontend", "version": "0.1.0", "dependencies": { - "@reduxjs/toolkit": "^1.9.5", + "@redux-devtools/extension": "^3.3.0", + "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "@vitejs/plugin-react-refresh": "^1.3.1", + "axios": "^1.6.3", "framer-motion": "^10.16.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-redux": "^8.1.2", + "react-redux": "^9.0.4", "react-router-dom": "^6.15.0", "react-tooltip": "^5.21.1", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", "vite": "^2.9.12", "vite-plugin-svgr": "^0.3.0", "web-vitals": "^2.1.4" @@ -462,9 +466,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", - "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.7.tgz", + "integrity": "sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -728,19 +732,31 @@ "node": ">=14" } }, + "node_modules/@redux-devtools/extension": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@redux-devtools/extension/-/extension-3.3.0.tgz", + "integrity": "sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==", + "dependencies": { + "@babel/runtime": "^7.23.2", + "immutable": "^4.3.4" + }, + "peerDependencies": { + "redux": "^3.1.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/@reduxjs/toolkit": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.6.tgz", - "integrity": "sha512-Gc4ikl90ORF4viIdAkY06JNUnODjKfGxZRwATM30EdHq8hLSVoSrwXne5dd739yenP5bJxAX7tLuOWK5RPGtrw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz", + "integrity": "sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA==", "dependencies": { - "immer": "^9.0.21", - "redux": "^4.2.1", - "redux-thunk": "^2.4.2", - "reselect": "^4.1.8" + "immer": "^10.0.3", + "redux": "^5.0.0", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.0.2" + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "peerDependenciesMeta": { "react": { @@ -1031,15 +1047,6 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.2.tgz", "integrity": "sha512-PHKZuMN+K5qgKIWhBodXzQslTo5P+K/6LqeKXS6O/4liIDdZqaX5RXrCK++LAw+y/nptN48YmUMFiQHRSWYwtQ==" }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw==", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -1118,9 +1125,9 @@ "integrity": "sha512-FbtmBWCcSa2J4zL781Zf1p5YUBXQomPEcep9QZCfRfQgTxz3pJWiDFLebohZ9fFntX5ibzOkSsrJ0TEew8cAog==" }, "node_modules/@types/react": { - "version": "18.2.23", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.23.tgz", - "integrity": "sha512-qHLW6n1q2+7KyBEYnrZpcsAmU/iiCh9WGCKgXvMxx89+TYdJWRjZohVIo9XTcoLhfX3+/hP0Pbulu3bCZQ9PSA==", + "version": "18.2.46", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.46.tgz", + "integrity": "sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1279,6 +1286,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/autoprefixer": { "version": "10.4.16", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", @@ -1327,6 +1339,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz", + "integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1538,6 +1560,17 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1676,6 +1709,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -2159,6 +2200,25 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -2183,6 +2243,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -2399,28 +2472,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", + "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3083,6 +3148,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -3524,6 +3608,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3573,35 +3662,23 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-redux": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz", - "integrity": "sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.0.4.tgz", + "integrity": "sha512-9J1xh8sWO0vYq2sCxK2My/QO7MzUMRi3rpiILP/+tDr8krBHixC6JMM17fMK88+Oh3e4Ae6/sHIhNBgkUivwFA==", "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", "use-sync-external-store": "^1.0.0" }, "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": ">=0.69", + "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, "react-native": { "optional": true }, @@ -3610,11 +3687,6 @@ } } }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, "node_modules/react-router": { "version": "6.16.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.16.0.tgz", @@ -3692,19 +3764,16 @@ } }, "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", "peerDependencies": { - "redux": "^4" + "redux": "^5.0.0" } }, "node_modules/regenerator-runtime": { @@ -3729,9 +3798,9 @@ } }, "node_modules/reselect": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", - "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz", + "integrity": "sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==" }, "node_modules/resolve": { "version": "1.22.6", diff --git a/frontend/package.json b/frontend/package.json index 558d700..5324411 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,17 +3,21 @@ "version": "0.1.0", "private": true, "dependencies": { - "@reduxjs/toolkit": "^1.9.5", + "@redux-devtools/extension": "^3.3.0", + "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "@vitejs/plugin-react-refresh": "^1.3.1", + "axios": "^1.6.3", "framer-motion": "^10.16.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-redux": "^8.1.2", + "react-redux": "^9.0.4", "react-router-dom": "^6.15.0", "react-tooltip": "^5.21.1", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", "vite": "^2.9.12", "vite-plugin-svgr": "^0.3.0", "web-vitals": "^2.1.4" diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index bb726a1..a0f9cd6 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -14,11 +14,14 @@ function App() { } /> - } > - + } /> + } /> } /> - } /> - } /> + {/**/} + {/**/} + {/**/} + {/**/} + {/*} />*/} diff --git a/frontend/src/app/store.jsx b/frontend/src/app/store.jsx index 9567971..5a848bf 100644 --- a/frontend/src/app/store.jsx +++ b/frontend/src/app/store.jsx @@ -1,16 +1,12 @@ -import { configureStore } from '@reduxjs/toolkit' -import { setupListeners } from '@reduxjs/toolkit/query' -import { userAuthApi } from '../services/userAuthApi' -// import authReducer from '../features/authSlice' -// import userReducer from '../features/userSlice' -export const store = configureStore({ - reducer: { - [userAuthApi.reducerPath]: userAuthApi.reducer, - // auth: authReducer, - // user: userReducer - }, - middleware: (getDefaultMiddleware) => - getDefaultMiddleware().concat(userAuthApi.middleware), -}) +import { configureStore } from '@reduxjs/toolkit'; +import rootReducer from '../services/reducers'; -setupListeners(store.dispatch) \ No newline at end of file +export const store = configureStore({ + reducer: rootReducer, + // middleware: getDefaultMiddleware => + // getDefaultMiddleware({ + // thunk: { + // extraArgument: { serviceApi } + // } + // }) +}); diff --git a/frontend/src/pages/Login/Login.jsx b/frontend/src/pages/Login/Login.jsx index b0be01e..fa9b613 100644 --- a/frontend/src/pages/Login/Login.jsx +++ b/frontend/src/pages/Login/Login.jsx @@ -2,15 +2,19 @@ import {socialButtons} from "../../components/SocialButton"; import InputField from "../../components/InputField"; import React, {useState} from "react"; import SubmitButton from "../../components/SubmitButton"; -import {Link} from "react-router-dom"; import {motion} from "framer-motion"; import {ReactComponent as LogoIcon} from "../../assets/img/Schwarz-logo.svg"; -const LoginScreen = () => { +import {useNavigate} from "react-router-dom"; +import {login} from "../../services/actions/auth"; +import {connect} from "react-redux"; +const LoginScreen = ({ login, isAuthenticated }) => { const [email, setEmail] = useState(""); const [emailError, setEmailError] = useState(""); const [password, setPassword] = useState(""); const [passwordError, setPasswordError] = useState(""); const [showErrors, setShowErrors] = useState(false); + const navigate = useNavigate(); + const handleEmailChange = (event) => { const newEmail = event.target.value; setEmail(newEmail); @@ -35,7 +39,9 @@ const LoginScreen = () => { } }; - const handleContinue1Click = () => { + const handleContinue1Click = e => { + e.preventDefault(); + setShowErrors(true); // Check for errors and show them if present @@ -44,12 +50,42 @@ const LoginScreen = () => { } else { } + + login(email, password); }; + if (isAuthenticated) { + return + } + + // const continueWithGoogle = async () => { + // try { + // const res = await axios.get(`${process.env.REACT_APP_API_URL}/auth/o/google-oauth2/?redirect_uri=${process.env.REACT_APP_API_URL}/google`) + // + // window.location.replace(res.data.authorization_url); + // } catch (err) { + // + // } + // }; + // + // const continueWithFacebook = async () => { + // try { + // const res = await axios.get(`${process.env.REACT_APP_API_URL}/auth/o/facebook/?redirect_uri=${process.env.REACT_APP_API_URL}/facebook`) + // + // window.location.replace(res.data.authorization_url); + // } catch (err) { + // + // } + // }; + + if (isAuthenticated) { + return navigate('/'); + } + return (
-
+
handleContinue1Click(e)}>

Welcome Back

Reconnect with your Schwarz ID for seamless access.

@@ -110,7 +146,7 @@ const LoginScreen = () => { onClick={handleContinue1Click}/>
-
+
@@ -120,4 +156,8 @@ const LoginScreen = () => { ) } -export default LoginScreen; \ No newline at end of file +const mapStateToProps = state => ({ + isAuthenticated: state.auth.isAuthenticated +}); + +export default connect(mapStateToProps, { login })(LoginScreen); \ No newline at end of file diff --git a/frontend/src/pages/Signup/SignupScreen.jsx b/frontend/src/pages/Signup/SignupScreen.jsx index 89fcbb7..bcc6c17 100644 --- a/frontend/src/pages/Signup/SignupScreen.jsx +++ b/frontend/src/pages/Signup/SignupScreen.jsx @@ -42,31 +42,6 @@ const SignupScreen = () => { setShowSignupTab3(true) } - const handleSubmit = async (e) => { - e.preventDefault(); - const data = new FormData(e.currentTarget); - const actualData = { - name: data.get('name'), - email: data.get('email'), - aadhaar: data.get('aadhaar'), - mobile: data.get('mobile'), - password: data.get('password'), - password2: data.get('password2'), - } - const res = await registerUser(actualData) - if (res.error) { - console.log(typeof (res.error.data.errors)) - console.log(res.error.data.errors) - setServerError(res.error.data.errors) - } - if (res.data) { - console.log(typeof (res.data)) - console.log(res.data) - storeToken(res.data.token) - navigate('/dashboard') - } - } - return (
diff --git a/frontend/src/services/actions/auth.js b/frontend/src/services/actions/auth.js new file mode 100644 index 0000000..804515d --- /dev/null +++ b/frontend/src/services/actions/auth.js @@ -0,0 +1,271 @@ +import axios from 'axios'; +import { + LOGIN_SUCCESS, + LOGIN_FAIL, + USER_LOADED_SUCCESS, + USER_LOADED_FAIL, + AUTHENTICATED_SUCCESS, + AUTHENTICATED_FAIL, + PASSWORD_RESET_SUCCESS, + PASSWORD_RESET_FAIL, + PASSWORD_RESET_CONFIRM_SUCCESS, + PASSWORD_RESET_CONFIRM_FAIL, + SIGNUP_SUCCESS, + SIGNUP_FAIL, + ACTIVATION_SUCCESS, + ACTIVATION_FAIL, + GOOGLE_AUTH_SUCCESS, + GOOGLE_AUTH_FAIL, + FACEBOOK_AUTH_SUCCESS, + FACEBOOK_AUTH_FAIL, + LOGOUT +} from './types'; + +export const load_user = () => async dispatch => { + if (localStorage.getItem('access')) { + const config = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `JWT ${localStorage.getItem('access')}`, + 'Accept': 'application/json' + } + }; + + try { + const res = await axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config); + + dispatch({ + type: USER_LOADED_SUCCESS, + payload: res.data + }); + } catch (err) { + dispatch({ + type: USER_LOADED_FAIL + }); + } + } else { + dispatch({ + type: USER_LOADED_FAIL + }); + } +}; + +export const googleAuthenticate = (state, code) => async dispatch => { + if (state && code && !localStorage.getItem('access')) { + const config = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }; + + const details = { + 'state': state, + 'code': code + }; + + const formBody = Object.keys(details).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(details[key])).join('&'); + + try { + const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/o/google-oauth2/?${formBody}`, config); + + dispatch({ + type: GOOGLE_AUTH_SUCCESS, + payload: res.data + }); + + dispatch(load_user()); + } catch (err) { + dispatch({ + type: GOOGLE_AUTH_FAIL + }); + } + } +}; + +export const facebookAuthenticate = (state, code) => async dispatch => { + if (state && code && !localStorage.getItem('access')) { + const config = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }; + + const details = { + 'state': state, + 'code': code + }; + + const formBody = Object.keys(details).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(details[key])).join('&'); + + try { + const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/o/facebook/?${formBody}`, config); + + dispatch({ + type: FACEBOOK_AUTH_SUCCESS, + payload: res.data + }); + + dispatch(load_user()); + } catch (err) { + dispatch({ + type: FACEBOOK_AUTH_FAIL + }); + } + } +}; + +export const checkAuthenticated = () => async dispatch => { + if (localStorage.getItem('access')) { + const config = { + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } + }; + + const body = JSON.stringify({ token: localStorage.getItem('access') }); + + try { + const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/verify/`, body, config) + + if (res.data.code !== 'token_not_valid') { + dispatch({ + type: AUTHENTICATED_SUCCESS + }); + } else { + dispatch({ + type: AUTHENTICATED_FAIL + }); + } + } catch (err) { + dispatch({ + type: AUTHENTICATED_FAIL + }); + } + + } else { + dispatch({ + type: AUTHENTICATED_FAIL + }); + } +}; + +export const login = (email, password) => async dispatch => { + const config = { + headers: { + 'Content-Type': 'application/json' + } + }; + + const body = JSON.stringify({ email, password }); + + try { + const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/create/`, body, config); + + dispatch({ + type: LOGIN_SUCCESS, + payload: res.data + }); + + dispatch(load_user()); + } catch (err) { + dispatch({ + type: LOGIN_FAIL + }) + } +}; + +export const signup = (first_name, last_name, email, password, re_password) => async dispatch => { + const config = { + headers: { + 'Content-Type': 'application/json' + } + }; + + const body = JSON.stringify({ first_name, last_name, email, password, re_password }); + + try { + const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/users/`, body, config); + + dispatch({ + type: SIGNUP_SUCCESS, + payload: res.data + }); + } catch (err) { + dispatch({ + type: SIGNUP_FAIL + }) + } +}; + +export const verify = (uid, token) => async dispatch => { + const config = { + headers: { + 'Content-Type': 'application/json' + } + }; + + const body = JSON.stringify({ uid, token }); + + try { + await axios.post(`${process.env.REACT_APP_API_URL}/auth/users/activation/`, body, config); + + dispatch({ + type: ACTIVATION_SUCCESS, + }); + } catch (err) { + dispatch({ + type: ACTIVATION_FAIL + }) + } +}; + +export const reset_password = (email) => async dispatch => { + const config = { + headers: { + 'Content-Type': 'application/json' + } + }; + + const body = JSON.stringify({ email }); + + try { + await axios.post(`${process.env.REACT_APP_API_URL}/auth/users/reset_password/`, body, config); + + dispatch({ + type: PASSWORD_RESET_SUCCESS + }); + } catch (err) { + dispatch({ + type: PASSWORD_RESET_FAIL + }); + } +}; + +export const reset_password_confirm = (uid, token, new_password, re_new_password) => async dispatch => { + const config = { + headers: { + 'Content-Type': 'application/json' + } + }; + + const body = JSON.stringify({ uid, token, new_password, re_new_password }); + + try { + await axios.post(`${process.env.REACT_APP_API_URL}/auth/users/reset_password_confirm/`, body, config); + + dispatch({ + type: PASSWORD_RESET_CONFIRM_SUCCESS + }); + } catch (err) { + dispatch({ + type: PASSWORD_RESET_CONFIRM_FAIL + }); + } +}; + +export const logout = () => dispatch => { + dispatch({ + type: LOGOUT + }); +}; diff --git a/frontend/src/services/actions/types.js b/frontend/src/services/actions/types.js new file mode 100644 index 0000000..fd4faa7 --- /dev/null +++ b/frontend/src/services/actions/types.js @@ -0,0 +1,19 @@ +export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; +export const LOGIN_FAIL = 'LOGIN_FAIL'; +export const SIGNUP_SUCCESS = 'SIGNUP_SUCCESS'; +export const SIGNUP_FAIL = 'SIGNUP_FAIL'; +export const ACTIVATION_SUCCESS = 'ACTIVATION_SUCCESS'; +export const ACTIVATION_FAIL = 'ACTIVATION_FAIL'; +export const USER_LOADED_SUCCESS = 'USER_LOADED_SUCCESS'; +export const USER_LOADED_FAIL = 'USER_LOADED_FAIL'; +export const AUTHENTICATED_SUCCESS = 'AUTHENTICATED_SUCCESS'; +export const AUTHENTICATED_FAIL = 'AUTHENTICATED_FAIL'; +export const PASSWORD_RESET_FAIL = 'PASSWORD_RESET_FAIL'; +export const PASSWORD_RESET_SUCCESS = 'PASSWORD_RESET_SUCCESS'; +export const PASSWORD_RESET_CONFIRM_FAIL = 'PASSWORD_RESET_CONFIRM_FAIL'; +export const PASSWORD_RESET_CONFIRM_SUCCESS = 'PASSWORD_RESET_CONFIRM_SUCCESS'; +export const GOOGLE_AUTH_SUCCESS = 'GOOGLE_AUTH_SUCCESS'; +export const GOOGLE_AUTH_FAIL = 'GOOGLE_AUTH_FAIL'; +export const FACEBOOK_AUTH_SUCCESS = 'FACEBOOK_AUTH_SUCCESS'; +export const FACEBOOK_AUTH_FAIL = 'FACEBOOK_AUTH_FAIL'; +export const LOGOUT = 'LOGOUT'; diff --git a/frontend/src/services/reducers/auth.js b/frontend/src/services/reducers/auth.js new file mode 100644 index 0000000..a76d029 --- /dev/null +++ b/frontend/src/services/reducers/auth.js @@ -0,0 +1,96 @@ +import { + LOGIN_SUCCESS, + LOGIN_FAIL, + USER_LOADED_SUCCESS, + USER_LOADED_FAIL, + AUTHENTICATED_SUCCESS, + AUTHENTICATED_FAIL, + PASSWORD_RESET_SUCCESS, + PASSWORD_RESET_FAIL, + PASSWORD_RESET_CONFIRM_SUCCESS, + PASSWORD_RESET_CONFIRM_FAIL, + SIGNUP_SUCCESS, + SIGNUP_FAIL, + ACTIVATION_SUCCESS, + ACTIVATION_FAIL, + GOOGLE_AUTH_SUCCESS, + GOOGLE_AUTH_FAIL, + FACEBOOK_AUTH_SUCCESS, + FACEBOOK_AUTH_FAIL, + LOGOUT +} from '../actions/types'; + +const initialState = { + access: localStorage.getItem('access'), + refresh: localStorage.getItem('refresh'), + isAuthenticated: null, + user: null +}; + +export default function(state = initialState, action) { + const { type, payload } = action; + + switch(type) { + case AUTHENTICATED_SUCCESS: + return { + ...state, + isAuthenticated: true + } + case LOGIN_SUCCESS: + case GOOGLE_AUTH_SUCCESS: + case FACEBOOK_AUTH_SUCCESS: + localStorage.setItem('access', payload.access); + localStorage.setItem('refresh', payload.refresh); + return { + ...state, + isAuthenticated: true, + access: payload.access, + refresh: payload.refresh + } + case SIGNUP_SUCCESS: + return { + ...state, + isAuthenticated: false + } + case USER_LOADED_SUCCESS: + return { + ...state, + user: payload + } + case AUTHENTICATED_FAIL: + return { + ...state, + isAuthenticated: false + } + case USER_LOADED_FAIL: + return { + ...state, + user: null + } + case GOOGLE_AUTH_FAIL: + case FACEBOOK_AUTH_FAIL: + case LOGIN_FAIL: + case SIGNUP_FAIL: + case LOGOUT: + localStorage.removeItem('access'); + localStorage.removeItem('refresh'); + return { + ...state, + access: null, + refresh: null, + isAuthenticated: false, + user: null + } + case PASSWORD_RESET_SUCCESS: + case PASSWORD_RESET_FAIL: + case PASSWORD_RESET_CONFIRM_SUCCESS: + case PASSWORD_RESET_CONFIRM_FAIL: + case ACTIVATION_SUCCESS: + case ACTIVATION_FAIL: + return { + ...state + } + default: + return state + } +}; diff --git a/frontend/src/services/reducers/index.js b/frontend/src/services/reducers/index.js new file mode 100644 index 0000000..f5d9042 --- /dev/null +++ b/frontend/src/services/reducers/index.js @@ -0,0 +1,6 @@ +import { combineReducers } from 'redux'; +import auth from './auth'; + +export default combineReducers({ + auth +});