Switch to unified view

a/Allura/allura/model/stats.py b/Allura/allura/model/stats.py
...
...
84
        if not days:
84
        if not days:
85
            days=1
85
            days=1
86
        for val in self['general']:
86
        for val in self['general']:
87
            if val['category'] is None:
87
            if val['category'] is None:
88
                for commits in val['commits']:
88
                for commits in val['commits']:
89
                    if commits['language'] is None: 
89
                    if commits['language'] is None:
90
                        if days > 30:
90
                        if days > 30:
91
                            return round(float(commits.lines)/days*30, 2)
91
                            return round(float(commits.lines)/days*30, 2)
92
                        else:
92
                        else:
93
                            return float(commits.lines)
93
                            return float(commits.lines)
94
        return 0
94
        return 0
...
...
98
        if not days:
98
        if not days:
99
            days=1
99
            days=1
100
        for val in self['general']:
100
        for val in self['general']:
101
            if val['category'] is None:
101
            if val['category'] is None:
102
                for artifact in val['messages']:
102
                for artifact in val['messages']:
103
                    if artifact['messagetype'] is None: 
103
                    if artifact['messagetype'] is None:
104
                        tot = artifact.created+artifact.modified
104
                        tot = artifact.created+artifact.modified
105
                        if days > 30:
105
                        if days > 30:
106
                            return round(float(tot)/days*30,2)
106
                            return round(float(tot)/days*30,2)
107
                        else:
107
                        else:
108
                            return float(tot)
108
                            return float(tot)
...
...
151
        return maxcontribution, round(averagecontribution, 2)
151
        return maxcontribution, round(averagecontribution, 2)
152
152
153
    def codeRanking(self):
153
    def codeRanking(self):
154
        res = self.query.find()
154
        res = self.query.find()
155
        totn = res.count()
155
        totn = res.count()
156
        if totn == 0:
157
            return 0
156
        codcontr = self.getCodeContribution()
158
        codcontr = self.getCodeContribution()
157
        upper = len([x for x in res if x.getCodeContribution() > codcontr])
159
        upper = len([x for x in res if x.getCodeContribution() > codcontr])
158
        return round((totn - upper) * 100.0 / totn, 2)
160
        return round((totn - upper) * 100.0 / totn, 2)
159
161
160
    def discussionRanking(self):
162
    def discussionRanking(self):
161
        res = self.query.find()
163
        res = self.query.find()
162
        totn = res.count()
164
        totn = res.count()
165
        if totn == 0:
166
            return 0
163
        disccontr = self.getDiscussionContribution()
167
        disccontr = self.getDiscussionContribution()
164
        upper=len([x for x in res if x.getDiscussionContribution()>disccontr])
168
        upper=len([x for x in res if x.getDiscussionContribution()>disccontr])
165
        return round((totn - upper) * 100.0 / totn, 2)
169
        return round((totn - upper) * 100.0 / totn, 2)
166
170
167
    def ticketsRanking(self):
171
    def ticketsRanking(self):
168
        res = self.query.find()
172
        res = self.query.find()
169
        totn = res.count()
173
        totn = res.count()
174
        if totn == 0:
175
            return 0
170
        ticketscontr = self.getTicketsContribution()
176
        ticketscontr = self.getTicketsContribution()
171
        upper=len([x for x in res if x.getTicketsContribution()>ticketscontr])
177
        upper=len([x for x in res if x.getTicketsContribution()>ticketscontr])
172
        return round((totn - upper) * 100.0 / totn, 2)
178
        return round((totn - upper) * 100.0 / totn, 2)
173
179
174
    def getCommits(self, category = None):
180
    def getCommits(self, category = None):
175
        i = getElementIndex(self.general, category = category)
181
        i = getElementIndex(self.general, category = category)
176
        if i is None: 
182
        if i is None:
177
            return dict(number=0, lines=0)
183
            return dict(number=0, lines=0)
