Merge: Mock Github API tests
[nit.git] / contrib / nitrpg / src / web.nit
index 80f7821..3d54672 100644 (file)
@@ -50,9 +50,85 @@ class RpgAction
                var page = new NitRpgPage(root_url)
                var error = new ErrorPanel(msg)
                page.flow_panels.add error
-               rsp.body = page.write_to_string
+               rsp.body = page
                return rsp
        end
+
+       # Returns the game with `name` or null if no game exists with this name.
+       fun load_game(name: String): nullable Game do
+               var repo = api.load_repo(name)
+               if repo == null then return null
+               var game = new Game.from_mongo(api, repo)
+               game.root_url = root_url
+               return game
+       end
+
+       # Returns the list of saved games from NitRPG data.
+       fun load_games: Array[Game] do
+               var res = new Array[Game]
+               # TODO should be option
+               var mongo = new MongoClient("mongodb://mongo:27017")
+               var db = mongo.database("nitrpg")
+               for obj in db.collection("games").find_all(new JsonObject) do
+                       var repo = api.load_repo(obj["name"].to_s)
+                       assert repo != null
+                       var game = new Game(api, repo)
+                       game.from_json(obj)
+                       game.root_url = root_url
+                       res.add game
+               end
+               return res
+       end
+end
+
+# Repo overview page.
+class RpgHome
+       super RpgAction
+
+       # Response page stub.
+       var page: NitRpgPage is noinit
+
+       redef fun answer(request, url) do
+               var readme = load_readme
+               var games = load_games
+               var response = new HttpResponse(200)
+               page = new NitRpgPage(root_url)
+               page.side_panels.add new GamesShortListPanel(root_url, games)
+               page.flow_panels.add new MDPanel(readme)
+               response.body = page
+               return response
+       end
+
+       # Load the string content of the nitrpg readme file.
+       private fun load_readme: String do
+               var readme = "README.md"
+               if not readme.file_exists then
+                       return "Unable to locate README file."
+               end
+               var file = new FileReader.open(readme)
+               var text = file.read_all
+               file.close
+               return text
+       end
+end
+
+# Display the list of active game.
+class ListGames
+       super RpgAction
+
+       # Response page stub.
+       var page: NitRpgPage is noinit
+
+       redef fun answer(request, url) do
+               var games = load_games
+               var response = new HttpResponse(200)
+               page = new NitRpgPage(root_url)
+               page.breadcrumbs = new Breadcrumbs
+               page.breadcrumbs.add_link(root_url / "games", "games")
+               page.flow_panels.add new GamesListPanel(root_url, games)
+               response.body = page
+               return response
+       end
 end
 
 # An action that require a game.
@@ -72,23 +148,41 @@ class GameAction
                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."
+                       var msg = "Bad request: should look like /games/: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 game = load_game("{owner}/{repo_name}")
+               if game == null then
                        var msg = api.last_error.message
                        return bad_request("Repo Error: {msg}")
                end
+               self.game = game
                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)
+               prepare_pagination(request)
                return response
        end
+
+       # Parse pagination related parameters.
+       private fun prepare_pagination(request: HttpRequest) do
+               var args = request.get_args
+               list_from = args.get_or_default("pfrom", "0").to_i
+               list_limit = args.get_or_default("plimit", "10").to_i
+       end
+
+       # Limit of events to display in lists.
+       var list_limit = 10
+
+       # From where to start the display of events related lists.
+       var list_from = 0
+
+       # TODO should also check 201, 203 ...
+       private fun is_response_error(response: HttpResponse): Bool do
+               return response.status_code != 200
+       end
 end
 
 # Repo overview page.
@@ -97,9 +191,12 @@ class RepoHome
 
        redef fun answer(request, url) do
                var rsp = prepare_response(request, url)
+               if is_response_error(rsp) then return rsp
                page.side_panels.add new ShortListPlayersPanel(game)
                page.flow_panels.add new PodiumPanel(game)
-               rsp.body = page.write_to_string
+               page.flow_panels.add new EventListPanel(game, list_limit, list_from)
+               page.flow_panels.add new AchievementsListPanel(game)
+               rsp.body = page
                return rsp
        end
 end
@@ -110,9 +207,10 @@ class ListPlayers
 
        redef fun answer(request, url) do
                var rsp = prepare_response(request, url)
+               if is_response_error(rsp) then return rsp
                page.breadcrumbs.add_link(game.url / "players", "players")
                page.flow_panels.add new ListPlayersPanel(game)
-               rsp.body = page.write_to_string
+               rsp.body = page
                return rsp
        end
 end
@@ -123,6 +221,7 @@ class PlayerHome
 
        redef fun answer(request, url) do
                var rsp = prepare_response(request, url)
+               if is_response_error(rsp) then return rsp
                var name = request.param("player")
                if name == null then
                        var msg = "Bad request: should look like /:owner/:repo/:players/:name."
@@ -137,7 +236,49 @@ class PlayerHome
                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
+               page.flow_panels.add new PlayerWorkPanel(game, player)
+               page.flow_panels.add new AchievementsListPanel(player)
+               page.flow_panels.add new EventListPanel(player, list_limit, list_from)
+               rsp.body = page
+               return rsp
+       end
+end
+
+# Display the list of achievements unlocked for this game.
+class ListAchievements
+       super GameAction
+
+       redef fun answer(request, url) do
+               var rsp = prepare_response(request, url)
+               if is_response_error(rsp) then return rsp
+               page.breadcrumbs.add_link(game.url / "achievements", "achievements")
+               page.flow_panels.add new AchievementsListPanel(game)
+               rsp.body = page
+               return rsp
+       end
+end
+
+# Player details page.
+class AchievementHome
+       super GameAction
+
+       redef fun answer(request, url) do
+               var rsp = prepare_response(request, url)
+               if is_response_error(rsp) then return rsp
+               var name = request.param("achievement")
+               if name == null then
+                       var msg = "Bad request: should look like /:owner/:repo/achievements/:achievement."
+                       return bad_request(msg)
+               end
+               var achievement = game.load_achievement(name)
+               if achievement == null then
+                       return bad_request("Request Error: unknown achievement {name}.")
+               end
+               page.breadcrumbs.add_link(game.url / "achievements", "achievements")
+               page.breadcrumbs.add_link(achievement.url, achievement.name)
+               page.flow_panels.add new AchievementPanel(achievement)
+               page.flow_panels.add new EventListPanel(achievement, list_limit, list_from)
+               rsp.body = page
                return rsp
        end
 end
@@ -159,7 +300,11 @@ 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/achievements/:achievement", new AchievementHome(root))
+vh.routes.add new Route("/games/:owner/:repo/achievements", new ListAchievements(root))
 vh.routes.add new Route("/games/:owner/:repo", new RepoHome(root))
+vh.routes.add new Route("/games", new ListGames(root))
+vh.routes.add new Route("/", new RpgHome(root))
 
 var fac = new HttpFactory.and_libevent
 fac.config.virtual_hosts.add vh