Compare commits

...
Author SHA1 Message Date
bence 703966f8f7 Merge pull request 'process scheme from reverse proxy correctly' (!69) from bugfix/process-scheme-correctly into develop
mapguesser/pipeline/head This commit looks good
mapguesser/pipeline/tag This commit looks good
Reviewed-on: #69
2023-09-17 11:02:57 +02:00
bence 76570a76c5 process scheme from reverse proxy correctly
mapguesser/pipeline/pr-develop This commit looks good
2023-09-17 01:53:29 +02:00
bence 383bb9d4fb Merge pull request 'feature/create-working-docker-images' (!68) from feature/create-working-docker-images into develop
mapguesser/pipeline/head This commit looks good
mapguesser/pipeline/tag This commit looks good
Reviewed-on: #68
2023-09-17 00:10:54 +02:00
bence 716494f614 update readme
mapguesser/pipeline/pr-develop This commit looks good
2023-09-17 00:04:16 +02:00
bence 7c61491653 update soko-web 2023-09-17 00:04:16 +02:00
bence 7a1da55ceb update docker-compose 2023-09-17 00:04:16 +02:00
bence cb5e90c0f7 add docker release stage to pipeline 2023-09-17 00:04:16 +02:00
bence 32e9fc2cb0 use the new dockerfile in pipeline 2023-09-17 00:04:13 +02:00
bence c180d7a012 delete deprecated dockerfiles 2023-09-17 00:04:10 +02:00
bence fea4211930 add new dockerfile with dev and release stages 2023-09-17 00:04:10 +02:00
bence 4f6e18f83a add entry point for dev docker 2023-09-17 00:04:06 +02:00
bence 57a24f8c90 add entry point for release docker 2023-09-17 00:03:20 +02:00
bence f5950658df install base database in MigrateDatabaseCommand 2023-09-17 00:03:20 +02:00
bence cd17f44de0 merge migration of migrations to base db 2023-09-17 00:03:20 +02:00
bence a11a879a4f remove deprecated scripts 2023-09-17 00:03:20 +02:00
bence 0048fb9b1d add cron for db:maintain 2023-09-17 00:03:20 +02:00
bence cede0e7985 add release generator script 2023-09-16 23:07:51 +02:00
bence 80501b7f0a add nodejs installer script 2023-09-16 15:05:34 +02:00
bence a255180a4d Merge pull request 'fix unambiguous where and orderBy statements in PlaceRepository' (!67) from fix-selects-in-placerepository into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: #67
2023-09-15 01:40:16 +02:00
bence af09da8782 fix unambiguous where and orderBy statements in PlaceRepository
mapguesser/pipeline/pr-develop This commit looks good
2023-09-15 01:38:26 +02:00
bence ddfea0530d Merge pull request 'fix syntax for password input in login form' (!66) from bugfix/fix-login-password-layout into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: #66
2023-05-16 18:08:37 +02:00
bence 9d7d19899d fix syntax for password input in login form
mapguesser/pipeline/pr-develop This commit looks good
2023-05-16 18:06:30 +02:00
bence 10f032a9a5 Merge pull request 'bugfix/fix-ambiguous-sql-field-names' (!65) from bugfix/fix-ambiguous-sql-field-names into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: #65
2023-05-02 18:12:04 +02:00
bence c02e35580f use sql field names with tables where join happens
mapguesser/pipeline/pr-develop This commit looks good
2023-05-02 18:10:22 +02:00
bence afd58bb91b update soko-web to 0.10.1 2023-05-02 18:08:53 +02:00
bence fc6792ccfc Merge pull request 'add autocomplete values for username and password fields' (!64) from feature/add-autocompletes-for-usernames-and-passwords into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: #64
2023-05-02 14:14:55 +02:00
bence a5ba8e71e4 add autocomplete values for username and password fields
mapguesser/pipeline/pr-develop This commit looks good
2023-05-02 14:10:10 +02:00
bence 184f63585c Merge pull request 'feature/session-handler-changes' (!63) from feature/session-handler-changes into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: #63
2023-05-02 13:20:07 +02:00
bence d666593fde session should be valid for a session
mapguesser/pipeline/pr-develop This commit looks good
2023-05-02 13:18:37 +02:00
bence 75fad05362 adapt to new soko-web interfaces 2023-05-02 13:18:14 +02:00
bence 45b34cb514 update to soko-web 0.10 2023-05-02 13:18:03 +02:00
bence a6ba53764b Merge pull request 'feature/update-soko-web-to-0.7' (!62) from feature/update-soko-web-to-0.7 into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: #62
2023-04-30 21:07:08 +02:00
bence e70f8a9965 adapt $withRelations usage to soko-web 0.7
mapguesser/pipeline/pr-develop This commit looks good
2023-04-30 21:01:15 +02:00
bence 4aadcab2d2 update soko-web to 0.7 2023-04-30 20:29:43 +02:00
bence 9aea195f85 Merge pull request 'feature/update-soko-web' (!61) from feature/update-soko-web into develop
mapguesser/pipeline/head This commit looks good
Reviewed-on: #61
2023-04-20 00:41:25 +02:00
bence eafcf2315e use IRouteCollection in app container
mapguesser/pipeline/pr-develop This commit looks good
2023-04-20 00:39:10 +02:00
bence e52300b9e5 adapt Container usage to new soko-web 2023-04-20 00:39:10 +02:00
bence ee4a9f2ce3 remove unnecessary startTransaction and commit calls 2023-04-20 00:39:10 +02:00
bence 8141845ae9 add error view 500 to app config 2023-04-20 00:39:10 +02:00
bence 69f54c861a add view for error 500 2023-04-20 00:39:10 +02:00
bence c9ab7c31b7 pass dbConnection to HttpResponse 2023-04-20 00:30:01 +02:00
bence 82279f11d3 update soko-web to 0.6.1 2023-04-20 00:30:01 +02:00
53 changed files with 776 additions and 993 deletions

No files matched your search

