From 26494fb5cdfb9cf103904d10b6bda564bcf2d0bd Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 8 May 2015 12:12:09 +0200 Subject: [PATCH] flush --- .gitignore | 1 + app/Cli.php | 26 ++-- app/Cli/GenModels.php | 130 ++++++++++++++++++ app/Cli/Initdb.php | 23 ++++ app/Cli/Ngrok.php | 28 ++++ app/Config.php | 21 +++ app/Controller/Github.php | 2 +- app/Controller/Github/Callback.php | 47 ++++++- app/Controller/Github/Hook.php | 128 +++++++++++++++-- app/Controller/Github/Repo/Hook.php | 7 +- app/Controller/Github/Signin.php | 2 +- app/Github/API.php | 19 ++- app/Github/Create/Release.php | 27 ++++ app/Github/Create/ReleaseAsset.php | 26 ++++ app/Github/Create/Webhook.php | 8 ++ .../Exception/ReleaseAssetCreateFailed.php | 13 ++ app/Github/Exception/ReleaseCreateFailed.php | 13 ++ app/Github/Fetch.php | 1 - app/Model/Account.php | 55 ++++++++ app/Model/AccountCollection.php | 10 ++ app/Model/Accounts.php | 90 ++++++++++++ app/Model/Authorities.php | 11 ++ app/Model/Authority.php | 9 ++ app/Model/AuthorityCollection.php | 10 ++ app/Model/Owner.php | 9 ++ app/Model/OwnerCollection.php | 10 ++ app/Model/Owners.php | 11 ++ app/Model/Token.php | 9 ++ app/Model/TokenCollection.php | 10 ++ app/Model/Tokens.php | 11 ++ app/Session.php | 15 +- app/bootstrap/cli.php | 2 + app/bootstrap/config.php | 21 +-- app/bootstrap/github.php | 1 - app/bootstrap/http.php | 9 ++ app/bootstrap/model.php | 33 +++++ app/bootstrap/plates.php | 2 - app/bootstrap/pq.php | 19 +++ app/bootstrap/router.php | 53 +++++++ app/bootstrap/session.php | 17 +++ app/bootstrap/web.php | 66 +-------- app/views/github/repo.phtml | 48 +++++-- app/views/navbar.phtml | 6 +- bin/pharext.org | 6 +- composer.json | 5 +- composer.lock | 66 +++++++-- app/config.ini => config/app.ini | 6 +- {app => config}/routes.ini | 0 config/sql/001.sql | 30 ++++ public/index.php | 2 +- 50 files changed, 1031 insertions(+), 143 deletions(-) create mode 100644 app/Cli/GenModels.php create mode 100644 app/Cli/Initdb.php create mode 100644 app/Cli/Ngrok.php create mode 100644 app/Config.php create mode 100644 app/Github/Create/Release.php create mode 100644 app/Github/Create/ReleaseAsset.php create mode 100644 app/Github/Exception/ReleaseAssetCreateFailed.php create mode 100644 app/Github/Exception/ReleaseCreateFailed.php create mode 100644 app/Model/Account.php create mode 100644 app/Model/AccountCollection.php create mode 100644 app/Model/Accounts.php create mode 100644 app/Model/Authorities.php create mode 100644 app/Model/Authority.php create mode 100644 app/Model/AuthorityCollection.php create mode 100644 app/Model/Owner.php create mode 100644 app/Model/OwnerCollection.php create mode 100644 app/Model/Owners.php create mode 100644 app/Model/Token.php create mode 100644 app/Model/TokenCollection.php create mode 100644 app/Model/Tokens.php create mode 100644 app/bootstrap/http.php create mode 100644 app/bootstrap/model.php create mode 100644 app/bootstrap/pq.php create mode 100644 app/bootstrap/router.php create mode 100644 app/bootstrap/session.php rename app/config.ini => config/app.ini (86%) rename {app => config}/routes.ini (100%) create mode 100644 config/sql/001.sql diff --git a/.gitignore b/.gitignore index b551a21..cfc2631 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ vendor nbproject app/credentials.ini +config/credentials.ini diff --git a/app/Cli.php b/app/Cli.php index 114bfed..56dbc5c 100644 --- a/app/Cli.php +++ b/app/Cli.php @@ -2,22 +2,26 @@ namespace app; -use merry\Config; use pharext\Cli\Args; class Cli { /** - * @var \merry\Config + * @var \app\Config */ private $config; + /** + * @var \pharext\Cli\Args + */ + private $args; + function __construct(Config $config, Args $args) { $this->config = $config; $this->args = $args; } - function __invoke($argc, array $argv) { + function __invoke($argc, array $argv, callable $exec) { $prog = array_shift($argv); foreach ($this->args->parse(--$argc, $argv) as $error) { $errs[] = $error; @@ -35,15 +39,13 @@ class Cli } if ($this->args["ngrok"]) { - system($this->config->ngrok->command . " ". implode(" ", array_map("escapeshellarg", [ - "http", - "--subdomain=pharext", - "--authtoken", - $this->config->ngrok->auth->token, - "--auth", - $this->config->ngrok->auth->user .":". $this->config->ngrok->auth->pass, - "80" - ]))); + $exec(Cli\Ngrok::class); + } + if ($this->args["initdb"]) { + $exec(Cli\Initdb::class); + } + if ($this->args["gen-models"]) { + $exec(Cli\GenModels::class); } } diff --git a/app/Cli/GenModels.php b/app/Cli/GenModels.php new file mode 100644 index 0000000..9f1b824 --- /dev/null +++ b/app/Cli/GenModels.php @@ -0,0 +1,130 @@ +pq = $pq; + } + + function __invoke(array $args = null) { + $tables = $this->pq->exec("SELECT tablename FROM pg_tables WHERE schemaname='public'"); + /* @var $tables \pq\Result */ + foreach ($tables->fetchAllCols("tablename") as $table) { + $this->genModel($table); + } + } + + function genModel($entity) { + $title = ucwords($entity); + $single = substr($title, -3) == "ies" + ? substr($title, 0, -3)."y" + : rtrim($title, "s"); + $this->genTable($entity, $title, $single."Collection"); + $this->genRowset($single."Collection", $single); + $this->genRow($single); + } + + function genTable($name, $class, $collection) { + $ns = explode("\\", $class); + + if (count($ns) > 1) { + $class = array_pop($ns); + $dir = implode("/", $ns); + $ns = "\\".implode("\\", $ns); + } else { + $ns = ""; + $dir = ""; + } + + $file = __DIR__."/../Model/$dir/$class.php"; + + if (!file_exists($file)) { + file_put_contents($file, << 1) { + $class = array_pop($ns); + $dir = implode("/", $ns); + $ns = "\\".implode("\\", $ns); + } else { + $ns = ""; + $dir = ""; + } + + $file = __DIR__."/../Model/$dir/$class.php"; + + if (!file_exists($file)) { + file_put_contents($file, << 1) { + $class = array_pop($ns); + $dir = implode("/", $ns); + $ns = "\\".implode("\\", $ns); + } else { + $ns = ""; + $dir = ""; + } + + $file = __DIR__."/../Model/$dir/$class.php"; + + if (!file_exists($file)) { + file_put_contents($file, <<pq = $pq; + } + + function __invoke(array $args = null) { + foreach (glob(__DIR__."/../../config/sql/*.sql") as $sql) { + $xa = $this->pq->startTransaction(); + $this->pq->exec(file_get_contents($sql)); + $xa->commit(); + } + } +} diff --git a/app/Cli/Ngrok.php b/app/Cli/Ngrok.php new file mode 100644 index 0000000..82236c2 --- /dev/null +++ b/app/Cli/Ngrok.php @@ -0,0 +1,28 @@ +config = $config; + } + + function __invoke(array $args = null) { + system($this->config->ngrok->command . " ". implode(" ", array_map("escapeshellarg", [ + "http", + "--subdomain=pharext", + "--log=stderr", + "--authtoken", + $this->config->ngrok->auth->token, + "--auth", + $this->config->ngrok->auth->user .":". $this->config->ngrok->auth->pass, + "80" + ]))); + } +} \ No newline at end of file diff --git a/app/Config.php b/app/Config.php new file mode 100644 index 0000000..2d97da2 --- /dev/null +++ b/app/Config.php @@ -0,0 +1,21 @@ + $conf) { + /* one level down should suffice, i.e. $config->github->client = {id,secret,scope} */ + if ($conf instanceof Config) { + foreach ($conf as $key => $val) { + $this->$sub->$key = $val; + } + } else { + $this->$sub = $conf; + } + } + } +} diff --git a/app/Controller/Github.php b/app/Controller/Github.php index 6432c86..5933fcd 100644 --- a/app/Controller/Github.php +++ b/app/Controller/Github.php @@ -26,7 +26,7 @@ abstract class Github implements Controller * @var \app\Session */ protected $session; - + function __construct(Web $app, API $github, Session $session) { $this->app = $app; $this->github = $github; diff --git a/app/Controller/Github/Callback.php b/app/Controller/Github/Callback.php index 5b62faa..d6d1192 100644 --- a/app/Controller/Github/Callback.php +++ b/app/Controller/Github/Callback.php @@ -3,9 +3,25 @@ namespace app\Controller\Github; use app\Controller\Github; +use app\Github\API; +use app\Github\Exception; +use app\Model\Accounts; +use app\Session; +use app\Web; class Callback extends Github { + + /** + * @var Accounts + */ + private $accounts; + + function __construct(Web $app, API $github, Session $session, Accounts $accounts) { + parent::__construct($app, $github, $session); + $this->accounts = $accounts; + } + function __invoke(array $args = null) { if ($this->app->getRequest()->getQuery("error")) { $this->app->getView()->addData([ @@ -16,22 +32,39 @@ class Callback extends Github $this->github->fetchToken( $this->app->getRequest()->getQuery("code"), $this->app->getRequest()->getQuery("state"), - function($json) { - $this->github->setToken($json->access_token); - $this->github->fetchUser(function($user) { - $this->session->github = $user; - }); + function($token) { + $this->github->setToken($token->access_token); + $this->github->fetchUser($this->createUserCallback($token)); })->send(); if (isset($this->session->returnto)) { - $this->app->redirect($this->session->returnto); + $returnto = $this->session->returnto; + unset($this->session->returnto); + $this->app->redirect($returnto); } else { $this->app->redirect( $this->app->getBaseUrl()->mod("./github")); } - } catch (\app\Github\Exception $exception) { + } catch (Exception $exception) { $this->app->getView()->addData(compact("exception")); } } $this->app->display("github/callback"); } + + function createUserCallback($token) { + return function($user) use($token) { + $tx = $this->accounts->getConnection()->startTransaction(); + + if (!($account = $this->accounts->byOAuth("github", $token->access_token, $user->login))) { + $account = $this->accounts->createOAuthAccount("github", $token->access_token, $user->login); + } + $account->updateToken("github", $token->access_token, $token); + $owner = $account->updateOwner("github", $user->login, $user); + + $tx->commit(); + + $this->session->account = $account->account->get(); + $this->session->github = (object) $owner->export(); + }; + } } diff --git a/app/Controller/Github/Hook.php b/app/Controller/Github/Hook.php index 946bb0c..8161dde 100644 --- a/app/Controller/Github/Hook.php +++ b/app/Controller/Github/Hook.php @@ -1,35 +1,143 @@ app = $app; $this->github = $github; + $this->accounts = $accounts; } function __invoke(array $args = []) { $request = $this->app->getRequest(); $response = $this->app->getResponse(); - if (!($sig = $request->getHeader("X-Github-Signature")) || !($evt = $request->getHeader("X-Github-Event"))) { + if (!($sig = $request->getHeader("X-Hub-Signature")) || !($evt = $request->getHeader("X-Github-Event"))) { $response->setResponseCode(400); - } elseif ($sig !== hash_hmac("sha1", $request->getBody(), $this->app->getConfig()->github->client->secret)) { - $response->setResponseCode(403); - } elseif ($evt === "ping") { - $response->setReponseStatus("PONG"); - } elseif ($evt !== "push") { - $this->app->getResponse()->setResponseCode(204); + $response->setContentType("message/http"); + $response->getBody()->append($request); } else { - $push = json_decode($request->getBody()); + $key = $this->github->getConfig()->client->secret; + foreach ((new Params($sig))->params as $algo => $mac) { + if ($mac["value"] !== hash_hmac($algo, $request->getBody(), $key)) { + $response->setResponseCode(403); + $response->getBody()->append("Invalid signature"); + return; + } + } + } + + switch ($evt) { + default: + $response->setResponseCode(202); + $response->getBody()->append("Not a configured event"); + break; + case "ping"; + $response->setResponseCode(204); + $response->setResponseStatus("PONG"); + break; + case "create": + case "release": + if (($json = json_decode($request->getBody()))) { + $this->$evt($json); + } else { + $response->setResponseCode(415); + $response->setContentType($request->getHeader("Content-Type")); + $response->getBody()->append($request->getBody()); + } + break; + } + } + + function release($release) { + if ($release->action !== "published") { + $response = $this->app->getResponse(); + + $response->setResponseCode(202); + $response->getBody()->append("Not published"); + return; } + + $this->uploadAssetForRelease($release->release, $release->repository); + } + + private function uploadAssetForRelease($release, $repo) { + $this->setTokenForUser($repo->owner->login); + $asset = $this->createReleaseAsset($release, $repo); + $this->github->createReleaseAsset($release->upload_url, $asset, "application/phar", function($json) { + $response = $this->app->getResponse(); + $response->setResponseCode(201); + $response->setHeader("Location", $json->url); + })->send(); + } + + private function createReleaseAsset($release, $repo) { + define("STDERR", fopen("/var/log/apache2/php_errors.log", "a")); + $source = (new Task\GitClone($repo->clone_url, $release->tag_name))->run(); + $iterator = new Git($source); + $meta = [ + "header" => sprintf("pharext v%s (c) Michael Wallner ", \pharext\VERSION), + "version" => \pharext\VERSION, + "date" => date("Y-m-d"), + "name" => $repo->name, + "release" => $release->tag_name, + "license" => @file_get_contents(current(glob($iterator->getBaseDir()."/LICENSE*"))), + "stub" => "pharext_installer.php", + "type" => false ? "zend_extension" : "extension", + ]; + $file = (new Task\PharBuild($iterator, $meta))->run(); + return $file; + } + + function create($create) { + if ($create->ref_type !== "tag") { + $response = $this->app->getResponse(); + + $response->setResponseCode(202); + $response->getBody()->append("Not a tag"); + return; + } + + $this->createReleaseFromTag($create->ref, $create->repository); + } + + private function setTokenForUser($login) { + $relations = [ + $this->accounts->getTokens()->getRelation("accounts"), + $this->accounts->getOwners()->getRelation("accounts") + ]; + $tokens = $this->accounts->getTokens()->with($relations, [ + "login=" => $login, + "tokens.authority=" => "github", + ]); + + if (count($tokens)) { + $this->github->setToken($tokens->current()->token->get()); + } + } + + private function createReleaseFromTag($tag, $repo) { + $this->setTokenForUser($repo->owner->login); + $this->github->createRelease($repo->full_name, $tag, function($json) { + $response = $this->app->getResponse(); + $response->setResponseCode(201); + $response->setHeader("Location", $json->url); + })->send(); } } diff --git a/app/Controller/Github/Repo/Hook.php b/app/Controller/Github/Repo/Hook.php index 1ef33a3..fac6450 100644 --- a/app/Controller/Github/Repo/Hook.php +++ b/app/Controller/Github/Repo/Hook.php @@ -15,6 +15,10 @@ class Hook extends Github "query" => "modal=hook&hook=" . $args["action"] ])); } else switch ($args["action"]) { + case "upd": + $this->updateHook($args["owner"], $args["name"]); + break; + case "add": $this->addHook($args["owner"], $args["name"]); break; @@ -27,7 +31,8 @@ class Hook extends Github } function addHook($owner, $repo) { - $this->github->createRepoHook("$owner/$repo", function($hook) use($owner, $repo) { + $hook_conf = $this->app->getRequest()->getForm(); + $this->github->createRepoHook("$owner/$repo", $hook_conf, function($hook) use($owner, $repo) { if (($cache = $this->github->getCacheStorage())) { $cache->del($this->github->getCacheKey("hooks:$owner/$repo")); } diff --git a/app/Controller/Github/Signin.php b/app/Controller/Github/Signin.php index 05f3e3c..9fca554 100644 --- a/app/Controller/Github/Signin.php +++ b/app/Controller/Github/Signin.php @@ -10,7 +10,7 @@ class Signin extends Github $callback = $this->app->getBaseUrl()->mod("./github/callback"); $location = $this->github->getAuthUrl($callback); $this->app->redirect($location); - if ($returnto = $this->app->getRequest()->getQuery("returnto")) { + if (($returnto = $this->app->getRequest()->getQuery("returnto"))) { $this->session->returnto = $returnto; } } diff --git a/app/Github/API.php b/app/Github/API.php index f62bf06..8737c16 100644 --- a/app/Github/API.php +++ b/app/Github/API.php @@ -150,13 +150,28 @@ class API return $fetch($callback); } - function createRepoHook($repo, callable $callback) { - $create = new Create\Webhook($this, compact("repo")); + function createRepoHook($repo, $conf, callable $callback) { + $create = new Create\Webhook($this, compact("repo", "conf")); return $create($callback); } + function updateRepoHook($repo, $id, $conf, callable $callback) { + $update = new Update\Webhook($this, compact("repo", "id", "conf")); + return $update($callback); + } + function deleteRepoHook($repo, $id, callable $callback) { $delete = new Delete\Webhook($this, compact("repo", "id")); return $delete($callback); } + + function createRelease($repo, $tag, callable $callback) { + $create = new Create\Release($this, compact("repo", "tag")); + return $create($callback); + } + + function createReleaseAsset($url, $asset, $type, callable $callback) { + $create = new Create\ReleaseAsset($this, compact("url", "asset", "type")); + return $create($callback); + } } diff --git a/app/Github/Create/Release.php b/app/Github/Create/Release.php new file mode 100644 index 0000000..3f9f710 --- /dev/null +++ b/app/Github/Create/Release.php @@ -0,0 +1,27 @@ +url->mod("/repos/". $this->args["repo"] ."/releases"); + $request = new Request("POST", $url, [ + "Accept" => "application/vnd.github.v3+json", + "Content-Type" => "application/json", + "Authorization" => "token ". $this->api->getToken() + ]); + $request->getBody()->append(json_encode([ + "tag_name" => $this->args["tag"] + ])); + return $request; + } + + function getException($message, $code, $previous = null) { + return new ReleaseCreateFailed($message, $code, $previous); + } +} diff --git a/app/Github/Create/ReleaseAsset.php b/app/Github/Create/ReleaseAsset.php new file mode 100644 index 0000000..03d0d41 --- /dev/null +++ b/app/Github/Create/ReleaseAsset.php @@ -0,0 +1,26 @@ +args["asset"])), $this->args["url"]); + $body = new \http\Message\Body(fopen($this->args["asset"], "rb")); + $request = new Request("POST", $url, [ + "Accept" => "application/vnd.github.v3+json", + "Content-Type" => $this->args["type"], + "Authorization" => "token ". $this->api->getToken() + ], $body); + return $request; + } + + function getException($message, $code, $previous = null) { + return new ReleaseAssetCreateFailed($message, $code, $previous); + } +} diff --git a/app/Github/Create/Webhook.php b/app/Github/Create/Webhook.php index 6f69d0c..72ff2d7 100644 --- a/app/Github/Create/Webhook.php +++ b/app/Github/Create/Webhook.php @@ -16,8 +16,16 @@ class Webhook extends Create "Authorization" => "token " . $this->api->getToken(), ]); + if (!empty($this->args["conf"]["tag"])) { + $events[] = "create"; + } + if (!empty($this->args["conf"]["release"])) { + $events[] = "release"; + } + $request->getBody()->append(json_encode([ "name" => "web", + "events" => $events, "config" => [ "url" => $this->config->hook->url, "content_type" => $this->config->hook->content_type, diff --git a/app/Github/Exception/ReleaseAssetCreateFailed.php b/app/Github/Exception/ReleaseAssetCreateFailed.php new file mode 100644 index 0000000..16a553d --- /dev/null +++ b/app/Github/Exception/ReleaseAssetCreateFailed.php @@ -0,0 +1,13 @@ +args = $args; $this->url = new Url("https://api.github.com/", null, 0); if (isset($this->config->fetch->{$this}->per_page)) { - header("X-Fetch-{$this}: ".$this->config->fetch->{$this}->per_page, false); $this->url->query = "per_page=" . $this->config->fetch->{$this}->per_page; } } diff --git a/app/Model/Account.php b/app/Model/Account.php new file mode 100644 index 0000000..dec3877 --- /dev/null +++ b/app/Model/Account.php @@ -0,0 +1,55 @@ +table->getTokens(); + + $existing = $tokens->find([ + "authority=" => $authority, + "account=" => $this->account, + ]); + + if (count($existing)) { + $found = $existing->current(); + $found->token = $token; + $found->oauth = $json; + $found->update(); + return $found; + } + + return $tokens->create([ + "authority" => $authority, + "account" => $this->account, + "token" => $token, + "oauth" => $json + ])->current(); + } + + function updateOwner($authority, $user, $json) { + $owners = $this->table->getOwners(); + + $existing = $owners->find([ + "authority=" => $authority, + "account=" => $this->account, + ]); + + if (count($existing)) { + $found = $existing->current(); + $found->login = $user; + $found->owner = $json; + $found->update(); + return $found; + } + + return $owners->create([ + "authority" => $authority, + "login" => $user, + "owner" => $json + ])->current(); + } +} diff --git a/app/Model/AccountCollection.php b/app/Model/AccountCollection.php new file mode 100644 index 0000000..d1354b7 --- /dev/null +++ b/app/Model/AccountCollection.php @@ -0,0 +1,10 @@ +tokens = $tokens; + $this->owners = $owners; + } + + function getTokens() { + return $this->tokens; + } + + function getOwners() { + return $this->owners; + } + + function byOAuth($authority, $token, $user) { + if (!($account = $this->byOAuthToken($authority, $token))) { + $account = $this->byOAuthOwner($authority, $user); + } + return $account; + } + + function byOAuthToken($authority, $access_token, &$token = null) { + $tokens = $this->tokens->find([ + "token=" => $access_token, + "authority=" => $authority, + ]); + + if (count($tokens)) { + $token = $tokens->current(); + $accounts = $this->by($token); + if (count($accounts)) { + return $accounts->current(); + } + } + } + + function byOAuthOwner($authority, $login, &$owner = null) { + $owners = $this->owners->find([ + "authority=" => $authority, + "login=" => $login, + ]); + + if (count($owners)) { + $owner = $owners->current(); + $accounts = $this->by($owner); + if (count($accounts)) { + return $accounts->current(); + } + } + } + + function createOAuthAccount($authority, $token, $user) { + $account = $this->create([ + "account" => new Expr("DEFAULT") + ])->current(); + $this->owners->create([ + "account" => $account->account, + "authority" => $authority, + "login" => $user, + ]); + $this->tokens->create([ + "account" => $account->account, + "authority" => "github", + "token" => $token + ]); + return $account; + } +} diff --git a/app/Model/Authorities.php b/app/Model/Authorities.php new file mode 100644 index 0000000..23cfb67 --- /dev/null +++ b/app/Model/Authorities.php @@ -0,0 +1,11 @@ +session as $key => $val) { ini_set("session.$key", $val); } + if (ini_get("session.use_cookies")) { + $response->addHeader("Vary", "cookie"); + } + $response->addHeader("Cache-Control", + new Params([ + "private" => true, + "must-revalidate" => true, + "max-age" => ini_get("session.cache_expire") * 60 + ]) + ); session_start(); } diff --git a/app/bootstrap/cli.php b/app/bootstrap/cli.php index 4a0239e..8142fb1 100644 --- a/app/bootstrap/cli.php +++ b/app/bootstrap/cli.php @@ -15,6 +15,8 @@ $injector->share(Args::class) ->define(Args::class, [ ":spec" => [ [null, "ngrok", "Run ngrok", Args::SINGLE], + [null, "initdb", "Create database", Args::SINGLE], + [null, "gen-models", "Generate pq\\Gateway models", Args::SINGLE], ["h", "help", "Show this help", Args::HALT], ] ]); diff --git a/app/bootstrap/config.php b/app/bootstrap/config.php index cbf70d2..3bc7f91 100644 --- a/app/bootstrap/config.php +++ b/app/bootstrap/config.php @@ -2,25 +2,16 @@ namespace app; -use merry\Config; - define("APP_ENVIRONMENT", getenv("APP_ENVIRONMENT") ?: "localhost"); $injector->share(Config::class) ->define(Config::class, [ - ":array" => parse_ini_file(__DIR__."/../config.ini", true), + "+array" => function($key, $injector) { + return parse_ini_file(__DIR__."/../../config/app.ini", true); + }, ":section" => APP_ENVIRONMENT ]) - ->prepare(Config::class, function(Config $config) { - $credentials = parse_ini_file(__DIR__."/../credentials.ini", true); - foreach (new Config($credentials, APP_ENVIRONMENT) as $app => $creds) { - /* one level down should suffice, i.e. $config->github->client = {id,secret,scope} */ - if ($creds instanceof Config) { - foreach ($creds as $key => $val) { - $config->$app->$key = $val; - } - } else { - $config->$app = $creds; - } - } + ->prepare(Config::class, function($config, $injector) { + $credentials = parse_ini_file(__DIR__."/../../config/credentials.ini", true); + $config->addConfig(new Config($credentials, APP_ENVIRONMENT)); }); diff --git a/app/bootstrap/github.php b/app/bootstrap/github.php index fe3477f..04396fb 100644 --- a/app/bootstrap/github.php +++ b/app/bootstrap/github.php @@ -4,7 +4,6 @@ namespace app; require_once __DIR__."/config.php"; -use merry\Config; use http\Url; $injector->share(Github\API::class) diff --git a/app/bootstrap/http.php b/app/bootstrap/http.php new file mode 100644 index 0000000..46fc75f --- /dev/null +++ b/app/bootstrap/http.php @@ -0,0 +1,9 @@ +share(Request::class); +$injector->share(Response::class); diff --git a/app/bootstrap/model.php b/app/bootstrap/model.php new file mode 100644 index 0000000..105125e --- /dev/null +++ b/app/bootstrap/model.php @@ -0,0 +1,33 @@ +define(Model\Accounts::class, [ + "conn" => Connection::class, + ]) + ->define(Model\Tokens::class, [ + "conn" => Connection::class, + ]) + ->define(Model\Authorities::class, [ + "conn" => Connection::class, + ]) + ->define(Model\Owners::class, [ + "conn" => Connection::class, + ]); + +//$modelconf = function($key, $injector) { +// return new Table($key, $injector->make(Connection::class)); +//}; +// +//$injector->define(Model\Account::class, [ +// "+accounts" => $modelconf, +// "+owners" => $modelconf, +// "+tokens" => $modelconf +//]); diff --git a/app/bootstrap/plates.php b/app/bootstrap/plates.php index 0b14222..f31d394 100644 --- a/app/bootstrap/plates.php +++ b/app/bootstrap/plates.php @@ -10,8 +10,6 @@ use League\Plates; use http\Env\Request; use http\Env\Response; -use merry\Config; - $injector->share(Plates\Engine::class) ->define(Plates\Engine::class, [ ":directory" => __DIR__."/../views", diff --git a/app/bootstrap/pq.php b/app/bootstrap/pq.php new file mode 100644 index 0000000..0aa3027 --- /dev/null +++ b/app/bootstrap/pq.php @@ -0,0 +1,19 @@ +make(Config::class)->pq->$key; +}; + +$injector->share(Connection::class) + ->define(Connection::class, [ + "+dsn" => $pqconfig, + "+flags" => $pqconfig + ]); diff --git a/app/bootstrap/router.php b/app/bootstrap/router.php new file mode 100644 index 0000000..7377cfd --- /dev/null +++ b/app/bootstrap/router.php @@ -0,0 +1,53 @@ +share(RouteCollector::class) + ->prepare(RouteCollector::class, function($routes) use($injector) { + $routes->addRoute("GET", "/reset", function(array $args = null) use($injector) { + $injector->make(Session::class)->reset()->regenerateId(); + $injector->make(Web::class)->redirect($injector->make(BaseUrl::class)); + }); + $routes->addRoute("GET", "/session", function(array $args = null) use($injector) { + $session = $injector->make(Session::class); + $response = $injector->make(Response::class); + if (!(extension_loaded("xdebug") && ini_get("xdebug.overload_var_dump") && ini_get("html_errors"))) { + $response->setContentType("text/plain"); + } + ob_start($response); + var_dump($_SESSION, $session); + }); + $routes->addRoute("GET", "/info", function(array $args = null) { + phpinfo(); + }); + + foreach (parse_ini_file(__DIR__."/../../config/routes.ini", true) as $controller => $definition) { + $factory = function(array $args = null) use($injector, $controller) { + $handler = $injector->make("app\\Controller\\$controller"); + $handler($args); + }; + foreach ($definition as $method => $locations) { + foreach ($locations as $location) { + $routes->addRoute($method, $location, $factory); + } + } + } + }) + ->alias(RouteParser::class, RouteParser\Std::class) + ->alias(DataGenerator::class, DataGenerator\GroupCountBased::class); + +$injector->share(Dispatcher::class) + ->alias(Dispatcher::class, Dispatcher\GroupCountBased::class) + ->delegate(Dispatcher\GroupCountBased::class, function($class, Injector $injector) { + return new $class($injector->make(RouteCollector::class)->getData()); + }); + diff --git a/app/bootstrap/session.php b/app/bootstrap/session.php new file mode 100644 index 0000000..55e6b2a --- /dev/null +++ b/app/bootstrap/session.php @@ -0,0 +1,17 @@ +share(Session::class) + ->prepare(Session::class, function(Session $session, Injector $injector) { + if (isset($session->current) && (!isset($session->previous) || strcmp($session->current, $session->previous))) { + $session->previous = $session->current; + $session->current = $injector->make(Request::class)->getRequestUrl(); + } + $session->current = $injector->make(Request::class)->getRequestUrl(); + }); diff --git a/app/bootstrap/web.php b/app/bootstrap/web.php index 755bb79..12cefeb 100644 --- a/app/bootstrap/web.php +++ b/app/bootstrap/web.php @@ -3,75 +3,21 @@ namespace app; require_once __DIR__."/config.php"; +require_once __DIR__."/http.php"; require_once __DIR__."/github.php"; +require_once __DIR__."/router.php"; +require_once __DIR__."/session.php"; use Auryn\Injector; -use FastRoute\DataGenerator; -use FastRoute\Dispatcher; -use FastRoute\RouteCollector; -use FastRoute\RouteParser; - -use http\Env\Request; -use http\Env\Response; - -$injector->share(Request::class); -$injector->share(Response::class); - -$injector->share(RouteCollector::class) - ->prepare(RouteCollector::class, function($routes) use($injector) { - $routes->addRoute("GET", "/reset", function(array $args = null) use($injector) { - $injector->make(Session::class)->reset()->regenerateId(); - $injector->make(Web::class)->redirect($injector->make(BaseUrl::class)); - }); - $routes->addRoute("GET", "/session", function(array $args = null) use($injector) { - $session = $injector->make(Session::class); - $response = $injector->make(Response::class); - if (!(extension_loaded("xdebug") && ini_get("xdebug.overload_var_dump") && ini_get("html_errors"))) { - $response->setContentType("text/plain"); - } - ob_start($response); - var_dump($_SESSION, $session); - }); - $routes->addRoute("GET", "/info", function(array $args = null) { - phpinfo(); - }); - - foreach (parse_ini_file(__DIR__."/../routes.ini", true) as $controller => $definition) { - $factory = function(array $args = null) use($injector, $controller) { - $handler = $injector->make("app\\Controller\\$controller"); - $handler($args); - }; - foreach ($definition as $method => $locations) { - foreach ($locations as $location) { - $routes->addRoute($method, $location, $factory); - } - } - } - }) - ->alias(RouteParser::class, RouteParser\Std::class) - ->alias(DataGenerator::class, DataGenerator\GroupCountBased::class); - -$injector->share(Dispatcher::class) - ->alias(Dispatcher::class, Dispatcher\GroupCountBased::class) - ->delegate(Dispatcher\GroupCountBased::class, function($class, Injector $injector) { - return new $class($injector->make(RouteCollector::class)->getData()); - }); - $injector->prepare(Controller::class, function(Controller $controller, Injector $injector) { if (method_exists($controller, "setSession")) { $controller->setSession($injector->make(Session::class)); } + if (method_exists($controller, "setDatabase")) { + $controller->setDatabase($injector->make(Connection::class)); + } }); -$injector->share(Session::class) - ->prepare(Session::class, function(Session $session, Injector $injector) { - if (isset($session->current) && (!isset($session->previous) || strcmp($session->current, $session->previous))) { - $session->previous = $session->current; - $session->current = $injector->make(Request::class)->getRequestUrl(); - } - $session->current = $injector->make(Request::class)->getRequestUrl(); - }); - $injector->share(BaseUrl::class); $injector->share(Web::class); diff --git a/app/views/github/repo.phtml b/app/views/github/repo.phtml index 372de5d..36849c0 100644 --- a/app/views/github/repo.phtml +++ b/app/views/github/repo.phtml @@ -119,20 +119,50 @@
- -
-
-
full_name ."/hook/add") ?>"> - -
-
+
+
full_name ."/hook/" . ($this->check($repo) ? "upd" : "add")) ?>"> +
+
+ +
+
+ +
+
+ check($repo)) : ?> +
+ +
+ +
+ +
+ +
+ + check($repo)) : ?>
full_name ."/hook/del") ?>"> - +
+
-
diff --git a/app/views/navbar.phtml b/app/views/navbar.phtml index 1d14a0b..c7fbfb5 100644 --- a/app/views/navbar.phtml +++ b/app/views/navbar.phtml @@ -47,13 +47,13 @@