contrib/nitrpg: introduce the tool that run the website
authorAlexandre Terrasa <alexandre@moz-code.org>
Tue, 3 Feb 2015 21:40:07 +0000 (22:40 +0100)
committerAlexandre Terrasa <alexandre@moz-code.org>
Wed, 4 Feb 2015 18:14:57 +0000 (19:14 +0100)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

contrib/nitrpg/src/web.nit [new file with mode: 0644]
contrib/nitrpg/www/styles/main.css [new file with mode: 0644]

diff --git a/contrib/nitrpg/src/web.nit b/contrib/nitrpg/src/web.nit
new file mode 100644 (file)
index 0000000..80f7821
--- /dev/null
@@ -0,0 +1,168 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Display `nitrpg` data as a website.
+module web
+
+import nitcorn
+import templates
+
+# A custom action forn `nitrpg`.
+class RpgAction
+       super Action
+
+       # Root URL is used as a prefix for all URL generated by the actions.
+       var root_url: String
+
+       # Github oauth token used for GithubAPI.
+       var auth: String is lazy do return get_github_oauth
+
+       # API client used to import data from Github.
+       var api: GithubAPI is lazy do
+               var api = new GithubAPI(auth)
+               return api
+       end
+
+       init do
+               super
+               if auth.is_empty then
+                       print "Error: Invalid Github oauth token!"
+                       exit 1
+               end
+       end
+
+       # Return an Error reponse page.
+       fun bad_request(msg: String): HttpResponse do
+               var rsp = new HttpResponse(400)
+               var page = new NitRpgPage(root_url)
+               var error = new ErrorPanel(msg)
+               page.flow_panels.add error
+               rsp.body = page.write_to_string
+               return rsp
+       end
+end
+
+# An action that require a game.
+class GameAction
+       super RpgAction
+
+       # Response page stub.
+       var page: NitRpgPage is noinit
+
+       # Target game.
+       var game: Game is noinit
+
+       redef fun answer(request, url) is abstract
+
+       # Check errors and prepare response.
+       private fun prepare_response(request: HttpRequest, url: String): HttpResponse do
+               var owner = request.param("owner")
+               var repo_name = request.param("repo")
+               if owner == null or repo_name == null then
+                       var msg = "Bad request: should look like /repos/:owner/:repo."
+                       return bad_request(msg)
+               end
+               var repo = new Repo(api, "{owner}/{repo_name}")
+               game = new Game(api, repo)
+               game.root_url = root_url
+               if api.was_error then
+                       var msg = api.last_error.message
+                       return bad_request("Repo Error: {msg}")
+               end
+               var response = new HttpResponse(200)
+               page = new NitRpgPage(root_url)
+               page.side_panels.add new GameStatusPanel(game)
+               page.breadcrumbs = new Breadcrumbs
+               page.breadcrumbs.add_link(game.url, game.name)
+               return response
+       end
+end
+
+# Repo overview page.
+class RepoHome
+       super GameAction
+
+       redef fun answer(request, url) do
+               var rsp = prepare_response(request, url)
+               page.side_panels.add new ShortListPlayersPanel(game)
+               page.flow_panels.add new PodiumPanel(game)
+               rsp.body = page.write_to_string
+               return rsp
+       end
+end
+
+# Repo players list.
+class ListPlayers
+       super GameAction
+
+       redef fun answer(request, url) do
+               var rsp = prepare_response(request, url)
+               page.breadcrumbs.add_link(game.url / "players", "players")
+               page.flow_panels.add new ListPlayersPanel(game)
+               rsp.body = page.write_to_string
+               return rsp
+       end
+end
+
+# Player details page.
+class PlayerHome
+       super GameAction
+
+       redef fun answer(request, url) do
+               var rsp = prepare_response(request, url)
+               var name = request.param("player")
+               if name == null then
+                       var msg = "Bad request: should look like /:owner/:repo/:players/:name."
+                       return bad_request(msg)
+               end
+               var player = game.load_player(name)
+               if player == null then
+                       return bad_request("Request Error: unknown player {name}.")
+               end
+               page.breadcrumbs.add_link(game.url / "players", "players")
+               page.breadcrumbs.add_link(player.url, name)
+               page.side_panels.clear
+               page.side_panels.add new PlayerStatusPanel(game, player)
+               page.flow_panels.add new PlayerReviewsPanel(game, player)
+               rsp.body = page.write_to_string
+               return rsp
+       end
+end
+
+if args.length != 3 then
+       print "Error: missing argument"
+       print ""
+       print "Usage:"
+       print "web <host> <port> <root_url>"
+       exit 1
+end
+
+var host = args[0]
+var port = args[1]
+var root = args[2]
+
+var iface = "{host}:{port}"
+var vh = new VirtualHost(iface)
+vh.routes.add new Route("/styles/", new FileServer("www/styles"))
+vh.routes.add new Route("/games/:owner/:repo/players/:player", new PlayerHome(root))
+vh.routes.add new Route("/games/:owner/:repo/players", new ListPlayers(root))
+vh.routes.add new Route("/games/:owner/:repo", new RepoHome(root))
+
+var fac = new HttpFactory.and_libevent
+fac.config.virtual_hosts.add vh
+
+print "Launching server on http://{iface}/"
+fac.run
diff --git a/contrib/nitrpg/www/styles/main.css b/contrib/nitrpg/www/styles/main.css
new file mode 100644 (file)
index 0000000..865123e
--- /dev/null
@@ -0,0 +1,74 @@
+body { padding-top: 70px; }
+
+.navbar .breadcrumb {
+       background-color: transparent;
+       margin-bottom: 0;
+       margin-top: 0.5em;
+}
+
+/* columns of same height styles */
+.container-xs-height {
+    display:table;
+    padding-left:0px;
+    padding-right:0px;
+}
+.row-xs-height {
+    display:table-row;
+}
+.col-xs-height {
+    display:table-cell;
+    float:none;
+}
+@media (min-width: 768px) {
+    .container-sm-height {
+        display:table;
+        padding-left:0px;
+        padding-right:0px;
+    }
+    .row-sm-height {
+        display:table-row;
+    }
+    .col-sm-height {
+        display:table-cell;
+        float:none;
+    }
+}
+@media (min-width: 992px) {
+    .container-md-height {
+        display:table;
+        padding-left:0px;
+        padding-right:0px;
+    }
+    .row-md-height {
+        display:table-row;
+    }
+    .col-md-height {
+        display:table-cell;
+        float:none;
+    }
+}
+@media (min-width: 1200px) {
+    .container-lg-height {
+        display:table;
+        padding-left:0px;
+        padding-right:0px;
+    }
+    .row-lg-height {
+        display:table-row;
+    }
+    .col-lg-height {
+        display:table-cell;
+        float:none;
+    }
+}
+
+/* vertical alignment styles */
+.col-top {
+    vertical-align:top;
+}
+.col-middle {
+    vertical-align:middle;
+}
+.col-bottom {
+    vertical-align:bottom;
+}