Compare commits

...
15 Commits
Author SHA1 Message Date
bence 4f45e213c3 Merge pull request 'add badge for passing builds' (!51) from feature/add-badge-for-builds into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/51
2021-12-22 02:26:03 +01:00
bence d877d2fe03 add badge for passing builds
mapguesser/pipeline/head This commit looks good
mapguesser/pipeline/pr-develop This commit looks good
2021-12-22 02:21:22 +01:00
bence 66240c2d65 Merge pull request 'add Jenkinsfile and Dockerfile-test' (!50) from feature/add-jenkins-support into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/50
2021-12-22 02:14:44 +01:00
bence 0654b65940 add Jenkinsfile and Dockerfile-test
mapguesser/pipeline/pr-develop This commit looks good
default-pipeline default-pipeline #18
2021-12-22 01:59:31 +01:00
bence 272ec3568d Merge pull request 'bugfix/MAPG-240-fix-static-code-analysis-errors' (!49) from bugfix/MAPG-240-fix-static-code-analysis-errors into develop
default-pipeline default-pipeline #11
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/49
Reviewed-by: Balázs Vigh <balazs@vigh.eu>
2021-05-29 10:22:20 +02:00
bence be4a2038e5 MAPG-240 add use for PlaceInChallenge (used in MapAdminController::deleteChallenge)
default-pipeline default-pipeline #9
2021-05-29 00:57:59 +02:00
bence f305c97513 MAPG-240 UserInChallengeRepository::isUserParticipatingInChallenge should return bool 2021-05-29 00:56:43 +02:00
balazs 784037de6f Merge pull request 'feature/MAPG-235-basic-challenge-mode' (#48) from feature/MAPG-235-basic-challenge-mode into develop
default-pipeline default-pipeline #8
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/48
Reviewed-by: Pőcze Bence <bence@pocze.ch>
2021-05-28 20:41:08 +02:00
balazs 6f27450423 MAPG-235 replaced explicit margin-top and margin-bottom with marginTop and marginBottom classes 2021-05-28 08:36:45 +02:00
balazs bbaa2fe1eb MAPG-235 removed font-family and font-weight css attributes for restrictions and now handled on higher level 2021-05-28 08:19:35 +02:00
balazs 28165d76d3 MAPG-235 refactored challenge token generation and check 2021-05-28 08:07:02 +02:00
balazs 1c1e5f051d MAPG-235 simplified highscore calculation 2021-05-26 08:16:32 +02:00
balazs 283c214c50 MAPG-235 noZoom label fix 2021-05-26 07:49:05 +02:00
balazs 7970927654 MAPG-235 refactored whitespaces 2021-05-22 21:17:49 +02:00
balazs 567602c749 MAPG-235 hide restrictions information if there are no restrictions for the challenge 2021-05-22 21:00:54 +02:00
15 changed files with 109 additions and 59 deletions

No files matched your search

Vendored
+59
View File
@@ -0,0 +1,59 @@
pipeline {
agent {
node {
label 'mapguesser'
customWorkspace 'workspace/mapguesser'
}
}
stages {
stage('Install composer') {
agent {
dockerfile {
filename 'docker/Dockerfile-test'
dir '.'
reuseNode true
}
}
steps {
sh 'composer install'
}
}
stage('Unit Testing') {
agent {
dockerfile {
filename 'docker/Dockerfile-test'
dir '.'
reuseNode true
}
}
steps {
sh 'vendor/bin/phpunit --log-junit unit_test_results.xml --testdox tests'
}
post {
success {
archiveArtifacts 'unit_test_results.xml'
}
}
}
stage('Static Code Analysis') {
agent {
dockerfile {
filename 'docker/Dockerfile-test'
dir '.'
reuseNode true
}
}
steps {
sh 'php -d memory_limit=1G vendor/bin/phpstan analyse -c phpstan.neon --error-format=prettyJson > static_code_analysis_results.json'
}
post {
success {
archiveArtifacts 'static_code_analysis_results.json'
}
}
}
}
}
+2
View File
@@ -1,5 +1,7 @@
# MapGuesser # MapGuesser
[![Build Status](https://jenkins.e5tv.hu/job/mapguesser/job/develop/badge/icon)](https://jenkins.e5tv.hu/job/mapguesser/job/develop/)
This is the MapGuesser Application project. This is a game about guessing where you are based on a street view panorama - inspired by existing applications. This is the MapGuesser Application project. This is a game about guessing where you are based on a street view panorama - inspired by existing applications.
## Installation ## Installation
+4
View File
@@ -0,0 +1,4 @@
FROM php:7.4.7-cli-buster
RUN apt-get update && apt-get install -y unzip
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+7 -3
View File
@@ -31,11 +31,11 @@ main {
color: #ffffff; color: #ffffff;
} }
p, h1, h2, input, textarea, select, button, a, table { p, h1, h2, h3, input, textarea, select, button, a, table, label {
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
} }
h1, h2 { h1, h2, h3 {
font-weight: 500; font-weight: 500;
} }
@@ -55,7 +55,11 @@ h2, header.small h1 {
font-size: 24px; font-size: 24px;
} }
p, h2 { h3 {
font-size: 18px;
}
p, h2, h3 {
line-height: 150%; line-height: 150%;
} }
-10
View File
@@ -75,16 +75,6 @@ div.mapItem>div.buttonContainer {
grid-auto-flow: column; grid-auto-flow: column;
} }
#restrictions {
margin-top: 1em;
margin-bottom: 1em;
font-family: 'Roboto', sans-serif;
}
#restrictions h3 {
font-weight: 500;
}
#restrictions input { #restrictions input {
height: auto; height: auto;
margin: 0.5em; margin: 0.5em;
+16 -15
View File
@@ -21,7 +21,6 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
googleLink: null, googleLink: null,
history: [], history: [],
restrictions: null, restrictions: null,
finishers: null,
readyToContinue: true, readyToContinue: true,
timeoutEnd: null, timeoutEnd: null,
@@ -348,8 +347,6 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
return; return;
} }
var restrictionsForDisplay = []; var restrictionsForDisplay = [];
if (Game.restrictions.timeLimit) { if (Game.restrictions.timeLimit) {
restrictionsForDisplay.push('time limit per ' + Game.restrictions.timeLimitType); restrictionsForDisplay.push('time limit per ' + Game.restrictions.timeLimitType);
@@ -366,6 +363,10 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
} }
} }
if (restrictionsForDisplay.length == 0) {
return;
}
// create restrictions span for header // create restrictions span for header
var restrictions = document.createElement('span'); var restrictions = document.createElement('span');
restrictions.setAttribute('id', 'restrictions'); restrictions.setAttribute('id', 'restrictions');
@@ -397,7 +398,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
Game.timeoutEnd = null; Game.timeoutEnd = null;
}, },
hideRestrictions: function() { hideRestrictions: function () {
var restrictions = document.getElementById('restrictions'); var restrictions = document.getElementById('restrictions');
if (restrictions) { if (restrictions) {
var header = restrictions.parentNode; var header = restrictions.parentNode;
@@ -486,10 +487,6 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
} }
} }
} }
if (response.finishers) {
Game.finishers = new Set(response.finishers);
}
}, },
reset: function () { reset: function () {
@@ -542,7 +539,6 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
document.getElementById('panningBlockerCover').style.display = null; document.getElementById('panningBlockerCover').style.display = null;
Game.history = []; Game.history = [];
Game.finishers = null;
Game.initialize(); Game.initialize();
}, },
@@ -871,16 +867,21 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
var highscores = new Map(); var highscores = new Map();
highscores.set('me', Game.scoreSum); highscores.set('me', Game.scoreSum);
for (var i = 0; i < Game.history.length; ++i) { // collect the results of users who are through the last round
const round = Game.history[Game.history.length - 1];
if (round.allResults) {
for (const result of round.allResults) {
highscores.set(result.userName, result.score);
}
}
// add up scores only for the finishers
for (var i = Game.history.length - 2; i >= 0; --i) {
const round = Game.history[i]; const round = Game.history[i];
if (round.allResults) { if (round.allResults) {
for (const result of round.allResults) { for (const result of round.allResults) {
if (Game.finishers.has(result.userName)) {
if (highscores.has(result.userName)) { if (highscores.has(result.userName)) {
highscores.set(result.userName, highscores.get(result.userName) + result.score); highscores.set(result.userName, highscores.get(result.userName) + result.score);
} else {
highscores.set(result.userName, result.score);
}
} }
} }
} }
@@ -955,7 +956,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
}, },
showHighscores: function() { showHighscores: function () {
if (Game.type == GameType.CHALLENGE) { if (Game.type == GameType.CHALLENGE) {
var highscores = this.calculateHighScores(); var highscores = this.calculateHighScores();
+6 -7
View File
@@ -112,11 +112,10 @@ class GameController implements ISecured
public function createNewChallenge(): IContent public function createNewChallenge(): IContent
{ {
// create Challenge // create Challenge
$challengeToken = rand(); do {
while ($this->challengeRepository->getByToken($challengeToken)) { // initiliaze or if a challenge with the same token already exists
// if a challenge with the same token already exists $challengeToken = mt_rand();
$challengeToken = rand(); } while ($this->challengeRepository->getByToken($challengeToken));
}
$challenge = new Challenge(); $challenge = new Challenge();
$challenge->setToken($challengeToken); $challenge->setToken($challengeToken);
@@ -208,7 +207,7 @@ class GameController implements ISecured
$room = $this->multiRoomRepository->getByRoomId($roomId); $room = $this->multiRoomRepository->getByRoomId($roomId);
if(!isset($room)) { if (!isset($room)) {
return new JsonContent(['error' => 'game_not_found']); return new JsonContent(['error' => 'game_not_found']);
} }
@@ -265,7 +264,7 @@ class GameController implements ISecured
return new JsonContent(['error' => 'game_not_found']); return new JsonContent(['error' => 'game_not_found']);
} }
if(!$this->userInChallengeRepository->isUserParticipatingInChallenge($userId, $challenge)) { if (!$this->userInChallengeRepository->isUserParticipatingInChallenge($userId, $challenge)) {
// new player is joining // new player is joining
$userInChallenge = new UserInChallenge(); $userInChallenge = new UserInChallenge();
$userInChallenge->setUserId($userId); $userInChallenge->setUserId($userId);
+3 -11
View File
@@ -199,14 +199,6 @@ class GameFlowController implements ISecured
if (!isset($currentPlace)) { // game finished if (!isset($currentPlace)) { // game finished
$response['finished'] = true; $response['finished'] = true;
// list all players who finished the challenge
$response['finishers'] = [];
foreach ($this->userInChallengeRepository->getAllByChallengeWithUsers($challenge) as $userInChallenge) {
if ($userInChallenge->getCurrentRound() == $currentRound && $userInChallenge->getUser()->getId() != $userId) {
$response['finishers'][] = $userInChallenge->getUser()->getDisplayName();
}
}
} else { // continue game } else { // continue game
$response['place'] = [ $response['place'] = [
'panoId' => $currentPlace->getPanoIdCached(), 'panoId' => $currentPlace->getPanoIdCached(),
@@ -309,9 +301,9 @@ class GameFlowController implements ISecured
$session = $this->request->session(); $session = $this->request->session();
$userId = $session->get('userId'); $userId = $session->get('userId');
if(isset($userId)) { if (isset($userId)) {
$userPlayedPlace = $this->userPlayedPlaceRepository->getByUserIdAndPlaceId($userId, $placeId); $userPlayedPlace = $this->userPlayedPlaceRepository->getByUserIdAndPlaceId($userId, $placeId);
if(!$userPlayedPlace) { if (!$userPlayedPlace) {
$userPlayedPlace = new UserPlayedPlace(); $userPlayedPlace = new UserPlayedPlace();
$userPlayedPlace->setUserId($userId); $userPlayedPlace->setUserId($userId);
$userPlayedPlace->setPlaceId($placeId); $userPlayedPlace->setPlaceId($placeId);
@@ -415,7 +407,7 @@ class GameFlowController implements ISecured
$response['restrictions']['timeLimit'] = $timeLimit * 1000; $response['restrictions']['timeLimit'] = $timeLimit * 1000;
} }
if(isset($response['history'][$currentRound]['allResults'])) { if (isset($response['history'][$currentRound]['allResults'])) {
$response['allResults'] = $response['history'][$currentRound]['allResults']; $response['allResults'] = $response['history'][$currentRound]['allResults'];
} }
+1
View File
@@ -8,6 +8,7 @@ use MapGuesser\Interfaces\Response\IContent;
use MapGuesser\PersistentData\Model\Challenge; use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Map; use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place; use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\PlaceInChallenge;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
use MapGuesser\Repository\ChallengeRepository; use MapGuesser\Repository\ChallengeRepository;
use MapGuesser\Repository\GuessRepository; use MapGuesser\Repository\GuessRepository;
+3 -3
View File
@@ -261,7 +261,7 @@ class Select
$queryString .= ' LIMIT ' . $this->limit[1] . ', ' . $this->limit[0]; $queryString .= ' LIMIT ' . $this->limit[1] . ', ' . $this->limit[0];
} }
if($this->isDerivedTable()) { if ($this->isDerivedTable()) {
$queryString = '(' . $queryString . ') AS ' . $this->tableAliases[Select::DERIVED_TABLE_KEY]; $queryString = '(' . $queryString . ') AS ' . $this->tableAliases[Select::DERIVED_TABLE_KEY];
} }
@@ -276,7 +276,7 @@ class Select
return [(string) $table, $params]; return [(string) $table, $params];
} }
if($table instanceof Select) if ($table instanceof Select)
{ {
return $table->generateQuery(); return $table->generateQuery();
} }
@@ -332,7 +332,7 @@ class Select
$joinQueries = []; $joinQueries = [];
$params = []; $params = [];
foreach($this->joins as $join) { foreach ($this->joins as $join) {
list($joinQueryFragment, $paramsFragment) = $this->generateTable($join[1], true); list($joinQueryFragment, $paramsFragment) = $this->generateTable($join[1], true);
$joinQueries[] = $join[0] . ' JOIN ' . $joinQueryFragment . ' ON ' . $this->generateColumn($join[2]) . ' ' . $join[3] . ' ' . $this->generateColumn($join[4]); $joinQueries[] = $join[0] . ' JOIN ' . $joinQueryFragment . ' ON ' . $this->generateColumn($join[2]) . ' ' . $join[3] . ' ' . $this->generateColumn($join[4]);
$params = array_merge($params, $paramsFragment); $params = array_merge($params, $paramsFragment);
+1 -1
View File
@@ -33,7 +33,7 @@ class Challenge extends Model
public function setTimeLimit(?int $timeLimit): void public function setTimeLimit(?int $timeLimit): void
{ {
if(isset($timeLimit)) { if (isset($timeLimit)) {
$this->timeLimit = $timeLimit; $this->timeLimit = $timeLimit;
} }
} }
+1 -1
View File
@@ -49,7 +49,7 @@ class UserInChallenge extends Model
public function setTimeLeft(?int $timeLeft): void public function setTimeLeft(?int $timeLeft): void
{ {
if(isset($timeLeft)) { if (isset($timeLeft)) {
$this->timeLeft = max(0, $timeLeft); $this->timeLeft = max(0, $timeLeft);
} }
} }
+2 -4
View File
@@ -57,11 +57,9 @@ class UserInChallengeRepository
} }
// validate token string // validate token string
foreach (str_split($token_str) as $char) { if (!ctype_xdigit($token_str)) {
if (!(('0' <= $char && $char <= '9') || ('a' <= $char && $char <= 'f'))) {
return null; return null;
} }
}
// convert token to int // convert token to int
$token = hexdec($token_str); $token = hexdec($token_str);
@@ -78,6 +76,6 @@ class UserInChallengeRepository
$select->where('user_id', '=', $userId); $select->where('user_id', '=', $userId);
$select->where('challenge_id', '=', $challenge->getId()); $select->where('challenge_id', '=', $challenge->getId());
return $select->count(); return $select->count() != 0;
} }
} }
+1 -1
View File
@@ -30,7 +30,7 @@
@section(subheader) @section(subheader)
<span id="mapName" class="bold">Loading map...</span><!-- <span id="mapName" class="bold">Loading map...</span><!--
--><span>Round <span id="currentRound" class="bold"></span></span><!-- --><span id="roundContainer">Round <span id="currentRound" class="bold"></span></span><!--
--><span>Score <span id="currentScoreSum" class="bold"></span></span> --><span>Score <span id="currentScoreSum" class="bold"></span></span>
@endsection @endsection
+3 -3
View File
@@ -43,7 +43,7 @@ TODO: condition!
<p class="bold center marginTop marginBottom">OR</p> <p class="bold center marginTop marginBottom">OR</p>
--> -->
<div id="restrictions"> <div id="restrictions" class="marginTop marginBottom">
<h3>Optional restrictions</h3> <h3>Optional restrictions</h3>
<div> <div>
<div> <div>
@@ -54,7 +54,7 @@ TODO: condition!
<input type="range" id="timeLimit" name="timeLimit" min="10" max="1800" step="10" value="300" /> <input type="range" id="timeLimit" name="timeLimit" min="10" max="1800" step="10" value="300" />
</div> </div>
<div id="timeLimitType"> <div id="timeLimitType">
Time limit <label>Time limit</label>
<input type="radio" id="timeLimitTypeGame" name="timeLimitType" value="game" checked /> <input type="radio" id="timeLimitTypeGame" name="timeLimitType" value="game" checked />
<label for="timeLimitTypeGame">for the whole game</label> <label for="timeLimitTypeGame">for the whole game</label>
<input type="radio" id="timeLimitTypeRound" name="timeLimitType" value="round" /> <input type="radio" id="timeLimitTypeRound" name="timeLimitType" value="round" />
@@ -67,7 +67,7 @@ TODO: condition!
</div> </div>
<div> <div>
<input type="checkbox" id="noZoom" name="noZoom" value="noZoom" /> <input type="checkbox" id="noZoom" name="noZoom" value="noZoom" />
<label for="noMove">No zoom allowed</label> <label for="noZoom">No zoom allowed</label>
</div> </div>
<div> <div>
<input type="checkbox" id="noPan" name="noPan" value="noPan" /> <input type="checkbox" id="noPan" name="noPan" value="noPan" />