1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Statistics about the Game.
19 # This module uses `GameReactor` to extract statistics about the game from
20 # triggered `Github::Event`.
27 redef class GameEntity
29 # Statistics manager for this entity.
30 fun stats
: GameStatsManager is abstract
35 redef var stats
is lazy
do return new GameStatsManager(game
, self)
38 var res
= new FlatBuffer
40 res
.append
"# stats:\n"
41 res
.append stats
.pretty
42 return res
.write_to_string
53 redef var stats
is lazy
do return new GameStatsManager(game
, self)
55 redef fun nitcoins
do return stats
["nitcoins"]
56 redef fun nitcoins
=(nc
) do stats
["nitcoins"] = nc
59 var res
= new FlatBuffer
61 res
.append
"# stats:\n"
62 res
.append stats
.pretty
63 return res
.write_to_string
72 # Store game stats for defined period.
73 class GameStatsManager
79 # The GameEntity monitored by these statistics.
82 # Current date to extract stats
83 private var date
= new Tm.gmtime
85 # Returns the `GameStats` instance for the overall statistics.
86 var overall
: GameStats = load_stats_for
("all") is lazy
88 # Returns the `GameStats` instance for the current year statistics.
89 var yearly
: GameStats = load_stats_for
(date
.strftime
("%Y")) is lazy
91 # Returns the `GameStats` instance for the current month statistics.
92 var monthly
: GameStats = load_stats_for
(date
.strftime
("%Y-%m")) is lazy
94 # Returns the `GameStats` instance for the current day statistics.
95 var daily
: GameStats = load_stats_for
(date
.strftime
("%Y-%m-%d")) is lazy
97 # Returns the `GameStats` instance for the current week statistics.
98 var weekly
: GameStats = load_stats_for
(date
.strftime
("%Y-W%U")) is lazy
100 # Load statistics for a `period` key.
101 fun load_stats_for
(period
: String): GameStats do
102 var req
= new JsonObject
103 req
["period"] = period
104 req
["owner"] = owner
.key
105 var obj
= game
.db
.collection
("statistics").find
(req
)
106 if obj
isa JsonObject then
107 return new GameStats.from_json
(game
, period
, owner
, obj
)
109 return new GameStats(game
, period
, owner
)
113 redef fun [](key
) do return overall
[key
]
115 redef fun []=(key
, value
) do
147 redef fun pretty
do return overall
.pretty
150 # Game statistics structure that can be saved as a `GameEntity`.
153 super Counter[String]
157 redef var collection_name
= "statistics"
159 # The period these stats are about.
162 # The game entity these stats are about.
163 var owner
: GameEntity
165 redef var key
= "{owner.key}-{period}" is lazy
167 # Load `self` from saved data.
168 init from_json
(game
: Game, period
: String, owner
: GameEntity, json
: JsonObject) do
169 init(game
, period
, owner
)
170 var values
= json
.get_or_null
("values")
171 if not values
isa JsonObject then return
172 for k
, v
in values
do self[k
] = v
.as(Int)
177 obj
["period"] = period
178 obj
["owner"] = owner
.key
179 var values
= new JsonObject
181 obj
["values"] = values
186 var res
= new FlatBuffer
188 res
.append
"# {v} {k}\n"
190 return res
.write_to_string
194 # `GameReactor` that computes statistics about the game.
195 class StatisticsReactor
198 redef fun react_event
(game
, e
) do e
.react_stats_event
(game
)
201 redef class GithubEvent
202 # Reacts to a statistics related event.
204 # Called by `StatisticsReactor::react_event`.
206 private fun react_stats_event
(game
: Game) do end
209 redef class IssuesEvent
211 # Count opened and closed issues.
212 redef fun react_stats_event
(game
) do
213 var player
= issue
.user
.player
(game
)
214 if action
== "opened" then
215 game
.stats
.inc
("issues")
216 game
.stats
.inc
("issues_open")
218 player
.stats
.inc
("issues")
219 player
.stats
.inc
("issues_open")
221 else if action
== "reopened" then
222 game
.stats
.inc
("issues_open")
224 player
.stats
.inc
("issues_open")
226 else if action
== "closed" then
227 game
.stats
.dec
("issues_open")
229 player
.stats
.dec
("issues_open")
235 redef class PullRequestEvent
237 # Count opened and closed pull requests.
238 redef fun react_stats_event
(game
) do
239 var player
= pull
.user
.player
(game
)
240 if action
== "opened" then
241 game
.stats
.inc
("pulls")
242 game
.stats
.inc
("pulls_open")
244 player
.stats
.inc
("pulls")
245 player
.stats
.inc
("pulls_open")
247 else if action
== "reopened" then
248 game
.stats
.inc
("pulls_open")
250 player
.stats
.inc
("pulls_open")
252 else if action
== "closed" then
253 game
.stats
.dec
("pulls_open")
254 player
.stats
.dec
("pulls_open")
256 game
.stats
["commits"] += pull
.commits
257 player
.stats
["commits"] += pull
.commits
265 redef class IssueCommentEvent
267 # Count posted comments
268 redef fun react_stats_event
(game
) do
269 if action
== "created" then
270 var player
= comment
.user
.player
(game
)
271 game
.stats
.inc
("comments")
272 player
.stats
.inc
("comments")
273 # FIXME use a more precise way to locate reviews
274 if comment
.is_ack
then
275 game
.stats
.inc
("reviews")
276 player
.stats
.inc
("reviews")