178
        cat = self.general[i]
184
        cat = self.general[i]
179
        j = getElementIndex(cat.commits, language = None)
185
        j = getElementIndex(cat.commits, language = None)
180
        if j is None:
186
        if j is None:
181
            return dict(number=0, lines=0)
187
            return dict(number=0, lines=0)
182
        return dict(
188
        return dict(
183
            number=cat.commits[j]['number'], 
189
            number=cat.commits[j]['number'],
184
            lines=cat.commits[j]['lines'])
190
            lines=cat.commits[j]['lines'])
185
191
186
    def getArtifacts(self, category = None, art_type = None):
192
    def getArtifacts(self, category = None, art_type = None):
187
        i = getElementIndex(self.general, category = category)
193
        i = getElementIndex(self.general, category = category)
188
        if i is None:
194
        if i is None:
...
...
200
                assigned=0,
206
                assigned=0,
201
                solved=0,
207
                solved=0,
202
                revoked=0,
208
                revoked=0,
203
                averagesolvingtime=None)
209
                averagesolvingtime=None)
204
        if self.general[i].tickets.solved > 0:
210
        if self.general[i].tickets.solved > 0:
205
            tot = self.general[i].tickets.totsolvingtime 
211
            tot = self.general[i].tickets.totsolvingtime
206
            number = self.general[i].tickets.solved
212
            number = self.general[i].tickets.solved
207
            average = tot / number
213
            average = tot / number
208
        else: 
214
        else:
209
            average = None
215
            average = None
