diff options
-rw-r--r-- | ickweb/app.py | 120 | ||||
-rw-r--r-- | views/builds.tpl | 19 | ||||
-rw-r--r-- | views/index.tpl | 10 | ||||
-rw-r--r-- | views/log.tpl | 13 | ||||
-rw-r--r-- | views/login.tpl | 6 | ||||
-rw-r--r-- | views/project.tpl | 13 | ||||
-rw-r--r-- | views/projects.tpl | 19 |
7 files changed, 192 insertions, 8 deletions
diff --git a/ickweb/app.py b/ickweb/app.py index f420098..42504e3 100644 --- a/ickweb/app.py +++ b/ickweb/app.py @@ -1,22 +1,140 @@ +import json + import bottle +import requests +import yaml + +API_URL = 'https://ci-prod-controller.vm.liw.fi' COOKIE = 'ickweb1' +TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJpc3MiOiJodHRwczovL2NpLXByb2QtY29udHJvbGxlci52bS5saXcuZmkiLCJhdWQiOiJhZG1pbiIsInN1YiI6IiIsInNjb3BlIjoidWFwaV92ZXJzaW9uX2dldCB1YXBpX3N0YXR1c19nZXQgdWFwaV9wcm9qZWN0c19pZF9zdGF0dXNfZ2V0IHVhcGlfcHJvamVjdHNfaWRfc3RhdHVzX3B1dCB1YXBpX2Jsb2JzX2lkX2dldCB1YXBpX25vdGlmeV9wb3N0IHVhcGlfcHJvamVjdHNfZ2V0IHVhcGlfcHJvamVjdHNfcG9zdCB1YXBpX3Byb2plY3RzX2lkX2dldCB1YXBpX3Byb2plY3RzX2lkX3B1dCB1YXBpX3Byb2plY3RzX2lkX2RlbGV0ZSB1YXBpX3BpcGVsaW5lc19nZXQgdWFwaV9waXBlbGluZXNfcG9zdCB1YXBpX3BpcGVsaW5lc19pZF9nZXQgdWFwaV9waXBlbGluZXNfaWRfcHV0IHVhcGlfcGlwZWxpbmVzX2lkX2RlbGV0ZSB1YXBpX3dvcmtlcnNfZ2V0IHVhcGlfd29ya2Vyc19pZF9nZXQgdWFwaV9idWlsZHNfZ2V0IHVhcGlfYnVpbGRzX2lkX2dldCB1YXBpX2xvZ3NfZ2V0IHVhcGlfbG9nc19pZF9nZXQiLCJleHAiOjE1MzMyOTkzMTIuNTgxNDMxfQ.MNd3eP6zmet7vLLGE_XXnfDZ1_flRb7qRw87qdKtZdx496NK3j-Aco0DuA5lKAeSFcK1yx01pnIH9maUO1uU5CTkOaVk2jlq1rr9LyRBaqyF1VI1qrTiWQ5QfLLCUXsH4zl4PC2g33BhcgLY74ua22P7QA3Rwnkp1xLP32VA6zN_Y4nrJDJhTFpRJXQk1Lo59hyOeiXnc2s26wXDASWMmqqNFJHf9i6uTvJQDrxjhiLjI7w3s_DxtBINJ6eWaZqbVvkYvQYVGBjqbDd3N1VOg4thoi_XXsF12Jrwo9LORT8pNygxlR40Lb-n5gDN9olTj0fVWZ9UMP-G1DQVrxZPf3rlMhRiPSmEvfLJJn7IF9fqwSnsseZYwvzjh6DafdFctuL9cNrCQt_UrlH7l0KPHC65GR1P4ejCVM5E5FC0Lx3KWhh6eagcnd47LNtQCxCMvl5Ffig58VBlRer4J3vTtpECkEryIC6rVurwUETlOGqai1LTJO_KOM3h9eP_RbAy0fogj8sE_UjIiEbp9IuodEaRwp3hGlX_qBkLZwKDMMhlhtZGX3dOyb4CiEoDxKnYQm7sE3Hu0KAE88QrpS8Lwt36q1SeD9srI5yfo31YXW__vBQ2AYlXF9efSpm0XuYIWHEaGX-7DF1ANAV0vMmyDxYsf32K4MQUEsF5nQ_fvao' + def create_app(): app = bottle.Bottle() + api = API(API_URL) + api.set_token(TOKEN) + + @app.route('/favicon.ico') + def favicon(): + raise bottle.HTTPError(status=404) @app.route('/') def root(): - if bottle.request.get_cookie(COOKIE) == 'yes': + if is_logged_in(): return bottle.template('index') else: return bottle.template('login') + def is_logged_in(): + return True # FIXME + + @app.route('/projects') + def projects(): + projects = api.get_projects() + return bottle.template('projects', projects=projects) + + @app.route('/projects/<name>') + def show_project(name): + project = api.get_project(name) + params = { + 'project': project, + 'as_yaml': as_yaml(project), + } + return bottle.template('project', **params) + + @app.route('/builds') + def builds(): + builds = api.get_builds() + return bottle.template('builds', builds=builds) + + @app.route('/logs/<buildid:path>') + def show_log(buildid): + log = api.get_log(buildid) + return bottle.template('log', buildid=buildid, log=log) + @app.route('/callback') def callback(): + assert 0 + print('/callback called') + print('URL args:', dict(bottle.request.query)) + bottle.response.set_cookie(ICKWEB, 'yes') bottle.redirect('/') return app + + +def as_yaml(obj): + return yaml.safe_dump(obj, indent=4, default_flow_style=False) + + +def string_representer(dumper, data): + style = None + if '\n' in data: + style = '|' + return dumper.represent_scalar('tag:yaml.org,2002:str', data, style=style) + + +yaml.add_representer(str, string_representer, Dumper=yaml.SafeDumper) + + +class API: + + def __init__(self, api_url): + self._url = api_url + self.set_token(None) + + def set_token(self, token): + self._token = token + + def get_token(self): + return self._token + + def get_projects(self): + url = self.url('/projects') + headers = { + 'Authorization': 'Bearer {}'.format(self.get_token()) + } + r = requests.get(url, headers=headers) + if not r.ok: + raise bottle.HTTPError(status=r.status_code) + obj = r.json() + return list(sorted(obj['projects'], key=lambda p: p['project'])) + + def get_project(self, name): + url = self.url('/projects', name) + print('get_project: url:', url) + headers = { + 'Authorization': 'Bearer {}'.format(self.get_token()) + } + r = requests.get(url, headers=headers) + if not r.ok: + raise bottle.HTTPError(status=r.status_code) + return r.json() + + def get_builds(self): + url = self.url('/builds') + headers = { + 'Authorization': 'Bearer {}'.format(self.get_token()) + } + r = requests.get(url, headers=headers) + if not r.ok: + raise bottle.HTTPError(status=r.status_code) + obj = r.json() + return list(sorted(obj['builds'], key=lambda p: p['build_id'])) + + def get_log(self, buildid): + url = self.url('/logs', buildid) + headers = { + 'Authorization': 'Bearer {}'.format(self.get_token()) + } + r = requests.get(url, headers=headers) + if not r.ok: + raise bottle.HTTPError(status=r.status_code) + return r.text + + def url(self, *parts): + return '{}{}'.format(self._url, '/'.join(parts)) diff --git a/views/builds.tpl b/views/builds.tpl new file mode 100644 index 0000000..2fd2d71 --- /dev/null +++ b/views/builds.tpl @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta name="description" content="ickweb"> + <meta name="author" content="The ick project"> + <title>Ick builds</title> + </head> + <body> + <p>Builds:</p> + <ol> + % for build in builds: + <li> + <a href="{{build['log']}}">{{ build['log'] }}</a> + </li> + % end + </ol> + </body> +</html> diff --git a/views/index.tpl b/views/index.tpl index 20ba140..01868ec 100644 --- a/views/index.tpl +++ b/views/index.tpl @@ -2,11 +2,13 @@ <html> <head> <meta charset="utf-8"> - <meta name="description" content="Facade content"> - <meta name="author" content="Qvarnlabs Ltd"> - <title>Facade content</title> + <meta name="description" content="ickweb"> + <meta name="author" content="The ick project"> + <title>Ick</title> </head> <body> - <p>You ARE logged in. Well done!</p> + <p>You ARE logged in. Well done!</p> + <p><a href="/projects">Projects</p> + <p><a href="/builds">Builds</p> </body> </html> diff --git a/views/log.tpl b/views/log.tpl new file mode 100644 index 0000000..14c5235 --- /dev/null +++ b/views/log.tpl @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta name="description" content="ickweb"> + <meta name="author" content="The ick project"> + <title>Ick build log {{ buildid }}</title> + </head> + <body> + <p>Build log {{buildid }}:</p> + <p><blockquote><pre>{{ log }}</pre></blockquote></p> + </body> +</html> diff --git a/views/login.tpl b/views/login.tpl index f983ac0..66cc02e 100644 --- a/views/login.tpl +++ b/views/login.tpl @@ -2,12 +2,12 @@ <html> <head> <meta charset="utf-8"> - <meta name="description" content="Facade login"> - <meta name="author" content="Qvarnlabs Ltd"> + <meta name="description" content="Ickweb login"> + <meta name="author" content="Lars Wirzenius"> <title>Facade login</title> </head> <body> <p>You are NOT logged in.</p> - <p><a href="https://qvisqve-demo.h.qvarnlabs.eu/login">Login</a></p> + <p><a href="https://ci-prod-controller.vm.liw.fi/login">Login</a></p> </body> </html> diff --git a/views/project.tpl b/views/project.tpl new file mode 100644 index 0000000..a4428aa --- /dev/null +++ b/views/project.tpl @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta name="description" content="ickweb"> + <meta name="author" content="The ick project"> + <title>Ick project: {{ project['project'] }}</title> + </head> + <body> + <p>Project: {{ project['project'] }}</p> + <p><blockquote><pre>{{ as_yaml }}</pre></blockquote></p> + </body> +</html> diff --git a/views/projects.tpl b/views/projects.tpl new file mode 100644 index 0000000..66feecf --- /dev/null +++ b/views/projects.tpl @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta name="description" content="ickweb"> + <meta name="author" content="The ick project"> + <title>Ick projects</title> + </head> + <body> + <p>Projects:</p> + <ol> + % for p in projects: + <li> + <a href="/projects/{{p['project']}}">{{ p['project'] }}</a> + </li> + % end + </ol> + </body> +</html> |