From 39ee34758963267ed6d3b690b8965035a959d73b Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Sat, 24 Oct 2020 15:45:17 +0000
Subject: [PATCH 1/8] Add Google Sheets API library (#1)

---
 composer.json |   9 +
 composer.lock | 742 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 738 insertions(+), 13 deletions(-)

diff --git a/composer.json b/composer.json
index e6fb155..7c4f792 100644
--- a/composer.json
+++ b/composer.json
@@ -13,6 +13,7 @@
         }
     },
     "require": {
+        "google/apiclient": "^2.8",
         "slim/slim": "^4.5",
         "slim/psr7": "^1.2"
     },
@@ -22,5 +23,13 @@
     },
     "config": {
         "sort-packages": true
+    },
+    "scripts": {
+        "post-update-cmd": "Google\\Task\\Composer::cleanup"
+    },
+    "extra": {
+        "google/apiclient-services": [
+            "Sheets"
+        ]
     }
 }
diff --git a/composer.lock b/composer.lock
index 68d91c6..cdbd120 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": "606fe156b60108e10c413d1dda797b79",
+    "content-hash": "97e9d1a8aa2a2d61bfb97a92fdc97996",
     "packages": [
         {
             "name": "fig/http-message-util",
@@ -58,6 +58,521 @@
             ],
             "time": "2020-02-05T20:36:27+00:00"
         },
+        {
+            "name": "firebase/php-jwt",
+            "version": "v5.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/firebase/php-jwt.git",
+                "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/feb0e820b8436873675fd3aca04f3728eb2185cb",
+                "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": ">=4.8 <=9"
+            },
+            "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"
+            ],
+            "time": "2020-03-25T18:49:23+00:00"
+        },
+        {
+            "name": "google/apiclient",
+            "version": "v2.8.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/googleapis/google-api-php-client.git",
+                "reference": "cf9a070f9da78cd207a69b2a94832d381c8c4163"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/cf9a070f9da78cd207a69b2a94832d381c8c4163",
+                "reference": "cf9a070f9da78cd207a69b2a94832d381c8c4163",
+                "shasum": ""
+            },
+            "require": {
+                "firebase/php-jwt": "~2.0||~3.0||~4.0||~5.0",
+                "google/apiclient-services": "~0.13",
+                "google/auth": "^1.10",
+                "guzzlehttp/guzzle": "~5.3.1||~6.0||~7.0",
+                "guzzlehttp/psr7": "^1.2",
+                "monolog/monolog": "^1.17|^2.0",
+                "php": ">=5.4",
+                "phpseclib/phpseclib": "~0.3.10||~2.0"
+            },
+            "require-dev": {
+                "cache/filesystem-adapter": "^0.3.2",
+                "composer/composer": "^1.10",
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
+                "phpcompatibility/php-compatibility": "^9.2",
+                "phpunit/phpunit": "^4.8.36|^5.0",
+                "squizlabs/php_codesniffer": "~2.3",
+                "symfony/css-selector": "~2.1",
+                "symfony/dom-crawler": "~2.1"
+            },
+            "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"
+            ],
+            "time": "2020-10-23T20:29:29+00:00"
+        },
+        {
+            "name": "google/apiclient-services",
+            "version": "v0.151",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/googleapis/google-api-php-client-services.git",
+                "reference": "784a4fdb110b67a2344cfbdbf927194bd29f9e73"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/784a4fdb110b67a2344cfbdbf927194bd29f9e73",
+                "reference": "784a4fdb110b67a2344cfbdbf927194bd29f9e73",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8|^5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Google_Service_": "src"
+                }
+            },
+            "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"
+            ],
+            "time": "2020-10-19T00:26:26+00:00"
+        },
+        {
+            "name": "google/auth",
+            "version": "v1.14.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/googleapis/google-auth-library-php.git",
+                "reference": "c1503299c779af0cbc99b43788f75930988852cf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/c1503299c779af0cbc99b43788f75930988852cf",
+                "reference": "c1503299c779af0cbc99b43788f75930988852cf",
+                "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.2",
+                "php": ">=5.4",
+                "psr/cache": "^1.0",
+                "psr/http-message": "^1.0"
+            },
+            "require-dev": {
+                "guzzlehttp/promises": "0.1.1|^1.3",
+                "kelvinmo/simplejwt": "^0.2.5",
+                "phpseclib/phpseclib": "^2",
+                "phpunit/phpunit": "^4.8.36|^5.7",
+                "sebastian/comparator": ">=1.2.3",
+                "squizlabs/php_codesniffer": "^3.5"
+            },
+            "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"
+            ],
+            "time": "2020-10-16T21:33:48+00:00"
+        },
+        {
+            "name": "guzzlehttp/guzzle",
+            "version": "7.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/guzzle.git",
+                "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0aa74dfb41ae110835923ef10a9d803a22d50e79",
+                "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "guzzlehttp/promises": "^1.4",
+                "guzzlehttp/psr7": "^1.7",
+                "php": "^7.2.5 || ^8.0",
+                "psr/http-client": "^1.0"
+            },
+            "provide": {
+                "psr/http-client-implementation": "1.0"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "php-http/client-integration-tests": "^3.0",
+                "phpunit/phpunit": "^8.5.5 || ^9.3.5",
+                "psr/log": "^1.1"
+            },
+            "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.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://sagikazarmark.hu"
+                }
+            ],
+            "description": "Guzzle is a PHP HTTP client library",
+            "homepage": "http://guzzlephp.org/",
+            "keywords": [
+                "client",
+                "curl",
+                "framework",
+                "http",
+                "http client",
+                "psr-18",
+                "psr-7",
+                "rest",
+                "web service"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/Nyholm",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/alexeyshockov",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/gmponos",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-10T11:47:56+00:00"
+        },
+        {
+            "name": "guzzlehttp/promises",
+            "version": "1.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/promises.git",
+                "reference": "60d379c243457e073cff02bc323a2a86cb355631"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631",
+                "reference": "60d379c243457e073cff02bc323a2a86cb355631",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "symfony/phpunit-bridge": "^4.4 || ^5.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Promise\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Guzzle promises library",
+            "keywords": [
+                "promise"
+            ],
+            "time": "2020-09-30T07:37:28+00:00"
+        },
+        {
+            "name": "guzzlehttp/psr7",
+            "version": "1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/psr7.git",
+                "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3",
+                "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0",
+                "psr/http-message": "~1.0",
+                "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+            },
+            "provide": {
+                "psr/http-message-implementation": "1.0"
+            },
+            "require-dev": {
+                "ext-zlib": "*",
+                "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
+            },
+            "suggest": {
+                "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Psr7\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Tobias Schultze",
+                    "homepage": "https://github.com/Tobion"
+                }
+            ],
+            "description": "PSR-7 message implementation that also provides common utility methods",
+            "keywords": [
+                "http",
+                "message",
+                "psr-7",
+                "request",
+                "response",
+                "stream",
+                "uri",
+                "url"
+            ],
+            "time": "2020-09-30T07:37:11+00:00"
+        },
+        {
+            "name": "monolog/monolog",
+            "version": "2.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/monolog.git",
+                "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f9eee5cec93dfb313a38b6b288741e84e53f02d5",
+                "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2",
+                "psr/log": "^1.0.1"
+            },
+            "provide": {
+                "psr/log-implementation": "1.0.0"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+                "doctrine/couchdb": "~1.0@dev",
+                "elasticsearch/elasticsearch": "^6.0",
+                "graylog2/gelf-php": "^1.4.2",
+                "php-amqplib/php-amqplib": "~2.4",
+                "php-console/php-console": "^3.1.3",
+                "php-parallel-lint/php-parallel-lint": "^1.0",
+                "phpspec/prophecy": "^1.6.1",
+                "phpunit/phpunit": "^8.5",
+                "predis/predis": "^1.1",
+                "rollbar/rollbar": "^1.3",
+                "ruflin/elastica": ">=0.90 <3.0",
+                "swiftmailer/swiftmailer": "^5.3|^6.0"
+            },
+            "suggest": {
+                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+                "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
+                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+                "ext-mbstring": "Allow to work properly with unicode symbols",
+                "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
+                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+                "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
+                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+                "php-console/php-console": "Allow sending log messages to Google Chrome",
+                "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-master": "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": "http://seld.be"
+                }
+            ],
+            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+            "homepage": "http://github.com/Seldaek/monolog",
+            "keywords": [
+                "log",
+                "logging",
+                "psr-3"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/Seldaek",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-07-23T08:41:23+00:00"
+        },
         {
             "name": "nikic/fast-route",
             "version": "v1.3.0",
@@ -104,6 +619,157 @@
             ],
             "time": "2018-02-13T20:26:39+00:00"
         },
