Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6f8735da8 | ||
|
|
6a9f7eddc1 | ||
|
|
af52ac3787 | ||
|
|
0481274335 | ||
|
|
618f2a4d48 | ||
|
|
e817a34a3a | ||
|
|
4dde24b70a | ||
|
|
2d91f94f0c | ||
|
|
dd2905286b | ||
|
|
12d24bfddf | ||
|
|
338537c774 | ||
|
|
b2ee25fcc5 | ||
|
|
af2375133a | ||
|
|
83a027c1bb | ||
|
|
4b2fc23129 | ||
|
|
c0c44bcbae | ||
|
|
e0273a4c41 | ||
|
|
b2c1749695 | ||
|
|
425d0d891a | ||
|
|
0d3203c10e | ||
|
|
cf63287ecc | ||
|
|
8b9dd0bc32 | ||
|
|
6acb19ba36 | ||
|
|
7f8e0fefa9 | ||
|
|
87ef0d1918 | ||
|
|
41b989d6e3 |
No files matched your search
+2
-1
@@ -4,7 +4,8 @@
|
|||||||
"description": "MapGuesser Application",
|
"description": "MapGuesser Application",
|
||||||
"license": "GNU GPL 3.0",
|
"license": "GNU GPL 3.0",
|
||||||
"require": {
|
"require": {
|
||||||
"vlucas/phpdotenv": "^4.1"
|
"vlucas/phpdotenv": "^4.1",
|
||||||
|
"symfony/console": "^5.1"
|
||||||
},
|
},
|
||||||
"require-dev": {},
|
"require-dev": {},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|||||||
Generated
+672
-1
@@ -4,7 +4,7 @@
|
|||||||
"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": "29431cf83ee884f01ee954b1068c0ccc",
|
"content-hash": "13a0eaff2786786caff2be86ac704fc7",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "phpoption/phpoption",
|
"name": "phpoption/phpoption",
|
||||||
@@ -61,6 +61,148 @@
|
|||||||
],
|
],
|
||||||
"time": "2020-03-21T18:07:53+00:00"
|
"time": "2020-03-21T18:07:53+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/container",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/container.git",
|
||||||
|
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||||
|
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Container\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "http://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||||
|
"homepage": "https://github.com/php-fig/container",
|
||||||
|
"keywords": [
|
||||||
|
"PSR-11",
|
||||||
|
"container",
|
||||||
|
"container-interface",
|
||||||
|
"container-interop",
|
||||||
|
"psr"
|
||||||
|
],
|
||||||
|
"time": "2017-02-14T16:28:37+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/console",
|
||||||
|
"version": "v5.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/console.git",
|
||||||
|
"reference": "00bed125812716d09b163f0727ef33bb49bf3448"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/console/zipball/00bed125812716d09b163f0727ef33bb49bf3448",
|
||||||
|
"reference": "00bed125812716d09b163f0727ef33bb49bf3448",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"symfony/polyfill-mbstring": "~1.0",
|
||||||
|
"symfony/polyfill-php73": "^1.8",
|
||||||
|
"symfony/polyfill-php80": "^1.15",
|
||||||
|
"symfony/service-contracts": "^1.1|^2",
|
||||||
|
"symfony/string": "^5.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/dependency-injection": "<4.4",
|
||||||
|
"symfony/dotenv": "<5.1",
|
||||||
|
"symfony/event-dispatcher": "<4.4",
|
||||||
|
"symfony/lock": "<4.4",
|
||||||
|
"symfony/process": "<4.4"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"psr/log-implementation": "1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"psr/log": "~1.0",
|
||||||
|
"symfony/config": "^4.4|^5.0",
|
||||||
|
"symfony/dependency-injection": "^4.4|^5.0",
|
||||||
|
"symfony/event-dispatcher": "^4.4|^5.0",
|
||||||
|
"symfony/lock": "^4.4|^5.0",
|
||||||
|
"symfony/process": "^4.4|^5.0",
|
||||||
|
"symfony/var-dumper": "^4.4|^5.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"psr/log": "For using the console logger",
|
||||||
|
"symfony/event-dispatcher": "",
|
||||||
|
"symfony/lock": "",
|
||||||
|
"symfony/process": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.1-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Console\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Console Component",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-30T20:35:19+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
"version": "v1.17.0",
|
"version": "v1.17.0",
|
||||||
@@ -133,6 +275,535 @@
|
|||||||
],
|
],
|
||||||
"time": "2020-05-12T16:14:59+00:00"
|
"time": "2020-05-12T16:14:59+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-intl-grapheme",
|
||||||
|
"version": "v1.17.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||||
|
"reference": "e094b0770f7833fdf257e6ba4775be4e258230b2"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e094b0770f7833fdf257e6ba4775be4e258230b2",
|
||||||
|
"reference": "e094b0770f7833fdf257e6ba4775be4e258230b2",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.17-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Intl\\Grapheme\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for intl's grapheme_* functions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"grapheme",
|
||||||
|
"intl",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-12T16:47:27+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-intl-normalizer",
|
||||||
|
"version": "v1.17.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||||
|
"reference": "1357b1d168eb7f68ad6a134838e46b0b159444a9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/1357b1d168eb7f68ad6a134838e46b0b159444a9",
|
||||||
|
"reference": "1357b1d168eb7f68ad6a134838e46b0b159444a9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.17-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for intl's Normalizer class and related functions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"intl",
|
||||||
|
"normalizer",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-12T16:14:59+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
"version": "v1.17.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
|
"reference": "fa79b11539418b02fc5e1897267673ba2c19419c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c",
|
||||||
|
"reference": "fa79b11539418b02fc5e1897267673ba2c19419c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.17-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for the Mbstring extension",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"mbstring",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-12T16:47:27+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php73",
|
||||||
|
"version": "v1.17.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php73.git",
|
||||||
|
"reference": "a760d8964ff79ab9bf057613a5808284ec852ccc"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a760d8964ff79ab9bf057613a5808284ec852ccc",
|
||||||
|
"reference": "a760d8964ff79ab9bf057613a5808284ec852ccc",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.17-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php73\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-12T16:47:27+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php80",
|
||||||
|
"version": "v1.17.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||||
|
"reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/5e30b2799bc1ad68f7feb62b60a73743589438dd",
|
||||||
|
"reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.0.8"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.17-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php80\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ion Bazan",
|
||||||
|
"email": "ion.bazan@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-12T16:47:27+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/service-contracts",
|
||||||
|
"version": "v2.1.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/service-contracts.git",
|
||||||
|
"reference": "66a8f0957a3ca54e4f724e49028ab19d75a8918b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/66a8f0957a3ca54e4f724e49028ab19d75a8918b",
|
||||||
|
"reference": "66a8f0957a3ca54e4f724e49028ab19d75a8918b",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"psr/container": "^1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/service-implementation": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.1-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Contracts\\Service\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Generic abstractions related to writing services",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"abstractions",
|
||||||
|
"contracts",
|
||||||
|
"decoupling",
|
||||||
|
"interfaces",
|
||||||
|
"interoperability",
|
||||||
|
"standards"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-20T17:43:50+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/string",
|
||||||
|
"version": "v5.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/string.git",
|
||||||
|
"reference": "90c2a5103f07feb19069379f3abdcdbacc7753a9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/string/zipball/90c2a5103f07feb19069379f3abdcdbacc7753a9",
|
||||||
|
"reference": "90c2a5103f07feb19069379f3abdcdbacc7753a9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"symfony/polyfill-ctype": "~1.8",
|
||||||
|
"symfony/polyfill-intl-grapheme": "~1.0",
|
||||||
|
"symfony/polyfill-intl-normalizer": "~1.0",
|
||||||
|
"symfony/polyfill-mbstring": "~1.0",
|
||||||
|
"symfony/polyfill-php80": "~1.15"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/error-handler": "^4.4|^5.0",
|
||||||
|
"symfony/http-client": "^4.4|^5.0",
|
||||||
|
"symfony/translation-contracts": "^1.1|^2",
|
||||||
|
"symfony/var-exporter": "^4.4|^5.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.1-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\String\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"Resources/functions.php"
|
||||||
|
],
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony String component",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"grapheme",
|
||||||
|
"i18n",
|
||||||
|
"string",
|
||||||
|
"unicode",
|
||||||
|
"utf-8",
|
||||||
|
"utf8"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-20T17:43:50+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "vlucas/phpdotenv",
|
"name": "vlucas/phpdotenv",
|
||||||
"version": "v4.1.5",
|
"version": "v4.1.5",
|
||||||
|
|||||||
File renamed without changes.
@@ -0,0 +1 @@
|
|||||||
|
<?php //empty on purpose
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
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;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
ALTER TABLE
|
||||||
|
`maps`
|
||||||
|
MODIFY
|
||||||
|
`bound_south_lat` decimal(9, 7) NOT NULL,
|
||||||
|
MODIFY
|
||||||
|
`bound_west_lng` decimal(10, 7) NOT NULL,
|
||||||
|
MODIFY
|
||||||
|
`bound_north_lat` decimal(9, 7) NOT NULL,
|
||||||
|
MODIFY
|
||||||
|
`bound_east_lng` decimal(10, 7) NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE
|
||||||
|
`places`
|
||||||
|
MODIFY
|
||||||
|
`lat` decimal(9, 7) NOT NULL,
|
||||||
|
MODIFY
|
||||||
|
`lng` decimal(10, 7) NOT NULL;
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
ALTER TABLE
|
||||||
|
`places`
|
||||||
|
ADD
|
||||||
|
`pano_id_cached` varchar(255) NULL DEFAULT NULL,
|
||||||
|
ADD
|
||||||
|
`pano_id_cached_timestamp` timestamp NULL DEFAULT NULL;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require 'main.php';
|
||||||
|
|
||||||
|
$app = new Symfony\Component\Console\Application('MapGuesser Console', '');
|
||||||
|
|
||||||
|
$app->add(new MapGuesser\Cli\DatabaseMigration());
|
||||||
|
|
||||||
|
$app->run();
|
||||||
@@ -22,6 +22,7 @@ Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCol
|
|||||||
Container::$routeCollection->group('admin', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('admin', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('admin.maps', 'maps', [MapGuesser\Controller\MapAdminController::class, 'getMaps']);
|
$routeCollection->get('admin.maps', 'maps', [MapGuesser\Controller\MapAdminController::class, 'getMaps']);
|
||||||
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
||||||
|
$routeCollection->get('admin.place', 'place.json/{placeId}', [MapGuesser\Controller\MapAdminController::class, 'getPlace']);
|
||||||
});
|
});
|
||||||
|
|
||||||
$match = Container::$routeCollection->match($method, explode('/', $url));
|
$match = Container::$routeCollection->match($method, explode('/', $url));
|
||||||
|
|||||||
@@ -4,24 +4,15 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#map.selected {
|
|
||||||
height: calc(50% - 25px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#panorama {
|
#panorama {
|
||||||
width: 100%;
|
position: absolute;
|
||||||
height: calc(50% - 25px);
|
|
||||||
display: none;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#noPano {
|
#noPano {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
height: calc(50% - 25px);
|
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
background: #cccccc;
|
background: #cccccc;
|
||||||
@@ -33,17 +24,53 @@
|
|||||||
|
|
||||||
#control {
|
#control {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
|
||||||
top: 60px;
|
|
||||||
width: 125px;
|
width: 125px;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#placeControl {
|
#placeControl {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
|
||||||
top: calc(50% + 35px);
|
|
||||||
width: 100px;
|
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
width: 100px;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 999px) and (min-height: 600px) {
|
||||||
|
#map.selected {
|
||||||
|
height: calc(50% - 25px);
|
||||||
|
}
|
||||||
|
#panorama, #noPano {
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
height: calc(50% - 25px);
|
||||||
|
}
|
||||||
|
#control {
|
||||||
|
right: 10px;
|
||||||
|
top: 60px;
|
||||||
|
}
|
||||||
|
#placeControl {
|
||||||
|
right: 10px;
|
||||||
|
top: calc(50% + 35px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1000px), (max-height: 599px) {
|
||||||
|
#map.selected {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
#panorama, #noPano {
|
||||||
|
top: 50px;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
#control, #placeControl {
|
||||||
|
right: 10px;
|
||||||
|
top: 60px;
|
||||||
|
}
|
||||||
|
#control.selected {
|
||||||
|
right: calc(50% + 10px);
|
||||||
|
top: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
Core.resetGame();
|
Core.resetGame();
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.open('GET', '/game/' + mapId + '/position.json', true);
|
xhr.open('GET', '/game/' + mapId + '/json', true);
|
||||||
xhr.send();
|
xhr.send();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -4,36 +4,47 @@
|
|||||||
panorama: null,
|
panorama: null,
|
||||||
selectedMarker: null,
|
selectedMarker: null,
|
||||||
|
|
||||||
loadPano: function (data, status) {
|
getPlace: function (placeId, marker) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'json';
|
||||||
|
xhr.onload = function () {
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
if (status !== google.maps.StreetViewStatus.OK) {
|
if (!this.response.panoId) {
|
||||||
document.getElementById('noPano').style.visibility = 'visible';
|
document.getElementById('noPano').style.visibility = 'visible';
|
||||||
|
|
||||||
|
marker.noPano = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MapEditor.loadPano(this.response.panoId);
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.open('GET', '/admin/place.json/' + placeId, true);
|
||||||
|
xhr.send();
|
||||||
|
},
|
||||||
|
|
||||||
|
loadPano: function (panoId) {
|
||||||
MapEditor.panorama.setVisible(true);
|
MapEditor.panorama.setVisible(true);
|
||||||
MapEditor.panorama.setPov({ heading: 0, pitch: 0 });
|
MapEditor.panorama.setPov({ heading: 0, pitch: 0 });
|
||||||
MapEditor.panorama.setZoom(0);
|
MapEditor.panorama.setZoom(0);
|
||||||
MapEditor.panorama.setPano(data.location.pano);
|
MapEditor.panorama.setPano(panoId);
|
||||||
},
|
},
|
||||||
|
|
||||||
select: function (marker) {
|
select: function (marker) {
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
document.getElementById('map').classList.add('selected');
|
document.getElementById('map').classList.add('selected');
|
||||||
|
document.getElementById('control').classList.add('selected');
|
||||||
document.getElementById('noPano').style.visibility = 'hidden';
|
document.getElementById('noPano').style.visibility = 'hidden';
|
||||||
document.getElementById('panorama').style.display = 'block';
|
document.getElementById('panorama').style.visibility = 'visible';
|
||||||
document.getElementById('placeControl').style.visibility = 'visible';
|
document.getElementById('placeControl').style.visibility = 'visible';
|
||||||
|
|
||||||
MapEditor.resetSelected();
|
MapEditor.resetSelected();
|
||||||
MapEditor.selectedMarker = marker;
|
MapEditor.selectedMarker = marker;
|
||||||
|
|
||||||
marker.setIcon(L.icon({
|
marker.setIcon(IconCollection.iconBlue);
|
||||||
iconUrl: '/static/img/markers/marker-blue.svg',
|
|
||||||
iconSize: [24, 32],
|
|
||||||
iconAnchor: [12, 32]
|
|
||||||
}));
|
|
||||||
marker.setZIndexOffset(2000);
|
marker.setZIndexOffset(2000);
|
||||||
|
|
||||||
MapEditor.map.invalidateSize(true);
|
MapEditor.map.invalidateSize(true);
|
||||||
@@ -41,8 +52,7 @@
|
|||||||
|
|
||||||
MapEditor.panorama.setVisible(false);
|
MapEditor.panorama.setVisible(false);
|
||||||
|
|
||||||
var sv = new google.maps.StreetViewService();
|
MapEditor.getPlace(marker.placeId, marker);
|
||||||
sv.getPanorama({ location: marker.getLatLng(), preference: google.maps.StreetViewPreference.NEAREST, source: google.maps.StreetViewSource.OUTDOOR }, MapEditor.loadPano);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
resetSelected: function () {
|
resetSelected: function () {
|
||||||
@@ -50,12 +60,38 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapEditor.selectedMarker.setIcon(L.icon({
|
MapEditor.selectedMarker.setIcon(MapEditor.selectedMarker.noPano ? IconCollection.iconRed : IconCollection.iconGreen);
|
||||||
|
MapEditor.selectedMarker.setZIndexOffset(1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var IconCollection = {
|
||||||
|
iconGreen: L.icon({
|
||||||
iconUrl: '/static/img/markers/marker-green.svg',
|
iconUrl: '/static/img/markers/marker-green.svg',
|
||||||
iconSize: [24, 32],
|
iconSize: [24, 32],
|
||||||
iconAnchor: [12, 32]
|
iconAnchor: [12, 32]
|
||||||
}));
|
}),
|
||||||
MapEditor.selectedMarker.setZIndexOffset(1000);
|
iconRed: L.icon({
|
||||||
|
iconUrl: '/static/img/markers/marker-red.svg',
|
||||||
|
iconSize: [24, 32],
|
||||||
|
iconAnchor: [12, 32]
|
||||||
|
}),
|
||||||
|
iconBlue: L.icon({
|
||||||
|
iconUrl: '/static/img/markers/marker-blue.svg',
|
||||||
|
iconSize: [24, 32],
|
||||||
|
iconAnchor: [12, 32]
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
var Util = {
|
||||||
|
getHighResData: function () {
|
||||||
|
if (window.devicePixelRatio >= 4) {
|
||||||
|
return { ppi: 320, tileSize: 128, zoomOffset: 1 };
|
||||||
|
} else if (window.devicePixelRatio >= 2) {
|
||||||
|
return { ppi: 250, tileSize: 256, zoomOffset: 0 };
|
||||||
|
} else {
|
||||||
|
return { ppi: 72, tileSize: 512, zoomOffset: -1 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,7 +100,13 @@
|
|||||||
zoomControl: false
|
zoomControl: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var highResData = Util.getHighResData();
|
||||||
|
|
||||||
L.tileLayer(tileUrl, {
|
L.tileLayer(tileUrl, {
|
||||||
|
subdomains: '1234',
|
||||||
|
ppi: highResData.ppi,
|
||||||
|
tileSize: highResData.tileSize,
|
||||||
|
zoomOffset: highResData.zoomOffset,
|
||||||
minZoom: 0,
|
minZoom: 0,
|
||||||
maxZoom: 20
|
maxZoom: 20
|
||||||
}).addTo(MapEditor.map);
|
}).addTo(MapEditor.map);
|
||||||
@@ -73,17 +115,20 @@
|
|||||||
|
|
||||||
for (var i = 0; i < places.length; ++i) {
|
for (var i = 0; i < places.length; ++i) {
|
||||||
var marker = L.marker({ lat: places[i].lat, lng: places[i].lng }, {
|
var marker = L.marker({ lat: places[i].lat, lng: places[i].lng }, {
|
||||||
icon: L.icon({
|
icon: places[i].noPano ? IconCollection.iconRed : IconCollection.iconGreen,
|
||||||
iconUrl: '/static/img/markers/marker-green.svg',
|
|
||||||
iconSize: [24, 32],
|
|
||||||
iconAnchor: [12, 32]
|
|
||||||
}),
|
|
||||||
zIndexOffset: 1000
|
zIndexOffset: 1000
|
||||||
})
|
})
|
||||||
.addTo(MapEditor.map)
|
.addTo(MapEditor.map)
|
||||||
.on('click', function () {
|
.on('click', function () {
|
||||||
|
if (MapEditor.selectedMarker === this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MapEditor.select(this);
|
MapEditor.select(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
marker.placeId = places[i].id;
|
||||||
|
marker.noPano = places[i].noPano;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapEditor.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
|
MapEditor.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
|
||||||
@@ -97,8 +142,9 @@
|
|||||||
|
|
||||||
document.getElementById('cancelButton').onclick = function () {
|
document.getElementById('cancelButton').onclick = function () {
|
||||||
document.getElementById('map').classList.remove('selected');
|
document.getElementById('map').classList.remove('selected');
|
||||||
|
document.getElementById('control').classList.remove('selected');
|
||||||
document.getElementById('noPano').style.visibility = 'hidden';
|
document.getElementById('noPano').style.visibility = 'hidden';
|
||||||
document.getElementById('panorama').style.display = 'none';
|
document.getElementById('panorama').style.visibility = 'hidden';
|
||||||
document.getElementById('placeControl').style.visibility = 'hidden';
|
document.getElementById('placeControl').style.visibility = 'hidden';
|
||||||
|
|
||||||
MapEditor.resetSelected();
|
MapEditor.resetSelected();
|
||||||
|
|||||||
Executable
+152
@@ -0,0 +1,152 @@
|
|||||||
|
#!/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():
|
||||||
|
return subprocess.check_output(["git", "for-each-ref", "refs/tags/Release*", "--count=1", "--sort=-creatordate", "--format=%(refname:short)"], cwd=REPO).decode().strip()
|
||||||
|
|
||||||
|
def updateRepoFromRemote():
|
||||||
|
subprocess.call(["git", "fetch", "origin", "--prune"], 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):
|
||||||
|
pass
|
||||||
|
#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")
|
||||||
|
|
||||||
|
checkoutWorktree(developmentWorktree.path, developmentWorktree.branch)
|
||||||
|
|
||||||
|
print(developmentWorktree.path + " is checked out to " + developmentWorktree.branch)
|
||||||
|
|
||||||
|
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("----------------------------------------------")
|
||||||
@@ -15,6 +15,9 @@ echo "Installing Yarn packages..."
|
|||||||
echo "Installing MapGuesser DB..."
|
echo "Installing MapGuesser DB..."
|
||||||
mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/db/mapguesser.sql
|
mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/db/mapguesser.sql
|
||||||
|
|
||||||
|
echo "Migrating DB..."
|
||||||
|
(cd ${ROOT_DIR} && ./mapg migrate)
|
||||||
|
|
||||||
if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
|
if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
|
||||||
echo "Minifying JS, CSS and SVG files..."
|
echo "Minifying JS, CSS and SVG files..."
|
||||||
${ROOT_DIR}/scripts/minify.sh
|
${ROOT_DIR}/scripts/minify.sh
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ echo "Installing Composer packages..."
|
|||||||
echo "Installing Yarn packages..."
|
echo "Installing Yarn packages..."
|
||||||
(cd ${ROOT_DIR}/public/static && yarn install)
|
(cd ${ROOT_DIR}/public/static && yarn install)
|
||||||
|
|
||||||
|
echo "Migrating DB..."
|
||||||
|
(cd ${ROOT_DIR} && ./mapg migrate)
|
||||||
|
|
||||||
if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
|
if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
|
||||||
echo "Minifying JS, CSS and SVG files..."
|
echo "Minifying JS, CSS and SVG files..."
|
||||||
${ROOT_DIR}/scripts/minify.sh
|
${ROOT_DIR}/scripts/minify.sh
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
<?php namespace MapGuesser\Cli;
|
||||||
|
|
||||||
|
use MapGuesser\Database\Query\Modify;
|
||||||
|
use MapGuesser\Database\Query\Select;
|
||||||
|
use MapGuesser\Interfaces\Database\IResultSet;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class DatabaseMigration extends Command
|
||||||
|
{
|
||||||
|
public function configure()
|
||||||
|
{
|
||||||
|
$this->setName('migrate')
|
||||||
|
->setDescription('Migration of database changes.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$db = \Container::$dbConnection;
|
||||||
|
|
||||||
|
$db->startTransaction();
|
||||||
|
|
||||||
|
$success = [];
|
||||||
|
try {
|
||||||
|
foreach ($this->readDir('structure') as $file) {
|
||||||
|
$db->multiQuery(file_get_contents($file));
|
||||||
|
|
||||||
|
$success[] = $this->saveToDB($file, 'structure');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->readDir('data') as $file) {
|
||||||
|
require $file;
|
||||||
|
|
||||||
|
$success[] = $this->saveToDB($file, 'data');
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$db->rollback();
|
||||||
|
|
||||||
|
$output->writeln('<error>Migration failed!</error>');
|
||||||
|
$output->writeln('');
|
||||||
|
|
||||||
|
$output->writeln((string) $e);
|
||||||
|
$output->writeln('');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->commit();
|
||||||
|
|
||||||
|
$output->writeln('<info>Migration was successful!</info>');
|
||||||
|
$output->writeln('');
|
||||||
|
|
||||||
|
if (count($success) > 0) {
|
||||||
|
foreach ($success as $migration) {
|
||||||
|
$output->writeln($migration);
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('');
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function readDir(string $type): array
|
||||||
|
{
|
||||||
|
$done = [];
|
||||||
|
|
||||||
|
$migrationTableExists = \Container::$dbConnection->query('SELECT count(*)
|
||||||
|
FROM information_schema.tables
|
||||||
|
WHERE table_schema = \'' . $_ENV['DB_NAME'] . '\'
|
||||||
|
AND table_name = \'migrations\';')
|
||||||
|
->fetch(IResultSet::FETCH_NUM)[0];
|
||||||
|
|
||||||
|
if ($migrationTableExists != 0) {
|
||||||
|
$select = new Select(\Container::$dbConnection, 'migrations');
|
||||||
|
$select->columns(['migration']);
|
||||||
|
$select->where('type', '=', $type);
|
||||||
|
$select->orderBy('migration');
|
||||||
|
|
||||||
|
$result = $select->execute();
|
||||||
|
|
||||||
|
while ($migration = $result->fetch(IResultSet::FETCH_ASSOC)) {
|
||||||
|
$done[] = $migration['migration'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = ROOT . '/database/migrations/' . $type;
|
||||||
|
$dir = opendir($path);
|
||||||
|
|
||||||
|
$files = [];
|
||||||
|
while ($file = readdir($dir)) {
|
||||||
|
$filePath = $path . '/' . $file;
|
||||||
|
|
||||||
|
if (!is_file($filePath) || in_array(pathinfo($file, PATHINFO_FILENAME), $done)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$files[] = $filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
natsort($files);
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveToDB(string $file, string $type): string
|
||||||
|
{
|
||||||
|
$baseName = pathinfo($file, PATHINFO_FILENAME);
|
||||||
|
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'migrations');
|
||||||
|
$modify->set('migration', $baseName);
|
||||||
|
$modify->set('type', $type);
|
||||||
|
$modify->save();
|
||||||
|
|
||||||
|
return $baseName . ' (' . $type . ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,18 +3,29 @@
|
|||||||
use MapGuesser\Database\Query\Select;
|
use MapGuesser\Database\Query\Select;
|
||||||
use MapGuesser\Interfaces\Database\IResultSet;
|
use MapGuesser\Interfaces\Database\IResultSet;
|
||||||
use MapGuesser\Interfaces\Response\IContent;
|
use MapGuesser\Interfaces\Response\IContent;
|
||||||
|
use MapGuesser\Repository\PlaceRepository;
|
||||||
use MapGuesser\Response\HtmlContent;
|
use MapGuesser\Response\HtmlContent;
|
||||||
|
use MapGuesser\Response\JsonContent;
|
||||||
use MapGuesser\Util\Geo\Bounds;
|
use MapGuesser\Util\Geo\Bounds;
|
||||||
|
|
||||||
class MapAdminController
|
class MapAdminController
|
||||||
{
|
{
|
||||||
public function getMaps(): IContent {
|
private PlaceRepository $placeRepository;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->placeRepository = new PlaceRepository();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMaps(): IContent
|
||||||
|
{
|
||||||
//TODO
|
//TODO
|
||||||
|
|
||||||
return new HtmlContent('admin/maps');
|
return new HtmlContent('admin/maps');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMapEditor(array $parameters): IContent {
|
public function getMapEditor(array $parameters): IContent
|
||||||
|
{
|
||||||
$mapId = (int) $parameters['mapId'];
|
$mapId = (int) $parameters['mapId'];
|
||||||
|
|
||||||
$bounds = $this->getMapBounds($mapId);
|
$bounds = $this->getMapBounds($mapId);
|
||||||
@@ -25,6 +36,16 @@ class MapAdminController
|
|||||||
return new HtmlContent('admin/map_editor', $data);
|
return new HtmlContent('admin/map_editor', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPlace(array $parameters)
|
||||||
|
{
|
||||||
|
$placeId = (int) $parameters['placeId'];
|
||||||
|
|
||||||
|
$placeData = $this->placeRepository->getById($placeId);
|
||||||
|
|
||||||
|
$data = ['panoId' => $placeData['panoId']];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
private function getMapBounds(int $mapId): Bounds
|
private function getMapBounds(int $mapId): Bounds
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection, 'maps');
|
$select = new Select(\Container::$dbConnection, 'maps');
|
||||||
@@ -41,12 +62,19 @@ class MapAdminController
|
|||||||
private function &getPlaces(int $mapId): array
|
private function &getPlaces(int $mapId): array
|
||||||
{
|
{
|
||||||
$select = new Select(\Container::$dbConnection, 'places');
|
$select = new Select(\Container::$dbConnection, 'places');
|
||||||
$select->columns(['id', 'lat', 'lng']);
|
$select->columns(['id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp']);
|
||||||
$select->where('map_id', '=', $mapId);
|
$select->where('map_id', '=', $mapId);
|
||||||
$select->orderBy('lng');
|
$select->orderBy('lng');
|
||||||
//$select->limit(100);
|
|
||||||
|
|
||||||
$places = $select->execute()->fetchAll(IResultSet::FETCH_ASSOC);
|
$result = $select->execute();
|
||||||
|
|
||||||
|
$places = [];
|
||||||
|
|
||||||
|
while ($place = $result->fetch(IResultSet::FETCH_ASSOC)) {
|
||||||
|
$noPano = $place['pano_id_cached_timestamp'] && $place['pano_id_cached'] === null;
|
||||||
|
|
||||||
|
$places[] = ['id' => $place['id'], 'lat' => $place['lat'], 'lng' => $place['lng'], 'noPano' => $noPano];
|
||||||
|
}
|
||||||
|
|
||||||
return $places;
|
return $places;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,33 @@
|
|||||||
<?php namespace MapGuesser\Controller;
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
use MapGuesser\Database\Query\Select;
|
|
||||||
use MapGuesser\Http\Request;
|
|
||||||
use MapGuesser\Interfaces\Database\IResultSet;
|
|
||||||
use MapGuesser\Util\Geo\Position;
|
use MapGuesser\Util\Geo\Position;
|
||||||
use MapGuesser\Response\JsonContent;
|
use MapGuesser\Response\JsonContent;
|
||||||
use MapGuesser\Interfaces\Response\IContent;
|
use MapGuesser\Interfaces\Response\IContent;
|
||||||
|
use MapGuesser\Repository\PlaceRepository;
|
||||||
|
|
||||||
class PositionController
|
class PositionController
|
||||||
{
|
{
|
||||||
const NUMBER_OF_ROUNDS = 5;
|
const NUMBER_OF_ROUNDS = 5;
|
||||||
const MAX_SCORE = 1000;
|
const MAX_SCORE = 1000;
|
||||||
|
|
||||||
|
private PlaceRepository $placeRepository;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->placeRepository = new PlaceRepository();
|
||||||
|
}
|
||||||
|
|
||||||
public function getPosition(array $parameters): IContent
|
public function getPosition(array $parameters): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $parameters['mapId'];
|
$mapId = (int) $parameters['mapId'];
|
||||||
|
|
||||||
if (!isset($_SESSION['state']) || $_SESSION['state']['mapId'] !== $mapId) {
|
if (!isset($_SESSION['state']) || $_SESSION['state']['mapId'] !== $mapId) {
|
||||||
$data = ['error' => 'No valid session found!'];
|
$data = ['error' => 'no_session_found'];
|
||||||
return new JsonContent($data);
|
return new JsonContent($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($_SESSION['state']['rounds']) === 0) {
|
if (count($_SESSION['state']['rounds']) === 0) {
|
||||||
$newPosition = $this->getNewPosition($mapId);
|
$newPosition = $this->placeRepository->getForMapWithValidPano($mapId);
|
||||||
$_SESSION['state']['rounds'][] = $newPosition;
|
$_SESSION['state']['rounds'][] = $newPosition;
|
||||||
|
|
||||||
$data = ['panoId' => $newPosition['panoId']];
|
$data = ['panoId' => $newPosition['panoId']];
|
||||||
@@ -55,7 +60,7 @@ class PositionController
|
|||||||
$mapId = (int) $parameters['mapId'];
|
$mapId = (int) $parameters['mapId'];
|
||||||
|
|
||||||
if (!isset($_SESSION['state']) || $_SESSION['state']['mapId'] !== $mapId) {
|
if (!isset($_SESSION['state']) || $_SESSION['state']['mapId'] !== $mapId) {
|
||||||
$data = ['error' => 'No valid session found!'];
|
$data = ['error' => 'no_session_found'];
|
||||||
return new JsonContent($data);
|
return new JsonContent($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +84,7 @@ class PositionController
|
|||||||
$exclude = array_merge($exclude, $round['placesWithoutPano'], [$round['placeId']]);
|
$exclude = array_merge($exclude, $round['placesWithoutPano'], [$round['placeId']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$newPosition = $this->getNewPosition($mapId, $exclude);
|
$newPosition = $this->placeRepository->getForMapWithValidPano($mapId, $exclude);
|
||||||
$_SESSION['state']['rounds'][] = $newPosition;
|
$_SESSION['state']['rounds'][] = $newPosition;
|
||||||
|
|
||||||
$panoId = $newPosition['panoId'];
|
$panoId = $newPosition['panoId'];
|
||||||
@@ -100,66 +105,6 @@ class PositionController
|
|||||||
return new JsonContent($data);
|
return new JsonContent($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getNewPosition(int $mapId, array $exclude = []): array
|
|
||||||
{
|
|
||||||
$placesWithoutPano = [];
|
|
||||||
|
|
||||||
do {
|
|
||||||
$place = $this->selectNewPlace($mapId, $exclude);
|
|
||||||
$position = new Position($place['lat'], $place['lng']);
|
|
||||||
$panoId = $this->getPanorama($position);
|
|
||||||
|
|
||||||
if ($panoId === null) {
|
|
||||||
$placesWithoutPano[] = $place['id'];
|
|
||||||
}
|
|
||||||
} while ($panoId === null);
|
|
||||||
|
|
||||||
return [
|
|
||||||
'placesWithoutPano' => $placesWithoutPano,
|
|
||||||
'placeId' => $place['id'],
|
|
||||||
'position' => $position,
|
|
||||||
'panoId' => $panoId
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function selectNewPlace(int $mapId, array $exclude): array
|
|
||||||
{
|
|
||||||
$select = new Select(\Container::$dbConnection, 'places');
|
|
||||||
$select->columns(['id', 'lat', 'lng']);
|
|
||||||
$select->where('id', 'NOT IN', $exclude);
|
|
||||||
$select->where('map_id', '=', $mapId);
|
|
||||||
|
|
||||||
$numberOfPlaces = $select->count();// TODO: what if 0
|
|
||||||
$randomOffset = random_int(0, $numberOfPlaces - 1);
|
|
||||||
|
|
||||||
$select->orderBy('id');
|
|
||||||
$select->limit(1, $randomOffset);
|
|
||||||
|
|
||||||
$place = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
|
||||||
|
|
||||||
return $place;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getPanorama(Position $position): ?string
|
|
||||||
{
|
|
||||||
$request = new Request('https://maps.googleapis.com/maps/api/streetview/metadata', Request::HTTP_GET);
|
|
||||||
$request->setQuery([
|
|
||||||
'key' => $_ENV['GOOGLE_MAPS_SERVER_API_KEY'],
|
|
||||||
'location' => $position->getLat() . ',' . $position->getLng(),
|
|
||||||
'source' => 'outdoor'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response = $request->send();
|
|
||||||
|
|
||||||
$panoData = json_decode($response->getBody(), true);
|
|
||||||
|
|
||||||
if ($panoData['status'] !== 'OK') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $panoData['pano_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function calculateDistance(Position $realPosition, Position $guessPosition): float
|
private function calculateDistance(Position $realPosition, Position $guessPosition): float
|
||||||
{
|
{
|
||||||
return $realPosition->calculateDistanceTo($guessPosition);
|
return $realPosition->calculateDistanceTo($guessPosition);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class Modify
|
|||||||
|
|
||||||
private array $original = [];
|
private array $original = [];
|
||||||
|
|
||||||
private bool $autoIncrement = false;
|
private bool $autoIncrement = true;
|
||||||
|
|
||||||
public function __construct(IConnection $connection, string $table)
|
public function __construct(IConnection $connection, string $table)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<?php namespace MapGuesser\Repository;
|
||||||
|
|
||||||
|
use MapGuesser\Util\Geo\Position;
|
||||||
|
use MapGuesser\Database\Query\Select;
|
||||||
|
use MapGuesser\Database\Query\Modify;
|
||||||
|
use MapGuesser\Http\Request;
|
||||||
|
use MapGuesser\Interfaces\Database\IResultSet;
|
||||||
|
use DateTime;
|
||||||
|
use DateInterval;
|
||||||
|
|
||||||
|
class PlaceRepository
|
||||||
|
{
|
||||||
|
public function getById(int $placeId)
|
||||||
|
{
|
||||||
|
$place = $this->selectFromDbById($placeId);
|
||||||
|
|
||||||
|
$panoId = $this->requestPanoId($place);
|
||||||
|
|
||||||
|
$position = new Position($place['lat'], $place['lng']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'position' => $position,
|
||||||
|
'panoId' => $panoId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getForMapWithValidPano(int $mapId, array $exclude = []): array
|
||||||
|
{
|
||||||
|
$placesWithoutPano = [];
|
||||||
|
|
||||||
|
do {
|
||||||
|
$place = $this->selectFromDbForMap($mapId, $exclude);
|
||||||
|
|
||||||
|
$panoId = $this->requestPanoId($place);
|
||||||
|
|
||||||
|
if ($panoId === null) {
|
||||||
|
$placesWithoutPano[] = $place['id'];
|
||||||
|
}
|
||||||
|
} while ($panoId === null);
|
||||||
|
|
||||||
|
$position = new Position($place['lat'], $place['lng']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'placesWithoutPano' => $placesWithoutPano,
|
||||||
|
'placeId' => $place['id'],
|
||||||
|
'position' => $position,
|
||||||
|
'panoId' => $panoId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function selectFromDbById(int $placeId): array
|
||||||
|
{
|
||||||
|
$select = new Select(\Container::$dbConnection, 'places');
|
||||||
|
$select->columns(['id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp']);
|
||||||
|
$select->whereId($placeId);
|
||||||
|
|
||||||
|
$place = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||||
|
|
||||||
|
return $place;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function selectFromDbForMap(int $mapId, array $exclude): array
|
||||||
|
{
|
||||||
|
$select = new Select(\Container::$dbConnection, 'places');
|
||||||
|
$select->columns(['id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp']);
|
||||||
|
$select->where('id', 'NOT IN', $exclude);
|
||||||
|
$select->where('map_id', '=', $mapId);
|
||||||
|
|
||||||
|
$numberOfPlaces = $select->count();// TODO: what if 0
|
||||||
|
$randomOffset = random_int(0, $numberOfPlaces - 1);
|
||||||
|
|
||||||
|
$select->orderBy('id');
|
||||||
|
$select->limit(1, $randomOffset);
|
||||||
|
|
||||||
|
$place = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||||
|
|
||||||
|
return $place;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function requestPanoId(array $place, bool $canBeIndoor = false): ?string
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
$place['pano_id_cached_timestamp'] &&
|
||||||
|
(new DateTime($place['pano_id_cached_timestamp']))->add(new DateInterval('P1D')) > new DateTime()
|
||||||
|
) {
|
||||||
|
return $place['pano_id_cached'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = new Request('https://maps.googleapis.com/maps/api/streetview/metadata', Request::HTTP_GET);
|
||||||
|
$request->setQuery([
|
||||||
|
'key' => $_ENV['GOOGLE_MAPS_SERVER_API_KEY'],
|
||||||
|
'location' => $place['lat'] . ',' . $place['lng'],
|
||||||
|
'source' => $canBeIndoor ? 'default' : 'outdoor'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $request->send();
|
||||||
|
|
||||||
|
$panoData = json_decode($response->getBody(), true);
|
||||||
|
|
||||||
|
$panoId = $panoData['status'] === 'OK' ? $panoData['pano_id'] : null;
|
||||||
|
|
||||||
|
// enable indoor panos if no outdoor found
|
||||||
|
if ($panoId === null && !$canBeIndoor) {
|
||||||
|
return $this->requestPanoId($place, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->saveCachedPanoId($place['id'], $panoId);
|
||||||
|
|
||||||
|
return $panoId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveCachedPanoId(int $placeId, ?string $panoId): void
|
||||||
|
{
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'places');
|
||||||
|
$modify->setId($placeId);
|
||||||
|
$modify->set('pano_id_cached', $panoId);
|
||||||
|
$modify->set('pano_id_cached_timestamp', (new DateTime())->format('Y-m-d H:i:s'));
|
||||||
|
$modify->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user