Merge branch 'master' into pr/forms

This commit is contained in:
Ludvík Prokopec 2022-09-08 13:57:09 +02:00
commit f54a526a8c
16 changed files with 439 additions and 116 deletions

4
.gitignore vendored
View File

@ -23,4 +23,6 @@ dist-ssr
*.sln *.sln
*.sw? *.sw?
public/vendor # php
/public/vendor
/api/vendor

View File

@ -3,7 +3,8 @@
"vendor-dir": "public/vendor" "vendor-dir": "public/vendor"
}, },
"require": { "require": {
"bramus/router": "1.5",
"vlucas/phpdotenv": "^5.4", "vlucas/phpdotenv": "^5.4",
"firebase/php-jwt": "^6.2" "catfan/medoo": "^2.1"
} }
} }

135
composer.lock generated
View File

@ -4,69 +4,134 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "5e6e41d564a162322502fd4108ce44cf", "content-hash": "a72d198969a21ad6ddd90355a3227085",
"packages": [ "packages": [
{ {
"name": "firebase/php-jwt", "name": "bramus/router",
"version": "v6.2.0", "version": "1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/firebase/php-jwt.git", "url": "https://github.com/bramus/router.git",
"reference": "d28e6df83830252650da4623c78aaaf98fb385f3" "reference": "6adc0182dc6b0ebc22fd10543f65a36de10d8c05"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/d28e6df83830252650da4623c78aaaf98fb385f3", "url": "https://api.github.com/repos/bramus/router/zipball/6adc0182dc6b0ebc22fd10543f65a36de10d8c05",
"reference": "d28e6df83830252650da4623c78aaaf98fb385f3", "reference": "6adc0182dc6b0ebc22fd10543f65a36de10d8c05",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.1||^8.0" "php": ">=5.3.0"
}, },
"require-dev": { "require-dev": {
"guzzlehttp/guzzle": "^6.5||^7.4", "friendsofphp/php-cs-fixer": "~2.14",
"phpspec/prophecy-phpunit": "^1.1", "phpunit/php-code-coverage": "~2.0",
"phpunit/phpunit": "^7.5||^9.5", "phpunit/phpunit": "~4.0"
"psr/cache": "^1.0||^2.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0"
},
"suggest": {
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
"psr-4": { "psr-0": {
"Firebase\\JWT\\": "src" "Bramus": "src/"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"BSD-3-Clause" "MIT"
], ],
"authors": [ "authors": [
{ {
"name": "Neuman Vong", "name": "Bram(us) Van Damme",
"email": "neuman+pear@twilio.com", "email": "bramus@bram.us",
"role": "Developer" "homepage": "http://www.bram.us"
},
{
"name": "Anant Narayanan",
"email": "anant@php.net",
"role": "Developer"
} }
], ],
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", "description": "A lightweight and simple object oriented PHP Router",
"homepage": "https://github.com/firebase/php-jwt", "homepage": "https://github.com/bramus/router",
"keywords": [ "keywords": [
"jwt", "router",
"php" "routing"
], ],
"support": { "support": {
"issues": "https://github.com/firebase/php-jwt/issues", "issues": "https://github.com/bramus/router/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.2.0" "source": "https://github.com/bramus/router/tree/1.5"
}, },
"time": "2022-05-13T20:54:50+00:00" "time": "2020-10-26T09:50:48+00:00"
},
{
"name": "catfan/medoo",
"version": "v2.1.7",
"source": {
"type": "git",
"url": "https://github.com/catfan/Medoo.git",
"reference": "74be58f80d330d1075ef3bfd0fb3d057349597ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/catfan/Medoo/zipball/74be58f80d330d1075ef3bfd0fb3d057349597ae",
"reference": "74be58f80d330d1075ef3bfd0fb3d057349597ae",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=7.3"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"suggest": {
"ext-pdo_dblib": "For MSSQL or Sybase database on Linux/UNIX platform",
"ext-pdo_mysql": "For MySQL or MariaDB database",
"ext-pdo_oci": "For Oracle database",
"ext-pdo_pqsql": "For PostgreSQL database",
"ext-pdo_sqlite": "For SQLite database",
"ext-pdo_sqlsrv": "For MSSQL database on both Window/Liunx platform"
},
"type": "framework",
"autoload": {
"psr-4": {
"Medoo\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Angel Lai",
"email": "angel@medoo.in"
}
],
"description": "The lightweight PHP database framework to accelerate development",
"homepage": "https://medoo.in",
"keywords": [
"database",
"database library",
"lightweight",
"mariadb",
"mssql",
"mysql",
"oracle",
"php framework",
"postgresql",
"sql",
"sqlite"
],
"support": {
"issues": "https://github.com/catfan/Medoo/issues",
"source": "https://github.com/catfan/Medoo"
},
"funding": [
{
"url": "https://paypal.me/AngelaonLai",
"type": "custom"
},
{
"url": "https://opencollective.com/medoo",
"type": "open_collective"
}
],
"time": "2022-07-02T04:27:50+00:00"
}, },
{ {
"name": "graham-campbell/result-type", "name": "graham-campbell/result-type",

View File

@ -5,7 +5,15 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title</title> <title>Erant</title>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-8RCL0H1Q7V"></script>
<script>
window.dataLayer = window.dataLayer || []
function gtag() { dataLayer.push(arguments) }
gtag('js', new Date())
gtag('config', 'G-8RCL0H1Q7V');
</script>
</head> </head>
<body> <body>

22
package-lock.json generated
View File

@ -8,7 +8,8 @@
"name": "geohry", "name": "geohry",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"svelte-routing": "^1.6.0" "svelte-routing": "^1.6.0",
"yallist": "^4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "^1.0.1", "@sveltejs/vite-plugin-svelte": "^1.0.1",
@ -1888,14 +1889,10 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true "dev": true
}, },
"node_modules/xtend": { "node_modules/yallist": {
"version": "4.0.2", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
"dev": true,
"engines": {
"node": ">=0.4"
}
}, },
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.1.1", "version": "2.1.1",
@ -3065,11 +3062,18 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true "dev": true
}, },
<<<<<<< HEAD
"xtend": { "xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true "dev": true
=======
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
>>>>>>> master
}, },
"yaml": { "yaml": {
"version": "2.1.1", "version": "2.1.1",

View File

@ -6,7 +6,8 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"preview": "vite preview" "preview": "vite preview",
"php": "php -S localhost:8000 -t ./public"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "^1.0.1", "@sveltejs/vite-plugin-svelte": "^1.0.1",
@ -20,6 +21,7 @@
"vite": "^3.0.0" "vite": "^3.0.0"
}, },
"dependencies": { "dependencies": {
"svelte-routing": "^1.6.0" "svelte-routing": "^1.6.0",
"yallist": "^4.0.0"
} }
} }

View File

@ -1,39 +0,0 @@
#database configuration
#database host
DB_HOST="localhost"
#database user
DB_USER="root"
#database user password
DB_PASS=""
#database name
DB_NAME="test"
#database port
DB_PORT="mysql"
#should connect to database? (false if you don't want to use database)
DB_ENABLED=false
#production flag (true if you want to use production settings)
PRODUCTION=false
#error reporting (true if you want to report errors)
ERROR_REPORTING=true
#character set for whole application
CHARSET="utf-8"
#should force redirect to https? (true if you want to use https)
FORCE_HTTPS=false
#jwt token authentication
#jwt key for token authentication
#online secure passwords generator - https://www.grc.com/passwords.htm
#generate key by PHP - $jwtKey = bin2hex(random_bytes(32));
JWT_KEY=""
#encryption algorithm for jwt token
JWT_ALGO="HS256"
#jwt token server name
SERVER_NAME="http://localhost"
#jwt token expiration time in seconds
JWT_EXPIRATION_TIME=3600

View File

@ -1,15 +1,10 @@
<Files ".env"> <Files "api/.env">
Order Allow,Deny Order Allow,Deny
Deny from all Deny from all
</Files> </Files>
<IfModule mod_rewrite.c>
RewriteEngine On RewriteEngine On
# RewriteCond %{HTTPS} off
# RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L] RewriteRule . index.php [L]
</IfModule>

6
public/api/.env Normal file
View File

@ -0,0 +1,6 @@
PRODUCTION=false
DB_HOST="db.db030.webglobe.com"
DB_USER="mysql85033"
DB_PASSWORD="troglodyt"
DB_DATABASE="mysql122279"

64
public/api/index.php Normal file
View File

@ -0,0 +1,64 @@
<?php
use Medoo\Medoo;
header('Content-Type: application/json; charset=utf-8');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
function env($key) {
global $_ENV;
return array_key_exists($key, $_ENV) ? $_ENV[$key] : null;
}
$database = new Medoo([
'type' => 'mysql',
'host' => env("DB_HOST"),
'database' => env("DB_DATABASE"),
'username' => env("DB_USER"),
'password' => env("DB_PASSWORD")
]);
$data = json_decode(file_get_contents("php://input"), true);
$routesDirectory = __DIR__ . "/routes";
$getFolderContentUtil = null;
$getFolderContentUtil = function($dir) use($routesDirectory, &$getFolderContentUtil, $router, $data, $database) {
$files = scandir($dir);
$filter = '/\.php$/';
foreach($files as $key => $value) {
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
$pathWithoutRoot = str_replace($routesDirectory, '', $path);
$pathWithoutRelativeRoot = str_replace($dir, '', $path);
if(!is_dir($path)) {
if(empty($filter) || preg_match($filter, $path)) {
$error = false;
$response = require $path;
if(!empty($response) && is_array($response)) {
foreach($response as $key => $fn) {
$router->{$key}(str_replace(".php", '', $pathWithoutRelativeRoot), function() use($router, $fn, $data, $error, $database) {
$responseResult = $fn($data, getallheaders(), $database, $error, $router);
if($responseResult) {
$responseResult["status"] = array_key_exists("status", $responseResult) ? $responseResult["status"] : 200;
http_response_code($responseResult["status"]);
echo json_encode($responseResult["data"]);
exit();
}
});
}
}
}
} else if($value != "." && $value != "..") {
$router->mount($pathWithoutRelativeRoot, function() use($getFolderContentUtil, $path, $filter) {
$getFolderContentUtil($path);
});
}
}
};
$getFolderContentUtil($routesDirectory);
$router->run();

View File

@ -0,0 +1,74 @@
<?php
return [
"post" => function($data, $headers, $db) {
function remoteFileExists($url) {
$curl = curl_init($url);
//don't fetch the actual page, you only want to check the connection is ok
curl_setopt($curl, CURLOPT_NOBODY, true);
//do request
$result = curl_exec($curl);
$ret = false;
//if request did not fail
if ($result !== false) {
//if request was ok, check response code
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($statusCode == 200) {
$ret = true;
}
}
curl_close($curl);
return $ret;
}
$imagesHostName = 'https://geohry.skolazdola.cz/';
if(!isset($data['gameurl']) || empty($data['gameurl'])) return [
"data" => [
"success" => false,
"message" => "Property 'gameurl' is not set."
]
];
$gameUrl = $data['gameurl'];
$gameDetails = $db->select('games4', '*', [
'url' => $gameUrl
]);
if(!$gameDetails) return [
"data" => [
"success" => false,
"message" => "Invalid 'gameurl'."
]
];
$gameDetails = $gameDetails[0];
$gameDetails["questions"] = $db->select('questions4', '*', [
'url' => $gameUrl
]);
$thumbnailPath = "{$imagesHostName}/games/{$gameUrl}/intro.jpg";
$gameDetails["thumbnail"] = remoteFileExists($thumbnailPath) ? $thumbnailPath : null;
foreach($gameDetails["questions"] as &$question) {
$questionThumbnailPath = "{$imagesHostName}/games/{$gameUrl}/" . $question["uniqid"] . ".jpg";
$question["thumbnail"] = remoteFileExists($questionThumbnailPath) ? $questionThumbnailPath : null;
}
return [
"success" => true,
"data" => $gameDetails
];
}
];

37
public/cors.php Normal file
View File