210
        return dict(
216
        return dict(
211
            assigned=self.general[i].tickets.assigned,
217
            assigned=self.general[i].tickets.assigned,
212
            solved=self.general[i].tickets.solved,
218
            solved=self.general[i].tickets.solved,
213
            revoked=self.general[i].tickets.revoked,
219
            revoked=self.general[i].tickets.revoked,
...
...
218
224
219
        by_cat = {}
225
        by_cat = {}
220
        for entry in self.general:
226
        for entry in self.general:
221
            cat = entry.category
227
            cat = entry.category
222
            i = getElementIndex(entry.commits, language = None)
228
            i = getElementIndex(entry.commits, language = None)
223
            if i is None: 
229
            if i is None:
224
                n, lines = 0, 0
230
                n, lines = 0, 0
225
            else: 
231
            else:
226
                n, lines = entry.commits[i].number, entry.commits[i].lines
232
                n, lines = entry.commits[i].number, entry.commits[i].lines
227
            if cat != None:
233
            if cat != None:
228
                cat = TroveCategory.query.get(_id = cat)
234
                cat = TroveCategory.query.get(_id = cat)
229
            by_cat[cat] = dict(number=n, lines=lines)
235
            by_cat[cat] = dict(number=n, lines=lines)
230
        return by_cat
236
        return by_cat
...
...
235
    #within a project including two or more languages.
241
    #within a project including two or more languages.
236
    def getCommitsByLanguage(self):
242
    def getCommitsByLanguage(self):
237
        langlist = []
243
        langlist = []
238
        by_lang = {}
244
        by_lang = {}
239
        i = getElementIndex(self.general, category=None)
245
        i = getElementIndex(self.general, category=None)
240
        if i is None: 
246
        if i is None:
241
            return dict(number=0, lines=0)
247
            return dict(number=0, lines=0)
242
        return dict([(el.language, dict(lines=el.lines, number=el.number))
248
        return dict([(el.language, dict(lines=el.lines, number=el.number))
243
                     for el in self.general[i].commits])
249
                     for el in self.general[i].commits])
244
250
245
    def getArtifactsByCategory(self, detailed=False):
251
    def getArtifactsByCategory(self, detailed=False):
246
        from allura.model.project import TroveCategory
252
        from allura.model.project import TroveCategory
247
253
248
        by_cat = {}
254
        by_cat = {}
249
        for entry in self.general:
255
        for entry in self.general:
250
            cat = entry.category
256
            cat = entry.category
251
            if cat != None: 
257
            if cat != None:
252
                cat = TroveCategory.query.get(_id = cat)
258
                cat = TroveCategory.query.get(_id = cat)
253
            if detailed: 
259
            if detailed:
254
                by_cat[cat] = entry.messages
260
                by_cat[cat] = entry.messages
255
            else:
261
            else:
256
                i = getElementIndex(entry.messages, messagetype=None)
262
                i = getElementIndex(entry.messages, messagetype=None)
257
                if i is not None:
263
                if i is not None:
258
                    by_cat[cat] = entry.messages[i]
264
                    by_cat[cat] = entry.messages[i]
259
                else: 
265
                else:
260
                    by_cat[cat] = dict(created=0, modified=0)
266
                    by_cat[cat] = dict(created=0, modified=0)
261
        return by_cat
267
        return by_cat
262
268
263
    def getArtifactsByType(self, category=None):
269
    def getArtifactsByType(self, category=None):
264
        i = getElementIndex(self.general, category = category)
270
        i = getElementIndex(self.general, category = category)
265
        if i is None: 
271
        if i is None:
266
            return {}
272
            return {}
267
        entry = self.general[i].messages
273
        entry = self.general[i].messages
268
        by_type = dict([(el.messagetype, dict(created=el.created,
274
        by_type = dict([(el.messagetype, dict(created=el.created,
269
                                              modified=el.modified))
275
                                              modified=el.modified))
270
                         for el in entry])
276
                         for el in entry])
...
...
285
            else:
291
            else:
286
                average = None
292
                average = None
287
            by_cat[cat] = dict(
293
            by_cat[cat] = dict(
288
                assigned=a,
294
                assigned=a,
289
                solved=s,
295
                solved=s,
290
                revoked=r, 
296
                revoked=r,
291
                averagesolvingtime=_convertTimeDiff(average))
297
                averagesolvingtime=_convertTimeDiff(average))
292
        return by_cat
298
        return by_cat
293
299
294
    def getLastMonthCommits(self, category = None):
300
    def getLastMonthCommits(self, category = None):
295
        self.checkOldArtifacts() 
301
        self.checkOldArtifacts()
296
        lineslist = [el.lines for el in self.lastmonth.commits
302
        lineslist = [el.lines for el in self.lastmonth.commits
297
                     if category in el.categories + [None]]
303
                     if category in el.categories + [None]]
298
        return dict(number=len(lineslist), lines=sum(lineslist))
304
        return dict(number=len(lineslist), lines=sum(lineslist))
299
305
300
    def getLastMonthCommitsByCategory(self):
306
    def getLastMonthCommitsByCategory(self):
301
        from allura.model.project import TroveCategory
307
        from allura.model.project import TroveCategory
302
308
303
        self.checkOldArtifacts() 
309
        self.checkOldArtifacts()
304
        seen = set()
310
        seen = set()
305
        catlist=[el.category for el in self.general
311
        catlist=[el.category for el in self.general
306
                 if el.category not in seen and not seen.add(el.category)]
312
                 if el.category not in seen and not seen.add(el.category)]
307
313
308
        by_cat = {}
314
        by_cat = {}
...
...
317
        return by_cat
323
        return by_cat
318
324
319
    def getLastMonthCommitsByLanguage(self):
325
    def getLastMonthCommitsByLanguage(self):
320
        from allura.model.project import TroveCategory
326
        from allura.model.project import TroveCategory
321
327
322
        self.checkOldArtifacts() 
328
        self.checkOldArtifacts()
323
        seen = set()
329
        seen = set()
324
        langlist=[el.language for el in self.general
330
        langlist=[el.language for el in self.general
325
                  if el.language not in seen and not seen.add(el.language)]
331
                  if el.language not in seen and not seen.add(el.language)]
326
332
327
        by_lang = {}
333
        by_lang = {}
...
...
334
                lang = TroveCategory.query.get(_id = lang)
340
                lang = TroveCategory.query.get(_id = lang)
335
            by_lang[lang] = dict(number=n, lines=lines)
341
            by_lang[lang] = dict(number=n, lines=lines)
336
        return by_lang
342
        return by_lang
337
343
338
    def getLastMonthArtifacts(self, category = None, art_type = None):
344
    def getLastMonthArtifacts(self, category = None, art_type = None):
339
        self.checkOldArtifacts() 
345
        self.checkOldArtifacts()
340
        cre, mod = reduce(
346
        cre, mod = reduce(
341
            addtuple, 
347
            addtuple,
342
            [(int(el.created),1-int(el.created))
348
            [(int(el.created),1-int(el.created))
343
                for el in self.lastmonth.messages
349
                for el in self.lastmonth.messages
344
                if (category is None or category in el.categories) and 
350
                if (category is None or category in el.categories) and
345
                (el.messagetype == art_type or art_type is None)], 
351
                (el.messagetype == art_type or art_type is None)],
346
            (0,0))
352
            (0,0))
347
        return dict(created=cre, modified=mod)
353
        return dict(created=cre, modified=mod)
348
354
349
    def getLastMonthArtifactsByType(self, category = None):
355
    def getLastMonthArtifactsByType(self, category = None):
350
        self.checkOldArtifacts()
356
        self.checkOldArtifacts()
...
...
353
               if el.messagetype not in seen and not seen.add(el.messagetype)]
359
               if el.messagetype not in seen and not seen.add(el.messagetype)]
