summaryrefslogtreecommitdiff
path: root/devel
diff options
context:
space:
mode:
authorNicolás Reynolds <fauno@kiwwwi.com.ar>2011-05-21 02:11:13 -0300
committerNicolás Reynolds <fauno@kiwwwi.com.ar>2011-05-21 02:11:13 -0300
commita30350ac6e76c66d14f6d78ed2b5ae4e5799c79c (patch)
treea2b7127366a1b9d8d5be9fcda5abefacef7d2579 /devel
parentd8f82d9d72eec6042536797f75e06a9296f4cc71 (diff)
parent2470c543d60c96343a5b0fefe04464b5b445b859 (diff)
Merge branch 'master' of git://projects.archlinux.org/archweb
Conflicts: devel/views.py feeds.py templates/devel/index.html templates/packages/flag.html templates/public/index.html todolists/views.py urls.py
Diffstat (limited to 'devel')
-rw-r--r--devel/management/commands/reporead.py6
-rw-r--r--devel/urls.py9
-rw-r--r--devel/views.py142
3 files changed, 130 insertions, 27 deletions
diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py
index e26bb800..a8875c7e 100644
--- a/devel/management/commands/reporead.py
+++ b/devel/management/commands/reporead.py
@@ -315,7 +315,7 @@ def populate_files(dbpkg, repopkg, force=False):
directory=dirname + '/',
filename=filename)
pkgfile.save(force_insert=True)
- dbpkg.files_last_update = datetime.now()
+ dbpkg.files_last_update = datetime.utcnow()
dbpkg.save()
@transaction.commit_on_success
@@ -374,7 +374,7 @@ def db_update(archname, reponame, pkgs, options):
for p in [x for x in pkgs if x.name in in_sync_not_db]:
logger.info("Adding package %s", p.name)
pkg = Package(pkgname = p.name, arch = architecture, repo = repository)
- populate_pkg(pkg, p, timestamp=datetime.now())
+ populate_pkg(pkg, p, timestamp=datetime.utcnow())
# packages in database and not in syncdb (remove from database)
in_db_not_sync = dbset - syncset
@@ -398,7 +398,7 @@ def db_update(archname, reponame, pkgs, options):
if not force:
continue
else:
- timestamp = datetime.now()
+ timestamp = datetime.utcnow()
if filesonly:
logger.debug("Checking files for package %s in database", p.name)
populate_files(dbp, p, force=force)
diff --git a/devel/urls.py b/devel/urls.py
index 41be2b31..9bf50f45 100644
--- a/devel/urls.py
+++ b/devel/urls.py
@@ -1,12 +1,13 @@
from django.conf.urls.defaults import patterns
urlpatterns = patterns('devel.views',
- (r'^$', 'index'),
+ (r'^admin_log/$','admin_log'),
+ (r'^admin_log/(?P<username>.*)/$','admin_log'),
(r'^clock/$', 'clock'),
- (r'^profile/$', 'change_profile'),
+ (r'^$', 'index'),
(r'^newuser/$', 'new_user_form'),
- (r'^admin_log/(?P<username>.*)/$','admin_log'),
- (r'^admin_log/$','admin_log'),
+ (r'^profile/$', 'change_profile'),
+ (r'^reports/(?P<report>.*)/$', 'report'),
)
# vim: set ts=4 sw=4 et:
diff --git a/devel/views.py b/devel/views.py
index 5b03f8c0..5d34cc41 100644
--- a/devel/views.py
+++ b/devel/views.py
@@ -2,21 +2,27 @@ from django import forms
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import \
login_required, permission_required, user_passes_test
-from django.contrib.auth.models import User
+from django.contrib.auth.models import User, Group
from django.contrib.sites.models import Site
from django.core.mail import send_mail
+from django.db import transaction
+from django.db.models import Q
+from django.http import Http404
from django.shortcuts import get_object_or_404
from django.template import loader, Context
+from django.template.defaultfilters import filesizeformat
from django.views.decorators.cache import never_cache
from django.views.generic.simple import direct_to_template
-from main.models import Package, Todolist, TodolistPkg
+from main.models import Package, PackageDepend, PackageFile, TodolistPkg
from main.models import Arch, Repo
from main.models import UserProfile
from packages.models import PackageRelation
+from todolists.utils import get_annotated_todolists
from .utils import get_annotated_maintainers
-import datetime
+from datetime import datetime, timedelta
+import operator
import pytz
import random
from string import ascii_letters, digits
@@ -24,7 +30,7 @@ from string import ascii_letters, digits
@login_required
@never_cache
def index(request):
- '''the Developer dashboard'''
+ '''the developer dashboard'''
inner_q = PackageRelation.objects.filter(user=request.user).values('pkgbase')
flagged = Package.objects.select_related('arch', 'repo').filter(
flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname')
@@ -34,6 +40,9 @@ def index(request):
todopkgs = todopkgs.filter(pkg__pkgbase__in=inner_q).order_by(
'list__name', 'pkg__pkgname')
+ todolists = get_annotated_todolists()
+ todolists = [todolist for todolist in todolists if todolist.incomplete_count > 0]
+
maintainers = get_annotated_maintainers()
maintained = PackageRelation.objects.filter(
@@ -47,7 +56,7 @@ def index(request):
}
page_dict = {
- 'todos': Todolist.objects.incomplete().order_by('-date_added'),
+ 'todos': todolists,
'repos': Repo.objects.all(),
'arches': Arch.objects.all(),
'maintainers': maintainers,
@@ -65,8 +74,8 @@ def clock(request):
'username').select_related('userprofile')
# now annotate each dev object with their current time
- now = datetime.datetime.now()
- utc_now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
+ now = datetime.now()
+ utc_now = datetime.utcnow().replace(tzinfo=pytz.utc)
for dev in devs:
# Work around https://bugs.launchpad.net/pytz/+bug/718673
timezone = str(dev.userprofile.time_zone)
@@ -118,14 +127,84 @@ def change_profile(request):
return direct_to_template(request, 'devel/profile.html',
{'form': form, 'profile_form': profile_form})
+@login_required
+def report(request, report):
+ title = 'Developer Report'
+ packages = Package.objects.select_related('arch', 'repo')
+ names = attrs = None
+ if report == 'old':
+ title = 'Packages last built more than two years ago'
+ cutoff = datetime.now() - timedelta(days=730)
+ packages = packages.filter(build_date__lt=cutoff).order_by('build_date')
+ elif report == 'big':
+ title = 'Packages with compressed size > 50 MiB'
+ cutoff = 50 * 1024 * 1024
+ packages = packages.filter(compressed_size__gte=cutoff).order_by('-compressed_size')
+ names = [ 'Compressed Size', 'Installed Size' ]
+ attrs = [ 'compressed_size_pretty', 'installed_size_pretty' ]
+ # Format the compressed and installed sizes with MB/GB/etc suffixes
+ for package in packages:
+ package.compressed_size_pretty = filesizeformat(
+ package.compressed_size)
+ package.installed_size_pretty = filesizeformat(
+ package.installed_size)
+ elif report == 'uncompressed-man':
+ title = 'Packages with uncompressed manpages'
+ # magic going on here! Checking for all '.1'...'.9' extensions
+ invalid_endings = [Q(filename__endswith='.%d' % n) for n in range(1,10)]
+ invalid_endings.append(Q(filename__endswith='.n'))
+ bad_files = PackageFile.objects.filter(Q(directory__contains='man') & (
+ reduce(operator.or_, invalid_endings))
+ ).values_list('pkg_id', flat=True).distinct()
+ packages = packages.filter(id__in=set(bad_files))
+ elif report == 'uncompressed-info':
+ title = 'Packages with uncompressed infopages'
+ # we don't worry abut looking for '*.info-1', etc., given that an
+ # uncompressed root page probably exists in the package anyway
+ bad_files = PackageFile.objects.filter(directory__endswith='/info/',
+ filename__endswith='.info').values_list(
+ 'pkg_id', flat=True).distinct()
+ packages = packages.filter(id__in=set(bad_files))
+ elif report == 'unneeded-orphans':
+ title = 'Orphan packages required by no other packages'
+ owned = PackageRelation.objects.all().values('pkgbase')
+ required = PackageDepend.objects.all().values('depname')
+ # The two separate calls to exclude is required to do the right thing
+ packages = packages.exclude(pkgbase__in=owned).exclude(
+ pkgname__in=required)
+ else:
+ raise Http404
+
+ context = {
+ 'title': title,
+ 'packages': packages,
+ 'column_names': names,
+ 'column_attrs': attrs,
+ }
+ return direct_to_template(request, 'devel/packages.html', context)
+
+
class NewUserForm(forms.ModelForm):
- class Meta:
- model = UserProfile
- exclude = ('picture', 'user')
username = forms.CharField(max_length=30)
- email = forms.EmailField()
+ private_email = forms.EmailField()
first_name = forms.CharField(required=False)
last_name = forms.CharField(required=False)
+ groups = forms.ModelMultipleChoiceField(required=False,
+ queryset=Group.objects.all())
+
+ class Meta:
+ model = UserProfile
+ exclude = ('picture', 'user')
+
+ def __init__(self, *args, **kwargs):
+ super(NewUserForm, self).__init__(*args, **kwargs)
+ # Hack ourself so certain fields appear first. self.fields is a
+ # SortedDict object where we can manipulate the keyOrder list.
+ order = self.fields.keyOrder
+ keys = ('username', 'private_email', 'first_name', 'last_name')
+ for key in reversed(keys):
+ order.remove(key)
+ order.insert(0, key)
def clean_username(self):
username = self.cleaned_data['username']
@@ -134,38 +213,61 @@ class NewUserForm(forms.ModelForm):
"A user with that username already exists.")
return username
- def save(self):
- profile = forms.ModelForm.save(self, False)
+ def save(self, commit=True):
+ profile = super(NewUserForm, self).save(False)
pwletters = ascii_letters + digits
password = ''.join([random.choice(pwletters) for i in xrange(8)])
user = User.objects.create_user(username=self.cleaned_data['username'],
- email=self.cleaned_data['email'], password=password)
+ email=self.cleaned_data['private_email'], password=password)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
+ # sucks that the MRM.add() method can't take a list directly... we have
+ # to resort to dirty * magic.
+ user.groups.add(*self.cleaned_data['groups'])
profile.user = user
- profile.save()
+ if commit:
+ profile.save()
+ self.save_m2m()
- t = loader.get_template('devel/new_account.txt')
- c = Context({
+ template = loader.get_template('devel/new_account.txt')
+ ctx = Context({
'site': Site.objects.get_current(),
'user': user,
'password': password,
})
- send_mail("Your new archweb account",
- t.render(c),
+ send_mail("Your new parabolaweb account",
+ template.render(ctx),
'Parabola <dev@list.parabolagnulinux.org>',
[user.email],
fail_silently=False)
+def log_addition(request, obj):
+ """Cribbed from ModelAdmin.log_addition."""
+ from django.contrib.admin.models import LogEntry, ADDITION
+ from django.contrib.contenttypes.models import ContentType
+ from django.utils.encoding import force_unicode
+ LogEntry.objects.log_action(
+ user_id = request.user.pk,
+ content_type_id = ContentType.objects.get_for_model(obj).pk,
+ object_id = obj.pk,
+ object_repr = force_unicode(obj),
+ action_flag = ADDITION,
+ change_message = "Added via Create New User form."
+ )
+
@permission_required('auth.add_user')
@never_cache
def new_user_form(request):
if request.POST:
form = NewUserForm(request.POST)
if form.is_valid():
- form.save()
+ @transaction.commit_on_success
+ def inner_save():
+ form.save()
+ log_addition(request, form.instance.user)
+ inner_save()
return HttpResponseRedirect('/admin/auth/user/%d/' % \
form.instance.user.id)
else: