├── backend
├── backend
│ ├── __init__.py
│ ├── asgi.py
│ ├── wsgi.py
│ ├── urls.py
│ └── settings.py
├── user_api
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── urls.py
│ ├── serializers.py
│ ├── models.py
│ ├── validations.py
│ └── views.py
├── requirements.txt
├── entrypoint.sh
├── Dockerfile
└── manage.py
├── frontend
├── public
│ ├── favicon.ico
│ ├── robots.txt
│ ├── manifest.json
│ └── index.html
├── Dockerfile
├── src
│ ├── index.css
│ ├── App.css
│ ├── index.js
│ └── App.js
└── package.json
├── .env
├── nginx
├── Dockerfile
└── default.conf
├── README.md
└── docker-compose.yaml
/backend/backend/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/user_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/user_api/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | SECRET_KEY='django-insecure--o+^2-knvxng9b0p=hz8g6-l-y8h15%vn7)v2luv_2#$lq_xef'
2 | DEBUG=True
3 |
--------------------------------------------------------------------------------
/backend/user_api/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/frontend/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.19.0-alpine
2 |
3 | COPY ./default.conf /etc/nginx/conf.d/default.conf
4 |
--------------------------------------------------------------------------------
/backend/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==4.1.5
2 | django-cors-headers==3.13.0
3 | djangorestframework==3.14.0
4 | gunicorn==20.1.0
--------------------------------------------------------------------------------
/frontend/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:alpine
2 |
3 | WORKDIR /app
4 | COPY . .
5 |
6 | RUN npm install
7 |
8 | CMD ["npm", "run", "build"]
9 |
--------------------------------------------------------------------------------
/backend/user_api/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class UserApiConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'user_api'
7 |
--------------------------------------------------------------------------------
/backend/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | python manage.py makemigrations
4 | python manage.py migrate --no-input
5 | python manage.py collectstatic --no-input
6 |
7 | gunicorn backend.wsgi:application --bind 0.0.0.0:8000
8 |
--------------------------------------------------------------------------------
/backend/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8-slim
2 |
3 | RUN pip install --upgrade pip
4 |
5 | COPY ./requirements.txt .
6 | RUN pip install -r requirements.txt
7 |
8 | COPY . /app
9 | WORKDIR /app
10 |
11 | COPY ./entrypoint.sh .
12 | ENTRYPOINT ["sh", "/app/entrypoint.sh"]
13 |
--------------------------------------------------------------------------------
/backend/user_api/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from . import views
3 |
4 | urlpatterns = [
5 | path('register', views.UserRegister.as_view(), name='register'),
6 | path('login', views.UserLogin.as_view(), name='login'),
7 | path('logout', views.UserLogout.as_view(), name='logout'),
8 | path('user', views.UserView.as_view(), name='user'),
9 | ]
10 |
--------------------------------------------------------------------------------
/nginx/default.conf:
--------------------------------------------------------------------------------
1 | upstream backend {
2 | server backend:8000;
3 | }
4 |
5 | server {
6 | listen 80;
7 |
8 | location /api/ {
9 | proxy_pass http://backend;
10 | }
11 |
12 | location /static/rest_framework/ {
13 | root /static/;
14 | }
15 |
16 | location / {
17 | root /var/www/frontend;
18 | try_files $uri $uri/ /index.html;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React/DjangoRF Authentication App
2 |
3 | Authentication app using React and Django REST framework with session authentication.
4 |
5 | ## Installations
6 |
7 | * backend
8 | ```
9 | pip install djangorestframework
10 | pip install django-cors-headers
11 | ```
12 |
13 | * frontend
14 | ```
15 | npm install axios
16 | npm install react-bootstrap bootstrap
17 | ```
18 |
--------------------------------------------------------------------------------
/frontend/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/backend/backend/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for backend project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/backend/backend/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for backend project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/frontend/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | /* boostrap form style */
11 |
12 | .form-inline {
13 | width: 100%;
14 | }
15 |
16 | .form-group {
17 | width: 90%;
18 | }
19 |
20 | .input-group {
21 | width: 90% !important;
22 | }
23 |
24 | .form-control {
25 | width: 80% !important;
26 | }
27 |
28 | span.input-group-addon {
29 | width: 50px !important;
30 | }
31 |
32 | .center {
33 | display: flex;
34 | justify-content: center;
35 | align-items: center;
36 | margin-top: 5%;
37 | }
--------------------------------------------------------------------------------
/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import 'bootstrap/dist/css/bootstrap.min.css';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | //reportWebVitals();
18 |
--------------------------------------------------------------------------------
/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 |
3 | services:
4 | backend:
5 | volumes:
6 | - static:/static
7 | env_file:
8 | - .env
9 | build:
10 | context: ./backend
11 | ports:
12 | - "8000:8000"
13 | frontend:
14 | build:
15 | context: ./frontend
16 | volumes:
17 | - frontend:/app/build
18 | nginx:
19 | build:
20 | context: ./nginx
21 | volumes:
22 | - static:/static
23 | - frontend:/var/www/frontend
24 | ports:
25 | - "80:80"
26 | depends_on:
27 | - backend
28 | - frontend
29 |
30 | volumes:
31 | static:
32 | frontend:
33 |
--------------------------------------------------------------------------------
/backend/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/backend/backend/urls.py:
--------------------------------------------------------------------------------
1 | """backend URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/4.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path, include
18 |
19 | urlpatterns = [
20 | path('admin/', admin.site.urls),
21 | path('api/', include('user_api.urls')),
22 | ]
23 |
--------------------------------------------------------------------------------
/backend/user_api/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from django.contrib.auth import get_user_model, authenticate
3 |
4 | UserModel = get_user_model()
5 |
6 | class UserRegisterSerializer(serializers.ModelSerializer):
7 | class Meta:
8 | model = UserModel
9 | fields = '__all__'
10 | def create(self, clean_data):
11 | user_obj = UserModel.objects.create_user(email=clean_data['email'], password=clean_data['password'])
12 | user_obj.username = clean_data['username']
13 | user_obj.save()
14 | return user_obj
15 |
16 | class UserLoginSerializer(serializers.Serializer):
17 | email = serializers.EmailField()
18 | password = serializers.CharField()
19 | ##
20 | def check_user(self, clean_data):
21 | user = authenticate(username=clean_data['email'], password=clean_data['password'])
22 | if not user:
23 | raise ValidationError('user not found')
24 | return user
25 |
26 | class UserSerializer(serializers.ModelSerializer):
27 | class Meta:
28 | model = UserModel
29 | fields = ('email', 'username')
30 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "axios": "^1.2.3",
10 | "bootstrap": "^5.2.3",
11 | "http-server": "^14.1.1",
12 | "js-cookie": "^3.0.1",
13 | "react": "^18.2.0",
14 | "react-bootstrap": "^2.7.0",
15 | "react-dom": "^18.2.0",
16 | "react-scripts": "5.0.1",
17 | "web-vitals": "^2.1.4"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject"
24 | },
25 | "eslintConfig": {
26 | "extends": [
27 | "react-app",
28 | "react-app/jest"
29 | ]
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.2%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 1 chrome version",
39 | "last 1 firefox version",
40 | "last 1 safari version"
41 | ]
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/backend/user_api/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.base_user import BaseUserManager
3 | from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
4 |
5 | class AppUserManager(BaseUserManager):
6 | def create_user(self, email, password=None):
7 | if not email:
8 | raise ValueError('An email is required.')
9 | if not password:
10 | raise ValueError('A password is required.')
11 | email = self.normalize_email(email)
12 | user = self.model(email=email)
13 | user.set_password(password)
14 | user.save()
15 | return user
16 | def create_superuser(self, email, password=None):
17 | if not email:
18 | raise ValueError('An email is required.')
19 | if not password:
20 | raise ValueError('A password is required.')
21 | user = self.create_user(email, password)
22 | user.is_superuser = True
23 | user.save()
24 | return user
25 |
26 |
27 | class AppUser(AbstractBaseUser, PermissionsMixin):
28 | user_id = models.AutoField(primary_key=True)
29 | email = models.EmailField(max_length=50, unique=True)
30 | username = models.CharField(max_length=50)
31 | USERNAME_FIELD = 'email'
32 | REQUIRED_FIELDS = ['username']
33 | objects = AppUserManager()
34 | def __str__(self):
35 | return self.username
36 |
--------------------------------------------------------------------------------
/backend/user_api/validations.py:
--------------------------------------------------------------------------------
1 | from django.core.exceptions import ValidationError
2 | from django.contrib.auth import get_user_model
3 | UserModel = get_user_model()
4 |
5 | def custom_validation(data):
6 | email = data['email'].strip()
7 | username = data['username'].strip()
8 | password = data['password'].strip()
9 | ##
10 | if not email or UserModel.objects.filter(email=email).exists():
11 | raise ValidationError('choose another email')
12 | ##
13 | if not password or len(password) < 8:
14 | raise ValidationError('choose another password, min 8 characters')
15 | ##
16 | if not username:
17 | raise ValidationError('choose another username')
18 | return data
19 |
20 |
21 | def validate_email(data):
22 | email = data['email'].strip()
23 | if not email:
24 | raise ValidationError('an email is needed')
25 | return True
26 |
27 | def validate_username(data):
28 | username = data['username'].strip()
29 | if not username:
30 | raise ValidationError('choose another username')
31 | return True
32 |
33 | def validate_password(data):
34 | password = data['password'].strip()
35 | if not password:
36 | raise ValidationError('a password is needed')
37 | return True
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/backend/user_api/views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model, login, logout
2 | from rest_framework.authentication import SessionAuthentication
3 | from rest_framework.views import APIView
4 | from rest_framework.response import Response
5 | from .serializers import UserRegisterSerializer, UserLoginSerializer, UserSerializer
6 | from rest_framework import permissions, status
7 | from .validations import custom_validation, validate_email, validate_password
8 |
9 |
10 | class UserRegister(APIView):
11 | permission_classes = (permissions.AllowAny,)
12 | def post(self, request):
13 | clean_data = custom_validation(request.data)
14 | serializer = UserRegisterSerializer(data=clean_data)
15 | if serializer.is_valid(raise_exception=True):
16 | user = serializer.create(clean_data)
17 | if user:
18 | return Response(serializer.data, status=status.HTTP_201_CREATED)
19 | return Response(status=status.HTTP_400_BAD_REQUEST)
20 |
21 |
22 | class UserLogin(APIView):
23 | permission_classes = (permissions.AllowAny,)
24 | authentication_classes = (SessionAuthentication,)
25 | ##
26 | def post(self, request):
27 | data = request.data
28 | assert validate_email(data)
29 | assert validate_password(data)
30 | serializer = UserLoginSerializer(data=data)
31 | if serializer.is_valid(raise_exception=True):
32 | user = serializer.check_user(data)
33 | login(request, user)
34 | return Response(serializer.data, status=status.HTTP_200_OK)
35 |
36 |
37 | class UserLogout(APIView):
38 | permission_classes = (permissions.AllowAny,)
39 | authentication_classes = ()
40 | def post(self, request):
41 | logout(request)
42 | return Response(status=status.HTTP_200_OK)
43 |
44 |
45 | class UserView(APIView):
46 | permission_classes = (permissions.IsAuthenticated,)
47 | authentication_classes = (SessionAuthentication,)
48 | ##
49 | def get(self, request):
50 | serializer = UserSerializer(request.user)
51 | return Response({'user': serializer.data}, status=status.HTTP_200_OK)
52 |
53 |
--------------------------------------------------------------------------------
/backend/backend/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for backend project.
3 |
4 | Generated by 'django-admin startproject' using Django 4.1.4.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/4.1/ref/settings/
11 | """
12 |
13 | from pathlib import Path
14 | import os
15 |
16 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
17 | BASE_DIR = Path(__file__).resolve().parent.parent
18 |
19 |
20 | # Quick-start development settings - unsuitable for production
21 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
22 |
23 | # SECURITY WARNING: keep the secret key used in production secret!
24 | SECRET_KEY = os.getenv('SECRET_KEY')
25 |
26 | # SECURITY WARNING: don't run with debug turned on in production!
27 | DEBUG = os.getenv('DEBUG')
28 |
29 | ALLOWED_HOSTS = ['*']
30 |
31 | CORS_ALLOWED_ORIGINS = [
32 | 'http://localhost',
33 | 'http://127.0.0.1',
34 | 'http://0.0.0.0',
35 | ]
36 |
37 | CORS_ALLOW_CREDENTIALS = True
38 |
39 |
40 | # Application definition
41 |
42 | INSTALLED_APPS = [
43 | 'django.contrib.admin',
44 | 'django.contrib.auth',
45 | 'django.contrib.contenttypes',
46 | 'django.contrib.sessions',
47 | 'django.contrib.messages',
48 | 'django.contrib.staticfiles',
49 | 'rest_framework',
50 | 'corsheaders',
51 | 'user_api.apps.UserApiConfig',
52 | ]
53 |
54 | MIDDLEWARE = [
55 | 'corsheaders.middleware.CorsMiddleware',
56 | 'django.middleware.security.SecurityMiddleware',
57 | 'django.contrib.sessions.middleware.SessionMiddleware',
58 | 'django.middleware.common.CommonMiddleware',
59 | 'django.middleware.csrf.CsrfViewMiddleware',
60 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
61 | 'django.contrib.messages.middleware.MessageMiddleware',
62 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
63 | ]
64 |
65 | ROOT_URLCONF = 'backend.urls'
66 |
67 | TEMPLATES = [
68 | {
69 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
70 | 'DIRS': [],
71 | 'APP_DIRS': True,
72 | 'OPTIONS': {
73 | 'context_processors': [
74 | 'django.template.context_processors.debug',
75 | 'django.template.context_processors.request',
76 | 'django.contrib.auth.context_processors.auth',
77 | 'django.contrib.messages.context_processors.messages',
78 | ],
79 | },
80 | },
81 | ]
82 |
83 | WSGI_APPLICATION = 'backend.wsgi.application'
84 |
85 |
86 | # Database
87 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases
88 |
89 | DATABASES = {
90 | 'default': {
91 | 'ENGINE': 'django.db.backends.sqlite3',
92 | 'NAME': BASE_DIR / 'db.sqlite3',
93 | }
94 | }
95 |
96 | ## User model
97 | AUTH_USER_MODEL = 'user_api.AppUser'
98 |
99 | REST_FRAMEWORK = {
100 | 'DEFAULT_PERMISSION_CLASSES': (
101 | 'rest_framework.permissions.IsAuthenticated',
102 | ),
103 | 'DEFAULT_AUTHENTICATION_CLASSES': (
104 | 'rest_framework.authentication.SessionAuthentication',
105 | ),
106 | }
107 |
108 | # Password validation
109 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
110 |
111 | AUTH_PASSWORD_VALIDATORS = [
112 | {
113 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
114 | },
115 | {
116 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
117 | },
118 | {
119 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
120 | },
121 | {
122 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
123 | },
124 | ]
125 |
126 |
127 | # Internationalization
128 | # https://docs.djangoproject.com/en/4.1/topics/i18n/
129 |
130 | LANGUAGE_CODE = 'en-us'
131 |
132 | TIME_ZONE = 'UTC'
133 |
134 | USE_I18N = True
135 |
136 | USE_TZ = True
137 |
138 |
139 | # Static files (CSS, JavaScript, Images)
140 | # https://docs.djangoproject.com/en/4.1/howto/static-files/
141 |
142 | STATIC_URL = 'static/'
143 | STATIC_ROOT = '/static/'
144 |
145 | # Default primary key field type
146 | # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
147 |
148 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
149 |
--------------------------------------------------------------------------------
/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 | import React from 'react';
3 | import { useState, useEffect } from 'react';
4 | import axios from 'axios';
5 | import Container from 'react-bootstrap/Container';
6 | import Navbar from 'react-bootstrap/Navbar';
7 | import Button from 'react-bootstrap/Button';
8 | import Form from 'react-bootstrap/Form';
9 |
10 |
11 | axios.defaults.xsrfCookieName = 'csrftoken';
12 | axios.defaults.xsrfHeaderName = 'X-CSRFToken';
13 | axios.defaults.withCredentials = true;
14 |
15 | const client = axios.create({
16 | baseURL: "http://127.0.0.1:8000"
17 | });
18 |
19 | function App() {
20 |
21 | const [currentUser, setCurrentUser] = useState();
22 | const [registrationToggle, setRegistrationToggle] = useState(false);
23 | const [email, setEmail] = useState('');
24 | const [username, setUsername] = useState('');
25 | const [password, setPassword] = useState('');
26 |
27 | useEffect(() => {
28 | client.get("/api/user")
29 | .then(function(res) {
30 | setCurrentUser(true);
31 | })
32 | .catch(function(error) {
33 | setCurrentUser(false);
34 | });
35 | }, []);
36 |
37 | function update_form_btn() {
38 | if (registrationToggle) {
39 | document.getElementById("form_btn").innerHTML = "Register";
40 | setRegistrationToggle(false);
41 | } else {
42 | document.getElementById("form_btn").innerHTML = "Log in";
43 | setRegistrationToggle(true);
44 | }
45 | }
46 |
47 | function submitRegistration(e) {
48 | e.preventDefault();
49 | client.post(
50 | "/api/register",
51 | {
52 | email: email,
53 | username: username,
54 | password: password
55 | }
56 | ).then(function(res) {
57 | client.post(
58 | "/api/login",
59 | {
60 | email: email,
61 | password: password
62 | }
63 | ).then(function(res) {
64 | setCurrentUser(true);
65 | });
66 | });
67 | }
68 |
69 | function submitLogin(e) {
70 | e.preventDefault();
71 | client.post(
72 | "/api/login",
73 | {
74 | email: email,
75 | password: password
76 | }
77 | ).then(function(res) {
78 | setCurrentUser(true);
79 | });
80 | }
81 |
82 | function submitLogout(e) {
83 | e.preventDefault();
84 | client.post(
85 | "/api/logout",
86 | {withCredentials: true}
87 | ).then(function(res) {
88 | setCurrentUser(false);
89 | });
90 | }
91 |
92 | if (currentUser) {
93 | return (
94 |
95 |
96 |
97 | Authentication App
98 |
99 |
100 |
101 |
104 |
105 |
106 |
107 |
108 |
109 |
You're logged in!
110 |
111 |
112 | );
113 | }
114 | return (
115 |
116 |
117 |
118 | Authentication App
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | {
128 | registrationToggle ? (
129 |
130 |
132 | Email address
133 | setEmail(e.target.value)} />
134 |
135 | We'll never share your email with anyone else.
136 |
137 |
138 |
139 | Username
140 | setUsername(e.target.value)} />
141 |
142 |
143 | Password
144 | setPassword(e.target.value)} />
145 |
146 |
149 |
150 |
151 | ) : (
152 |
153 |
155 | Email address
156 | setEmail(e.target.value)} />
157 |
158 | We'll never share your email with anyone else.
159 |
160 |
161 |
162 | Password
163 | setPassword(e.target.value)} />
164 |
165 |
168 |
169 |
170 | )
171 | }
172 |
173 | );
174 | }
175 |
176 | export default App;
177 |
--------------------------------------------------------------------------------