354
360
355
        by_type = {}
361
        by_type = {}
356
        for t in types:
362
        for t in types:
357
            cre, mod = reduce(
363
            cre, mod = reduce(
358
                addtuple, 
364
                addtuple,
359
                [(int(el.created),1-int(el.created))
365
                [(int(el.created),1-int(el.created))
360
                 for el in self.lastmonth.messages
366
                 for el in self.lastmonth.messages
361
                 if el.messagetype == t and
367
                 if el.messagetype == t and
362
                 category in [None]+el.categories],
368
                 category in [None]+el.categories],
363
                (0,0))
369
                (0,0))
...
...
365
        return by_type
371
        return by_type
366
372
367
    def getLastMonthArtifactsByCategory(self):
373
    def getLastMonthArtifactsByCategory(self):
368
        from allura.model.project import TroveCategory
374
        from allura.model.project import TroveCategory
369
375
370
        self.checkOldArtifacts() 
376
        self.checkOldArtifacts()
371
        seen = set()
377
        seen = set()
372
        catlist=[el.category for el in self.general
378
        catlist=[el.category for el in self.general
373
                 if el.category not in seen and not seen.add(el.category)]
379
                 if el.category not in seen and not seen.add(el.category)]
374
380
375
        by_cat = {}
381
        by_cat = {}
376
        for cat in catlist:
382
        for cat in catlist:
377
            cre, mod = reduce(
383
            cre, mod = reduce(
378
                addtuple, 
384
                addtuple,
379
                [(int(el.created),1-int(el.created))
385
                [(int(el.created),1-int(el.created))
380
                 for el in self.lastmonth.messages 
386
                 for el in self.lastmonth.messages
381
                 if cat in el.categories + [None]], (0,0))
387
                 if cat in el.categories + [None]], (0,0))
382
            if cat != None:
388
            if cat != None:
383
                cat = TroveCategory.query.get(_id = cat)
389
                cat = TroveCategory.query.get(_id = cat)
384
            by_cat[cat] = dict(created=cre, modified=mod)
390
            by_cat[cat] = dict(created=cre, modified=mod)
385
        return by_cat
391
        return by_cat
