You've already forked WhereToGoRedux
mirror of
https://github.com/Llloooggg/WhereToGoRedux.git
synced 2026-03-05 20:46:24 +03:00
[backend + frontend]: Добавлена базовая регистрация
This commit is contained in:
@@ -1,10 +1,35 @@
|
||||
asgiref==3.5.2
|
||||
backports.zoneinfo==0.2.1
|
||||
certifi==2022.6.15.1
|
||||
cffi==1.15.1
|
||||
charset-normalizer==2.1.1
|
||||
coreapi==2.3.3
|
||||
coreschema==0.0.4
|
||||
cryptography==38.0.1
|
||||
defusedxml==0.7.1
|
||||
Django==4.1.1
|
||||
django-cors-headers==3.13.0
|
||||
django-filter==22.1
|
||||
django-templated-mail==1.1.1
|
||||
djangorestframework==3.13.1
|
||||
djangorestframework-gis==1.0
|
||||
djangorestframework-simplejwt==4.8.0
|
||||
djoser==2.1.0
|
||||
idna==3.3
|
||||
itypes==1.2.0
|
||||
Jinja2==3.1.2
|
||||
MarkupSafe==2.1.1
|
||||
oauthlib==3.2.1
|
||||
psycopg2==2.9.3
|
||||
pycparser==2.21
|
||||
PyJWT==2.4.0
|
||||
python3-openid==3.2.0
|
||||
pytz==2022.2.1
|
||||
requests==2.28.1
|
||||
requests-oauthlib==1.3.1
|
||||
six==1.16.0
|
||||
social-auth-app-django==4.0.0
|
||||
social-auth-core==4.3.0
|
||||
sqlparse==0.4.2
|
||||
uritemplate==4.1.1
|
||||
urllib3==1.26.12
|
||||
|
||||
@@ -4,5 +4,5 @@ from django.utils.translation import gettext_lazy
|
||||
|
||||
class AuthConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "authentication"
|
||||
verbose_name = gettext_lazy("authentication")
|
||||
name = "accounts"
|
||||
verbose_name = gettext_lazy("accounts")
|
||||
14
backend/wheretogo/accounts/urls.py
Normal file
14
backend/wheretogo/accounts/urls.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from django.urls import path
|
||||
from django.urls import include
|
||||
|
||||
from accounts.views import CustomTokenObtainPairView
|
||||
|
||||
urlpatterns = [
|
||||
path("", include("djoser.urls")),
|
||||
path(
|
||||
"auth/jwt/create",
|
||||
CustomTokenObtainPairView.as_view(),
|
||||
name="custom_token_obtain_pair",
|
||||
),
|
||||
path("auth/", include("djoser.urls.jwt")),
|
||||
]
|
||||
13
backend/wheretogo/accounts/views.py
Normal file
13
backend/wheretogo/accounts/views.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
||||
|
||||
|
||||
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
|
||||
def validate(self, attrs):
|
||||
data = super().validate(attrs)
|
||||
data["username"] = self.user.username
|
||||
return data
|
||||
|
||||
|
||||
class CustomTokenObtainPairView(TokenObtainPairView):
|
||||
serializer_class = CustomTokenObtainPairSerializer
|
||||
@@ -1,9 +0,0 @@
|
||||
from django.urls import path
|
||||
|
||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
||||
from rest_framework_simplejwt.views import TokenRefreshView
|
||||
|
||||
urlpatterns = [
|
||||
path("token", TokenObtainPairView.as_view(), name="token_obtain_pair"),
|
||||
path("token/refresh", TokenRefreshView.as_view(), name="token_refresh"),
|
||||
]
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-09-10 14:48+0300\n"
|
||||
"POT-Creation-Date: 2022-09-12 23:55+0300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -20,6 +20,10 @@ msgstr ""
|
||||
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
|
||||
"%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||
|
||||
#: accounts/apps.py:8
|
||||
msgid "accounts"
|
||||
msgstr "аккаунты"
|
||||
|
||||
#: facilities/apps.py:8 facilities/models.py:18
|
||||
msgid "facilities"
|
||||
msgstr "заведения"
|
||||
|
||||
@@ -43,11 +43,11 @@ INSTALLED_APPS = [
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django.contrib.gis",
|
||||
"djoser",
|
||||
"rest_framework",
|
||||
"rest_framework_simplejwt",
|
||||
"rest_framework_gis",
|
||||
"corsheaders",
|
||||
"authentication",
|
||||
"accounts",
|
||||
"facilities",
|
||||
]
|
||||
|
||||
@@ -128,9 +128,12 @@ STATIC_URL = "static/"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
SIMPLE_JWT = {
|
||||
"AUTH_HEADER_TYPES": ("JWT",),
|
||||
}
|
||||
|
||||
@@ -11,3 +11,7 @@ DATABASES = {
|
||||
"PORT": "5432",
|
||||
}
|
||||
}
|
||||
|
||||
CORS_ALLOWED_ORIGINS = [
|
||||
"http://localhost:8080",
|
||||
]
|
||||
|
||||
@@ -19,6 +19,6 @@ from django.urls import include
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("api/auth/", include("authentication.urls")),
|
||||
path("api/accounts/", include("accounts.urls")),
|
||||
path("api/facilities/", include("facilities.urls")),
|
||||
]
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<div class="card card-container">
|
||||
<Form @submit="handleLogin" :validation-schema="schema"
|
||||
class="p-4 p-md-5 border rounded-3 bg-light">
|
||||
<h5 class="card-title">Login</h5>
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<Field name="username" type="text" class="form-control" />
|
||||
@@ -61,7 +62,7 @@ export default {
|
||||
},
|
||||
created() {
|
||||
if (this.loggedIn) {
|
||||
this.$router.push("/profile");
|
||||
this.$router.push("/");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -69,7 +70,7 @@ export default {
|
||||
this.loading = true;
|
||||
this.$store.dispatch("auth/login", user).then(
|
||||
() => {
|
||||
this.$router.push("/profile");
|
||||
this.$router.push("/");
|
||||
},
|
||||
(error) => {
|
||||
this.loading = false;
|
||||
|
||||
112
frontend/wheretogo/src/components/RegistrationPage.vue
Normal file
112
frontend/wheretogo/src/components/RegistrationPage.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="container col-xl-10 col-xxl-8 px-4 py-5">
|
||||
<div class="row align-items-center g-lg-5 py-5">
|
||||
<div class="col-md-10 mx-auto col-lg-5">
|
||||
<div class="card card-container">
|
||||
<Form @submit="handleRegister" :validation-schema="schema"
|
||||
class="p-4 p-md-5 border rounded-3 bg-light">
|
||||
<h5 class="card-title">Registration</h5>
|
||||
<div v-if="!successful">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<Field name="username" type="text" class="form-control" />
|
||||
<ErrorMessage name="username" class="error-feedback" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<Field name="email" type="email" class="form-control" />
|
||||
<ErrorMessage name="email" class="error-feedback" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<Field name="password" type="password" class="form-control" />
|
||||
<ErrorMessage name="password" class="error-feedback" />
|
||||
</div>
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary btn-block" :disabled="loading">
|
||||
<span v-show="loading" class="spinner-border spinner-border-sm"></span>
|
||||
Sign Up
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
<div v-if="message" class="alert" :class="successful ? 'alert-success' : 'alert-danger'">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { Form, Field, ErrorMessage } from "vee-validate";
|
||||
import * as yup from "yup";
|
||||
export default {
|
||||
name: "RegistrationPage",
|
||||
components: {
|
||||
Form,
|
||||
Field,
|
||||
ErrorMessage,
|
||||
},
|
||||
data() {
|
||||
const schema = yup.object().shape({
|
||||
username: yup
|
||||
.string()
|
||||
.required("Username is required!")
|
||||
.min(3, "Must be at least 3 characters!")
|
||||
.max(20, "Must be maximum 20 characters!"),
|
||||
email: yup
|
||||
.string()
|
||||
.required("Email is required!")
|
||||
.email("Email is invalid!")
|
||||
.max(50, "Must be maximum 50 characters!"),
|
||||
password: yup
|
||||
.string()
|
||||
.required("Password is required!")
|
||||
.min(6, "Must be at least 6 characters!")
|
||||
.max(40, "Must be maximum 40 characters!"),
|
||||
});
|
||||
return {
|
||||
successful: false,
|
||||
loading: false,
|
||||
message: "",
|
||||
schema,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
loggedIn() {
|
||||
return this.$store.state.auth.status.loggedIn;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.loggedIn) {
|
||||
this.$router.push("/");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleRegister(user) {
|
||||
this.message = "";
|
||||
this.successful = false;
|
||||
this.loading = true;
|
||||
this.$store.dispatch("auth/register", user).then(
|
||||
(data) => {
|
||||
this.message = data.message;
|
||||
this.successful = true;
|
||||
this.loading = false;
|
||||
},
|
||||
(error) => {
|
||||
this.message =
|
||||
(error.response &&
|
||||
error.response.data &&
|
||||
error.response.data.message) ||
|
||||
error.message ||
|
||||
error.toString();
|
||||
this.successful = false;
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createWebHistory, createRouter } from "vue-router";
|
||||
import MapPage from "./components/MapPage.vue";
|
||||
import LoginPage from "./components/LoginPage.vue";
|
||||
import RegistrationPage from "./components/RegistrationPage.vue";
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
@@ -11,6 +12,10 @@ const routes = [
|
||||
path: "/login",
|
||||
component: LoginPage,
|
||||
},
|
||||
{
|
||||
path: "/register",
|
||||
component: RegistrationPage,
|
||||
},
|
||||
];
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export default function authHeader() {
|
||||
let user = JSON.parse(localStorage.getItem('user'));
|
||||
if (user && user.accessToken) {
|
||||
return { Authorization: 'Bearer ' + user.accessToken };
|
||||
if (user && user.access) {
|
||||
return { Authorization: 'Bearer ' + user.access };
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import axios from "axios";
|
||||
const API_URL = "http://localhost:8000/api/auth/";
|
||||
const API_URL = "http://127.0.0.1:8000/api/accounts/";
|
||||
class AuthService {
|
||||
login(user) {
|
||||
return axios
|
||||
.post(API_URL + "token", {
|
||||
.post(API_URL + "auth/jwt/create", {
|
||||
username: user.username,
|
||||
password: user.password,
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data.accessToken) {
|
||||
if (response.data.access) {
|
||||
localStorage.setItem("user", JSON.stringify(response.data));
|
||||
}
|
||||
return response.data;
|
||||
@@ -18,7 +18,7 @@ class AuthService {
|
||||
localStorage.removeItem("user");
|
||||
}
|
||||
register(user) {
|
||||
return axios.post(API_URL + "signup", {
|
||||
return axios.post(API_URL + "users/", {
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import axios from 'axios';
|
||||
import authHeader from './auth-header';
|
||||
const API_URL = 'http://localhost:8000/api/auth/user/';
|
||||
const API_URL = 'http://127.0.0.1:8000/api/accounts/users/me/';
|
||||
class UserService {
|
||||
getPublicContent() {
|
||||
return axios.get(API_URL + 'all');
|
||||
|
||||
Reference in New Issue
Block a user