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>
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
# 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.
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
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
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
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.
#
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
# 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
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
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`.
# 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.
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
# 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.
redef fun to_json do
var json = super
+ json["game"] = game.key
json["name"] = name
json["nitcoins"] = nitcoins
return json
# 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)
# 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)
# 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]
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
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