publish release *after* uploading the asset
[pharext/pharext.org] / app / Github / API.php
1 <?php
2
3 namespace app\Github;
4
5 use app\Github\API;
6 use app\Github\Storage;
7 use app\Github\Exception;
8
9 use merry\Config;
10
11 use http\Client;
12 use http\QueryString;
13 use http\Url;
14
15 use Psr\Log\LoggerInterface;
16
17 class API
18 {
19 /**
20 * @var Client
21 */
22 private $client;
23
24 /**
25 * @var Storage
26 */
27 private $tokens;
28
29 /**
30 * @var Storage
31 */
32 private $cache;
33
34 /**
35 * @var merry\Config
36 */
37 private $config;
38
39 /**
40 * @var int
41 */
42 private $maxAge;
43
44 /**
45 * @var \Psr\Log\LoggerInterface;
46 */
47 private $logger;
48
49 function __construct(Config $config, LoggerInterface $logger, Storage $tokens = null, Storage $cache = null) {
50 $this->logger = $logger;
51 $this->config = $config;
52 $this->client = new Client("curl", "github");
53 $this->client->configure($config->http->configure->toArray());
54 $this->client->attach(new ClientObserver($logger));
55 $this->tokens = $tokens ?: new Storage\Session;
56 $this->cache = $cache;
57 }
58
59 /**
60 * Set maximum acceptable age of cache items
61 * @param int $seconds
62 */
63 function setMaxAge($seconds) {
64 $this->maxAge = $seconds;
65 return $this;
66 }
67
68 function getMaxAge() {
69 return $this->maxAge;
70 }
71
72 function getLogger() {
73 return $this->logger;
74 }
75
76 function getConfig() {
77 return $this->config;
78 }
79
80 function getClient() {
81 return $this->client;
82 }
83
84 function getTokenStorage() {
85 return $this->tokens;
86 }
87
88 function getCacheStorage() {
89 return $this->cache;
90 }
91
92 function getCacheKey($ident, $page = null) {
93 return sprintf("%s:%s:%s", $this->getToken(), $ident, $page ?: 1);
94 }
95
96 function hasToken() {
97 return $this->tokens->get("access_token");
98 }
99
100 function setToken($token) {
101 $this->tokens->set("access_token", new Storage\Item(
102 $token,
103 $this->config->storage->token->ttl
104 ));
105 }
106
107 function getToken() {
108 if ($this->tokens->get("access_token", $token, true)) {
109 return $token->getValue();
110 }
111 if (isset($token)) {
112 $this->logger->notice("Token expired", $token);
113 throw new Exception\TokenExpired($token->getLTL());
114 }
115 throw new Exception\TokenNotSet;
116 }
117
118 function dropToken() {
119 $this->tokens->del("access_token");
120 }
121
122 function getAuthUrl($callback_url) {
123 $state = base64_encode(openssl_random_pseudo_bytes(24));
124 $this->tokens->set("state", new Storage\Item($state, 5*60));
125 $param = [
126 "state" => $state,
127 "client_id" => $this->config->client->id,
128 "scope" => $this->config->client->scope,
129 "redirect_uri" => $callback_url,
130 ];
131 return new Url("https://github.com/login/oauth/authorize", [
132 "query" => new QueryString($param)
133 ], 0);
134 }
135
136 function fetchToken($code, $state, callable $callback) {
137 if (!$this->tokens->get("state", $orig_state, true)) {
138 if (isset($orig_state)) {
139 $this->logger->notice("State expired", $orig_state);
140 throw new Exception\StateExpired($orig_state->getLTL());
141 }
142 throw new Exception\StateNotSet;
143 }
144 if ($state !== $orig_state->getValue()) {
145 $this->logger->warning("State mismatch", compact("state", "orig_state"));
146 throw new Exception\StateMismatch($orig_state->getValue(), $state);
147 }
148
149 $call = new API\Users\ReadAuthToken($this, [
150 "code" => $code,
151 "client_id" => $this->config->client->id,
152 "client_secret" => $this->config->client->secret,
153 ]);
154 return $call($callback);
155 }
156
157 function readAuthUser(callable $callback) {
158 $call = new API\Users\ReadAuthUser($this);
159 return $call($callback);
160 }
161
162 function listRepos($page, callable $callback) {
163 $call = new API\Repos\ListRepos($this, compact("page"));
164 return $call($callback);
165 }
166
167 function readRepo($repo, callable $callback) {
168 $call = new API\Repos\ReadRepo($this, compact("repo"));
169 return $call($callback);
170 }
171
172 /**
173 * Check if the pharext webhook is set for the repo and return it
174 * @param object $repo
175 * @return stdClass hook
176 */
177 function checkRepoHook($repo) {
178 if ($repo->hooks) {
179 foreach ($repo->hooks as $hook) {
180 if ($hook->name === "web" && $hook->config->url === $this->config->hook->url) {
181 return $hook;
182 }
183 }
184 }
185 return null;
186 }
187
188 function listHooks($repo, callable $callback) {
189 $call = new API\Hooks\ListHooks($this, compact("repo"));
190 return $call($callback);
191 }
192
193 function listReleases($repo, $page, callable $callback) {
194 $call = new API\Releases\ListReleases($this, compact("repo", "page"));
195 return $call($callback);
196 }
197
198 function listTags($repo, $page, callable $callback) {
199 $call = new API\Tags\ListTags($this, compact("repo", "page"));
200 return $call($callback);
201 }
202
203 function readContents($repo, $path, callable $callback) {
204 $call = new API\Repos\ReadContents($this, compact("repo", "path"));
205 return $call($callback);
206 }
207
208 function createRepoHook($repo, $conf, callable $callback) {
209 $call = new API\Hooks\CreateHook($this, compact("repo", "conf"));
210 return $call($callback);
211 }
212
213 function updateRepoHook($repo, $id, $conf, callable $callback) {
214 $call = new API\Hooks\UpdateHook($this, compact("repo", "id", "conf"));
215 return $call($callback);
216 }
217
218 function deleteRepoHook($repo, $id, callable $callback) {
219 $call = new API\Hooks\DeleteHook($this, compact("repo", "id"));
220 return $call($callback);
221 }
222
223 function createRelease($repo, $tag, callable $callback) {
224 $call = new API\Releases\CreateRelease($this, compact("repo", "tag"));
225 return $call($callback);
226 }
227
228 function publishRelease($repo, $id, $tag, callable $callback) {
229 $call = new API\Releases\PublishRelease($this, compact("repo", "id", "tag"));
230 return $call($callback);
231 }
232
233 function createReleaseAsset($url, $asset, $type, callable $callback) {
234 $call = new API\Releases\CreateReleaseAsset($this, compact("url", "asset", "type"));
235 return $call($callback);
236 }
237
238 function listReleaseAssets($repo, $id, callable $callback) {
239 $call = new API\Releases\ListReleaseAssets($this, compact("repo", "id"));
240 return $call($callback);
241 }
242 }