+        {
+            "name": "phpseclib/phpseclib",
+            "version": "2.0.29",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpseclib/phpseclib.git",
+                "reference": "497856a8d997f640b4a516062f84228a772a48a8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/497856a8d997f640b4a516062f84228a772a48a8",
+                "reference": "497856a8d997f640b4a516062f84228a772a48a8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phing/phing": "~2.7",
+                "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
+                "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": {
+                    "phpseclib\\": "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"
+            ],
+            "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": "2020-09-08T04:24:43+00:00"
+        },
+        {
+            "name": "psr/cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/cache.git",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Cache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for caching libraries",
+            "keywords": [
+                "cache",
+                "psr",
+                "psr-6"
+            ],
+            "time": "2016-08-06T20:24:11+00:00"
+        },
         {
             "name": "psr/container",
             "version": "1.0.0",
@@ -153,6 +819,55 @@
             ],
             "time": "2017-02-14T16:28:37+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"
+            ],
+            "time": "2020-06-29T06:28:15+00:00"
+        },
         {
             "name": "psr/http-factory",
             "version": "1.0.1",
@@ -705,16 +1420,16 @@
         },
         {
             "name": "composer/xdebug-handler",
-            "version": "1.4.3",
+            "version": "1.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/composer/xdebug-handler.git",
-                "reference": "ebd27a9866ae8254e873866f795491f02418c5a5"
+                "reference": "6e076a124f7ee146f2487554a94b6a19a74887ba"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ebd27a9866ae8254e873866f795491f02418c5a5",
-                "reference": "ebd27a9866ae8254e873866f795491f02418c5a5",
+                "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6e076a124f7ee146f2487554a94b6a19a74887ba",
+                "reference": "6e076a124f7ee146f2487554a94b6a19a74887ba",
                 "shasum": ""
             },
             "require": {
@@ -759,20 +1474,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-08-19T10:27:58+00:00"
+            "time": "2020-10-24T12:39:10+00:00"
         },
         {
             "name": "doctrine/annotations",
-            "version": "1.10.4",
+            "version": "1.11.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/annotations.git",
-                "reference": "bfe91e31984e2ba76df1c1339681770401ec262f"
+                "reference": "88fb6fb1dae011de24dd6b632811c1ff5c2928f5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/annotations/zipball/bfe91e31984e2ba76df1c1339681770401ec262f",
-                "reference": "bfe91e31984e2ba76df1c1339681770401ec262f",
+                "url": "https://api.github.com/repos/doctrine/annotations/zipball/88fb6fb1dae011de24dd6b632811c1ff5c2928f5",
+                "reference": "88fb6fb1dae011de24dd6b632811c1ff5c2928f5",
                 "shasum": ""
             },
             "require": {
@@ -782,13 +1497,14 @@
             },
             "require-dev": {
                 "doctrine/cache": "1.*",
+                "doctrine/coding-standard": "^6.0 || ^8.1",
                 "phpstan/phpstan": "^0.12.20",
                 "phpunit/phpunit": "^7.5 || ^9.1.5"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.9.x-dev"
+                    "dev-master": "1.11.x-dev"
                 }
             },
             "autoload": {
@@ -823,13 +1539,13 @@
                 }
             ],
             "description": "Docblock Annotations Parser",
-            "homepage": "http://www.doctrine-project.org",
+            "homepage": "https://www.doctrine-project.org/projects/annotations.html",
             "keywords": [
                 "annotations",
                 "docblock",
                 "parser"
             ],