...
...
391
        a = len([el for el in self.lastmonth.assignedtickets
397
        a = len([el for el in self.lastmonth.assignedtickets
392
                 if category in el.categories + [None]])
398
                 if category in el.categories + [None]])
393
        r = len([el for el in self.lastmonth.revokedtickets
399
        r = len([el for el in self.lastmonth.revokedtickets
394
                 if category in el.categories + [None]])
400
                 if category in el.categories + [None]])
395
        s, time = reduce(
401
        s, time = reduce(
396
            addtuple, 
402
            addtuple,
397
            [(1, el.solvingtime)
403
            [(1, el.solvingtime)
398
             for el in self.lastmonth.solvedtickets
404
             for el in self.lastmonth.solvedtickets
399
             if category in el.categories + [None]],
405
             if category in el.categories + [None]],
400
            (0,0))
406
            (0,0))
401
        if category!=None:
407
        if category!=None:
...
...
405
        else:
411
        else:
406
            time = None
412
            time = None
407
        return dict(
413
        return dict(
408
            assigned=a,
414
            assigned=a,
409
            revoked=r,
415
            revoked=r,
410
            solved=s, 
416
            solved=s,
411
            averagesolvingtime=_convertTimeDiff(time))
417
            averagesolvingtime=_convertTimeDiff(time))
412
        
418
413
    def getLastMonthTicketsByCategory(self):
419
    def getLastMonthTicketsByCategory(self):
414
        from allura.model.project import TroveCategory
420
        from allura.model.project import TroveCategory
415
421
416
        self.checkOldArtifacts()
422
        self.checkOldArtifacts()
417
        seen = set()
423
        seen = set()
...
...
426
            s, time = reduce(addtuple, [(1, el.solvingtime)
432
            s, time = reduce(addtuple, [(1, el.solvingtime)
427
                                        for el in self.lastmonth.solvedtickets
433
                                        for el in self.lastmonth.solvedtickets
428
                                        if cat in el.categories+[None]],(0,0))
434
                                        if cat in el.categories+[None]],(0,0))
429
            if cat != None:
435
            if cat != None:
430
                cat = TroveCategory.query.get(_id = cat)
436
                cat = TroveCategory.query.get(_id = cat)
431
            if s > 0: 
437
            if s > 0:
432
                time = time / s
438
                time = time / s
433
            else:
439
            else:
434
                time = None
440
                time = None
435
            by_cat[cat] = dict(
441
            by_cat[cat] = dict(
436
                assigned=a,
442
                assigned=a,
437
                revoked=r,
443
                revoked=r,
438
                solved=s, 
444
                solved=s,
439
                averagesolvingtime=_convertTimeDiff(time))
445
                averagesolvingtime=_convertTimeDiff(time))
440
        return by_cat
446
        return by_cat
441
        
447
442
    def checkOldArtifacts(self):
448
    def checkOldArtifacts(self):
443
        now = datetime.utcnow()
449
        now = datetime.utcnow()
444
        for m in self.lastmonth.messages:
450
        for m in self.lastmonth.messages:
445
            if now - m.datetime > timedelta(30):
451
            if now - m.datetime > timedelta(30):
446
                self.lastmonth.messages.remove(m)
452
                self.lastmonth.messages.remove(m)
...
...
507
                lines = len([l for l in diff if len(l) > 0 and l[0] == '+'])-1
513
                lines = len([l for l in diff if len(l) > 0 and l[0] == '+'])-1
508
            else:
514
            else:
509
                lines = 0
515
                lines = 0
510
            return lines
516
            return lines
511
517
512
        def _addCommitData(stats, topics, languages, lines):          
518
        def _addCommitData(stats, topics, languages, lines):
513
            lt = topics + [None]
519
            lt = topics + [None]
514
            ll = languages + [None]
520
            ll = languages + [None]
515
            for t in lt:
521
            for t in lt:
516
                i = getElementIndex(stats.general, category=t) 
522
                i = getElementIndex(stats.general, category=t)
