diff --git a/.vscode/settings.json b/.vscode/settings.json index b02ef900e7a5db6b3da7e7593e38600b00b950bf..0b692c6a7f2975cb9b16a528101c1be148fd8257 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,7 @@ "editor.tabCompletion": "on", "editor.codeActionsOnSave": { "source.fixAll.eslint": true, - "source.organizeImports": false + "source.organizeImports": true }, //python "python.venvPath": "${workspaceFolder}\\server", diff --git a/client/src/Main.tsx b/client/src/Main.tsx index deeb7a477a76e6297a4e5cdc416e20bc2a663ec6..9e079471e43b94367438ab58c08d29a28a4ebd9b 100644 --- a/client/src/Main.tsx +++ b/client/src/Main.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react' -import { BrowserRouter, Route, Switch } from 'react-router-dom' +import { BrowserRouter, Switch } from 'react-router-dom' import { getTypes } from './actions/typesAction' import { useAppDispatch } from './hooks' import AdminPage from './pages/admin/AdminPage' @@ -27,21 +27,31 @@ const Main: React.FC = () => { path="/editor/competition-id=:competitionId" component={PresentationEditorPage} /> - <Route exact path="/:code" component={ViewSelectPage} /> + <SecureRoute authLevel={'competition'} exact path="/:code" component={ViewSelectPage} /> <SecureRoute authLevel={'competition'} exact - path="/participant/id=:id&code=:code" + path="/team/competition-id=:competitionId" component={ParticipantViewPage} /> <SecureRoute authLevel={'competition'} exact - path="/presenter/id=:id&code=:code" + path="/operator/competition-id=:competitionId" component={PresenterViewPage} /> - <SecureRoute authLevel={'competition'} exact path="/judge/id=:id&code=:code" component={JudgeViewPage} /> - <SecureRoute authLevel={'competition'} exact path="/audience/id=:id&code=:code" component={AudienceViewPage} /> + <SecureRoute + authLevel={'competition'} + exact + path="/judge/competition-id=:competitionId" + component={JudgeViewPage} + /> + <SecureRoute + authLevel={'competition'} + exact + path="/audience/competition-id=:competitionId" + component={AudienceViewPage} + /> </Switch> </BrowserRouter> ) diff --git a/client/src/actions/competitionLogin.ts b/client/src/actions/competitionLogin.ts index b5d8775694649affe4778e58eb4a2a65fc1d0630..ed75e71133ba9c28e83432c50b4fca04bd4637b2 100644 --- a/client/src/actions/competitionLogin.ts +++ b/client/src/actions/competitionLogin.ts @@ -5,7 +5,6 @@ This file handles actions for the competitionLogin redux state import axios from 'axios' import { History } from 'history' import { AppDispatch } from '../store' -import { AccountLoginModel } from './../interfaces/FormModels' import Types from './types' // Action creator to attempt to login with competition code @@ -14,10 +13,13 @@ export const loginCompetition = (code: string, history: History) => async (dispa await axios .post('/api/auth/login/code', { code }) .then((res) => { - console.log(code, res.data[0]) + const token = `Bearer ${res.data.access_token}` + localStorage.setItem('competitionToken', token) //setting token to local storage + axios.defaults.headers.common['Authorization'] = token //setting authorize token to header in axios + console.log(code, res.data) dispatch({ type: Types.CLEAR_COMPETITION_LOGIN_ERRORS }) // no error // history.push('/admin') //redirecting to admin page after login success - if (res.data && res.data[0] && res.data[0].view_type_id) { + if (res.data && res.data.view_type_id) { history.push(`/${code}`) } }) diff --git a/client/src/pages/admin/AdminPage.tsx b/client/src/pages/admin/AdminPage.tsx index a8b1746aa8ee4e7564a6f13dc074b11082002747..c206cfdd9c1f206035b0f600da27e5c61adda7be 100644 --- a/client/src/pages/admin/AdminPage.tsx +++ b/client/src/pages/admin/AdminPage.tsx @@ -74,6 +74,7 @@ const AdminView: React.FC = () => { dispatch(getRoles()) dispatch(getTypes()) dispatch(getStatistics()) + axios.get('/api/competitions/1/codes').then((res) => console.log(res.data.items)) }, []) const menuAdminItems = [ diff --git a/client/src/pages/views/ViewSelectPage.tsx b/client/src/pages/views/ViewSelectPage.tsx index 686ce4f1e2d7465a4d8e8ba3ac75d1dee75914ff..9a0264f3da7651543841a28c5a5ad0f73c3f5aa3 100644 --- a/client/src/pages/views/ViewSelectPage.tsx +++ b/client/src/pages/views/ViewSelectPage.tsx @@ -1,22 +1,16 @@ -import Button from '@material-ui/core/Button' -import React, { useEffect, useState } from 'react' -import { Link, useRouteMatch } from 'react-router-dom' -import { ViewSelectButtonGroup, ViewSelectContainer } from './styled' -import { useParams } from 'react-router-dom' import { CircularProgress, Typography } from '@material-ui/core' -import ParticipantViewPage from './ParticipantViewPage' -import axios from 'axios' -import PresenterViewPage from './PresenterViewPage' -import JudgeViewPage from './JudgeViewPage' -import AudienceViewPage from './AudienceViewPage' +import React, { useEffect, useState } from 'react' +import { Redirect, useHistory, useParams } from 'react-router-dom' +import { loginCompetition } from '../../actions/competitionLogin' import { useAppDispatch, useAppSelector } from '../../hooks' -import { getPresentationCompetition, setPresentationCode } from '../../actions/presentation' +import { ViewSelectButtonGroup, ViewSelectContainer } from './styled' interface ViewSelectParams { code: string } const ViewSelectPage: React.FC = () => { const dispatch = useAppDispatch() + const history = useHistory() const [loading, setLoading] = useState(true) const [error, setError] = useState(false) const [viewTypeId, setViewTypeId] = useState(undefined) @@ -29,11 +23,13 @@ const ViewSelectPage: React.FC = () => { if (competitionId) { switch (viewType) { case 'Team': - return <ParticipantViewPage /> + return <Redirect to={`/team/${competitionId}`} /> case 'Judge': - return <JudgeViewPage code={code} competitionId={competitionId} /> + return <Redirect to={`/judge/${competitionId}`} /> case 'Audience': - return <AudienceViewPage /> + return <Redirect to={`/audience/${competitionId}`} /> + case 'Operator': + return <Redirect to={`/operator/${competitionId}`} /> default: return <Typography>Inkorrekt vy</Typography> } @@ -41,7 +37,8 @@ const ViewSelectPage: React.FC = () => { } useEffect(() => { - axios + dispatch(loginCompetition(code, history)) + /* axios .post('/api/auth/login/code', { code }) .then((response) => { setLoading(false) @@ -53,7 +50,7 @@ const ViewSelectPage: React.FC = () => { .catch(() => { setLoading(false) setError(true) - }) + }) */ }, []) return ( diff --git a/client/src/reducers/competitionLoginReducer.ts b/client/src/reducers/competitionLoginReducer.ts index 81c426a4a297f138fdfa6350e17a3cd4fc72d3fd..c8802ef7b64929815baa8155bc4fee49359968c9 100644 --- a/client/src/reducers/competitionLoginReducer.ts +++ b/client/src/reducers/competitionLoginReducer.ts @@ -5,25 +5,34 @@ interface UIError { message: string } -interface UserState { +interface CompetitionLoginState { loading: boolean errors: null | UIError + authenticated: boolean } -const initialState: UserState = { +const initialState: CompetitionLoginState = { loading: false, errors: null, + authenticated: false, } export default function (state = initialState, action: AnyAction) { switch (action.type) { + case Types.SET_COMPETITION_LOGIN_AUTHENTICATED: + return { + ...state, + authenticated: true, + } case Types.SET_COMPETITION_LOGIN_ERRORS: return { + ...state, errors: action.payload as UIError, loading: false, } case Types.CLEAR_COMPETITION_LOGIN_ERRORS: return { + ...state, loading: false, errors: null, } diff --git a/client/src/utils/SecureRoute.tsx b/client/src/utils/SecureRoute.tsx index 9e977c4bdcb2d3638c9f4ecc4774c5bd83e47a18..cfdf52f602668222e24e5e20e095e6a62da59e5e 100644 --- a/client/src/utils/SecureRoute.tsx +++ b/client/src/utils/SecureRoute.tsx @@ -26,6 +26,7 @@ const SecureRoute: React.FC<SecureRouteProps> = ({ } else { await CheckAuthenticationCompetition() } + console.log('initialized') setInitialized(true) } waitForAuthentication() diff --git a/client/src/utils/checkAuthenticationCompetition.ts b/client/src/utils/checkAuthenticationCompetition.ts index 533cfbfd5fae8e0517887522e9af2caf96b16188..ef3e6c0056b9f8225a232724e7f79ba77016b9fe 100644 --- a/client/src/utils/checkAuthenticationCompetition.ts +++ b/client/src/utils/checkAuthenticationCompetition.ts @@ -2,7 +2,6 @@ import axios from 'axios' import jwtDecode from 'jwt-decode' import { logoutCompetition } from '../actions/competitionLogin' import Types from '../actions/types' -import { logoutUser } from '../actions/user' import store from '../store' const UnAuthorized = async () => { @@ -10,9 +9,11 @@ const UnAuthorized = async () => { } export const CheckAuthenticationCompetition = async () => { + console.log('checkAuthComp') const authToken = localStorage.competitionToken if (authToken) { const decodedToken: any = jwtDecode(authToken) + console.log(decodedToken) if (decodedToken.exp * 1000 >= Date.now()) { axios.defaults.headers.common['Authorization'] = authToken await axios diff --git a/server/app/apis/auth.py b/server/app/apis/auth.py index 9c9ed24a876a9b130c385194bb8cc322bef65c9d..62795e3afd0ee1f846e3e24aa612784e9b56d9fe 100644 --- a/server/app/apis/auth.py +++ b/server/app/apis/auth.py @@ -1,19 +1,15 @@ +from datetime import timedelta + import app.core.http_codes as codes import app.database.controller as dbc from app.apis import item_response, protect_route, text_response +from app.core import sockets from app.core.codes import verify_code from app.core.dto import AuthDTO, CodeDTO -from flask_jwt_extended import ( - create_access_token, - create_refresh_token, - get_jwt_identity, - get_raw_jwt, - jwt_refresh_token_required, -) -from flask_restx import Resource -from flask_restx import inputs, reqparse -from datetime import timedelta -from app.core import sockets +from flask_jwt_extended import (create_access_token, create_refresh_token, + get_jwt_identity, get_raw_jwt, + jwt_refresh_token_required) +from flask_restx import Resource, inputs, reqparse api = AuthDTO.api schema = AuthDTO.schema @@ -95,9 +91,10 @@ class AuthLoginCode(Resource): api.abort(codes.UNAUTHORIZED, "Invalid code") item_code = dbc.get.code_by_code(code) - - if item_code.competition_id not in sockets.presentations: - api.abort(codes.UNAUTHORIZED, "Competition not active") + + if item_code.view_type_id != 4: + if item_code.competition_id not in sockets.presentations: + api.abort(codes.UNAUTHORIZED, "Competition not active") access_token = create_access_token( item_code.id, user_claims=get_code_claims(item_code), expires_delta=timedelta(hours=8)