[damned-lies] Add ability for authorized persons to refresh statistics
- From: Claude Paroz <claudep src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [damned-lies] Add ability for authorized persons to refresh statistics
- Date: Sat, 30 Mar 2013 14:06:32 +0000 (UTC)
commit 2e612a8bae7fb79113ff81a708ffd8cb19dc2e71
Author: Claude Paroz <claude 2xlibre net>
Date: Sat Mar 30 14:59:03 2013 +0100
Add ability for authorized persons to refresh statistics
Currently, team coordinators and members of the global i18n
coordination team are allowed to proceed with this new action.
common/static/img/refresh.png | Bin 0 -> 827 bytes
people/models.py | 24 +++++++++++++++-------
stats/models.py | 7 +++++-
stats/views.py | 42 ++++++++++++++++++++++++++++++++++++++--
templates/module_detail.html | 10 ++++++++-
urls.py | 4 +++
6 files changed, 74 insertions(+), 13 deletions(-)
---
diff --git a/common/static/img/refresh.png b/common/static/img/refresh.png
new file mode 100644
index 0000000..3b80028
Binary files /dev/null and b/common/static/img/refresh.png differ
diff --git a/people/models.py b/people/models.py
index a6a7585..3e9e99f 100644
--- a/people/models.py
+++ b/people/models.py
@@ -21,6 +21,7 @@
import datetime
import re
+from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils.html import escape
from django.utils.safestring import mark_safe
@@ -136,31 +137,38 @@ class Person(User):
return Team.objects.filter(role__person__id=self.id).all()
def is_coordinator(self, team):
- try:
- self.role_set.get(team__id=team.id, role='coordinator')
- return True
- except:
- return False
+ """
+ If team is provided, tell if current Person is coordinator of that team.
+ If not provided (None), tell if current Person is coordinator of at least one team.
+ """
+ if team is None:
+ return self.role_set.filter(role='coordinator').exists()
+ else:
+ try:
+ self.role_set.get(team__id=team.id, role='coordinator')
+ return True
+ except ObjectDoesNotExist:
+ return False
def is_committer(self, team):
try:
self.role_set.get(team__id=team.id, role__in=['committer', 'coordinator'])
return True
- except:
+ except ObjectDoesNotExist:
return False
def is_reviewer(self, team):
try:
self.role_set.get(team__id=team.id, role__in=['reviewer', 'committer', 'coordinator'])
return True
- except:
+ except ObjectDoesNotExist:
return False
def is_translator(self, team):
try:
self.role_set.get(team__id=team.id)
return True
- except:
+ except ObjectDoesNotExist:
return False
def is_maintainer_of(self, module):
diff --git a/stats/models.py b/stats/models.py
index 4069019..2e1db01 100644
--- a/stats/models.py
+++ b/stats/models.py
@@ -163,9 +163,9 @@ class ModuleLock(object):
def __init__(self, mod):
assert isinstance(mod, Module)
self.module = mod
+ self.dirpath = os.path.join("/tmp", "updating-%s" % (self.module.name,))
def __enter__(self):
- self.dirpath = os.path.join("/tmp", "updating-%s" % (self.module.name,))
while True:
try:
os.mkdir(self.dirpath)
@@ -176,6 +176,11 @@ class ModuleLock(object):
def __exit__(self, *exc_info):
os.rmdir(self.dirpath)
+ @property
+ def is_locked(self):
+ return os.path.exists(self.dirpath)
+
+
class Branch(models.Model):
""" Branch of a module """
name = models.CharField(max_length=50)
diff --git a/stats/views.py b/stats/views.py
index caa2e78..0ce670f 100644
--- a/stats/views.py
+++ b/stats/views.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2008-2011 Claude Paroz <claude 2xlibre net>.
+# Copyright (c) 2008-2013 Claude Paroz <claude 2xlibre net>.
#
# This file is part of Damned Lies.
#
@@ -24,12 +24,13 @@ from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.core import serializers
-from django.http import HttpResponse, Http404
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect, Http404
from django.shortcuts import render, get_object_or_404
from django.utils.translation import ugettext as _
from common.utils import MIME_TYPES, get_user_locale
-from stats.models import Statistics, FakeLangStatistics, Module, Branch, Category, Release
+from stats.models import Statistics, FakeLangStatistics, Module, ModuleLock, Branch, Category, Release
from stats.forms import ModuleBranchForm
from stats import utils
from languages.models import Language
@@ -62,6 +63,7 @@ def module(request, module_name):
'branches': branches,
'non_standard_repo_msg' : _(settings.VCS_HOME_WARNING),
'can_edit_branches': mod.can_edit_branches(request.user),
+ 'can_refresh': can_refresh_branch(request.user),
'user_language': get_user_locale(request)
}
return render(request, 'module_detail.html', context)
@@ -146,6 +148,27 @@ def module_edit_branches(request, module_name):
}
return render(request, 'module_edit_branches.html', context)
+
+def branch_refresh(request, branch_id):
+ if not can_refresh_branch(request.user):
+ return HttpResponseForbidden("You are not allowed to refresh this branch's stats.")
+
+ branch = get_object_or_404(Branch, pk=branch_id)
+ if ModuleLock(branch.module).is_locked:
+ messages.info(request, "A statistics update is already running for branch %s of module %s" % (
+ branch.name, branch.module.name))
+ else:
+ try:
+ branch.update_stats(force=True)
+ except Exception as exc:
+ messages.error(request, "An error occurred while updating statistics for branch %s of module
%s:<br>%s" % (
+ branch.name, branch.module.name, exc))
+ else:
+ messages.success(request, "Statistics successfully updated for branch %s of module %s" % (
+ branch.name, branch.module.name))
+ return HttpResponseRedirect(reverse('module', args=[branch.module.name]))
+
+
def docimages(request, module_name, potbase, branch_name, langcode):
mod = get_object_or_404(Module, name=module_name)
try:
@@ -280,3 +303,16 @@ def compare_by_releases(request, dtype, rels_to_compare):
'stats': stats
}
return render(request, 'release_compare.html', context)
+
+
+# ********** Utility function **********
+def can_refresh_branch(user):
+ """ Return True if user is authorized to force statistics refresh """
+ if not user.is_authenticated():
+ return False
+ if user.has_perm('stats.change_module'):
+ return True
+ person = Person.get_by_user(user)
+ if person.is_coordinator(team=None):
+ return True
+ return False
diff --git a/templates/module_detail.html b/templates/module_detail.html
index 80e30e6..58e92f3 100644
--- a/templates/module_detail.html
+++ b/templates/module_detail.html
@@ -26,6 +26,10 @@ $(document).ready(function() {
$(this).children('img').attr("src", "{{ STATIC_URL }}img/open.png");
}
});
+ $(".refresh").click(function(event) {
+ resp = confirm("You are about to force statistics refresh for that branch. This action can take
several minutes. Are you sure you want to proceed?");
+ return resp;
+ });
}
);
</script>
@@ -93,7 +97,7 @@ $(document).ready(function() {
<!-- Main loop through branches -->
{% for branch in branches %}
- <hr />
+ <hr>
<h2><a href="." class="branch" id="{{ branch.name }}">
{% if forloop.counter < 3 %}
<img src="{{ STATIC_URL }}img/open.png" /></a>
@@ -104,6 +108,10 @@ $(document).ready(function() {
{% if branch.get_vcs_web_url %}
<a href="{{ branch.get_vcs_web_url }}" title="{% trans 'Browse Repository' %}"><img src="{{ STATIC_URL
}}img/repository-icon.png" /></a>
{% endif %}
+ {% if can_refresh %}
+ <a href="{% url 'branch_refresh' branch.pk %}" title="{% trans 'Refresh branch statistics' %}"
class="refresh">
+ <img src="{{ STATIC_URL }}img/refresh.png"></a>
+ {% endif %}
</h2>
{% if forloop.counter < 3 %}
<div id="div-{{ branch.name }}" class="loaded">
diff --git a/urls.py b/urls.py
index daafdd5..a541845 100644
--- a/urls.py
+++ b/urls.py
@@ -80,6 +80,10 @@ urlpatterns += patterns('stats.views',
regex = r'^module/(?P<module_name>[\w\-\+]+)/branch/(?P<branch_name>[\w\-\.]+)/$',
view = 'module_branch'),
url(
+ regex = r'^branch/(?P<branch_id>\d+)/refresh/$',
+ view = 'branch_refresh',
+ name = 'branch_refresh'),
+ url(
regex =
r'^module/(?P<module_name>[\w\-\+]+)/(?P<potbase>[\w~-]+)/(?P<branch_name>[\w\-\.]+)/(?P<langcode>[\w
]+)/images/$',
view = 'docimages',
name = 'docimages'),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]