From 24ea3038cc59f16511f82bb922eb417ade15fc82 Mon Sep 17 00:00:00 2001 From: Andrew B Date: Thu, 30 Jul 2020 20:10:46 +0700 Subject: [PATCH] Adds vk_id --- backend/src/auth/auth.controller.ts | 23 ++++++------- backend/src/auth/auth.service.ts | 5 +-- backend/src/entities/user.entity.ts | 5 +++ backend/src/models/user.model.ts | 12 +++++++ backend/src/user/user.service.ts | 8 +++++ frontend/src/App/index.tsx | 21 ++---------- .../src/components/LayoutDefault/index.tsx | 33 +++++++++++++++---- frontend/src/components/LayoutUser/index.tsx | 1 - .../components/VKButton/VKButton.module.scss | 9 +++-- frontend/src/components/VKButton/index.tsx | 2 +- frontend/src/pages/HomePage/index.tsx | 8 +++-- frontend/src/pages/SignInPage/index.tsx | 7 ++-- frontend/src/pages/UserPage/index.tsx | 5 --- 13 files changed, 82 insertions(+), 57 deletions(-) diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts index 1025d9e..e5988d8 100644 --- a/backend/src/auth/auth.controller.ts +++ b/backend/src/auth/auth.controller.ts @@ -5,7 +5,7 @@ import { ValidationPipe, UnprocessableEntityException, } from "@nestjs/common"; -import { AuthModel, UserModel, AuthVK, IGrant } from "./../models"; +import { AuthModel, UserModel, AuthVK, IGrant, UserDTO } from "./../models"; import { AuthService } from "./auth.service"; import { UserService } from "./../user"; @@ -17,7 +17,7 @@ export class AuthController { ) {} @Post("/login/vk") - async vk(@Body(new ValidationPipe()) auth: AuthVK): Promise { + async vk(@Body(new ValidationPipe()) auth: AuthVK): Promise { let authData; try { @@ -26,14 +26,14 @@ export class AuthController { throw new UnprocessableEntityException("Wrong VK code"); } - if (!authData.data.hasOwnProperty("email")) { - throw new UnprocessableEntityException("Email should be provided"); - } + const hasEmail = authData.data.hasOwnProperty("email"); - const emailUser = await this.userService.findByEmail(authData.data.email); + const _user = hasEmail + ? await this.userService.findByEmail(authData.data.email) + : await this.userService.findByVkId(authData.data.user_id); - if (emailUser) { - return this.authService.authenticate(emailUser, true); + if (_user) { + return this.authService.authenticate(_user, true); } try { @@ -45,6 +45,7 @@ export class AuthController { const profile = data.response[0]; let user: UserModel = { + vk_id: authData.data.user_id, email: authData.data.email, password: null, name: `${profile.first_name} ${profile.last_name}`, @@ -61,18 +62,18 @@ export class AuthController { } @Post("/login") - async login(@Body(new ValidationPipe()) auth: AuthModel): Promise { + async login(@Body(new ValidationPipe()) auth: AuthModel): Promise { return this.authService.authenticate(auth); } @Post("/register") async register( @Body(new ValidationPipe()) userModel: UserModel - ): Promise { + ): Promise { const emailExists = await this.userService.findByEmail(userModel.email); if (emailExists) { - throw new UnprocessableEntityException(); + throw new UnprocessableEntityException("Email already exists!"); } await this.userService.create(userModel); diff --git a/backend/src/auth/auth.service.ts b/backend/src/auth/auth.service.ts index e3fcaeb..fb9543e 100644 --- a/backend/src/auth/auth.service.ts +++ b/backend/src/auth/auth.service.ts @@ -4,7 +4,7 @@ import { JwtService } from "@nestjs/jwt"; import { UserService } from "./../user"; import { UserEntity } from "../entities"; import { JwtPayloadInterface } from "./interfaces"; -import { AuthModel } from "../models"; +import { AuthModel, UserDTO } from "../models"; @Injectable() export class AuthService { @@ -21,7 +21,7 @@ export class AuthService { async authenticate( auth: AuthModel, skipPasswordCheck: boolean = false - ): Promise { + ): Promise { const user = await this.userService.findByEmailWithPassword(auth.email); if (!user) { @@ -39,6 +39,7 @@ export class AuthService { return { id: user.id, + vk_id: user.vk_id, email: user.email, grant: user.grant, name: user.name, diff --git a/backend/src/entities/user.entity.ts b/backend/src/entities/user.entity.ts index a0e271e..4e0b5c8 100644 --- a/backend/src/entities/user.entity.ts +++ b/backend/src/entities/user.entity.ts @@ -3,6 +3,11 @@ import { Entity, Column } from "typeorm"; @Entity() export class UserEntity extends BaseEntity { + @Column({ + nullable: true, + }) + vk_id: number; + @Column() name: string; diff --git a/backend/src/models/user.model.ts b/backend/src/models/user.model.ts index 4accca5..233c27a 100644 --- a/backend/src/models/user.model.ts +++ b/backend/src/models/user.model.ts @@ -6,6 +6,8 @@ export enum IGrant { } export class UserModel { + vk_id?: number; + @IsEmail() email: string; @@ -20,3 +22,13 @@ export class UserModel { avatar_url?: string; } + +export class UserDTO { + id: number; + vk_id: number; + email: string; + name: string; + grant: IGrant; + avatar_url: string; + token: string; +} diff --git a/backend/src/user/user.service.ts b/backend/src/user/user.service.ts index b004163..029e5a1 100644 --- a/backend/src/user/user.service.ts +++ b/backend/src/user/user.service.ts @@ -47,6 +47,14 @@ export class UserService { }); } + async findByVkId(vk_id: number): Promise { + return await this.userRepository.findOne({ + where: { + vk_id, + }, + }); + } + async findById(id: number): Promise { return await this.userRepository.findOneOrFail(id); } diff --git a/frontend/src/App/index.tsx b/frontend/src/App/index.tsx index 3ee3114..9fce533 100644 --- a/frontend/src/App/index.tsx +++ b/frontend/src/App/index.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { observer } from "mobx-react"; import { BrowserRouter, Switch, Route } from "react-router-dom"; import NotFound from "pages/404"; @@ -7,25 +6,9 @@ import SignInPage from "pages/SignInPage"; import UserPage from "pages/UserPage"; import HomePage from "pages/HomePage"; -import { RequestState } from "types/RequestState"; - -import { useStores } from "stores/useStores"; - interface IProps {} -const App: React.FC = observer(() => { - const { user, state, getProfile } = useStores()["UserStore"]; - - React.useEffect(() => { - const token = sessionStorage.getItem("token"); - - if (!user && state !== RequestState.LOADING && token) { - getProfile().catch(console.log); - } - }, [user, state, getProfile]); - - // if (state === RequestState.LOADING) return

Loading..

; - +const App: React.FC = () => { return ( @@ -37,6 +20,6 @@ const App: React.FC = observer(() => { ); -}); +}; export default App; diff --git a/frontend/src/components/LayoutDefault/index.tsx b/frontend/src/components/LayoutDefault/index.tsx index a8fd5c9..038eed4 100644 --- a/frontend/src/components/LayoutDefault/index.tsx +++ b/frontend/src/components/LayoutDefault/index.tsx @@ -1,12 +1,31 @@ import React from "react"; +import { observer } from "mobx-react"; +import { Link, useHistory } from "react-router-dom"; -import styles from "./LayoutDefault.module.scss"; -import { Link } from "react-router-dom"; -import { IUser } from "stores/UserStore"; import { useStores } from "stores/useStores"; +import { RequestState } from "types/RequestState"; + +import styles from "./LayoutDefault.module.scss"; + +const PRIVATE_ROUTES = ["/user"]; + +const LayoutDefault: React.FC = observer((props) => { + const { user, state, getProfile, logout } = useStores()["UserStore"]; + let history = useHistory(); + + React.useEffect(() => { + const token = sessionStorage.getItem("token"); + + if (PRIVATE_ROUTES.includes(history.location.pathname) && !token) + return history.push("/signin"); -const LayoutDefault: React.FC = (props) => { - const user: IUser = useStores()["UserStore"].user; + if (!user && state !== RequestState.LOADING && token) { + getProfile().catch(() => { + history.push("/signin"); + logout(); + }); + } + }, [user, state, getProfile, logout, history]); return (
@@ -15,12 +34,12 @@ const LayoutDefault: React.FC = (props) => { {user ? ( Мой профиль ) : ( - Войти + Войти )}
{props.children}
); -}; +}); export default LayoutDefault; diff --git a/frontend/src/components/LayoutUser/index.tsx b/frontend/src/components/LayoutUser/index.tsx index 1507be9..ea9ba2a 100644 --- a/frontend/src/components/LayoutUser/index.tsx +++ b/frontend/src/components/LayoutUser/index.tsx @@ -10,7 +10,6 @@ const LayoutUser: React.FC = (props) => { return (
- {/*

Профиль

*/}
{props.children}
diff --git a/frontend/src/components/VKButton/VKButton.module.scss b/frontend/src/components/VKButton/VKButton.module.scss index dacd209..bed40d1 100644 --- a/frontend/src/components/VKButton/VKButton.module.scss +++ b/frontend/src/components/VKButton/VKButton.module.scss @@ -1,14 +1,17 @@ .vk-button__input { - width: 150px; display: flex; - background-color: #4680c2; + align-items: center; - color: white; + color: #4680c2; border: none; border-radius: 10px; font-weight: bold; padding-right: 20px; cursor: pointer; + + &:hover { + opacity: 0.8; + } } .vk-button { diff --git a/frontend/src/components/VKButton/index.tsx b/frontend/src/components/VKButton/index.tsx index 267aa94..35b2c9e 100644 --- a/frontend/src/components/VKButton/index.tsx +++ b/frontend/src/components/VKButton/index.tsx @@ -49,7 +49,7 @@ const VKButton: React.FC = (props) => { alt="vk logo" className={styles["vk-button__input-icon"]} /> - Вконтакте + Войти через Вконтакте {isError &&

Ошибка входа через ВК

}
diff --git a/frontend/src/pages/HomePage/index.tsx b/frontend/src/pages/HomePage/index.tsx index d46e742..6d26e6d 100644 --- a/frontend/src/pages/HomePage/index.tsx +++ b/frontend/src/pages/HomePage/index.tsx @@ -1,10 +1,12 @@ import React from "react"; -import LayoutDefault from "components/LayoutDefault"; +import { observer } from "mobx-react"; import { useStores } from "stores/useStores"; import { IUser } from "stores/UserStore"; -const HomePage = () => { +import LayoutDefault from "components/LayoutDefault"; + +const HomePage = observer(() => { const user: IUser = useStores()["UserStore"].user; return ( @@ -13,6 +15,6 @@ const HomePage = () => { {user &&

О привет, {user.name}

}
); -}; +}); export default HomePage; diff --git a/frontend/src/pages/SignInPage/index.tsx b/frontend/src/pages/SignInPage/index.tsx index 5f77b9c..1d55252 100644 --- a/frontend/src/pages/SignInPage/index.tsx +++ b/frontend/src/pages/SignInPage/index.tsx @@ -1,14 +1,11 @@ import React from "react"; -import { RouteComponentProps } from "react-router-dom"; import VKButton from "components/VKButton"; - -import styles from "./SignInPage.module.scss"; import LayoutDefault from "components/LayoutDefault"; -interface IProps extends RouteComponentProps {} +import styles from "./SignInPage.module.scss"; -const SignInPage: React.FC = (props) => { +const SignInPage: React.FC = () => { return (
diff --git a/frontend/src/pages/UserPage/index.tsx b/frontend/src/pages/UserPage/index.tsx index 748bc4e..f0b4e29 100644 --- a/frontend/src/pages/UserPage/index.tsx +++ b/frontend/src/pages/UserPage/index.tsx @@ -15,13 +15,8 @@ interface IProps extends RouteComponentProps { class UserPage extends React.Component { componentDidMount() { - const { getProfile, user } = this.props.UserStore; const token = sessionStorage.getItem("token"); - if (!token) return this.props.history.push("/signin"); - - if (!user) - return getProfile().catch(() => this.props.history.push("/signin")); } handleLogout = () => {