Compare commits
99 Commits
Release_23
...
develop
Author | SHA1 | Date | |
---|---|---|---|
9b2ffa8b2c | |||
9bafc52626 | |||
18ddaa1da4 | |||
be2105a284 | |||
5481cc67a0 | |||
a547fbb631 | |||
0e3f943f1e | |||
ec42479304 | |||
dbb7c1c0fc | |||
410bba4966 | |||
17aee22400 | |||
aaf220dce2 | |||
276a289ca7 | |||
e684365612 | |||
105cc96963 | |||
bdd62aadf5 | |||
390c13608a | |||
345cf31bb3 | |||
c7f5ea0d85 | |||
fc6141e2b9 | |||
5049a01d2a | |||
45d0c9fa80 | |||
1e4b982430 | |||
0a7d248a3e | |||
2177dfd893 | |||
173b50fa6c | |||
d7338b84d3 | |||
0216861579 | |||
7be04f128a | |||
c4dd60e0de | |||
752ea12810 | |||
751a86c823 | |||
52873fc759 | |||
0882a67019 | |||
49069f4a52 | |||
4bba7599e1 | |||
7fb75c9f25 | |||
5d367d5b35 | |||
a2d6376e81 | |||
f3c3aa69eb | |||
467399c81b | |||
84e848506f | |||
e18ed3a034 | |||
ea8b46ab91 | |||
a1b0f5e9fb | |||
b1ed28f4b5 | |||
36f4b6b4d0 | |||
2c706cc7f3 | |||
77c6e6c4e6 | |||
c25ba2dd28 | |||
5b045335a1 | |||
703966f8f7 | |||
76570a76c5 | |||
383bb9d4fb | |||
716494f614 | |||
7c61491653 | |||
7a1da55ceb | |||
cb5e90c0f7 | |||
32e9fc2cb0 | |||
c180d7a012 | |||
fea4211930 | |||
4f6e18f83a | |||
57a24f8c90 | |||
f5950658df | |||
cd17f44de0 | |||
a11a879a4f | |||
0048fb9b1d | |||
cede0e7985 | |||
80501b7f0a | |||
a255180a4d | |||
af09da8782 | |||
ddfea0530d | |||
9d7d19899d | |||
10f032a9a5 | |||
c02e35580f | |||
afd58bb91b | |||
fc6792ccfc | |||
a5ba8e71e4 | |||
184f63585c | |||
d666593fde | |||
75fad05362 | |||
45b34cb514 | |||
a6ba53764b | |||
e70f8a9965 | |||
4aadcab2d2 | |||
9aea195f85 | |||
eafcf2315e | |||
e52300b9e5 | |||
ee4a9f2ce3 | |||
8141845ae9 | |||
69f54c861a | |||
c9ab7c31b7 | |||
82279f11d3 | |||
6cb4e06acc | |||
ee33fc1913 | |||
4fb1831763 | |||
9dee8ba988 | |||
82562117b2 | |||
317a4de5c0 |
54
Jenkinsfile
vendored
54
Jenkinsfile
vendored
@ -13,8 +13,9 @@ pipeline {
|
|||||||
}
|
}
|
||||||
agent {
|
agent {
|
||||||
dockerfile {
|
dockerfile {
|
||||||
filename 'docker/Dockerfile-test'
|
filename 'docker/Dockerfile'
|
||||||
dir '.'
|
dir '.'
|
||||||
|
additionalBuildArgs '--target mapg_base'
|
||||||
reuseNode true
|
reuseNode true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,8 +27,9 @@ pipeline {
|
|||||||
stage('Unit Testing') {
|
stage('Unit Testing') {
|
||||||
agent {
|
agent {
|
||||||
dockerfile {
|
dockerfile {
|
||||||
filename 'docker/Dockerfile-test'
|
filename 'docker/Dockerfile'
|
||||||
dir '.'
|
dir '.'
|
||||||
|
additionalBuildArgs '--target mapg_base'
|
||||||
reuseNode true
|
reuseNode true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,7 +37,7 @@ pipeline {
|
|||||||
sh 'vendor/bin/phpunit --log-junit unit_test_results.xml --testdox tests'
|
sh 'vendor/bin/phpunit --log-junit unit_test_results.xml --testdox tests'
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
success {
|
always {
|
||||||
archiveArtifacts 'unit_test_results.xml'
|
archiveArtifacts 'unit_test_results.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,8 +46,9 @@ pipeline {
|
|||||||
stage('Static Code Analysis') {
|
stage('Static Code Analysis') {
|
||||||
agent {
|
agent {
|
||||||
dockerfile {
|
dockerfile {
|
||||||
filename 'docker/Dockerfile-test'
|
filename 'docker/Dockerfile'
|
||||||
dir '.'
|
dir '.'
|
||||||
|
additionalBuildArgs '--target mapg_base'
|
||||||
reuseNode true
|
reuseNode true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,10 +56,51 @@ pipeline {
|
|||||||
sh 'php -d memory_limit=1G vendor/bin/phpstan analyse -c phpstan.neon --error-format=prettyJson > static_code_analysis_results.json'
|
sh 'php -d memory_limit=1G vendor/bin/phpstan analyse -c phpstan.neon --error-format=prettyJson > static_code_analysis_results.json'
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
success {
|
always {
|
||||||
archiveArtifacts 'static_code_analysis_results.json'
|
archiveArtifacts 'static_code_analysis_results.json'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stage('Prepare Docker release') {
|
||||||
|
environment {
|
||||||
|
COMPOSER_HOME="${WORKSPACE}/.composer"
|
||||||
|
npm_config_cache="${WORKSPACE}/.npm"
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
filename 'docker/Dockerfile'
|
||||||
|
dir '.'
|
||||||
|
additionalBuildArgs '--target mapg_base'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh script: 'git clean -ffdx', label: 'Clean repository'
|
||||||
|
env.VERSION = sh(script: 'git describe --tags --always --match "Release_*" HEAD', returnStdout: true).trim()
|
||||||
|
sh script: 'docker/scripts/release.sh', label: 'Release script'
|
||||||
|
sh script: "rm -rf ${env.COMPOSER_HOME} ${env.npm_config_cache}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Release Docker image') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
withDockerRegistry([credentialsId: 'gitea-system-user', url: 'https://git.esoko.eu/']) {
|
||||||
|
sh script: 'docker buildx create --use --bootstrap --platform=linux/arm64,linux/amd64 --name multi-platform-builder'
|
||||||
|
sh script: """docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
-f docker/Dockerfile \
|
||||||
|
--target mapg_release \
|
||||||
|
-t git.esoko.eu/esoko/mapguesser:${env.VERSION} \
|
||||||
|
--push \
|
||||||
|
.""",
|
||||||
|
label: 'Build Docker image'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
111
README.md
111
README.md
@ -1,58 +1,16 @@
|
|||||||
# MapGuesser
|
# MapGuesser
|
||||||
|
|
||||||
[![Build Status](https://jenkins.e5tv.hu/job/mapguesser/job/develop/badge/icon)](https://jenkins.e5tv.hu/job/mapguesser/job/develop/)
|
[![Build Status](https://ci.esoko.eu/job/mapguesser/job/develop/badge/icon)](https://ci.esoko.eu/job/mapguesser/job/develop/)
|
||||||
|
|
||||||
This is the MapGuesser Application project. This is a game about guessing where you are based on a street view panorama - inspired by existing applications.
|
This is the MapGuesser Application project. This is a game about guessing where you are based on a street view panorama - inspired by existing applications.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### 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
|
### 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.
|
**Important: `DEV` should NOT be set for production! See section Development if you want to use the application in development 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.
|
|
||||||
|
|
||||||
#### API keys
|
#### API keys
|
||||||
|
|
||||||
@ -75,31 +33,72 @@ LEAFLET_TILESERVER_SUBDOMAINS=abc
|
|||||||
LEAFLET_TILESERVER_ATTRIBUTION="© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
|
LEAFLET_TILESERVER_ATTRIBUTION="© <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:
|
**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:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/install.sh
|
./mapg user:add EMAIL USERNAME PASSWORD admin
|
||||||
```
|
```
|
||||||
|
|
||||||
**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.**
|
## Development
|
||||||
|
|
||||||
**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:
|
### 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!**
|
||||||
./mapg user:add EMAIL PASSWORD admin
|
|
||||||
|
### Docker Compose
|
||||||
|
|
||||||
|
Execute the following command from the repo root:
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
**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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -10,11 +10,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"esoko/soko-web": "0.3",
|
"esoko/soko-web": "0.15"
|
||||||
"fzaninotto/faker": "^1.9"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9.6",
|
"phpunit/phpunit": "^10.3",
|
||||||
"phpstan/phpstan": "^1.10"
|
"phpstan/phpstan": "^1.10"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
1060
composer.lock
generated
1060
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,14 @@ CREATE TABLE `maps` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) 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`;
|
DROP TABLE IF EXISTS `places`;
|
||||||
CREATE TABLE `places` (
|
CREATE TABLE `places` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<?php //empty on purpose
|
|
20
database/migrations/data/20230923_1905_username.php
Normal file
20
database/migrations/data/20230923_1905_username.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use MapGuesser\PersistentData\Model\User;
|
||||||
|
use MapGuesser\Repository\UserRepository;
|
||||||
|
use MapGuesser\Util\UsernameGenerator;
|
||||||
|
use SokoWeb\Database\Query\Select;
|
||||||
|
|
||||||
|
$select = new Select(Container::$dbConnection);
|
||||||
|
$users = Container::$persistentDataManager->selectMultipleFromDb($select, User::class);
|
||||||
|
$userRepository = new UserRepository();
|
||||||
|
$usernameGenerator = new UsernameGenerator();
|
||||||
|
|
||||||
|
foreach ($users as $user) {
|
||||||
|
do {
|
||||||
|
$username = $usernameGenerator->generate();
|
||||||
|
} while ($userRepository->getByUsername($username));
|
||||||
|
|
||||||
|
$user->setUsername($username);
|
||||||
|
Container::$persistentDataManager->saveToDb($user);
|
||||||
|
}
|
@ -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;
|
|
3
database/migrations/structure/20230923_1905_username.sql
Normal file
3
database/migrations/structure/20230923_1905_username.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE `users`
|
||||||
|
ADD `username` VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL AFTER `email`,
|
||||||
|
ADD UNIQUE `username` (`username`);
|
@ -2,22 +2,20 @@ version: '3'
|
|||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
build:
|
build:
|
||||||
context: ./docker
|
context: .
|
||||||
dockerfile: Dockerfile-app
|
dockerfile: docker/Dockerfile
|
||||||
|
target: mapg_dev
|
||||||
|
depends_on:
|
||||||
|
mariadb:
|
||||||
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
volumes:
|
|
||||||
- .:/var/www/mapguesser
|
|
||||||
multi:
|
|
||||||
build:
|
|
||||||
context: ./docker
|
|
||||||
dockerfile: Dockerfile-multi
|
|
||||||
ports:
|
|
||||||
- 5000:5000
|
- 5000:5000
|
||||||
- 8090:8090
|
- 8090:8090
|
||||||
- 9229:9229
|
- 9229:9229
|
||||||
volumes:
|
volumes:
|
||||||
- .:/var/www/mapguesser
|
- .:/var/www/mapguesser
|
||||||
|
working_dir: /var/www/mapguesser
|
||||||
mariadb:
|
mariadb:
|
||||||
image: mariadb:10.3
|
image: mariadb:10.3
|
||||||
ports:
|
ports:
|
||||||
@ -29,6 +27,13 @@ services:
|
|||||||
MYSQL_DATABASE: 'mapguesser'
|
MYSQL_DATABASE: 'mapguesser'
|
||||||
MYSQL_USER: 'mapguesser'
|
MYSQL_USER: 'mapguesser'
|
||||||
MYSQL_PASSWORD: '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:
|
adminer:
|
||||||
image: adminer:4.8.1-standalone
|
image: adminer:4.8.1-standalone
|
||||||
ports:
|
ports:
|
||||||
|
44
docker/Dockerfile
Normal file
44
docker/Dockerfile
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
FROM ubuntu:22.04 AS mapg_base
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
|
||||||
|
RUN apt update --fix-missing && apt install -y sudo curl git unzip mariadb-client nginx \
|
||||||
|
php-apcu php8.1-cli php8.1-curl php8.1-fpm php8.1-mbstring php8.1-mysql php8.1-zip php8.1-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/8.1/mods-available/xdebug.ini &&\
|
||||||
|
echo "xdebug.remote_autostart = 1" >> /etc/php/8.1/mods-available/xdebug.ini &&\
|
||||||
|
echo "xdebug.remote_connect_back = 1" >> /etc/php/8.1/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 rm -rf /var/www/mapguesser/.git
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
EXPOSE 8090
|
||||||
|
ENTRYPOINT docker/scripts/entry-point.sh
|
@ -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;'
|
|
@ -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
|
|
@ -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
|
|
@ -1,11 +1,15 @@
|
|||||||
|
map $http_x_forwarded_proto $forwarded_scheme {
|
||||||
|
default $scheme;
|
||||||
|
http http;
|
||||||
|
https https;
|
||||||
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80 default_server;
|
listen 80 default_server;
|
||||||
listen [::]:80 default_server;
|
listen [::]:80 default_server;
|
||||||
|
|
||||||
root /var/www/mapguesser/public;
|
root /var/www/mapguesser/public;
|
||||||
|
|
||||||
index index.php index.html index.htm index.nginx-debian.html;
|
index index.php index.html index.htm index.nginx-debian.html;
|
||||||
|
|
||||||
server_name mapguesser-dev.ch;
|
server_name mapguesser-dev.ch;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
@ -14,7 +18,8 @@ server {
|
|||||||
|
|
||||||
location ~ \.php$ {
|
location ~ \.php$ {
|
||||||
include snippets/fastcgi-php.conf;
|
include snippets/fastcgi-php.conf;
|
||||||
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
|
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
|
||||||
|
fastcgi_param REQUEST_SCHEME $forwarded_scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ /\.ht {
|
location ~ /\.ht {
|
||||||
|
1
docker/scripts/cron
Normal file
1
docker/scripts/cron
Normal file
@ -0,0 +1 @@
|
|||||||
|
0 * * * * /var/www/mapguesser/mapg db:maintain
|
40
docker/scripts/entry-point-dev.sh
Executable file
40
docker/scripts/entry-point-dev.sh
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
echo "Set runner user based on owner of .env..."
|
||||||
|
if ! getent group mapg; then
|
||||||
|
USER_GID=$(stat -c "%g" .env)
|
||||||
|
groupadd --gid $USER_GID mapg
|
||||||
|
fi
|
||||||
|
if ! id -u mapg; then
|
||||||
|
USER_UID=$(stat -c "%u" .env)
|
||||||
|
useradd --uid $USER_UID --gid $USER_GID mapg
|
||||||
|
fi
|
||||||
|
sed -i -e "s/^user = .*$/user = mapg/g" -e "s/^group = .*$/group = mapg/g" /etc/php/8.1/fpm/pool.d/www.conf
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
|
/usr/sbin/php-fpm8.1 -F &
|
||||||
|
/usr/sbin/nginx -g 'daemon off;' &
|
||||||
|
sudo -u mapg -g mapg /usr/bin/node --inspect=0.0.0.0:9229 multi &
|
||||||
|
|
||||||
|
wait -n
|
||||||
|
|
||||||
|
exit $?
|
32
docker/scripts/entry-point.sh
Executable file
32
docker/scripts/entry-point.sh
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Migrating DB..."
|
||||||
|
./mapg db:migrate
|
||||||
|
|
||||||
|
echo "Installing crontab..."
|
||||||
|
/usr/bin/crontab docker/scripts/cron
|
||||||
|
|
||||||
|
echo "Set runner user based on owner of .env..."
|
||||||
|
if ! getent group mapg; then
|
||||||
|
USER_GID=$(stat -c "%g" .env)
|
||||||
|
groupadd --gid $USER_GID mapg
|
||||||
|
fi
|
||||||
|
if ! id -u mapg; then
|
||||||
|
USER_UID=$(stat -c "%u" .env)
|
||||||
|
useradd --uid $USER_UID --gid $USER_GID mapg
|
||||||
|
fi
|
||||||
|
chown mapg:mapg cache
|
||||||
|
sed -i -e "s/^user = .*$/user = mapg/g" -e "s/^group = .*$/group = mapg/g" /etc/php/8.1/fpm/pool.d/www.conf
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
|
/usr/sbin/cron -f &
|
||||||
|
/usr/sbin/php-fpm8.1 -F &
|
||||||
|
/usr/sbin/nginx -g 'daemon off;' &
|
||||||
|
sudo -u mapg -g mapg /usr/bin/node multi &
|
||||||
|
|
||||||
|
wait -n
|
||||||
|
|
||||||
|
exit $?
|
14
docker/scripts/install-nodejs.sh
Executable file
14
docker/scripts/install-nodejs.sh
Executable 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
docker/scripts/release.sh
Executable file
30
docker/scripts/release.sh
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
rm .env
|
4
main.php
4
main.php
@ -15,9 +15,11 @@ $dotenv->load();
|
|||||||
class Container
|
class Container
|
||||||
{
|
{
|
||||||
static SokoWeb\Interfaces\Database\IConnection $dbConnection;
|
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\Session\ISessionHandler $sessionHandler;
|
||||||
static SokoWeb\Interfaces\Request\IRequest $request;
|
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::$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);
|
||||||
|
36
multi/package-lock.json
generated
36
multi/package-lock.json
generated
@ -1,17 +1,43 @@
|
|||||||
{
|
{
|
||||||
"name": "mapguesser-multi",
|
"name": "mapguesser-multi",
|
||||||
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"lockfileVersion": 1,
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "mapguesser-multi",
|
||||||
|
"license": "GNU AGPL 3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": {
|
"dotenv": "^8.2.0",
|
||||||
|
"ws": "^7.4.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
"version": "8.2.0",
|
"version": "8.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ws": {
|
"node_modules/ws": {
|
||||||
"version": "7.4.4",
|
"version": "7.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
|
||||||
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
|
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": "^5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,66 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use SokoWeb\Interfaces\Response\IRedirect;
|
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
|
||||||
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
|
||||||
use SokoWeb\Interfaces\Authorization\ISecured;
|
|
||||||
use SokoWeb\Response\Redirect;
|
|
||||||
use SokoWeb\Response\HtmlContent;
|
|
||||||
use SokoWeb\Response\JsonContent;
|
|
||||||
|
|
||||||
require '../web.php';
|
require '../web.php';
|
||||||
|
|
||||||
$method = strtolower($_SERVER['REQUEST_METHOD']);
|
|
||||||
$url = substr($_SERVER['REQUEST_URI'], strlen('/'));
|
|
||||||
if (($pos = strpos($url, '?')) !== false) {
|
|
||||||
$url = substr($url, 0, $pos);
|
|
||||||
}
|
|
||||||
$url = rawurldecode($url);
|
|
||||||
|
|
||||||
$match = Container::$routeCollection->match($method, $url == '' ? [] : explode('/', $url));
|
|
||||||
|
|
||||||
if ($match !== null) {
|
|
||||||
list($route, $params) = $match;
|
|
||||||
|
|
||||||
Container::$request->setParsedRouteParams($params);
|
|
||||||
|
|
||||||
$handler = $route->getHandler();
|
|
||||||
$controller = new $handler[0](Container::$request);
|
|
||||||
|
|
||||||
if (
|
|
||||||
$controller instanceof IAuthenticationRequired &&
|
|
||||||
$controller->isAuthenticationRequired() &&
|
|
||||||
Container::$request->user() === null
|
|
||||||
) {
|
|
||||||
Container::$request->session()->set('redirect_after_login', substr($_SERVER['REQUEST_URI'], strlen('/')));
|
|
||||||
$response = new Redirect(Container::$routeCollection->getRoute('login')->generateLink(), IRedirect::TEMPORARY);
|
|
||||||
header('Location: ' . $response->getUrl(), true, $response->getHttpCode());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($method === 'post' && Container::$request->post('anti_csrf_token') !== Container::$request->session()->get('anti_csrf_token')) {
|
|
||||||
$content = new JsonContent(['error' => 'no_valid_anti_csrf_token']);
|
|
||||||
header('Content-Type: text/html; charset=UTF-8', true, 403);
|
|
||||||
$content->render();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!($controller instanceof ISecured) ||
|
|
||||||
$controller->authorize()
|
|
||||||
) {
|
|
||||||
$response = call_user_func([$controller, $handler[1]]);
|
|
||||||
if ($response instanceof IContent) {
|
|
||||||
header('Content-Type: ' . $response->getContentType() . '; charset=UTF-8');
|
|
||||||
$response->render();
|
|
||||||
return;
|
|
||||||
} elseif ($response instanceof IRedirect) {
|
|
||||||
header('Location: ' . $response->getUrl(), true, $response->getHttpCode());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = new HtmlContent('error/404');
|
|
||||||
header('Content-Type: text/html; charset=UTF-8', true, 404);
|
|
||||||
$content->render();
|
|
||||||
|
@ -376,7 +376,7 @@ header>p>span {
|
|||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header>p>span>a:link, header>p>span>a:visited {
|
header>p>span>a:link, header>p>span>a:visited, footer>p>a:link, footer>p>a:visited {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,17 +231,6 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
|||||||
|
|
||||||
prepare: function () {
|
prepare: function () {
|
||||||
var data = new FormData();
|
var data = new FormData();
|
||||||
var userNames;
|
|
||||||
|
|
||||||
if (roomId) {
|
|
||||||
var userNames = localStorage.userNames ? JSON.parse(localStorage.userNames) : {};
|
|
||||||
if (!userNames.hasOwnProperty(roomId)) {
|
|
||||||
userNames[roomId] = prompt('Your name: ');
|
|
||||||
localStorage.userNames = JSON.stringify(userNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.append('userName', userNames[roomId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
var url = Game.getGameIdentifier() + '/prepare.json';
|
var url = Game.getGameIdentifier() + '/prepare.json';
|
||||||
@ -618,7 +607,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'anonymous_user':
|
case 'anonymous_user':
|
||||||
MapGuesser.showModalWithContent('Error', 'You have to login to join a challenge!');
|
MapGuesser.showModalWithContent('Error', 'You have to login to join this game!');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -89,6 +89,9 @@ var MapGuesser = {
|
|||||||
|
|
||||||
formError.style.display = 'block';
|
formError.style.display = 'block';
|
||||||
formError.innerHTML = this.response.error.errorText;
|
formError.innerHTML = this.response.error.errorText;
|
||||||
|
if (typeof grecaptcha !== 'undefined') {
|
||||||
|
grecaptcha.reset();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -183,12 +186,23 @@ var MapGuesser = {
|
|||||||
document.getElementById('cover').style.visibility = 'hidden';
|
document.getElementById('cover').style.visibility = 'hidden';
|
||||||
},
|
},
|
||||||
|
|
||||||
observeInput: function (input, buttonToToggle) {
|
observeInput: function (form, observedInputs) {
|
||||||
if (input.defaultValue !== input.value) {
|
var anyChanged = false;
|
||||||
buttonToToggle.disabled = false;
|
|
||||||
} else {
|
for (var i = 0; i < observedInputs.length; i++) {
|
||||||
buttonToToggle.disabled = true;
|
var input = form.elements[observedInputs[i]];
|
||||||
|
if (input.type === 'checkbox') {
|
||||||
|
if (input.defaultChecked !== input.checked) {
|
||||||
|
anyChanged = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (input.defaultValue !== input.value) {
|
||||||
|
anyChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.elements['submit_button'].disabled = !anyChanged;
|
||||||
},
|
},
|
||||||
|
|
||||||
observeInputsInForm: function (form, observedInputs) {
|
observeInputsInForm: function (form, observedInputs) {
|
||||||
@ -199,19 +213,19 @@ var MapGuesser = {
|
|||||||
case 'INPUT':
|
case 'INPUT':
|
||||||
case 'TEXTAREA':
|
case 'TEXTAREA':
|
||||||
input.oninput = function () {
|
input.oninput = function () {
|
||||||
MapGuesser.observeInput(this, form.elements.submit);
|
MapGuesser.observeInput(form, observedInputs);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 'SELECT':
|
case 'SELECT':
|
||||||
input.onchange = function () {
|
input.onchange = function () {
|
||||||
MapGuesser.observeInput(this, form.elements.submit);
|
MapGuesser.observeInput(form, observedInputs);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
form.onreset = function () {
|
form.onreset = function () {
|
||||||
form.elements.submit.disabled = true;
|
form.elements['submit_button'].disabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -131,12 +131,14 @@
|
|||||||
}, formData);
|
}, formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (document.getElementById('multiButton')) {
|
||||||
document.getElementById('multiButton').onclick = function () {
|
document.getElementById('multiButton').onclick = function () {
|
||||||
MapGuesser.showModal('multi');
|
MapGuesser.showModal('multi');
|
||||||
document.getElementById('createNewRoomButton').href = '/multiGame/new/' + this.dataset.mapId;
|
document.getElementById('createNewRoomButton').href = '/multiGame/new/' + this.dataset.mapId;
|
||||||
document.getElementById('multiForm').elements.roomId.select();
|
document.getElementById('multiForm').elements.roomId.select();
|
||||||
document.getElementById('playMode').style.visibility = 'hidden';
|
document.getElementById('playMode').style.visibility = 'hidden';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (document.getElementById('challengeButton')) {
|
if (document.getElementById('challengeButton')) {
|
||||||
document.getElementById('challengeButton').onclick = function () {
|
document.getElementById('challengeButton').onclick = function () {
|
||||||
|
@ -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("----------------------------------------------")
|
|
@ -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
|
|
@ -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 {} \;
|
|
@ -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
|
|
@ -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,7 +1,6 @@
|
|||||||
<?php namespace MapGuesser\Cli;
|
<?php namespace MapGuesser\Cli;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
@ -15,6 +14,7 @@ class AddUserCommand extends Command
|
|||||||
$this->setName('user:add')
|
$this->setName('user:add')
|
||||||
->setDescription('Adding of user.')
|
->setDescription('Adding of user.')
|
||||||
->addArgument('email', InputArgument::REQUIRED, 'Email of user')
|
->addArgument('email', InputArgument::REQUIRED, 'Email of user')
|
||||||
|
->addArgument('username', InputArgument::REQUIRED, 'Username of user')
|
||||||
->addArgument('password', InputArgument::REQUIRED, 'Password of user')
|
->addArgument('password', InputArgument::REQUIRED, 'Password of user')
|
||||||
->addArgument('type', InputArgument::OPTIONAL, 'Type of user');;
|
->addArgument('type', InputArgument::OPTIONAL, 'Type of user');;
|
||||||
}
|
}
|
||||||
@ -23,6 +23,7 @@ class AddUserCommand extends Command
|
|||||||
{
|
{
|
||||||
$user = new User();
|
$user = new User();
|
||||||
$user->setEmail($input->getArgument('email'));
|
$user->setEmail($input->getArgument('email'));
|
||||||
|
$user->setUsername($input->getArgument('username'));
|
||||||
$user->setPlainPassword($input->getArgument('password'));
|
$user->setPlainPassword($input->getArgument('password'));
|
||||||
$user->setActive(true);
|
$user->setActive(true);
|
||||||
$user->setCreatedDate(new DateTime());
|
$user->setCreatedDate(new DateTime());
|
||||||
@ -32,8 +33,7 @@ class AddUserCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$pdm = new PersistentDataManager();
|
\Container::$persistentDataManager->saveToDb($user);
|
||||||
$pdm->saveToDb($user);
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$output->writeln('<error>Adding user failed!</error>');
|
$output->writeln('<error>Adding user failed!</error>');
|
||||||
$output->writeln('');
|
$output->writeln('');
|
||||||
|
@ -4,7 +4,6 @@ use DateTime;
|
|||||||
use SokoWeb\Database\Query\Modify;
|
use SokoWeb\Database\Query\Modify;
|
||||||
use SokoWeb\Database\Query\Select;
|
use SokoWeb\Database\Query\Select;
|
||||||
use SokoWeb\Interfaces\Database\IResultSet;
|
use SokoWeb\Interfaces\Database\IResultSet;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\Repository\MultiRoomRepository;
|
use MapGuesser\Repository\MultiRoomRepository;
|
||||||
use MapGuesser\Repository\UserConfirmationRepository;
|
use MapGuesser\Repository\UserConfirmationRepository;
|
||||||
use MapGuesser\Repository\UserPasswordResetterRepository;
|
use MapGuesser\Repository\UserPasswordResetterRepository;
|
||||||
@ -16,8 +15,6 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
|
|
||||||
class MaintainDatabaseCommand extends Command
|
class MaintainDatabaseCommand extends Command
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private UserRepository $userRepository;
|
private UserRepository $userRepository;
|
||||||
|
|
||||||
private UserConfirmationRepository $userConfirmationRepository;
|
private UserConfirmationRepository $userConfirmationRepository;
|
||||||
@ -32,7 +29,6 @@ class MaintainDatabaseCommand extends Command
|
|||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->userRepository = new UserRepository();
|
$this->userRepository = new UserRepository();
|
||||||
$this->userConfirmationRepository = new UserConfirmationRepository();
|
$this->userConfirmationRepository = new UserConfirmationRepository();
|
||||||
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
||||||
@ -77,19 +73,19 @@ class MaintainDatabaseCommand extends Command
|
|||||||
//TODO: these can be in some wrapper class
|
//TODO: these can be in some wrapper class
|
||||||
$userConfirmation = $this->userConfirmationRepository->getByUser($user);
|
$userConfirmation = $this->userConfirmationRepository->getByUser($user);
|
||||||
if ($userConfirmation !== null) {
|
if ($userConfirmation !== null) {
|
||||||
$this->pdm->deleteFromDb($userConfirmation);
|
\Container::$persistentDataManager->deleteFromDb($userConfirmation);
|
||||||
}
|
}
|
||||||
|
|
||||||
$userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user);
|
$userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user);
|
||||||
if ($userPasswordResetter !== null) {
|
if ($userPasswordResetter !== null) {
|
||||||
$this->pdm->deleteFromDb($userPasswordResetter);
|
\Container::$persistentDataManager->deleteFromDb($userPasswordResetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->userPlayedPlaceRepository->getAllByUser($user) as $userPlayedPlace) {
|
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();
|
\Container::$dbConnection->commit();
|
||||||
@ -98,14 +94,14 @@ class MaintainDatabaseCommand extends Command
|
|||||||
private function deleteExpiredPasswordResetters(): void
|
private function deleteExpiredPasswordResetters(): void
|
||||||
{
|
{
|
||||||
foreach ($this->userPasswordResetterRepository->getAllExpired() as $passwordResetter) {
|
foreach ($this->userPasswordResetterRepository->getAllExpired() as $passwordResetter) {
|
||||||
$this->pdm->deleteFromDb($passwordResetter);
|
\Container::$persistentDataManager->deleteFromDb($passwordResetter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function deleteExpiredRooms(): void
|
private function deleteExpiredRooms(): void
|
||||||
{
|
{
|
||||||
foreach ($this->multiRoomRepository->getAllExpired() as $multiRoom) {
|
foreach ($this->multiRoomRepository->getAllExpired() as $multiRoom) {
|
||||||
$this->pdm->deleteFromDb($multiRoom);
|
\Container::$persistentDataManager->deleteFromDb($multiRoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ class MigrateDatabaseCommand extends Command
|
|||||||
{
|
{
|
||||||
$db = \Container::$dbConnection;
|
$db = \Container::$dbConnection;
|
||||||
|
|
||||||
|
$this->createBaseDb();
|
||||||
|
|
||||||
$db->startTransaction();
|
$db->startTransaction();
|
||||||
|
|
||||||
$success = [];
|
$success = [];
|
||||||
@ -62,10 +64,8 @@ class MigrateDatabaseCommand extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function readDir(string $type): array
|
private function createBaseDb()
|
||||||
{
|
{
|
||||||
$done = [];
|
|
||||||
|
|
||||||
$migrationTableExists = \Container::$dbConnection->query('SELECT count(*)
|
$migrationTableExists = \Container::$dbConnection->query('SELECT count(*)
|
||||||
FROM information_schema.tables
|
FROM information_schema.tables
|
||||||
WHERE table_schema = \'' . $_ENV['DB_NAME'] . '\'
|
WHERE table_schema = \'' . $_ENV['DB_NAME'] . '\'
|
||||||
@ -73,6 +73,16 @@ class MigrateDatabaseCommand extends Command
|
|||||||
->fetch(IResultSet::FETCH_NUM)[0];
|
->fetch(IResultSet::FETCH_NUM)[0];
|
||||||
|
|
||||||
if ($migrationTableExists != 0) {
|
if ($migrationTableExists != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
\Container::$dbConnection->multiQuery(file_get_contents(ROOT . '/database/mapguesser.sql'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function readDir(string $type): array
|
||||||
|
{
|
||||||
|
$done = [];
|
||||||
|
|
||||||
$select = new Select(\Container::$dbConnection, 'migrations');
|
$select = new Select(\Container::$dbConnection, 'migrations');
|
||||||
$select->columns(['migration']);
|
$select->columns(['migration']);
|
||||||
$select->where('type', '=', $type);
|
$select->where('type', '=', $type);
|
||||||
@ -83,7 +93,6 @@ class MigrateDatabaseCommand extends Command
|
|||||||
while ($migration = $result->fetch(IResultSet::FETCH_ASSOC)) {
|
while ($migration = $result->fetch(IResultSet::FETCH_ASSOC)) {
|
||||||
$done[] = $migration['migration'];
|
$done[] = $migration['migration'];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$path = ROOT . '/database/migrations/' . $type;
|
$path = ROOT . '/database/migrations/' . $type;
|
||||||
$dir = opendir($path);
|
$dir = opendir($path);
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
<?php namespace MapGuesser\Controller;
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use Faker\Factory;
|
|
||||||
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
||||||
use SokoWeb\Interfaces\Request\IRequest;
|
|
||||||
use SokoWeb\Response\HtmlContent;
|
use SokoWeb\Response\HtmlContent;
|
||||||
use SokoWeb\Response\JsonContent;
|
use SokoWeb\Response\JsonContent;
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
@ -13,7 +11,7 @@ use MapGuesser\PersistentData\Model\Challenge;
|
|||||||
use MapGuesser\PersistentData\Model\MultiRoom;
|
use MapGuesser\PersistentData\Model\MultiRoom;
|
||||||
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
||||||
use MapGuesser\PersistentData\Model\UserInChallenge;
|
use MapGuesser\PersistentData\Model\UserInChallenge;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\Repository\ChallengeRepository;
|
use MapGuesser\Repository\ChallengeRepository;
|
||||||
use MapGuesser\Repository\MapRepository;
|
use MapGuesser\Repository\MapRepository;
|
||||||
use MapGuesser\Repository\MultiRoomRepository;
|
use MapGuesser\Repository\MultiRoomRepository;
|
||||||
@ -25,10 +23,6 @@ class GameController implements IAuthenticationRequired
|
|||||||
{
|
{
|
||||||
const NUMBER_OF_ROUNDS = 5;
|
const NUMBER_OF_ROUNDS = 5;
|
||||||
|
|
||||||
private IRequest $request;
|
|
||||||
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private MultiConnector $multiConnector;
|
private MultiConnector $multiConnector;
|
||||||
|
|
||||||
private MultiRoomRepository $multiRoomRepository;
|
private MultiRoomRepository $multiRoomRepository;
|
||||||
@ -41,10 +35,8 @@ class GameController implements IAuthenticationRequired
|
|||||||
|
|
||||||
private UserInChallengeRepository $userInChallengeRepository;
|
private UserInChallengeRepository $userInChallengeRepository;
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->request = $request;
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->multiConnector = new MultiConnector();
|
$this->multiConnector = new MultiConnector();
|
||||||
$this->multiRoomRepository = new MultiRoomRepository();
|
$this->multiRoomRepository = new MultiRoomRepository();
|
||||||
$this->mapRepository = new MapRepository();
|
$this->mapRepository = new MapRepository();
|
||||||
@ -60,14 +52,14 @@ class GameController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function getGame(): IContent
|
public function getGame(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
|
|
||||||
return new HtmlContent('game', ['mapId' => $mapId]);
|
return new HtmlContent('game', ['mapId' => $mapId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNewMultiGame(): IRedirect
|
public function getNewMultiGame(): IRedirect
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
$map = $this->mapRepository->getById($mapId);
|
$map = $this->mapRepository->getById($mapId);
|
||||||
$roomId = bin2hex(random_bytes(3));
|
$roomId = bin2hex(random_bytes(3));
|
||||||
$token = $this->getMultiToken($roomId);
|
$token = $this->getMultiToken($roomId);
|
||||||
@ -83,7 +75,7 @@ class GameController implements IAuthenticationRequired
|
|||||||
$room->setMembersArray(['owner' => $token, 'all' => []]);
|
$room->setMembersArray(['owner' => $token, 'all' => []]);
|
||||||
$room->setUpdatedDate(new DateTime());
|
$room->setUpdatedDate(new DateTime());
|
||||||
|
|
||||||
$this->pdm->saveToDb($room);
|
\Container::$persistentDataManager->saveToDb($room);
|
||||||
|
|
||||||
$this->multiConnector->sendMessage('create_room', ['roomId' => $roomId]);
|
$this->multiConnector->sendMessage('create_room', ['roomId' => $roomId]);
|
||||||
|
|
||||||
@ -97,14 +89,14 @@ class GameController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function getMultiGame(): IContent
|
public function getMultiGame(): IContent
|
||||||
{
|
{
|
||||||
$roomId = $this->request->query('roomId');
|
$roomId = \Container::$request->query('roomId');
|
||||||
|
|
||||||
return new HtmlContent('game', ['roomId' => $roomId]);
|
return new HtmlContent('game', ['roomId' => $roomId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getChallenge(): IContent
|
public function getChallenge(): IContent
|
||||||
{
|
{
|
||||||
$challengeToken = $this->request->query('challengeToken');
|
$challengeToken = \Container::$request->query('challengeToken');
|
||||||
|
|
||||||
return new HtmlContent('game', ['challengeToken' => $challengeToken]);
|
return new HtmlContent('game', ['challengeToken' => $challengeToken]);
|
||||||
}
|
}
|
||||||
@ -121,27 +113,27 @@ class GameController implements IAuthenticationRequired
|
|||||||
$challenge->setToken($challengeToken);
|
$challenge->setToken($challengeToken);
|
||||||
$challenge->setCreatedDate(new DateTime());
|
$challenge->setCreatedDate(new DateTime());
|
||||||
|
|
||||||
if ($this->request->post('timerEnabled') !== null && $this->request->post('timeLimit') !== null) {
|
if (\Container::$request->post('timerEnabled') !== null && \Container::$request->post('timeLimit') !== null) {
|
||||||
$challenge->setTimeLimit($this->request->post('timeLimit'));
|
$challenge->setTimeLimit(\Container::$request->post('timeLimit'));
|
||||||
}
|
}
|
||||||
if ($this->request->post('timeLimitType') !== null) {
|
if (\Container::$request->post('timeLimitType') !== null) {
|
||||||
$challenge->setTimeLimitType($this->request->post('timeLimitType'));
|
$challenge->setTimeLimitType(\Container::$request->post('timeLimitType'));
|
||||||
}
|
}
|
||||||
if ($this->request->post('noMove') !== null) {
|
if (\Container::$request->post('noMove') !== null) {
|
||||||
$challenge->setNoMove(true);
|
$challenge->setNoMove(true);
|
||||||
}
|
}
|
||||||
if ($this->request->post('noPan') !== null) {
|
if (\Container::$request->post('noPan') !== null) {
|
||||||
$challenge->setNoPan(true);
|
$challenge->setNoPan(true);
|
||||||
}
|
}
|
||||||
if ($this->request->post('noZoom') !== null) {
|
if (\Container::$request->post('noZoom') !== null) {
|
||||||
$challenge->setNoZoom(true);
|
$challenge->setNoZoom(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pdm->saveToDb($challenge);
|
\Container::$persistentDataManager->saveToDb($challenge);
|
||||||
|
|
||||||
// save owner/creator
|
// save owner/creator
|
||||||
|
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
$userId = $session->get('userId');
|
$userId = $session->get('userId');
|
||||||
|
|
||||||
$userInChallenge = new UserInChallenge();
|
$userInChallenge = new UserInChallenge();
|
||||||
@ -150,11 +142,11 @@ class GameController implements IAuthenticationRequired
|
|||||||
$userInChallenge->setTimeLeft($challenge->getTimeLimit());
|
$userInChallenge->setTimeLeft($challenge->getTimeLimit());
|
||||||
$userInChallenge->setIsOwner(true);
|
$userInChallenge->setIsOwner(true);
|
||||||
|
|
||||||
$this->pdm->saveToDb($userInChallenge);
|
\Container::$persistentDataManager->saveToDb($userInChallenge);
|
||||||
|
|
||||||
// select places
|
// select places
|
||||||
|
|
||||||
$mapId = (int) $this->request->post('mapId');
|
$mapId = (int) \Container::$request->post('mapId');
|
||||||
// $map = $this->mapRepository->getById($mapId);
|
// $map = $this->mapRepository->getById($mapId);
|
||||||
|
|
||||||
$places = $this->placeRepository->getRandomNPlaces($mapId, static::NUMBER_OF_ROUNDS, $userId);
|
$places = $this->placeRepository->getRandomNPlaces($mapId, static::NUMBER_OF_ROUNDS, $userId);
|
||||||
@ -165,7 +157,7 @@ class GameController implements IAuthenticationRequired
|
|||||||
$placeInChallenge->setPlace($place);
|
$placeInChallenge->setPlace($place);
|
||||||
$placeInChallenge->setChallenge($challenge);
|
$placeInChallenge->setChallenge($challenge);
|
||||||
$placeInChallenge->setRound($round++);
|
$placeInChallenge->setRound($round++);
|
||||||
$this->pdm->saveToDb($placeInChallenge);
|
\Container::$persistentDataManager->saveToDb($placeInChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonContent(['challengeToken' => dechex($challengeToken)]);
|
return new JsonContent(['challengeToken' => dechex($challengeToken)]);
|
||||||
@ -173,9 +165,9 @@ class GameController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function prepareGame(): IContent
|
public function prepareGame(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
$map = $this->mapRepository->getById($mapId);
|
$map = $this->mapRepository->getById($mapId);
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
|
|
||||||
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
||||||
$session->set('state', [
|
$session->set('state', [
|
||||||
@ -198,13 +190,17 @@ class GameController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function prepareMultiGame(): IContent
|
public function prepareMultiGame(): IContent
|
||||||
{
|
{
|
||||||
$roomId = $this->request->query('roomId');
|
/**
|
||||||
$userName = $this->request->post('userName');
|
* @var User|null $user
|
||||||
if (empty($userName)) {
|
*/
|
||||||
$faker = Factory::create();
|
$user = \Container::$request->user();
|
||||||
$userName = $faker->userName;
|
if ($user === null)
|
||||||
|
{
|
||||||
|
return new JsonContent(['error' => 'anonymous_user']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$roomId = \Container::$request->query('roomId');
|
||||||
|
|
||||||
$room = $this->multiRoomRepository->getByRoomId($roomId);
|
$room = $this->multiRoomRepository->getByRoomId($roomId);
|
||||||
|
|
||||||
if (!isset($room)) {
|
if (!isset($room)) {
|
||||||
@ -228,12 +224,12 @@ class GameController implements IAuthenticationRequired
|
|||||||
$room->setMembersArray($members);
|
$room->setMembersArray($members);
|
||||||
$room->setUpdatedDate(new DateTime());
|
$room->setUpdatedDate(new DateTime());
|
||||||
|
|
||||||
$this->pdm->saveToDb($room);
|
\Container::$persistentDataManager->saveToDb($room);
|
||||||
|
|
||||||
$this->multiConnector->sendMessage('join_room', [
|
$this->multiConnector->sendMessage('join_room', [
|
||||||
'roomId' => $roomId,
|
'roomId' => $roomId,
|
||||||
'token' => $token,
|
'token' => $token,
|
||||||
'userName' => $userName
|
'userName' => $user->getDisplayName()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
@ -248,8 +244,8 @@ class GameController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function prepareChallenge(): IContent
|
public function prepareChallenge(): IContent
|
||||||
{
|
{
|
||||||
$challengeToken_str = $this->request->query('challengeToken');
|
$challengeToken_str = \Container::$request->query('challengeToken');
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
$userId = $session->get('userId');
|
$userId = $session->get('userId');
|
||||||
|
|
||||||
if (!isset($userId))
|
if (!isset($userId))
|
||||||
@ -270,7 +266,7 @@ class GameController implements IAuthenticationRequired
|
|||||||
$userInChallenge->setUserId($userId);
|
$userInChallenge->setUserId($userId);
|
||||||
$userInChallenge->setChallenge($challenge);
|
$userInChallenge->setChallenge($challenge);
|
||||||
$userInChallenge->setTimeLeft($challenge->getTimeLimit());
|
$userInChallenge->setTimeLeft($challenge->getTimeLimit());
|
||||||
$this->pdm->saveToDb($userInChallenge);
|
\Container::$persistentDataManager->saveToDb($userInChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
$map = $this->mapRepository->getByChallenge($challenge);
|
$map = $this->mapRepository->getByChallenge($challenge);
|
||||||
@ -284,7 +280,7 @@ class GameController implements IAuthenticationRequired
|
|||||||
|
|
||||||
private function getMultiToken(string $roomId): string
|
private function getMultiToken(string $roomId): string
|
||||||
{
|
{
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
|
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
||||||
$token = bin2hex(random_bytes(16));
|
$token = bin2hex(random_bytes(16));
|
||||||
|
@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
||||||
use SokoWeb\Interfaces\Request\IRequest;
|
|
||||||
use MapGuesser\Util\Geo\Position;
|
use MapGuesser\Util\Geo\Position;
|
||||||
use SokoWeb\Response\JsonContent;
|
use SokoWeb\Response\JsonContent;
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
use MapGuesser\Multi\MultiConnector;
|
use MapGuesser\Multi\MultiConnector;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\PersistentData\Model\Challenge;
|
use MapGuesser\PersistentData\Model\Challenge;
|
||||||
use MapGuesser\PersistentData\Model\Guess;
|
use MapGuesser\PersistentData\Model\Guess;
|
||||||
use MapGuesser\PersistentData\Model\Map;
|
use MapGuesser\PersistentData\Model\Map;
|
||||||
@ -27,10 +25,6 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
const NUMBER_OF_ROUNDS = 5;
|
const NUMBER_OF_ROUNDS = 5;
|
||||||
const MAX_SCORE = 1000;
|
const MAX_SCORE = 1000;
|
||||||
|
|
||||||
private IRequest $request;
|
|
||||||
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private MultiConnector $multiConnector;
|
private MultiConnector $multiConnector;
|
||||||
|
|
||||||
private MultiRoomRepository $multiRoomRepository;
|
private MultiRoomRepository $multiRoomRepository;
|
||||||
@ -45,10 +39,8 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
private GuessRepository $guessRepository;
|
private GuessRepository $guessRepository;
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->request = $request;
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->multiConnector = new MultiConnector();
|
$this->multiConnector = new MultiConnector();
|
||||||
$this->multiRoomRepository = new MultiRoomRepository();
|
$this->multiRoomRepository = new MultiRoomRepository();
|
||||||
$this->placeRepository = new PlaceRepository();
|
$this->placeRepository = new PlaceRepository();
|
||||||
@ -65,8 +57,8 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function initialData(): IContent
|
public function initialData(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
|
|
||||||
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
return new JsonContent(['error' => 'no_session_found']);
|
||||||
@ -103,8 +95,8 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function multiInitialData(): IContent
|
public function multiInitialData(): IContent
|
||||||
{
|
{
|
||||||
$roomId = $this->request->query('roomId');
|
$roomId = \Container::$request->query('roomId');
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
|
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
return new JsonContent(['error' => 'no_session_found']);
|
||||||
@ -122,7 +114,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
$this->startNewGame($state, $state['mapId']);
|
$this->startNewGame($state, $state['mapId']);
|
||||||
$room->setStateArray($state);
|
$room->setStateArray($state);
|
||||||
$room->setUpdatedDate(new DateTime());
|
$room->setUpdatedDate(new DateTime());
|
||||||
$this->pdm->saveToDb($room);
|
\Container::$persistentDataManager->saveToDb($room);
|
||||||
}
|
}
|
||||||
|
|
||||||
$places = [];
|
$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 the last round was played ($currentPlace == null) or history is explicitly requested (for initializing)
|
||||||
if (!isset($currentPlace) || $withHistory) {
|
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) {
|
foreach ($this->guessRepository->getAllInChallenge($challenge, $withRelations) as $guess) {
|
||||||
$round = $guess->getPlaceInChallenge()->getRound();
|
$round = $guess->getPlaceInChallenge()->getRound();
|
||||||
|
|
||||||
@ -195,7 +187,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
$prevRound = $currentRound - 1;
|
$prevRound = $currentRound - 1;
|
||||||
if ($prevRound >= 0) {
|
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) {
|
if ($guess->getUser()->getId() != $userId) {
|
||||||
$response['allResults'][] = [
|
$response['allResults'][] = [
|
||||||
'userName' => $guess->getUser()->getDisplayName(),
|
'userName' => $guess->getUser()->getDisplayName(),
|
||||||
@ -221,10 +213,10 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function challengeInitialData(): IContent
|
public function challengeInitialData(): IContent
|
||||||
{
|
{
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
$userId = $session->get('userId');
|
$userId = $session->get('userId');
|
||||||
$challengeToken_str = $this->request->query('challengeToken');
|
$challengeToken_str = \Container::$request->query('challengeToken');
|
||||||
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, [Challenge::class]);
|
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, ['challenge']);
|
||||||
|
|
||||||
if (!isset($userInChallenge)) {
|
if (!isset($userInChallenge)) {
|
||||||
return new JsonContent(['error' => 'game_not_found']);
|
return new JsonContent(['error' => 'game_not_found']);
|
||||||
@ -245,15 +237,15 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function guess(): IContent
|
public function guess(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
|
|
||||||
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
return new JsonContent(['error' => 'no_session_found']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$last = $state['rounds'][$state['currentRound']];
|
$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']);
|
$result = $this->evaluateGuess($last['position'], $guessPosition, $state['area']);
|
||||||
|
|
||||||
$last['guessPosition'] = $guessPosition;
|
$last['guessPosition'] = $guessPosition;
|
||||||
@ -286,7 +278,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
// save the selected place for the round in UserPlayedPlace
|
// save the selected place for the round in UserPlayedPlace
|
||||||
private function saveVisit($placeId): void
|
private function saveVisit($placeId): void
|
||||||
{
|
{
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
$userId = $session->get('userId');
|
$userId = $session->get('userId');
|
||||||
|
|
||||||
if (isset($userId)) {
|
if (isset($userId)) {
|
||||||
@ -299,14 +291,14 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
$userPlayedPlace->incrementOccurrences();
|
$userPlayedPlace->incrementOccurrences();
|
||||||
}
|
}
|
||||||
$userPlayedPlace->setLastTimeDate(new DateTime());
|
$userPlayedPlace->setLastTimeDate(new DateTime());
|
||||||
$this->pdm->saveToDb($userPlayedPlace);
|
\Container::$persistentDataManager->saveToDb($userPlayedPlace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function multiGuess(): IContent
|
public function multiGuess(): IContent
|
||||||
{
|
{
|
||||||
$roomId = $this->request->query('roomId');
|
$roomId = \Container::$request->query('roomId');
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
|
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
return new JsonContent(['error' => 'no_session_found']);
|
||||||
@ -316,7 +308,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
$state = $room->getStateArray();
|
$state = $room->getStateArray();
|
||||||
|
|
||||||
$last = $state['rounds'][$state['currentRound']];
|
$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']);
|
$result = $this->evaluateGuess($last['position'], $guessPosition, $state['area']);
|
||||||
|
|
||||||
$responseFromMulti = $this->multiConnector->sendMessage('guess', [
|
$responseFromMulti = $this->multiConnector->sendMessage('guess', [
|
||||||
@ -342,10 +334,10 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function challengeGuess(): IContent
|
public function challengeGuess(): IContent
|
||||||
{
|
{
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
$userId = $session->get('userId');
|
$userId = $session->get('userId');
|
||||||
$challengeToken_str = $this->request->query('challengeToken');
|
$challengeToken_str = \Container::$request->query('challengeToken');
|
||||||
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, [Challenge::class]);
|
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, ['challenge']);
|
||||||
|
|
||||||
if (!isset($userInChallenge)) {
|
if (!isset($userInChallenge)) {
|
||||||
return new JsonContent(['error' => 'game_not_found']);
|
return new JsonContent(['error' => 'game_not_found']);
|
||||||
@ -353,7 +345,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
$challenge = $userInChallenge->getChallenge();
|
$challenge = $userInChallenge->getChallenge();
|
||||||
$currentRound = $userInChallenge->getCurrentRound();
|
$currentRound = $userInChallenge->getCurrentRound();
|
||||||
$currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge, [Place::class, Map::class]);
|
$currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge, ['place', 'map']);
|
||||||
$currentPlace = $currentPlaceInChallenge->getPlace();
|
$currentPlace = $currentPlaceInChallenge->getPlace();
|
||||||
$map = $currentPlace->getMap();
|
$map = $currentPlace->getMap();
|
||||||
|
|
||||||
@ -362,8 +354,8 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
$response = $this->prepareChallengeResponse($userId, $challenge, $nextRound);
|
$response = $this->prepareChallengeResponse($userId, $challenge, $nextRound);
|
||||||
$response['position'] = $currentPlace->getPosition()->toArray();
|
$response['position'] = $currentPlace->getPosition()->toArray();
|
||||||
|
|
||||||
if ($this->request->post('lat') && $this->request->post('lng')) {
|
if (\Container::$request->post('lat') && \Container::$request->post('lng')) {
|
||||||
$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($currentPlace->getPosition(), $guessPosition, $map->getArea());
|
$result = $this->evaluateGuess($currentPlace->getPosition(), $guessPosition, $map->getArea());
|
||||||
|
|
||||||
// save guess
|
// save guess
|
||||||
@ -373,7 +365,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
$guess->setPosition($guessPosition);
|
$guess->setPosition($guessPosition);
|
||||||
$guess->setDistance($result['distance']);
|
$guess->setDistance($result['distance']);
|
||||||
$guess->setScore($result['score']);
|
$guess->setScore($result['score']);
|
||||||
$this->pdm->saveToDb($guess);
|
\Container::$persistentDataManager->saveToDb($guess);
|
||||||
|
|
||||||
$response['result'] = $result;
|
$response['result'] = $result;
|
||||||
|
|
||||||
@ -384,11 +376,11 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
// save user relevant state of challenge
|
// save user relevant state of challenge
|
||||||
$userInChallenge->setCurrentRound($nextRound);
|
$userInChallenge->setCurrentRound($nextRound);
|
||||||
$timeLeft = $this->request->post('timeLeft');
|
$timeLeft = \Container::$request->post('timeLeft');
|
||||||
if (isset($timeLeft)) {
|
if (isset($timeLeft)) {
|
||||||
$userInChallenge->setTimeLeft(intval($timeLeft));
|
$userInChallenge->setTimeLeft(intval($timeLeft));
|
||||||
}
|
}
|
||||||
$this->pdm->saveToDb($userInChallenge);
|
\Container::$persistentDataManager->saveToDb($userInChallenge);
|
||||||
|
|
||||||
if ($challenge->getTimeLimitType() === 'game' && isset($timeLeft)) {
|
if ($challenge->getTimeLimitType() === 'game' && isset($timeLeft)) {
|
||||||
$timeLimit = max(10, intval($timeLeft));
|
$timeLimit = max(10, intval($timeLeft));
|
||||||
@ -406,8 +398,8 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
public function multiNextRound(): IContent
|
public function multiNextRound(): IContent
|
||||||
{
|
{
|
||||||
$roomId = $this->request->query('roomId');
|
$roomId = \Container::$request->query('roomId');
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
|
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
return new JsonContent(['error' => 'no_session_found']);
|
||||||
@ -428,7 +420,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
$room->setStateArray($state);
|
$room->setStateArray($state);
|
||||||
$room->setUpdatedDate(new DateTime());
|
$room->setUpdatedDate(new DateTime());
|
||||||
$this->pdm->saveToDb($room);
|
\Container::$persistentDataManager->saveToDb($room);
|
||||||
|
|
||||||
return new JsonContent(['ok' => true]);
|
return new JsonContent(['ok' => true]);
|
||||||
}
|
}
|
||||||
@ -443,7 +435,7 @@ class GameFlowController implements IAuthenticationRequired
|
|||||||
|
|
||||||
private function startNewGame(array &$state, int $mapId): void
|
private function startNewGame(array &$state, int $mapId): void
|
||||||
{
|
{
|
||||||
$session = $this->request->session();
|
$session = \Container::$request->session();
|
||||||
$userId = $session->get('userId');
|
$userId = $session->get('userId');
|
||||||
|
|
||||||
$places = $this->placeRepository->getRandomNPlaces($mapId, static::NUMBER_OF_ROUNDS, $userId);
|
$places = $this->placeRepository->getRandomNPlaces($mapId, static::NUMBER_OF_ROUNDS, $userId);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<?php namespace MapGuesser\Controller;
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
use SokoWeb\Interfaces\Request\IRequest;
|
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
use SokoWeb\Interfaces\Response\IRedirect;
|
use SokoWeb\Interfaces\Response\IRedirect;
|
||||||
use SokoWeb\Response\JsonContent;
|
use SokoWeb\Response\JsonContent;
|
||||||
@ -8,13 +7,6 @@ use SokoWeb\Response\Redirect;
|
|||||||
|
|
||||||
class HomeController
|
class HomeController
|
||||||
{
|
{
|
||||||
private IRequest $request;
|
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
|
||||||
{
|
|
||||||
$this->request = $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIndex(): IRedirect
|
public function getIndex(): IRedirect
|
||||||
{
|
{
|
||||||
return new Redirect(\Container::$routeCollection->getRoute('maps')->generateLink(), IRedirect::TEMPORARY);
|
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
|
// 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')]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
use DateInterval;
|
use DateInterval;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use SokoWeb\Http\Request;
|
use SokoWeb\Http\Request;
|
||||||
use SokoWeb\Interfaces\Request\IRequest;
|
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
use SokoWeb\Interfaces\Response\IRedirect;
|
use SokoWeb\Interfaces\Response\IRedirect;
|
||||||
use SokoWeb\Mailing\Mail;
|
use SokoWeb\Mailing\Mail;
|
||||||
@ -11,11 +10,11 @@ use SokoWeb\OAuth\GoogleOAuth;
|
|||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\PersistentData\Model\UserConfirmation;
|
use MapGuesser\PersistentData\Model\UserConfirmation;
|
||||||
use MapGuesser\PersistentData\Model\UserPasswordResetter;
|
use MapGuesser\PersistentData\Model\UserPasswordResetter;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\Repository\UserConfirmationRepository;
|
use MapGuesser\Repository\UserConfirmationRepository;
|
||||||
use MapGuesser\Repository\UserPasswordResetterRepository;
|
use MapGuesser\Repository\UserPasswordResetterRepository;
|
||||||
use MapGuesser\Repository\UserPlayedPlaceRepository;
|
use MapGuesser\Repository\UserPlayedPlaceRepository;
|
||||||
use MapGuesser\Repository\UserRepository;
|
use MapGuesser\Repository\UserRepository;
|
||||||
|
use MapGuesser\Util\UsernameGenerator;
|
||||||
use SokoWeb\Response\HtmlContent;
|
use SokoWeb\Response\HtmlContent;
|
||||||
use SokoWeb\Response\JsonContent;
|
use SokoWeb\Response\JsonContent;
|
||||||
use SokoWeb\Response\Redirect;
|
use SokoWeb\Response\Redirect;
|
||||||
@ -24,10 +23,6 @@ use SokoWeb\Util\JwtParser;
|
|||||||
|
|
||||||
class LoginController
|
class LoginController
|
||||||
{
|
{
|
||||||
private IRequest $request;
|
|
||||||
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private UserRepository $userRepository;
|
private UserRepository $userRepository;
|
||||||
|
|
||||||
private UserConfirmationRepository $userConfirmationRepository;
|
private UserConfirmationRepository $userConfirmationRepository;
|
||||||
@ -38,27 +33,25 @@ class LoginController
|
|||||||
|
|
||||||
private string $redirectUrl;
|
private string $redirectUrl;
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->request = $request;
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->userRepository = new UserRepository();
|
$this->userRepository = new UserRepository();
|
||||||
$this->userConfirmationRepository = new UserConfirmationRepository();
|
$this->userConfirmationRepository = new UserConfirmationRepository();
|
||||||
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
||||||
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
|
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
|
||||||
$this->redirectUrl = $this->request->session()->has('redirect_after_login') ?
|
$this->redirectUrl = \Container::$request->session()->has('redirect_after_login') ?
|
||||||
$this->request->session()->get('redirect_after_login') :
|
\Container::$request->session()->get('redirect_after_login') :
|
||||||
\Container::$routeCollection->getRoute('index')->generateLink();
|
\Container::$routeCollection->getRoute('index')->generateLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLoginForm()
|
public function getLoginForm()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HtmlContent('login/login', ['redirectUrl' => '/' . $this->redirectUrl]);
|
return new HtmlContent('login/login', ['redirectUrl' => $this->redirectUrl]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getGoogleLoginRedirect(): IRedirect
|
public function getGoogleLoginRedirect(): IRedirect
|
||||||
@ -66,13 +59,13 @@ class LoginController
|
|||||||
$state = bin2hex(random_bytes(16));
|
$state = bin2hex(random_bytes(16));
|
||||||
$nonce = bin2hex(random_bytes(16));
|
$nonce = bin2hex(random_bytes(16));
|
||||||
|
|
||||||
$this->request->session()->set('oauth_state', $state);
|
\Container::$request->session()->set('oauth_state', $state);
|
||||||
$this->request->session()->set('oauth_nonce', $nonce);
|
\Container::$request->session()->set('oauth_nonce', $nonce);
|
||||||
|
|
||||||
$oAuth = new GoogleOAuth(new Request());
|
$oAuth = new GoogleOAuth(new Request());
|
||||||
$url = $oAuth->getDialogUrl(
|
$url = $oAuth->getDialogUrl(
|
||||||
$state,
|
$state,
|
||||||
$this->request->getBase() . '/' . \Container::$routeCollection->getRoute('login-google-action')->generateLink(),
|
\Container::$request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink(),
|
||||||
$nonce
|
$nonce
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -81,53 +74,56 @@ class LoginController
|
|||||||
|
|
||||||
public function getSignupForm()
|
public function getSignupForm()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->request->session()->has('tmp_user_data')) {
|
if (\Container::$request->session()->has('tmp_user_data')) {
|
||||||
$tmpUserData = $this->request->session()->get('tmp_user_data');
|
$tmpUserData = \Container::$request->session()->get('tmp_user_data');
|
||||||
|
|
||||||
$data = ['email' => $tmpUserData['email']];
|
|
||||||
} else {
|
} else {
|
||||||
$data = [];
|
$tmpUserData = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HtmlContent('login/signup', $data);
|
return new HtmlContent('login/signup', $tmpUserData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSignupSuccess(): IContent
|
public function getSignupSuccess()
|
||||||
{
|
{
|
||||||
|
if (\Container::$request->user() !== null) {
|
||||||
|
$this->deleteRedirectUrl();
|
||||||
|
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
|
||||||
return new HtmlContent('login/signup_success');
|
return new HtmlContent('login/signup_success');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSignupWithGoogleForm()
|
public function getSignupWithGoogleForm()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
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);
|
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']);
|
$user = $this->userRepository->getByEmail($userData['email']);
|
||||||
|
|
||||||
return new HtmlContent('login/google_signup', ['found' => $user !== null, 'email' => $userData['email'], 'redirectUrl' => '/' . $this->redirectUrl]);
|
return new HtmlContent('login/google_signup', ['found' => $user !== null, 'email' => $userData['email'], 'redirectUrl' => $this->redirectUrl]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestPasswordResetForm()
|
public function getRequestPasswordResetForm()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
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
|
public function getRequestPasswordResetSuccess(): IContent
|
||||||
@ -137,12 +133,12 @@ class LoginController
|
|||||||
|
|
||||||
public function getResetPasswordForm()
|
public function getResetPasswordForm()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $this->request->query('token');
|
$token = \Container::$request->query('token');
|
||||||
$resetter = $this->userPasswordResetterRepository->getByToken($token);
|
$resetter = $this->userPasswordResetterRepository->getByToken($token);
|
||||||
|
|
||||||
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
|
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
|
||||||
@ -151,20 +147,27 @@ class LoginController
|
|||||||
|
|
||||||
$user = $this->userRepository->getById($resetter->getUserId());
|
$user = $this->userRepository->getById($resetter->getUserId());
|
||||||
|
|
||||||
return new HtmlContent('login/reset_password', ['success' => true, 'token' => $token, 'email' => $user->getEmail(), 'redirectUrl' => '/' . $this->redirectUrl]);
|
return new HtmlContent('login/reset_password', ['success' => true, 'token' => $token, 'email' => $user->getEmail(), 'redirectUrl' => $this->redirectUrl]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(): IContent
|
public function login(): IContent
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->userRepository->getByEmail($this->request->post('email'));
|
if (
|
||||||
|
filter_var(\Container::$request->post('email'), FILTER_VALIDATE_EMAIL) === false &&
|
||||||
|
preg_match('/^[a-zA-Z0-9_\-\.]+$/', \Container::$request->post('email')) !== 1
|
||||||
|
) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'This is not a valid email address or username.']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->userRepository->getByEmailOrUsername(\Container::$request->post('email'));
|
||||||
|
|
||||||
if ($user === null) {
|
if ($user === null) {
|
||||||
if (strlen($this->request->post('password')) < 6) {
|
if (strlen(\Container::$request->post('password')) < 6) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
|
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
|
||||||
@ -173,16 +176,20 @@ class LoginController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$tmpUser = new User();
|
$tmpUser = new User();
|
||||||
$tmpUser->setPlainPassword($this->request->post('password'));
|
$tmpUser->setPlainPassword(\Container::$request->post('password'));
|
||||||
|
|
||||||
$this->request->session()->set('tmp_user_data', [
|
$tmpUserData = ['password_hashed' => $tmpUser->getPassword()];
|
||||||
'email' => $this->request->post('email'),
|
if (filter_var(\Container::$request->post('email'), FILTER_VALIDATE_EMAIL) === false) {
|
||||||
'password_hashed' => $tmpUser->getPassword()
|
$tmpUserData['username'] = \Container::$request->post('email');
|
||||||
]);
|
} else {
|
||||||
|
$tmpUserData['email'] = \Container::$request->post('email');
|
||||||
|
}
|
||||||
|
|
||||||
|
\Container::$request->session()->set('tmp_user_data', $tmpUserData);
|
||||||
|
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'redirect' => [
|
'redirect' => [
|
||||||
'target' => '/' . \Container::$routeCollection->getRoute('signup')->generateLink()
|
'target' => \Container::$routeCollection->getRoute('signup')->generateLink()
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -192,13 +199,13 @@ class LoginController
|
|||||||
|
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'User found with the given email address, but the account is not activated. ' .
|
'errorText' => 'User found with the given email address / username, but the account is not activated. ' .
|
||||||
'Please check your email and click on the activation link!'
|
'Please check your email and click on the activation link!'
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$user->checkPassword($this->request->post('password'))) {
|
if (!$user->checkPassword(\Container::$request->post('password'))) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'The given password is wrong. You can <a href="/password/requestReset?email=' .
|
'errorText' => 'The given password is wrong. You can <a href="/password/requestReset?email=' .
|
||||||
@ -207,7 +214,7 @@ class LoginController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request->setUser($user);
|
\Container::$request->setUser($user);
|
||||||
|
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
@ -215,19 +222,19 @@ class LoginController
|
|||||||
|
|
||||||
public function loginWithGoogle()
|
public function loginWithGoogle()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
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');
|
return new HtmlContent('login/google_login');
|
||||||
}
|
}
|
||||||
|
|
||||||
$oAuth = new GoogleOAuth(new Request());
|
$oAuth = new GoogleOAuth(new Request());
|
||||||
$tokenData = $oAuth->getToken(
|
$tokenData = $oAuth->getToken(
|
||||||
$this->request->query('code'),
|
\Container::$request->query('code'),
|
||||||
$this->request->getBase() . '/' . \Container::$routeCollection->getRoute('login-google-action')->generateLink()
|
\Container::$request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isset($tokenData['id_token'])) {
|
if (!isset($tokenData['id_token'])) {
|
||||||
@ -237,7 +244,7 @@ class LoginController
|
|||||||
$jwtParser = new JwtParser($tokenData['id_token']);
|
$jwtParser = new JwtParser($tokenData['id_token']);
|
||||||
$idToken = $jwtParser->getPayload();
|
$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');
|
return new HtmlContent('login/google_login');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,12 +255,12 @@ class LoginController
|
|||||||
$user = $this->userRepository->getByGoogleSub($idToken['sub']);
|
$user = $this->userRepository->getByGoogleSub($idToken['sub']);
|
||||||
|
|
||||||
if ($user === null) {
|
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);
|
return new Redirect(\Container::$routeCollection->getRoute('signup-google')->generateLink(), IRedirect::TEMPORARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request->setUser($user);
|
\Container::$request->setUser($user);
|
||||||
|
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
||||||
@ -261,40 +268,60 @@ class LoginController
|
|||||||
|
|
||||||
public function logout(): IRedirect
|
public function logout(): IRedirect
|
||||||
{
|
{
|
||||||
$this->request->setUser(null);
|
\Container::$request->setUser(null);
|
||||||
|
|
||||||
return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY);
|
return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function signup(): IContent
|
public function signup(): IContent
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new JsonContent(['redirect' => ['target' => '/' . $this->redirectUrl]]);
|
return new JsonContent(['redirect' => ['target' => $this->redirectUrl]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->userRepository->getByEmail($this->request->post('email'));
|
$newUser = new User();
|
||||||
|
|
||||||
|
$googleUserData = \Container::$request->session()->get('google_user_data');
|
||||||
|
if ($googleUserData !== null) {
|
||||||
|
$user = $this->userRepository->getByEmail($googleUserData['email']);
|
||||||
|
|
||||||
|
if ($user !== null) {
|
||||||
|
return new JsonContent([
|
||||||
|
'error' => [
|
||||||
|
'errorText' => 'There is a user already registered with the email address of this Google account, ' .
|
||||||
|
'but Google account is not linked to the user. Please <a href="/login?email=' .
|
||||||
|
urlencode($googleUserData['email']) . '" title="Login">login</a> first to link your Google account!'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newUser->setActive(true);
|
||||||
|
$newUser->setEmail($googleUserData['email']);
|
||||||
|
$newUser->setGoogleSub($googleUserData['sub']);
|
||||||
|
} else {
|
||||||
|
$user = $this->userRepository->getByEmailOrUsername(\Container::$request->post('email'));
|
||||||
|
|
||||||
if ($user !== null) {
|
if ($user !== null) {
|
||||||
if ($user->getActive()) {
|
if ($user->getActive()) {
|
||||||
if (!$user->checkPassword($this->request->post('password'))) {
|
if (!$user->checkPassword(\Container::$request->post('password'))) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'There is a user already registered with the given email address, ' .
|
'errorText' => 'There is a user already registered with the given email address / username, ' .
|
||||||
'but the given password is wrong. You can <a href="/password/requestReset?email=' .
|
'but the given password is wrong. You can <a href="/password/requestReset?email=' .
|
||||||
urlencode($user->getEmail()) . '" title="Request password reset">request password reset</a>!'
|
urlencode($user->getEmail()) . '" title="Request password reset">request password reset</a>!'
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request->setUser($user);
|
\Container::$request->setUser($user);
|
||||||
|
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
$data = ['redirect' => ['target' => '/' . $this->redirectUrl]];
|
$data = ['redirect' => ['target' => $this->redirectUrl]];
|
||||||
} else {
|
} else {
|
||||||
$data = [
|
$data = [
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'There is a user already registered with the given email address. ' .
|
'errorText' => 'There is a user already registered with the given email address / username. ' .
|
||||||
'Please check your email and click on the activation link!'
|
'Please check your email and click on the activation link!'
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
@ -303,32 +330,32 @@ class LoginController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($_ENV['RECAPTCHA_SITEKEY'])) {
|
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!']]);
|
return new JsonContent(['error' => ['errorText' => 'Please check "I\'m not a robot" in the reCAPTCHA box!']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$captchaValidator = new CaptchaValidator();
|
$captchaValidator = new CaptchaValidator();
|
||||||
$captchaResponse = $captchaValidator->validate($this->request->post('g-recaptcha-response'));
|
$captchaResponse = $captchaValidator->validate(\Container::$request->post('g-recaptcha-response'));
|
||||||
if (!$captchaResponse['success']) {
|
if (!$captchaResponse['success']) {
|
||||||
return new JsonContent(['error' => ['errorText' => 'reCAPTCHA challenge failed. Please try again!']]);
|
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.']]);
|
return new JsonContent(['error' => ['errorText' => 'The given email address is not valid.']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->request->session()->has('tmp_user_data')) {
|
if (\Container::$request->session()->has('tmp_user_data')) {
|
||||||
$tmpUserData = $this->request->session()->get('tmp_user_data');
|
$tmpUserData = \Container::$request->session()->get('tmp_user_data');
|
||||||
|
|
||||||
$tmpUser = new User();
|
$tmpUser = new User();
|
||||||
$tmpUser->setPassword($tmpUserData['password_hashed']);
|
$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.']]);
|
return new JsonContent(['error' => ['errorText' => 'The given passwords do not match.']]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (strlen($this->request->post('password')) < 6) {
|
if (strlen(\Container::$request->post('password')) < 6) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
|
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
|
||||||
@ -336,114 +363,96 @@ 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.']]);
|
return new JsonContent(['error' => ['errorText' => 'The given passwords do not match.']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = new User();
|
$newUser->setActive(false);
|
||||||
$user->setEmail($this->request->post('email'));
|
$newUser->setEmail(\Container::$request->post('email'));
|
||||||
$user->setPlainPassword($this->request->post('password'));
|
$newUser->setPlainPassword(\Container::$request->post('password'));
|
||||||
$user->setCreatedDate(new DateTime());
|
}
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
if (strlen(\Container::$request->post('username')) > 0) {
|
||||||
|
$username = \Container::$request->post('username');
|
||||||
|
|
||||||
$this->pdm->saveToDb($user);
|
if (preg_match('/^[a-zA-Z0-9_\-\.]+$/', $username) !== 1) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'Username can contain only english letters, digits, - (hyphen), . (dot), _ (underscore).']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->userRepository->getByUsername($username) !== null) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'The given username is already taken.']]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$usernameGenerator = new UsernameGenerator();
|
||||||
|
do {
|
||||||
|
$username = $usernameGenerator->generate();
|
||||||
|
} while ($this->userRepository->getByUsername($username));
|
||||||
|
}
|
||||||
|
|
||||||
|
$newUser->setUsername($username);
|
||||||
|
$newUser->setCreatedDate(new DateTime());
|
||||||
|
|
||||||
|
\Container::$persistentDataManager->saveToDb($newUser);
|
||||||
|
|
||||||
|
if ($googleUserData !== null) {
|
||||||
|
$this->sendWelcomeEmail($newUser->getEmail());
|
||||||
|
|
||||||
|
\Container::$request->setUser($newUser);
|
||||||
|
} else {
|
||||||
$token = bin2hex(random_bytes(16));
|
$token = bin2hex(random_bytes(16));
|
||||||
|
|
||||||
$confirmation = new UserConfirmation();
|
$confirmation = new UserConfirmation();
|
||||||
$confirmation->setUser($user);
|
$confirmation->setUser($newUser);
|
||||||
$confirmation->setToken($token);
|
$confirmation->setToken($token);
|
||||||
$confirmation->setLastSentDate(new DateTime());
|
$confirmation->setLastSentDate(new DateTime());
|
||||||
|
|
||||||
$this->pdm->saveToDb($confirmation);
|
\Container::$persistentDataManager->saveToDb($confirmation);
|
||||||
|
|
||||||
\Container::$dbConnection->commit();
|
$this->sendConfirmationEmail($newUser->getEmail(), $token, $newUser->getCreatedDate());
|
||||||
|
|
||||||
$this->sendConfirmationEmail($user->getEmail(), $token, $user->getCreatedDate());
|
|
||||||
|
|
||||||
$this->request->session()->delete('tmp_user_data');
|
|
||||||
|
|
||||||
return new JsonContent(['success' => true]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function signupWithGoogle(): IContent
|
\Container::$request->session()->delete('tmp_user_data');
|
||||||
{
|
\Container::$request->session()->delete('google_user_data');
|
||||||
if ($this->request->user() !== null) {
|
|
||||||
$this->deleteRedirectUrl();
|
|
||||||
return new JsonContent(['success' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$userData = $this->request->session()->get('google_user_data');
|
|
||||||
|
|
||||||
$user = $this->userRepository->getByEmail($userData['email']);
|
|
||||||
|
|
||||||
if ($user === null) {
|
|
||||||
$sendWelcomeEmail = true;
|
|
||||||
|
|
||||||
$user = new User();
|
|
||||||
$user->setEmail($userData['email']);
|
|
||||||
$user->setCreatedDate(new DateTime());
|
|
||||||
} else {
|
|
||||||
$sendWelcomeEmail = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->setActive(true);
|
|
||||||
$user->setGoogleSub($userData['sub']);
|
|
||||||
|
|
||||||
$this->pdm->saveToDb($user);
|
|
||||||
|
|
||||||
if ($sendWelcomeEmail) {
|
|
||||||
$this->sendWelcomeEmail($user->getEmail());
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->request->session()->delete('google_user_data');
|
|
||||||
$this->request->setUser($user);
|
|
||||||
|
|
||||||
$this->deleteRedirectUrl();
|
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetSignup(): IContent
|
public function resetSignup(): IContent
|
||||||
{
|
{
|
||||||
$this->request->session()->delete('tmp_user_data');
|
\Container::$request->session()->delete('tmp_user_data');
|
||||||
|
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetGoogleSignup(): IContent
|
public function resetGoogleSignup(): IContent
|
||||||
{
|
{
|
||||||
$this->request->session()->delete('google_user_data');
|
\Container::$request->session()->delete('google_user_data');
|
||||||
|
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function activate()
|
public function activate()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
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) {
|
if ($confirmation === null) {
|
||||||
return new HtmlContent('login/activate');
|
return new HtmlContent('login/activate');
|
||||||
}
|
}
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
\Container::$persistentDataManager->deleteFromDb($confirmation);
|
||||||
|
|
||||||
$this->pdm->deleteFromDb($confirmation);
|
|
||||||
|
|
||||||
$user = $this->userRepository->getById($confirmation->getUserId());
|
$user = $this->userRepository->getById($confirmation->getUserId());
|
||||||
$user->setActive(true);
|
$user->setActive(true);
|
||||||
|
|
||||||
$this->pdm->saveToDb($user);
|
\Container::$persistentDataManager->saveToDb($user);
|
||||||
|
|
||||||
\Container::$dbConnection->commit();
|
\Container::$request->setUser($user);
|
||||||
|
|
||||||
$this->request->setUser($user);
|
|
||||||
|
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
||||||
@ -451,63 +460,66 @@ class LoginController
|
|||||||
|
|
||||||
public function cancel()
|
public function cancel()
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
|
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) {
|
if ($confirmation === null) {
|
||||||
return new HtmlContent('login/cancel', ['success' => false]);
|
return new HtmlContent('login/cancel', ['success' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
\Container::$persistentDataManager->deleteFromDb($confirmation);
|
||||||
|
|
||||||
$this->pdm->deleteFromDb($confirmation);
|
|
||||||
|
|
||||||
$user = $this->userRepository->getById($confirmation->getUserId());
|
$user = $this->userRepository->getById($confirmation->getUserId());
|
||||||
|
|
||||||
foreach ($this->userPlayedPlaceRepository->getAllByUser($user) as $userPlayedPlace) {
|
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();
|
|
||||||
|
|
||||||
return new HtmlContent('login/cancel', ['success' => true]);
|
return new HtmlContent('login/cancel', ['success' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function requestPasswordReset(): IContent
|
public function requestPasswordReset(): IContent
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'redirect' => [
|
'redirect' => [
|
||||||
'target' => '/' . $this->redirectUrl
|
'target' => $this->redirectUrl
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($_ENV['RECAPTCHA_SITEKEY'])) {
|
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!']]);
|
return new JsonContent(['error' => ['errorText' => 'Please check "I\'m not a robot" in the reCAPTCHA box!']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$captchaValidator = new CaptchaValidator();
|
$captchaValidator = new CaptchaValidator();
|
||||||
$captchaResponse = $captchaValidator->validate($this->request->post('g-recaptcha-response'));
|
$captchaResponse = $captchaValidator->validate(\Container::$request->post('g-recaptcha-response'));
|
||||||
if (!$captchaResponse['success']) {
|
if (!$captchaResponse['success']) {
|
||||||
return new JsonContent(['error' => ['errorText' => 'reCAPTCHA challenge failed. Please try again!']]);
|
return new JsonContent(['error' => ['errorText' => 'reCAPTCHA challenge failed. Please try again!']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->userRepository->getByEmail($this->request->post('email'));
|
if (
|
||||||
|
filter_var(\Container::$request->post('email'), FILTER_VALIDATE_EMAIL) === false &&
|
||||||
|
preg_match('/^[a-zA-Z0-9_\-\.]+$/', \Container::$request->post('email')) !== 1
|
||||||
|
) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'This is not a valid email address or username.']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->userRepository->getByEmailOrUsername(\Container::$request->post('email'));
|
||||||
|
|
||||||
if ($user === null) {
|
if ($user === null) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'No user found with the given email address. You can <a href="/signup" title="Sign up">sign up</a>!'
|
'errorText' => 'No user found with the given email address / username. You can <a href="/signup" title="Sign up">sign up</a>!'
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -517,7 +529,7 @@ class LoginController
|
|||||||
|
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'User found with the given email address, but the account is not activated. ' .
|
'errorText' => 'User found with the given email address / username, but the account is not activated. ' .
|
||||||
'Please check your email and click on the activation link!'
|
'Please check your email and click on the activation link!'
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
@ -541,15 +553,11 @@ class LoginController
|
|||||||
$passwordResetter->setToken($token);
|
$passwordResetter->setToken($token);
|
||||||
$passwordResetter->setExpiresDate($expires);
|
$passwordResetter->setExpiresDate($expires);
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
|
||||||
|
|
||||||
if ($existingResetter !== null) {
|
if ($existingResetter !== null) {
|
||||||
$this->pdm->deleteFromDb($existingResetter);
|
\Container::$persistentDataManager->deleteFromDb($existingResetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pdm->saveToDb($passwordResetter);
|
\Container::$persistentDataManager->saveToDb($passwordResetter);
|
||||||
|
|
||||||
\Container::$dbConnection->commit();
|
|
||||||
|
|
||||||
$this->sendPasswordResetEmail($user->getEmail(), $token, $expires);
|
$this->sendPasswordResetEmail($user->getEmail(), $token, $expires);
|
||||||
|
|
||||||
@ -559,27 +567,27 @@ class LoginController
|
|||||||
|
|
||||||
public function resetPassword(): IContent
|
public function resetPassword(): IContent
|
||||||
{
|
{
|
||||||
if ($this->request->user() !== null) {
|
if (\Container::$request->user() !== null) {
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'redirect' => [
|
'redirect' => [
|
||||||
'target' => '/' . $this->redirectUrl
|
'target' => $this->redirectUrl
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $this->request->query('token');
|
$token = \Container::$request->query('token');
|
||||||
$resetter = $this->userPasswordResetterRepository->getByToken($token);
|
$resetter = $this->userPasswordResetterRepository->getByToken($token);
|
||||||
|
|
||||||
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
|
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'redirect' => [
|
'redirect' => [
|
||||||
'target' => '/' . \Container::$routeCollection->getRoute('password-reset')->generateLink(['token' => $token])
|
'target' => \Container::$routeCollection->getRoute('password-reset')->generateLink(['token' => $token])
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($this->request->post('password')) < 6) {
|
if (strlen(\Container::$request->post('password')) < 6) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
|
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
|
||||||
@ -587,22 +595,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.']]);
|
return new JsonContent(['error' => ['errorText' => 'The given passwords do not match.']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
\Container::$persistentDataManager->deleteFromDb($resetter);
|
||||||
|
|
||||||
$this->pdm->deleteFromDb($resetter);
|
|
||||||
|
|
||||||
$user = $this->userRepository->getById($resetter->getUserId());
|
$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();
|
\Container::$request->setUser($user);
|
||||||
|
|
||||||
$this->request->setUser($user);
|
|
||||||
|
|
||||||
$this->deleteRedirectUrl();
|
$this->deleteRedirectUrl();
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
@ -615,9 +619,9 @@ class LoginController
|
|||||||
$mail->setSubject('Welcome to ' . $_ENV['APP_NAME'] . ' - Activate your account');
|
$mail->setSubject('Welcome to ' . $_ENV['APP_NAME'] . ' - Activate your account');
|
||||||
$mail->setBodyFromTemplate('signup', [
|
$mail->setBodyFromTemplate('signup', [
|
||||||
'EMAIL' => $email,
|
'EMAIL' => $email,
|
||||||
'ACTIVATE_LINK' => $this->request->getBase() . '/' .
|
'ACTIVATE_LINK' => \Container::$request->getBase() .
|
||||||
\Container::$routeCollection->getRoute('signup.activate')->generateLink(['token' => $token]),
|
\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]),
|
\Container::$routeCollection->getRoute('signup.cancel')->generateLink(['token' => $token]),
|
||||||
'ACTIVATABLE_UNTIL' => (clone $created)->add(new DateInterval('P1D'))->format('Y-m-d H:i T')
|
'ACTIVATABLE_UNTIL' => (clone $created)->add(new DateInterval('P1D'))->format('Y-m-d H:i T')
|
||||||
]);
|
]);
|
||||||
@ -634,7 +638,7 @@ class LoginController
|
|||||||
|
|
||||||
$confirmation->setLastSentDate(new DateTime());
|
$confirmation->setLastSentDate(new DateTime());
|
||||||
|
|
||||||
$this->pdm->saveToDb($confirmation);
|
\Container::$persistentDataManager->saveToDb($confirmation);
|
||||||
|
|
||||||
$this->sendConfirmationEmail($user->getEmail(), $confirmation->getToken(), $user->getCreatedDate());
|
$this->sendConfirmationEmail($user->getEmail(), $confirmation->getToken(), $user->getCreatedDate());
|
||||||
|
|
||||||
@ -659,7 +663,7 @@ class LoginController
|
|||||||
$mail->setSubject($_ENV['APP_NAME'] . ' - Password reset');
|
$mail->setSubject($_ENV['APP_NAME'] . ' - Password reset');
|
||||||
$mail->setBodyFromTemplate('password-reset', [
|
$mail->setBodyFromTemplate('password-reset', [
|
||||||
'EMAIL' => $email,
|
'EMAIL' => $email,
|
||||||
'RESET_LINK' => $this->request->getBase() . '/' .
|
'RESET_LINK' => \Container::$request->getBase() .
|
||||||
\Container::$routeCollection->getRoute('password-reset')->generateLink(['token' => $token]),
|
\Container::$routeCollection->getRoute('password-reset')->generateLink(['token' => $token]),
|
||||||
'EXPIRES' => $expires->format('Y-m-d H:i T')
|
'EXPIRES' => $expires->format('Y-m-d H:i T')
|
||||||
]);
|
]);
|
||||||
@ -668,6 +672,6 @@ class LoginController
|
|||||||
|
|
||||||
private function deleteRedirectUrl(): void
|
private function deleteRedirectUrl(): void
|
||||||
{
|
{
|
||||||
$this->request->session()->delete('redirect_after_login');
|
\Container::$request->session()->delete('redirect_after_login');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,11 @@ use DateTime;
|
|||||||
use SokoWeb\Interfaces\Authentication\IUser;
|
use SokoWeb\Interfaces\Authentication\IUser;
|
||||||
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
||||||
use SokoWeb\Interfaces\Authorization\ISecured;
|
use SokoWeb\Interfaces\Authorization\ISecured;
|
||||||
use SokoWeb\Interfaces\Request\IRequest;
|
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
use MapGuesser\PersistentData\Model\Challenge;
|
use MapGuesser\PersistentData\Model\Challenge;
|
||||||
use MapGuesser\PersistentData\Model\Map;
|
use MapGuesser\PersistentData\Model\Map;
|
||||||
use MapGuesser\PersistentData\Model\Place;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\Repository\ChallengeRepository;
|
use MapGuesser\Repository\ChallengeRepository;
|
||||||
use MapGuesser\Repository\GuessRepository;
|
use MapGuesser\Repository\GuessRepository;
|
||||||
use MapGuesser\Repository\MapRepository;
|
use MapGuesser\Repository\MapRepository;
|
||||||
@ -27,10 +25,6 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
{
|
{
|
||||||
private static string $unnamedMapName = '[unnamed map]';
|
private static string $unnamedMapName = '[unnamed map]';
|
||||||
|
|
||||||
private IRequest $request;
|
|
||||||
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private MapRepository $mapRepository;
|
private MapRepository $mapRepository;
|
||||||
|
|
||||||
private PlaceRepository $placeRepository;
|
private PlaceRepository $placeRepository;
|
||||||
@ -45,10 +39,8 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
|
|
||||||
private UserInChallengeRepository $userInChallengeRepository;
|
private UserInChallengeRepository $userInChallengeRepository;
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->request = $request;
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->mapRepository = new MapRepository();
|
$this->mapRepository = new MapRepository();
|
||||||
$this->placeRepository = new PlaceRepository();
|
$this->placeRepository = new PlaceRepository();
|
||||||
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
|
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
|
||||||
@ -65,12 +57,12 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return $this->request->user()->hasPermission(IUser::PERMISSION_ADMIN);
|
return \Container::$request->user()->hasPermission(IUser::PERMISSION_ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMapEditor(): IContent
|
public function getMapEditor(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
|
|
||||||
if ($mapId) {
|
if ($mapId) {
|
||||||
$map = $this->mapRepository->getById($mapId);
|
$map = $this->mapRepository->getById($mapId);
|
||||||
@ -93,7 +85,7 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
|
|
||||||
public function getPlace(): IContent
|
public function getPlace(): IContent
|
||||||
{
|
{
|
||||||
$placeId = (int) $this->request->query('placeId');
|
$placeId = (int) \Container::$request->query('placeId');
|
||||||
|
|
||||||
$place = $this->placeRepository->getById($placeId);
|
$place = $this->placeRepository->getById($placeId);
|
||||||
|
|
||||||
@ -102,16 +94,14 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
|
|
||||||
public function saveMap(): IContent
|
public function saveMap(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
|
||||||
|
|
||||||
if ($mapId) {
|
if ($mapId) {
|
||||||
$map = $this->mapRepository->getById($mapId);
|
$map = $this->mapRepository->getById($mapId);
|
||||||
} else {
|
} else {
|
||||||
$map = new Map();
|
$map = new Map();
|
||||||
$map->setName(self::$unnamedMapName);
|
$map->setName(self::$unnamedMapName);
|
||||||
$this->pdm->saveToDb($map);
|
\Container::$persistentDataManager->saveToDb($map);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_POST['added'])) {
|
if (isset($_POST['added'])) {
|
||||||
@ -133,7 +123,7 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
$place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
|
$place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pdm->saveToDb($place);
|
\Container::$persistentDataManager->saveToDb($place);
|
||||||
|
|
||||||
$addedIds[] = ['tempId' => $placeRaw['id'], 'id' => $place->getId()];
|
$addedIds[] = ['tempId' => $placeRaw['id'], 'id' => $place->getId()];
|
||||||
}
|
}
|
||||||
@ -155,7 +145,7 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
));
|
));
|
||||||
$place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
|
$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']);
|
$map->setUnlisted((bool)$_POST['unlisted']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pdm->saveToDb($map);
|
\Container::$persistentDataManager->saveToDb($map);
|
||||||
|
|
||||||
\Container::$dbConnection->commit();
|
|
||||||
|
|
||||||
return new JsonContent(['mapId' => $map->getId(), 'added' => $addedIds]);
|
return new JsonContent(['mapId' => $map->getId(), 'added' => $addedIds]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteMap(): IContent
|
public function deleteMap(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) \Container::$request->query('mapId');
|
||||||
|
|
||||||
$map = $this->mapRepository->getById($mapId);
|
$map = $this->mapRepository->getById($mapId);
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
|
||||||
|
|
||||||
$this->deletePlaces($map);
|
$this->deletePlaces($map);
|
||||||
|
|
||||||
$this->pdm->deleteFromDb($map);
|
\Container::$persistentDataManager->deleteFromDb($map);
|
||||||
|
|
||||||
\Container::$dbConnection->commit();
|
|
||||||
|
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
}
|
}
|
||||||
@ -211,14 +195,14 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
private function deletePlace(Place $place): void
|
private function deletePlace(Place $place): void
|
||||||
{
|
{
|
||||||
foreach ($this->userPlayedPlaceRepository->getAllByPlace($place) as $userPlayedPlace) {
|
foreach ($this->userPlayedPlaceRepository->getAllByPlace($place) as $userPlayedPlace) {
|
||||||
$this->pdm->deleteFromDb($userPlayedPlace);
|
\Container::$persistentDataManager->deleteFromDb($userPlayedPlace);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->challengeRepository->getAllByPlace($place) as $challenge) {
|
foreach ($this->challengeRepository->getAllByPlace($place) as $challenge) {
|
||||||
$this->deleteChallenge($challenge);
|
$this->deleteChallenge($challenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pdm->deleteFromDb($place);
|
\Container::$persistentDataManager->deleteFromDb($place);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function deletePlaces(Map $map): void
|
private function deletePlaces(Map $map): void
|
||||||
@ -231,18 +215,18 @@ class MapAdminController implements IAuthenticationRequired, ISecured
|
|||||||
private function deleteChallenge(Challenge $challenge): void
|
private function deleteChallenge(Challenge $challenge): void
|
||||||
{
|
{
|
||||||
foreach ($this->userInChallengeRepository->getAllByChallenge($challenge) as $userInChallenge) {
|
foreach ($this->userInChallengeRepository->getAllByChallenge($challenge) as $userInChallenge) {
|
||||||
$this->pdm->deleteFromDb($userInChallenge);
|
\Container::$persistentDataManager->deleteFromDb($userInChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->guessRepository->getAllInChallenge($challenge, [PlaceInChallenge::class]) as $guess) {
|
foreach ($this->guessRepository->getAllInChallenge($challenge, ['place_in_challange']) as $guess) {
|
||||||
$this->pdm->deleteFromDb($guess);
|
\Container::$persistentDataManager->deleteFromDb($guess);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->placeInChallengeRepository->getAllByChallenge($challenge) as $placeInChallenge) {
|
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
|
private function calculateMapBounds(Map $map): Bounds
|
||||||
|
@ -4,19 +4,11 @@ use SokoWeb\Database\Query\Select;
|
|||||||
use SokoWeb\Database\RawExpression;
|
use SokoWeb\Database\RawExpression;
|
||||||
use SokoWeb\Interfaces\Authentication\IUser;
|
use SokoWeb\Interfaces\Authentication\IUser;
|
||||||
use SokoWeb\Interfaces\Database\IResultSet;
|
use SokoWeb\Interfaces\Database\IResultSet;
|
||||||
use SokoWeb\Interfaces\Request\IRequest;
|
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
use SokoWeb\Response\HtmlContent;
|
use SokoWeb\Response\HtmlContent;
|
||||||
|
|
||||||
class MapsController
|
class MapsController
|
||||||
{
|
{
|
||||||
private IRequest $request;
|
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
|
||||||
{
|
|
||||||
$this->request = $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMaps(): IContent
|
public function getMaps(): IContent
|
||||||
{
|
{
|
||||||
//TODO: from repository - count should be added
|
//TODO: from repository - count should be added
|
||||||
@ -37,7 +29,7 @@ class MapsController
|
|||||||
$select->groupBy(['maps', 'id']);
|
$select->groupBy(['maps', 'id']);
|
||||||
$select->orderBy('name');
|
$select->orderBy('name');
|
||||||
|
|
||||||
$user = $this->request->user();
|
$user = \Container::$request->user();
|
||||||
$isAdmin = $user !== null && $user->hasPermission(IUser::PERMISSION_ADMIN);
|
$isAdmin = $user !== null && $user->hasPermission(IUser::PERMISSION_ADMIN);
|
||||||
if (!$isAdmin) {
|
if (!$isAdmin) {
|
||||||
$select->where(['maps', 'unlisted'], '=', false);
|
$select->where(['maps', 'unlisted'], '=', false);
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
use DateTime;
|
use DateTime;
|
||||||
use SokoWeb\Http\Request;
|
use SokoWeb\Http\Request;
|
||||||
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
||||||
use SokoWeb\Interfaces\Request\IRequest;
|
|
||||||
use SokoWeb\Interfaces\Response\IContent;
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
use SokoWeb\Interfaces\Response\IRedirect;
|
use SokoWeb\Interfaces\Response\IRedirect;
|
||||||
use SokoWeb\OAuth\GoogleOAuth;
|
use SokoWeb\OAuth\GoogleOAuth;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\Repository\GuessRepository;
|
use MapGuesser\Repository\GuessRepository;
|
||||||
|
use MapGuesser\Repository\UserRepository;
|
||||||
use MapGuesser\Repository\UserConfirmationRepository;
|
use MapGuesser\Repository\UserConfirmationRepository;
|
||||||
use MapGuesser\Repository\UserInChallengeRepository;
|
use MapGuesser\Repository\UserInChallengeRepository;
|
||||||
use MapGuesser\Repository\UserPasswordResetterRepository;
|
use MapGuesser\Repository\UserPasswordResetterRepository;
|
||||||
@ -21,9 +20,7 @@ use SokoWeb\Util\JwtParser;
|
|||||||
|
|
||||||
class UserController implements IAuthenticationRequired
|
class UserController implements IAuthenticationRequired
|
||||||
{
|
{
|
||||||
private IRequest $request;
|
private UserRepository $userRepository;
|
||||||
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private UserConfirmationRepository $userConfirmationRepository;
|
private UserConfirmationRepository $userConfirmationRepository;
|
||||||
|
|
||||||
@ -35,10 +32,9 @@ class UserController implements IAuthenticationRequired
|
|||||||
|
|
||||||
private GuessRepository $guessRepository;
|
private GuessRepository $guessRepository;
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->request = $request;
|
$this->userRepository = new UserRepository();
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->userConfirmationRepository = new UserConfirmationRepository();
|
$this->userConfirmationRepository = new UserConfirmationRepository();
|
||||||
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
||||||
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
|
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
|
||||||
@ -56,29 +52,153 @@ class UserController implements IAuthenticationRequired
|
|||||||
/**
|
/**
|
||||||
* @var User $user
|
* @var User $user
|
||||||
*/
|
*/
|
||||||
$user = $this->request->user();
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
return new HtmlContent('account/account', ['user' => $user->toArray()]);
|
return new HtmlContent('account/account', ['user' => $user->toArray()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getGoogleConnectRedirect(): IRedirect
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var User $user
|
||||||
|
*/
|
||||||
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
|
$state = bin2hex(random_bytes(16));
|
||||||
|
$nonce = bin2hex(random_bytes(16));
|
||||||
|
|
||||||
|
\Container::$request->session()->set('oauth_state', $state);
|
||||||
|
\Container::$request->session()->set('oauth_nonce', $nonce);
|
||||||
|
|
||||||
|
$oAuth = new GoogleOAuth(new Request());
|
||||||
|
|
||||||
|
$url = $oAuth->getDialogUrl(
|
||||||
|
$state,
|
||||||
|
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleConnect-confirm')->generateLink(),
|
||||||
|
$nonce,
|
||||||
|
$user->getEmail()
|
||||||
|
);
|
||||||
|
|
||||||
|
return new Redirect($url, IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGoogleConnectConfirm(): IContent
|
||||||
|
{
|
||||||
|
$defaultError = 'Authentication with Google failed. Please <a href="' . \Container::$routeCollection->getRoute('account.googleConnect')->generateLink() . '" title="Connect with Google">try again</a>!';
|
||||||
|
|
||||||
|
if (\Container::$request->query('state') !== \Container::$request->session()->get('oauth_state')) {
|
||||||
|
return new HtmlContent('account/google_connect', ['success' => false, 'error' => $defaultError]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$oAuth = new GoogleOAuth(new Request());
|
||||||
|
$tokenData = $oAuth->getToken(
|
||||||
|
\Container::$request->query('code'),
|
||||||
|
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleConnect-confirm')->generateLink()
|
||||||
|
);
|
||||||
|
if (!isset($tokenData['id_token'])) {
|
||||||
|
return new HtmlContent('account/google_connect', ['success' => false, 'error' => $defaultError]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$jwtParser = new JwtParser($tokenData['id_token']);
|
||||||
|
$idToken = $jwtParser->getPayload();
|
||||||
|
if ($idToken['nonce'] !== \Container::$request->session()->get('oauth_nonce')) {
|
||||||
|
return new HtmlContent('account/google_connect', ['success' => false, 'error' => $defaultError]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$anotherUser = $this->userRepository->getByGoogleSub($idToken['sub']);
|
||||||
|
if ($anotherUser !== null) {
|
||||||
|
return new HtmlContent('account/google_connect', [
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'This Google account is linked to another account.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
\Container::$request->session()->set('google_user_data', $idToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var User $user
|
||||||
|
*/
|
||||||
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
|
return new HtmlContent('account/google_connect', [
|
||||||
|
'success' => true,
|
||||||
|
'googleAccount' => $idToken['email'],
|
||||||
|
'userEmail' => $user->getEmail()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connectGoogle(): IContent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var User $user
|
||||||
|
*/
|
||||||
|
$user = \Container::$request->user();
|
||||||
|
if (!$user->checkPassword(\Container::$request->post('password'))) {
|
||||||
|
return new JsonContent([
|
||||||
|
'error' => [
|
||||||
|
'errorText' => 'The given password is wrong.'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$googleUserData = \Container::$request->session()->get('google_user_data');
|
||||||
|
$user->setGoogleSub($googleUserData['sub']);
|
||||||
|
\Container::$persistentDataManager->saveToDb($user);
|
||||||
|
|
||||||
|
return new JsonContent(['success' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGoogleDisconnectConfirm(): IContent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var User $user
|
||||||
|
*/
|
||||||
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
|
return new HtmlContent('account/google_disconnect', [
|
||||||
|
'success' => true,
|
||||||
|
'userEmail' => $user->getEmail()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnectGoogle(): IContent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var User $user
|
||||||
|
*/
|
||||||
|
$user = \Container::$request->user();
|
||||||
|
if (!$user->checkPassword(\Container::$request->post('password'))) {
|
||||||
|
return new JsonContent([
|
||||||
|
'error' => [
|
||||||
|
'errorText' => 'The given password is wrong.'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->setGoogleSub(null);
|
||||||
|
\Container::$persistentDataManager->saveToDb($user);
|
||||||
|
|
||||||
|
return new JsonContent(['success' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
public function getGoogleAuthenticateRedirect(): IRedirect
|
public function getGoogleAuthenticateRedirect(): IRedirect
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var User $user
|
* @var User $user
|
||||||
*/
|
*/
|
||||||
$user = $this->request->user();
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
$state = bin2hex(random_bytes(16));
|
$state = bin2hex(random_bytes(16));
|
||||||
$nonce = bin2hex(random_bytes(16));
|
$nonce = bin2hex(random_bytes(16));
|
||||||
|
|
||||||
$this->request->session()->set('oauth_state', $state);
|
\Container::$request->session()->set('oauth_state', $state);
|
||||||
$this->request->session()->set('oauth_nonce', $nonce);
|
\Container::$request->session()->set('oauth_nonce', $nonce);
|
||||||
|
|
||||||
$oAuth = new GoogleOAuth(new Request());
|
$oAuth = new GoogleOAuth(new Request());
|
||||||
|
|
||||||
$url = $oAuth->getDialogUrl(
|
$url = $oAuth->getDialogUrl(
|
||||||
$state,
|
$state,
|
||||||
$this->request->getBase() . '/' . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(),
|
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(),
|
||||||
$nonce,
|
$nonce,
|
||||||
$user->getEmail()
|
$user->getEmail()
|
||||||
);
|
);
|
||||||
@ -91,16 +211,16 @@ class UserController implements IAuthenticationRequired
|
|||||||
/**
|
/**
|
||||||
* @var User $user
|
* @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]);
|
return new HtmlContent('account/google_authenticate', ['success' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$oAuth = new GoogleOAuth(new Request());
|
$oAuth = new GoogleOAuth(new Request());
|
||||||
$tokenData = $oAuth->getToken(
|
$tokenData = $oAuth->getToken(
|
||||||
$this->request->query('code'),
|
\Container::$request->query('code'),
|
||||||
$this->request->getBase() . '/' . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink()
|
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isset($tokenData['id_token'])) {
|
if (!isset($tokenData['id_token'])) {
|
||||||
@ -110,7 +230,7 @@ class UserController implements IAuthenticationRequired
|
|||||||
$jwtParser = new JwtParser($tokenData['id_token']);
|
$jwtParser = new JwtParser($tokenData['id_token']);
|
||||||
$idToken = $jwtParser->getPayload();
|
$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]);
|
return new HtmlContent('account/google_authenticate', ['success' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +242,7 @@ class UserController implements IAuthenticationRequired
|
|||||||
}
|
}
|
||||||
|
|
||||||
$authenticatedWithGoogleUntil = new DateTime('+45 seconds');
|
$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', [
|
return new HtmlContent('account/google_authenticate', [
|
||||||
'success' => true,
|
'success' => true,
|
||||||
@ -135,7 +255,7 @@ class UserController implements IAuthenticationRequired
|
|||||||
/**
|
/**
|
||||||
* @var User $user
|
* @var User $user
|
||||||
*/
|
*/
|
||||||
$user = $this->request->user();
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
return new HtmlContent('account/delete', ['user' => $user->toArray()]);
|
return new HtmlContent('account/delete', ['user' => $user->toArray()]);
|
||||||
}
|
}
|
||||||
@ -145,19 +265,49 @@ class UserController implements IAuthenticationRequired
|
|||||||
/**
|
/**
|
||||||
* @var User $user
|
* @var User $user
|
||||||
*/
|
*/
|
||||||
$user = $this->request->user();
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
if (!$this->confirmUserIdentity(
|
if (!$this->confirmUserIdentity(
|
||||||
$user,
|
$user,
|
||||||
$this->request->session()->get('authenticated_with_google_until'),
|
\Container::$request->session()->get('authenticated_with_google_until'),
|
||||||
$this->request->post('password'),
|
\Container::$request->post('password'),
|
||||||
$error
|
$error
|
||||||
)) {
|
)) {
|
||||||
return new JsonContent(['error' => ['errorText' => $error]]);
|
return new JsonContent(['error' => ['errorText' => $error]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($this->request->post('password_new')) > 0) {
|
$newEmail = \Container::$request->post('email');
|
||||||
if (strlen($this->request->post('password_new')) < 6) {
|
if ($newEmail !== $user->getEmail()) {
|
||||||
|
if (!filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'The given email address is not valid.']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->userRepository->getByEmail($newEmail) !== null) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'The given email address belongs to another account.']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->setEmail($newEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newUsername = \Container::$request->post('username');
|
||||||
|
if ($newUsername !== $user->getUsername()) {
|
||||||
|
if (strlen($newUsername) == 0) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'Username cannot be empty.']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^[a-zA-Z0-9_\-\.]+$/', $newUsername) !== 1) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'Username can contain only english letters, digits, - (hyphen), . (dot), _ (underscore).']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->userRepository->getByUsername($newUsername) !== null) {
|
||||||
|
return new JsonContent(['error' => ['errorText' => 'The given username is already taken.']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->setUsername($newUsername);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(\Container::$request->post('password_new')) > 0) {
|
||||||
|
if (strlen(\Container::$request->post('password_new')) < 6) {
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'The given new password is too short. Please choose a password that is at least 6 characters long!'
|
'errorText' => 'The given new password is too short. Please choose a password that is at least 6 characters long!'
|
||||||
@ -165,7 +315,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([
|
return new JsonContent([
|
||||||
'error' => [
|
'error' => [
|
||||||
'errorText' => 'The given new passwords do not match.'
|
'errorText' => 'The given new passwords do not match.'
|
||||||
@ -173,12 +323,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]);
|
return new JsonContent(['success' => true]);
|
||||||
}
|
}
|
||||||
@ -188,46 +338,42 @@ class UserController implements IAuthenticationRequired
|
|||||||
/**
|
/**
|
||||||
* @var User $user
|
* @var User $user
|
||||||
*/
|
*/
|
||||||
$user = $this->request->user();
|
$user = \Container::$request->user();
|
||||||
|
|
||||||
if (!$this->confirmUserIdentity(
|
if (!$this->confirmUserIdentity(
|
||||||
$user,
|
$user,
|
||||||
$this->request->session()->get('authenticated_with_google_until'),
|
\Container::$request->session()->get('authenticated_with_google_until'),
|
||||||
$this->request->post('password'),
|
\Container::$request->post('password'),
|
||||||
$error
|
$error
|
||||||
)) {
|
)) {
|
||||||
return new JsonContent(['error' => ['errorText' => $error]]);
|
return new JsonContent(['error' => ['errorText' => $error]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
\Container::$dbConnection->startTransaction();
|
|
||||||
|
|
||||||
$userConfirmation = $this->userConfirmationRepository->getByUser($user);
|
$userConfirmation = $this->userConfirmationRepository->getByUser($user);
|
||||||
if ($userConfirmation !== null) {
|
if ($userConfirmation !== null) {
|
||||||
$this->pdm->deleteFromDb($userConfirmation);
|
\Container::$persistentDataManager->deleteFromDb($userConfirmation);
|
||||||
}
|
}
|
||||||
|
|
||||||
$userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user);
|
$userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user);
|
||||||
if ($userPasswordResetter !== null) {
|
if ($userPasswordResetter !== null) {
|
||||||
$this->pdm->deleteFromDb($userPasswordResetter);
|
\Container::$persistentDataManager->deleteFromDb($userPasswordResetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->userPlayedPlaceRepository->getAllByUser($user) as $userPlayedPlace) {
|
foreach ($this->userPlayedPlaceRepository->getAllByUser($user) as $userPlayedPlace) {
|
||||||
$this->pdm->deleteFromDb($userPlayedPlace);
|
\Container::$persistentDataManager->deleteFromDb($userPlayedPlace);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->userInChallengeRepository->getAllByUser($user) as $userInChallenge) {
|
foreach ($this->userInChallengeRepository->getAllByUser($user) as $userInChallenge) {
|
||||||
$this->pdm->deleteFromDb($userInChallenge);
|
\Container::$persistentDataManager->deleteFromDb($userInChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->guessRepository->getAllByUser($user) as $guess) {
|
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();
|
\Container::$request->session()->delete('authenticated_with_google_until');
|
||||||
|
|
||||||
$this->request->session()->delete('authenticated_with_google_until');
|
|
||||||
|
|
||||||
return new JsonContent(['success' => true]);
|
return new JsonContent(['success' => true]);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ use DateInterval;
|
|||||||
use DateTime;
|
use DateTime;
|
||||||
use SokoWeb\PersistentData\Model\Model;
|
use SokoWeb\PersistentData\Model\Model;
|
||||||
use SokoWeb\Http\Request;
|
use SokoWeb\Http\Request;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\Util\Geo\Position;
|
use MapGuesser\Util\Geo\Position;
|
||||||
use MapGuesser\Util\Panorama\Pov;
|
use MapGuesser\Util\Panorama\Pov;
|
||||||
|
|
||||||
@ -163,7 +162,7 @@ class Place extends Model
|
|||||||
$this->panoIdCached = $panoId;
|
$this->panoIdCached = $panoId;
|
||||||
$this->panoIdCachedTimestamp = new DateTime();
|
$this->panoIdCachedTimestamp = new DateTime();
|
||||||
|
|
||||||
(new PersistentDataManager())->saveToDb($this);
|
\Container::$persistentDataManager->saveToDb($this);
|
||||||
|
|
||||||
return $panoId;
|
return $panoId;
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,14 @@ class User extends Model implements IUser
|
|||||||
{
|
{
|
||||||
protected static string $table = 'users';
|
protected static string $table = 'users';
|
||||||
|
|
||||||
protected static array $fields = ['email', 'password', 'type', 'active', 'google_sub', 'created'];
|
protected static array $fields = ['email', 'username', 'password', 'type', 'active', 'google_sub', 'created'];
|
||||||
|
|
||||||
private static array $types = ['user', 'admin'];
|
private static array $types = ['user', 'admin'];
|
||||||
|
|
||||||
private string $email = '';
|
private string $email = '';
|
||||||
|
|
||||||
|
private string $username = '';
|
||||||
|
|
||||||
private ?string $password = null;
|
private ?string $password = null;
|
||||||
|
|
||||||
private string $type = 'user';
|
private string $type = 'user';
|
||||||
@ -29,6 +31,11 @@ class User extends Model implements IUser
|
|||||||
$this->email = $email;
|
$this->email = $email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setUsername(string $username): void
|
||||||
|
{
|
||||||
|
$this->username = $username;
|
||||||
|
}
|
||||||
|
|
||||||
public function setPassword(?string $hashedPassword): void
|
public function setPassword(?string $hashedPassword): void
|
||||||
{
|
{
|
||||||
$this->password = $hashedPassword;
|
$this->password = $hashedPassword;
|
||||||
@ -71,6 +78,11 @@ class User extends Model implements IUser
|
|||||||
return $this->email;
|
return $this->email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUsername(): string
|
||||||
|
{
|
||||||
|
return $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
public function getPassword(): ?string
|
public function getPassword(): ?string
|
||||||
{
|
{
|
||||||
return $this->password;
|
return $this->password;
|
||||||
@ -120,7 +132,7 @@ class User extends Model implements IUser
|
|||||||
|
|
||||||
public function getDisplayName(): string
|
public function getDisplayName(): string
|
||||||
{
|
{
|
||||||
return $this->email;
|
return $this->username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkPassword(string $password): bool
|
public function checkPassword(string $password): bool
|
||||||
|
@ -5,20 +5,12 @@ use SokoWeb\Database\Query\Select;
|
|||||||
use MapGuesser\PersistentData\Model\Challenge;
|
use MapGuesser\PersistentData\Model\Challenge;
|
||||||
use MapGuesser\PersistentData\Model\Place;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class ChallengeRepository
|
class ChallengeRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $challengeId): ?Challenge
|
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
|
public function getByToken(int $token): ?Challenge
|
||||||
@ -26,7 +18,7 @@ class ChallengeRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('token', '=', $token);
|
$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
|
public function getByTokenStr(string $token_str): ?Challenge
|
||||||
@ -48,9 +40,9 @@ class ChallengeRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('user_in_challenge', ['challenge', 'id'], '=', ['user_in_challenge', 'challenge_id']);
|
$select->innerJoin('user_in_challenge', ['challenge', 'id'], '=', ['user_in_challenge', 'challenge_id']);
|
||||||
$select->innerJoin('users', ['users', 'id'], '=', ['user_in_challenge', 'user_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
|
public function getAllByOwner(User $user): Generator
|
||||||
@ -58,18 +50,18 @@ class ChallengeRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('user_in_challenge', ['challenge', 'id'], '=', ['user_in_challenge', 'challenge_id']);
|
$select->innerJoin('user_in_challenge', ['challenge', 'id'], '=', ['user_in_challenge', 'challenge_id']);
|
||||||
$select->innerJoin('users', ['users', 'id'], '=', ['user_in_challenge', 'user_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());
|
||||||
$select->where('is_owner', '=', true);
|
$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
|
public function getAllByPlace(Place $place): Generator
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('place_in_challenge', ['challenges', 'id'], '=', ['place_in_challenge', 'challenge_id']);
|
$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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,23 +7,15 @@ use MapGuesser\PersistentData\Model\Guess;
|
|||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\PersistentData\Model\Place;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class GuessRepository
|
class GuessRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAllByUser(User $user): Generator
|
public function getAllByUser(User $user): Generator
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$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
|
public function getAllByUserAndChallenge(User $user, Challenge $challenge): Generator
|
||||||
@ -31,9 +23,9 @@ class GuessRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
|
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$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
|
public function getByUserAndPlaceInChallenge(User $user, Challenge $challenge, Place $place): ?Guess
|
||||||
@ -41,10 +33,10 @@ class GuessRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
|
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$select->where('user_id', '=', $user->getId());
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
|
||||||
$select->where('place_id', '=', $place->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
|
public function getAllInChallengeByUser(int $userId, Challenge $challenge): Generator
|
||||||
@ -52,46 +44,46 @@ class GuessRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
|
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
|
||||||
$select->where('user_id', '=', $userId);
|
$select->where('user_id', '=', $userId);
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$select->where(['place_in_challenge', 'challenge_id'], '=', $challenge->getId());
|
||||||
$select->orderBy('round');
|
$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
|
public function getAllInChallenge(Challenge $challenge, array $withRelations = []): Generator
|
||||||
{
|
{
|
||||||
if (count($withRelations)) {
|
if (count($withRelations)) {
|
||||||
$necessaryRelations = [PlaceInChallenge::class];
|
$necessaryRelations = ['place_in_challenge'];
|
||||||
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
|
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
|
||||||
}
|
}
|
||||||
|
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$select->where(['guesses__place_in_challenge', 'challenge_id'], '=', $challenge->getId());
|
||||||
$select->orderBy('round');
|
$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
|
public function getAllInChallengeByRound(int $round, Challenge $challenge, array $withRelations = []): Generator
|
||||||
{
|
{
|
||||||
if (count($withRelations)) {
|
if (count($withRelations)) {
|
||||||
$necessaryRelations = [PlaceInChallenge::class];
|
$necessaryRelations = ['place_in_challenge'];
|
||||||
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
|
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
|
||||||
}
|
}
|
||||||
|
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$select->where(['guesses__place_in_challenge', 'challenge_id'], '=', $challenge->getId());
|
||||||
$select->where('round', '=', $round);
|
$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
|
public function getAllByPlace(Place $place): Generator
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
|
$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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,20 +4,12 @@ use SokoWeb\Database\Query\Select;
|
|||||||
use MapGuesser\PersistentData\Model\Challenge;
|
use MapGuesser\PersistentData\Model\Challenge;
|
||||||
use MapGuesser\PersistentData\Model\Map;
|
use MapGuesser\PersistentData\Model\Map;
|
||||||
use MapGuesser\PersistentData\Model\Place;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class MapRepository
|
class MapRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $mapId): ?Map
|
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
|
public function getByPlace(Place $place): ?Map
|
||||||
@ -30,9 +22,9 @@ class MapRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('places', ['maps', 'id'], '=', ['places', 'map_id']);
|
$select->innerJoin('places', ['maps', 'id'], '=', ['places', 'map_id']);
|
||||||
$select->innerJoin('place_in_challenge', ['places', 'id'], '=', ['place_in_challenge', 'place_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);
|
$select->limit(1);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, Map::class);
|
return \Container::$persistentDataManager->selectFromDb($select, Map::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,20 +4,12 @@ use DateTime;
|
|||||||
use Generator;
|
use Generator;
|
||||||
use SokoWeb\Database\Query\Select;
|
use SokoWeb\Database\Query\Select;
|
||||||
use MapGuesser\PersistentData\Model\MultiRoom;
|
use MapGuesser\PersistentData\Model\MultiRoom;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class MultiRoomRepository
|
class MultiRoomRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $id): ?MultiRoom
|
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
|
public function getByRoomId(string $roomId): ?MultiRoom
|
||||||
@ -25,7 +17,7 @@ class MultiRoomRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('room_id', '=', $roomId);
|
$select->where('room_id', '=', $roomId);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, MultiRoom::class);
|
return \Container::$persistentDataManager->selectFromDb($select, MultiRoom::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllExpired(): Generator
|
public function getAllExpired(): Generator
|
||||||
@ -33,6 +25,6 @@ class MultiRoomRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('updated', '<', (new DateTime('-7 day'))->format('Y-m-d H:i:s'));
|
$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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,15 @@ use SokoWeb\Database\Query\Select;
|
|||||||
use MapGuesser\PersistentData\Model\Challenge;
|
use MapGuesser\PersistentData\Model\Challenge;
|
||||||
use MapGuesser\PersistentData\Model\Place;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
use MapGuesser\PersistentData\Model\PlaceInChallenge;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class PlaceInChallengeRepository
|
class PlaceInChallengeRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAllByPlace(Place $place, array $withRelations = []) : Generator
|
public function getAllByPlace(Place $place, array $withRelations = []) : Generator
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('place_id', '=', $place->getId());
|
$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
|
public function getAllByChallenge(Challenge $challenge) : Generator
|
||||||
@ -29,7 +21,7 @@ class PlaceInChallengeRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$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
|
public function getByPlaceAndChallenge(Place $place, Challenge $challenge) : ?PlaceInChallenge
|
||||||
@ -38,7 +30,7 @@ class PlaceInChallengeRepository
|
|||||||
$select->where('place_id', '=', $place->getId());
|
$select->where('place_id', '=', $place->getId());
|
||||||
$select->where('challenge_id', '=', $challenge->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
|
public function getByRoundInChallenge(int $round, Challenge $challenge, array $withRelations = []): ?PlaceInChallenge
|
||||||
@ -48,6 +40,6 @@ class PlaceInChallengeRepository
|
|||||||
$select->orderBy('round');
|
$select->orderBy('round');
|
||||||
$select->limit(1, $round);
|
$select->limit(1, $round);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, PlaceInChallenge::class, true, $withRelations);
|
return \Container::$persistentDataManager->selectFromDb($select, PlaceInChallenge::class, true, $withRelations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,12 @@ use SokoWeb\Database\Query\Select;
|
|||||||
use MapGuesser\PersistentData\Model\Challenge;
|
use MapGuesser\PersistentData\Model\Challenge;
|
||||||
use MapGuesser\PersistentData\Model\Map;
|
use MapGuesser\PersistentData\Model\Map;
|
||||||
use MapGuesser\PersistentData\Model\Place;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class PlaceRepository
|
class PlaceRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $placeId): ?Place
|
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
|
public function getAllForMap(Map $map): Generator
|
||||||
@ -26,7 +18,7 @@ class PlaceRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('map_id', '=', $map->getId());
|
$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
|
//TODO: use Map and User instead of id
|
||||||
@ -99,7 +91,7 @@ class PlaceRepository
|
|||||||
$select->where('id', 'NOT IN', $exclude);
|
$select->where('id', 'NOT IN', $exclude);
|
||||||
$select->limit(1, $randomOffset);
|
$select->limit(1, $randomOffset);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, Place::class);
|
return \Container::$persistentDataManager->selectFromDb($select, Place::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never visited places
|
// Never visited places
|
||||||
@ -117,8 +109,8 @@ class PlaceRepository
|
|||||||
// count the places never visited
|
// count the places never visited
|
||||||
$selectUnvisited = new Select(\Container::$dbConnection, 'places');
|
$selectUnvisited = new Select(\Container::$dbConnection, 'places');
|
||||||
$selectUnvisited->leftJoin($selectPlacesByCurrentUser, ['places', 'id'], '=', ['places_by_current_user', 'place_id']);
|
$selectUnvisited->leftJoin($selectPlacesByCurrentUser, ['places', 'id'], '=', ['places_by_current_user', 'place_id']);
|
||||||
$selectUnvisited->where('map_id', '=', $mapId);
|
$selectUnvisited->where(['places', 'map_id'], '=', $mapId);
|
||||||
$selectUnvisited->where('last_time', '=', null);
|
$selectUnvisited->where(['places_by_current_user', 'last_time'], '=', null);
|
||||||
$numberOfUnvisitedPlaces = $selectUnvisited->count();
|
$numberOfUnvisitedPlaces = $selectUnvisited->count();
|
||||||
|
|
||||||
// look for as many new places as possible but maximum $n
|
// 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
|
// count places that were visited at least once
|
||||||
$selectOldPlaces = new Select(\Container::$dbConnection, 'places');
|
$selectOldPlaces = new Select(\Container::$dbConnection, 'places');
|
||||||
$selectOldPlaces->innerJoin($selectPlacesByCurrentUser, ['places', 'id'], '=', ['places_by_current_user', 'place_id']);
|
$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();
|
$numberOfOldPlaces = $selectOldPlaces->count();
|
||||||
|
|
||||||
// set order by datetime, oldest first
|
// 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
|
// selection algorithm with preference (weighting) for older places using Box-Muller transform
|
||||||
$pickGaussianRandomInt = function($numberOfPlaces) {
|
$pickGaussianRandomInt = function($numberOfPlaces) {
|
||||||
@ -182,21 +174,21 @@ class PlaceRepository
|
|||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('place_in_challenge', ['places', 'id'], '=', ['place_in_challenge', 'place_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->orderBy('round');
|
$select->orderBy(['place_in_challenge', 'round']);
|
||||||
$select->limit(1, $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
|
public function getAllInChallenge(Challenge $challenge): Generator
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->innerJoin('place_in_challenge', ['places', 'id'], '=', ['place_in_challenge', 'place_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->orderBy('round');
|
$select->orderBy(['place_in_challenge', 'round']);
|
||||||
|
|
||||||
yield from $this->pdm->selectMultipleFromDb($select, Place::class);
|
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, Place::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,12 @@
|
|||||||
use SokoWeb\Database\Query\Select;
|
use SokoWeb\Database\Query\Select;
|
||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\PersistentData\Model\UserConfirmation;
|
use MapGuesser\PersistentData\Model\UserConfirmation;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class UserConfirmationRepository
|
class UserConfirmationRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $userConfirmationId): ?UserConfirmation
|
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
|
public function getByToken(string $token): ?UserConfirmation
|
||||||
@ -24,7 +16,7 @@ class UserConfirmationRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('token', '=', $token);
|
$select->where('token', '=', $token);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, UserConfirmation::class);
|
return \Container::$persistentDataManager->selectFromDb($select, UserConfirmation::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByUser(User $user): ?UserConfirmation
|
public function getByUser(User $user): ?UserConfirmation
|
||||||
@ -32,6 +24,6 @@ class UserConfirmationRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$select->where('user_id', '=', $user->getId());
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, UserConfirmation::class);
|
return \Container::$persistentDataManager->selectFromDb($select, UserConfirmation::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,15 @@ use SokoWeb\Database\Query\Select;
|
|||||||
use MapGuesser\PersistentData\Model\Challenge;
|
use MapGuesser\PersistentData\Model\Challenge;
|
||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\PersistentData\Model\UserInChallenge;
|
use MapGuesser\PersistentData\Model\UserInChallenge;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class UserInChallengeRepository
|
class UserInChallengeRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAllByUser(User $user) : Generator
|
public function getAllByUser(User $user) : Generator
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$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
|
public function getAllByChallenge(Challenge $challenge) : Generator
|
||||||
@ -29,7 +21,7 @@ class UserInChallengeRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$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
|
public function getAllByChallengeWithUsers(Challenge $challenge) : Generator
|
||||||
@ -37,7 +29,7 @@ class UserInChallengeRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$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
|
public function getByUserIdAndChallenge(int $userId, Challenge $challenge): ?UserInChallenge
|
||||||
@ -46,13 +38,13 @@ class UserInChallengeRepository
|
|||||||
$select->where('user_id', '=', $userId);
|
$select->where('user_id', '=', $userId);
|
||||||
$select->where('challenge_id', '=', $challenge->getId());
|
$select->where('challenge_id', '=', $challenge->getId());
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, UserInChallenge::class);
|
return \Container::$persistentDataManager->selectFromDb($select, UserInChallenge::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByUserIdAndToken(int $userId, string $token_str, array $withRelations = []): ?UserInChallenge
|
public function getByUserIdAndToken(int $userId, string $token_str, array $withRelations = []): ?UserInChallenge
|
||||||
{
|
{
|
||||||
if (count($withRelations)) {
|
if (count($withRelations)) {
|
||||||
$necessaryRelations = [Challenge::class];
|
$necessaryRelations = ['challange'];
|
||||||
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
|
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,9 +57,9 @@ class UserInChallengeRepository
|
|||||||
|
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('user_id', '=', $userId);
|
$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
|
public function isUserParticipatingInChallenge(int $userId, Challenge $challenge): bool
|
||||||
|
@ -5,20 +5,12 @@ use Generator;
|
|||||||
use SokoWeb\Database\Query\Select;
|
use SokoWeb\Database\Query\Select;
|
||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\PersistentData\Model\UserPasswordResetter;
|
use MapGuesser\PersistentData\Model\UserPasswordResetter;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class UserPasswordResetterRepository
|
class UserPasswordResetterRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $userConfirmationId): ?UserPasswordResetter
|
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
|
public function getByToken(string $token): ?UserPasswordResetter
|
||||||
@ -26,7 +18,7 @@ class UserPasswordResetterRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('token', '=', $token);
|
$select->where('token', '=', $token);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, UserPasswordResetter::class);
|
return \Container::$persistentDataManager->selectFromDb($select, UserPasswordResetter::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByUser(User $user): ?UserPasswordResetter
|
public function getByUser(User $user): ?UserPasswordResetter
|
||||||
@ -34,7 +26,7 @@ class UserPasswordResetterRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$select->where('user_id', '=', $user->getId());
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, UserPasswordResetter::class);
|
return \Container::$persistentDataManager->selectFromDb($select, UserPasswordResetter::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllExpired(): Generator
|
public function getAllExpired(): Generator
|
||||||
@ -42,6 +34,6 @@ class UserPasswordResetterRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('expires', '<', (new DateTime())->format('Y-m-d H:i:s'));
|
$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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,15 @@ use SokoWeb\Database\Query\Select;
|
|||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use MapGuesser\PersistentData\Model\Place;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use MapGuesser\PersistentData\Model\UserPlayedPlace;
|
use MapGuesser\PersistentData\Model\UserPlayedPlace;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class UserPlayedPlaceRepository
|
class UserPlayedPlaceRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getByUser(User $user): Generator
|
public function getByUser(User $user): Generator
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$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
|
public function getAllByPlace(Place $place): Generator
|
||||||
@ -29,7 +21,7 @@ class UserPlayedPlaceRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('place_id', '=', $place->getId());
|
$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
|
public function getAllByUser(User $user) : Generator
|
||||||
@ -37,7 +29,7 @@ class UserPlayedPlaceRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('user_id', '=', $user->getId());
|
$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
|
public function getByUserIdAndPlaceId(int $userId, int $placeId) : ?UserPlayedPlace
|
||||||
@ -46,6 +38,6 @@ class UserPlayedPlaceRepository
|
|||||||
$select->where('user_id', '=', $userId);
|
$select->where('user_id', '=', $userId);
|
||||||
$select->where('place_id', '=', $placeId);
|
$select->where('place_id', '=', $placeId);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, UserPlayedPlace::class);
|
return \Container::$persistentDataManager->selectFromDb($select, UserPlayedPlace::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,12 @@ use SokoWeb\Interfaces\Repository\IUserRepository;
|
|||||||
use SokoWeb\Database\Query\Select;
|
use SokoWeb\Database\Query\Select;
|
||||||
use MapGuesser\PersistentData\Model\Guess;
|
use MapGuesser\PersistentData\Model\Guess;
|
||||||
use MapGuesser\PersistentData\Model\User;
|
use MapGuesser\PersistentData\Model\User;
|
||||||
use SokoWeb\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class UserRepository implements IUserRepository
|
class UserRepository implements IUserRepository
|
||||||
{
|
{
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $userId): ?User
|
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
|
public function getByEmail(string $email): ?User
|
||||||
@ -27,7 +19,24 @@ class UserRepository implements IUserRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('email', '=', $email);
|
$select->where('email', '=', $email);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, User::class);
|
return \Container::$persistentDataManager->selectFromDb($select, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getByUsername(string $username): ?User
|
||||||
|
{
|
||||||
|
$select = new Select(\Container::$dbConnection);
|
||||||
|
$select->where('username', '=', $username);
|
||||||
|
|
||||||
|
return \Container::$persistentDataManager->selectFromDb($select, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getByEmailOrUsername(string $emailOrUsername): ?User
|
||||||
|
{
|
||||||
|
if (filter_var($emailOrUsername, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return $this->getByEmail($emailOrUsername);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getByUsername($emailOrUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByGoogleSub(string $sub): ?User
|
public function getByGoogleSub(string $sub): ?User
|
||||||
@ -35,7 +44,7 @@ class UserRepository implements IUserRepository
|
|||||||
$select = new Select(\Container::$dbConnection);
|
$select = new Select(\Container::$dbConnection);
|
||||||
$select->where('google_sub', '=', $sub);
|
$select->where('google_sub', '=', $sub);
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, User::class);
|
return \Container::$persistentDataManager->selectFromDb($select, User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllInactiveExpired(): Generator
|
public function getAllInactiveExpired(): Generator
|
||||||
@ -44,7 +53,7 @@ class UserRepository implements IUserRepository
|
|||||||
$select->where('active', '=', false);
|
$select->where('active', '=', false);
|
||||||
$select->where('created', '<', (new DateTime('-1 day'))->format('Y-m-d H:i:s'));
|
$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
|
public function getByGuess(Guess $guess): ?User
|
||||||
|
247
src/Util/UsernameGenerator.php
Normal file
247
src/Util/UsernameGenerator.php
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
<?php namespace MapGuesser\Util;
|
||||||
|
|
||||||
|
class UsernameGenerator
|
||||||
|
{
|
||||||
|
const ADJECTIVES = [
|
||||||
|
'abundant',
|
||||||
|
'agile',
|
||||||
|
'alluring',
|
||||||
|
'ample',
|
||||||
|
'adorable',
|
||||||
|
'angry',
|
||||||
|
'anxious',
|
||||||
|
'astonishing',
|
||||||
|
'beautiful',
|
||||||
|
'big',
|
||||||
|
'bitter',
|
||||||
|
'blissful',
|
||||||
|
'blue',
|
||||||
|
'brave',
|
||||||
|
'bright',
|
||||||
|
'brilliant',
|
||||||
|
'busy',
|
||||||
|
'calm',
|
||||||
|
'captivating',
|
||||||
|
'careful',
|
||||||
|
'charming',
|
||||||
|
'cheerful',
|
||||||
|
'clumsy',
|
||||||
|
'colorful',
|
||||||
|
'confused',
|
||||||
|
'cooperative',
|
||||||
|
'courageous',
|
||||||
|
'cozy',
|
||||||
|
'crispy',
|
||||||
|
'curious',
|
||||||
|
'dazzling',
|
||||||
|
'delightful',
|
||||||
|
'determined',
|
||||||
|
'eager',
|
||||||
|
'elegant',
|
||||||
|
'enchanting',
|
||||||
|
'enthusiastic',
|
||||||
|
'exciting',
|
||||||
|
'exquisite',
|
||||||
|
'faithful',
|
||||||
|
'fancy',
|
||||||
|
'fearless',
|
||||||
|
'fierce',
|
||||||
|
'fluffy',
|
||||||
|
'fresh',
|
||||||
|
'friendly',
|
||||||
|
'frigid',
|
||||||
|
'funny',
|
||||||
|
'gentle',
|
||||||
|
'glorious',
|
||||||
|
'graceful',
|
||||||
|
'grateful',
|
||||||
|
'happy',
|
||||||
|
'harmonious',
|
||||||
|
'healthy',
|
||||||
|
'helpful',
|
||||||
|
'honest',
|
||||||
|
'hopeful',
|
||||||
|
'hot',
|
||||||
|
'humble',
|
||||||
|
'hungry',
|
||||||
|
'impressive',
|
||||||
|
'infamous',
|
||||||
|
'innocent',
|
||||||
|
'intense',
|
||||||
|
'jolly',
|
||||||
|
'joyful',
|
||||||
|
'kind',
|
||||||
|
'lively',
|
||||||
|
'lonely',
|
||||||
|
'lovely',
|
||||||
|
'lucky',
|
||||||
|
'mysterious',
|
||||||
|
'naughty',
|
||||||
|
'nervous',
|
||||||
|
'nutritious',
|
||||||
|
'obedient',
|
||||||
|
'peaceful',
|
||||||
|
'playful',
|
||||||
|
'polite',
|
||||||
|
'powerful',
|
||||||
|
'precious',
|
||||||
|
'proud',
|
||||||
|
'radiant',
|
||||||
|
'reckless',
|
||||||
|
'reliable',
|
||||||
|
'rich',
|
||||||
|
'romantic',
|
||||||
|
'rough',
|
||||||
|
'sad',
|
||||||
|
'scary',
|
||||||
|
'sensitive',
|
||||||
|
'shiny',
|
||||||
|
'silky',
|
||||||
|
'sincere',
|
||||||
|
'sleepy',
|
||||||
|
'smart',
|
||||||
|
'sneaky',
|
||||||
|
'soft',
|
||||||
|
'sparkling',
|
||||||
|
'splendid',
|
||||||
|
'strong',
|
||||||
|
'stubborn',
|
||||||
|
'sweet',
|
||||||
|
'tender',
|
||||||
|
'thoughtful',
|
||||||
|
'thrilling',
|
||||||
|
'timid',
|
||||||
|
'tranquil',
|
||||||
|
'trustworthy',
|
||||||
|
'unique',
|
||||||
|
'vibrant',
|
||||||
|
'victorious',
|
||||||
|
'warm',
|
||||||
|
'wise',
|
||||||
|
'witty',
|
||||||
|
'wonderful',
|
||||||
|
'worried',
|
||||||
|
'zealous'
|
||||||
|
];
|
||||||
|
|
||||||
|
const NOUNS = [
|
||||||
|
'airplane',
|
||||||
|
'ant',
|
||||||
|
'apple',
|
||||||
|
'aquarium',
|
||||||
|
'backpack',
|
||||||
|
'banana',
|
||||||
|
'bear',
|
||||||
|
'bee',
|
||||||
|
'camera',
|
||||||
|
'car',
|
||||||
|
'cat',
|
||||||
|
'chocolate',
|
||||||
|
'desk',
|
||||||
|
'diamond',
|
||||||
|
'dog',
|
||||||
|
'dolphin',
|
||||||
|
'duck',
|
||||||
|
'egg',
|
||||||
|
'eiffeltower',
|
||||||
|
'elephant',
|
||||||
|
'fire',
|
||||||
|
'flower',
|
||||||
|
'forest',
|
||||||
|
'fork',
|
||||||
|
'fox',
|
||||||
|
'galaxy',
|
||||||
|
'giraffe',
|
||||||
|
'globe',
|
||||||
|
'guitar',
|
||||||
|
'hammer',
|
||||||
|
'hamster',
|
||||||
|
'hat',
|
||||||
|
'house',
|
||||||
|
'icecream',
|
||||||
|
'iguana',
|
||||||
|
'island',
|
||||||
|
'jacket',
|
||||||
|
'jaguar',
|
||||||
|
'jellyfish',
|
||||||
|
'jigsaw',
|
||||||
|
'kangaroo',
|
||||||
|
'key',
|
||||||
|
'kite',
|
||||||
|
'koala',
|
||||||
|
'lamp',
|
||||||
|
'lighthouse',
|
||||||
|
'lightning',
|
||||||
|
'lion',
|
||||||
|
'llama',
|
||||||
|
'moon',
|
||||||
|
'mountain',
|
||||||
|
'mouse',
|
||||||
|
'necklace',
|
||||||
|
'nest',
|
||||||
|
'newt',
|
||||||
|
'notebook',
|
||||||
|
'ocean',
|
||||||
|
'octopus',
|
||||||
|
'orchid',
|
||||||
|
'owl',
|
||||||
|
'panda',
|
||||||
|
'pencil',
|
||||||
|
'penguin',
|
||||||
|
'piano',
|
||||||
|
'queen',
|
||||||
|
'quilt',
|
||||||
|
'quokka',
|
||||||
|
'rabbit',
|
||||||
|
'rainbow',
|
||||||
|
'robot',
|
||||||
|
'ship',
|
||||||
|
'snake',
|
||||||
|
'statue',
|
||||||
|
'sun',
|
||||||
|
'sunflower',
|
||||||
|
'table',
|
||||||
|
'telescope',
|
||||||
|
'tiger',
|
||||||
|
'tree',
|
||||||
|
'turtle',
|
||||||
|
'uakari',
|
||||||
|
'umbrella',
|
||||||
|
'unicorn',
|
||||||
|
'universe',
|
||||||
|
'vase',
|
||||||
|
'violin',
|
||||||
|
'volcano',
|
||||||
|
'vulture',
|
||||||
|
'wallaby',
|
||||||
|
'waterfall',
|
||||||
|
'whale',
|
||||||
|
'xray',
|
||||||
|
'xylophone',
|
||||||
|
'yacht',
|
||||||
|
'yak',
|
||||||
|
'yarn',
|
||||||
|
'yeti',
|
||||||
|
'zebra',
|
||||||
|
'zeppelin',
|
||||||
|
'zucchini',
|
||||||
|
];
|
||||||
|
|
||||||
|
function generate(): string
|
||||||
|
{
|
||||||
|
$numberOfAdjectives = count(self::ADJECTIVES);
|
||||||
|
$numberOfNouns = count(self::NOUNS);
|
||||||
|
|
||||||
|
$firstAdjective = self::ADJECTIVES[mt_rand(0, $numberOfAdjectives - 1)];
|
||||||
|
do {
|
||||||
|
$secondAdjective = self::ADJECTIVES[mt_rand(0, $numberOfAdjectives - 1)];
|
||||||
|
} while ($firstAdjective === $secondAdjective);
|
||||||
|
$noun = self::NOUNS[mt_rand(0, $numberOfNouns - 1)];
|
||||||
|
|
||||||
|
$firstAdjective = ucfirst($firstAdjective);
|
||||||
|
$secondAdjective = ucfirst($secondAdjective);
|
||||||
|
$noun = ucfirst($noun);
|
||||||
|
|
||||||
|
return $firstAdjective . $secondAdjective . $noun;
|
||||||
|
}
|
||||||
|
}
|
23
tests/Util/UsernameGeneratorTest.php
Normal file
23
tests/Util/UsernameGeneratorTest.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php namespace MapGuesser\Tests\Util;
|
||||||
|
|
||||||
|
use MapGuesser\Util\UsernameGenerator;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
final class UsernameGeneratorTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testCanGenerateRandomUsernameFromComponents(): void
|
||||||
|
{
|
||||||
|
$generator = new UsernameGenerator();
|
||||||
|
$parts = $this->getUsernameParts($generator->generate());
|
||||||
|
|
||||||
|
$this->assertEquals(3, count($parts));
|
||||||
|
$this->assertContains($parts[0], UsernameGenerator::ADJECTIVES);
|
||||||
|
$this->assertContains($parts[1], UsernameGenerator::ADJECTIVES);
|
||||||
|
$this->assertContains($parts[2], UsernameGenerator::NOUNS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUsernameParts(string $username): array
|
||||||
|
{
|
||||||
|
return explode('-', strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $username)));
|
||||||
|
}
|
||||||
|
}
|
@ -5,16 +5,16 @@
|
|||||||
@section(main)
|
@section(main)
|
||||||
<h2>Account</h2>
|
<h2>Account</h2>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<form id="accountForm" action="/account" method="post" data-observe-inputs="password_new,password_new_confirm">
|
<form id="accountForm" action="/account" method="post" data-reload-on-success="true" data-observe-inputs="email,username,password_new,password_new_confirm">
|
||||||
<?php if ($user['password'] !== null && $user['google_sub'] !== null): ?>
|
<?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>
|
<p class="justify small">Please confirm your identity with your password or with Google to modify your account.</p>
|
||||||
<div class="inputWithButton">
|
<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>
|
--><button id="authenticateWithGoogleButton" class="yellow" type="button">Google</button>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($user['password'] !== null): ?>
|
<?php elseif ($user['password'] !== null): ?>
|
||||||
<p class="justify small">Please confirm your identity with your password to modify your account.</p>
|
<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): ?>
|
<?php elseif ($user['google_sub'] !== null): ?>
|
||||||
<p class="justify small">Please confirm your identity with Google to modify your account.</p>
|
<p class="justify small">Please confirm your identity with Google to modify your account.</p>
|
||||||
<div class="inputWithButton">
|
<div class="inputWithButton">
|
||||||
@ -23,16 +23,23 @@
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<hr>
|
<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" autocomplete="username" value="<?= $user['email'] ?>">
|
||||||
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" value="<?= $user['email'] ?>" disabled>
|
<input type="username" class="text big fullWidth marginTop" name="username" placeholder="Username" value="<?= $user['username'] ?>">
|
||||||
<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" placeholder="New password" autocomplete="new-password" minlength="6">
|
||||||
<input type="password" class="text big fullWidth marginTop" name="password_new_confirm" placeholder="New password confirmation" 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>
|
<p id="accountFormError" class="formError justify marginTop"></p>
|
||||||
<div class="right marginTop">
|
<div class="right marginTop">
|
||||||
<button type="submit" name="submit" disabled>Save</button>
|
<button type="submit" name="submit_button" disabled>Save</button>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="center">
|
<div class="center" style="font-size: 0;">
|
||||||
|
<?php if ($user['google_sub'] === null): ?>
|
||||||
|
<a class="button yellow marginRight" href="<?= Container::$routeCollection->getRoute('account.googleConnect')->generateLink() ?>" title="Connect with Google">Connect with Google</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php if ($user['password'] !== null): ?>
|
||||||
|
<a class="button yellow marginRight" href="<?= Container::$routeCollection->getRoute('account.googleDisconnect')->generateLink() ?>" title="Disconnect from Google">Disconnect from Google</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endif; ?>
|
||||||
<a class="button red" href="/account/delete" title="Delete account">Delete account</a>
|
<a class="button red" href="/account/delete" title="Delete account">Delete account</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -7,15 +7,16 @@
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
<form id="deleteAccountForm" action="/account/delete" method="post" data-redirect-on-success="/">
|
<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>
|
<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): ?>
|
<?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>
|
<p class="justify small">Please confirm your identity with your password or with Google to delete your account.</p>
|
||||||
<div class="inputWithButton">
|
<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>
|
--><button id="authenticateWithGoogleButton" class="yellow" type="button">Google</button>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($user['password'] !== null): ?>
|
<?php elseif ($user['password'] !== null): ?>
|
||||||
<p class="justify small">Please confirm your identity with your password to delete your account.</p>
|
<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): ?>
|
<?php elseif ($user['google_sub'] !== null): ?>
|
||||||
<p class="justify small">Please confirm your identity with Google to delete your account.</p>
|
<p class="justify small">Please confirm your identity with Google to delete your account.</p>
|
||||||
<div class="inputWithButton">
|
<div class="inputWithButton">
|
||||||
@ -25,7 +26,7 @@
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<p id="deleteAccountFormError" class="formError justify marginTop"></p>
|
<p id="deleteAccountFormError" class="formError justify marginTop"></p>
|
||||||
<div class="right marginTop">
|
<div class="right marginTop">
|
||||||
<button class="red marginRight" type="submit" name="submit">Delete account</button><!--
|
<button class="red marginRight" type="submit" name="submit_button">Delete account</button><!--
|
||||||
--><a class="button gray marginTop" href="/account" title="Back to account">Cancel</a>
|
--><a class="button gray marginTop" href="/account" title="Back to account">Cancel</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
22
views/account/google_connect.php
Normal file
22
views/account/google_connect.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
@extends(templates/layout_normal)
|
||||||
|
|
||||||
|
@section(main)
|
||||||
|
<h2>Connect with Google</h2>
|
||||||
|
<div class="box compactBox">
|
||||||
|
<?php if (!$success): ?>
|
||||||
|
<p class="error justify"><?= $error ?></p>
|
||||||
|
<?php else: ?>
|
||||||
|
<form id="connectGoogleForm" action="<?= Container::$routeCollection->getRoute('account.googleConnect-action')->generateLink() ?>" method="post" data-redirect-on-success="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>">
|
||||||
|
<p class="justify marginBottom">Your account will be connected with the following Google account: <b><?= $googleAccount ?></b></p>
|
||||||
|
<input type="email" style="display: none;" name="email" autocomplete="username" value="<?= $userEmail ?>">
|
||||||
|
<p class="formLabel marginTop">Password</p>
|
||||||
|
<input type="password" class="text big fullWidth" name="password" autocomplete="current-password" required minlength="6" autofocus>
|
||||||
|
<p class="formError justify marginTop"></p>
|
||||||
|
<div class="right marginTop">
|
||||||
|
<button class="marginRight" type="submit" name="submit"><i class="fa-solid fa-link"></i> Connect</button><!--
|
||||||
|
--><a class="button gray" href="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>" title="Back to account">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
@endsection
|
18
views/account/google_disconnect.php
Normal file
18
views/account/google_disconnect.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
@extends(templates/layout_normal)
|
||||||
|
|
||||||
|
@section(main)
|
||||||
|
<h2>Disconnect from Google</h2>
|
||||||
|
<div class="box compactBox">
|
||||||
|
<form id="connectGoogleForm" action="<?= Container::$routeCollection->getRoute('account.googleDisconnect-action')->generateLink() ?>" method="post" data-redirect-on-success="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>">
|
||||||
|
<p class="justify marginBottom">Your account will be disconnected from the currently set Google account.</p>
|
||||||
|
<input type="email" style="display: none;" name="email" autocomplete="username" value="<?= $userEmail ?>">
|
||||||
|
<p class="formLabel marginTop">Password</p>
|
||||||
|
<input type="password" class="text big fullWidth" name="password" autocomplete="current-password" required minlength="6" autofocus>
|
||||||
|
<p class="formError justify marginTop"></p>
|
||||||
|
<div class="right marginTop">
|
||||||
|
<button class="red marginRight" type="submit" name="submit"><i class="fa-solid fa-link-slash"></i> Disconnect</button><!--
|
||||||
|
--><a class="button gray" href="<?= Container::$routeCollection->getRoute('account')->generateLink() ?>" title="Back to account">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
@endsection
|
11
views/error/500.php
Normal file
11
views/error/500.php
Normal 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
|
@ -5,21 +5,13 @@
|
|||||||
@section(main)
|
@section(main)
|
||||||
<h2>Sign up</h2>
|
<h2>Sign up</h2>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<form id="googleSignupForm" action="/signup/google" method="post" data-redirect-on-success="<?= $redirectUrl ?>">
|
<form id="googleSignupForm" action="/signup" method="post" data-redirect-on-success="/signup/success">
|
||||||
<?php if ($found): ?>
|
|
||||||
<p class="justify">Please confirm that you link your account to your Google account.</p>
|
|
||||||
<?php else: ?>
|
|
||||||
<p class="justify">Please confirm your sign up request. Your account will be linked to your Google account.</p>
|
<p class="justify">Please confirm your sign up request. Your account will be linked to your Google account.</p>
|
||||||
<?php endif; ?>
|
|
||||||
<input type="email" class="text big fullWidth marginTop" name="email" placeholder="Email address" value="<?= $email ?>" disabled>
|
<input type="email" class="text big fullWidth marginTop" name="email" placeholder="Email address" value="<?= $email ?>" disabled>
|
||||||
|
<input type="username" class="text big fullWidth marginTop" name="username" placeholder="Username">
|
||||||
|
<p id="googleSignupFormError" class="formError justify marginTop"></p>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button class="marginTop marginRight" type="submit">
|
<button class="marginTop marginRight" type="submit">Sign up</button><!--
|
||||||
<?php if ($found): ?>
|
|
||||||
Link
|
|
||||||
<?php else: ?>
|
|
||||||
Sign up
|
|
||||||
<?php endif; ?>
|
|
||||||
</button><!--
|
|
||||||
--><button id="cancelGoogleSignupButton" class="gray marginTop" type="button">Cancel</button>
|
--><button id="cancelGoogleSignupButton" class="gray marginTop" type="button">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<h2>Login</h2>
|
<h2>Login</h2>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<form id="loginForm" action="/login" method="post" data-redirect-on-success="<?= $redirectUrl ?>">
|
<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="text" class="text big fullWidth" name="email" placeholder="Email address / username" autocomplete="username" 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" placeholder="Password" autocomplete="current-password" required minlength="6">
|
||||||
<p id="loginFormError" class="formError justify marginTop"></p>
|
<p id="loginFormError" class="formError justify marginTop"></p>
|
||||||
<div class="right marginTop">
|
<div class="right marginTop">
|
||||||
<button type="submit">Login</button>
|
<button type="submit">Login</button>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<h2>Request password reset</h2>
|
<h2>Request password reset</h2>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<form id="passwordResetForm" action="/password/requestReset" method="post" data-redirect-on-success="/password/requestReset/success">
|
<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="text" class="text big fullWidth" name="email" placeholder="Email address / username" autocomplete="username" value="<?= isset($email) ? $email : '' ?>" required autofocus>
|
||||||
<?php if (!empty($_ENV['RECAPTCHA_SITEKEY'])): ?>
|
<?php if (!empty($_ENV['RECAPTCHA_SITEKEY'])): ?>
|
||||||
<div class="marginTop">
|
<div class="marginTop">
|
||||||
<div class="g-recaptcha" data-sitekey="<?= $_ENV['RECAPTCHA_SITEKEY'] ?>"></div>
|
<div class="g-recaptcha" data-sitekey="<?= $_ENV['RECAPTCHA_SITEKEY'] ?>"></div>
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
<?php if ($success) : ?>
|
<?php if ($success) : ?>
|
||||||
<form id="resetPasswordForm" action="/password/reset/<?= $token ?>" method="post" data-redirect-on-success="<?= $redirectUrl ?>">
|
<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="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" required minlength="6" autofocus>
|
<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" required minlength="6">
|
<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>
|
<p id="resetPasswordFormError" class="formError justify marginTop"></p>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button class="marginTop" type="submit">Reset password</button>
|
<button class="marginTop" type="submit">Reset password</button>
|
||||||
|
@ -7,14 +7,24 @@
|
|||||||
<h2>Sign up</h2>
|
<h2>Sign up</h2>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<form id="signupForm" action="/signup" method="post" data-redirect-on-success="/signup/success">
|
<form id="signupForm" action="/signup" method="post" data-redirect-on-success="/signup/success">
|
||||||
|
<?php if (isset($email) || isset($username)): ?>
|
||||||
|
<p class="justify">No user found with the given email address / username. Sign up with one click!</p>
|
||||||
<?php if (isset($email)): ?>
|
<?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" autocomplete="username" value="<?= $email ?>" required>
|
||||||
<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>
|
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" required autofocus>
|
<input type="email" class="text big fullWidth marginTop" name="email" placeholder="Email address" autocomplete="username" required autofocus>
|
||||||
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password" required minlength="6">
|
<?php endif; ?>
|
||||||
<input type="password" class="text big fullWidth marginTop" name="password_confirm" placeholder="Password confirmation" minlength="6">
|
<?php if (isset($username)): ?>
|
||||||
|
<input type="username" class="text big fullWidth marginTop" name="username" placeholder="Username" value="<?= $username ?>">
|
||||||
|
<?php else: ?>
|
||||||
|
<input type="username" class="text big fullWidth marginTop" name="username" placeholder="Username" autofocus>
|
||||||
|
<?php endif; ?>
|
||||||
|
<input type="password" class="text big fullWidth marginTop" name="password" placeholder="Password confirmation" autocomplete="new-password" required minlength="6">
|
||||||
|
<?php else: ?>
|
||||||
|
<input type="email" class="text big fullWidth" name="email" placeholder="Email address" autocomplete="username" required autofocus>
|
||||||
|
<input type="username" class="text big fullWidth marginTop" name="username" placeholder="Username">
|
||||||
|
<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 endif; ?>
|
||||||
<?php if (!empty($_ENV['RECAPTCHA_SITEKEY'])): ?>
|
<?php if (!empty($_ENV['RECAPTCHA_SITEKEY'])): ?>
|
||||||
<div class="marginTop">
|
<div class="marginTop">
|
||||||
|
@ -9,9 +9,9 @@ TODO: condition!
|
|||||||
<div id="playMode" class="modal">
|
<div id="playMode" class="modal">
|
||||||
<h2>Play map</h2>
|
<h2>Play map</h2>
|
||||||
<a id="singleButton" class="button fullWidth marginTop" href="" title="Single player">Single player</a>
|
<a id="singleButton" class="button fullWidth marginTop" href="" title="Single player">Single player</a>
|
||||||
|
<?php if ($isLoggedIn): ?>
|
||||||
<p class="bold center marginTop marginBottom">OR</p>
|
<p class="bold center marginTop marginBottom">OR</p>
|
||||||
<button id="multiButton" class="fullWidth green" data-map-id="">Multiplayer (beta)</button>
|
<button id="multiButton" class="fullWidth green" data-map-id="">Multiplayer (beta)</button>
|
||||||
<?php if ($isLoggedIn): ?>
|
|
||||||
<p class="bold center marginTop marginBottom">OR</p>
|
<p class="bold center marginTop marginBottom">OR</p>
|
||||||
<button id="challengeButton" class="fullWidth yellow" data-map-id="" data-timer="">Challenge (gamma)</button>
|
<button id="challengeButton" class="fullWidth yellow" data-map-id="" data-timer="">Challenge (gamma)</button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
@ -29,6 +29,6 @@
|
|||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p><span class="bold"><?= $_ENV['APP_NAME'] ?></span> <?= str_replace('Release_', '', VERSION) ?></p><!--
|
<p><span class="bold"><?= $_ENV['APP_NAME'] ?></span> <?= str_replace('Release_', '', VERSION) ?></p><!--
|
||||||
--><p>© The MapGuesser Contributors <?= (new DateTime(REVISION_DATE))->format('Y') ?></p>
|
--><p>© The <a href="https://git.esoko.eu/esoko/mapguesser" target="_blank">MapGuesser</a> Contributors <?= (new DateTime(REVISION_DATE))->format('Y') ?></p>
|
||||||
</footer>
|
</footer>
|
||||||
@endsection
|
@endsection
|
||||||
|
176
web.php
176
web.php
@ -1,103 +1,114 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
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;
|
||||||
|
use MapGuesser\Controller\UserController;
|
||||||
|
use MapGuesser\Controller\GameController;
|
||||||
|
use MapGuesser\Controller\GameFlowController;
|
||||||
|
use MapGuesser\Controller\MapAdminController;
|
||||||
|
use MapGuesser\Repository\UserRepository;
|
||||||
|
|
||||||
require 'main.php';
|
require 'main.php';
|
||||||
|
|
||||||
|
error_reporting(E_ALL);
|
||||||
if (!empty($_ENV['DEV'])) {
|
if (!empty($_ENV['DEV'])) {
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
ini_set('display_errors', '1');
|
ini_set('display_errors', '1');
|
||||||
} else {
|
} else {
|
||||||
ini_set('display_errors', '0');
|
ini_set('display_errors', '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
Container::$routeCollection = new SokoWeb\Routing\RouteCollection();
|
Container::$routeCollection = new RouteCollection();
|
||||||
|
|
||||||
Container::$routeCollection->get('index', '', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
Container::$routeCollection->get('index', '', [MapsController::class, 'getMaps']);
|
||||||
Container::$routeCollection->get('startSession', 'startSession.json', [MapGuesser\Controller\HomeController::class, 'startSession']);
|
Container::$routeCollection->get('startSession', 'startSession.json', [HomeController::class, 'startSession']);
|
||||||
Container::$routeCollection->group('login', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('login', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('login', '', [MapGuesser\Controller\LoginController::class, 'getLoginForm']);
|
$routeCollection->get('login', '', [LoginController::class, 'getLoginForm']);
|
||||||
$routeCollection->post('login-action', '', [MapGuesser\Controller\LoginController::class, 'login']);
|
$routeCollection->post('login-action', '', [LoginController::class, 'login']);
|
||||||
$routeCollection->get('login-google', 'google', [MapGuesser\Controller\LoginController::class, 'getGoogleLoginRedirect']);
|
$routeCollection->get('login-google', 'google', [LoginController::class, 'getGoogleLoginRedirect']);
|
||||||
$routeCollection->get('login-google-action', 'google/code', [MapGuesser\Controller\LoginController::class, 'loginWithGoogle']);
|
$routeCollection->get('login-google-action', 'google/code', [LoginController::class, 'loginWithGoogle']);
|
||||||
});
|
});
|
||||||
Container::$routeCollection->group('signup', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('signup', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('signup', '', [MapGuesser\Controller\LoginController::class, 'getSignupForm']);
|
$routeCollection->get('signup', '', [LoginController::class, 'getSignupForm']);
|
||||||
$routeCollection->post('signup-action', '', [MapGuesser\Controller\LoginController::class, 'signup']);
|
$routeCollection->post('signup-action', '', [LoginController::class, 'signup']);
|
||||||
$routeCollection->get('signup-google', 'google', [MapGuesser\Controller\LoginController::class, 'getSignupWithGoogleForm']);
|
$routeCollection->get('signup-google', 'google', [LoginController::class, 'getSignupWithGoogleForm']);
|
||||||
$routeCollection->post('signup-google-action', 'google', [MapGuesser\Controller\LoginController::class, 'signupWithGoogle']);
|
$routeCollection->post('signup.reset', 'reset', [LoginController::class, 'resetSignup']);
|
||||||
$routeCollection->post('signup.reset', 'reset', [MapGuesser\Controller\LoginController::class, 'resetSignup']);
|
$routeCollection->post('signup-google.reset', 'google/reset', [LoginController::class, 'resetGoogleSignup']);
|
||||||
$routeCollection->post('signup-google.reset', 'google/reset', [MapGuesser\Controller\LoginController::class, 'resetGoogleSignup']);
|
$routeCollection->get('signup.success', 'success', [LoginController::class, 'getSignupSuccess']);
|
||||||
$routeCollection->get('signup.success', 'success', [MapGuesser\Controller\LoginController::class, 'getSignupSuccess']);
|
$routeCollection->get('signup.activate', 'activate/{token}', [LoginController::class, 'activate']);
|
||||||
$routeCollection->get('signup.activate', 'activate/{token}', [MapGuesser\Controller\LoginController::class, 'activate']);
|
$routeCollection->get('signup.cancel', 'cancel/{token}', [LoginController::class, 'cancel']);
|
||||||
$routeCollection->get('signup.cancel', 'cancel/{token}', [MapGuesser\Controller\LoginController::class, 'cancel']);
|
|
||||||
});
|
});
|
||||||
Container::$routeCollection->group('password', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('password', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('password-requestReset', 'requestReset', [MapGuesser\Controller\LoginController::class, 'getRequestPasswordResetForm']);
|
$routeCollection->get('password-requestReset', 'requestReset', [LoginController::class, 'getRequestPasswordResetForm']);
|
||||||
$routeCollection->post('password-requestReset-action', 'requestReset', [MapGuesser\Controller\LoginController::class, 'requestPasswordReset']);
|
$routeCollection->post('password-requestReset-action', 'requestReset', [LoginController::class, 'requestPasswordReset']);
|
||||||
$routeCollection->get('password-requestReset.success', 'requestReset/success', [MapGuesser\Controller\LoginController::class, 'getRequestPasswordResetSuccess']);
|
$routeCollection->get('password-requestReset.success', 'requestReset/success', [LoginController::class, 'getRequestPasswordResetSuccess']);
|
||||||
$routeCollection->get('password-reset', 'reset/{token}', [MapGuesser\Controller\LoginController::class, 'getResetPasswordForm']);
|
$routeCollection->get('password-reset', 'reset/{token}', [LoginController::class, 'getResetPasswordForm']);
|
||||||
$routeCollection->post('password-reset.action', 'reset/{token}', [MapGuesser\Controller\LoginController::class, 'resetPassword']);
|
$routeCollection->post('password-reset.action', 'reset/{token}', [LoginController::class, 'resetPassword']);
|
||||||
});
|
});
|
||||||
Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']);
|
Container::$routeCollection->get('logout', 'logout', [LoginController::class, 'logout']);
|
||||||
Container::$routeCollection->group('account', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('account', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('account', '', [MapGuesser\Controller\UserController::class, 'getAccount']);
|
$routeCollection->get('account', '', [UserController::class, 'getAccount']);
|
||||||
$routeCollection->post('account-action', '', [MapGuesser\Controller\UserController::class, 'saveAccount']);
|
$routeCollection->post('account-action', '', [UserController::class, 'saveAccount']);
|
||||||
$routeCollection->get('account.delete', 'delete', [MapGuesser\Controller\UserController::class, 'getDeleteAccount']);
|
$routeCollection->get('account.delete', 'delete', [UserController::class, 'getDeleteAccount']);
|
||||||
$routeCollection->post('account.delete-action', 'delete', [MapGuesser\Controller\UserController::class, 'deleteAccount']);
|
$routeCollection->post('account.delete-action', 'delete', [UserController::class, 'deleteAccount']);
|
||||||
$routeCollection->get('account.googleAuthenticate', 'googleAuthenticate', [MapGuesser\Controller\UserController::class, 'getGoogleAuthenticateRedirect']);
|
$routeCollection->get('account.googleConnect', 'googleConnect', [UserController::class, 'getGoogleConnectRedirect']);
|
||||||
$routeCollection->get('account.googleAuthenticate-action', 'googleAuthenticate/code', [MapGuesser\Controller\UserController::class, 'authenticateWithGoogle']);
|
$routeCollection->get('account.googleConnect-confirm', 'googleConnect/code', [UserController::class, 'getGoogleConnectConfirm']);
|
||||||
|
$routeCollection->post('account.googleConnect-action', 'googleConnect', [UserController::class, 'connectGoogle']);
|
||||||
|
$routeCollection->get('account.googleDisconnect', 'googleDisconnect', [UserController::class, 'getGoogleDisconnectConfirm']);
|
||||||
|
$routeCollection->post('account.googleDisconnect-action', 'googleDisconnect', [UserController::class, 'disconnectGoogle']);
|
||||||
|
$routeCollection->get('account.googleAuthenticate', 'googleAuthenticate', [UserController::class, 'getGoogleAuthenticateRedirect']);
|
||||||
|
$routeCollection->get('account.googleAuthenticate-action', 'googleAuthenticate/code', [UserController::class, 'authenticateWithGoogle']);
|
||||||
});
|
});
|
||||||
//Container::$routeCollection->get('maps', 'maps', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
//Container::$routeCollection->get('maps', 'maps', [MapsController::class, 'getMaps']);
|
||||||
Container::$routeCollection->group('game', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('game', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']);
|
$routeCollection->get('game', '{mapId}', [GameController::class, 'getGame']);
|
||||||
$routeCollection->post('game.prepare-json', '{mapId}/prepare.json', [MapGuesser\Controller\GameController::class, 'prepareGame']);
|
$routeCollection->post('game.prepare-json', '{mapId}/prepare.json', [GameController::class, 'prepareGame']);
|
||||||
$routeCollection->post('game.initialData-json', '{mapId}/initialData.json', [MapGuesser\Controller\GameFlowController::class, 'initialData']);
|
$routeCollection->post('game.initialData-json', '{mapId}/initialData.json', [GameFlowController::class, 'initialData']);
|
||||||
$routeCollection->post('game.guess-json', '{mapId}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'guess']);
|
$routeCollection->post('game.guess-json', '{mapId}/guess.json', [GameFlowController::class, 'guess']);
|
||||||
});
|
});
|
||||||
Container::$routeCollection->group('multiGame', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('multiGame', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('multiGame.new', 'new/{mapId}', [MapGuesser\Controller\GameController::class, 'getNewMultiGame']);
|
$routeCollection->get('multiGame.new', 'new/{mapId}', [GameController::class, 'getNewMultiGame']);
|
||||||
$routeCollection->get('multiGame', '{roomId}', [MapGuesser\Controller\GameController::class, 'getMultiGame']);
|
$routeCollection->get('multiGame', '{roomId}', [GameController::class, 'getMultiGame']);
|
||||||
$routeCollection->post('multiGame.prepare-json', '{roomId}/prepare.json', [MapGuesser\Controller\GameController::class, 'prepareMultiGame']);
|
$routeCollection->post('multiGame.prepare-json', '{roomId}/prepare.json', [GameController::class, 'prepareMultiGame']);
|
||||||
$routeCollection->post('multiGame.initialData-json', '{roomId}/initialData.json', [MapGuesser\Controller\GameFlowController::class, 'multiInitialData']);
|
$routeCollection->post('multiGame.initialData-json', '{roomId}/initialData.json', [GameFlowController::class, 'multiInitialData']);
|
||||||
$routeCollection->post('multiGame.nextRound-json', '{roomId}/nextRound.json', [MapGuesser\Controller\GameFlowController::class, 'multiNextRound']);
|
$routeCollection->post('multiGame.nextRound-json', '{roomId}/nextRound.json', [GameFlowController::class, 'multiNextRound']);
|
||||||
$routeCollection->post('multiGame.guess-json', '{roomId}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'multiGuess']);
|
$routeCollection->post('multiGame.guess-json', '{roomId}/guess.json', [GameFlowController::class, 'multiGuess']);
|
||||||
});
|
});
|
||||||
Container::$routeCollection->group('challenge', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('challenge', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->post('challenge.create', 'create.json', [\MapGuesser\Controller\GameController::class, 'createNewChallenge']);
|
$routeCollection->post('challenge.create', 'create.json', [GameController::class, 'createNewChallenge']);
|
||||||
$routeCollection->get('challenge', '{challengeToken}', [MapGuesser\Controller\GameController::class, 'getChallenge']);
|
$routeCollection->get('challenge', '{challengeToken}', [GameController::class, 'getChallenge']);
|
||||||
$routeCollection->post('challenge.prepare-json', '{challengeToken}/prepare.json', [MapGuesser\Controller\GameController::class, 'prepareChallenge']);
|
$routeCollection->post('challenge.prepare-json', '{challengeToken}/prepare.json', [GameController::class, 'prepareChallenge']);
|
||||||
$routeCollection->post('challenge.initialData-json', '{challengeToken}/initialData.json', [MapGuesser\Controller\GameFlowController::class, 'challengeInitialData']);
|
$routeCollection->post('challenge.initialData-json', '{challengeToken}/initialData.json', [GameFlowController::class, 'challengeInitialData']);
|
||||||
$routeCollection->post('challenge.guess-json', '{challengeToken}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'challengeGuess']);
|
$routeCollection->post('challenge.guess-json', '{challengeToken}/guess.json', [GameFlowController::class, 'challengeGuess']);
|
||||||
});
|
});
|
||||||
Container::$routeCollection->group('admin', function (SokoWeb\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('admin', function (RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId?}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId?}', [MapAdminController::class, 'getMapEditor']);
|
||||||
$routeCollection->get('admin.place', 'place.json/{placeId}', [MapGuesser\Controller\MapAdminController::class, 'getPlace']);
|
$routeCollection->get('admin.place', 'place.json/{placeId}', [MapAdminController::class, 'getPlace']);
|
||||||
$routeCollection->post('admin.saveMap', 'saveMap/{mapId}/json', [MapGuesser\Controller\MapAdminController::class, 'saveMap']);
|
$routeCollection->post('admin.saveMap', 'saveMap/{mapId}/json', [MapAdminController::class, 'saveMap']);
|
||||||
$routeCollection->post('admin.deleteMap', 'deleteMap/{mapId}', [MapGuesser\Controller\MapAdminController::class, 'deleteMap']);
|
$routeCollection->post('admin.deleteMap', 'deleteMap/{mapId}', [MapAdminController::class, 'deleteMap']);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isset($_COOKIE['COOKIES_CONSENT'])) {
|
if (isset($_COOKIE['COOKIES_CONSENT'])) {
|
||||||
Container::$sessionHandler = new SokoWeb\Session\DatabaseSessionHandler();
|
Container::$sessionHandler = new DatabaseSessionHandler(
|
||||||
|
Container::$dbConnection,
|
||||||
|
'sessions',
|
||||||
|
new DateTime('-7 days')
|
||||||
|
);
|
||||||
|
|
||||||
session_set_save_handler(Container::$sessionHandler, true);
|
session_set_save_handler(Container::$sessionHandler, true);
|
||||||
session_start([
|
session_start([
|
||||||
'gc_probability' => 0, // old sessions are deleted by MaintainDatabaseCommand
|
'gc_probability' => 0, // old sessions are deleted by MaintainDatabaseCommand
|
||||||
'cookie_lifetime' => 604800,
|
'cookie_lifetime' => 0,
|
||||||
'cookie_path' => '/',
|
'cookie_path' => '/',
|
||||||
'cookie_httponly' => true,
|
'cookie_httponly' => true,
|
||||||
'cookie_samesite' => 'Lax'
|
'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
|
// this is needed to handle old type of session IDs
|
||||||
if (!Container::$sessionHandler->validateId(session_id())) {
|
if (!Container::$sessionHandler->validateId(session_id())) {
|
||||||
session_regenerate_id(true);
|
session_regenerate_id(true);
|
||||||
@ -106,15 +117,34 @@ if (isset($_COOKIE['COOKIES_CONSENT'])) {
|
|||||||
$_SESSION = [];
|
$_SESSION = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
Container::$request = new SokoWeb\Request\Request(
|
Container::$request = new Request(
|
||||||
$_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'],
|
$_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'],
|
||||||
$_GET,
|
$_GET,
|
||||||
$_POST,
|
$_POST,
|
||||||
getallheaders(),
|
getallheaders(),
|
||||||
$_SESSION,
|
new Session($_SESSION),
|
||||||
new MapGuesser\Repository\UserRepository()
|
new UserRepository()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!Container::$request->session()->has('anti_csrf_token')) {
|
if (!Container::$request->session()->has('anti_csrf_token')) {
|
||||||
Container::$request->session()->set('anti_csrf_token', bin2hex(random_bytes(16)));
|
Container::$request->session()->set('anti_csrf_token', bin2hex(random_bytes(16)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$appConfig = [
|
||||||
|
'antiCsrfTokenName' => 'anti_csrf_token',
|
||||||
|
'antiCsrfTokenErrorResponse' => ['error' => 'no_valid_anti_csrf_token'],
|
||||||
|
'antiCsrfTokenExceptions' => [],
|
||||||
|
'loginRouteId' => 'login',
|
||||||
|
'error404View' => 'error/404',
|
||||||
|
'error500View' => 'error/500'
|
||||||
|
];
|
||||||
|
|
||||||
|
$httpReponse = new HttpResponse(
|
||||||
|
Container::$request,
|
||||||
|
Container::$dbConnection,
|
||||||
|
Container::$routeCollection,
|
||||||
|
$appConfig,
|
||||||
|
$_SERVER['REQUEST_METHOD'],
|
||||||
|
$_SERVER['REQUEST_URI']
|
||||||
|
);
|
||||||
|
$httpReponse->render();
|
||||||
|
Loading…
Reference in New Issue
Block a user