diff --git a/backend/config/social.js b/backend/config/social.js new file mode 100644 index 0000000..7238232 --- /dev/null +++ b/backend/config/social.js @@ -0,0 +1,6 @@ +module.exports.SOCIAL = { + VK: { + client_secret: 'Z71DsxoMF7PS9kayLuks', + client_id: 5987644, + } +}; diff --git a/backend/config/strings.js b/backend/config/strings.js new file mode 100644 index 0000000..e402ca5 --- /dev/null +++ b/backend/config/strings.js @@ -0,0 +1,11 @@ +// export const OAUTH_FAILED_TITLE = 'Ошибка авторизации'; +module.exports.STRINGS = { + OAUTH: { + ERROR_TITLE: 'Ошибка авторизации', + ERROR_HEADING: 'Ошибка', + ERROR_TEXT: 'Авторизация не удалась, попробуйте еще раз', + ERROR_CLOSE_BUTTON: 'ЗАКРЫТЬ', + + SUCCESS_TITLE: 'Успешно!', + }, +}; diff --git a/backend/models/User.js b/backend/models/User.js index a64552e..b19881e 100644 --- a/backend/models/User.js +++ b/backend/models/User.js @@ -1,21 +1,27 @@ const mongoose = require('mongoose'); + const { Schema } = mongoose; // Schemas -const UserSchema = new Schema({ - id: { type: String, required: true }, - role: { - type: String, - required: true, - enum: ['admin', 'guest', 'user', 'vk'], - }, - token: { type: String, required: true }, - created_at: { type: Date, required: true, default: Date.now }, +const UserSchema = new Schema( + { + _id: { type: String, required: true }, + role: { + type: String, + required: true, + enum: ['admin', 'guest', 'user', 'vk'], + }, + token: { type: String, required: true }, + created_at: { type: Date, required: true, default: Date.now }, - first_name: { type: String }, - last_name: { type: String }, - photo: { type: String }, -}); + first_name: { type: String }, + last_name: { type: String }, + photo: { type: String }, + }, + { + timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' } + } +); const User = mongoose.model('User', UserSchema); module.exports.User = User; diff --git a/backend/public/stylesheets/social/vk.less b/backend/public/stylesheets/social/vk.less new file mode 100644 index 0000000..a5ffeb6 --- /dev/null +++ b/backend/public/stylesheets/social/vk.less @@ -0,0 +1,47 @@ +body { + background: #6d9dc8; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; + color: white; + margin: 0; + font-weight: 300; +} + +div#message { + padding: 100px; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + height: 100vh; + width: 100vw; + margin: 0; + position: absolute; + box-sizing: border-box; + text-align: left; +} + +div.bg { + background: white; + color: #666666; + padding: 20px 40px; + border-radius: 4px; +} + +h1 { + margin-bottom: 10px; + text-transform: uppercase; +} + +button { + height: 32px; + padding: 0 24px; + color: white; + border: none; + box-sizing: border-box; + margin-top: 40px; + border-radius: 3px; + background: #6d9dc8; + font-weight: bold; + float: right; + cursor: pointer; +} diff --git a/backend/routes/auth/check.js b/backend/routes/auth/check.js index f40d4ba..09a4ee1 100644 --- a/backend/routes/auth/check.js +++ b/backend/routes/auth/check.js @@ -3,16 +3,22 @@ const { generateGuest, generateRandomUrl } = require('./guest'); module.exports = async (req, res) => { const { id, token } = req.query; - const user = await User.find({ id, token }); + console.log(req.query); + console.log('SEARCHING', id, token); + + const user = await User.findOne({ _id: id, token }); const random_url = await generateRandomUrl(); - if (user.length > 0) { - return res.send({ success: true, ...user[0].toObject() }); + if (user) { + console.log('FOUND'); + return res.send({ success: true, ...user.toObject(), id: user._id, random_url }); } const guest = await generateGuest(); + const created = await User.create(guest).then(result => result.toObject()); + return res.send({ - success: false, error: 'user not found', error_code: 1231, ...guest, random_url + success: false, error: 'user not found', error_code: 1231, ...created, id: created._id, random_url }); }; diff --git a/backend/routes/auth/guest.js b/backend/routes/auth/guest.js index 01ad72f..e2dadcd 100644 --- a/backend/routes/auth/guest.js +++ b/backend/routes/auth/guest.js @@ -2,19 +2,19 @@ const { genRandomSequence } = require('../../utils/gen'); const { User } = require('../../models/User'); const generateGuestToken = () => { - const id = `guest:${genRandomSequence(16)}`; + const _id = `guest:${genRandomSequence(16)}`; - return User.find({ id }).then(user => { + return User.find({ _id }).then(user => { if (user.length) return generateGuestToken(); - return id; + return _id; }); }; -const generateUser = (id, role = 'guest') => { +const generateUser = (_id, role = 'guest') => { const token = `seq:${genRandomSequence(32)}`; - return { id, token, role }; + return { _id, token, role }; }; const saveUser = user => { @@ -37,7 +37,7 @@ const generateGuest = async () => { .then(generateUser); const random_url = await generateRandomUrl(); - return { ...user, random_url }; + return { ...user, random_url, first_name: '', last_name: '', photo: '' }; }; module.exports = async (req, res) => { diff --git a/backend/routes/auth/social/vk.js b/backend/routes/auth/social/vk.js index e448a90..aa0ef81 100644 --- a/backend/routes/auth/social/vk.js +++ b/backend/routes/auth/social/vk.js @@ -1,13 +1,10 @@ const { User } = require('../../../models/User'); const axios = require('axios'); -const { generateGuest, generateRandomUrl, generateUser } = require('../guest'); -// -// const generateTokenUrl = (host, code) => ( -// `https://oauth.vk.com/access_token?client_id=5987644&redirect_uri=http://${host}/` + -// `auth/social/vk&client_secret=Z71DsxoMF7PS9kayLuks&code=${code}` -// ); +const { generateUser } = require('../guest'); +const { STRINGS } = require('../../../config/strings'); +const { SOCIAL } = require('../../../config/social'); -const fetchUserData = async (req) => { +const fetchUserData = async (req, res) => { const { query: { code } } = req; const host = req.get('host'); @@ -15,13 +12,18 @@ const fetchUserData = async (req) => { 'https://oauth.vk.com/access_token', { params: { - client_id: 5987644, - client_secret: 'Z71DsxoMF7PS9kayLuks', + client_id: SOCIAL.VK.client_id, + client_secret: SOCIAL.VK.client_secret, code, redirect_uri: `http://${host}/auth/social/vk`, } } - ).catch(() => ({ data: { } })); + ).catch(() => res.render('social/vk_error', { + title: STRINGS.OAUTH.ERROR_TITLE, + heading: STRINGS.OAUTH.ERROR_HEADING, + reason: STRINGS.OAUTH.ERROR_TEXT, + button: STRINGS.OAUTH.ERROR_CLOSE_BUTTON, + })); const { data } = await axios.get( 'https://api.vk.com/method/users.get', @@ -33,26 +35,41 @@ const fetchUserData = async (req) => { access_token, } } - ).catch(() => ({ data: { response: [] } })); + ).catch(() => res.render('social/vk_error', { + title: STRINGS.OAUTH.ERROR_TITLE, + heading: STRINGS.OAUTH.ERROR_HEADING, + reason: STRINGS.OAUTH.ERROR_TEXT, + button: STRINGS.OAUTH.ERROR_CLOSE_BUTTON, + })); return data; }; module.exports = async (req, res) => { - const { response } = await fetchUserData(req); + const { response } = await fetchUserData(req, res); const { first_name = '', last_name = '', photo = '', id = '' } = response[0]; const newUser = await generateUser(`vk:${id}`, 'vk'); + const name = `${first_name} ${last_name}`; const user = { - ...newUser, first_name, last_name, photo + ...newUser, first_name, last_name, photo, name, }; - // todo: error handling - // console.log('USE', user); + const auth = await User.findOne({ _id: user._id }); - res.send(user); + if (auth) { + await auth.set({ + first_name, last_name, name, photo + }).save(); + + res.render('social/success', { title: STRINGS.OAUTH.SUCCESS_TITLE, ...user }); + } else { + const created = await User.create(user, (err, result) => result.toObject()); + + res.render('social/success', { title: STRINGS.OAUTH.SUCCESS_TITLE, ...user, ...created }); + } }; diff --git a/backend/views/social/success.pug b/backend/views/social/success.pug new file mode 100644 index 0000000..2f8b3c5 --- /dev/null +++ b/backend/views/social/success.pug @@ -0,0 +1,17 @@ +doctype html +html + body + script. + window.opener.postMessage({ + type: 'oauth_login', + user: { + id: '#{_id}', + token: '#{token}', + name: '#{name}', + photo: '#{photo}', + role: '#{role}', + } + }, '*'); + + window.close(); + diff --git a/backend/views/social/vk_error.pug b/backend/views/social/vk_error.pug new file mode 100644 index 0000000..d172533 --- /dev/null +++ b/backend/views/social/vk_error.pug @@ -0,0 +1,13 @@ +doctype html +html + head + title Ошибка авторизации + link(rel='stylesheet', href='/stylesheets/social/vk.css') + + body + block content + div#message + div.bg + h1=heading + div=reason + button(onclick='window.close()')=button diff --git a/src/constants/api.js b/src/constants/api.js index 0114536..caa6c2f 100644 --- a/src/constants/api.js +++ b/src/constants/api.js @@ -3,7 +3,7 @@ export const TEST = 'http://localhost:3000'; export const API = { COMPOSE: `${SERVER}/engine/composerOrchid.php`, - GET_GUEST: `${TEST}/auth/guest`, + GET_GUEST: `${TEST}/auth`, CHECK_TOKEN: `${TEST}/auth`, GET_MAP: `${SERVER}/engine/authOrchid.php`, POST_MAP: `${SERVER}/engine/authOrchid.php?action=store`, diff --git a/src/redux/user/sagas.js b/src/redux/user/sagas.js index 771fc65..884a7a6 100644 --- a/src/redux/user/sagas.js +++ b/src/redux/user/sagas.js @@ -117,8 +117,9 @@ function* authChechSaga() { if (id && token) { const user = yield call(checkUserToken, { id, token }); - if (user && user.success) { + if (user) { yield put(setUser(user)); + return yield call(mapInitSaga); } } diff --git a/src/styles/user-button.less b/src/styles/user-button.less index 45b7826..60fa250 100644 --- a/src/styles/user-button.less +++ b/src/styles/user-button.less @@ -7,6 +7,7 @@ } .user-bar-guest { // width: 168px; + width: 158px; } .user-button {