-            "time": "2020-08-10T19:35:50+00:00"
+            "time": "2020-10-17T22:05:33+00:00"
         },
         {
             "name": "doctrine/instantiator",
-- 
GitLab


From 9cffafcb10084f3b407b50d14682f5253506c3a5 Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Sat, 24 Oct 2020 19:13:26 +0000
Subject: [PATCH 2/8] Add phpdotenv dependency (#1)

---
 composer.json |   3 +-
 composer.lock | 703 ++++++++++++++++++++++++++++++++------------------
 2 files changed, 455 insertions(+), 251 deletions(-)

diff --git a/composer.json b/composer.json
index 7c4f792..59d07ff 100644
--- a/composer.json
+++ b/composer.json
@@ -15,7 +15,8 @@
     "require": {
         "google/apiclient": "^2.8",
         "slim/slim": "^4.5",
-        "slim/psr7": "^1.2"
+        "slim/psr7": "^1.2",
+        "vlucas/phpdotenv": "^5.2"
     },
     "require-dev": {
         "friendsofphp/php-cs-fixer": "^2.15",
diff --git a/composer.lock b/composer.lock
index cdbd120..82b9412 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": "97e9d1a8aa2a2d61bfb97a92fdc97996",
+    "content-hash": "19a4921a70e47cef1bf577d177349004",
     "packages": [
         {
             "name": "fig/http-message-util",
@@ -262,6 +262,68 @@
             ],
             "time": "2020-10-16T21:33:48+00:00"
         },
+        {
+            "name": "graham-campbell/result-type",
+            "version": "v1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/GrahamCampbell/Result-Type.git",
+                "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/7e279d2cd5d7fbb156ce46daada972355cea27bb",
+                "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0|^8.0",
+                "phpoption/phpoption": "^1.7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.5|^7.5|^8.5|^9.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GrahamCampbell\\ResultType\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com"
+                }
+            ],
+            "description": "An Implementation Of The Result Type",
+            "keywords": [
+                "Graham Campbell",
+                "GrahamCampbell",
+                "Result Type",
+                "Result-Type",
+                "result"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-04-13T13:17:36+00:00"
+        },
         {
             "name": "guzzlehttp/guzzle",
             "version": "7.2.0",
@@ -619,6 +681,71 @@
             ],
             "time": "2018-02-13T20:26:39+00:00"
         },
+        {
+            "name": "phpoption/phpoption",
+            "version": "1.7.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/schmittjoh/php-option.git",
+                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525",
+                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpOption\\": "src/PhpOption/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Johannes M. Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                },
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com"
+                }
+            ],
+            "description": "Option Type for PHP",
+            "keywords": [
+                "language",
+                "option",
+                "php",
+                "type"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-07-20T17:29:33+00:00"
+        },
         {
             "name": "phpseclib/phpseclib",
             "version": "2.0.29",
@@ -1311,35 +1438,344 @@
                     "homepage": "http://akrabat.com"
                 },
                 {
-                    "name": "Pierre Berube",
-                    "email": "pierre@lgse.com",
-                    "homepage": "http://www.lgse.com"
+                    "name": "Pierre Berube",
+                    "email": "pierre@lgse.com",
+                    "homepage": "http://www.lgse.com"
+                },
+                {
+                    "name": "Gabriel Manricks",
+                    "email": "gmanricks@me.com",
+                    "homepage": "http://gabrielmanricks.com"
+                }
+            ],
+            "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
+            "homepage": "https://www.slimframework.com",
+            "keywords": [
+                "api",
+                "framework",
+                "micro",
+                "router"
+            ],
+            "funding": [
+                {
+                    "url": "https://opencollective.com/slimphp",
+                    "type": "open_collective"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/slim/slim",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-04-14T20:49:48+00:00"
+        },
+        {
+            "name": "symfony/polyfill-ctype",
+            "version": "v1.19.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-ctype.git",
+                "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b",
+                "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-ctype": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.19-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for ctype functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
+            ],
+            "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-10-23T09:01:57+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.19.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "b5f7b932ee6fa802fc792eabd77c4c88084517ce"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b5f7b932ee6fa802fc792eabd77c4c88084517ce",
+                "reference": "b5f7b932ee6fa802fc792eabd77c4c88084517ce",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.19-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "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-10-23T09:01:57+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php80",
+            "version": "v1.19.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "f54ef00f4678f348f133097fa8c3701d197ff44d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/f54ef00f4678f348f133097fa8c3701d197ff44d",
+                "reference": "f54ef00f4678f348f133097fa8c3701d197ff44d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.19-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "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-10-23T09:01:57+00:00"
+        },
+        {
+            "name": "vlucas/phpdotenv",
+            "version": "v5.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/vlucas/phpdotenv.git",
+                "reference": "fba64139db67123c7a57072e5f8d3db10d160b66"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/fba64139db67123c7a57072e5f8d3db10d160b66",
+                "reference": "fba64139db67123c7a57072e5f8d3db10d160b66",
+                "shasum": ""
+            },
+            "require": {
+                "ext-pcre": "*",
+                "graham-campbell/result-type": "^1.0.1",
+                "php": "^7.1.3 || ^8.0",
+                "phpoption/phpoption": "^1.7.4",
+                "symfony/polyfill-ctype": "^1.17",
+                "symfony/polyfill-mbstring": "^1.17",
+                "symfony/polyfill-php80": "^1.17"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "ext-filter": "*",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.2 || ^9.0"
+            },
+            "suggest": {
+                "ext-filter": "Required to use the boolean validator."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Dotenv\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com",
+                    "homepage": "https://gjcampbell.co.uk/"
                 },
                 {
-                    "name": "Gabriel Manricks",
-                    "email": "gmanricks@me.com",
-                    "homepage": "http://gabrielmanricks.com"
+                    "name": "Vance Lucas",
+                    "email": "vance@vancelucas.com",
+                    "homepage": "https://vancelucas.com/"
                 }
             ],
-            "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
-            "homepage": "https://www.slimframework.com",
+            "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
             "keywords": [
-                "api",
-                "framework",
-                "micro",
-                "router"
+                "dotenv",
+                "env",
+                "environment"
             ],
             "funding": [
                 {
-                    "url": "https://opencollective.com/slimphp",
-                    "type": "open_collective"
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
                 },
                 {
-                    "url": "https://tidelift.com/funding/github/packagist/slim/slim",
+                    "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-04-14T20:49:48+00:00"
+            "time": "2020-09-14T15:57:31+00:00"
         }
     ],
     "packages-dev": [
@@ -4164,82 +4600,6 @@
             ],
             "time": "2020-09-27T03:44:28+00:00"
         },
-        {
-            "name": "symfony/polyfill-ctype",
-            "version": "v1.19.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b",
-                "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-ctype": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-main": "1.19-dev"
-                },
-                "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Ctype\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Gert de Pagter",
-                    "email": "BackEndTea@gmail.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for ctype functions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "ctype",
-                "polyfill",
-                "portable"
-            ],
-            "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-10-23T09:01:57+00:00"
-        },
         {
             "name": "symfony/polyfill-intl-grapheme",
             "version": "v1.19.0",
@@ -4399,83 +4759,6 @@
             ],
             "time": "2020-10-23T09:01:57+00:00"
         },
-        {
-            "name": "symfony/polyfill-mbstring",
-            "version": "v1.19.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "b5f7b932ee6fa802fc792eabd77c4c88084517ce"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b5f7b932ee6fa802fc792eabd77c4c88084517ce",
-                "reference": "b5f7b932ee6fa802fc792eabd77c4c88084517ce",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-mbstring": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-main": "1.19-dev"
-                },
-                "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
-                }
-            },
-            "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-10-23T09:01:57+00:00"
-        },
         {
             "name": "symfony/polyfill-php70",
             "version": "v1.19.0",
@@ -4702,86 +4985,6 @@
             ],
             "time": "2020-10-23T09:01:57+00:00"
         },
