diff --git a/pairent_backend/pairent_app/urls.py b/pairent_backend/pairent_app/urls.py index 5270515..6b9b991 100644 --- a/pairent_backend/pairent_app/urls.py +++ b/pairent_backend/pairent_app/urls.py @@ -1,4 +1,5 @@ -from django.urls import path +from django.urls import path, re_path +# from django.conf.urls import url from rest_framework.urlpatterns import format_suffix_patterns from . import views @@ -10,5 +11,6 @@ urlpatterns = format_suffix_patterns([ path("apartaments/favorite/", views.ApartamentGetManyViewSet.as_view({'get': 'list'})), # пример: apartaments/favorite/?user_id=1 user_id - id пользователя path("apartaments/filters/", views.ApartmentFilter.as_view({'post': 'list'})), path("psych_test/add_result/", views.PsychTestAddResultViewSet.as_view({'patch': 'update'})), # пример: psych_test/add_result/1/?result=50 result - результат псих теста пользователя - path("users/get_compatible", views.CompatibleUsersView.as_view({'post': 'list'})) + path("users/get_compatible", views.CompatibleUsersView.as_view({'post': 'list'})), + re_path(r'^auth/vvsu/', views.VVSUAuthProxy), ]) diff --git a/pairent_backend/pairent_app/views.py b/pairent_backend/pairent_app/views.py index 34da1f2..1744561 100644 --- a/pairent_backend/pairent_app/views.py +++ b/pairent_backend/pairent_app/views.py @@ -3,7 +3,7 @@ from rest_framework.response import Response from rest_framework.views import APIView, View from rest_framework.request import Request -from django.http import HttpResponseBadRequest +from django.http import HttpResponseBadRequest, HttpResponse from django.db.models.query import QuerySet from django.core.validators import validate_email @@ -15,7 +15,7 @@ from .serializer import (ApartamentListSerializer, PsychTestAddResultSerializer, PublicUserSerializer) -import json, math, random, re +import json, math, random, re, requests class ApartamentViewSet(viewsets.ReadOnlyModelViewSet): """Вывод списка квартир или отдельной квартиры""" @@ -137,4 +137,18 @@ class CompatibleUsersView(viewsets.ViewSet): random.shuffle(users); - return Response(users); \ No newline at end of file + return Response(users); + +def VVSUAuthProxy(req: Request): + proxy = 'https://vvsu.ru/connect' + req.path[len('/api/auth/vvsu'):]; + + preq = requests.request(req.method, proxy, headers={ + 'User-Agent': 'OIDC Client / Pairent', + 'Origin': 'http://pairent.vvsu.ru', + 'Referer': 'http://pairent.vvsu.ru' + }); + + resp = HttpResponse(preq.content); + resp.headers['Content-Type'] = preq.headers['Content-Type']; + + return resp; \ No newline at end of file diff --git a/pairent_backend/requirements.txt b/pairent_backend/requirements.txt index b929a02..fb3ac95 100644 --- a/pairent_backend/requirements.txt +++ b/pairent_backend/requirements.txt @@ -2,4 +2,5 @@ mysqlclient django djangorestframework django-cors-headers -Pillow \ No newline at end of file +Pillow +requests \ No newline at end of file diff --git a/pairent_frontend_react/src/components/UI/BlueButton/index.jsx b/pairent_frontend_react/src/components/UI/BlueButton/index.jsx new file mode 100644 index 0000000..066524b --- /dev/null +++ b/pairent_frontend_react/src/components/UI/BlueButton/index.jsx @@ -0,0 +1,34 @@ +import { styled } from "styled-components"; + +const BlueButton = styled.button` + background: white; + border: 2px solid royalblue; + border-radius: 12px; + color: royalblue; + font-weight: 600; + line-height: 20px; + transition: 150ms ease; + width: 100%; + font-size: 10.5pt; + height: 36px; + padding: 6px 10px; + clip-path: border-box; + box-sizing: border-box; + + & svg { + fill: royalblue; + margin: 0; + margin-right: 6px; + transform: translateY(2px); + } + + &:hover { + color: white; + background: royalblue; + } + &:hover svg { + fill: white + } +`; + +export default BlueButton; \ No newline at end of file diff --git a/pairent_frontend_react/src/pages/LoggedIn/index.jsx b/pairent_frontend_react/src/pages/LoggedIn/index.jsx new file mode 100644 index 0000000..11444b5 --- /dev/null +++ b/pairent_frontend_react/src/pages/LoggedIn/index.jsx @@ -0,0 +1 @@ +// TODO: Make a logged in handler \ No newline at end of file diff --git a/pairent_frontend_react/src/pages/LoginPage/index.jsx b/pairent_frontend_react/src/pages/LoginPage/index.jsx new file mode 100644 index 0000000..9421e78 --- /dev/null +++ b/pairent_frontend_react/src/pages/LoginPage/index.jsx @@ -0,0 +1,130 @@ +import React from 'react'; + +import { styled } from 'styled-components'; +import BlueButton from '../../components/UI/BlueButton'; +import { HashLoader } from 'react-spinners'; + +import * as OpenID from 'oidc-client-ts'; +import constants from '../../constants'; + +const { API_ROOT } = constants; + +const LoginBox = styled.div` + position: fixed; + top: 45%; + left: 50%; + transform: translate(-50%, -50%); + border: 1px solid #c2c4c2; + border-radius: 12px; + padding: 24px 36px; + background: white; + box-shadow: 0 2px 1px #00000010; + + text-align: center; + + & h2 { + margin: 0px 0; + } + & hr { + margin: 16px 0; + margin-bottom: 24px; + height: 0px; + border: 0; + border-bottom: 1px solid #c2c4c2; + box-shadow: 0 2px 1px #c2c4c280; + } + & p { + font-size: 8pt; + color: gray; + margin-top: 16px; + } +`; + +const LoginButton = styled(BlueButton)` + font-size: 11pt; + width: 250px; + height: 60px; + padding: 16px 20px; + + font-size: 11.5pt; + font-weight: 700; + cursor: ${props => props.disabled ? 'default' : 'pointer'}; + + & svg { + height: 12pt; + margin-left: 6px + } + &:hover { + background: ${props => props.disabled ? 'white' : 'royalblue'}; + } +`; + +const OIDCConfig = { + onSignIn: () => {}, + authority: API_ROOT + '/api/auth/vvsu/', + client_id: 'it-hub-client', + redirect_uri: 'https://pairent.vvsu.ru/sign-in/', + scope: [ + 'openid', + // 'vvsu_IdUser', + // 'vvsu_IdEmpl', + // 'vvsu_IdStud', + // 'vvsu_login', + // 'given_name', + // 'family_name' + ] +}; + +const VVSULogoSVG = () => { + return ; +} + +export default class LoginPage extends React.Component { + constructor(props) { + super(props); + + this.state = { + loading: false + } + + this.openid = this.openid.bind(this); + } + + async openid() { + if (this.state.loading === true) return; + this.setState({loading: true}); + + OpenID.Log.setLogger(console); + OpenID.Log.setLevel(OpenID.Log.DEBUG); + + let client = new OpenID.OidcClient(OIDCConfig); + + const req = await client.createSigninRequest({}); + window.location.href = req.url; + } + + render() { + return ( +
+ +

