Skip to content
Open
Show file tree
Hide file tree
Changes from 84 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f296930
Update the timer task setup.
zpChris Jun 18, 2021
a2164a3
Add createGameReport method and update corresponding data models.
zpChris Jun 19, 2021
bbc04bd
Resolve merge conflicts with ResultSetup and main.
zpChris Jun 22, 2021
5282463
Add TODO and helper methods.
zpChris Jun 25, 2021
e25a919
Merge branch 'main' of https://github.com/rocketden/main into Generat…
zpChris Jun 25, 2021
8c0ab51
Merge with multi-problem UI.
zpChris Jun 29, 2021
ddc34c1
Add logic to set data in submission report.
zpChris Jun 29, 2021
54d81fe
Add problem container variable and remaining game report statistics.
zpChris Jun 29, 2021
7f5d22a
Delay before creating the game report.
zpChris Jun 29, 2021
5530121
Add game report repository and save the object in the database.
zpChris Jun 29, 2021
913cf38
Update the saving functionality for users and accounts.
zpChris Jun 29, 2021
15aa1ed
Update column definitions to text.
zpChris Jun 30, 2021
cc3a0d4
Move utility tasks to the task folder.
zpChris Jun 30, 2021
56a73ec
Add the timer task for creating a game report.
zpChris Jun 30, 2021
0fbd919
Fix average test cases passed and total number of test cases.
zpChris Jun 30, 2021
ed5c3da
Remove old logs.
zpChris Jun 30, 2021
18e1f1c
Merge branch 'main' of https://github.com/rocketden/main into Generat…
zpChris Jul 3, 2021
0311bec
Merge branch 'main' of https://github.com/rocketden/main into Generat…
zpChris Jul 3, 2021
22eff98
Add file for creating game report.
zpChris Jul 4, 2021
56c580a
Add mockito annotations calls to fix methods, remove unnecessary checks.
zpChris Jul 4, 2021
0ae5741
Remove unnecessary tests and add check for create game report.
zpChris Jul 4, 2021
ee95904
Update the game management service tests.
zpChris Jul 5, 2021
54795e5
Remove unused variables.
zpChris Jul 5, 2021
3433138
Add verification of the relevant game report objects.
zpChris Jul 6, 2021
9dcabee
Update the submission helper to have only one test case.
zpChris Jul 6, 2021
4325c79
Add the overall problems solved and test cases passed statistics.
zpChris Jul 6, 2021
71f715c
Add a second incorrect attempt that factors only into attempt count.
zpChris Jul 6, 2021
f43d8ce
Add final test statistics and add explanatory top-level comment.
zpChris Jul 6, 2021
b22927e
Add the create two game reports test.
zpChris Jul 6, 2021
832341a
Add final test for game end type.
zpChris Jul 6, 2021
ed98efb
Remove unnecessary user repository save.
zpChris Jul 6, 2021
6cf7dd8
Add problem service delete method.
zpChris Jul 7, 2021
bd62778
Remove extraneous comment.
zpChris Jul 8, 2021
c972883
Resolve merge conflicts with main.
zpChris Jul 21, 2021
da88286
Create the new ReportService as well as modified the other correspond…
zpChris Jul 21, 2021
dabe142
Add problem repository to the report service to take care of deleted …
zpChris Jul 21, 2021
8ad55e7
Update submit service functionality to prevent submissions from occur…
zpChris Jul 26, 2021
7f52b25
Remove CreateGameReportTask class and call createGameReport directly.
zpChris Jul 28, 2021
056dd07
Fix reportService tests.
zpChris Jul 28, 2021
f3dc868
Update the removeProblem test API.
zpChris Jul 28, 2021
fe0bd95
Attempt initial implementation of createGameReportStarted.
zpChris Jul 28, 2021
72dd0a6
Test problem deletion in the ReportServiceTests class.
zpChris Aug 1, 2021
87d39b1
Split problem container and account additions to separate methods.
zpChris Aug 2, 2021
c743cfa
Further split up the createGameReport method into different methods.
zpChris Aug 2, 2021
2705ac5
Remove blank lines in createGameReport method.
zpChris Aug 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions frontend/src/api/Room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { axiosErrorHandler } from './Error';
import { User } from './User';
import { Difficulty } from './Difficulty';
import { ProblemIdParam, SelectableProblem } from './Problem';
import { getAuthHttpHeader } from '../util/Utility';

