diff --git a/.env b/.env index f9515c5..bdbf102 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -APP_ENV=prod +APP_ENV=dev APP_SECRET=303bdf2e8891dee499ac5367ab9a53ed DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8" MAILER_DSN=null://null @@ -7,4 +7,7 @@ SITE_TITLE="Your Site Title" SSL_STAGE=local SSL_STORE=./infra/docker/dev/ssl_certs DOMAINS="howtocodewell-local.fm -> http://webserver" -FORCE_RENEW='false' \ No newline at end of file +FORCE_RENEW='false' +GOOGLE_API_KEY= +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= diff --git a/.gitignore b/.gitignore index 02b226b..3512e37 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,7 @@ npm-debug.log yarn-error.log ###< symfony/webpack-encore-bundle ### /infra/docker/dev/ssl_certs/* -!/infra/docker/dev/ssl_certs/.gitkeep \ No newline at end of file +!/infra/docker/dev/ssl_certs/.gitkeep + +/data +!/data/.gitkeep \ No newline at end of file diff --git a/composer.json b/composer.json index d36b097..0f33436 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "doctrine/doctrine-bundle": "^2.4", "doctrine/doctrine-migrations-bundle": "^3.1", "doctrine/orm": "^2.10", + "google/apiclient": "^2.0", "knplabs/knp-paginator-bundle": "^5.7", "phpdocumentor/reflection-docblock": "^5.2", "sensio/framework-extra-bundle": "^6.1", diff --git a/composer.lock b/composer.lock index 5e738b5..a248af9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "625d3669509b45ad532c8db8be418a14", + "content-hash": "254686280ea63962fea1bdbdc7289347", "packages": [ { "name": "composer/package-versions-deprecated", @@ -1509,6 +1509,63 @@ ], "time": "2021-10-11T09:18:27+00:00" }, + { + "name": "firebase/php-jwt", + "version": "v5.5.1", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "83b609028194aa042ea33b5af2d41a7427de80e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6", + "reference": "83b609028194aa042ea33b5af2d41a7427de80e6", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": ">=4.8 <=9" + }, + "suggest": { + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "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.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v5.5.1" + }, + "time": "2021-11-08T20:18:51+00:00" + }, { "name": "friendsofphp/proxy-manager-lts", "version": "v1.0.5", @@ -1591,6 +1648,500 @@ ], "time": "2021-05-22T16:11:15+00:00" }, + { + "name": "google/apiclient", + "version": "v2.11.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client.git", + "reference": "7db9eb40c8ba887e81c0fe84f2888a967396cdfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/7db9eb40c8ba887e81c0fe84f2888a967396cdfb", + "reference": "7db9eb40c8ba887e81c0fe84f2888a967396cdfb", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~2.0||~3.0||~4.0||~5.0", + "google/apiclient-services": "~0.200", + "google/auth": "^1.10", + "guzzlehttp/guzzle": "~5.3.3||~6.0||~7.0", + "guzzlehttp/psr7": "^1.7||^2.0.0", + "monolog/monolog": "^1.17||^2.0", + "php": "^5.6|^7.0|^8.0", + "phpseclib/phpseclib": "~2.0||^3.0.2" + }, + "require-dev": { + "cache/filesystem-adapter": "^0.3.2|^1.1", + "composer/composer": "^1.10.22", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "phpcompatibility/php-compatibility": "^9.2", + "phpspec/prophecy-phpunit": "^1.1||^2.0", + "phpunit/phpunit": "^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "~2.3", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "cache/filesystem-adapter": "For caching certs and tokens (using Google\\Client::setCache)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Google\\": "src/" + }, + "files": [ + "src/aliases.php" + ], + "classmap": [ + "src/aliases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client/issues", + "source": "https://github.com/googleapis/google-api-php-client/tree/v2.11.0" + }, + "time": "2021-09-20T21:15:55+00:00" + }, + { + "name": "google/apiclient-services", + "version": "v0.221.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client-services.git", + "reference": "55fb77c4dcb7ec2b41128d41815b3aac65ddfadb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/55fb77c4dcb7ec2b41128d41815b3aac65ddfadb", + "reference": "55fb77c4dcb7ec2b41128d41815b3aac65ddfadb", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^5.7||^8.5.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Service\\": "src" + }, + "files": [ + "autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client-services/issues", + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.221.0" + }, + "time": "2021-11-06T11:26:11+00:00" + }, + { + "name": "google/auth", + "version": "v1.18.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-auth-library-php.git", + "reference": "21dd478e77b0634ed9e3a68613f74ed250ca9347" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/21dd478e77b0634ed9e3a68613f74ed250ca9347", + "reference": "21dd478e77b0634ed9e3a68613f74ed250ca9347", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~2.0|~3.0|~4.0|~5.0", + "guzzlehttp/guzzle": "^5.3.1|^6.2.1|^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", + "php": ">=5.4", + "psr/cache": "^1.0|^2.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "guzzlehttp/promises": "0.1.1|^1.3", + "kelvinmo/simplejwt": "^0.2.5|^0.5.1", + "phpseclib/phpseclib": "^2.0.31", + "phpunit/phpunit": "^4.8.36|^5.7", + "sebastian/comparator": ">=1.2.3" + }, + "suggest": { + "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "http://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "support": { + "docs": "https://googleapis.github.io/google-auth-library-php/master/", + "issues": "https://github.com/googleapis/google-auth-library-php/issues", + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.18.0" + }, + "time": "2021-08-24T18:03:18+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.4.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/868b3571a039f0ebc11ac8f344f4080babe2cb94", + "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.4.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2021-10-18T09:52:00+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2021-10-22T20:56:57+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2021-10-06T17:43:30+00:00" + }, { "name": "knplabs/knp-components", "version": "v3.3.0", @@ -1871,15 +2422,76 @@ "rollbar/rollbar": "Allow sending log messages to Rollbar", "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.x-dev" - } + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.3.5" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2021-10-01T21:08:31+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" }, + "type": "library", "autoload": { "psr-4": { - "Monolog\\": "src/Monolog" + "ParagonIE\\ConstantTime\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1888,33 +2500,89 @@ ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" } ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "https://github.com/Seldaek/monolog", + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", "keywords": [ - "log", - "logging", - "psr-3" + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" ], "support": { - "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.3.5" + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, + "time": "2020-12-06T15:14:20+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", - "type": "tidelift" + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" } ], - "time": "2021-10-01T21:08:31+00:00" + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -2076,6 +2744,117 @@ }, "time": "2021-10-02T14:08:47+00:00" }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.11", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "6e794226a35159eb06f355efe59a0075a16551dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/6e794226a35159eb06f355efe59a0075a16551dd", + "reference": "6e794226a35159eb06f355efe59a0075a16551dd", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^5.7|^6.0|^9.4", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.11" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2021-10-27T03:01:46+00:00" + }, { "name": "psr/cache", "version": "2.0.0", @@ -2223,6 +3002,166 @@ }, "time": "2019-01-08T18:20:26+00:00" }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, { "name": "psr/link", "version": "1.1.1", @@ -2326,6 +3265,50 @@ }, "time": "2021-07-14T16:41:46+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "sensio/framework-extra-bundle", "version": "v6.2.1", diff --git a/config/packages/google_apiclient.yaml b/config/packages/google_apiclient.yaml new file mode 100644 index 0000000..4809e14 --- /dev/null +++ b/config/packages/google_apiclient.yaml @@ -0,0 +1,7 @@ +services: + Google_Client: + class: Google_Client + calls: + - [setDeveloperKey, ['%env(GOOGLE_API_KEY)%']] + - [setClientId, ['%env(GOOGLE_CLIENT_ID)%']] + - [setClientSecret, ['%env(GOOGLE_CLIENT_SECRET)%']] diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml index d294ff1..a6ecdb8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -41,7 +41,7 @@ services: - howtocodewell environment: - APACHE_DOCUMENT_ROOT=/var/www/html/public - - APP_ENV=prod + - APP_ENV=dev node: image: node:16 diff --git a/migrations/Version20211113210826.php b/migrations/Version20211113210826.php new file mode 100644 index 0000000..b97758d --- /dev/null +++ b/migrations/Version20211113210826.php @@ -0,0 +1,31 @@ +addSql('CREATE TABLE scheduled_video (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, external_id VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, thumbnail VARCHAR(255) NOT NULL, scheduled_date DATETIME NOT NULL, created_date DATETIME NOT NULL)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE scheduled_video'); + } +} diff --git a/src/Command/YouTubeUpcomingBroadcastsCommand.php b/src/Command/YouTubeUpcomingBroadcastsCommand.php new file mode 100644 index 0000000..201bf4a --- /dev/null +++ b/src/Command/YouTubeUpcomingBroadcastsCommand.php @@ -0,0 +1,231 @@ +entityManager = $entityManager; + $this->googleClient = $googleClient; + parent::__construct('app:youtube-upcoming-broadcasts'); + } + + protected function configure(): void + { + $this->addOption('renew-token', null, InputOption::VALUE_OPTIONAL, 'Forces a new auth code to be requested'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->io = new SymfonyStyle($input, $output); + $this->io->info('Running script'); + try { + $this->setUpGoogleClient(); + $renewToken = $input->getOption('renew-token'); + + $token = $this->getStoredAccessToken(); + if (empty($token) || ($renewToken === 'yes')) { + $token = $this->renewToken(); + $this->saveToken($token); + } + + $this->googleClient->setAccessToken($token); + $this->io->info('Token has been set'); + + $this->io->info('Getting upcoming broadcasts'); + $foundIds = $this->getUpcomingVideoIds(); + if (count($foundIds) === 0) { + $this->io->info('There are no upcoming broadcasts'); + + return Command::SUCCESS; + } + + foreach ($foundIds as $videoId) { + $this->io->info('Working on video Id '.$videoId); + $video = $this->getVideo($videoId); + if (!$video instanceof YouTube\Video) { + $this->io->info('Video could not be found ..... SKIPPING'); + continue; + } + + // Do we have this video in the DB? + $scheduledVideo = $this->entityManager->getRepository(ScheduledVideo::class)->findOneBy( + [ + 'externalId' => $video->getId(), + ] + ); + + $scheduledVideo = $this->createUpdateScheduledVideo($video, $scheduledVideo); + + $this->io->info('Saving upcoming broadcast'); + $this->entityManager->persist($scheduledVideo); + $this->entityManager->flush(); + } + + return Command::SUCCESS; + + } catch (Exception | GoogleException $exception) { + $this->io->error($exception->getMessage()); + } + + return Command::SUCCESS; + } + + /** + * @throws GoogleException + * @throws Exception + */ + protected function setUpGoogleClient(): void + { + $file = self::FILE_DIR.'/googleusercontent.com.json'; + if (!file_exists($file)) { + throw new Exception('googleusercontent.com.json is missing'); + } + $this->googleClient->setApplicationName('Test'); + $this->googleClient->setScopes( + [ + 'https://www.googleapis.com/auth/youtube.readonly', + ] + ); + $this->googleClient->setAccessType('offline'); + $this->googleClient->setAuthConfig($file); + } + + protected function getStoredAccessToken(): ?array + { + $tokenData = null; + $file = self::FILE_DIR.'/google_token.txt'; + if (file_exists($file)) { + $fileContents = file_get_contents($file); + if ($fileContents === false) { + $this->io->error('File does not contain data'); + + return null; + } + $tokenData = (array)json_decode($fileContents, true); + } + + return $tokenData; + } + + /** + * @throws Exception + */ + protected function renewToken(): array + { + $authUrl = $this->googleClient->createAuthUrl(); + $this->io->info('Please go to '.$authUrl); + $question = new Question('Please enter the auth code?'); + $authCode = $this->io->askQuestion($question); + $tokenResponse = $this->getAccessTokenFromAuthCode($authCode); + if ($tokenResponse === null) { + throw new Exception('Token response is null'); + } + + return $tokenResponse; + } + + protected function getAccessTokenFromAuthCode(string $authCode): ?array + { + $tokenResponse = $this->googleClient->fetchAccessTokenWithAuthCode($authCode); + if (isset($tokenResponse['error']) && isset($tokenResponse['error_description'])) { + $this->io->error($tokenResponse['error']); + $this->io->error($tokenResponse['error_description']); + + return null; + } + + return $tokenResponse; + } + + protected function saveToken(array $token): void + { + $file = self::FILE_DIR.'/google_token.txt'; + file_put_contents($file, json_encode($token)); + } + + protected function getUpcomingVideoIds(): array + { + $service = new Google_Service_YouTube($this->googleClient); + $part = 'id,status,contentDetails'; + $query = [ + 'broadcastStatus' => 'upcoming', + ]; + $response = $service->liveBroadcasts->listLiveBroadcasts($part, $query); + $items = $response->getItems(); + + $foundResults = []; + foreach ($items as $item) { + $status = $item->getStatus()->getPrivacyStatus(); + if ($status === 'public') { + $foundResults[] = $item->getId(); + } + } + + return $foundResults; + } + + protected function getVideo(string $videoId): ?YouTube\Video + { + $service = new Google_Service_YouTube($this->googleClient); + $part = 'id,contentDetails,snippet'; + $query = [ + 'id' => $videoId, + ]; + $response = $service->videos->listVideos($part, $query); + if (!empty($response->getItems()) && is_array($response->getItems())) { + return $response->getItems()[0]; + } + + return null; + } + + public function createUpdateScheduledVideo( + YouTube\Video $youTubeVideo, + ?ScheduledVideo $scheduledVideo = null + ): ScheduledVideo { + if (!$scheduledVideo instanceof ScheduledVideo) { + $this->io->info('This is a new broadcast. A new one will be created'); + $scheduledVideo = new ScheduledVideo(); + } else { + $this->io->info('This is a known broadcast. It will be updated'); + } + + $date = new DateTime($youTubeVideo->getSnippet()->getPublishedAt()); + $scheduledVideo->setTitle($youTubeVideo->getSnippet()->getTitle()); + $scheduledVideo->setScheduledDate($date); + $scheduledVideo->setExternalId($youTubeVideo->getId()); + $scheduledVideo->setThumbnail($youTubeVideo->getSnippet()->getThumbnails()->getHigh()->getUrl()); + $scheduledVideo->setCreatedDate(new DateTime()); + + return $scheduledVideo; + } +} + + diff --git a/src/Entity/ScheduledVideo.php b/src/Entity/ScheduledVideo.php new file mode 100644 index 0000000..492b807 --- /dev/null +++ b/src/Entity/ScheduledVideo.php @@ -0,0 +1,162 @@ +id; + } + + /** + * @param int $id + * @return self + */ + public function setId(int $id): self + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getExternalId(): string + { + return $this->externalId; + } + + /** + * @param string $externalId + * @return self + */ + public function setExternalId(string $externalId): self + { + $this->externalId = $externalId; + + return $this; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @param string $title + * @return self + */ + public function setTitle(string $title): self + { + $this->title = $title; + + return $this; + } + + /** + * @return DateTime + */ + public function getScheduledDate(): DateTime + { + return $this->scheduledDate; + } + + /** + * @param DateTime $scheduledDate + * @return self + */ + public function setScheduledDate(DateTime $scheduledDate): self + { + $this->scheduledDate = $scheduledDate; + + return $this; + } + + /** + * @return DateTime + */ + public function getCreatedDate(): DateTime + { + return $this->createdDate; + } + + /** + * @param DateTime $createdDate + * @return self + */ + public function setCreatedDate(DateTime $createdDate): self + { + $this->createdDate = $createdDate; + + return $this; + } + + /** + * @return string + */ + public function getThumbnail(): string + { + return $this->thumbnail; + } + + /** + * @param string $thumbnail + * @return self + */ + public function setThumbnail(string $thumbnail): self + { + $this->thumbnail = $thumbnail; + + return $this; + } + + +} diff --git a/src/Repository/ScheduledVideoRepository.php b/src/Repository/ScheduledVideoRepository.php new file mode 100644 index 0000000..1ce3e5f --- /dev/null +++ b/src/Repository/ScheduledVideoRepository.php @@ -0,0 +1,36 @@ +findBy( + [ + + ], + [ + 'scheduledDate' => 'DESC', + ] + ); + + } + +} diff --git a/symfony.lock b/symfony.lock index 50ad074..a2e158a 100644 --- a/symfony.lock +++ b/symfony.lock @@ -85,9 +85,39 @@ "egulias/email-validator": { "version": "3.1.1" }, + "firebase/php-jwt": { + "version": "v5.5.1" + }, "friendsofphp/proxy-manager-lts": { "version": "v1.0.5" }, + "google/apiclient": { + "version": "2.11", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "master", + "version": "2.0", + "ref": "49c5d7a66d863d28513979bf0666dc77599100c0" + }, + "files": [ + "config/packages/google_apiclient.yaml" + ] + }, + "google/apiclient-services": { + "version": "v0.221.0" + }, + "google/auth": { + "version": "v1.18.0" + }, + "guzzlehttp/guzzle": { + "version": "7.4.0" + }, + "guzzlehttp/promises": { + "version": "1.5.1" + }, + "guzzlehttp/psr7": { + "version": "2.1.0" + }, "knplabs/knp-components": { "version": "v3.1.0" }, @@ -106,6 +136,12 @@ "nikic/php-parser": { "version": "v4.13.0" }, + "paragonie/constant_time_encoding": { + "version": "v2.4.0" + }, + "paragonie/random_compat": { + "version": "v9.99.100" + }, "phar-io/manifest": { "version": "2.0.3" }, @@ -121,6 +157,9 @@ "phpdocumentor/type-resolver": { "version": "1.5.1" }, + "phpseclib/phpseclib": { + "version": "3.0.11" + }, "phpspec/prophecy": { "version": "1.14.0" }, @@ -165,12 +204,24 @@ "psr/event-dispatcher": { "version": "1.0.0" }, + "psr/http-client": { + "version": "1.0.1" + }, + "psr/http-factory": { + "version": "1.0.1" + }, + "psr/http-message": { + "version": "1.0.1" + }, "psr/link": { "version": "1.1.1" }, "psr/log": { "version": "2.0.0" }, + "ralouphie/getallheaders": { + "version": "3.0.3" + }, "roave/security-advisories": { "version": "dev-latest" },