Major spring cleaning: Remove unused code, clarify comments, move assets
This commit is contained in:
		
							parent
							
								
									5e1ed162a3
								
							
						
					
					
						commit
						c30d6912e6
					
				| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "tournament-server", | ||||
|   "version": "1.0.0", | ||||
|   "version": "1.1.0", | ||||
|   "description": "DCST1008 Project - Server - Asura Tournament Management System", | ||||
|   "author": "felixalb, kristoju, jonajha, krisleri", | ||||
|   "private": true, | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
|       name="description" | ||||
|       content="Asura Tournament System" | ||||
|     /> | ||||
|     <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> | ||||
|     <link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.png" /> | ||||
|     <!-- | ||||
|       manifest.json provides metadata used when your web app is installed on a | ||||
|       user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ | ||||
|  | ||||
| @ -8,14 +8,9 @@ | ||||
|       "type": "image/x-icon" | ||||
|     }, | ||||
|     { | ||||
|       "src": "logo192.png", | ||||
|       "src": "favicon.png", | ||||
|       "type": "image/png", | ||||
|       "sizes": "192x192" | ||||
|     }, | ||||
|     { | ||||
|       "src": "logo512.png", | ||||
|       "type": "image/png", | ||||
|       "sizes": "512x512" | ||||
|       "sizes": "100x100" | ||||
|     } | ||||
|   ], | ||||
|   "start_url": ".", | ||||
|  | ||||
| @ -3,11 +3,10 @@ import { BrowserRouter as Router, Link, Route, Routes, useParams } from "react-r | ||||
| import Appbar from "./components/AsuraBar"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| import LoginPage from "./LoginPage"; | ||||
| import { Button, Box, TextField, Stack, InputLabel, Paper, TableContainer, Table, TableBody, TableHead, TableCell, TableRow, Typography, Select, MenuItem, FormControl } from '@mui/material'; | ||||
| import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material"; | ||||
| import { Button, Box, TextField, Stack, Paper, Table, TableBody, TableHead, TableCell, TableRow, Typography, Select, MenuItem, FormControl } from '@mui/material'; | ||||
| import { Dialog, DialogActions, DialogContent, DialogTitle } from "@mui/material"; | ||||
| import AddCircleIcon from '@mui/icons-material/AddCircle'; | ||||
| import DeleteIcon from '@mui/icons-material/Delete'; | ||||
| import EditIcon from '@mui/icons-material/Edit'; | ||||
| import PropTypes from 'prop-types' | ||||
| 
 | ||||