Вход

+
+ + { + this.state.loading ? + : + <> + Войти через + + + } + +

+ Вход осуществляется только через
+ Систему Единого Входа ВВГУ +

+
+
+ ); + } +} \ No newline at end of file diff --git a/pairent_frontend_react/src/router/index.jsx b/pairent_frontend_react/src/router/index.jsx index 90dd83e..d3bcd15 100644 --- a/pairent_frontend_react/src/router/index.jsx +++ b/pairent_frontend_react/src/router/index.jsx @@ -3,6 +3,7 @@ import Comparisons from "../pages/Comparisons"; import IndexApartment from "../pages/IndexApartment"; import IndexPage from "../pages/IndexPage"; import Tinder from "../pages/Tinder"; +import LoginPage from "../pages/LoginPage"; // НА ПРОДАШКЕНЕ СДЕЛАТЬ ПРИВАТНЫЕ МАРШРУТЫ // export const privateRoutes = [ @@ -16,7 +17,9 @@ export default Object.freeze({ { path: '/apartment/:id', component: , exact: true }, { path: '/favorites', component: , exact: true }, { path: '/comparisons', component: , exact: true }, - { path: '/tinder', component: , exact: true } + { path: '/tinder', component: , exact: true }, + { path: '/login', component: , exact: true }, + { path: '/sign-in', component: , exact: true } ], privateRoutes: [] }) \ No newline at end of file diff --git a/pairent_frontend_react/yarn.lock b/pairent_frontend_react/yarn.lock index 9885d3a..bf14c28 100644 --- a/pairent_frontend_react/yarn.lock +++ b/pairent_frontend_react/yarn.lock @@ -1730,6 +1730,11 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +crypto-js@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" + integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== + css-color-keywords@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz" @@ -2706,6 +2711,11 @@ json5@^2.2.2: array-includes "^3.1.5" object.assign "^4.1.3" +jwt-decode@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== + levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" @@ -2893,6 +2903,14 @@ object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" +oidc-client-ts@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/oidc-client-ts/-/oidc-client-ts-2.2.3.tgz#85c6382540cf59383896d6470c9c3908d5d625f7" + integrity sha512-nheMI8kSJu8L+Pmg7E4ra+LJ7lOTK60IfyblFmyx5qaJwwDpc1zkzFyH9eyERAQ92xUTF1uaB8WiaVxXATjLGA== + dependencies: + crypto-js "^4.1.1" + jwt-decode "^3.1.2" + once@^1.3.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"