Vendored
+28 -3
View File
@@ -13,8 +13,9 @@ pipeline {
}
agent {
dockerfile {
filename 'docker/Dockerfile-test'
filename 'docker/Dockerfile'
dir '.'
additionalBuildArgs '--target mapg_base'
reuseNode true
}
}
@@ -26,8 +27,9 @@ pipeline {
stage('Unit Testing') {
agent {
dockerfile {
filename 'docker/Dockerfile-test'
filename 'docker/Dockerfile'
dir '.'
additionalBuildArgs '--target mapg_base'
reuseNode true
}
}
@@ -44,8 +46,9 @@ pipeline {
stage('Static Code Analysis') {
agent {
dockerfile {
filename 'docker/Dockerfile-test'
filename 'docker/Dockerfile'
dir '.'
additionalBuildArgs '--target mapg_base'
reuseNode true
}
}
@@ -58,5 +61,27 @@ pipeline {
}
}
}
stage('Release Docker image') {
steps {
script {
sh script: 'git clean -ffdx', label: 'Clean repository'
def version = sh(script: 'git describe --tags --always --match "Release_*" HEAD', returnStdout: true).trim()
def imageUrl = "git.esoko.eu/esoko/mapguesser:${version}"
sh script: """docker buildx build \
-t ${imageUrl} \
-f docker/Dockerfile \
--target mapg_release \
.""",
label: 'Build Docker image'
withDockerRegistry([credentialsId: 'gitea-system-user', url: 'https://git.esoko.eu/']) {
sh script: "docker push ${imageUrl}", label: 'Push Docker image to registry'
}
}
}
}
}
}
+57 -58
View File
@@ -6,53 +6,11 @@ This is the MapGuesser Application project. This is a game about guessing where
## Installation
### Clone the Git repository
The first step is obviously cloning the repository to your machine:
```
git clone https://gitea.e5tv.hu/esoko/mapguesser.git
```
All the commands listed here should be executed from the repository root.
### Setup Docker stack (recommended)
The easiest way to build up a fully working application with web server and database is to use Docker Compose with the included `docker-compose.yml`.
All you have to do is executing the following command:
```
docker-compose up -d
```
Attach shell to the container of `mapguesser_app`:
```
docker exec -it mapguesser_app_1 bash
```
All of the following commands should be executed there.
### Manual setup (alternative)
If you don't use the Docker stack you need to install your environment manually. Check `docker-compose.yml` and `docker/Dockerfile` to see the system requirements.
### Initialize project
This command installes all of the Composer requirements and creates a copy of the example `.env` file.
```
composer create-project
```
### Set environment variables
The `.env` file contains several environment variables that are needed by the application to work properly. These should be configured for your environment.
The `.env` file contains several environment variables that are needed by the application to work properly. These should be configured for your environment. Check `.env.example` for reference.
One very important variable is `DEV`. This indicates that the application operates in development (staging) and not in production mode.
**Hint:** If you install the application in the Docker stack for development (staging) environment, only the variables for external dependencies (API keys, map attribution, etc.) should be adapted. All other variables (for DB connection, static root, mailing, multiplayer, etc.) are fine with the default value.
**Important: `DEV` should NOT be set for production! See section Development if you want to use the application in development mode.**
#### API keys
@@ -75,31 +33,72 @@ LEAFLET_TILESERVER_SUBDOMAINS=abc
LEAFLET_TILESERVER_ATTRIBUTION="&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
```
### (Production only) Create cron job
### Docker Compose
To maintain database (delete inactive users, old sessions etc.), the command `db:maintain` should be regularly executed. It is recommended to create a cron job that runs every hour:
Create a `docker-compose.yml` file. The example code below assumes that `.env` is placed in the same folder.
```yml
version: '3'
services:
app:
image: git.esoko.eu/esoko/mapguesser:latest
depends_on:
mariadb:
condition: service_healthy
ports:
- 80:80
- 8090:8090
volumes:
- .env:/var/www/mapguesser/.env
mariadb:
image: mariadb:10.3
volumes:
- mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 'root'
MYSQL_DATABASE: 'mapguesser'
MYSQL_USER: 'mapguesser'
MYSQL_PASSWORD: 'mapguesser'
healthcheck:
test: ["CMD-SHELL", "mysqladmin -u $$MYSQL_USER -p$$MYSQL_PASSWORD ping -h localhost || exit 1"]
start_period: 5s
start_interval: 1s
interval: 5s
timeout: 5s
retries: 5
volumes:
mysql:
```
0 * * * * /path/to/your/installation/mapg db:maintain >>/var/log/cron-mapguesser.log 2>&1
Execute the following command:
```bash
docker compose up -d
```
### Finalize installation
After you followed the above steps, execute the following command:
```
scripts/install.sh
```
**Warning: Because of a known issue the image `mapguesser_multi` fails to run without the installation steps. You have to relauch `docker-compose up -d` after you finished the installation process.**
**And you are done!** The application is ready to use and develop. In development mode an administrative user is also created by the installation script, email is **mapg@mapg.dev**, password is **123456**. In production mode you should create the first administrative user with the following command:
**And you are done!** The application is ready to use. You can create the first administrative user with the following command after attaching to the `app` container:
```
./mapg user:add EMAIL PASSWORD admin
```
If you installed it in the Docker stack, you can reach it on http://localhost. The mails that are sent by the application can be found on http://localhost:8080/. If needed, the database server can be directly reached on localhost:3306.
## Development
### Set environment variables
`.env.example` should be copied to `.env` into the repo root. Only the variables for external dependencies (API keys, map attribution, etc.) should be adapted in. All other variables (for DB connection, static root, mailing, multiplayer, etc.) are fine with the default value. **`DEV=1` should be set for development!**
### Docker Compose
Execute the following command from the repo root:
```bash
docker compose up -d
```
**And you are done!** You can reach the application on http://localhost. The mails that are sent by the application can be found on http://localhost:8080. If needed, the database server can be directly reached on localhost:3306, or you can use Adminer web interface on http://localhost:9090
You might have to attach to the `app` container, e.g. for creating users, `composer update`, etc.
---
+1 -1
View File
@@ -10,7 +10,7 @@
}
],
"require": {
"esoko/soko-web": "0.4",
"esoko/soko-web": "0.14",
"fzaninotto/faker": "^1.9"
},
"require-dev": {
Generated
+179 -103
View File
@@ -4,17 +4,92 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "5e355d5efeb34e7e0ad2a69b1ec109d6",
"content-hash": "00d7fdf2ffefd95b3379f5eb8305c288",
"packages": [
{
"name": "cocur/slugify",
"version": "v4.5.0",
"source": {
"type": "git",
"url": "https://github.com/cocur/slugify.git",
"reference": "af8e6ee771458bf885f7457807b5ff9bad8743cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cocur/slugify/zipball/af8e6ee771458bf885f7457807b5ff9bad8743cb",
"reference": "af8e6ee771458bf885f7457807b5ff9bad8743cb",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"symfony/config": "<3.4 || >=4,<4.3",
"symfony/dependency-injection": "<3.4 || >=4,<4.3",
"symfony/http-kernel": "<3.4 || >=4,<4.3",
"twig/twig": "<2.12.1"
},
"require-dev": {
"laravel/framework": "^5.0|^6.0|^7.0|^8.0",
"latte/latte": "~2.2",
"league/container": "^2.2.0",
"mikey179/vfsstream": "~1.6.8",
"mockery/mockery": "^1.3",
"nette/di": "~2.4",
"pimple/pimple": "~1.1",
"plumphp/plum": "~0.1",
"symfony/config": "^3.4 || ^4.3 || ^5.0 || ^6.0",
"symfony/dependency-injection": "^3.4 || ^4.3 || ^5.0 || ^6.0",
"symfony/http-kernel": "^3.4 || ^4.3 || ^5.0 || ^6.0",
"symfony/phpunit-bridge": "^5.4 || ^6.0",
"twig/twig": "^2.12.1 || ~3.0",
"zendframework/zend-modulemanager": "~2.2",
"zendframework/zend-servicemanager": "~2.2",
"zendframework/zend-view": "~2.2"
},
"type": "library",
"autoload": {
"psr-4": {
"Cocur\\Slugify\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Florian Eckerstorfer",
"email": "florian@eckerstorfer.co",
"homepage": "https://florian.ec"
},
{
"name": "Ivo Bathke",
"email": "ivo.bathke@gmail.com"
}
],
"description": "Converts a string into a slug.",
"keywords": [
"slug",
"slugify"
],
"support": {
"issues": "https://github.com/cocur/slugify/issues",
"source": "https://github.com/cocur/slugify/tree/v4.5.0"
},
"time": "2023-09-16T10:10:53+00:00"
},
{
"name": "esoko/soko-web",
"version": "v0.4",
"version": "v0.14",
"source": {
"type": "git",
"url": "https://git.esoko.eu/esoko/soko-web.git",
"reference": "948b36c80d324e07339a543d97b9e629487f3a45"
"reference": "ebe1fa2aa625c9035611bd995539e9d0f87d1e08"
},
"require": {
"cocur/slugify": "^4.3",
"phpmailer/phpmailer": "^6.8",
"symfony/console": "^5.4",
"vlucas/phpdotenv": "^5.5"
@@ -33,7 +108,7 @@
"GNU GPL 3.0"
],
"description": "Lightweight web framework",
"time": "2023-04-16T18:52:06+00:00"
"time": "2023-09-16T21:56:41+00:00"
},
{
"name": "fzaninotto/faker",
@@ -154,16 +229,16 @@
},
{
"name": "phpmailer/phpmailer",
"version": "v6.8.0",
"version": "v6.8.1",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "df16b615e371d81fb79e506277faea67a1be18f1"
"reference": "e88da8d679acc3824ff231fdc553565b802ac016"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1",
"reference": "df16b615e371d81fb79e506277faea67a1be18f1",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e88da8d679acc3824ff231fdc553565b802ac016",
"reference": "e88da8d679acc3824ff231fdc553565b802ac016",
"shasum": ""
},
"require": {
@@ -173,13 +248,13 @@
"php": ">=5.5.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.7.1",
"squizlabs/php_codesniffer": "^3.7.2",
"yoast/phpunit-polyfills": "^1.0.4"
},
"suggest": {
@@ -222,7 +297,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0"
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.1"
},
"funding": [
{
@@ -230,7 +305,7 @@
"type": "github"
}
],
"time": "2023-03-06T14:43:22+00:00"
"time": "2023-08-29T08:26:30+00:00"
},
{
"name": "phpoption/phpoption",
@@ -357,16 +432,16 @@
},
{
"name": "symfony/console",
"version": "v5.4.22",
"version": "v5.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8"
"reference": "f4f71842f24c2023b91237c72a365306f3c58827"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/3cd51fd2e6c461ca678f84d419461281bd87a0a8",
"reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8",
"url": "https://api.github.com/repos/symfony/console/zipball/f4f71842f24c2023b91237c72a365306f3c58827",
"reference": "f4f71842f24c2023b91237c72a365306f3c58827",
"shasum": ""
},
"require": {
@@ -436,7 +511,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.4.22"
"source": "https://github.com/symfony/console/tree/v5.4.28"
},
"funding": [
{
@@ -452,7 +527,7 @@
"type": "tidelift"
}
],
"time": "2023-03-25T09:27:28+00:00"
"time": "2023-08-07T06:12:30+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -523,16 +598,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@@ -547,7 +622,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -585,7 +660,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@@ -601,20 +676,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
"reference": "875e90aeea2777b6f135677f618529449334a612"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": ""
},
"require": {
@@ -626,7 +701,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -666,7 +741,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
},
"funding": [
{
@@ -682,20 +757,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": ""
},
"require": {
@@ -707,7 +782,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -750,7 +825,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
},
"funding": [
{
@@ -766,20 +841,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@@ -794,7 +869,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -833,7 +908,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@@ -849,20 +924,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9"
"reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5",
"reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5",
"shasum": ""
},
"require": {
@@ -871,7 +946,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -912,7 +987,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0"
},
"funding": [
{
@@ -928,20 +1003,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": ""
},
"require": {
@@ -950,7 +1025,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -995,7 +1070,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
},
"funding": [
{
@@ -1011,7 +1086,7 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/service-contracts",
@@ -1098,16 +1173,16 @@
},
{
"name": "symfony/string",
"version": "v5.4.22",
"version": "v5.4.26",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62"
"reference": "1181fe9270e373537475e826873b5867b863883c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
"reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
"url": "https://api.github.com/repos/symfony/string/zipball/1181fe9270e373537475e826873b5867b863883c",
"reference": "1181fe9270e373537475e826873b5867b863883c",
"shasum": ""
},
"require": {
@@ -1164,7 +1239,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.4.22"
"source": "https://github.com/symfony/string/tree/v5.4.26"
},
"funding": [
{
@@ -1180,7 +1255,7 @@
"type": "tidelift"
}
],
"time": "2023-03-14T06:11:53+00:00"
"time": "2023-06-28T12:46:07+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -1399,16 +1474,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.15.4",
"version": "v4.17.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": ""
},
"require": {
@@ -1449,9 +1524,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
},
"time": "2023-03-05T19:49:14+00:00"
"time": "2023-08-13T19:53:39+00:00"
},
{
"name": "phar-io/manifest",
@@ -1566,16 +1641,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.11",
"version": "1.10.34",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "8aa62e6ea8b58ffb650e02940e55a788cbc3fe21"
"reference": "7f806b6f1403e6914c778140e2ba07c293cb4901"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8aa62e6ea8b58ffb650e02940e55a788cbc3fe21",
"reference": "8aa62e6ea8b58ffb650e02940e55a788cbc3fe21",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/7f806b6f1403e6914c778140e2ba07c293cb4901",
"reference": "7f806b6f1403e6914c778140e2ba07c293cb4901",
"shasum": ""
},
"require": {
@@ -1624,20 +1699,20 @@
"type": "tidelift"
}
],
"time": "2023-04-04T19:17:42+00:00"
"time": "2023-09-13T09:49:47+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.26",
"version": "9.2.28",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
"reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
"reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
"shasum": ""
},
"require": {
@@ -1693,7 +1768,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.28"
},
"funding": [
{
@@ -1701,7 +1777,7 @@
"type": "github"
}
],
"time": "2023-03-06T12:58:08+00:00"
"time": "2023-09-12T14:36:20+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1946,16 +2022,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.6",
"version": "9.6.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115"
"reference": "a122c2ebd469b751d774aa0f613dc0d67697653f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115",
"reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a122c2ebd469b751d774aa0f613dc0d67697653f",
"reference": "a122c2ebd469b751d774aa0f613dc0d67697653f",
"shasum": ""
},
"require": {
@@ -1970,7 +2046,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=7.3",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-code-coverage": "^9.2.28",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",
@@ -2029,7 +2105,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.12"
},
"funding": [
{
@@ -2045,7 +2121,7 @@
"type": "tidelift"
}
],
"time": "2023-03-27T11:43:46+00:00"
"time": "2023-09-12T14:39:31+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -2347,16 +2423,16 @@
},
{
"name": "sebastian/diff",
"version": "4.0.4",
"version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"shasum": ""
},
"require": {
@@ -2401,7 +2477,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
},
"funding": [
{
@@ -2409,7 +2485,7 @@
"type": "github"
}
],
"time": "2020-10-26T13:10:38+00:00"
"time": "2023-05-07T05:35:17+00:00"
},
{
"name": "sebastian/environment",
@@ -2553,16 +2629,16 @@
},
{
"name": "sebastian/global-state",
"version": "5.0.5",
"version": "5.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
"reference": "bde739e7565280bda77be70044ac1047bc007e34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
"reference": "bde739e7565280bda77be70044ac1047bc007e34",
"shasum": ""
},
"require": {
@@ -2605,7 +2681,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
},
"funding": [
{
@@ -2613,7 +2689,7 @@
"type": "github"
}
],
"time": "2022-02-14T08:28:10+00:00"
"time": "2023-08-02T09:26:13+00:00"
},
{
"name": "sebastian/lines-of-code",
@@ -3069,5 +3145,5 @@
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.6.0"
}
+8
View File
@@ -15,6 +15,14 @@ CREATE TABLE `maps` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `migrations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`migration` varchar(255) NOT NULL,
`type` enum('structure', 'data') NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
DROP TABLE IF EXISTS `places`;
CREATE TABLE `places` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -1,6 +0,0 @@
CREATE TABLE `migrations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`migration` varchar(255) NOT NULL,
`type` enum('structure', 'data') NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
+14 -9
View File
@@ -2,22 +2,20 @@ version: '3'
services:
app:
build:
context: ./docker
dockerfile: Dockerfile-app
context: .
dockerfile: docker/Dockerfile
target: mapg_dev
depends_on:
mariadb:
condition: service_healthy
ports:
- 80:80
volumes:
- .:/var/www/mapguesser
multi:
build:
context: ./docker
dockerfile: Dockerfile-multi
ports:
- 5000:5000
- 8090:8090
- 9229:9229
volumes:
- .:/var/www/mapguesser
working_dir: /var/www/mapguesser
mariadb:
image: mariadb:10.3
ports:
@@ -29,6 +27,13 @@ services:
MYSQL_DATABASE: 'mapguesser'
MYSQL_USER: 'mapguesser'
MYSQL_PASSWORD: 'mapguesser'
healthcheck:
test: ["CMD-SHELL", "mysqladmin -u $$MYSQL_USER -p$$MYSQL_PASSWORD ping -h localhost || exit 1"]
start_period: 5s
start_interval: 1s
interval: 5s
timeout: 5s
retries: 5
adminer:
image: adminer:4.8.1-standalone
ports:
+44
View File
@@ -0,0 +1,44 @@
FROM ubuntu:focal AS mapg_base
ENV DEBIAN_FRONTEND noninteractive
RUN apt update --fix-missing && apt install -y curl git unzip mariadb-client nginx \
php-apcu php7.4-cli php7.4-curl php7.4-fpm php7.4-mbstring php7.4-mysql php7.4-zip php7.4-xml
RUN mkdir -p /run/php
COPY docker/configs/nginx.conf /etc/nginx/sites-available/default
COPY docker/scripts/install-composer.sh install-composer.sh
RUN ./install-composer.sh
COPY docker/scripts/install-nodejs.sh install-nodejs.sh
RUN ./install-nodejs.sh
RUN npm install -g uglify-js clean-css-cli svgo yarn
FROM mapg_base AS mapg_dev
RUN apt update --fix-missing && apt install -y php-xdebug
RUN echo "xdebug.remote_enable = 1" >> /etc/php/7.4/mods-available/xdebug.ini &&\
echo "xdebug.remote_autostart = 1" >> /etc/php/7.4/mods-available/xdebug.ini &&\
echo "xdebug.remote_connect_back = 1" >> /etc/php/7.4/mods-available/xdebug.ini
EXPOSE 80
EXPOSE 5000
EXPOSE 8090
EXPOSE 9229
ENTRYPOINT docker/scripts/entry-point-dev.sh
FROM mapg_base AS mapg_release
RUN apt update --fix-missing && apt install -y cron
WORKDIR /var/www/mapguesser
COPY ./ /var/www/mapguesser
RUN docker/scripts/release.sh &&\
rm -rf /var/www/mapguesser/.git /var/www/mapguesser/.env
EXPOSE 80
EXPOSE 8090
ENTRYPOINT docker/scripts/entry-point.sh
-30
View File
@@ -1,30 +0,0 @@
FROM ubuntu:focal
ENV DEBIAN_FRONTEND noninteractive
# Install Nginx, PHP and further necessary packages
RUN apt update --fix-missing
RUN apt install -y curl git unzip mariadb-client nginx \
php-apcu php-xdebug php7.4-cli php7.4-curl php7.4-fpm php7.4-mbstring php7.4-mysql php7.4-zip php7.4-xml
# Configure Nginx with PHP
RUN mkdir -p /run/php
COPY configs/nginx.conf /etc/nginx/sites-available/default
RUN echo "xdebug.remote_enable = 1" >> /etc/php/7.4/mods-available/xdebug.ini
RUN echo "xdebug.remote_autostart = 1" >> /etc/php/7.4/mods-available/xdebug.ini
RUN echo "xdebug.remote_connect_back = 1" >> /etc/php/7.4/mods-available/xdebug.ini
# Install Composer
COPY scripts/install-composer.sh install-composer.sh
RUN ./install-composer.sh
# Install Node.js and required packages
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt install -y nodejs
RUN npm install -g uglify-js clean-css-cli svgo yarn
EXPOSE 80
VOLUME /var/www/mapguesser
WORKDIR /var/www/mapguesser
ENTRYPOINT /usr/sbin/php-fpm7.4 -F & /usr/sbin/nginx -g 'daemon off;'
-16
View File
@@ -1,16 +0,0 @@
FROM ubuntu:focal
ENV DEBIAN_FRONTEND noninteractive
# Install necessary packages
RUN apt update --fix-missing
RUN apt install -y curl build-essential
# Install Node.js and required packages
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt install -y nodejs
VOLUME /var/www/mapguesser
WORKDIR /var/www/mapguesser
ENTRYPOINT /usr/bin/node --inspect=0.0.0.0:9229 multi
-6
View File
@@ -1,6 +0,0 @@
FROM ubuntu:focal
ENV DEBIAN_FRONTEND noninteractive
RUN apt update && apt install -y curl git unzip php7.4-cli php7.4-mbstring php7.4-xml
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+7 -2
View File
@@ -1,11 +1,15 @@
map $http_x_forwarded_proto $forwarded_scheme {
default $scheme;
http http;
https https;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/mapguesser/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name mapguesser-dev.ch;
location / {
@@ -15,6 +19,7 @@ server {
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param REQUEST_SCHEME $forwarded_scheme;
}
location ~ /\.ht {
+1
View File
@@ -0,0 +1 @@
0 * * * * /var/www/mapguesser/mapg db:maintain
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
set -e
chmod 777 cache
echo "Installing Composer packages..."
if [ -f .env ]; then
composer install
else
composer create-project
fi
echo "Installing NPM packages..."
(cd multi && npm install)
echo "Installing Yarn packages..."
(cd public/static && yarn install)
echo "Migrating DB..."
./mapg db:migrate
set +e
/usr/sbin/php-fpm7.4 -F &
/usr/sbin/nginx -g 'daemon off;' &
/usr/bin/node --inspect=0.0.0.0:9229 multi &
wait -n
exit $?
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
set -e
echo "Migrating DB..."
./mapg db:migrate
echo "Installing crontab..."
/usr/bin/crontab docker/scripts/cron
set +e
/usr/sbin/cron -f &
/usr/sbin/php-fpm7.4 -F &
/usr/sbin/nginx -g 'daemon off;' &
/usr/bin/node multi &
wait -n
exit $?
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
set -e
apt update
apt install -y ca-certificates curl gnupg
mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
NODE_MAJOR=18
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
apt update
apt install -y nodejs
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
set -e
chmod 777 cache
echo "Installing Composer packages..."
composer create-project --no-dev
echo "Installing NPM packages..."
(cd multi && npm install)
echo "Installing Yarn packages..."
(cd public/static && yarn install)
echo "Updating version info..."
VERSION=$(git describe --tags --always --match "Release_*" HEAD)
REVISION=$(git rev-parse --short HEAD)
REVISION_DATE=$(git show -s --format=%aI HEAD)
sed -i -E "s/const VERSION = '(.*)';/const VERSION = '${VERSION}';/" main.php
sed -i -E "s/const REVISION = '(.*)';/const REVISION = '${REVISION}';/" main.php
sed -i -E "s/const REVISION_DATE = '(.*)';/const REVISION_DATE = '${REVISION_DATE}';/" main.php
echo "Minifying JS, CSS and SVG files..."
find public/static/js -type f -iname '*.js' -exec uglifyjs {} -c -m -o {} \;
find public/static/css -type f -iname '*.css' -exec cleancss {} -o {} \;
find public/static/img -type f -iname '*.svg' -exec svgo {} -o {} \;
echo "Linking view files..."
./mapg view:link
+3 -1
View File
@@ -15,9 +15,11 @@ $dotenv->load();
class Container
{
static SokoWeb\Interfaces\Database\IConnection $dbConnection;
static SokoWeb\Routing\RouteCollection $routeCollection;
static SokoWeb\Interfaces\PersistentData\IPersistentDataManager $persistentDataManager;
static SokoWeb\Interfaces\Routing\IRouteCollection $routeCollection;
static SokoWeb\Interfaces\Session\ISessionHandler $sessionHandler;
static SokoWeb\Interfaces\Request\IRequest $request;
}
Container::$dbConnection = new SokoWeb\Database\Mysql\Connection($_ENV['DB_HOST'], $_ENV['DB_USER'], $_ENV['DB_PASSWORD'], $_ENV['DB_NAME']);
Container::$persistentDataManager = new SokoWeb\PersistentData\PersistentDataManager(Container::$dbConnection);
-162
View File
@@ -1,162 +0,0 @@
#!/usr/bin/python3
# Usage: ./deploy-to-multiple-worktrees.py REPO_PATH WORKTREE_DEVELOPMENT_PATH WORKTREE_PRODUCTION_PATH
import sys
import os
import subprocess
import re
WORKTREE_REGEX = r"^worktree (.*)\nHEAD ([a-f0-9]*)\n(?:branch refs\/heads\/(.*)|detached)$"
if len(sys.argv) < 4:
print("Usage: ./deploy-to-multiple-worktrees.py REPO_PATH WORKTREE_DEVELOPMENT_PATH WORKTREE_PRODUCTION_PATH")
exit(1)
REPO = os.path.abspath(sys.argv[1])
WORKTREE_DEVELOPMENT = os.path.abspath(sys.argv[2])
WORKTREE_PRODUCTION = os.path.abspath(sys.argv[3])
class Worktree:
def __init__(self, path, branch, revision, version):
self.path = path
self.branch = branch
self.revision = revision
self.version = version
self.newRevision = None
self.newVersion = None
def getDataForWorktrees():
ret = subprocess.check_output(["git", "worktree", "list", "--porcelain"], cwd=REPO).decode().strip()
blocks = ret.split("\n\n")
worktrees = []
for block in blocks:
matches = re.search(WORKTREE_REGEX, block)
if matches:
path = matches.group(1)
revision = matches.group(2)
branch = matches.group(3)
version = getVersion(revision)
worktrees.append(Worktree(path, branch, revision, version))
return worktrees
def findWorktree(path):
for worktree in worktrees:
if worktree.path == path:
return worktree
return None
def getVersion(branch):
return subprocess.check_output(["git", "describe", "--tags", "--always", "--match", "Release_*", branch], cwd=REPO).decode().strip()
def getRevisionForRef(ref):
return subprocess.check_output(["git", "rev-list", "-1", ref], cwd=REPO).decode().strip()
def getLatestReleaseTag():
process = subprocess.Popen(["git", "for-each-ref", "refs/tags/Release*", "--sort=-creatordate", "--format=%(refname:short)"], stdout=subprocess.PIPE, cwd=REPO)
for line in process.stdout:
tag = line.decode().rstrip()
if isTagVerified(tag):
return tag
print(f"[WARNING] Tag '{tag}' is not verified, skipping.")
raise Exception("No verified 'Release*' tag found!")
def isTagVerified(tag):
process = subprocess.run(["git", "tag", "--verify", tag], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=REPO)
return process.returncode == 0
def updateRepoFromRemote():
subprocess.call(["git", "fetch", "origin", "--prune", "--prune-tags"], cwd=REPO)
def checkoutWorktree(worktreePath, ref):
subprocess.call(["git", "checkout", "-f", ref], cwd=worktreePath)
def cleanWorktree(worktreePath):
subprocess.call(["git", "clean", "-f", "-d"], cwd=worktreePath)
def updateAppInWorktree(worktreePath):
subprocess.call([worktreePath + "/scripts/update.sh"], cwd=worktreePath)
def updateAppVersionInWorktree(worktreePath):
subprocess.call([worktreePath + "/scripts/update-version.sh"], cwd=worktreePath)
worktrees = getDataForWorktrees()
updateRepoFromRemote()
print("Repo is updated from origin")
print("----------------------------------------------")
print("----------------------------------------------")
developmentWorktree = findWorktree(WORKTREE_DEVELOPMENT)
developmentWorktree.newRevision = getRevisionForRef(developmentWorktree.branch)
developmentWorktree.newVersion = getVersion(developmentWorktree.revision)
print("DEVELOPMENT (" + developmentWorktree.path + ") is on branch " + developmentWorktree.branch)
print(developmentWorktree.revision + " = " + developmentWorktree.branch + " (" + developmentWorktree.version + ")")
print(developmentWorktree.newRevision + " = origin/" + developmentWorktree.branch + " (" + developmentWorktree.newVersion + ")")
if developmentWorktree.revision != developmentWorktree.newRevision:
print("-> DEVELOPMENT (" + developmentWorktree.path + ") will be UPDATED")
print("----------------------------------------------")
checkoutWorktree(developmentWorktree.path, developmentWorktree.branch)
cleanWorktree(developmentWorktree.path)
print(developmentWorktree.path + " is checked out to " + developmentWorktree.branch + " and cleaned")
updateAppInWorktree(developmentWorktree.path)
updateAppVersionInWorktree(developmentWorktree.path)
print("MapGuesser is updated in " + developmentWorktree.path)
elif developmentWorktree.version != developmentWorktree.newVersion:
print("-> DEVELOPMENT " + developmentWorktree.path + "'s version info will be UPDATED")
updateAppVersionInWorktree(developmentWorktree.path)
print("MapGuesser version is updated in " + developmentWorktree.path)
else:
print("-> DEVELOPMENT (" + developmentWorktree.path + ") WON'T be updated")
print("----------------------------------------------")
print("----------------------------------------------")
productionWorktree = findWorktree(WORKTREE_PRODUCTION)
productionWorktree.newVersion = getLatestReleaseTag()
productionWorktree.newRevision = getRevisionForRef(productionWorktree.newVersion)
print("PRODUCTION (" + productionWorktree.path + ")")
print(productionWorktree.revision + " = " + productionWorktree.version)
print(productionWorktree.newRevision + " = " + productionWorktree.newVersion)
if productionWorktree.revision != productionWorktree.newRevision:
print("-> PRODUCTION (" + productionWorktree.path + ") will be UPDATED")
checkoutWorktree(productionWorktree.path, productionWorktree.newRevision)
cleanWorktree(productionWorktree.path)
print(productionWorktree.path + " is checked out to " + productionWorktree.newRevision + " and cleaned")
updateAppInWorktree(productionWorktree.path)
updateAppVersionInWorktree(productionWorktree.path)
print("MapGuesser is updated in " + productionWorktree.path)
else:
print("-> PRODUCTION (" + productionWorktree.path + ") WON'T be updated")
print("----------------------------------------------")
print("----------------------------------------------")
-35
View File
@@ -1,35 +0,0 @@
#!/bin/bash
ROOT_DIR=$(dirname $(readlink -f "$0"))/..
. ${ROOT_DIR}/.env
if [ -f ${ROOT_DIR}/installed ]; then
echo "MapGuesser is already installed! To force reinstall, delete file 'installed' from the root directory!"
exit 1
fi
echo "Installing NPM packages..."
(cd ${ROOT_DIR}/multi && npm install)
echo "Installing Yarn packages..."
(cd ${ROOT_DIR}/public/static && yarn install)
echo "Installing MapGuesser DB..."
mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/database/mapguesser.sql
echo "Migrating DB..."
(cd ${ROOT_DIR} && ./mapg db:migrate)
if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
echo "Minifying JS, CSS and SVG files..."
${ROOT_DIR}/scripts/minify.sh
echo "Linking view files..."
(cd ${ROOT_DIR} && ./mapg view:link)
else
echo "Creating the first user..."
(cd ${ROOT_DIR} && ./mapg user:add mapg@mapg.dev 123456 admin)
fi
touch ${ROOT_DIR}/installed
-11
View File
@@ -1,11 +0,0 @@
#!/bin/bash
ROOT_DIR=$(dirname $(readlink -f "$0"))/..
. ${ROOT_DIR}/.env
find ${ROOT_DIR}/public/static/js -type f -iname '*.js' -exec uglifyjs {} -c -m -o {} \;
find ${ROOT_DIR}/public/static/css -type f -iname '*.css' -exec cleancss {} -o {} \;
find ${ROOT_DIR}/public/static/img -type f -iname '*.svg' -exec svgo {} -o {} \;
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
ROOT_DIR=$(dirname $(readlink -f "$0"))/..
. ${ROOT_DIR}/.env
cd ${ROOT_DIR}
echo "Updating version info..."
VERSION=$(git describe --tags --always --match "Release_*" HEAD)
REVISION=$(git rev-parse --short HEAD)
REVISION_DATE=$(git show -s --format=%aI HEAD)
sed -i -E "s/const VERSION = '(.*)';/const VERSION = '${VERSION}';/" main.php
sed -i -E "s/const REVISION = '(.*)';/const REVISION = '${REVISION}';/" main.php
sed -i -E "s/const REVISION_DATE = '(.*)';/const REVISION_DATE = '${REVISION_DATE}';/" main.php
-29
View File
@@ -1,29 +0,0 @@
#!/bin/bash
ROOT_DIR=$(dirname $(readlink -f "$0"))/..
. ${ROOT_DIR}/.env
echo "Installing Composer packages..."
if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
(cd ${ROOT_DIR} && composer install --no-dev)
else
(cd ${ROOT_DIR} && composer install --dev)
fi
echo "Installing NPM packages..."
(cd ${ROOT_DIR}/multi && npm install)
echo "Installing Yarn packages..."
(cd ${ROOT_DIR}/public/static && yarn install)
echo "Migrating DB..."
(cd ${ROOT_DIR} && ./mapg db:migrate)
if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
echo "Minifying JS, CSS and SVG files..."
${ROOT_DIR}/scripts/minify.sh
echo "Linking view files..."
(cd ${ROOT_DIR} && ./mapg view:link)
fi
+1 -3
View File
@@ -1,7 +1,6 @@
<?php namespace MapGuesser\Cli;
use DateTime;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\PersistentData\Model\User;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -32,8 +31,7 @@ class AddUserCommand extends Command
}
try {
$pdm = new PersistentDataManager();
$pdm->saveToDb($user);
\Container::$persistentDataManager->saveToDb($user);
} catch (\Exception $e) {
$output->writeln('<error>Adding user failed!</error>');
$output->writeln('');
+6 -10
View File
@@ -4,7 +4,6 @@ use DateTime;
use SokoWeb\Database\Query\Modify;
use SokoWeb\Database\Query\Select;
use SokoWeb\Interfaces\Database\IResultSet;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\Repository\MultiRoomRepository;
use MapGuesser\Repository\UserConfirmationRepository;
use MapGuesser\Repository\UserPasswordResetterRepository;
@@ -16,8 +15,6 @@ use Symfony\Component\Console\Output\OutputInterface;
class MaintainDatabaseCommand extends Command
{
private PersistentDataManager $pdm;
private UserRepository $userRepository;
private UserConfirmationRepository $userConfirmationRepository;
@@ -32,7 +29,6 @@ class MaintainDatabaseCommand extends Command
{
parent::__construct();
$this->pdm = new PersistentDataManager();
$this->userRepository = new UserRepository();
$this->userConfirmationRepository = new UserConfirmationRepository();
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
@@ -77,19 +73,19 @@ class MaintainDatabaseCommand extends Command
//TODO: these can be in some wrapper class
$userConfirmation = $this->userConfirmationRepository->getByUser($user);
if ($userConfirmation !== null) {
$this->pdm->deleteFromDb($userConfirmation);
\Container::$persistentDataManager->deleteFromDb($userConfirmation);
}
$userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user);
if ($userPasswordResetter !== null) {
$this->pdm->deleteFromDb($userPasswordResetter);
\Container::$persistentDataManager->deleteFromDb($userPasswordResetter);
}
foreach ($this->userPlayedPlaceRepository->getAllByUser($user) as $userPlayedPlace) {
$this->pdm->deleteFromDb($userPlayedPlace);
\Container::$persistentDataManager->deleteFromDb($userPlayedPlace);
}
$this->pdm->deleteFromDb($user);
\Container::$persistentDataManager->deleteFromDb($user);
}
\Container::$dbConnection->commit();
@@ -98,14 +94,14 @@ class MaintainDatabaseCommand extends Command
private function deleteExpiredPasswordResetters(): void
{
foreach ($this->userPasswordResetterRepository->getAllExpired() as $passwordResetter) {
$this->pdm->deleteFromDb($passwordResetter);
\Container::$persistentDataManager->deleteFromDb($passwordResetter);
}
}
private function deleteExpiredRooms(): void
{
foreach ($this->multiRoomRepository->getAllExpired() as $multiRoom) {
$this->pdm->deleteFromDb($multiRoom);
\Container::$persistentDataManager->deleteFromDb($multiRoom);
}
}
+20 -11
View File
@@ -19,6 +19,8 @@ class MigrateDatabaseCommand extends Command
{
$db = \Container::$dbConnection;
$this->createBaseDb();
$db->startTransaction();
$success = [];
@@ -62,10 +64,8 @@ class MigrateDatabaseCommand extends Command
return 0;
}
private function readDir(string $type): array
private function createBaseDb()
{
$done = [];
$migrationTableExists = \Container::$dbConnection->query('SELECT count(*)
FROM information_schema.tables
WHERE table_schema = \'' . $_ENV['DB_NAME'] . '\'
@@ -73,16 +73,25 @@ class MigrateDatabaseCommand extends Command
->fetch(IResultSet::FETCH_NUM)[0];
if ($migrationTableExists != 0) {
$select = new Select(\Container::$dbConnection, 'migrations');
$select->columns(['migration']);
$select->where('type', '=', $type);
$select->orderBy('migration');
return;
}
$result = $select->execute();
\Container::$dbConnection->multiQuery(file_get_contents(ROOT . '/database/mapguesser.sql'));
}
while ($migration = $result->fetch(IResultSet::FETCH_ASSOC)) {
$done[] = $migration['migration'];
}
private function readDir(string $type): array
{
$done = [];
$select = new Select(\Container::$dbConnection, 'migrations');
$select->columns(['migration']);
$select->where('type', '=', $type);
$select->orderBy('migration');
$result = $select->execute();
while ($migration = $result->fetch(IResultSet::FETCH_ASSOC)) {
$done[] = $migration['migration'];
}
$path = ROOT . '/database/migrations/' . $type;
+27 -35
View File
@@ -3,7 +3,6 @@
use DateTime;
use Faker\Factory;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Response\HtmlContent;
use SokoWeb\Response\JsonContent;
use SokoWeb\Interfaces\Response\IContent;
@@ -13,7 +12,6 @@ use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\MultiRoom;
use MapGuesser\PersistentData\Model\PlaceInChallenge;
use MapGuesser\PersistentData\Model\UserInChallenge;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\Repository\ChallengeRepository;
use MapGuesser\Repository\MapRepository;
use MapGuesser\Repository\MultiRoomRepository;
@@ -25,10 +23,6 @@ class GameController implements IAuthenticationRequired
{
const NUMBER_OF_ROUNDS = 5;
private IRequest $request;
private PersistentDataManager $pdm;
private MultiConnector $multiConnector;
private MultiRoomRepository $multiRoomRepository;
@@ -41,10 +35,8 @@ class GameController implements IAuthenticationRequired
private UserInChallengeRepository $userInChallengeRepository;
public function __construct(IRequest $request)
public function __construct()
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->multiConnector = new MultiConnector();
$this->multiRoomRepository = new MultiRoomRepository();
$this->mapRepository = new MapRepository();
@@ -60,14 +52,14 @@ class GameController implements IAuthenticationRequired
public function getGame(): IContent
{
$mapId = (int) $this->request->query('mapId');
$mapId = (int) \Container::$request->query('mapId');
return new HtmlContent('game', ['mapId' => $mapId]);
}
public function getNewMultiGame(): IRedirect
{
$mapId = (int) $this->request->query('mapId');
$mapId = (int) \Container::$request->query('mapId');
$map = $this->mapRepository->getById($mapId);
$roomId = bin2hex(random_bytes(3));
$token = $this->getMultiToken($roomId);
@@ -83,7 +75,7 @@ class GameController implements IAuthenticationRequired
$room->setMembersArray(['owner' => $token, 'all' => []]);
$room->setUpdatedDate(new DateTime());
$this->pdm->saveToDb($room);
\Container::$persistentDataManager->saveToDb($room);
$this->multiConnector->sendMessage('create_room', ['roomId' => $roomId]);
@@ -97,14 +89,14 @@ class GameController implements IAuthenticationRequired
public function getMultiGame(): IContent
{
$roomId = $this->request->query('roomId');
$roomId = \Container::$request->query('roomId');
return new HtmlContent('game', ['roomId' => $roomId]);
}
public function getChallenge(): IContent
{
$challengeToken = $this->request->query('challengeToken');
$challengeToken = \Container::$request->query('challengeToken');
return new HtmlContent('game', ['challengeToken' => $challengeToken]);
}
@@ -121,27 +113,27 @@ class GameController implements IAuthenticationRequired
$challenge->setToken($challengeToken);
$challenge->setCreatedDate(new DateTime());
if ($this->request->post('timerEnabled') !== null && $this->request->post('timeLimit') !== null) {
$challenge->setTimeLimit($this->request->post('timeLimit'));
if (\Container::$request->post('timerEnabled') !== null && \Container::$request->post('timeLimit') !== null) {
$challenge->setTimeLimit(\Container::$request->post('timeLimit'));
}
if ($this->request->post('timeLimitType') !== null) {
$challenge->setTimeLimitType($this->request->post('timeLimitType'));
if (\Container::$request->post('timeLimitType') !== null) {
$challenge->setTimeLimitType(\Container::$request->post('timeLimitType'));
}
if ($this->request->post('noMove') !== null) {
if (\Container::$request->post('noMove') !== null) {
$challenge->setNoMove(true);
}
if ($this->request->post('noPan') !== null) {
if (\Container::$request->post('noPan') !== null) {
$challenge->setNoPan(true);
}
if ($this->request->post('noZoom') !== null) {
if (\Container::$request->post('noZoom') !== null) {
$challenge->setNoZoom(true);
}
$this->pdm->saveToDb($challenge);
\Container::$persistentDataManager->saveToDb($challenge);
// save owner/creator
$session = $this->request->session();
$session = \Container::$request->session();
$userId = $session->get('userId');
$userInChallenge = new UserInChallenge();
@@ -150,11 +142,11 @@ class GameController implements IAuthenticationRequired
$userInChallenge->setTimeLeft($challenge->getTimeLimit());
$userInChallenge->setIsOwner(true);
$this->pdm->saveToDb($userInChallenge);
\Container::$persistentDataManager->saveToDb($userInChallenge);
// select places
$mapId = (int) $this->request->post('mapId');
$mapId = (int) \Container::$request->post('mapId');
// $map = $this->mapRepository->getById($mapId);
$places = $this->placeRepository->getRandomNPlaces($mapId, static::NUMBER_OF_ROUNDS, $userId);
@@ -165,7 +157,7 @@ class GameController implements IAuthenticationRequired
$placeInChallenge->setPlace($place);
$placeInChallenge->setChallenge($challenge);
$placeInChallenge->setRound($round++);
$this->pdm->saveToDb($placeInChallenge);
\Container::$persistentDataManager->saveToDb($placeInChallenge);
}
return new JsonContent(['challengeToken' => dechex($challengeToken)]);
@@ -173,9 +165,9 @@ class GameController implements IAuthenticationRequired
public function prepareGame(): IContent
{
$mapId = (int) $this->request->query('mapId');
$mapId = (int) \Container::$request->query('mapId');
$map = $this->mapRepository->getById($mapId);
$session = $this->request->session();
$session = \Container::$request->session();
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
$session->set('state', [
@@ -198,8 +190,8 @@ class GameController implements IAuthenticationRequired
public function prepareMultiGame(): IContent
{
$roomId = $this->request->query('roomId');
$userName = $this->request->post('userName');
$roomId = \Container::$request->query('roomId');
$userName = \Container::$request->post('userName');
if (empty($userName)) {
$faker = Factory::create();
$userName = $faker->userName;
@@ -228,7 +220,7 @@ class GameController implements IAuthenticationRequired
$room->setMembersArray($members);
$room->setUpdatedDate(new DateTime());
$this->pdm->saveToDb($room);
\Container::$persistentDataManager->saveToDb($room);
$this->multiConnector->sendMessage('join_room', [
'roomId' => $roomId,
@@ -248,8 +240,8 @@ class GameController implements IAuthenticationRequired
public function prepareChallenge(): IContent
{
$challengeToken_str = $this->request->query('challengeToken');
$session = $this->request->session();
$challengeToken_str = \Container::$request->query('challengeToken');
$session = \Container::$request->session();
$userId = $session->get('userId');
if (!isset($userId))
@@ -270,7 +262,7 @@ class GameController implements IAuthenticationRequired
$userInChallenge->setUserId($userId);
$userInChallenge->setChallenge($challenge);
$userInChallenge->setTimeLeft($challenge->getTimeLimit());
$this->pdm->saveToDb($userInChallenge);
\Container::$persistentDataManager->saveToDb($userInChallenge);
}
$map = $this->mapRepository->getByChallenge($challenge);
@@ -284,7 +276,7 @@ class GameController implements IAuthenticationRequired
private function getMultiToken(string $roomId): string
{
$session = $this->request->session();
$session = \Container::$request->session();
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
$token = bin2hex(random_bytes(16));
+32 -40
View File
@@ -2,12 +2,10 @@
use DateTime;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use MapGuesser\Util\Geo\Position;
use SokoWeb\Response\JsonContent;
use SokoWeb\Interfaces\Response\IContent;
use MapGuesser\Multi\MultiConnector;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Guess;
use MapGuesser\PersistentData\Model\Map;
@@ -27,10 +25,6 @@ class GameFlowController implements IAuthenticationRequired
const NUMBER_OF_ROUNDS = 5;
const MAX_SCORE = 1000;
private IRequest $request;
private PersistentDataManager $pdm;
private MultiConnector $multiConnector;
private MultiRoomRepository $multiRoomRepository;
@@ -45,10 +39,8 @@ class GameFlowController implements IAuthenticationRequired
private GuessRepository $guessRepository;
public function __construct(IRequest $request)
public function __construct()
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->multiConnector = new MultiConnector();
$this->multiRoomRepository = new MultiRoomRepository();
$this->placeRepository = new PlaceRepository();
@@ -65,8 +57,8 @@ class GameFlowController implements IAuthenticationRequired
public function initialData(): IContent
{
$mapId = (int) $this->request->query('mapId');
$session = $this->request->session();
$mapId = (int) \Container::$request->query('mapId');
$session = \Container::$request->session();
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
return new JsonContent(['error' => 'no_session_found']);
@@ -103,8 +95,8 @@ class GameFlowController implements IAuthenticationRequired
public function multiInitialData(): IContent
{
$roomId = $this->request->query('roomId');
$session = $this->request->session();
$roomId = \Container::$request->query('roomId');
$session = \Container::$request->session();
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
return new JsonContent(['error' => 'no_session_found']);
@@ -122,7 +114,7 @@ class GameFlowController implements IAuthenticationRequired
$this->startNewGame($state, $state['mapId']);
$room->setStateArray($state);
$room->setUpdatedDate(new DateTime());
$this->pdm->saveToDb($room);
\Container::$persistentDataManager->saveToDb($room);
}
$places = [];
@@ -146,7 +138,7 @@ class GameFlowController implements IAuthenticationRequired
// if the last round was played ($currentPlace == null) or history is explicitly requested (for initializing)
if (!isset($currentPlace) || $withHistory) {
$withRelations = [User::class, PlaceInChallenge::class, Place::class];
$withRelations = ['user', 'place_in_challange', 'place'];
foreach ($this->guessRepository->getAllInChallenge($challenge, $withRelations) as $guess) {
$round = $guess->getPlaceInChallenge()->getRound();
@@ -195,7 +187,7 @@ class GameFlowController implements IAuthenticationRequired
$prevRound = $currentRound - 1;
if ($prevRound >= 0) {
foreach ($this->guessRepository->getAllInChallengeByRound($prevRound, $challenge, [User::class]) as $guess) {
foreach ($this->guessRepository->getAllInChallengeByRound($prevRound, $challenge, ['user']) as $guess) {
if ($guess->getUser()->getId() != $userId) {
$response['allResults'][] = [
'userName' => $guess->getUser()->getDisplayName(),
@@ -221,10 +213,10 @@ class GameFlowController implements IAuthenticationRequired
public function challengeInitialData(): IContent
{
$session = $this->request->session();
$session = \Container::$request->session();
$userId = $session->get('userId');
$challengeToken_str = $this->request->query('challengeToken');
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, [Challenge::class]);
$challengeToken_str = \Container::$request->query('challengeToken');
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, ['challenge']);
if (!isset($userInChallenge)) {
return new JsonContent(['error' => 'game_not_found']);
@@ -245,15 +237,15 @@ class GameFlowController implements IAuthenticationRequired
public function guess(): IContent
{
$mapId = (int) $this->request->query('mapId');
$session = $this->request->session();
$mapId = (int) \Container::$request->query('mapId');
$session = \Container::$request->session();
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
return new JsonContent(['error' => 'no_session_found']);
}
$last = $state['rounds'][$state['currentRound']];
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
$guessPosition = new Position((float) \Container::$request->post('lat'), (float) \Container::$request->post('lng'));
$result = $this->evaluateGuess($last['position'], $guessPosition, $state['area']);
$last['guessPosition'] = $guessPosition;
@@ -286,7 +278,7 @@ class GameFlowController implements IAuthenticationRequired
// save the selected place for the round in UserPlayedPlace
private function saveVisit($placeId): void
{
$session = $this->request->session();
$session = \Container::$request->session();
$userId = $session->get('userId');
if (isset($userId)) {
@@ -299,14 +291,14 @@ class GameFlowController implements IAuthenticationRequired
$userPlayedPlace->incrementOccurrences();
}
$userPlayedPlace->setLastTimeDate(new DateTime());
$this->pdm->saveToDb($userPlayedPlace);
\Container::$persistentDataManager->saveToDb($userPlayedPlace);
}
}
public function multiGuess(): IContent
{
$roomId = $this->request->query('roomId');
$session = $this->request->session();
$roomId = \Container::$request->query('roomId');
$session = \Container::$request->session();
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
return new JsonContent(['error' => 'no_session_found']);
@@ -316,7 +308,7 @@ class GameFlowController implements IAuthenticationRequired
$state = $room->getStateArray();
$last = $state['rounds'][$state['currentRound']];
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
$guessPosition = new Position((float) \Container::$request->post('lat'), (float) \Container::$request->post('lng'));
$result = $this->evaluateGuess($last['position'], $guessPosition, $state['area']);
$responseFromMulti = $this->multiConnector->sendMessage('guess', [
@@ -342,10 +334,10 @@ class GameFlowController implements IAuthenticationRequired
public function challengeGuess(): IContent
{
$session = $this->request->session();
$session = \Container::$request->session();
$userId = $session->get('userId');
$challengeToken_str = $this->request->query('challengeToken');
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, [Challenge::class]);
$challengeToken_str = \Container::$request->query('challengeToken');
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, ['challenge']);
if (!isset($userInChallenge)) {
return new JsonContent(['error' => 'game_not_found']);
@@ -353,7 +345,7 @@ class GameFlowController implements IAuthenticationRequired
$challenge = $userInChallenge->getChallenge();
$currentRound = $userInChallenge->getCurrentRound();
$currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge, [Place::class, Map::class]);
$currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge, ['place', 'map']);
$currentPlace = $currentPlaceInChallenge->getPlace();
$map = $currentPlace->getMap();
@@ -362,8 +354,8 @@ class GameFlowController implements IAuthenticationRequired
$response = $this->prepareChallengeResponse($userId, $challenge, $nextRound);
$response['position'] = $currentPlace->getPosition()->toArray();
if ($this->request->post('lat') && $this->request->post('lng')) {
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
if (\Container::$request->post('lat') && \Container::$request->post('lng')) {
$guessPosition = new Position((float) \Container::$request->post('lat'), (float) \Container::$request->post('lng'));
$result = $this->evaluateGuess($currentPlace->getPosition(), $guessPosition, $map->getArea());
// save guess
@@ -373,7 +365,7 @@ class GameFlowController implements IAuthenticationRequired
$guess->setPosition($guessPosition);
$guess->setDistance($result['distance']);
$guess->setScore($result['score']);
$this->pdm->saveToDb($guess);
\Container::$persistentDataManager->saveToDb($guess);
$response['result'] = $result;
@@ -384,11 +376,11 @@ class GameFlowController implements IAuthenticationRequired
// save user relevant state of challenge
$userInChallenge->setCurrentRound($nextRound);
$timeLeft = $this->request->post('timeLeft');
$timeLeft = \Container::$request->post('timeLeft');
if (isset($timeLeft)) {
$userInChallenge->setTimeLeft(intval($timeLeft));
}
$this->pdm->saveToDb($userInChallenge);
\Container::$persistentDataManager->saveToDb($userInChallenge);
if ($challenge->getTimeLimitType() === 'game' && isset($timeLeft)) {
$timeLimit = max(10, intval($timeLeft));
@@ -406,8 +398,8 @@ class GameFlowController implements IAuthenticationRequired
public function multiNextRound(): IContent
{
$roomId = $this->request->query('roomId');
$session = $this->request->session();
$roomId = \Container::$request->query('roomId');
$session = \Container::$request->session();
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
return new JsonContent(['error' => 'no_session_found']);
@@ -428,7 +420,7 @@ class GameFlowController implements IAuthenticationRequired
$room->setStateArray($state);
$room->setUpdatedDate(new DateTime());
$this->pdm->saveToDb($room);
\Container::$persistentDataManager->saveToDb($room);
return new JsonContent(['ok' => true]);
}
@@ -443,7 +435,7 @@ class GameFlowController implements IAuthenticationRequired
private function startNewGame(array &$state, int $mapId): void
{
$session = $this->request->session();
$session = \Container::$request->session();
$userId = $session->get('userId');
$places = $this->placeRepository->getRandomNPlaces($mapId, static::NUMBER_OF_ROUNDS, $userId);
+1 -9
View File
@@ -1,6 +1,5 @@
<?php namespace MapGuesser\Controller;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Interfaces\Response\IRedirect;
use SokoWeb\Response\JsonContent;
@@ -8,13 +7,6 @@ use SokoWeb\Response\Redirect;
class HomeController
{
private IRequest $request;
public function __construct(IRequest $request)
{
$this->request = $request;
}
public function getIndex(): IRedirect
{
return new Redirect(\Container::$routeCollection->getRoute('maps')->generateLink(), IRedirect::TEMPORARY);
@@ -24,6 +16,6 @@ class HomeController
{
// session starts with the request, this method just sends valid data to the client
return new JsonContent(['antiCsrfToken' => $this->request->session()->get('anti_csrf_token')]);
return new JsonContent(['antiCsrfToken' => \Container::$request->session()->get('anti_csrf_token')]);
}
}
+86 -114
View File
@@ -3,7 +3,6 @@
use DateInterval;
use DateTime;
use SokoWeb\Http\Request;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Interfaces\Response\IRedirect;
use SokoWeb\Mailing\Mail;
@@ -11,7 +10,6 @@ use SokoWeb\OAuth\GoogleOAuth;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\UserConfirmation;
use MapGuesser\PersistentData\Model\UserPasswordResetter;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\Repository\UserConfirmationRepository;
use MapGuesser\Repository\UserPasswordResetterRepository;
use MapGuesser\Repository\UserPlayedPlaceRepository;
@@ -24,10 +22,6 @@ use SokoWeb\Util\JwtParser;
class LoginController
{
private IRequest $request;
private PersistentDataManager $pdm;
private UserRepository $userRepository;
private UserConfirmationRepository $userConfirmationRepository;
@@ -38,22 +32,20 @@ class LoginController
private string $redirectUrl;
public function __construct(IRequest $request)
public function __construct()
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->userRepository = new UserRepository();
$this->userConfirmationRepository = new UserConfirmationRepository();
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
$this->redirectUrl = $this->request->session()->has('redirect_after_login') ?
$this->request->session()->get('redirect_after_login') :
$this->redirectUrl = \Container::$request->session()->has('redirect_after_login') ?
\Container::$request->session()->get('redirect_after_login') :
\Container::$routeCollection->getRoute('index')->generateLink();
}
public function getLoginForm()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
@@ -66,13 +58,13 @@ class LoginController
$state = bin2hex(random_bytes(16));
$nonce = bin2hex(random_bytes(16));
$this->request->session()->set('oauth_state', $state);
$this->request->session()->set('oauth_nonce', $nonce);
\Container::$request->session()->set('oauth_state', $state);
\Container::$request->session()->set('oauth_nonce', $nonce);
$oAuth = new GoogleOAuth(new Request());
$url = $oAuth->getDialogUrl(
$state,
$this->request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink(),
\Container::$request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink(),
$nonce
);
@@ -81,13 +73,13 @@ class LoginController
public function getSignupForm()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
if ($this->request->session()->has('tmp_user_data')) {
$tmpUserData = $this->request->session()->get('tmp_user_data');
if (\Container::$request->session()->has('tmp_user_data')) {
$tmpUserData = \Container::$request->session()->get('tmp_user_data');
$data = ['email' => $tmpUserData['email']];
} else {
@@ -104,16 +96,16 @@ class LoginController
public function getSignupWithGoogleForm()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
if (!$this->request->session()->has('google_user_data')) {
if (!\Container::$request->session()->has('google_user_data')) {
return new Redirect(\Container::$routeCollection->getRoute('login-google')->generateLink(), IRedirect::TEMPORARY);
}
$userData = $this->request->session()->get('google_user_data');
$userData = \Container::$request->session()->get('google_user_data');
$user = $this->userRepository->getByEmail($userData['email']);
@@ -122,12 +114,12 @@ class LoginController
public function getRequestPasswordResetForm()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
return new HtmlContent('login/password_reset_request', ['email' => $this->request->query('email')]);
return new HtmlContent('login/password_reset_request', ['email' => \Container::$request->query('email')]);
}
public function getRequestPasswordResetSuccess(): IContent
@@ -137,12 +129,12 @@ class LoginController
public function getResetPasswordForm()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
$token = $this->request->query('token');
$token = \Container::$request->query('token');
$resetter = $this->userPasswordResetterRepository->getByToken($token);
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
@@ -156,15 +148,15 @@ class LoginController
public function login(): IContent
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
}
$user = $this->userRepository->getByEmail($this->request->post('email'));
$user = $this->userRepository->getByEmail(\Container::$request->post('email'));
if ($user === null) {
if (strlen($this->request->post('password')) < 6) {
if (strlen(\Container::$request->post('password')) < 6) {
return new JsonContent([
'error' => [
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
@@ -173,10 +165,10 @@ class LoginController
}
$tmpUser = new User();
$tmpUser->setPlainPassword($this->request->post('password'));
$tmpUser->setPlainPassword(\Container::$request->post('password'));
$this->request->session()->set('tmp_user_data', [
'email' => $this->request->post('email'),
\Container::$request->session()->set('tmp_user_data', [
'email' => \Container::$request->post('email'),
'password_hashed' => $tmpUser->getPassword()
]);
@@ -198,7 +190,7 @@ class LoginController
]);
}
if (!$user->checkPassword($this->request->post('password'))) {
if (!$user->checkPassword(\Container::$request->post('password'))) {
return new JsonContent([
'error' => [
'errorText' => 'The given password is wrong. You can <a href="/password/requestReset?email=' .
@@ -207,7 +199,7 @@ class LoginController
]);
}
$this->request->setUser($user);
\Container::$request->setUser($user);
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
@@ -215,19 +207,19 @@ class LoginController
public function loginWithGoogle()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
if ($this->request->query('state') !== $this->request->session()->get('oauth_state')) {
if (\Container::$request->query('state') !== \Container::$request->session()->get('oauth_state')) {
return new HtmlContent('login/google_login');
}
$oAuth = new GoogleOAuth(new Request());
$tokenData = $oAuth->getToken(
$this->request->query('code'),
$this->request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink()
\Container::$request->query('code'),
\Container::$request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink()
);
if (!isset($tokenData['id_token'])) {
@@ -237,7 +229,7 @@ class LoginController
$jwtParser = new JwtParser($tokenData['id_token']);
$idToken = $jwtParser->getPayload();
if ($idToken['nonce'] !== $this->request->session()->get('oauth_nonce')) {
if ($idToken['nonce'] !== \Container::$request->session()->get('oauth_nonce')) {
return new HtmlContent('login/google_login');
}
@@ -248,12 +240,12 @@ class LoginController
$user = $this->userRepository->getByGoogleSub($idToken['sub']);
if ($user === null) {
$this->request->session()->set('google_user_data', ['sub' => $idToken['sub'], 'email' => $idToken['email']]);
\Container::$request->session()->set('google_user_data', ['sub' => $idToken['sub'], 'email' => $idToken['email']]);
return new Redirect(\Container::$routeCollection->getRoute('signup-google')->generateLink(), IRedirect::TEMPORARY);
}
$this->request->setUser($user);
\Container::$request->setUser($user);
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
@@ -261,23 +253,23 @@ class LoginController
public function logout(): IRedirect
{
$this->request->setUser(null);
\Container::$request->setUser(null);
return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY);
}
public function signup(): IContent
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent(['redirect' => ['target' => $this->redirectUrl]]);
}
$user = $this->userRepository->getByEmail($this->request->post('email'));
$user = $this->userRepository->getByEmail(\Container::$request->post('email'));
if ($user !== null) {
if ($user->getActive()) {
if (!$user->checkPassword($this->request->post('password'))) {
if (!$user->checkPassword(\Container::$request->post('password'))) {
return new JsonContent([
'error' => [
'errorText' => 'There is a user already registered with the given email address, ' .
@@ -287,7 +279,7 @@ class LoginController
]);
}
$this->request->setUser($user);
\Container::$request->setUser($user);
$this->deleteRedirectUrl();
$data = ['redirect' => ['target' => $this->redirectUrl]];
@@ -303,32 +295,32 @@ class LoginController
}
if (!empty($_ENV['RECAPTCHA_SITEKEY'])) {
if (!$this->request->post('g-recaptcha-response')) {
if (!\Container::$request->post('g-recaptcha-response')) {
return new JsonContent(['error' => ['errorText' => 'Please check "I\'m not a robot" in the reCAPTCHA box!']]);
}
$captchaValidator = new CaptchaValidator();
$captchaResponse = $captchaValidator->validate($this->request->post('g-recaptcha-response'));
$captchaResponse = $captchaValidator->validate(\Container::$request->post('g-recaptcha-response'));
if (!$captchaResponse['success']) {
return new JsonContent(['error' => ['errorText' => 'reCAPTCHA challenge failed. Please try again!']]);
}
}
if (filter_var($this->request->post('email'), FILTER_VALIDATE_EMAIL) === false) {
if (filter_var(\Container::$request->post('email'), FILTER_VALIDATE_EMAIL) === false) {
return new JsonContent(['error' => ['errorText' => 'The given email address is not valid.']]);
}
if ($this->request->session()->has('tmp_user_data')) {
$tmpUserData = $this->request->session()->get('tmp_user_data');
if (\Container::$request->session()->has('tmp_user_data')) {
$tmpUserData = \Container::$request->session()->get('tmp_user_data');
$tmpUser = new User();
$tmpUser->setPassword($tmpUserData['password_hashed']);
if (!$tmpUser->checkPassword($this->request->post('password'))) {
if (!$tmpUser->checkPassword(\Container::$request->post('password'))) {
return new JsonContent(['error' => ['errorText' => 'The given passwords do not match.']]);
}
} else {
if (strlen($this->request->post('password')) < 6) {
if (strlen(\Container::$request->post('password')) < 6) {
return new JsonContent([
'error' => [
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
@@ -336,19 +328,17 @@ class LoginController
]);
}
if ($this->request->post('password') !== $this->request->post('password_confirm')) {
if (\Container::$request->post('password') !== \Container::$request->post('password_confirm')) {
return new JsonContent(['error' => ['errorText' => 'The given passwords do not match.']]);
}
}
$user = new User();
$user->setEmail($this->request->post('email'));
$user->setPlainPassword($this->request->post('password'));
$user->setEmail(\Container::$request->post('email'));
$user->setPlainPassword(\Container::$request->post('password'));
$user->setCreatedDate(new DateTime());
\Container::$dbConnection->startTransaction();
$this->pdm->saveToDb($user);
\Container::$persistentDataManager->saveToDb($user);
$token = bin2hex(random_bytes(16));
@@ -357,25 +347,23 @@ class LoginController
$confirmation->setToken($token);
$confirmation->setLastSentDate(new DateTime());
$this->pdm->saveToDb($confirmation);
\Container::$dbConnection->commit();
\Container::$persistentDataManager->saveToDb($confirmation);
$this->sendConfirmationEmail($user->getEmail(), $token, $user->getCreatedDate());
$this->request->session()->delete('tmp_user_data');
\Container::$request->session()->delete('tmp_user_data');
return new JsonContent(['success' => true]);
}
public function signupWithGoogle(): IContent
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
}
$userData = $this->request->session()->get('google_user_data');
$userData = \Container::$request->session()->get('google_user_data');
$user = $this->userRepository->getByEmail($userData['email']);
@@ -392,14 +380,14 @@ class LoginController
$user->setActive(true);
$user->setGoogleSub($userData['sub']);
$this->pdm->saveToDb($user);
\Container::$persistentDataManager->saveToDb($user);
if ($sendWelcomeEmail) {
$this->sendWelcomeEmail($user->getEmail());
}
$this->request->session()->delete('google_user_data');
$this->request->setUser($user);
\Container::$request->session()->delete('google_user_data');
\Container::$request->setUser($user);
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
@@ -407,43 +395,39 @@ class LoginController
public function resetSignup(): IContent
{
$this->request->session()->delete('tmp_user_data');
\Container::$request->session()->delete('tmp_user_data');
return new JsonContent(['success' => true]);
}
public function resetGoogleSignup(): IContent
{
$this->request->session()->delete('google_user_data');
\Container::$request->session()->delete('google_user_data');
return new JsonContent(['success' => true]);
}
public function activate()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
$confirmation = $this->userConfirmationRepository->getByToken(substr($this->request->query('token'), 0, 32));
$confirmation = $this->userConfirmationRepository->getByToken(substr(\Container::$request->query('token'), 0, 32));
if ($confirmation === null) {
return new HtmlContent('login/activate');
}
\Container::$dbConnection->startTransaction();
$this->pdm->deleteFromDb($confirmation);
\Container::$persistentDataManager->deleteFromDb($confirmation);
$user = $this->userRepository->getById($confirmation->getUserId());
$user->setActive(true);
$this->pdm->saveToDb($user);
\Container::$persistentDataManager->saveToDb($user);
\Container::$dbConnection->commit();
$this->request->setUser($user);
\Container::$request->setUser($user);
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
@@ -451,37 +435,33 @@ class LoginController
public function cancel()
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
$confirmation = $this->userConfirmationRepository->getByToken(substr($this->request->query('token'), 0, 32));
$confirmation = $this->userConfirmationRepository->getByToken(substr(\Container::$request->query('token'), 0, 32));
if ($confirmation === null) {
return new HtmlContent('login/cancel', ['success' => false]);
}
\Container::$dbConnection->startTransaction();
$this->pdm->deleteFromDb($confirmation);
\Container::$persistentDataManager->deleteFromDb($confirmation);
$user = $this->userRepository->getById($confirmation->getUserId());
foreach ($this->userPlayedPlaceRepository->getAllByUser($user) as $userPlayedPlace) {
$this->pdm->deleteFromDb($userPlayedPlace);
\Container::$persistentDataManager->deleteFromDb($userPlayedPlace);
}
$this->pdm->deleteFromDb($user);
\Container::$dbConnection->commit();
\Container::$persistentDataManager->deleteFromDb($user);
return new HtmlContent('login/cancel', ['success' => true]);
}
public function requestPasswordReset(): IContent
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent([
'redirect' => [
@@ -491,18 +471,18 @@ class LoginController
}
if (!empty($_ENV['RECAPTCHA_SITEKEY'])) {
if (!$this->request->post('g-recaptcha-response')) {
if (!\Container::$request->post('g-recaptcha-response')) {
return new JsonContent(['error' => ['errorText' => 'Please check "I\'m not a robot" in the reCAPTCHA box!']]);
}
$captchaValidator = new CaptchaValidator();
$captchaResponse = $captchaValidator->validate($this->request->post('g-recaptcha-response'));
$captchaResponse = $captchaValidator->validate(\Container::$request->post('g-recaptcha-response'));
if (!$captchaResponse['success']) {
return new JsonContent(['error' => ['errorText' => 'reCAPTCHA challenge failed. Please try again!']]);
}
}
$user = $this->userRepository->getByEmail($this->request->post('email'));
$user = $this->userRepository->getByEmail(\Container::$request->post('email'));
if ($user === null) {
return new JsonContent([
@@ -541,15 +521,11 @@ class LoginController
$passwordResetter->setToken($token);
$passwordResetter->setExpiresDate($expires);
\Container::$dbConnection->startTransaction();
if ($existingResetter !== null) {
$this->pdm->deleteFromDb($existingResetter);
\Container::$persistentDataManager->deleteFromDb($existingResetter);
}
$this->pdm->saveToDb($passwordResetter);
\Container::$dbConnection->commit();
\Container::$persistentDataManager->saveToDb($passwordResetter);
$this->sendPasswordResetEmail($user->getEmail(), $token, $expires);
@@ -559,7 +535,7 @@ class LoginController
public function resetPassword(): IContent
{
if ($this->request->user() !== null) {
if (\Container::$request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent([
'redirect' => [
@@ -568,7 +544,7 @@ class LoginController
]);
}
$token = $this->request->query('token');
$token = \Container::$request->query('token');
$resetter = $this->userPasswordResetterRepository->getByToken($token);
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
@@ -579,7 +555,7 @@ class LoginController
]);
}
if (strlen($this->request->post('password')) < 6) {
if (strlen(\Container::$request->post('password')) < 6) {
return new JsonContent([
'error' => [
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
@@ -587,22 +563,18 @@ class LoginController
]);
}
if ($this->request->post('password') !== $this->request->post('password_confirm')) {
if (\Container::$request->post('password') !== \Container::$request->post('password_confirm')) {
return new JsonContent(['error' => ['errorText' => 'The given passwords do not match.']]);
}
\Container::$dbConnection->startTransaction();
$this->pdm->deleteFromDb($resetter);
\Container::$persistentDataManager->deleteFromDb($resetter);
$user = $this->userRepository->getById($resetter->getUserId());
$user->setPlainPassword($this->request->post('password'));
$user->setPlainPassword(\Container::$request->post('password'));
$this->pdm->saveToDb($user);
\Container::$persistentDataManager->saveToDb($user);
\Container::$dbConnection->commit();
$this->request->setUser($user);
\Container::$request->setUser($user);
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
@@ -615,9 +587,9 @@ class LoginController
$mail->setSubject('Welcome to ' . $_ENV['APP_NAME'] . ' - Activate your account');
$mail->setBodyFromTemplate('signup', [
'EMAIL' => $email,
'ACTIVATE_LINK' => $this->request->getBase() .
'ACTIVATE_LINK' => \Container::$request->getBase() .
\Container::$routeCollection->getRoute('signup.activate')->generateLink(['token' => $token]),
'CANCEL_LINK' => $this->request->getBase() .
'CANCEL_LINK' => \Container::$request->getBase() .
\Container::$routeCollection->getRoute('signup.cancel')->generateLink(['token' => $token]),
'ACTIVATABLE_UNTIL' => (clone $created)->add(new DateInterval('P1D'))->format('Y-m-d H:i T')
]);
@@ -634,7 +606,7 @@ class LoginController
$confirmation->setLastSentDate(new DateTime());
$this->pdm->saveToDb($confirmation);
\Container::$persistentDataManager->saveToDb($confirmation);
$this->sendConfirmationEmail($user->getEmail(), $confirmation->getToken(), $user->getCreatedDate());
@@ -659,7 +631,7 @@ class LoginController
$mail->setSubject($_ENV['APP_NAME'] . ' - Password reset');
$mail->setBodyFromTemplate('password-reset', [
'EMAIL' => $email,
'RESET_LINK' => $this->request->getBase() .
'RESET_LINK' => \Container::$request->getBase() .
\Container::$routeCollection->getRoute('password-reset')->generateLink(['token' => $token]),
'EXPIRES' => $expires->format('Y-m-d H:i T')
]);
@@ -668,6 +640,6 @@ class LoginController
private function deleteRedirectUrl(): void
{
$this->request->session()->delete('redirect_after_login');
\Container::$request->session()->delete('redirect_after_login');
}
}
+18 -34
View File
@@ -4,13 +4,11 @@ use DateTime;
use SokoWeb\Interfaces\Authentication\IUser;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Authorization\ISecured;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\PlaceInChallenge;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\Repository\ChallengeRepository;
use MapGuesser\Repository\GuessRepository;
use MapGuesser\Repository\MapRepository;
@@ -27,10 +25,6 @@ class MapAdminController implements IAuthenticationRequired, ISecured
{
private static string $unnamedMapName = '[unnamed map]';
private IRequest $request;
private PersistentDataManager $pdm;
private MapRepository $mapRepository;
private PlaceRepository $placeRepository;
@@ -45,10 +39,8 @@ class MapAdminController implements IAuthenticationRequired, ISecured
private UserInChallengeRepository $userInChallengeRepository;
public function __construct(IRequest $request)
public function __construct()
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->mapRepository = new MapRepository();
$this->placeRepository = new PlaceRepository();
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
@@ -65,12 +57,12 @@ class MapAdminController implements IAuthenticationRequired, ISecured
public function authorize(): bool
{
return $this->request->user()->hasPermission(IUser::PERMISSION_ADMIN);
return \Container::$request->user()->hasPermission(IUser::PERMISSION_ADMIN);
}
public function getMapEditor(): IContent
{
$mapId = (int) $this->request->query('mapId');
$mapId = (int) \Container::$request->query('mapId');
if ($mapId) {
$map = $this->mapRepository->getById($mapId);
@@ -93,7 +85,7 @@ class MapAdminController implements IAuthenticationRequired, ISecured
public function getPlace(): IContent
{
$placeId = (int) $this->request->query('placeId');
$placeId = (int) \Container::$request->query('placeId');
$place = $this->placeRepository->getById($placeId);
@@ -102,16 +94,14 @@ class MapAdminController implements IAuthenticationRequired, ISecured
public function saveMap(): IContent
{
$mapId = (int) $this->request->query('mapId');
\Container::$dbConnection->startTransaction();
$mapId = (int) \Container::$request->query('mapId');
if ($mapId) {
$map = $this->mapRepository->getById($mapId);
} else {
$map = new Map();
$map->setName(self::$unnamedMapName);
$this->pdm->saveToDb($map);
\Container::$persistentDataManager->saveToDb($map);
}
if (isset($_POST['added'])) {
@@ -133,7 +123,7 @@ class MapAdminController implements IAuthenticationRequired, ISecured
$place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
}
$this->pdm->saveToDb($place);
\Container::$persistentDataManager->saveToDb($place);
$addedIds[] = ['tempId' => $placeRaw['id'], 'id' => $place->getId()];
}
@@ -155,7 +145,7 @@ class MapAdminController implements IAuthenticationRequired, ISecured
));
$place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
$this->pdm->saveToDb($place);
\Container::$persistentDataManager->saveToDb($place);
}
}
@@ -184,26 +174,20 @@ class MapAdminController implements IAuthenticationRequired, ISecured
$map->setUnlisted((bool)$_POST['unlisted']);
}
$this->pdm->saveToDb($map);
\Container::$dbConnection->commit();
\Container::$persistentDataManager->saveToDb($map);
return new JsonContent(['mapId' => $map->getId(), 'added' => $addedIds]);
}
public function deleteMap(): IContent
{
$mapId = (int) $this->request->query('mapId');
$mapId = (int) \Container::$request->query('mapId');
$map = $this->mapRepository->getById($mapId);
\Container::$dbConnection->startTransaction();
$this->deletePlaces($map);
$this->pdm->deleteFromDb($map);
\Container::$dbConnection->commit();
\Container::$persistentDataManager->deleteFromDb($map);
return new JsonContent(['success' => true]);
}
@@ -211,14 +195,14 @@ class MapAdminController implements IAuthenticationRequired, ISecured
private function deletePlace(Place $place): void
{
foreach ($this->userPlayedPlaceRepository->getAllByPlace($place) as $userPlayedPlace) {
$this->pdm->deleteFromDb($userPlayedPlace);
\Container::$persistentDataManager->deleteFromDb($userPlayedPlace);
}
foreach ($this->challengeRepository->getAllByPlace($place) as $challenge) {
$this->deleteChallenge($challenge);
}
$this->pdm->deleteFromDb($place);
\Container::$persistentDataManager->deleteFromDb($place);
}
private function deletePlaces(Map $map): void
@@ -231,18 +215,18 @@ class MapAdminController implements IAuthenticationRequired, ISecured
private function deleteChallenge(Challenge $challenge): void
{
foreach ($this->userInChallengeRepository->getAllByChallenge($challenge) as $userInChallenge) {
$this->pdm->deleteFromDb($userInChallenge);
\Container::$persistentDataManager->deleteFromDb($userInChallenge);
}
foreach ($this->guessRepository->getAllInChallenge($challenge, [PlaceInChallenge::class]) as $guess) {
$this->pdm->deleteFromDb($guess);
foreach ($this->guessRepository->getAllInChallenge($challenge, ['place_in_challange']) as $guess) {
\Container::$persistentDataManager->deleteFromDb($guess);
}
foreach ($this->placeInChallengeRepository->getAllByChallenge($challenge) as $placeInChallenge) {
$this->pdm->deleteFromDb($placeInChallenge);
\Container::$persistentDataManager->deleteFromDb($placeInChallenge);
}
$this->pdm->deleteFromDb($challenge);
\Container::$persistentDataManager->deleteFromDb($challenge);
}
private function calculateMapBounds(Map $map): Bounds
+1 -9
View File
@@ -4,19 +4,11 @@ use SokoWeb\Database\Query\Select;
use SokoWeb\Database\RawExpression;
use SokoWeb\Interfaces\Authentication\IUser;
use SokoWeb\Interfaces\Database\IResultSet;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Response\HtmlContent;
class MapsController
{
private IRequest $request;
public function __construct(IRequest $request)
{
$this->request = $request;
}
public function getMaps(): IContent
{
//TODO: from repository - count should be added
@@ -37,7 +29,7 @@ class MapsController
$select->groupBy(['maps', 'id']);
$select->orderBy('name');
$user = $this->request->user();
$user = \Container::$request->user();
$isAdmin = $user !== null && $user->hasPermission(IUser::PERMISSION_ADMIN);
if (!$isAdmin) {
$select->where(['maps', 'unlisted'], '=', false);
+32 -44
View File
@@ -3,11 +3,9 @@
use DateTime;
use SokoWeb\Http\Request;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Interfaces\Response\IRedirect;
use SokoWeb\OAuth\GoogleOAuth;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\Repository\GuessRepository;
use MapGuesser\Repository\UserConfirmationRepository;
@@ -21,10 +19,6 @@ use SokoWeb\Util\JwtParser;
class UserController implements IAuthenticationRequired
{
private IRequest $request;
private PersistentDataManager $pdm;
private UserConfirmationRepository $userConfirmationRepository;
private UserPasswordResetterRepository $userPasswordResetterRepository;
@@ -35,10 +29,8 @@ class UserController implements IAuthenticationRequired
private GuessRepository $guessRepository;
public function __construct(IRequest $request)
public function __construct()
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->userConfirmationRepository = new UserConfirmationRepository();
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
@@ -56,7 +48,7 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = $this->request->user();
$user = \Container::$request->user();
return new HtmlContent('account/account', ['user' => $user->toArray()]);
}
@@ -66,19 +58,19 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = $this->request->user();
$user = \Container::$request->user();
$state = bin2hex(random_bytes(16));
$nonce = bin2hex(random_bytes(16));
$this->request->session()->set('oauth_state', $state);
$this->request->session()->set('oauth_nonce', $nonce);
\Container::$request->session()->set('oauth_state', $state);
\Container::$request->session()->set('oauth_nonce', $nonce);
$oAuth = new GoogleOAuth(new Request());
$url = $oAuth->getDialogUrl(
$state,
$this->request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(),
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(),
$nonce,
$user->getEmail()
);
@@ -91,16 +83,16 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = $this->request->user();
$user = \Container::$request->user();
if ($this->request->query('state') !== $this->request->session()->get('oauth_state')) {
if (\Container::$request->query('state') !== \Container::$request->session()->get('oauth_state')) {
return new HtmlContent('account/google_authenticate', ['success' => false]);
}
$oAuth = new GoogleOAuth(new Request());
$tokenData = $oAuth->getToken(
$this->request->query('code'),
$this->request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink()
\Container::$request->query('code'),
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink()
);
if (!isset($tokenData['id_token'])) {
@@ -110,7 +102,7 @@ class UserController implements IAuthenticationRequired
$jwtParser = new JwtParser($tokenData['id_token']);
$idToken = $jwtParser->getPayload();
if ($idToken['nonce'] !== $this->request->session()->get('oauth_nonce')) {
if ($idToken['nonce'] !== \Container::$request->session()->get('oauth_nonce')) {
return new HtmlContent('account/google_authenticate', ['success' => false]);
}
@@ -122,7 +114,7 @@ class UserController implements IAuthenticationRequired
}
$authenticatedWithGoogleUntil = new DateTime('+45 seconds');
$this->request->session()->set('authenticated_with_google_until', $authenticatedWithGoogleUntil);
\Container::$request->session()->set('authenticated_with_google_until', $authenticatedWithGoogleUntil);
return new HtmlContent('account/google_authenticate', [
'success' => true,
@@ -135,7 +127,7 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = $this->request->user();
$user = \Container::$request->user();
return new HtmlContent('account/delete', ['user' => $user->toArray()]);
}
@@ -145,19 +137,19 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = $this->request->user();
$user = \Container::$request->user();
if (!$this->confirmUserIdentity(
$user,
$this->request->session()->get('authenticated_with_google_until'),
$this->request->post('password'),
\Container::$request->session()->get('authenticated_with_google_until'),
\Container::$request->post('password'),
$error
)) {
return new JsonContent(['error' => ['errorText' => $error]]);
}
if (strlen($this->request->post('password_new')) > 0) {
if (strlen($this->request->post('password_new')) < 6) {
if (strlen(\Container::$request->post('password_new')) > 0) {
if (strlen(\Container::$request->post('password_new')) < 6) {
return new JsonContent([
'error' => [
'errorText' => 'The given new password is too short. Please choose a password that is at least 6 characters long!'
@@ -165,7 +157,7 @@ class UserController implements IAuthenticationRequired
]);
}
if ($this->request->post('password_new') !== $this->request->post('password_new_confirm')) {
if (\Container::$request->post('password_new') !== \Container::$request->post('password_new_confirm')) {
return new JsonContent([
'error' => [
'errorText' => 'The given new passwords do not match.'
@@ -173,12 +165,12 @@ class UserController implements IAuthenticationRequired
]);
}
$user->setPlainPassword($this->request->post('password_new'));
$user->setPlainPassword(\Container::$request->post('password_new'));
}
$this->pdm->saveToDb($user);
\Container::$persistentDataManager->saveToDb($user);
$this->request->session()->delete('authenticated_with_google_until');
\Container::$request->session()->delete('authenticated_with_google_until');
return new JsonContent(['success' => true]);
}
@@ -188,46 +180,42 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = $this->request->user();
$user = \Container::$request->user();
if (!$this->confirmUserIdentity(
$user,
$this->request->session()->get('authenticated_with_google_until'),
$this->request->post('password'),
\Container::$request->session()->get('authenticated_with_google_until'),
\Container::$request->post('password'),
$error
)) {
return new JsonContent(['error' => ['errorText' => $error]]);
}
\Container::$dbConnection->startTransaction();
$userConfirmation = $this->userConfirmationRepository->getByUser($user);
if ($userConfirmation !== null) {
$this->pdm->deleteFromDb($userConfirmation);
\Container::$persistentDataManager->deleteFromDb($userConfirmation);
}
$userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user);
if ($userPasswordResetter !== null) {
$this->pdm->deleteFromDb($userPasswordResetter);
\Container::$persistentDataManager->deleteFromDb($userPasswordResetter);
}
foreach ($this->userPlayedPlaceRepository->getAllByUser($user) as $userPlayedPlace) {
$this->pdm->deleteFromDb($userPlayedPlace);
\Container::$persistentDataManager->deleteFromDb($userPlayedPlace);
}
foreach ($this->userInChallengeRepository->getAllByUser($user) as $userInChallenge) {
$this->pdm->deleteFromDb($userInChallenge);
\Container::$persistentDataManager->deleteFromDb($userInChallenge);
}
foreach ($this->guessRepository->getAllByUser($user) as $guess) {
$this->pdm->deleteFromDb($guess);
\Container::$persistentDataManager->deleteFromDb($guess);
}
$this->pdm->deleteFromDb($user);
\Container::$persistentDataManager->deleteFromDb($user);
\Container::$dbConnection->commit();
$this->request->session()->delete('authenticated_with_google_until');
\Container::$request->session()->delete('authenticated_with_google_until');
return new JsonContent(['success' => true]);
}
+1 -2
View File
@@ -4,7 +4,6 @@ use DateInterval;
use DateTime;
use SokoWeb\PersistentData\Model\Model;
use SokoWeb\Http\Request;
use SokoWeb\PersistentData\PersistentDataManager;
use MapGuesser\Util\Geo\Position;
use MapGuesser\Util\Panorama\Pov;
@@ -163,7 +162,7 @@ class Place extends Model
$this->panoIdCached = $panoId;
$this->panoIdCachedTimestamp = new DateTime();
(new PersistentDataManager())->saveToDb($this);
\Container::$persistentDataManager->saveToDb($this);
return $panoId;
}
+9 -17
View File
@@ -5,20 +5,12 @@ use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\User;
use SokoWeb\PersistentData\PersistentDataManager;
class ChallengeRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $challengeId): ?Challenge
{
return $this->pdm->selectFromDbById($challengeId, Challenge::class);
return \Container::$persistentDataManager->selectFromDbById($challengeId, Challenge::class);
}
public function getByToken(int $token): ?Challenge
@@ -26,7 +18,7 @@ class ChallengeRepository
$select = new Select(\Container::$dbConnection);
$select->where('token', '=', $token);
return $this->pdm->selectFromDb($select, Challenge::class);
return \Container::$persistentDataManager->selectFromDb($select, Challenge::class);
}
public function getByTokenStr(string $token_str): ?Challenge
@@ -48,9 +40,9 @@ class ChallengeRepository
$select = new Select(\Container::$dbConnection);
$select->innerJoin('user_in_challenge', ['challenge', 'id'], '=', ['user_in_challenge', 'challenge_id']);
$select->innerJoin('users', ['users', 'id'], '=', ['user_in_challenge', 'user_id']);
$select->where('user_id', '=', $user->getId());
$select->where(['user_in_challenge', 'user_id'], '=', $user->getId());
yield from $this->pdm->selectMultipleFromDb($select, Challenge::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Challenge::class);
}
public function getAllByOwner(User $user): Generator
@@ -58,18 +50,18 @@ class ChallengeRepository
$select = new Select(\Container::$dbConnection);
$select->innerJoin('user_in_challenge', ['challenge', 'id'], '=', ['user_in_challenge', 'challenge_id']);
$select->innerJoin('users', ['users', 'id'], '=', ['user_in_challenge', 'user_id']);
$select->where('user_id', '=', $user->getId());
$select->where('is_owner', '=', true);
$select->where(['user_in_challenge', 'user_id'], '=', $user->getId());
$select->where(['user_in_challenge', 'is_owner'], '=', true);
yield from $this->pdm->selectMultipleFromDb($select, Challenge::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Challenge::class);
}
public function getAllByPlace(Place $place): Generator
{
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['challenges', 'id'], '=', ['place_in_challenge', 'challenge_id']);
$select->where('place_id', '=', $place->getId());
$select->where(['place_in_challenge', 'place_id'], '=', $place->getId());
yield from $this->pdm->selectMultipleFromDb($select, Challenge::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Challenge::class);
}
}
+19 -27
View File
@@ -7,23 +7,15 @@ use MapGuesser\PersistentData\Model\Guess;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\PlaceInChallenge;
use SokoWeb\PersistentData\PersistentDataManager;
class GuessRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getAllByUser(User $user): Generator
{
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Guess::class);
}
public function getAllByUserAndChallenge(User $user, Challenge $challenge): Generator
@@ -31,9 +23,9 @@ class GuessRepository
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
$select->where('user_id', '=', $user->getId());
$select->where('challenge_id', '=', $challenge->getId());
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Guess::class);
}
public function getByUserAndPlaceInChallenge(User $user, Challenge $challenge, Place $place): ?Guess
@@ -41,10 +33,10 @@ class GuessRepository
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
$select->where('user_id', '=', $user->getId());
$select->where('challenge_id', '=', $challenge->getId());
$select->where('place_id', '=', $place->getId());
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
$select->where(['place_in_challenge', 'place_id'], '=', $place->getId());
return $this->pdm->selectFromDb($select, Guess::class);
return \Container::$persistentDataManager->selectFromDb($select, Guess::class);
}
public function getAllInChallengeByUser(int $userId, Challenge $challenge): Generator
@@ -52,46 +44,46 @@ class GuessRepository
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
$select->where('user_id', '=', $userId);
$select->where('challenge_id', '=', $challenge->getId());
$select->orderBy('round');
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
$select->orderBy(['place_in_challenge', 'round']);
yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Guess::class);
}
public function getAllInChallenge(Challenge $challenge, array $withRelations = []): Generator
{
if (count($withRelations)) {
$necessaryRelations = [PlaceInChallenge::class];
$necessaryRelations = ['place_in_challenge'];
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
}
$select = new Select(\Container::$dbConnection);
$select->where('challenge_id', '=', $challenge->getId());
$select->orderBy('round');
$select->where(['guesses__place_in_challenge', 'challenge_id'], '=', $challenge->getId());
$select->orderBy(['guesses__place_in_challenge', 'round']);
yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true, $withRelations);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Guess::class, true, $withRelations);
}
public function getAllInChallengeByRound(int $round, Challenge $challenge, array $withRelations = []): Generator
{
if (count($withRelations)) {
$necessaryRelations = [PlaceInChallenge::class];
$necessaryRelations = ['place_in_challenge'];
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
}
$select = new Select(\Container::$dbConnection);
$select->where('challenge_id', '=', $challenge->getId());
$select->where('round', '=', $round);
$select->where(['guesses__place_in_challenge', 'challenge_id'], '=', $challenge->getId());
$select->where(['guesses__place_in_challenge', 'round'], '=', $round);
yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true, $withRelations);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Guess::class, true, $withRelations);
}
public function getAllByPlace(Place $place): Generator
{
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
$select->where('place_id', '=', $place->getId());
$select->where(['place_in_challenge', 'place_id'], '=', $place->getId());
yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Guess::class);
}
}
+3 -11
View File
@@ -4,20 +4,12 @@ use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place;
use SokoWeb\PersistentData\PersistentDataManager;
class MapRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $mapId): ?Map
{
return $this->pdm->selectFromDbById($mapId, Map::class);
return \Container::$persistentDataManager->selectFromDbById($mapId, Map::class);
}
public function getByPlace(Place $place): ?Map
@@ -30,9 +22,9 @@ class MapRepository
$select = new Select(\Container::$dbConnection);
$select->innerJoin('places', ['maps', 'id'], '=', ['places', 'map_id']);
$select->innerJoin('place_in_challenge', ['places', 'id'], '=', ['place_in_challenge', 'place_id']);
$select->where('challenge_id', '=', $challenge->getId());
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
$select->limit(1);
return $this->pdm->selectFromDb($select, Map::class);
return \Container::$persistentDataManager->selectFromDb($select, Map::class);
}
}
+3 -11
View File
@@ -4,20 +4,12 @@ use DateTime;
use Generator;
use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\MultiRoom;
use SokoWeb\PersistentData\PersistentDataManager;
class MultiRoomRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $id): ?MultiRoom
{
return $this->pdm->selectFromDbById($id, MultiRoom::class);
return \Container::$persistentDataManager->selectFromDbById($id, MultiRoom::class);
}
public function getByRoomId(string $roomId): ?MultiRoom
@@ -25,7 +17,7 @@ class MultiRoomRepository
$select = new Select(\Container::$dbConnection);
$select->where('room_id', '=', $roomId);
return $this->pdm->selectFromDb($select, MultiRoom::class);
return \Container::$persistentDataManager->selectFromDb($select, MultiRoom::class);
}
public function getAllExpired(): Generator
@@ -33,6 +25,6 @@ class MultiRoomRepository
$select = new Select(\Container::$dbConnection);
$select->where('updated', '<', (new DateTime('-7 day'))->format('Y-m-d H:i:s'));
yield from $this->pdm->selectMultipleFromDb($select, MultiRoom::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, MultiRoom::class);
}
}
+4 -12
View File
@@ -5,23 +5,15 @@ use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\PlaceInChallenge;
use SokoWeb\PersistentData\PersistentDataManager;
class PlaceInChallengeRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getAllByPlace(Place $place, array $withRelations = []) : Generator
{
$select = new Select(\Container::$dbConnection);
$select->where('place_id', '=', $place->getId());
yield from $this->pdm->selectMultipleFromDb($select, PlaceInChallenge::class, true, $withRelations);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, PlaceInChallenge::class, true, $withRelations);
}
public function getAllByChallenge(Challenge $challenge) : Generator
@@ -29,7 +21,7 @@ class PlaceInChallengeRepository
$select = new Select(\Container::$dbConnection);
$select->where('challenge_id', '=', $challenge->getId());
yield from $this->pdm->selectMultipleFromDb($select, PlaceInChallenge::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, PlaceInChallenge::class);
}
public function getByPlaceAndChallenge(Place $place, Challenge $challenge) : ?PlaceInChallenge
@@ -38,7 +30,7 @@ class PlaceInChallengeRepository
$select->where('place_id', '=', $place->getId());
$select->where('challenge_id', '=', $challenge->getId());
return $this->pdm->selectFromDb($select, PlaceInChallenge::class);
return \Container::$persistentDataManager->selectFromDb($select, PlaceInChallenge::class);
}
public function getByRoundInChallenge(int $round, Challenge $challenge, array $withRelations = []): ?PlaceInChallenge
@@ -48,6 +40,6 @@ class PlaceInChallengeRepository
$select->orderBy('round');
$select->limit(1, $round);
return $this->pdm->selectFromDb($select, PlaceInChallenge::class, true, $withRelations);
return \Container::$persistentDataManager->selectFromDb($select, PlaceInChallenge::class, true, $withRelations);
}
}
+13 -21
View File
@@ -5,20 +5,12 @@ use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place;
use SokoWeb\PersistentData\PersistentDataManager;
class PlaceRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $placeId): ?Place
{
return $this->pdm->selectFromDbById($placeId, Place::class);
return \Container::$persistentDataManager->selectFromDbById($placeId, Place::class);
}
public function getAllForMap(Map $map): Generator
@@ -26,7 +18,7 @@ class PlaceRepository
$select = new Select(\Container::$dbConnection);
$select->where('map_id', '=', $map->getId());
yield from $this->pdm->selectMultipleFromDb($select, Place::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Place::class);
}
//TODO: use Map and User instead of id
@@ -99,7 +91,7 @@ class PlaceRepository
$select->where('id', 'NOT IN', $exclude);
$select->limit(1, $randomOffset);
return $this->pdm->selectFromDb($select, Place::class);
return \Container::$persistentDataManager->selectFromDb($select, Place::class);
}
// Never visited places
@@ -117,8 +109,8 @@ class PlaceRepository
// count the places never visited
$selectUnvisited = new Select(\Container::$dbConnection, 'places');
$selectUnvisited->leftJoin($selectPlacesByCurrentUser, ['places', 'id'], '=', ['places_by_current_user', 'place_id']);
$selectUnvisited->where('map_id', '=', $mapId);
$selectUnvisited->where('last_time', '=', null);
$selectUnvisited->where(['places', 'map_id'], '=', $mapId);
$selectUnvisited->where(['places_by_current_user', 'last_time'], '=', null);
$numberOfUnvisitedPlaces = $selectUnvisited->count();
// look for as many new places as possible but maximum $n
@@ -148,11 +140,11 @@ class PlaceRepository
// count places that were visited at least once
$selectOldPlaces = new Select(\Container::$dbConnection, 'places');
$selectOldPlaces->innerJoin($selectPlacesByCurrentUser, ['places', 'id'], '=', ['places_by_current_user', 'place_id']);
$selectOldPlaces->where('map_id', '=', $mapId);
$selectOldPlaces->where(['places', 'map_id'], '=', $mapId);
$numberOfOldPlaces = $selectOldPlaces->count();
// set order by datetime, oldest first
$selectOldPlaces->orderBy('last_time');
$selectOldPlaces->orderBy(['places_by_current_user', 'last_time']);
// selection algorithm with preference (weighting) for older places using Box-Muller transform
$pickGaussianRandomInt = function($numberOfPlaces) {
@@ -182,21 +174,21 @@ class PlaceRepository
{
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['places', 'id'], '=', ['place_in_challenge', 'place_id']);
$select->where('challenge_id', '=', $challenge->getId());
$select->orderBy('round');
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
$select->orderBy(['place_in_challenge', 'round']);
$select->limit(1, $round);
return $this->pdm->selectFromDb($select, Place::class);
return \Container::$persistentDataManager->selectFromDb($select, Place::class);
}
public function getAllInChallenge(Challenge $challenge): Generator
{
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['places', 'id'], '=', ['place_in_challenge', 'place_id']);
$select->where('challenge_id', '=', $challenge->getId());
$select->orderBy('round');
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
$select->orderBy(['place_in_challenge', 'round']);
yield from $this->pdm->selectMultipleFromDb($select, Place::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Place::class);
}
}
+3 -11
View File
@@ -3,20 +3,12 @@
use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\UserConfirmation;
use SokoWeb\PersistentData\PersistentDataManager;
class UserConfirmationRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $userConfirmationId): ?UserConfirmation
{
return $this->pdm->selectFromDbById($userConfirmationId, UserConfirmation::class);
return \Container::$persistentDataManager->selectFromDbById($userConfirmationId, UserConfirmation::class);
}
public function getByToken(string $token): ?UserConfirmation
@@ -24,7 +16,7 @@ class UserConfirmationRepository
$select = new Select(\Container::$dbConnection);
$select->where('token', '=', $token);
return $this->pdm->selectFromDb($select, UserConfirmation::class);
return \Container::$persistentDataManager->selectFromDb($select, UserConfirmation::class);
}
public function getByUser(User $user): ?UserConfirmation
@@ -32,6 +24,6 @@ class UserConfirmationRepository
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
return $this->pdm->selectFromDb($select, UserConfirmation::class);
return \Container::$persistentDataManager->selectFromDb($select, UserConfirmation::class);
}
}
+7 -15
View File
@@ -5,23 +5,15 @@ use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\UserInChallenge;
use SokoWeb\PersistentData\PersistentDataManager;
class UserInChallengeRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getAllByUser(User $user) : Generator
{
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
yield from $this->pdm->selectMultipleFromDb($select, UserInChallenge::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserInChallenge::class);
}
public function getAllByChallenge(Challenge $challenge) : Generator
@@ -29,7 +21,7 @@ class UserInChallengeRepository
$select = new Select(\Container::$dbConnection);
$select->where('challenge_id', '=', $challenge->getId());
yield from $this->pdm->selectMultipleFromDb($select, UserInChallenge::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserInChallenge::class);
}
public function getAllByChallengeWithUsers(Challenge $challenge) : Generator
@@ -37,7 +29,7 @@ class UserInChallengeRepository
$select = new Select(\Container::$dbConnection);
$select->where('challenge_id', '=', $challenge->getId());
yield from $this->pdm->selectMultipleFromDb($select, UserInChallenge::class, true, [User::class]);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserInChallenge::class, true, ['user']);
}
public function getByUserIdAndChallenge(int $userId, Challenge $challenge): ?UserInChallenge
@@ -46,13 +38,13 @@ class UserInChallengeRepository
$select->where('user_id', '=', $userId);
$select->where('challenge_id', '=', $challenge->getId());
return $this->pdm->selectFromDb($select, UserInChallenge::class);
return \Container::$persistentDataManager->selectFromDb($select, UserInChallenge::class);
}
public function getByUserIdAndToken(int $userId, string $token_str, array $withRelations = []): ?UserInChallenge
{
if (count($withRelations)) {
$necessaryRelations = [Challenge::class];
$necessaryRelations = ['challange'];
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
}
@@ -65,9 +57,9 @@ class UserInChallengeRepository
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $userId);
$select->where('token', '=', $token);
$select->where(['user_in_challenge__challenge', 'token'], '=', $token);
return $this->pdm->selectFromDb($select, UserInChallenge::class, true, $withRelations);
return \Container::$persistentDataManager->selectFromDb($select, UserInChallenge::class, true, $withRelations);
}
public function isUserParticipatingInChallenge(int $userId, Challenge $challenge): bool
@@ -5,20 +5,12 @@ use Generator;
use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\UserPasswordResetter;
use SokoWeb\PersistentData\PersistentDataManager;
class UserPasswordResetterRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $userConfirmationId): ?UserPasswordResetter
{
return $this->pdm->selectFromDbById($userConfirmationId, UserPasswordResetter::class);
return \Container::$persistentDataManager->selectFromDbById($userConfirmationId, UserPasswordResetter::class);
}
public function getByToken(string $token): ?UserPasswordResetter
@@ -26,7 +18,7 @@ class UserPasswordResetterRepository
$select = new Select(\Container::$dbConnection);
$select->where('token', '=', $token);
return $this->pdm->selectFromDb($select, UserPasswordResetter::class);
return \Container::$persistentDataManager->selectFromDb($select, UserPasswordResetter::class);
}
public function getByUser(User $user): ?UserPasswordResetter
@@ -34,7 +26,7 @@ class UserPasswordResetterRepository
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
return $this->pdm->selectFromDb($select, UserPasswordResetter::class);
return \Container::$persistentDataManager->selectFromDb($select, UserPasswordResetter::class);
}
public function getAllExpired(): Generator
@@ -42,6 +34,6 @@ class UserPasswordResetterRepository
$select = new Select(\Container::$dbConnection);
$select->where('expires', '<', (new DateTime())->format('Y-m-d H:i:s'));
yield from $this->pdm->selectMultipleFromDb($select, UserPasswordResetter::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserPasswordResetter::class);
}
}
+4 -12
View File
@@ -5,23 +5,15 @@ use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\UserPlayedPlace;
use SokoWeb\PersistentData\PersistentDataManager;
class UserPlayedPlaceRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getByUser(User $user): Generator
{
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
yield from $this->pdm->selectMultipleFromDb($select, UserPlayedPlace::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserPlayedPlace::class);
}
public function getAllByPlace(Place $place): Generator
@@ -29,7 +21,7 @@ class UserPlayedPlaceRepository
$select = new Select(\Container::$dbConnection);
$select->where('place_id', '=', $place->getId());
yield from $this->pdm->selectMultipleFromDb($select, UserPlayedPlace::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserPlayedPlace::class);
}
public function getAllByUser(User $user) : Generator
@@ -37,7 +29,7 @@ class UserPlayedPlaceRepository
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
yield from $this->pdm->selectMultipleFromDb($select, UserPlayedPlace::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserPlayedPlace::class);
}
public function getByUserIdAndPlaceId(int $userId, int $placeId) : ?UserPlayedPlace
@@ -46,6 +38,6 @@ class UserPlayedPlaceRepository
$select->where('user_id', '=', $userId);
$select->where('place_id', '=', $placeId);
return $this->pdm->selectFromDb($select, UserPlayedPlace::class);
return \Container::$persistentDataManager->selectFromDb($select, UserPlayedPlace::class);
}
}
+4 -12
View File
@@ -6,20 +6,12 @@ use SokoWeb\Interfaces\Repository\IUserRepository;
use SokoWeb\Database\Query\Select;
use MapGuesser\PersistentData\Model\Guess;
use MapGuesser\PersistentData\Model\User;
use SokoWeb\PersistentData\PersistentDataManager;
class UserRepository implements IUserRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $userId): ?User
{
return $this->pdm->selectFromDbById($userId, User::class);
return \Container::$persistentDataManager->selectFromDbById($userId, User::class);
}
public function getByEmail(string $email): ?User
@@ -27,7 +19,7 @@ class UserRepository implements IUserRepository
$select = new Select(\Container::$dbConnection);
$select->where('email', '=', $email);
return $this->pdm->selectFromDb($select, User::class);
return \Container::$persistentDataManager->selectFromDb($select, User::class);
}
public function getByGoogleSub(string $sub): ?User
@@ -35,7 +27,7 @@ class UserRepository implements IUserRepository
$select = new Select(\Container::$dbConnection);
$select->where('google_sub', '=', $sub);
return $this->pdm->selectFromDb($select, User::class);
return \Container::$persistentDataManager->selectFromDb($select, User::class);
}
public function getAllInactiveExpired(): Generator
@@ -44,7 +36,7 @@ class UserRepository implements IUserRepository
$select->where('active', '=', false);
$select->where('created', '<', (new DateTime('-1 day'))->format('Y-m-d H:i:s'));
yield from $this->pdm->selectMultipleFromDb($select, User::class);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, User::class);
}
public function getByGuess(Guess $guess): ?User
+5 -5
View File
@@ -9,12 +9,12 @@
<?php if ($user['password'] !== null && $user['google_sub'] !== null): ?>
<p class="justify small">Please confirm your identity with your password or with Google to modify your account.</p>
<div class="inputWithButton">
<input type="password" class="text name="password" placeholder="Current password" required minlength="6" autofocus><!--
<input type="password" class="text name="password" placeholder="Current password" autocomplete="current-password" required minlength="6" autofocus><!--
--><button id="authenticateWithGoogleButton" class="yellow" type="button">Google</button>
</div>
<?php elseif ($user['password'] !== null): ?>
<p class="justify small">Please confirm your identity with your password to modify your account.</p>
<input type="password" class="text big fullWidth" name="password" placeholder="Current password" required minlength="6" autofocus>
<input type="password" class="text big fullWidth" name="password" placeholder="Current password" autocomplete="current-password" required minlength="6" autofocus>
<?php elseif ($user['google_sub'] !== null): ?>
<p class="justify small">Please confirm your identity with Google to modify your account.</p>
<div class="inputWithButton">
@@ -24,9 +24,9 @@
<?php endif; ?>
<hr>
<?php /* TODO: disabled for the time being, email modification should be implemented */ ?>
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" value="<?= $user['email'] ?>" disabled>
<input type="password" class="text big fullWidth marginTop" name="password_new" placeholder="New password" minlength="6">
<input type="password" class="text big fullWidth marginTop" name="password_new_confirm" placeholder="New password confirmation" minlength="6">
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" autocomplete="username" value="<?= $user['email'] ?>" disabled>
<input type="password" class="text big fullWidth marginTop" name="password_new" placeholder="New password" autocomplete="new-password" minlength="6">
<input type="password" class="text big fullWidth marginTop" name="password_new_confirm" placeholder="New password confirmation" autocomplete="new-password" minlength="6">
<p id="accountFormError" class="formError justify marginTop"></p>
<div class="right marginTop">
<button type="submit" name="submit" disabled>Save</button>
+3 -2
View File
@@ -7,15 +7,16 @@
<div class="box">
<form id="deleteAccountForm" action="/account/delete" method="post" data-redirect-on-success="/">
<p class="justify marginBottom">Are you sure you want to delete your account? This cannot be undone!</p>
<input type="email" style="display: none;" name="email" autocomplete="username" value="<?= $user['email'] ?>">
<?php if ($user['password'] !== null && $user['google_sub'] !== null): ?>
<p class="justify small">Please confirm your identity with your password or with Google to delete your account.</p>
<div class="inputWithButton">
<input type="password" class="text" name="password" placeholder="Current password" required minlength="6" autofocus><!--
<input type="password" class="text" name="password" placeholder="Current password" autocomplete="current-password" required minlength="6" autofocus><!--
--><button id="authenticateWithGoogleButton" class="yellow" type="button">Google</button>
</div>
<?php elseif ($user['password'] !== null): ?>
<p class="justify small">Please confirm your identity with your password to delete your account.</p>
<input type="password" class="text big fullWidth" name="password" placeholder="Current password" required minlength="6" autofocus>
<input type="password" class="text big fullWidth" name="password" placeholder="Current password" autocomplete="current-password" required minlength="6" autofocus>
<?php elseif ($user['google_sub'] !== null): ?>
<p class="justify small">Please confirm your identity with Google to delete your account.</p>
<div class="inputWithButton">
+11
View File
@@ -0,0 +1,11 @@
@extends(templates/layout_normal)
@section(main)
<h2>500 | Internal server error</h2>
<p>An error occured during processing your request. <a href="<?= Container::$routeCollection->getRoute('index')->generateLink() ?>" title="<?= $_ENV['APP_NAME'] ?>">Back to start.</a></p>
<?php if (isset($exceptionToPrint)): ?>
<pre class="marginTop">
<?= $exceptionToPrint ?>
</pre>
<?php endif; ?>
@endsection
+2 -2
View File
@@ -4,8 +4,8 @@
<h2>Login</h2>
<div class="box">
<form id="loginForm" action="/login" method="post" data-redirect-on-success="<?= $redirectUrl ?>">
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" required autofocus>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password" required minlength="6">
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" autocomplete="username" required autofocus>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password" autocomplete="current-password" required minlength="6">
<p id="loginFormError" class="formError justify marginTop"></p>
<div class="right marginTop">
<button type="submit">Login</button>
+1 -1
View File
@@ -6,7 +6,7 @@
<h2>Request password reset</h2>
<div class="box">
<form id="passwordResetForm" action="/password/requestReset" method="post" data-redirect-on-success="/password/requestReset/success">
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" value="<?= isset($email) ? $email : '' ?>" required autofocus>
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" autocomplete="username" value="<?= isset($email) ? $email : '' ?>" required autofocus>
<?php if (!empty($_ENV['RECAPTCHA_SITEKEY'])): ?>
<div class="marginTop">
<div class="g-recaptcha" data-sitekey="<?= $_ENV['RECAPTCHA_SITEKEY'] ?>"></div>
+3 -3
View File
@@ -5,9 +5,9 @@
<div class="box">
<?php if ($success) : ?>
<form id="resetPasswordForm" action="/password/reset/<?= $token ?>" method="post" data-redirect-on-success="<?= $redirectUrl ?>">
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" value="<?= $email ?>" disabled>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password" required minlength="6" autofocus>
<input type="password" class="text big fullWidth marginTop" name="password_confirm" placeholder="Password confirmation" required minlength="6">
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" autocomplete="username" value="<?= $email ?>" disabled>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password" autocomplete="new-password" required minlength="6" autofocus>
<input type="password" class="text big fullWidth marginTop" name="password_confirm" placeholder="Password confirmation" autocomplete="new-password" required minlength="6">
<p id="resetPasswordFormError" class="formError justify marginTop"></p>
<div class="right">
<button class="marginTop" type="submit">Reset password</button>
+5 -5
View File
@@ -9,12 +9,12 @@
<form id="signupForm" action="/signup" method="post" data-redirect-on-success="/signup/success">
<?php if (isset($email)): ?>
<p class="justify">No user found with the given email address. Sign up with one click!</p>
<input type="email" class="text big fullWidth marginTop" name="email" placeholder="Email address" value="<?= $email ?>" required>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password confirmation" required minlength="6" autofocus>
<input type="email" class="text big fullWidth marginTop" name="email" placeholder="Email address" autocomplete="username" value="<?= $email ?>" required>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password confirmation" autocomplete="new-password" required minlength="6" autofocus>
<?php else: ?>
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" required autofocus>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password" required minlength="6">
<input type="password" class="text big fullWidth marginTop" name="password_confirm" placeholder="Password confirmation" minlength="6">
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" autocomplete="username" required autofocus>
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password" autocomplete="new-password" required minlength="6">
<input type="password" class="text big fullWidth marginTop" name="password_confirm" placeholder="Password confirmation" autocomplete="new-password" minlength="6">
<?php endif; ?>
<?php if (!empty($_ENV['RECAPTCHA_SITEKEY'])): ?>
<div class="marginTop">
+11 -14
View File
@@ -4,6 +4,7 @@ use SokoWeb\Response\HttpResponse;
use SokoWeb\Routing\RouteCollection;
use SokoWeb\Session\DatabaseSessionHandler;
use SokoWeb\Request\Request;
use SokoWeb\Request\Session;
use MapGuesser\Controller\MapsController;
use MapGuesser\Controller\HomeController;
use MapGuesser\Controller\LoginController;
@@ -90,27 +91,21 @@ Container::$routeCollection->group('admin', function (RouteCollection $routeColl
});
if (isset($_COOKIE['COOKIES_CONSENT'])) {
Container::$sessionHandler = new DatabaseSessionHandler();
Container::$sessionHandler = new DatabaseSessionHandler(
Container::$dbConnection,
'sessions',
new DateTime('-7 days')
);
session_set_save_handler(Container::$sessionHandler, true);
session_start([
'gc_probability' => 0, // old sessions are deleted by MaintainDatabaseCommand
'cookie_lifetime' => 604800,
'cookie_lifetime' => 0,
'cookie_path' => '/',
'cookie_httponly' => true,
'cookie_samesite' => 'Lax'
]);
if (isset($_COOKIE[session_name()])) {
// extend session cookie lifetime is cookie already exists
setcookie(session_name(), session_id(), [
'expires' => time() + 604800,
'path' => '/',
'httponly' => true,
'samesite' => 'Lax'
]);
}
// this is needed to handle old type of session IDs
if (!Container::$sessionHandler->validateId(session_id())) {
session_regenerate_id(true);
@@ -124,7 +119,7 @@ Container::$request = new Request(
$_GET,
$_POST,
getallheaders(),
$_SESSION,
new Session($_SESSION),
new UserRepository()
);
@@ -137,11 +132,13 @@ $appConfig = [
'antiCsrfTokenErrorResponse' => ['error' => 'no_valid_anti_csrf_token'],
'antiCsrfTokenExceptions' => [],
'loginRouteId' => 'login',
'error404View' => 'error/404'
'error404View' => 'error/404',
'error500View' => 'error/500'
];
$httpReponse = new HttpResponse(
Container::$request,
Container::$dbConnection,
Container::$routeCollection,
$appConfig,
$_SERVER['REQUEST_METHOD'],