@ -0,0 +1,37 @@
<?php
/**
* An example CORS-compliant method. It will allow any GET, POST, or OPTIONS requests from any
* origin.
*
* In a production environment, you probably want to be more restrictive, but this gives you
* the general idea of what is involved. For the nitty-gritty low-down, read:
*
* - https://developer.mozilla.org/en/HTTP_access_control
* - https://fetch.spec.whatwg.org/#http-cors-protocol
*
*/
function cors() {
// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
// you want to allow, and if so:
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Header: *");
header("Access-Control-Max-Age: 86400"); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
header("Access-Control-Allow-Origin: *");
exit(0);
}
}

View File

@ -1,18 +1,30 @@
<?php <?php
require_once(__DIR__ . '/vendor/autoload.php'); require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/cors.php';
$envFile = Dotenv\Dotenv::createArrayBacked(__DIR__)->load(); cors();
function env($key, $default = null) { $router = new \Bramus\Router\Router();
global $envFile; $router->setBasePath('/');
if(isset($envFile[$key])) { $router->mount("/api", function() use($router) {
return $envFile[$key]; require_once __DIR__ . '/api/index.php';
} });
return $default; $router->set404('/api(/.*)?', function() {
} header('HTTP/1.1 404 Not Found');
header('Content-Type: application/json');
header('Content-Type: text/html; charset=' . env("CHARSET")); echo json_encode([
require_once(__DIR__ . '/index.html'); "message" => "Route not defined."
]);
});
$router->get("/.*", function() {
header('Content-Type: text/html; charset=UTF-8');
echo "frontend!";
});
$router->run();

60
src/lib/utils/api.js Normal file
View File

@ -0,0 +1,60 @@
async function send({ method, path, body, token, headers }) {
const opts = { method, headers: new Headers(), mode: 'cors' }
opts.headers.append('Content-Type', 'application/json')
opts.headers.append('Access-Control-Allow-Origin', '*')
if (body) {
opts.body = JSON.stringify(body)
}
if (headers) {
for (const [k, v] of Object.entries(headers)) {
opts.headers.append(k, v)
}
}
if (token) {
opts.headers['Authorization'] = `Bearer ${token}`
}
const res = fetch(path, opts)
.then(async (r) => {
if (r.status >= 200 && r.status < 400) {
return await r.text()
} else {
return await r.text()
}
})
.then((str) => {
try {
return JSON.parse(str)
} catch (err) {
return str
}
})
return res
}
export function get(path, token = null) {
return send({ method: 'GET', path, body: null, token })
}
export function del(path, token = null) {
return send({ method: 'DELETE', path, body: null, token })
}
export function post(path, body, token = null) {
return send({ method: 'POST', path, body, token })
}
export function put(
path,
body,
token = null,
headers = []
) {
return send({ method: 'PUT', path, body, token, headers })
}
export const hostName = 'https://erant.cz/api'

View File

@ -0,0 +1,16 @@
export default (question, questionType) => {
switch (questionType.toLowerCase()) {
case 'text':
return question
case 'number':
return Number.parseFloat(question)
case 'choice':
return question.split(/;\s*/).map(item => ({
label: item.startsWith('*') ? item.substring(1) : item,
value: item.startsWith('*') ? true : false
}))
default:
return null
}
}

View File

@ -9,8 +9,24 @@
import Map from '../lib/Components/game/Map.svelte' import Map from '../lib/Components/game/Map.svelte'
import ImageSlider from '../lib/Components/ImageSlider.svelte' import ImageSlider from '../lib/Components/ImageSlider.svelte'
import * as api from '$lib/utils/api'
import parseQuestion from '$lib/utils/parseQuestion'
import yallist from 'yallist'
let background = '/assets/temp/kar1.png' let background = '/assets/temp/kar1.png'
let assets = Array.from(Array(6).keys()).map((_, i) => `/assets/temp/kar${i + 1}.png`) let assets = Array.from(Array(6).keys()).map((_, i) => `/assets/temp/kar${i + 1}.png`)
;(async () => {
const gameData = await api.post(`${api.hostName}/game/details`, {
gameurl: 'pisek-mesto-kralovske',
})
const questions = yallist(gameData.questions)
console.log(questions)
console.log(parseQuestion(gameData.questions[0].answer, gameData.questions[0].type))
})()
let shareData = { let shareData = {
title: 'Geohry', title: 'Geohry',
text: 'Naše geohry', text: 'Naše geohry',