517
                if i is None:
523
                if i is None:
518
                    newstats = dict(
524
                    newstats = dict(
519
                        category=t,
525
                        category=t,
520
                        commits=[],
526
                        commits=[],
521
                        messages=[],
527
                        messages=[],
...
...
559
            totlines+=_computeLines(newblob)
565
            totlines+=_computeLines(newblob)
560
566
561
        _addCommitData(self, topics, languages, totlines)
567
        _addCommitData(self, topics, languages, totlines)
562
568
563
        self.lastmonth.commits.append(dict(
569
        self.lastmonth.commits.append(dict(
564
            datetime=commit_datetime, 
570
            datetime=commit_datetime,
565
            categories=topics, 
571
            categories=topics,
566
            programming_languages=languages,
572
            programming_languages=languages,
567
            lines=totlines))
573
            lines=totlines))
568
        self.checkOldArtifacts()
574
        self.checkOldArtifacts()
569
575
570
    def _updateArtifactsStats(self, art_type, art_datetime, project, action):
576
    def _updateArtifactsStats(self, art_type, art_datetime, project, action):
571
        if action not in ['created', 'modified']: 
577
        if action not in ['created', 'modified']:
572
            return
578
            return
573
        topics = [t for t in project.trove_topic if t]
579
        topics = [t for t in project.trove_topic if t]
574
        lt = [None] + topics
580
        lt = [None] + topics
575
        for mtype in [None, art_type]:
581
        for mtype in [None, art_type]:
576
            for t in lt:
582
            for t in lt:
...
...
599
        self.lastmonth.messages.append(dict(
605
        self.lastmonth.messages.append(dict(
600
            datetime=art_datetime,
606
            datetime=art_datetime,
601
            created=(action == 'created'),
607
            created=(action == 'created'),
602
            categories=topics,
608
            categories=topics,
603
            messagetype=art_type))
609
            messagetype=art_type))
604
        self.checkOldArtifacts() 
610
        self.checkOldArtifacts()
605
611
606
    def _updateTicketsStats(self, topics, action, s_time = None):
612
    def _updateTicketsStats(self, topics, action, s_time = None):
607
        if action not in ['solved', 'assigned', 'revoked']:
613
        if action not in ['solved', 'assigned', 'revoked']:
608
            return
614
            return
609
        lt = topics + [None]
615
        lt = topics + [None]
...
...
619
                        revoked=0,
625
                        revoked=0,
620
                        totsolvingtime=0),
626
                        totsolvingtime=0),
621
                    messages=[])
627
                    messages=[])
622
                self.general.append(stats)
628
                self.general.append(stats)
623
                i = getElementIndex(self.general, category = t)
629
                i = getElementIndex(self.general, category = t)
624
            self.general[i]['tickets'][action] += 1 
630
            self.general[i]['tickets'][action] += 1
625
            if action == 'solved': 
631
            if action == 'solved':
626
                self.general[i]['tickets']['totsolvingtime']+=s_time
632
                self.general[i]['tickets']['totsolvingtime']+=s_time
627
633
628
def getElementIndex(el_list, **kw):
634
def getElementIndex(el_list, **kw):
629
    for i in range(len(el_list)):
635
    for i in range(len(el_list)):
630
        for k in kw:
636
        for k in kw:
...
...
647
    hours = seconds / 3600
653
    hours = seconds / 3600
648
    seconds = seconds % 3600
654
    seconds = seconds % 3600
649
    minutes = seconds / 60
655
    minutes = seconds / 60
650
    seconds = seconds % 60
656
    seconds = seconds % 60
651
    return dict(
657
    return dict(
652
        days=days, 
658
        days=days,
653
        hours=hours, 
659
        hours=hours,
654
        minutes=minutes,
660
        minutes=minutes,
655
        seconds=seconds)
661
        seconds=seconds)
656
662
657
Mapper.compile_all()
663
Mapper.compile_all()