export type Room = {
roomId: string,
Expand Down Expand Up @@ -63,15 +64,15 @@ const routes = {
setSpectator: (roomId: string) => `${basePath}/${roomId}/spectator`,
};

export const createRoom = (roomParams: CreateRoomParams):
Promise<Room> => axios.post<Room>(routes.createRoom, roomParams)
export const createRoom = (roomParams: CreateRoomParams, token: string | null):
Promise<Room> => axios.post<Room>(routes.createRoom, roomParams, getAuthHttpHeader(token))
.then((res) => res.data)
.catch((err) => {
throw axiosErrorHandler(err);
});

export const joinRoom = (roomId: string, roomParams: JoinRoomParams):
Promise<Room> => axios.put<Room>(routes.joinRoom(roomId), roomParams)
export const joinRoom = (roomId: string, roomParams: JoinRoomParams, token: string | null):
Promise<Room> => axios.put<Room>(routes.joinRoom(roomId), roomParams, getAuthHttpHeader(token))
.then((res) => res.data)
.catch((err) => {
throw axiosErrorHandler(err);
Expand Down
18 changes: 18 additions & 0 deletions frontend/src/api/User.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import axios from 'axios';
import { getAuthHttpHeader } from '../util/Utility';
import { AccountUid } from './Account';
import { axiosErrorHandler } from './Error';

export type User = {
nickname: string,
userId?: string,
spectator?: boolean,
sessionId?: string,
account?: AccountUid,
};

const basePath = '/api/v1/user';
const routes = {
updateUserAccount: (userId: string) => `${basePath}/${userId}/account`,
};

export const updateUserAccount = (userId: string, token: string | null):
Promise<User> => axios.put<User>(routes.updateUserAccount(userId), {}, getAuthHttpHeader(token))
.then((res) => res.data)
.catch((err) => {
throw axiosErrorHandler(err);
});
4 changes: 2 additions & 2 deletions frontend/src/components/card/ProblemCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import styled from 'styled-components';
import { Problem } from '../../api/Problem';
import { LargeText, SelectedItemText, Text } from '../core/Text';
import { LargeText, SelectedItemText, SingleLineText } from '../core/Text';
import { getDifficultyDisplayButton } from '../core/Button';
import { SelectedItemContainer } from '../core/Container';
import { DivLink } from '../core/Link';
Expand Down Expand Up @@ -52,7 +52,7 @@ function ProblemCard(props: ProblemCardProps) {
<InnerContent>
<TitleText>{problem.name}</TitleText>
{getDifficultyDisplayButton(problem.difficulty, true)}
<Text>{`${problem.description.substring(0, 80)}...`}</Text>
<SingleLineText>{problem.description}</SingleLineText>

{problem.problemTags.map((tag) => (
<ProblemTagContainer key={tag.name}>
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/components/core/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,11 @@ export const SelectedItemText = styled.p`
display: inline;
margin: 0 10px;
`;

export const SingleLineText = styled(Text)`
display: -webkit-box;
-webkit-line-clamp: 1;
overflow: hidden;
-webkit-box-orient: vertical;
word-break: break-all;
`;
1 change: 1 addition & 0 deletions frontend/src/components/game/Console.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ function Console(props: ConsoleProps) {
if (!firstFailure && !result.correct) {
firstFailure = result;
}

if (!firstNonHiddenFailure && !result.correct && !result.hidden) {
firstNonHiddenFailure = result;
}
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/navigation/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ const Content = styled.div`
height: 50px;
padding: 20px;
text-align: center;
z-index: 1;
z-index: 2;
`;

const MinimalContent = styled.div`
height: 20px;
padding: 20px 20px 0 20px;
text-align: center;
z-index: 2;
`;

const LeftHeader = styled(NavbarLink)`
Expand Down Expand Up @@ -51,6 +52,7 @@ const NavButton = styled(TextButton)`
const RightContainer = styled.div`
float: right;
margin-right: 50px;
z-index: 1;

@media(max-width: 600px) {
margin-right: 0;
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/problem/Selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { TextInput } from '../core/Input';
import { useAppDispatch, useAppSelector, useClickOutside } from '../../util/Hook';
import { User } from '../../api/User';
import { fetchAccount } from '../../redux/Account';
import { problemMatchesFilterText } from '../../util/Utility';
import { dedupProblems, problemMatchesFilterText } from '../../util/Utility';

type ProblemSelectorProps = {
selectedProblems: SelectableProblem[],
Expand Down Expand Up @@ -123,7 +123,9 @@ export function ProblemSelector(props: ProblemSelectorProps) {
let accountProblems = account?.problems || [];
accountProblems = accountProblems.filter((problem) => problem.testCases.length > 0);

setAllProblems((accountProblems as SelectableProblem[]).concat(verifiedProblems));
// Merge list with verified problems and de-duplicate the result.
const problemsWithDupes = (accountProblems as SelectableProblem[]).concat(verifiedProblems);
setAllProblems(dedupProblems(problemsWithDupes));
}, [account, verifiedProblems]);

// Close list of problems if clicked outside of div
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/components/problem/editor/ProblemDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,15 @@ function ProblemDisplay(props: ProblemDisplayParams) {
<TopButtonsContainer>
<InvertedSmallButton
onClick={() => {
// eslint-disable-next-line no-alert
if (JSON.stringify(problem) === JSON.stringify(newProblem)
// eslint-disable-next-line no-alert
|| window.confirm('Go back? Your unsaved changes will be lost.')) {
history.goBack();
// Use the return link if available; otherwise, use dashboard.
if (history.action !== 'POP') {
history.goBack();
} else {
history.push('/');
}
}
}}
>
Expand Down
35 changes: 30 additions & 5 deletions frontend/src/util/Utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,19 @@ export const onEnterAction = (action: () => void, event: React.KeyboardEvent<HTM
}
};

export const getAuthHttpHeader = (token: string) => ({
headers: {
Authorization: token,
},
});
export const getAuthHttpHeader = (token: string | null) => {
// If token is provided, return headers with authorization token.
if (token) {
return {
headers: {
Authorization: token,
},
};
}

// If no token is provided, return undefined.
return undefined;
};

export const problemMatchesFilterText = (problem: Problem | SelectableProblem,
filterText: string): boolean => {
Expand Down Expand Up @@ -134,3 +142,20 @@ export const getSubmissionTime = (bestSubmission: Submission | null,
};

export const getSubmissionCount = (player: Player | null) => player?.submissions.length || '0';

/**
* De-duplicate a list of SelectableProblems.
* Solution at: https://stackoverflow.com/a/1584377/7517518.
*/
export const dedupProblems = (array: SelectableProblem[]) => {
for (let i = 0; i < array.length; i += 1) {
for (let j = i + 1; j < array.length; j += 1) {
if (array[i].problemId === array[j].problemId) {
array.splice(j, 1);
j -= 1;
}
}
}

return array;
};
6 changes: 4 additions & 2 deletions frontend/src/views/Create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useHistory } from 'react-router-dom';
import EnterNicknamePage from '../components/core/EnterNickname';
import { createRoom, Room, CreateRoomParams } from '../api/Room';
import { User } from '../api/User';
import { useAppDispatch } from '../util/Hook';
import { useAppDispatch, useAppSelector } from '../util/Hook';
import { setRoom } from '../redux/Room';
import { setCurrentUser } from '../redux/User';

Expand All @@ -12,6 +12,8 @@ function CreateGamePage() {
const history = useHistory();
const dispatch = useAppDispatch();

const { token } = useAppSelector((state) => state.account);

// Creates a room with the user as the host, and joins that same lobby.
const createJoinLobby = (nickname: string) => new Promise<void>((resolve, reject) => {
const redirectToLobby = (room: Room, user: User) => {
Expand All @@ -24,7 +26,7 @@ function CreateGamePage() {
spectator: true,
},
};
createRoom(roomHost)
createRoom(roomHost, token)
.then((res) => {
dispatch(setRoom(res));
dispatch(setCurrentUser(res.host));
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/views/Join.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ErrorMessage from '../components/core/Error';
import { ErrorResponse } from '../api/Error';
import { checkLocationState, isValidRoomId } from '../util/Utility';
import { TextLink } from '../components/core/Link';
import { useAppDispatch } from '../util/Hook';
import { useAppDispatch, useAppSelector } from '../util/Hook';
import { setRoom } from '../redux/Room';
import { setCurrentUser } from '../redux/User';

Expand All @@ -29,6 +29,8 @@ function JoinGamePage() {
const location = useLocation<JoinPageLocation>();
const dispatch = useAppDispatch();

const { token } = useAppSelector((state) => state.account);

/**
* Page state variable that defines whether the user is
* entering a room ID or a nickname.
Expand Down Expand Up @@ -94,7 +96,7 @@ function JoinGamePage() {
let currentUser: User = { nickname };
const roomParams = { user: currentUser };

joinRoom(roomId, roomParams)
joinRoom(roomId, roomParams, token)
.then((res) => {
dispatch(setRoom(res));

Expand Down
14 changes: 13 additions & 1 deletion frontend/src/views/Lobby.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import {
connect, routes, subscribe, disconnect,
} from '../api/Socket';
import { User } from '../api/User';
import { User, updateUserAccount } from '../api/User';
import { isValidRoomId, leaveRoom, checkLocationState } from '../util/Utility';
import { Difficulty } from '../api/Difficulty';
import {
Expand Down Expand Up @@ -181,6 +181,7 @@ function LobbyPage() {
const dispatch = useAppDispatch();
const { room } = useAppSelector((state) => state);
const { currentUser } = useAppSelector((state) => state);
const { token } = useAppSelector((state) => state.account);

const mousePosition = useMousePosition(true);

Expand Down Expand Up @@ -240,6 +241,17 @@ function LobbyPage() {
}
}, [room, setStateFromRoom]);

// If the user token changes due to login state, update user account.
useEffect(() => {
if (currentUser?.userId && Boolean(currentUser?.account) !== Boolean(token)) {
updateUserAccount(currentUser?.userId, token).then((user: User) => {
dispatch(setCurrentUser(user));
}).catch((err) => {
setError(err.message);
});
}
}, [currentUser, token, dispatch]);

const kickUser = (user: User) => {
setLoading(true);
setError('');
Expand Down
27 changes: 15 additions & 12 deletions frontend/src/views/ProblemPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,21 @@ function ProblemPage() {
return;
}

setLoading(true);
getSingleProblem(params.id, token!)
.then((res) => {
res.testCases.forEach((testCase) => {
// eslint-disable-next-line no-param-reassign
testCase.id = generateRandomId();
});
setProblem(res);
})
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, [params, token]);
// Checks added to ensure problem fetched only once.
if (!problem && !loading) {
setLoading(true);
getSingleProblem(params.id, token!)
.then((res) => {
res.testCases.forEach((testCase) => {
// eslint-disable-next-line no-param-reassign
testCase.id = generateRandomId();
});
setProblem(res);
})
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}
}, [params, token, problem, loading]);

if (!problem) {
if (error && !loading) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/VerifiedProblemsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function VerifiedProblemsPage() {
return (
<Content>
<LargeText>Verified Problems</LargeText>
<TextLink to="/game/create">Create new problem &#8594;</TextLink>
<TextLink to="/problem/create">Create new problem &#8594;</TextLink>

<FilteredProblemList problems={verifiedProblems} />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,16 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.codejoust.main.dto.problem.CreateProblemRequest;
import com.codejoust.main.dto.problem.CreateProblemTagRequest;
import com.codejoust.main.dto.problem.CreateTestCaseRequest;
import com.codejoust.main.dto.problem.ProblemDto;
import com.codejoust.main.dto.problem.ProblemMapper;
import com.codejoust.main.dto.problem.ProblemSettingsDto;
import com.codejoust.main.dto.problem.ProblemTagDto;
import com.codejoust.main.dto.problem.ProblemTestCaseDto;
import com.codejoust.main.game_object.CodeLanguage;
import com.codejoust.main.model.problem.Problem;
import com.codejoust.main.model.report.CodeLanguage;
import com.codejoust.main.service.ProblemService;

@RestController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

@RestController
Expand All @@ -37,13 +38,13 @@ public ResponseEntity<RoomDto> getRoom(@PathVariable String roomId) {
}

@PutMapping("/rooms/{roomId}/users")
public ResponseEntity<RoomDto> joinRoom(@PathVariable String roomId,@RequestBody JoinRoomRequest request) {
return new ResponseEntity<>(service.joinRoom(roomId, request), HttpStatus.OK);
public ResponseEntity<RoomDto> joinRoom(@PathVariable String roomId,@RequestBody JoinRoomRequest request, @RequestHeader(name="Authorization", required = false) String token) {
return new ResponseEntity<>(service.joinRoom(roomId, request, token), HttpStatus.OK);
}

@PostMapping("/rooms")
public ResponseEntity<RoomDto> createRoom(@RequestBody CreateRoomRequest request) {
return new ResponseEntity<>(service.createRoom(request), HttpStatus.CREATED);
public ResponseEntity<RoomDto> createRoom(@RequestBody CreateRoomRequest request, @RequestHeader(name="Authorization", required = false) String token) {
return new ResponseEntity<>(service.createRoom(request, token), HttpStatus.CREATED);
}

@DeleteMapping("/rooms/{roomId}")
Expand Down
Loading