-        {
-            "name": "symfony/polyfill-php80",
-            "version": "v1.19.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php80.git",
-                "reference": "f54ef00f4678f348f133097fa8c3701d197ff44d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/f54ef00f4678f348f133097fa8c3701d197ff44d",
-                "reference": "f54ef00f4678f348f133097fa8c3701d197ff44d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.0.8"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-main": "1.19-dev"
-                },
-                "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
-                }
-            },
-            "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-10-23T09:01:57+00:00"
-        },
         {
             "name": "symfony/process",
             "version": "v5.1.7",
-- 
GitLab


From 5e548b5403e91af1b341ba0714c9b9d92b7607af Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Sat, 24 Oct 2020 20:10:22 +0000
Subject: [PATCH 3/8] [WIP] Create API client wrapper class (#1)

---
 .gitignore        | 87 ++++++++++++++++++++++++++---------------------
 src/.env.example  |  1 +
 src/APIClient.php | 35 +++++++++++++++++++
 3 files changed, 84 insertions(+), 39 deletions(-)
 create mode 100644 src/.env.example
 create mode 100644 src/APIClient.php

diff --git a/.gitignore b/.gitignore
index 7d7f20e..1cdd93f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,39 +1,48 @@
-# Created by https://www.toptal.com/developers/gitignore/api/phpunit,composer,visualstudiocode
-# Edit at https://www.toptal.com/developers/gitignore?templates=phpunit,composer,visualstudiocode
-
-### Composer ###
-composer.phar
-/vendor/
-
-# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
-# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
-# composer.lock
-
-### PHPUnit ###
-# Covers PHPUnit
-# Reference: https://phpunit.de/
-
-# Generated files
-.phpunit.result.cache
-
-# PHPUnit
-/app/phpunit.xml
-/phpunit.xml
-
-# Build data
-/build/
-
-### VisualStudioCode ###
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
-*.code-workspace
-
-### VisualStudioCode Patch ###
-# Ignore all local history of files
-.history
-.ionide
-
-# End of https://www.toptal.com/developers/gitignore/api/phpunit,composer,visualstudiocode
+# Created by https://www.toptal.com/developers/gitignore/api/phpunit,composer,visualstudiocode
+# Edit at https://www.toptal.com/developers/gitignore?templates=phpunit,composer,visualstudiocode
+
+### Composer ###
+composer.phar
+/vendor/
+
+# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
+# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
+# composer.lock
+
+### PHPUnit ###
+# Covers PHPUnit
+# Reference: https://phpunit.de/
+
+# Generated files
+.phpunit.result.cache
+
+# PHPUnit
+/app/phpunit.xml
+/phpunit.xml
+
+# Build data
+/build/
+
+### VisualStudioCode ###
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
+.ionide
+
+# End of https://www.toptal.com/developers/gitignore/api/phpunit,composer,visualstudiocode
+
+### Project-specific ###
+
+# Google API credentials
+src/config/*.json
+
+# Environment variables
+.env
+!.env.example
diff --git a/src/.env.example b/src/.env.example
new file mode 100644
index 0000000..e04d457
--- /dev/null
+++ b/src/.env.example
@@ -0,0 +1 @@
+GOOGLE_AUTH_CONFIG_FILE=/opt/example/foobar.json
diff --git a/src/APIClient.php b/src/APIClient.php
new file mode 100644
index 0000000..8369e4b
--- /dev/null
+++ b/src/APIClient.php
@@ -0,0 +1,35 @@
+<?php
+declare(strict_types=1);
+
+namespace addianto\LionGame\Backend;
+
+use Dotenv\Dotenv;
+use Google\Client;
+use Google_Service_Sheets as GoogleSheetsAPI;
+
+$dotenv = Dotenv::createImmutable(__DIR__);
+$dotenv->required("GOOGLE_AUTH_CONFIG_FILE");
+$dotenv->load();
+
+class APIClient
+{
+    private Client $client;
+
+    public function __construct()
+    {
+        $client = new Client();
+
+        $this->buildClient($client);
+
+        $this->client = $client;
+    }
+
+    private function buildClient(Client $client): void
+    {
+        $client->setApplicationName("Lion Game Backend");
+        $client->setScopes(GoogleSheetsAPI::SPREADSHEETS);
+        $client->setAuthConfig($_ENV["GOOGLE_AUTH_CONFIG_FILE"]);
+        $client->setAccessType("offline");
+        $client->setPrompt("none");
+    }
+}
-- 
GitLab


From 0dc4e40dbe1de5bfaa1ac0a4cd0fc0687e390f88 Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Mon, 26 Oct 2020 12:38:31 +0700
Subject: [PATCH 4/8] [WIP] Setup unit tests

---
 composer.json                       |   8 +-
 composer.lock                       | 173 +++++++++++++++++++++++++++-
 src/.env.example                    |   3 +-
 src/APIClient.php                   |  35 ------
 src/App.php                         |   6 +-
 src/config/Config.php               |  32 +++++
 src/index.php                       |   6 +
 src/service/SheetsService.php       |  54 +++++++++
 tests/config/ConfigTest.php         |  33 ++++++
 tests/config/example.json           |  12 ++
 tests/service/SheetsServiceTest.php |  14 +++
 11 files changed, 336 insertions(+), 40 deletions(-)
 delete mode 100644 src/APIClient.php
 create mode 100644 src/config/Config.php
 create mode 100644 src/service/SheetsService.php
 create mode 100644 tests/config/ConfigTest.php
 create mode 100644 tests/config/example.json
 create mode 100644 tests/service/SheetsServiceTest.php

diff --git a/composer.json b/composer.json
index 59d07ff..43cfeb6 100644
--- a/composer.json
+++ b/composer.json
@@ -4,12 +4,15 @@
     "version": "0.1.0",
     "autoload": {
         "psr-4": {
-            "addianto\\LionGame\\Backend\\": "src/"
+            "addianto\\LionGame\\Backend\\": "src/",
+            "addianto\\LionGame\\Backend\\Config\\": "src/config/",
+            "addianto\\LionGame\\Backend\\Service\\": "src/service/"
         }
     },
     "autoload-dev": {
         "psr-4": {
-            "addianto\\LionGame\\Backend\\Test\\": "tests/"
+            "addianto\\LionGame\\Backend\\Test\\": "tests/",
+            "addianto\\LionGame\\Backend\\Test\\Config\\": "tests/config/"
         }
     },
     "require": {
@@ -20,6 +23,7 @@
     },
     "require-dev": {
         "friendsofphp/php-cs-fixer": "^2.15",
+        "php-mock/php-mock-phpunit": "^2.6",
         "phpunit/phpunit": "^9"
     },
     "config": {
diff --git a/composer.lock b/composer.lock
index 82b9412..5edc499 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": "19a4921a70e47cef1bf577d177349004",
+    "content-hash": "69f8854bea11845783251b07b439ec3d",
     "packages": [
         {
             "name": "fig/http-message-util",
@@ -2531,6 +2531,177 @@
             ],
             "time": "2020-10-14T08:39:05+00:00"
         },
+        {
+            "name": "php-mock/php-mock",
+            "version": "2.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-mock/php-mock.git",
+                "reference": "890d3e32e3a5f29715a8fd17debd87a0c9e614a0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-mock/php-mock/zipball/890d3e32e3a5f29715a8fd17debd87a0c9e614a0",
+                "reference": "890d3e32e3a5f29715a8fd17debd87a0c9e614a0",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0",
+                "phpunit/php-text-template": "^1 || ^2"
+            },
+            "replace": {
+                "malkusch/php-mock": "*"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.0 || ^9.0"
+            },
+            "suggest": {
+                "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock."
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "autoload.php"
+                ],
+                "psr-4": {
+                    "phpmock\\": [
+                        "classes/",
+                        "tests/"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "WTFPL"
+            ],
+            "authors": [
+                {
+                    "name": "Markus Malkusch",
+                    "email": "markus@malkusch.de",
+                    "homepage": "http://markus.malkusch.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.",
+            "homepage": "https://github.com/php-mock/php-mock",
+            "keywords": [
+                "BDD",
+                "TDD",
+                "function",
+                "mock",
+                "stub",
+                "test",
+                "test double"
+            ],
+            "time": "2020-04-17T16:39:00+00:00"
+        },
+        {
+            "name": "php-mock/php-mock-integration",
+            "version": "2.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-mock/php-mock-integration.git",
+                "reference": "003d585841e435958a02e9b986953907b8b7609b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/003d585841e435958a02e9b986953907b8b7609b",
+                "reference": "003d585841e435958a02e9b986953907b8b7609b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6",
+                "php-mock/php-mock": "^2.2",
+                "phpunit/php-text-template": "^1 || ^2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7.27 || ^6 || ^7 || ^8 || ^9"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "phpmock\\integration\\": "classes/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "WTFPL"
+            ],
+            "authors": [
+                {
+                    "name": "Markus Malkusch",
+                    "email": "markus@malkusch.de",
+                    "homepage": "http://markus.malkusch.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Integration package for PHP-Mock",
+            "homepage": "https://github.com/php-mock/php-mock-integration",
+            "keywords": [
+                "BDD",
+                "TDD",
+                "function",
+                "mock",
+                "stub",
+                "test",
+                "test double"
+            ],
+            "time": "2020-02-08T14:40:25+00:00"
+        },
+        {
+            "name": "php-mock/php-mock-phpunit",
+            "version": "2.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-mock/php-mock-phpunit.git",
+                "reference": "2877a0e58f12e91b64bf36ccd080a209dcbf6c30"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/2877a0e58f12e91b64bf36ccd080a209dcbf6c30",
+                "reference": "2877a0e58f12e91b64bf36ccd080a209dcbf6c30",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7",
+                "php-mock/php-mock-integration": "^2.1",
+                "phpunit/phpunit": "^6 || ^7 || ^8 || ^9"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "autoload.php"
+                ],
+                "psr-4": {
+                    "phpmock\\phpunit\\": "classes/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "WTFPL"
+            ],
+            "authors": [
+                {
+                    "name": "Markus Malkusch",
+                    "email": "markus@malkusch.de",
+                    "homepage": "http://markus.malkusch.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Mock built-in PHP functions (e.g. time()) with PHPUnit. This package relies on PHP's namespace fallback policy. No further extension is needed.",
+            "homepage": "https://github.com/php-mock/php-mock-phpunit",
+            "keywords": [
+                "BDD",
+                "TDD",
+                "function",
+                "mock",
+                "phpunit",
+                "stub",
+                "test",
+                "test double"
+            ],
+            "time": "2020-02-08T15:44:47+00:00"
+        },
         {
             "name": "phpdocumentor/reflection-common",
             "version": "2.2.0",
diff --git a/src/.env.example b/src/.env.example
index e04d457..027c888 100644
--- a/src/.env.example
+++ b/src/.env.example
@@ -1 +1,2 @@
-GOOGLE_AUTH_CONFIG_FILE=/opt/example/foobar.json
+GOOGLE_APPLICATION_CREDENTIALS=/opt/liongame/service-account.json
+SPREADSHEET_ID=1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms
diff --git a/src/APIClient.php b/src/APIClient.php
deleted file mode 100644
index 8369e4b..0000000
--- a/src/APIClient.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace addianto\LionGame\Backend;
-
-use Dotenv\Dotenv;
-use Google\Client;
-use Google_Service_Sheets as GoogleSheetsAPI;
-
-$dotenv = Dotenv::createImmutable(__DIR__);
-$dotenv->required("GOOGLE_AUTH_CONFIG_FILE");
-$dotenv->load();
-
-class APIClient
-{
-    private Client $client;
-
-    public function __construct()
-    {
-        $client = new Client();
-
-        $this->buildClient($client);
-
-        $this->client = $client;
-    }
-
-    private function buildClient(Client $client): void
-    {
-        $client->setApplicationName("Lion Game Backend");
-        $client->setScopes(GoogleSheetsAPI::SPREADSHEETS);
-        $client->setAuthConfig($_ENV["GOOGLE_AUTH_CONFIG_FILE"]);
-        $client->setAccessType("offline");
-        $client->setPrompt("none");
-    }
-}
diff --git a/src/App.php b/src/App.php
index f2db0bb..01bf1a1 100644
--- a/src/App.php
+++ b/src/App.php
@@ -7,14 +7,17 @@ use Psr\Http\Message\ServerRequestInterface as Request;
 use Psr\Http\Message\ResponseInterface as Response;
 use Slim\Factory\AppFactory;
 use Slim\App as SlimApp;
+use addianto\LionGame\Backend\Service\SheetsService;
 
 class App
 {
     private SlimApp $app;
+    private SheetsService $sheets;
 
     public function __construct(bool $debug = false)
     {
         $this->app = AppFactory::create();
+        $this->sheets = SheetsService::getInstance();
 
         $this->addErrorMiddleware($debug);
         $this->handleBase();
@@ -35,7 +38,8 @@ class App
     private function handleBase(): void
     {
         $this->app->get('/', function (Request $request, Response $response, $args) {
-            $response->getBody()->write("Hello, world!");
+            $range = "'Play Session Analytics (Example)'!A:AC";
+            $response->getBody()->write("Hello, World!");
             return $response;
         });
     }
diff --git a/src/config/Config.php b/src/config/Config.php
new file mode 100644
index 0000000..e9c1d60
--- /dev/null
+++ b/src/config/Config.php
@@ -0,0 +1,32 @@
+<?php
+declare(strict_types=1);
+
+namespace addianto\LionGame\Backend\Config;
+
+use Google\Client;
+use Google_Service_Sheets as GoogleSheetsAPI;
+
+class Config
+{
+    private function __construct()
+    {
+        // Do nothing
+    }
+
+    public static function createGoogleAPIClient(string $appName, string $appCredentials): Client
+    {
+        $client = new Client();
+
+        $client->setApplicationName($appName);
+        $client->setAuthConfig($appCredentials);
+        $client->setScopes(GoogleSheetsAPI::SPREADSHEETS);
+        $client->setPrompt("none");
+
+        return $client;
+    }
+
+    public static function createGoogleSheetsAPI(Client $client): GoogleSheetsAPI
+    {
+        return new GoogleSheetsAPI($client);
+    }
+}
diff --git a/src/index.php b/src/index.php
index bece6b0..5867147 100644
--- a/src/index.php
+++ b/src/index.php
@@ -3,10 +3,16 @@ declare(strict_types=1);
 
 namespace addianto\LionGame\Backend;
 
+use Dotenv\Dotenv;
 use addianto\LionGame\Backend\App;
 
 require __DIR__ . '/../vendor/autoload.php';
 
+$dotenv = Dotenv::createImmutable(__DIR__);
+$dotenv->load();
+$dotenv->required("GOOGLE_APPLICATION_CREDENTIALS");
+$dotenv->required("SPREADSHEET_ID");
+
 // Run the app
 $app = (new App(true))->get();
 $app->run();
diff --git a/src/service/SheetsService.php b/src/service/SheetsService.php
new file mode 100644
index 0000000..1cd9019
--- /dev/null
+++ b/src/service/SheetsService.php
@@ -0,0 +1,54 @@
+<?php
+declare(strict_types=1);
+
+namespace addianto\LionGame\Backend\Service;
+
+use Google_Service_Sheets as GoogleSheetsAPI;
+use Google_Service_Sheets_ValueRange as ValueRange;
+use Google_Service_Sheets_AppendValuesResponse as AppendValuesResponse;
+use is_null;
+
+class SheetsService
+{
+    private static ?SheetsService $instance = null;
+    private GoogleSheetsAPI $api;
+    private string $spreadsheetId;
+
+    private function __construct(GoogleSheetsAPI $api, string $spreadsheetId)
+    {
+        $this->api = $api;
+        $this->spreadsheetId = $spreadsheetId;
+    }
+
+    public function getValues(string $range): array
+    {
+        $response = $this->api
+            ->spreadsheets_values
+            ->get($this->spreadsheetId, $range);
+
+        return $response->getValues();
+    }
+
+    public function appendValues(string $range, array $values): void
+    {
+        $body = new ValueRange([
+            "majorDimension" => "ROWS",
+            "values" => array($values),
+        ]);
+        $optionalParameters = array(
+            "valueInputOption" => "RAW",
+        );
+        $response = $this->api
+            ->spreadsheets_values
+            ->append($this->spreadsheetId, $range, $body, $optionalParameters);
+    }
+
+    public static function getInstance(GoogleSheetsAPI $api, string $spreadsheetId): SheetsService
+    {
+        if (is_null(self::$instance)) {
+            self::$instance = new SheetsService($api, $spreadsheetId);
+        }
+
+        return self::$instance;
+    }
+}
diff --git a/tests/config/ConfigTest.php b/tests/config/ConfigTest.php
new file mode 100644
index 0000000..7cf3f04
--- /dev/null
+++ b/tests/config/ConfigTest.php
@@ -0,0 +1,33 @@
+<?php
+declare(strict_types=1);
+
+namespace addianto\LionGame\Backend\Config\Test;
+
+use PHPUnit\Framework\TestCase;
+use Google_Service_Sheets as GoogleSheetsAPI;
+use addianto\LionGame\Backend\Config\Config;
+
+class ConfigTest extends TestCase
+{
+    private array $fixture = array(
+        "applicationCredentials" => __DIR__ . "/example.json",
+    );
+
+    public function testCreateGoogleAPIClient(): void
+    {
+        $client = Config::createGoogleAPIClient("Test App", $this->fixture["applicationCredentials"]);
+
+        $this->assertFileIsReadable($this->fixture["applicationCredentials"]);
+        $this->assertEquals("Test App", $client->getConfig("application_name"));
+        $this->assertEquals(GoogleSheetsAPI::SPREADSHEETS, $client->getScopes()[0]);
+    }
+
+    public function testCreateGoogleSheetsAPI(): void
+    {
+        $api = Config::createGoogleSheetsAPI(
+            Config::createGoogleAPIClient("Test App", $this->fixture["applicationCredentials"])
+        );
+
+        $this->assertInstanceOf(GoogleSheetsAPI::class, $api);
+    }
+}
diff --git a/tests/config/example.json b/tests/config/example.json
new file mode 100644
index 0000000..358eca2
--- /dev/null
+++ b/tests/config/example.json
@@ -0,0 +1,12 @@
+{
+  "type": "service_account",
+  "project_id": "example",
+  "private_key_id": "ffffffffffffffffffffffffffffffffffffffff",
+  "private_key": "-----BEGIN PRIVATE KEY-----\n0000000000000000000000000000000000000000000000000000000000000000\n1111111111111111111111111111111111111111111111111111111111111111\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\nu0hJNJ+94Iievs4nryU/vYFTG2uPPdSpdi4PAEixnQfUsDPf2PrJCjEDjXbaCmeL\n9R8Mwr7a89ptyphgwTyw7zFVt5hsMilwpOxxMg2kq9F3kn08L9/55CPk3G0LlM42\nWDi9NXn9AgMBAAECggEACfOWsTldefUByeb6m4SncpyxtVASMggmWyoKR4bRRJLf\nAMLyDSv93zgWppVu3hcvXiI6RWOcMwUWx4X2lO8xzHwODulzey21u/QJLAMFRSLo\nHbGGdqSuRKJ/0ugtMrgPXs8dDk+2poH4k1T6Aoi3G++u7q/tFH3JLSs2NeCbrZRd\nYLlwufFON9fOKn0EoRRNbtrSREabk2HFim7Y4OjmIVvZPitIGds0OTo6lyhwtUzx\nXBCbVNDB0N6svVLlvc7Tyqtg7TmXUZ6KRYtUCYoVlrEkAbfd6sIGkamVgPZ1S04T\nZ87sBBmAS8g1m7Q4JqaADv00dJSVUKWPgtfwfVueqwKBgQC2Wxom3nUViLxqNhel\n+wg6hXxoYybOpobWryMs4jwEBG/GVzhHtvIuXFAl3H/aWsVPEXpwj8z11athpFu3\nM6jEdkFRPJBppNzYxvHl/kJJF5HgPNQ0Vn6nsKErI0hzw96VC9gTUsA+AImNv2hx\nAObz9EymxiOhPGoh5LZwKkFIawKBgQC1UiMd4HJ2bzsHRgGHOgMkp1gViy+dPbbi\nzKIUKiuIUb0UaM67G9QnnNucCHbrVX4xIVn+RINRj1bwO8FolfQnv3KHyRdwDu7z\neiBeweQMx2BRzgGWlGpQEU5lYVtvGCXQYB6Ol3XFVceYuBjRWjP5Gjzk4nCbe3hv\nnN7VG1OBNwKBgQCLfSaFAveG8GBH0nbGdT63HTKr2uRtgL516+Q5ShjkbcxeaItZ\neBzKz7xTKdb23SY+tDz3a1g52CbPetzZR3/aQCb4kB5bYUu52nxhFNv5czkX0Q/1\ntRAPD7JJACVEwFg7pKK1LUB2bQzLS9YFUs5XX9FeZQQOKtt4b64KIJhtXwKBgHkF\nT4b7bap65y0dnpuBLuPiBbqrYaZTsKOD7ZID63ZbCBZ9Na5RDrM50KI+TBEayNVF\n62j4laV0RJSnbZm+rG1zLKBQqaITdY1wr/ZO90VINZOkKg81FBhI1Mh5yKtHtMV1\nwi9uDB8f986I4Zep2xKiXo5uTLaaHHJyg5A9YujVAoGAI2jKkMRUVnG9InKb0UJA\nZbEy3Zc+6kj+3Lilj7LHSG0zLGlwU96+v6B/DLMfZioAMDtyfGwCLfG/fK/V8TWf\niOv0wgE2KQEVfwKsET/zhQx1e/3nFsY01F2AWGQVNL2Or5WQBST+/TI85/GSGT8x\nzzzzzzzzzzzzzzzzzzzzzzz=\n-----END PRIVATE KEY-----\n",
+  "client_email": "example@example.iam.gserviceaccount.com",
+  "client_id": "000000000000000000000",
+  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+  "token_uri": "https://oauth2.googleapis.com/token",
+  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/example%40example.iam.gserviceaccount.com"
+}
diff --git a/tests/service/SheetsServiceTest.php b/tests/service/SheetsServiceTest.php
new file mode 100644
index 0000000..847d3e9
--- /dev/null
+++ b/tests/service/SheetsServiceTest.php
@@ -0,0 +1,14 @@
+<?php
+declare(strict_types=1);
+
+namespace addianto\LionGame\Backend\Service\Test;
+
+use PHPUnit\Framework\TestCase;
+
+class SheetsServiceTest extends TestCase
+{
+    /*
+    TODO: Use mock to mock Google Sheets API instance that passed down
+    into the service class constructor.
+    */
+}
-- 
GitLab


From 6dad2e51f63bd0f3230389d55532de5f9368f082 Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Wed, 28 Oct 2020 15:37:22 +0700
Subject: [PATCH 5/8] Add script to run unit tests (#1)

---
 composer.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/composer.json b/composer.json
index 43cfeb6..3a27d4d 100644
--- a/composer.json
+++ b/composer.json
@@ -30,7 +30,8 @@
         "sort-packages": true
     },
     "scripts": {
-        "post-update-cmd": "Google\\Task\\Composer::cleanup"
+        "post-update-cmd": "Google\\Task\\Composer::cleanup",
+        "test": "phpunit tests/"
     },
     "extra": {
         "google/apiclient-services": [
-- 
GitLab


From c671cee791a2783e4bc25738681ee4ecc94cc3b5 Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Wed, 28 Oct 2020 09:14:21 +0000
Subject: [PATCH 6/8] Create basic tests for SheetsService

---
 src/service/SheetsService.php       |  2 ++
 tests/service/SheetsServiceTest.php | 28 ++++++++++++++++++++++++----
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/service/SheetsService.php b/src/service/SheetsService.php
index 1cd9019..b680f83 100644
--- a/src/service/SheetsService.php
+++ b/src/service/SheetsService.php
@@ -35,9 +35,11 @@ class SheetsService
             "majorDimension" => "ROWS",
             "values" => array($values),
         ]);
+
         $optionalParameters = array(
             "valueInputOption" => "RAW",
         );
+
         $response = $this->api
             ->spreadsheets_values
             ->append($this->spreadsheetId, $range, $body, $optionalParameters);
diff --git a/tests/service/SheetsServiceTest.php b/tests/service/SheetsServiceTest.php
index 847d3e9..62f85a8 100644
--- a/tests/service/SheetsServiceTest.php
+++ b/tests/service/SheetsServiceTest.php
@@ -4,11 +4,31 @@ declare(strict_types=1);
 namespace addianto\LionGame\Backend\Service\Test;
 
 use PHPUnit\Framework\TestCase;
+use Google_Service_Sheets as GoogleSheetsAPI;
+use addianto\LionGame\Backend\Service\SheetsService;
 
 class SheetsServiceTest extends TestCase
 {
-    /*
-    TODO: Use mock to mock Google Sheets API instance that passed down
-    into the service class constructor.
-    */
+    private GoogleSheetsAPI $mockAPI;
+
+    protected function setUp(): void
+    {
+        $this->mockAPI = $this->createMock(GoogleSheetsAPI::class);
+    }
+
+    public function testGetInstance(): void
+    {
+        $this->assertInstanceOf(
+            SheetsService::class,
+            SheetsService::getInstance($this->mockAPI, "12345")
+        );
+    }
+
+    public function testSingletonProperty(): void
+    {
+        $this->assertEquals(
+            SheetsService::getInstance($this->mockAPI, "12345"),
+            SheetsService::getInstance($this->mockAPI, "12345")
+        );
+    }
 }
-- 
GitLab


From 3db9c04f97d3a125fa61a46c4faa82ef8aac4f91 Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Wed, 28 Oct 2020 09:31:43 +0000
Subject: [PATCH 7/8] Wrap get & append login inside a try-catch block (#1)

---
 src/service/SheetsService.php | 55 ++++++++++++++++++++++++-----------
 1 file changed, 38 insertions(+), 17 deletions(-)

diff --git a/src/service/SheetsService.php b/src/service/SheetsService.php
index b680f83..9c6a0c3 100644
--- a/src/service/SheetsService.php
+++ b/src/service/SheetsService.php
@@ -22,27 +22,48 @@ class SheetsService
 
     public function getValues(string $range): array
     {
-        $response = $this->api
-            ->spreadsheets_values
-            ->get($this->spreadsheetId, $range);
+        $values = array();
 
-        return $response->getValues();
+        try {
+            $response = $this->api
+                ->spreadsheets_values
+                ->get($this->spreadsheetId, $range);
+
+            $values = $response->getValues();
+        } catch (Exception $e) {
+            error_log($e->getMessage());
+            error_log($e->getTraceAsString());
+        }
+
+        return $values;
     }
 
-    public function appendValues(string $range, array $values): void
+    public function appendValues(string $range, array $values): bool
     {
-        $body = new ValueRange([
-            "majorDimension" => "ROWS",
-            "values" => array($values),
-        ]);
-
-        $optionalParameters = array(
-            "valueInputOption" => "RAW",
-        );
-
-        $response = $this->api
-            ->spreadsheets_values
-            ->append($this->spreadsheetId, $range, $body, $optionalParameters);
+        $isAppended = false;
+
+        try {
+            $body = new ValueRange([
+                "majorDimension" => "ROWS",
+                "values" => array($values),
+            ]);
+
+            $optionalParameters = array(
+                "insertDataOption" => "INSERT_ROWS",
+                "valueInputOption" => "RAW",
+            );
+
+            $response = $this->api
+                ->spreadsheets_values
+                ->append($this->spreadsheetId, $range, $body, $optionalParameters);
+
+            $isAppended = true;
+        } catch (Exception $e) {
+            error_log($e->getMessage());
+            error_log($e->getTraceAsString());
+        }
+
+        return $isAppended;
     }
 
     public static function getInstance(GoogleSheetsAPI $api, string $spreadsheetId): SheetsService
-- 
GitLab


From a3b4b5e685d5a105e519852cc97ba12ff8382c33 Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Wed, 28 Oct 2020 20:45:59 +0700
Subject: [PATCH 8/8] Setup base code without actual functionality (#1)

---
 README.md         |  2 +-
 src/.env.example  |  2 ++
 src/App.php       | 35 +++++++++++++++++++++--------------
 src/index.php     | 19 ++++++++++++++++++-
 tests/AppTest.php | 47 +++++++++++++++++++++++++++++++++++++++++------
 5 files changed, 83 insertions(+), 22 deletions(-)

diff --git a/README.md b/README.md
index 58a699f..9759cb1 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
-# Lion Game Backend _(liongame-backend)_
+# Lion Game - Backend _(liongame-backend)_
 
 TBD.
diff --git a/src/.env.example b/src/.env.example
index 027c888..79d0e6f 100644
--- a/src/.env.example
+++ b/src/.env.example
@@ -1,2 +1,4 @@
+API_KEY=sha512(bangtoyib-cepatpulang)
+DEBUG=true
 GOOGLE_APPLICATION_CREDENTIALS=/opt/liongame/service-account.json
 SPREADSHEET_ID=1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms
diff --git a/src/App.php b/src/App.php
index 01bf1a1..7f698ce 100644
--- a/src/App.php
+++ b/src/App.php
@@ -7,20 +7,28 @@ use Psr\Http\Message\ServerRequestInterface as Request;
 use Psr\Http\Message\ResponseInterface as Response;
 use Slim\Factory\AppFactory;
 use Slim\App as SlimApp;
+use addianto\LionGame\Backend\Config\Config;
 use addianto\LionGame\Backend\Service\SheetsService;
 
 class App
 {
+    private string $apiKey;
     private SlimApp $app;
     private SheetsService $sheets;
-
-    public function __construct(bool $debug = false)
-    {
+    private bool $debug;
+
+    public function __construct(
+        string $apiKey,
+        SheetsService $sheets,
+        bool $debug = false
+    ) {
+        $this->apiKey = $apiKey;
         $this->app = AppFactory::create();
-        $this->sheets = SheetsService::getInstance();
+        $this->sheets = $sheets;
+        $this->debug = $debug;
 
-        $this->addErrorMiddleware($debug);
-        $this->handleBase();
+        $this->setupMiddleware();
+        $this->setupController();
     }
 
     public function get(): SlimApp
@@ -28,18 +36,17 @@ class App
         return $this->app;
     }
 
-    private function addErrorMiddleware(bool $debug = false): void
+    private function setupMiddleware(): void
     {
-        // Add error middleware
-        // Note: First arg should be set to false in production
-        $this->app->addErrorMiddleware($debug, true, true);
+        $this->app->addErrorMiddleware($this->debug, true, true);
     }
 
-    private function handleBase(): void
+    private function setupController(): void
     {
-        $this->app->get('/', function (Request $request, Response $response, $args) {
-            $range = "'Play Session Analytics (Example)'!A:AC";
-            $response->getBody()->write("Hello, World!");
+        $this->app->post("/logs", function (Request $request, Response $response, $args) {
+            $response->getBody()->write(json_encode(array(
+                "message" => "TODO: Implement me!"
+            )));
             return $response;
         });
     }
diff --git a/src/index.php b/src/index.php
index 5867147..6f99f83 100644
--- a/src/index.php
+++ b/src/index.php
@@ -10,9 +10,26 @@ require __DIR__ . '/../vendor/autoload.php';
 
 $dotenv = Dotenv::createImmutable(__DIR__);
 $dotenv->load();
+$dotenv->required("API_KEY");
+$dotenv->required("DEBUG");
 $dotenv->required("GOOGLE_APPLICATION_CREDENTIALS");
 $dotenv->required("SPREADSHEET_ID");
 
+// Wiring up the dependencies
+$sheetsService = SheetsService::getInstance(
+    Config::createGoogleSheetsAPI(
+        Config::createGoogleAPIClient(
+            "Lion Game - Backend",
+            $_ENV["GOOGLE_APPLICATION_CREDENTIALS"]
+        )
+    ),
+    $_ENV["SPREADSHEET_ID"]
+);
+
 // Run the app
-$app = (new App(true))->get();
+$app = (new App(
+    $_ENV["API_KEY"],
+    $sheetsService,
+    $_ENV["DEBUG"] === 'true'
+))->get();
 $app->run();
diff --git a/tests/AppTest.php b/tests/AppTest.php
index 0cc708b..3fb849c 100644
--- a/tests/AppTest.php
+++ b/tests/AppTest.php
@@ -6,27 +6,62 @@ namespace addianto\LionGame\Backend\Test;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\ServerRequestInterface as Request;
 use Psr\Http\Message\ResponseInterface as Response;
+use Slim\Psr7\Factory\UriFactory;
 use Slim\Factory\ServerRequestCreatorFactory as RequestFactory;
 use Slim\App as SlimApp;
+use addianto\LionGame\Backend\Service\SheetsService;
 use addianto\LionGame\Backend\App;
 
+use json_decode;
+use json_last_error;
+use strtoupper;
+
 class AppTest extends TestCase
 {
-    protected SlimApp $app;
+    const API_KEY = "12345";
+    const DEBUG = false;
+    const SUCCESS_JSON_DECODE = 0;
+
+    private SlimApp $app;
 
     protected function setUp(): void
     {
-        $this->app = (new App(true))->get();
+        $this->app = (new App(
+            self::API_KEY,
+            $this->createMock(SheetsService::class),
+            self::DEBUG
+        ))->get();
     }
 
-    public function testHandleBase(): void
+    public function testAppIsASlimFrameworkApp(): void
     {
-        $request = RequestFactory::create()->createServerRequestFromGlobals();
-        $request->withMethod("GET");
-        $request->withRequestTarget("/");
+        $this->assertInstanceOf(SlimApp::class, $this->app);
+    }
 
+    public function testPOSTLogsShouldResolve(): void
+    {
+        $request = $this->buildRequest("POST", "/logs");
         $response = $this->app->handle($request);
 
         $this->assertEquals(200, $response->getStatusCode());
     }
+
+    public function testPOSTLogsShouldReturnJSON(): void
+    {
+        $request = $this->buildRequest("POST", "/logs");
+
+        $response = $this->app->handle($request);
+        $jsonString = $response->getBody()->__toString();
+        $json = json_decode($jsonString);
+
+        $this->assertEquals(self::SUCCESS_JSON_DECODE, json_last_error());
+    }
+
+    private function buildRequest(string $method, string $path)
+    {
+        return RequestFactory::create()
+            ->createServerRequestFromGlobals()
+            ->withMethod(strtoupper($method))
+            ->withUri(UriFactory::createUri($path));
+    }
 }
-- 
GitLab