summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/__init__.py0
-rw-r--r--packages/models.py91
-rw-r--r--packages/templatetags/__init__.py0
-rw-r--r--packages/templatetags/package_extras.py28
-rw-r--r--packages/views.py172
5 files changed, 291 insertions, 0 deletions
diff --git a/packages/__init__.py b/packages/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/packages/__init__.py
diff --git a/packages/models.py b/packages/models.py
new file mode 100644
index 00000000..c1b6c84d
--- /dev/null
+++ b/packages/models.py
@@ -0,0 +1,91 @@
+from django.db import models
+from django.contrib.auth.models import User
+import re
+
+class PackageManager(models.Manager):
+ def get_flag_stats(self):
+ results = []
+ # first the orphans
+ unflagged = self.filter(maintainer=0).count()
+ flagged = self.filter(maintainer=0).filter(needupdate=True).count()
+ results.append((User(id=0,first_name='Orphans'), unflagged, flagged))
+ # now the rest
+ for maint in User.objects.all().order_by('first_name'):
+ unflagged = self.filter(maintainer=maint.id).count()
+ flagged = self.filter(maintainer=maint.id).filter(needupdate=True).count()
+ results.append((maint, unflagged, flagged))
+ return results
+
+class Category(models.Model):
+ id = models.AutoField(primary_key=True)
+ category = models.CharField(maxlength=255)
+ class Meta:
+ db_table = 'categories'
+ verbose_name_plural = 'categories'
+
+class Repo(models.Model):
+ id = models.AutoField(primary_key=True)
+ name = models.CharField(maxlength=255)
+ class Meta:
+ db_table = 'repos'
+ def last_update(self):
+ try:
+ latest = Package.objects.filter(repo__name__exact=self.name).order_by('-last_update')[0]
+ return latest.last_update
+ except IndexError:
+ return "N/A"
+
+class Package(models.Model):
+ id = models.AutoField(primary_key=True)
+ repo = models.ForeignKey(Repo)
+ maintainer = models.ForeignKey(User)
+ category = models.ForeignKey(Category)
+ needupdate = models.BooleanField(default=False)
+ pkgname = models.CharField(maxlength=255)
+ pkgver = models.CharField(maxlength=255)
+ pkgrel = models.CharField(maxlength=255)
+ pkgdesc = models.CharField(maxlength=255)
+ url = models.URLField()
+ sources = models.TextField()
+ depends = models.TextField()
+ last_update = models.DateTimeField(null=True, blank=True)
+ objects = PackageManager()
+ class Meta:
+ db_table = 'packages'
+ get_latest_by = 'last_update'
+
+ def get_absolute_url(self):
+ return '/packages/%i/' % self.id
+
+ def depends_urlize(self):
+ urls = ''
+ for dep in self.depends.split(' '):
+ # shave off any version qualifiers
+ nameonly = re.match(r"([a-z0-9-]+)", dep).group(1)
+ try:
+ p = Package.objects.filter(pkgname=nameonly)[0]
+ except IndexError:
+ # couldn't find a package in the DB -- it might be a virtual depend
+ urls = urls + '<li>' + dep + '</li>'
+ continue
+ url = '<li><a href="/packages/' + str(p.id) + '">' + dep + '</a></li>'
+ urls = urls + url
+ return urls
+
+ def sources_urlize(self):
+ urls = ''
+ for source in self.sources.split(' '):
+ if re.search('://', source):
+ url = '<li><a href="' + source + '">' + source + '</a></li>'
+ else:
+ url = '<li>' + source + '</li>'
+ urls = urls + url
+ return urls
+
+class PackageFile(models.Model):
+ id = models.AutoField(primary_key=True)
+ pkg = models.ForeignKey(Package)
+ path = models.CharField(maxlength=255)
+ class Meta:
+ db_table = 'packages_files'
+
diff --git a/packages/templatetags/__init__.py b/packages/templatetags/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/packages/templatetags/__init__.py
diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py
new file mode 100644
index 00000000..8b55221b
--- /dev/null
+++ b/packages/templatetags/package_extras.py
@@ -0,0 +1,28 @@
+from django import template
+
+register = template.Library()
+
+class BuildQueryStringNode(template.Node):
+ def __init__(self, sortfield):
+ self.sortfield = sortfield
+ def render(self, context):
+ qs = context['querystring'].copy()
+ if qs.has_key('sort') and qs['sort'] == self.sortfield:
+ qs['sort'] = '-' + self.sortfield
+ else:
+ qs['sort'] = self.sortfield
+ return '?' + qs.urlencode()
+
+@register.tag(name='buildsortqs')
+def do_buildsortqs(parser, token):
+ try:
+ tagname, sortfield = token.split_contents()
+ except ValueError:
+ raise template.TemplateSyntaxError, "%r tag requires a single argument" % tagname
+ if not (sortfield[0] == sortfield[-1] and sortfield[0] in ('"', "'")):
+ raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tagname
+ return BuildQueryStringNode(sortfield[1:-1])
+
+@register.filter(name='space2br')
+def space2br(value):
+ return value.replace(' ', '<br />')
diff --git a/packages/views.py b/packages/views.py
new file mode 100644
index 00000000..f9cecf1b
--- /dev/null
+++ b/packages/views.py
@@ -0,0 +1,172 @@
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import get_object_or_404
+from django.core.mail import send_mail
+from django.template import Context, loader
+from django.core import validators
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
+from archlinux.utils import validate, render_template
+from datetime import datetime
+from archlinux.packages.models import Package, PackageFile, Repo, Category
+
+def update(request):
+ if request.POST.has_key('adopt'):
+ mode = 'adopt'
+ message = 'Adoption was successful'
+ if request.POST.has_key('disown'):
+ mode = 'disown'
+ message = 'Disown was successful'
+ try:
+ maint = User.objects.get(username=request.user.username)
+ except User.DoesNotExist:
+ return render_template('error_page.html', request, {'errmsg':'No maintainer record found! Are you a maintainer?'})
+ ids = request.POST.getlist('pkgid')
+ for id in ids:
+ pkg = Package.objects.get(id=id)
+ if mode == 'adopt' and pkg.maintainer_id == 0:
+ pkg.maintainer = maint
+ elif mode == 'disown' and pkg.maintainer == maint:
+ pkg.maintainer_id = 0
+ else:
+ message = "You are not the current maintainer"
+ pkg.save()
+ return render_template('status_page.html', request, {'message':message})
+
+def details(request, pkgid=0, name='', repo=''):
+ if pkgid == 0:
+ p = Package.objects.filter(pkgname=name)
+ if repo: p = p.filter(repo__name__exact=repo)
+ # if more then one result, send to the search view
+ if len(p) > 1: return search(request, name)
+ if len(p) < 1: return render_template('error_page.html', request,
+ {'errmsg': 'No matching packages.'})
+ pkgid = p[0].id
+
+ pkg = get_object_or_404(Package, id=pkgid)
+ return render_template('packages/details.html', request, {'pkg':pkg})
+
+def search(request, query=''):
+ if request.GET.has_key('q'):
+ # take the q GET var over the one passed on the URL
+ query = request.GET['q'].strip()
+
+ # fetch the form vars
+ repo = request.GET.get('repo', 'all')
+ category = request.GET.get('category', 'all')
+ lastupdate = request.GET.get('lastupdate', '')
+ limit = int(request.GET.get('limit', '50'))
+ skip = int(request.GET.get('skip', '0'))
+ sort = request.GET.get('sort', '')
+ maint = request.GET.get('maint', 'all')
+
+ # build the form lists
+ repos = Repo.objects.order_by('name')
+ cats = Category.objects.order_by('category')
+ # copy GET data over and add the lists
+ c = request.GET.copy()
+ c['repos'], c['categories'] = repos, cats
+ c['limit'], c['skip'] = limit, skip
+ c['lastupdate'] = lastupdate
+ c['sort'] = sort
+ # 'q' gets renamed to 'query', so it's not in GET
+ c['query'] = query
+
+ # validate
+ errors = {}
+ validate(errors, 'Last Update', lastupdate, validators.isValidANSIDate, True, request)
+ validate(errors, 'Page Limit', str(limit), validators.isOnlyDigits, True, request)
+ validate(errors, 'Page Skip', str(skip), validators.isOnlyDigits, True, request)
+ if errors:
+ c['errors'] = errors
+ return render_template('packages/search.html', request, c)
+
+ if query:
+ res1 = Package.objects.filter(pkgname__icontains=query)
+ res2 = Package.objects.filter(pkgdesc__icontains=query)
+ results = res1 | res2
+ else:
+ results = Package.objects.all()
+ if repo != 'all': results = results.filter(repo__name__exact=repo)
+ if category != 'all': results = results.filter(category__category__exact=category)
+ if maint != 'all': results = results.filter(maintainer=maint)
+ if lastupdate: results = results.filter(last_update__gte=datetime(int(lastupdate[0:4]),int(lastupdate[5:7]),int(lastupdate[8:10])))
+ # select_related() shouldn't be needed -- we're working around a Django bug
+ #results = results.select_related().order_by('repos.name', 'category', 'pkgname')
+
+ # sort results
+ if sort == '':
+ results = results.order_by('repo', 'category', 'pkgname')
+ else:
+ # duplicate sort fields shouldn't hurt anything
+ results = results.order_by(sort, 'repo', 'category', 'pkgname')
+
+ qs = request.GET.copy()
+ # build pagination urls
+ if results.count() > (skip + limit):
+ qs['skip'] = skip + limit
+ c['nextpage'] = '?' + qs.urlencode()
+ if skip > 0:
+ qs['skip'] = max(0, skip - limit)
+ c['prevpage'] = '?' + qs.urlencode()
+ # pass the querystring to the template so we can build sort queries
+ c['querystring'] = request.GET
+
+ # if only there's only one result, pass right to the package details view
+ if results.count() == 1: return details(request, results[0].id)
+ # limit result set
+ if limit > 0: results = results[skip:(skip+limit)]
+
+ c['results'] = results
+ return render_template('packages/search.html', request, c)
+
+def files(request, pkgid):
+ pkg = get_object_or_404(Package, id=pkgid)
+ files = PackageFile.objects.filter(pkg=pkgid)
+ return render_template('packages/files.html', request, {'pkg':pkg,'files':files})
+
+def flaghelp(request):
+ return render_template('packages/flaghelp.html', request)
+
+def flag(request, pkgid):
+ pkg = get_object_or_404(Package, id=pkgid)
+ context = {'pkg': pkg}
+ if request.POST.has_key('confirmemail'):
+ email = request.POST['confirmemail']
+ if request.POST.has_key('usermessage'):
+ message = request.POST['usermessage']
+ else:
+ message = None
+ # validate
+ errors = {}
+ validate(errors, 'Email Address', email, validators.isValidEmail, False, request)
+ if errors:
+ context['errors'] = errors
+ return render_template('packages/flag.html', request, context)
+
+ context['confirmemail'] = email
+ pkg.needupdate = 1
+ pkg.save()
+ if pkg.maintainer_id > 0:
+ # send notification email to the maintainer
+ t = loader.get_template('packages/outofdate.txt')
+ c = Context({
+ 'email': request.POST['confirmemail'],
+ 'message': message,
+ 'pkgname': pkg.pkgname,
+ 'weburl': 'http://www.archlinux.org/packages/' + str(pkg.id) + '/'
+ })
+ send_mail('arch: Package [%s] marked out-of-date' % pkg.pkgname,
+ t.render(c),
+ 'Arch Website Notification <nobody@archlinux.org>',
+ [pkg.maintainer.email],
+ fail_silently=True)
+ return render_template('packages/flag.html', request, context)
+
+@login_required
+def unflag(request, pkgid):
+ pkg = get_object_or_404(Package, id=pkgid)
+ if pkg.maintainer.username != request.user.username:
+ return render_template('error_page.html', request, {'errmsg': 'You do not own this package.'})
+ pkg.needupdate = 0
+ pkg.save()
+ return HttpResponseRedirect('/packages/%d/' % (pkg.id))