Merge: nitiwiki: fix multiple trails
authorJean Privat <jean@pryen.org>
Sat, 28 Nov 2015 23:04:07 +0000 (18:04 -0500)
committerJean Privat <jean@pryen.org>
Sat, 28 Nov 2015 23:04:07 +0000 (18:04 -0500)
Fix a bug where independent trails could have been merged into a big one.

Pull-Request: #1854
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

contrib/nitrpg/src/achievements.nit
contrib/nitrpg/src/events.nit
contrib/nitrpg/src/game.nit
contrib/nitrpg/src/reactors.nit
contrib/nitrpg/src/statistics.nit
contrib/nitrpg/src/templates/templates_base.nit

index 9b18a6b..5ce317a 100644 (file)
@@ -74,10 +74,15 @@ end
 class Achievement
        super GameEntity
 
-       redef var key is lazy do return "achievements" / id
 
        redef var game
 
+       redef var key is lazy do
+               var owner = self.owner
+               if owner == null then return id
+               return "{owner.key}-{id}"
+       end
+
        # Uniq ID for this achievement.
        var id: String
 
@@ -93,6 +98,9 @@ class Achievement
        # Is this achievement unlocked by somebody?
        var is_unlocked: Bool is lazy do return not load_events.is_empty
 
+       # Game entity this achievement is about.
+       var owner: nullable GameEntity = null
+
        # Init `self` from a `json` object.
        #
        # Used to load achievements from storage.
@@ -106,6 +114,8 @@ class Achievement
                json["name"] = name
                json["desc"] = desc
                json["reward"] = reward
+               json["game"] = game.key
+               if owner != null then json["owner"] = owner.key
                return json
        end
 end
@@ -346,7 +356,7 @@ abstract class PlayerXCommits
                if not event.action == "closed" then return
                if not event.pull.merged then return
                var player = event.pull.user.player(game)
-               if player.stats["commits"] == threshold then
+               if player.stats["commits"] >= threshold then
                        var a = new_achievement(game)
                        player.unlock_achievement(a, event)
                end
@@ -447,7 +457,7 @@ end
 class Player1KComments
        super PlayerXComments
 
-       redef var id = "player_1000__comments"
+       redef var id = "player_1000_comments"
        redef var name = "You sir, talk a lot!"
        redef var desc = "Comment 1000 times on issues."
        redef var reward = 1000
index d1ba25a..bd1ee58 100644 (file)
@@ -24,8 +24,10 @@ import game
 
 redef class GameEntity
 
-       # Saves `event` in `self`.
-       fun add_event(event: GameEvent) do event.save_in(self.key)
+       fun add_event(event: GameEvent) do
+               event.owner = self
+               event.save
+       end
 
        # List all events registered in this entity.
        #
@@ -61,10 +63,12 @@ end
 class GameEvent
        super GameEntity
 
-       redef var key is lazy do return "events" / internal_id
 
        redef var game
 
+       # Entity this event belongs to.
+       var owner: nullable GameEntity = null
+
        # String used to dissociate events in the display.
        var kind: String
 
@@ -76,6 +80,8 @@ class GameEvent
        # GameEvent uniq id used for storage.
        var internal_id: String is noinit
 
+       redef var key = internal_id is lazy
+
        # Date and time of the event.
        var time: ISODate is noinit, writable
 
@@ -100,6 +106,8 @@ class GameEvent
                json["kind"] = kind
                json["time"] = time.to_s
                json["data"] = data
+               json["game"] = game.key
+               if owner != null then json["owner"] = owner.key
                return json
        end
 end
index a109949..2924e46 100644 (file)
@@ -65,20 +65,20 @@ class Game
 
        redef fun game do return self
 
-       # Returns the repo `full_name`.
-       #
-       # Example: `"nitlang/nit"`
-       redef fun key do return repo.full_name
-
        # We need a `GithubAPI` client to load Github data.
        var api: GithubAPI
 
        # A game takes place in a `github::Repo`.
        var repo: Repo
 
+       # Game name
+       var name: String = repo.full_name is lazy
+
        # Directory where game data are stored.
        var game_dir: String is lazy do return "nitrpg_data" / repo.full_name
 
+       redef var key = name is lazy
+
        # Used for data storage.
        #
        # File are stored in `game_dir`.
@@ -92,6 +92,12 @@ class Game
        # Used to load entities from saved data.
        fun from_json(json: JsonObject) do end
 
+       redef fun to_json do
+               var json = super
+               json["name"] = name
+               return json
+       end
+
        # Create a player from a Github `User`.
        #
        # Or return the existing one from game data.
@@ -180,9 +186,6 @@ end
 class Player
        super GameEntity
 
-       # Key is based on player `name`.
-       redef var key is lazy do return "players" / name
-
        redef var game
 
        # FIXME contructor should be private
@@ -195,6 +198,8 @@ class Player
        # The name is also used to load the user data lazilly from Github API.
        var name: String
 
+       redef var key = name is lazy
+
        # Player amount of nitcoins.
        #
        # Nitcoins is the currency used in nitrpg.