| function AdminCreator(props){ | ||||
| @ -43,7 +42,6 @@ function AdminCreator(props){ | ||||
|             <div align="center"> | ||||
|                 <form> | ||||
|                     <TextField id="adminEmailInput" label="Admin Email" variant="outlined" type="email" sx={{width:['auto','50%','60%','70%']}} /> | ||||
|                         {/* <Button variant="contained" color="primary" onClick={postCreate}>Create Team</Button> */} | ||||
|                         <Button type="submit" variant="contained" color="success" onClick={postCreate} sx={{marginLeft:['5px'],width:['fit-content','40%','30%','20%']}}> | ||||
|                             <Box sx={{padding: "10px"}}> | ||||
|                                 Create Admin | ||||
| @ -64,7 +62,6 @@ function UserList(props){ | ||||
|             .then(data => { | ||||
|                 if(data.status !== "OK"){ | ||||
|                     showError(data.data); | ||||
|                     console.log("UWU") | ||||
|                     return; | ||||
|                 } | ||||
|                 props.onUserUpdated(); | ||||
| @ -115,7 +112,6 @@ function UserList(props){ | ||||
|                           </b> | ||||
|                           </TableCell> | ||||
|                           <TableCell>{user.email}</TableCell> | ||||
|                           {/* TODO Drop down menu for selecting rank */} | ||||
|                           <TableCell> | ||||
|                               <FormControl variant="standard"> | ||||
|                                   <Select onChange={updateRank(user.asuraId)} value={user.isManager ? "manager" : "admin"} aria-label="rank" id="rankSelect"> | ||||
| @ -124,9 +120,7 @@ function UserList(props){ | ||||
|                                   </Select> | ||||
|                               </FormControl> | ||||
|                           </TableCell> | ||||
|                           {/* <TableCell align="right">{team.members}</TableCell> */} | ||||
|                           <TableCell align="center"> | ||||
|                             {/* <Button variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={() => props.setSelectedTeamId(team.id)} endIcon={<EditIcon />}>Edit</Button> */} | ||||
|                             <Button variant="contained" sx={{margin: "auto 5px"}} color="error" onClick={() => {deleteUser(user.asuraId)}} endIcon={<DeleteIcon />}>Delete</Button> | ||||
|                           </TableCell> | ||||
|                         </TableRow> | ||||
| @ -139,7 +133,6 @@ function UserList(props){ | ||||
| } | ||||
| 
 | ||||
| function ConfirmationDialogRaw(props) { | ||||
|   const { userId } = useParams(); | ||||
|   const { onClose, value: valueProp, open, ...other } = props; | ||||
|   const [value, setValue] = React.useState(valueProp); | ||||
| 
 | ||||
|  | ||||
| @ -12,8 +12,10 @@ import Appbar from './components/AsuraBar'; | ||||
| import SuccessSnackbar from "./components/SuccessSnackbar"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| import AdminsOverview from "./AdminsOverview"; | ||||
| import NoSuchPage from "./components/NoSuchPage.js"; | ||||
| import NoUserPage from "./components/NoUserPage.js"; | ||||
| 
 | ||||
| import { Button, Container, Typography, Box, Stack, Card, CardContent, CardMedia, Paper, Grid, Icon, TextField } from "@mui/material"; | ||||
| import { Button, Container, Typography, Box, Stack, Card, CardContent, CardMedia, Paper, Grid, } from "@mui/material"; | ||||
| import AddCircleIcon from '@mui/icons-material/AddCircle'; | ||||
| import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown'; | ||||
| import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp'; | ||||
| @ -164,7 +166,6 @@ function TournamentList(props) { | ||||
|             currenttournaments.push(tournaments[i]) | ||||
|           } | ||||
|         } | ||||
|         // tournaments.filter((tournament) => today - tournament.endTime < 24*60*60*1000)
 | ||||
|         setTournamentList(currenttournaments); | ||||
|       }) | ||||
|       .catch((err) => console.log(err.message)); | ||||
| @ -224,17 +225,6 @@ export default function App() { | ||||
|         setUser({ isManager: false, isLoggedIn: false }); | ||||
|       }); | ||||
|   } | ||||
|   // Debug mode, allow all:
 | ||||
|   // let fetchUser = () => {
 | ||||
|     // setUser({
 | ||||
|       // name: "TEST USERTEST",
 | ||||
|       // isManager: true,
 | ||||
|       // isLoggedIn: true,
 | ||||
|       // email: "testesen@gmail.com",
 | ||||
|       // asuraId: "123456789",
 | ||||
|       // googleId: "234"
 | ||||
|     // });
 | ||||
|   // }
 | ||||
| 
 | ||||
|   React.useEffect(() => { | ||||
|     fetchUser(); | ||||
| @ -269,6 +259,8 @@ export default function App() { | ||||
|         <Route path="/login" element={<LoginPage user={user} />} /> | ||||
|         <Route path="/profile" element={<ProfilePage user={user} />} /> | ||||
|         <Route path="/admins" element={<AdminsOverview user={user} />} /> | ||||
|         <Route path="/nouser" element={<NoUserPage user={user} />} /> | ||||
|         <Route path="*"element={<NoSuchPage user={user} />} /> | ||||
|       </Routes> | ||||
|     </Router> | ||||
| 
 | ||||
|  | ||||
| @ -1,13 +1,12 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import Appbar from "./components/AsuraBar"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| 
 | ||||
| import {Button, Textfield, Stack, InputLabel, Paper, Typography} from '@mui/material'; | ||||
| import { Stack, Paper, Typography} from '@mui/material'; | ||||
| 
 | ||||
| export default function LoginPage(props) { | ||||
|     if (props.user.isLoggedIn) { | ||||
|         //Redirect to the front page if the user is logged in
 | ||||
|         // Redirect to the front page if the user is logged in
 | ||||
|         window.location.href = "/"; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @ -2,8 +2,8 @@ import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import Appbar from "./components/AsuraBar"; | ||||
| import LoginPage from "./LoginPage"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| import { Button, TextField, Stack, InputLabel, Select, Container, Slider, Paper, Box, Grid, Typography } from '@mui/material'; | ||||
| 
 | ||||
| import { Stack, Paper, Box } from '@mui/material'; | ||||
| 
 | ||||
| export default function ProfilePage(props) { | ||||
|     let user = props.user; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import Appbar from "./components/AsuraBar"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| import LoginPage from "./LoginPage"; | ||||
| import { Button, TextField, Stack, InputLabel, Select, Container, Slider, Paper, Box, Grid, Typography } from '@mui/material'; | ||||
| import { Button, TextField, Stack, InputLabel, Container, Slider, Paper, Box, Grid } from '@mui/material'; | ||||
| import DateTimePicker from '@mui/lab/DateTimePicker'; | ||||
| import AdapterDateFns from '@mui/lab/AdapterDateFns'; | ||||
| import LocalizationProvider from '@mui/lab/LocalizationProvider'; | ||||
| @ -57,7 +57,7 @@ function postTournament(tournamentName, tournamentDescription, tournamentStartDa | ||||
|     .then(response => response.json()) | ||||
|     .then(data => { | ||||
|       if (data.status === "OK") { | ||||
|         alert("Tournament created successfully"); | ||||
|         console.log("Tournament created successfully"); | ||||
|         let tournamentId = data.data.tournamentId; | ||||
|         if (tournamentId) { | ||||
|           window.location.href = "/tournament/" + tournamentId; | ||||
| @ -106,9 +106,7 @@ function TournamentForm(props) { | ||||
|     <> | ||||
|     <form> | ||||
|     <Stack sx={{minHeight: "30vh", margin: "10px auto"}} direction="column" justifyContent="center" spacing={3} align="center"> | ||||
|         {/* <InputLabel htmlFor="nameInput">Tournament Name: </InputLabel> */} | ||||
|         <TextField type="text" id="nameInput" label="Tournament Name" placeholder="Tournament Name" InputLabelProps={{shrink: true}}/> | ||||
|         {/* <InputLabel htmlFor="descriptionInput">Description: </InputLabel */} | ||||
|         <TextField type="text" multiline={true} id="descriptionInput" label="Description" placeholder="Description" InputLabelProps={{shrink: true}}/>         | ||||
|         <TextField type="text" id="prizeInput" label="Prize" placeholder="Prize" InputLabelProps={{shrink: true}}/>      | ||||
|         <Box flexGrow={1}> | ||||
| @ -129,8 +127,6 @@ function TournamentForm(props) { | ||||
|             /> | ||||
|           </LocalizationProvider> | ||||
|           </Grid> | ||||
|           {/* <TextField type="datetime-local" id="startDatePicker" label="Start Time" InputLabelProps={{shrink: true}} sx={{width: "48%", marginRight: "2%"}} /> | ||||
|           <TextField type="datetime-local" id="endDatePicker" label="End Time" InputLabelProps={{shrink: true}} sx={{width: "48%", marginLeft: "2%"}} /> */} | ||||
|         </Grid> | ||||
|         </Box> | ||||
|         <InputLabel id="max-teams-label">Maximum number of teams</InputLabel> | ||||
| @ -146,7 +142,6 @@ function TournamentForm(props) { | ||||
|           </Grid> | ||||
|         </Box> | ||||
| 
 | ||||
|         {/* go brrrr */} | ||||
|         <br /><br /> | ||||
|          | ||||
|         <Button type="submit" variant="contained" onClick={submitTournament} color="primary">Create Tournament!</Button> | ||||
|  | ||||
| @ -1,15 +1,13 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import { Button, Container, Typography, Box, Stack, Card, CardContent, CardMedia, Paper, Grid, Icon, TextField } from "@mui/material"; | ||||
| import AddCircleIcon from '@mui/icons-material/AddCircle'; | ||||
| import { Button, Container, Typography, Box, Stack, Card, CardContent, CardMedia, Paper, Grid, TextField } from "@mui/material"; | ||||
| import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown'; | ||||
| import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp'; | ||||
| import Appbar from './components/AsuraBar'; | ||||
| import LoginPage from './LoginPage'; | ||||
| import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; | ||||
| 
 | ||||
| 
 | ||||
| function shorten(description, maxLength) { | ||||
| function shorten(description, maxLength) {  | ||||
|     if (description.length > maxLength) { | ||||
|       return description.substring(0, maxLength) + "..."; | ||||
|     } | ||||
| @ -22,7 +20,7 @@ function shorten(description, maxLength) { | ||||
|     function toggleDescription() { | ||||
|       setLongDescription(!longDescription); | ||||
|     } | ||||
|     function Description() { | ||||
|     function Description() { // Allows for shortening description if needed
 | ||||
|       if (longDescription) { | ||||
|         return( <Box component={Stack} direction="row"> | ||||
|           <Typography variant="body1" onClick={toggleDescription}>{props.tournament.description}</Typography> | ||||
| @ -77,7 +75,7 @@ function shorten(description, maxLength) { | ||||
|    | ||||
|   function TournamentList() { | ||||
|     let [tournamentList, setTournamentList] = React.useState([]); | ||||
|     let [originalList, setOriginalList] = React.useState([]) | ||||
|     let [originalList, setOriginalList] = React.useState([]); | ||||
|    | ||||
|     React.useEffect(() => { | ||||
|       fetch(process.env.REACT_APP_API_URL + `/tournament/getTournaments`) | ||||
| @ -88,60 +86,61 @@ function shorten(description, maxLength) { | ||||
|             return; | ||||
|           } | ||||
| 
 | ||||
|           let tournamenthistory = [] | ||||
|           let today = new Date() | ||||
|           let tournamenthistory = []; | ||||
|           let today = new Date(); | ||||
|           let tournaments = Object.values(data.data); | ||||
|           for (let i = 0; i < tournaments.length; i++) { | ||||
|             tournaments[i].startTime = new Date(tournaments[i].startTime); | ||||
|             tournaments[i].endTime = new Date(tournaments[i].endTime); | ||||
|             if(today - tournaments[i].endTime >= 2*60*60*1000) { | ||||
|                 tournamenthistory.push(tournaments[i]) | ||||
|               tournamenthistory.push(tournaments[i]); | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           setTournamentList(tournamenthistory); | ||||
|           setOriginalList(tournamenthistory) | ||||
|           setOriginalList(tournamenthistory) // Stores the original tournament list in case its searched
 | ||||
|         }) | ||||
|         .catch((err) => console.log(err.message)); | ||||
|     }, []); | ||||
| 
 | ||||
|   function search() { | ||||
|     let searchBase = [] | ||||
|     let searchResult = [] | ||||
|     originalList.map((tournament) => searchBase.push(tournament.name)) | ||||
|     let input = document.getElementById("searchInput") | ||||
|     let inputUpperCase = input.value.toUpperCase() | ||||
|     for (let i = 0; i < searchBase.length; i++) { | ||||
|       let tournamentName = searchBase[i].toUpperCase() | ||||
|     let searchBase = []; | ||||
|     let searchResult = []; | ||||
|     originalList.map((tournament) => searchBase.push(tournament.name)); | ||||
|     let input = document.getElementById("searchInput"); | ||||
|     let inputUpperCase = input.value.toUpperCase(); | ||||
|     for (let i = 0; i < searchBase.length; i++) { // Matches search input with any part of the team names
 | ||||
|       let tournamentName = searchBase[i].toUpperCase(); | ||||
|       if(tournamentName.indexOf(inputUpperCase) >= 0) { | ||||
|         searchResult.push(tournamentName) | ||||
|         searchResult.push(tournamentName); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     let searchedList = [] | ||||
|     let searchedList = []; | ||||
|     for (let i = 0; i < originalList.length; i++) { | ||||
|       let name = originalList[i].name | ||||
|       let name = originalList[i].name; | ||||
|       for (let j = 0; j < searchResult.length; j++) { | ||||
|         if (name.toUpperCase() == searchResult[j]) { | ||||
|           searchedList.push(originalList[i]) | ||||
|         if (name.toUpperCase() === searchResult[j]) { | ||||
|           searchedList.push(originalList[i]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (input.value == "") { | ||||
|       setTournamentList(originalList) | ||||
|     if (input.value === "") { | ||||
|       setTournamentList(originalList); | ||||
|     } else { | ||||
|       setTournamentList(searchedList) | ||||
|       setTournamentList(searchedList);  | ||||
|     } | ||||
|   } | ||||
|    | ||||
|     return <Container sx={{minHeight: "30vh", width: "90vw", padding: "20px 20px", alignContent:'center'}}> | ||||
|     <TextField sx={{width: '50%', marginLeft: '25%', color: 'black', fontSize: '1.5em'}} size="large" type="text" id="searchInput" label="Search finished tournaments" placeholder="Tournament Name" InputLabelProps={{shrink: true}} onChange={search}/> | ||||
|     <Stack spacing={3} sx={{margin: "10px auto"}}> | ||||
|       {tournamentList && tournamentList.map((tournamentObject) => <TournamentListItem key={tournamentObject.id.toString()} tournament={tournamentObject} />)} | ||||
|     </Stack> | ||||
|        | ||||
|     </Container>; | ||||
|     return ( | ||||
|       <Container sx={{minHeight: "30vh", width: "90vw", padding: "20px 20px", alignContent:'center'}}> | ||||
|         <TextField sx={{width: '50%', marginLeft: '25%', color: 'black', fontSize: '1.5em'}} size="large" type="text" id="searchInput" label="Search finished tournaments" placeholder="Tournament Name" InputLabelProps={{shrink: true}} onChange={search}/> | ||||
|         <Stack spacing={3} sx={{margin: "10px auto"}}> | ||||
|           {tournamentList && tournamentList.map((tournamentObject) => <TournamentListItem key={tournamentObject.id.toString()} tournament={tournamentObject} />)} | ||||
|         </Stack> | ||||
|       </Container> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| export default function TournamentHistory(props) { | ||||
| @ -152,4 +151,4 @@ export default function TournamentHistory(props) { | ||||
|         <TournamentList /> | ||||
|       </> | ||||
|     ); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,11 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| // import { AlertContainer, alert } from "react-custom-alert";
 | ||||
| import Appbar from "./components/AsuraBar"; | ||||
| import TournamentBar from "./components/TournamentBar"; | ||||
| import LoginPage from "./LoginPage"; | ||||
| import { useParams } from "react-router-dom"; | ||||
| import { Button, TextField, Grid, Box, Container, Paper, Stack } from "@mui/material"; | ||||
| import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material"; | ||||
| import CloseIcon from '@mui/icons-material/Close'; | ||||
| import { Dialog, DialogActions, DialogContent, DialogTitle } from "@mui/material"; | ||||
| import DeleteIcon from '@mui/icons-material/Delete'; | ||||
| import DateTimePicker from '@mui/lab/DateTimePicker'; | ||||
| import AdapterDateFns from '@mui/lab/AdapterDateFns'; | ||||
| @ -17,10 +15,8 @@ import PropTypes from 'prop-types' | ||||
| let submitChanges = curryTournamentId => event => { | ||||
|   event.preventDefault(); | ||||
|   let tournamentId = curryTournamentId; | ||||
|   //TODO: use refs to get values
 | ||||
|   let tournamentName = document.getElementById("editName").value; | ||||
|   let tournamentDescription = document.getElementById("editDesc").value; | ||||
|   // let tournamentImageFile = document.getElementById("editImage").files[0];
 | ||||
|   let tournamentStartDate = document.getElementById("editStartDate").value; | ||||
|   let tournamentEndDate = document.getElementById("editEndDate").value; | ||||
|   let tournamentPrize = document.getElementById("editPrize").value | ||||
| @ -61,11 +57,10 @@ let submitChanges = curryTournamentId => event => { | ||||
|   formData.append("description", tournamentDescription); | ||||
|   formData.append("startDate", tournamentStartDate); | ||||
|   formData.append("endDate", tournamentEndDate); | ||||
|   // formData.append("teamLimit", tournamentMaxTeams);
 | ||||
|   formData.append("prize", tournamentPrize) | ||||
|   let body = new URLSearchParams(formData); | ||||
| 
 | ||||
|   fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}/edit`, { | ||||
|   fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}/edit`, { // Sends edited data to api
 | ||||
|     method: "POST", | ||||
|     body: body, | ||||
|   }) | ||||
| @ -82,7 +77,6 @@ let submitChanges = curryTournamentId => event => { | ||||
| } | ||||
| 
 | ||||
| let deleteTournament = tournamentId => event => { | ||||
|   console.log(tournamentId); | ||||
|   event.preventDefault(); | ||||
| 
 | ||||
|   fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}`, { | ||||
| @ -168,7 +162,7 @@ function ManageTournament(props) { | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function ConfirmationDialogRaw(props) { | ||||
| function ConfirmationDialogRaw(props) { // Creates required confirmation before tournament deletion
 | ||||
|   const { tournamentId } = useParams(); | ||||
|   const { onClose, value: valueProp, open, ...other } = props; | ||||
|   const [value, setValue] = React.useState(valueProp); | ||||
| @ -235,7 +229,6 @@ export default function TournamentManager(props) { | ||||
|     <TournamentBar pageTitle="Edit Tournament"/> | ||||
|     <Paper sx={{minHeight: "30vh", width: "90vw", margin: "20px auto", padding: "20px 0"}} component={Container} direction="column" align="center"> | ||||
|       <ManageTournament tournamentId={tournamentId} /> | ||||
|       {/* <AnnounceButton /> */} | ||||
|       <Box sx={{width: "100%"}}> | ||||
|         <Button variant="contained" color="error" onClick={handleDialogClickListItem} sx={{margin: "auto 5px"}} endIcon={<DeleteIcon />}> | ||||
|           Delete Tournament | ||||
|  | ||||
| @ -2,15 +2,12 @@ import * as React from "react"; | ||||
| import { Link } from "react-router-dom"; | ||||
| import Appbar from './components/AsuraBar'; | ||||
| import TournamentBar from "./components/TournamentBar"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| import { useParams } from 'react-router-dom' | ||||
| import { Button, IconButton, Paper, Stack, CircularProgress, Box, Grid, Typography, Container } from "@mui/material"; | ||||
| import {  IconButton, Stack, CircularProgress, Box, Typography } from "@mui/material"; | ||||
| import "./components/tournamentBracket.css"; | ||||
| import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; | ||||
| import DoDisturbIcon from '@mui/icons-material/DoDisturb'; | ||||
| import BackspaceIcon from '@mui/icons-material/Backspace'; | ||||
| import AddCircleIcon from '@mui/icons-material/AddCircle'; | ||||
| import { fontSize } from "@mui/system"; | ||||
| 
 | ||||
| function TournamentTier(props){ | ||||
|   let roundTypes = ["finals", "semifinals", "quarterfinals", "eighthfinals", "sixteenthfinals", "thirtysecondfinals"]; | ||||
| @ -54,7 +51,7 @@ function Match(props){ | ||||
|       .then(response => response.json()) | ||||
|       .then(data => { | ||||
|         if (data.status === "OK") { | ||||
|           //Refresh when winner is set successfully
 | ||||
|           // Refresh when winner is set successfully
 | ||||
|           props.onwinnerchange(); | ||||
|         } else { | ||||
|           showError(data.data) | ||||
| @ -84,7 +81,7 @@ function Match(props){ | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|         {/* Team 1 (Winner-status?) (Team name) */} | ||||
|         {/* First team of a match, renders team name and checks if its the winner, includes conditional rendering of buttons to promote and demote */} | ||||
|         <Box component='li' className={`game game-top`}> | ||||
|           <Stack direction={"row"} alignItems="center" spacing={1} sx={{justifyContent:['start','space-between']}}> | ||||
|               <Typography noWrap className={`${props.match.winnerId !== null ? (props.match.team1Id === props.match.winnerId) ? "winner"  : "loser" : ""}`} align={'center'} sx={{ maxWidth:'70%', overflow:'hidden', wordWrap:'none', fontSize:['1em','1em','1.5em','1.75em']}}> | ||||
| @ -104,7 +101,7 @@ function Match(props){ | ||||
|           </Stack> | ||||
|         </Box> | ||||
|         <Box component='li' className="game game-spacer"> </Box> | ||||
|         {/* Team 2 (Winner-status?) (Team name) */} | ||||
|         {/* Second team of a match, renders team name and checks if its the winner, includes conditional rendering of buttons to promote and demote */} | ||||
|         <Box component='li' className={`game game-bottom`}> | ||||
|         <Stack direction={"row"} alignItems="center" sx={{justifyContent:['start','space-between']}}> | ||||
|               <Typography noWrap className={`${props.match.winnerId !== null ? (props.match.team2Id === props.match.winnerId) ? "winner" : "loser" : ""}`} sx={{maxWidth:'70%', overflow:'hidden', wordWrap:'none',fontSize:['1em','1em','1.5em','1.75em']}}> | ||||
| @ -144,8 +141,6 @@ function WinnerDisplay(props) { | ||||
|       }) | ||||
|       .catch(error => showError(error)); | ||||
|   }; | ||||
|            | ||||
| 
 | ||||
| 
 | ||||
|   if (!props.team) { | ||||
|     // Winner is not yet chosen
 | ||||
| @ -179,8 +174,7 @@ function BracketViewer(props){ | ||||
|       .then(res => res.json()) | ||||
|       .then(data => { | ||||
|         if (data.status !== "OK") { | ||||
|           // Do your error thing
 | ||||
|           console.error(data); | ||||
|           showError(data); | ||||
|           return; | ||||
|         } | ||||
|         let allMatches = data.data; | ||||
| @ -203,7 +197,7 @@ function BracketViewer(props){ | ||||
|       .then(res => res.json()) | ||||
|       .then(data=>{ | ||||
|         if(data.status !== "OK"){ | ||||
|           console.error(data) | ||||
|           showError(data) | ||||
|           return; | ||||
|         } | ||||
|         let teams = data.data; | ||||
| @ -229,7 +223,6 @@ function BracketViewer(props){ | ||||
|   return ( | ||||
|      | ||||
|       (props.tournament && matches && teams) ? | ||||
|         // <div sx={{width: "100vw", height: "80vh", overflow: "scroll"}} className="bracket">
 | ||||
|         <> | ||||
|         <div className="bracket"> | ||||
|         {matches.map(tierMatches => { | ||||
| @ -244,19 +237,14 @@ function BracketViewer(props){ | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| let showError = (message) => {}; | ||||
| function showError(error) { | ||||
|   console.error(error); | ||||
| } | ||||
| 
 | ||||
| export default function TournamentOverview(props) { | ||||
|   const { tournamentId } = useParams(); | ||||
|   const [tournament, setTournament] = React.useState(false); | ||||
| 
 | ||||
|   const [openError, setOpenError] = React.useState(false); | ||||
|   const [errorMessage, setErrorMessage] = React.useState(""); | ||||
|   showError = (message) => { | ||||
|     setOpenError(false); | ||||
|     setErrorMessage(message); | ||||
|     setOpenError(true); | ||||
|   } | ||||
| 
 | ||||
|   React.useEffect(() => { | ||||
|     fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}`) | ||||
|       .then(res => res.json()) | ||||
|  | ||||
| @ -4,13 +4,13 @@ import Appbar from "./components/AsuraBar"; | ||||
| import TournamentBar from "./components/TournamentBar"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| import LoginPage from "./LoginPage"; | ||||
| import { Button, TextField, Stack, MenuItem, Box, InputLabel, Select, Container, TableContainer, Table, TableBody, TableHead, TableCell, TableRow, Paper, Typography} from "@mui/material"; | ||||
| import { Button, TextField, Stack, Box, Table, TableBody, TableHead, TableCell, TableRow, Paper} from "@mui/material"; | ||||
| import AddCircleIcon from '@mui/icons-material/AddCircle'; | ||||
| import DeleteIcon from '@mui/icons-material/Delete'; | ||||
| import EditIcon from '@mui/icons-material/Edit'; | ||||
| 
 | ||||
| function TeamCreator(props) { | ||||
|   function postCreate() { | ||||
|   function postCreate() { // Posts new team to api when the form is submitted
 | ||||
|     let teamName = document.getElementById("teamNameInput").value; | ||||
|     if (!teamName) { | ||||
|       showError("Team name is required"); | ||||
| @ -43,7 +43,6 @@ function TeamCreator(props) { | ||||
|       <div align="center"> | ||||
|         <form> | ||||
|         <TextField id="teamNameInput" sx={{width:['auto','50%','60%','70%'], margin:'1% 0'}} label="Team Name" variant="outlined" /> | ||||
|         {/* <Button variant="contained" color="primary" onClick={postCreate}>Create Team</Button> */} | ||||
|         <Button type="submit" variant="contained" color="success" onClick={postCreate} sx={{ margin:'1% 1%',width:['fit-content','40%','30%','20%']}}> | ||||
|           <Box sx={{padding: "10px"}}> | ||||
|             Create Team | ||||
| @ -71,48 +70,47 @@ function TeamList(props) { | ||||
|       .catch(error => showError(error)); | ||||
|   } | ||||
| 
 | ||||
|   function search() { | ||||
|     let searchBase = [] | ||||
|     let searchResult = [] | ||||
|     let originalList = props.originalList | ||||
|     originalList.map((tournament) => searchBase.push(tournament.name)) | ||||
|     let input = document.getElementById("searchInput") | ||||
|     let inputUpperCase = input.value.toUpperCase() | ||||
|     for (let i = 0; i < searchBase.length; i++) { | ||||
|       let tournamentName = searchBase[i].toUpperCase() | ||||
|   function search() {  | ||||
|     // Update search criteria and re-render the list
 | ||||
|     let searchBase = []; | ||||
|     let searchResult = []; | ||||
|     let originalList = props.originalList; // Stores the original list of teams before searching
 | ||||
|     originalList.map((tournament) => searchBase.push(tournament.name)); | ||||
|     let input = document.getElementById("searchInput"); | ||||
|     let inputUpperCase = input.value.toUpperCase(); | ||||
|     for (let i = 0; i < searchBase.length; i++) { // Matches search input with any part of the team names
 | ||||
|       let tournamentName = searchBase[i].toUpperCase(); | ||||
|       if(tournamentName.indexOf(inputUpperCase) >= 0) { | ||||
|         searchResult.push(tournamentName) | ||||
|         searchResult.push(tournamentName); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     let searchedList = [] | ||||
|     let searchedList = []; | ||||
|     for (let i = 0; i < originalList.length; i++) { | ||||
|       let name = originalList[i].name | ||||
|       let name = originalList[i].name; | ||||
|       for (let j = 0; j < searchResult.length; j++) { | ||||
|         if (name.toUpperCase() == searchResult[j]) { | ||||
|           searchedList.push(originalList[i]) | ||||
|         if (name.toUpperCase() === searchResult[j]) { | ||||
|           searchedList.push(originalList[i]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (input.value == "") { | ||||
|       props.setTeams(originalList) | ||||
|     if (input.value === "") { | ||||
|       props.setTeams(originalList); | ||||
|     } else { | ||||
|       props.setTeams(searchedList) | ||||
|       props.setTeams(searchedList); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|   <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> | ||||
|   <div align="center" > | ||||
|   {/* Make a horizontal stack */} | ||||
|     <TextField sx={{margin:'2.5% 0 0 0', width: '50%'}} type="text" id="searchInput" label="Search" placeholder="Team Name" InputLabelProps={{shrink: true}} onChange={search}/>    | ||||
|   | ||||
|       <Table aria-label="simple table"> | ||||
|         <TableHead> | ||||
|           <TableRow> | ||||
|             <TableCell><h2>Team Name</h2></TableCell> | ||||
|             {/* <TableCell align="right">Team Members</TableCell> */} | ||||
|             <TableCell align="center"><h2>Actions</h2></TableCell> | ||||
|           </TableRow> | ||||
|         </TableHead> | ||||
| @ -138,6 +136,7 @@ function TeamList(props) { | ||||
| } | ||||
| 
 | ||||
| function TeamEditor(props) { | ||||
|   // Component that returns a team name editor if a team is selected in the list.
 | ||||
|   const [team, setTeam] = React.useState({}); | ||||
|   React.useEffect(() => { | ||||
|     if (props.selectedTeamId === -1) { | ||||
| @ -156,7 +155,7 @@ function TeamEditor(props) { | ||||
|       .catch(error => showError(error)); | ||||
|   }, [props.selectedTeamId]); | ||||
| 
 | ||||
|   if (props.selectedTeamId === -1 || !team) { | ||||
|   if (props.selectedTeamId === -1 || !team) { //returns if no team is selected for editing
 | ||||
|     return ( | ||||
|       <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> | ||||
|         <div align="center" > | ||||
| @ -176,7 +175,7 @@ function TeamEditor(props) { | ||||
|     event.currentTarget.select() | ||||
|   } | ||||
| 
 | ||||
|   function saveTeam() { | ||||
|   function saveTeam() { //pushes new team name to api
 | ||||
|     let formData = new FormData(); | ||||
|     formData.append("name", team.name); | ||||
|     let body = new URLSearchParams(formData) | ||||
| @ -197,7 +196,7 @@ function TeamEditor(props) { | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|   return (  | ||||
|     <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> | ||||
|     <div align="center"> | ||||
|       <h2><b>Edit Team:</b></h2> | ||||
| @ -227,7 +226,6 @@ export default function TournamentTeams(props) { | ||||
|         } | ||||
|         setTeams(data.data); | ||||
|         setOriginalList(data.data) | ||||
|         //setselectedTeamId(teams[0].id);
 | ||||
|       }) | ||||
|       .catch((err) => showError(err)); | ||||
|   } | ||||
| @ -243,7 +241,7 @@ export default function TournamentTeams(props) { | ||||
|     setOpenError(true); | ||||
|   } | ||||
|    | ||||
|   if (!props.user.isLoggedIn) { return <LoginPage user={props.user} />; } | ||||
|   if (!props.user.isLoggedIn) { return <LoginPage user={props.user} />; }  | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|  | ||||
| @ -1,13 +1,13 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes, History } from "react-router-dom"; | ||||
| import { AppBar, Typography, Toolbar, CssBaseline, Box, Button, IconButton, Grid, Menu, MenuItem, Container } from "@mui/material" | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import { AppBar, Typography, Toolbar, CssBaseline, Box, Button, IconButton, Grid, Menu, MenuItem } from "@mui/material" | ||||
| import MenuIcon from '@mui/icons-material/Menu'; | ||||
| import AccountCircleIcon from '@mui/icons-material/AccountCircle'; | ||||
| import HistoryIcon from '@mui/icons-material/History'; | ||||
| import EditIcon from '@mui/icons-material/Edit'; | ||||
| import LogoutIcon from '@mui/icons-material/Logout'; | ||||
| import LoginIcon from '@mui/icons-material/Login'; | ||||
| import logo from "./../Asura2222.png"; | ||||
| import logo from "./AsuraLogo.png"; | ||||
| 
 | ||||
| function LoggedInMenu(props) { | ||||
|   const [anchorEl, setAnchorEl] = React.useState(null); | ||||
| @ -42,13 +42,10 @@ function LoggedInMenu(props) { | ||||
| 
 | ||||
| 
 | ||||
| function NotLoggedInButton() { | ||||
|   const login = () => { | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|     <Link to="/login" style={{color:"white"}}> | ||||
|       <Button sx={{color:"white"}} onClick={login} endIcon={<LoginIcon />}> | ||||
|       <Button sx={{color:"white"}} endIcon={<LoginIcon />}> | ||||
|         Login | ||||
|         </Button> | ||||
|       </Link> | ||||
|  | ||||
| Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB | 
| @ -1,6 +1,5 @@ | ||||
| import * as React from 'react'; | ||||
| import Stack from '@mui/material/Stack'; | ||||
| import Button from '@mui/material/Button'; | ||||
| import Snackbar from '@mui/material/Snackbar'; | ||||
| import MuiAlert from '@mui/material/Alert'; | ||||
| 
 | ||||
| @ -17,7 +16,7 @@ export default function showError(props) { | ||||
|     props.setOpen(false); | ||||
|   }; | ||||
|   if (props.message && props.message.length > 0) { | ||||
|     console.log(props.message); | ||||
|     console.log(props.message); // Lets the user check the console if they want to see the error
 | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|  | ||||
| @ -1,19 +1,25 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import { Typography } from '@mui/material' | ||||
| import { Typography, Paper, Stack } from '@mui/material' | ||||
| import Appbar from './AsuraBar' | ||||
| 
 | ||||
| export default function NoSuchPage() { | ||||
|     return( | ||||
| export default function NoSuchPage(props) { | ||||
|     return ( | ||||
|     <> | ||||
|         <Typography type="h3"> | ||||
|     <Appbar user={props.user} pageTitle={"Page not found"} /> | ||||
|     <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> | ||||
|         <div align="center"> | ||||
|         <Typography type="h2"> | ||||
|             This page does not exist | ||||
|         </Typography> | ||||
|         <Typography type="h4"> | ||||
|         <Typography type="h3"> | ||||
|             The page you are looking for does not exist or has been moved | ||||
|         </Typography> | ||||
|         <Link to="/"> | ||||
|             Return to the home page | ||||
|         </Link> | ||||
|         </div> | ||||
|     </Paper> | ||||
|     </> | ||||
|     ) | ||||
|     ); | ||||
| } | ||||
| @ -1,18 +1,24 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import { Typography } from '@mui/material' | ||||
| import { Typography, Paper, Stack } from '@mui/material' | ||||
| import Appbar from './AsuraBar' | ||||
| 
 | ||||
| export default function NoSuchPage() { | ||||
|     return( | ||||
| export default function NoUserPage(props) { | ||||
|     return ( | ||||
|     <> | ||||
|         <Typography type="h3"> | ||||
|     <Appbar user={props.user} pageTitle={"Invalid User"} /> | ||||
|     <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> | ||||
|         <div align="center"> | ||||
|         <Typography type="h2"> | ||||
|             You are not logged in | ||||
|         </Typography> | ||||
|         <Typography type="h4"> | ||||
|         <Typography type="h3"> | ||||
|         Your account is not in the administrators list. Try again with another account here: <Link to="/login">Login</Link> | ||||
|         or  | ||||
|         <Link to="/"> Return to the home page</Link> | ||||
|         </Typography> | ||||
|         </div> | ||||
|     </Paper> | ||||
|     </> | ||||
|     ) | ||||
|     ); | ||||
| } | ||||
| @ -1,7 +1,7 @@ | ||||
| import * as React from "react"; | ||||
| import { useParams } from "react-router-dom"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes, History } from "react-router-dom"; | ||||
| import { Stack, Paper, Typography, Box, Button, Grid, Snackbar, IconButton } from "@mui/material" | ||||
| import { Stack, Paper, Button, Snackbar, IconButton } from "@mui/material" | ||||
| import CloseIcon from '@mui/icons-material/Close'; | ||||
| import MuiAlert from '@mui/material/Alert'; | ||||
| 
 | ||||
|  | ||||
| @ -1,12 +0,0 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| 
 | ||||
| import Button from "@mui/material/Button"; | ||||
| 
 | ||||
| export default function SaveButton(props) { | ||||
|   return ( | ||||
|     <Link to="/"> | ||||
|       <Button variant="outlined" color="primary">Save and Exit</Button> | ||||
|     </Link> | ||||
|   ); | ||||
| } | ||||
| @ -4,10 +4,6 @@ import { createTheme } from '@mui/material/styles'; | ||||
| 
 | ||||
| const theme = createTheme({ | ||||
|     palette: { | ||||
|     //   primary: {
 | ||||
|     //   },
 | ||||
|     //   secondary: {
 | ||||
|     //   },
 | ||||
|       pewterblue: { | ||||
|         main: '#8fbcbb', | ||||
|         contrastText: '#fff', | ||||
| @ -63,8 +59,6 @@ const theme = createTheme({ | ||||
|       background: { | ||||
|         default: '#f0f2f2', | ||||
|       } | ||||
|       // contrastThreshold: 5,
 | ||||
|       // tonalOffset: 0.2,
 | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|  | ||||
| @ -1,19 +1,14 @@ | ||||
| /* | ||||
|  *  Flex Layout Specifics | ||||
| */ | ||||
| .bracket{ | ||||
| 	display:flex; | ||||
| 	flex-direction:row; | ||||
| 	justify-content: center; | ||||
|   } | ||||
| } | ||||
| .round{ | ||||
| 	display:flex; | ||||
| 	flex-direction:column; | ||||
| 	justify-content:center; | ||||
| 	/* width:20vw; */ | ||||
| 	list-style:none; | ||||
| 	padding:0; | ||||
| 	/* font-size: 1.5rem; */ | ||||
| } | ||||
| .round .spacer{ flex-grow:1;} | ||||
| .round .spacer:first-child, | ||||
| @ -21,17 +16,7 @@ | ||||
| .round .game-spacer{ | ||||
| 	flex-grow:1; | ||||
| } | ||||
|    | ||||
|   /* | ||||
|    *  General Styles | ||||
|   */ | ||||
| /* body{ | ||||
| 	font-family:sans-serif; | ||||
| 	font-size:medium; | ||||
| 	padding:10px; | ||||
| 	line-height:1.4em; | ||||
|   } */ | ||||
|    | ||||
| 
 | ||||
| li.game{ | ||||
| 	padding-left:20px; | ||||
| } | ||||
| @ -54,7 +39,6 @@ li.game-spacer{ | ||||
| li.game-bottom{  | ||||
| 	border-top:1px solid #aaa; | ||||
| } | ||||
|    | ||||
| 
 | ||||
| .winnerDisplay { | ||||
| 	display:flex; | ||||
|  | ||||
| @ -4,11 +4,9 @@ body { | ||||
|   height: 100%; | ||||
| } | ||||
| body { | ||||
|   /* <yeet> */ | ||||
|   overflow-y: auto !important; | ||||
|   margin: 0 !important; | ||||
|   padding: 0 !important; | ||||
|   /* </yeet> */ | ||||
|    | ||||
|   font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", | ||||
|     "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", | ||||
| @ -25,12 +23,10 @@ code { | ||||
| 
 | ||||
| .mainIcon{ | ||||
|   border-radius: 50%; | ||||
|   /* border: 5px dotted salmon; */ | ||||
|   border: 3px solid #1ab35a; | ||||
|   background-color: white; | ||||
|   margin: 5px; | ||||
|   float: left; | ||||
|   /* margin: 50% calc(2vw + 50%) 50% 50%; */ | ||||
| } | ||||
| 
 | ||||
| a { | ||||
|  | ||||
| @ -7,6 +7,7 @@ GOOGLE_CLIENT_ID=xxxxxxxxxxxxxxx.apps.googleusercontent.com | ||||
| GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxx | ||||
| GOOGLE_CALLBACK_URL=https://asura.feal.no/auth/google/callback | ||||
| AUTH_SUCCESS_REDIRECT=https://asura.feal.no/ | ||||
| AUTH_ERROR_REDIRECT=https://asura.feal.no/nouser | ||||
| DEBUG_ALLOW_ALL=false | ||||
| COOKIE_SECURE=false | ||||
| COOKIE_SECRET=any random string | ||||
|  | ||||
| @ -4,11 +4,18 @@ const session = require('express-session'); | ||||
| const https = require("https"); | ||||
| require("dotenv").config(); | ||||
| 
 | ||||
| /* Asura Tournament Server Index | ||||
|   This node applications functions as a web server to serve the client application, as well as serving the API. | ||||
|   The program is divided into sections or "regions". Each region lies between two comments "// #region <title>" and "// #endregion". | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| // Our self-written module for handling database operations
 | ||||
| let tmdb = require("./tmdb.js"); | ||||
| 
 | ||||
| // #region Express setup
 | ||||
| const app = express(); | ||||
| // Default to 3000 if no port is specified. This port is fine, as the server should be behind a reverse proxy
 | ||||
| const port = process.env.SERVER_PORT || 3000; | ||||
| app.listen(parseInt(port), () => { | ||||
|   console.log(`Listening on port ${port}`) | ||||
| @ -32,9 +39,13 @@ app.use("/api", api); | ||||
| api.use(function(req, res, next) { | ||||
|   res.header("Access-Control-Allow-Origin", "*"); | ||||
|   res.header("Access-Control-Allow-Methods", "GET, POST, DELETE"); | ||||
|   // If your API is CORS-enabled, you can use the following line instead of the above line
 | ||||
|   // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
 | ||||
|   next(); | ||||
| }); | ||||
| 
 | ||||
| // Log both the client requests and API requests to terminal.
 | ||||
| // This allows for easier debugging and overview. The output includes the response status code and requested URL.
 | ||||
| api.use(require('express-log-url')); | ||||
| app.use(require('express-log-url')); | ||||
| 
 | ||||
| @ -42,11 +53,12 @@ app.use(require('express-log-url')); | ||||
| 
 | ||||
| // #region frontend
 | ||||
| 
 | ||||
| // Serve static files from the React app
 | ||||
| // Serve static files from the React app.
 | ||||
| const indexhtmlPath = path.join(process.env.CLIENT_BUILD_DIR, "index.html"); | ||||
| const staticPath = path.join(process.env.CLIENT_BUILD_DIR, "static"); | ||||
| app.use('/', express.static(process.env.CLIENT_BUILD_DIR)); | ||||
| app.use('/login', express.static(indexhtmlPath)); | ||||
| app.use('/nous', express.static(indexhtmlPath)); | ||||
| app.use('/history', express.static(indexhtmlPath)); | ||||
| app.use('/admins', express.static(indexhtmlPath)); | ||||
| app.use('/profile', express.static(indexhtmlPath)); | ||||
| @ -56,6 +68,9 @@ app.use('/static/*', express.static(staticPath)); | ||||
| // #endregion
 | ||||
| 
 | ||||
| // #region PASSPORT / OAUTH
 | ||||
| // This process of signing in with google oauth and storing the session cookie with passport and express 
 | ||||
| // is loosely based on the google documentation: https://developers.google.com/identity/sign-in/web/sign-in
 | ||||
| // as well as this tutorial: https://www.loginradius.com/blog/engineering/google-authentication-with-nodejs-and-passportjs/
 | ||||
| 
 | ||||
| const passport = require('passport'); | ||||
| var userProfile; | ||||
| @ -109,7 +124,7 @@ app.get('/auth/google/callback', | ||||
|         req.session.user = dbUser; | ||||
|       } else { | ||||
|         // User is "preregistered" with email only, so complete the registration
 | ||||
|         // This step will register the name, img and googleId
 | ||||
|         // This step will register the name and googleId
 | ||||
|         tmdb.editUser(user.email, user).catch(err => console.log(err)); | ||||
| 
 | ||||
|         req.session.user = user; | ||||
| @ -120,7 +135,8 @@ app.get('/auth/google/callback', | ||||
|     }) | ||||
|     .catch(err => { | ||||
|       // User is not in the database at all, do not give them a session.
 | ||||
|       res.json({"status": "error", message: "Email is not in administrator list."}); | ||||
|       // JSON alternative: res.json({"status": "error", message: "Email is not in administrator list."});
 | ||||
|       res.redirect(process.env.AUTH_ERROR_REDIRECT); | ||||
|       return; | ||||
|     }); | ||||
|   } | ||||
| @ -128,7 +144,14 @@ app.get('/auth/google/callback', | ||||
| 
 | ||||
| // #endregion
 | ||||
| 
 | ||||
| /*  | ||||
|   API *endpoints* are given in api.get, api.post, api.delete, etc. | ||||
|   These are the endpoints that the client will use to interact with the server. | ||||
|   Functions that are not defined in this way will not be accessible to the client, but internally in the server. | ||||
| 
 | ||||
|   Most of these endpoints do some simple validations, make an asynchrnous call to the tmdb-module, and returns the result in JSON. | ||||
| 
 | ||||
| */ | ||||
| // #region API
 | ||||
| api.get("/tournament/getTournaments", (req, res) => { | ||||
|   tmdb.getTournaments() | ||||
| @ -190,7 +213,6 @@ api.post("/tournament/:tournamentId/edit", async (req, res) => { | ||||
|   let prize = req.body.prize; | ||||
|   let startDate = req.body.startDate; | ||||
|   let endDate = req.body.endDate; | ||||
|   console.log(startDate); | ||||
|   if (name == undefined || name == "" || description == undefined || description == "") { | ||||
|     res.json({"status": "error", "data": "name and description must be provided"}); | ||||
|     return | ||||
| @ -206,11 +228,7 @@ api.post("/tournament/:tournamentId/edit", async (req, res) => { | ||||
|     res.json({"status": "error", "data": "startDate and endDate must be valid dates"}); | ||||
|     return | ||||
|   } | ||||
|   // let today = new Date();
 | ||||
|   // if (startDate < today) {
 | ||||
|   //   res.json({"status": "error", "data": "startDate cannot be in the past"});
 | ||||
|   //   return
 | ||||
|   // }
 | ||||
| 
 | ||||
|   if (startDate > endDate) { | ||||
|     res.json({"status": "error", "data": "startDate cannot be after endDate"}); | ||||
|     return | ||||
| @ -376,7 +394,6 @@ api.post("/team/:teamId/edit", async (req, res) => { | ||||
|    | ||||
|   let teamId = req.params.teamId; | ||||
|   let teamName = req.body.name; | ||||
|   console.log(req.body); | ||||
|   if (isNaN(teamId)) { | ||||
|     res.json({"status": "error", "data": "teamId must be a number"}); | ||||
|     return | ||||
| @ -406,16 +423,13 @@ api.post("/tournament/create", async (req, res) => { | ||||
|     res.json({"status": "error", "data": "No data supplied"}); | ||||
|     return | ||||
|   } | ||||
|   //Check that req is json  
 | ||||
|   // if (req.get("Content-Type") != "application/json") {
 | ||||
|   console.log(req.get("Content-Type")); | ||||
| 
 | ||||
|   let name = req.body.name; | ||||
|   let description = req.body.description; | ||||
|   let prize = req.body.prize; | ||||
|   let teamLimit = req.body.teamLimit; | ||||
|   let startDate = req.body.startDate; //TODO: timezones, 2 hr skips
 | ||||
|   let startDate = req.body.startDate; | ||||
|   let endDate = req.body.endDate; | ||||
|   console.log(startDate, endDate); | ||||
|   if (name == undefined || name == "" || description == undefined || description == "") { | ||||
|     res.json({"status": "error", "data": "name and description must be provided"}); | ||||
|     return | ||||
| @ -450,7 +464,6 @@ api.post("/tournament/create", async (req, res) => { | ||||
|     res.json({"status": "error", "data": "endDate must be later than startDate"}); | ||||
|     return | ||||
|   } | ||||
|   console.log(startDate); | ||||
| 
 | ||||
|   tmdb.createTournament(name, description, prize, startDate, endDate, teamLimit) | ||||
|     .then(msg => res.json({"status": "OK", "data": msg})) | ||||
| @ -573,7 +586,7 @@ api.get("/users/logout", (req, res) => { | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| // Debugging functions, disabled on purpouse
 | ||||
| // Debugging functions, disabled in production environment
 | ||||
| // api.get("/users/getSessionUser", (req, res) => {
 | ||||
| //   if (req.session.user) {
 | ||||
| //     res.json({"status": "OK", "data": req.session.user});
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user