@@ -218,6 +223,7 @@ class Player
 
        redef fun to_json do
                var json = super
+               json["game"] = game.key
                json["name"] = name
                json["nitcoins"] = nitcoins
                return json
index 7073c98..e2717f4 100644 (file)
@@ -58,7 +58,7 @@ redef class PullRequestEvent
 
        # Rewards player for opened pull requests.
        redef fun react_player_event(r, game) do
-               if action == "opened" then
+               if action == "opened" or action == "reopened" then
                        react_pull_open(r, game)
                else if action == "closed" then
                        react_pull_close(r, game)
@@ -95,14 +95,18 @@ redef class IssueCommentEvent
        # Rewards player for review comments.
        #
        # TODO only give nitcoins if reviewers < 2
+       # TODO give more points to first reviewer
        redef fun react_player_event(r, game) do
                if comment.is_ack then
                        react_player_review(r, game)
                end
        end
 
+       # TODO same player should not be authorized to review multiple times? How to handle rerols?
        private fun react_player_review(r: PlayerReactor, game: Game) do
+               if issue.state == "closed" then return
                var player = comment.user.player(game)
+               if issue.user == player.user then return
                player.nitcoins += r.nc_pull_review
                player.save
                var event = player_reward_event("pull_review", player, r.nc_pull_review)
index b7d3530..153b5cd 100644 (file)
@@ -79,49 +79,32 @@ class GameStatsManager
        # The GameEntity monitored by these statistics.
        var owner: GameEntity
 
-       redef var key = "stats"
+       # Current date to extract stats
+       private var date = new Tm.gmtime
 
        # Returns the `GameStats` instance for the overall statistics.
-       var overall: GameStats is lazy do
-               return load_stats_for("all")
-       end
+       var overall: GameStats = load_stats_for("all") is lazy
 
        # Returns the `GameStats` instance for the current year statistics.
-       var yearly: GameStats is lazy do
-               var date = new Tm.gmtime
-               var key = date.strftime("%Y")
-               return load_stats_for(key)
-       end
+       var yearly: GameStats = load_stats_for(date.strftime("%Y")) is lazy
 
        # Returns the `GameStats` instance for the current month statistics.
-       var monthly: GameStats is lazy do
-               var date = new Tm.gmtime
-               var key = date.strftime("%Y-%m")
-               return load_stats_for(key)
-       end
+       var monthly: GameStats = load_stats_for(date.strftime("%Y-%m")) is lazy
 
        # Returns the `GameStats` instance for the current day statistics.
-       var daily: GameStats is lazy do
-               var date = new Tm.gmtime
-               var key = date.strftime("%Y-%m-%d")
-               return load_stats_for(key)
-       end
+       var daily: GameStats = load_stats_for(date.strftime("%Y-%m-%d")) is lazy
 
        # Returns the `GameStats` instance for the current week statistics.
-       var weekly: GameStats is lazy do
-               var date = new Tm.gmtime
-               var key = date.strftime("%Y-W%U")
-               return load_stats_for(key)
-       end
+       var weekly: GameStats = load_stats_for(date.strftime("%Y-W%U")) is lazy
 
        # Load statistics for a `period` key.
        fun load_stats_for(period: String): GameStats do
                var key = owner.key / self.key / period
                if not game.store.has_key(key) then
-                       return new GameStats(game, period)
+                       return new GameStats(game, period, owner)
                end
                var json = game.store.load_object(key)
-               return new GameStats.from_json(game, period, json)
+               return new GameStats.from_json(game, period, owner, json)
        end
 
        redef fun [](key) do return overall[key]
@@ -168,19 +151,28 @@ class GameStats
 
        redef var game
 
-       # The pedriod these stats are about.
+       # The period these stats are about.
        var period: String
 
-       redef fun key do return period
+       # The game entity these stats are about.
+       var owner: GameEntity
+
+       redef var key = "{owner.key}-{period}" is lazy
 
        # Load `self` from saved data.
-       init from_json(game: Game, period: String, json: JsonObject) do
-               for k, v in json do self[k] = v.as(Int)
+       init from_json(game: Game, period: String, owner: GameEntity, json: JsonObject) do
+               var values = json.get_or_null("values")
+               if not values isa JsonObject then return
+               for k, v in values do self[k] = v.as(Int)
        end
 
        redef fun to_json do
-               var obj = new JsonObject
-               for k, v in self do obj[k] = v
+               var obj = super
+               obj["period"] = period
+               obj["owner"] = owner.key
+               var values = new JsonObject
+               values.recover_with(self)
+               obj["values"] = values
                return obj
        end
 
index 8b85a4d..a4f40d9 100644 (file)
@@ -34,9 +34,6 @@ redef class Game
 
        redef fun url do return "{root_url}/games" / key
 
-       # Displayed name.
-       fun name: String do return repo.full_name
-
        # Return a HTML link to this Game.
        fun link: String do return "<a href=\"{url}\">{name}</a>"
 end