aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Sim <russell.sim@vpac.org>2009-04-21 21:04:16 +1000
committerRussell Sim <russell.sim@vpac.org>2009-04-21 21:04:16 +1000
commit05af358f9cbeeb04216f649ffec6c828edac794c (patch)
treeaf4ae4eab467013ecb8cabaef66059a88461b409
parentb9acbab26cd672b3fe441ae2e111ce575ae6b8ef (diff)
downloadchishop-05af358f9cbeeb04216f649ffec6c828edac794c.tar.bz2
chishop-05af358f9cbeeb04216f649ffec6c828edac794c.tar.xz
chishop-05af358f9cbeeb04216f649ffec6c828edac794c.zip
complete refactor to use ModelForm
-rw-r--r--chishop/settings.py1
-rw-r--r--djangopypi/forms.py85
-rw-r--r--djangopypi/models.py5
-rw-r--r--djangopypi/views.py102
4 files changed, 91 insertions, 102 deletions
diff --git a/chishop/settings.py b/chishop/settings.py
index 9d769f2..22dff36 100644
--- a/chishop/settings.py
+++ b/chishop/settings.py
@@ -15,6 +15,7 @@ ADMINS = (
15# The default on PyPI is to not allow this, but it can be real handy 15# The default on PyPI is to not allow this, but it can be real handy
16# if you're sloppy. 16# if you're sloppy.
17DJANGOPYPI_ALLOW_VERSION_OVERWRITE = False 17DJANGOPYPI_ALLOW_VERSION_OVERWRITE = False
18DJANGOPYPI_RELEASE_UPLOAD_TO = 'dists'
18 19
19MANAGERS = ADMINS 20MANAGERS = ADMINS
20 21
diff --git a/djangopypi/forms.py b/djangopypi/forms.py
index 51b1498..7704753 100644
--- a/djangopypi/forms.py
+++ b/djangopypi/forms.py
@@ -37,83 +37,14 @@ from djangopypi.models import Project, Classifier, Release
37from django.utils.translation import ugettext_lazy as _ 37from django.utils.translation import ugettext_lazy as _
38 38
39 39
40class PermissionDeniedError(Exception): 40class ProjectForm(forms.ModelForm):
41 """The user did not have the privileges to execute an action.""" 41 class Meta:
42 model = Project
43 exclude = ['owner', 'classifiers']
42 44
43 45
44class AlreadyExistsError(Exception): 46class ReleaseForm(forms.ModelForm):
45 """Filename already exists.""" 47 class Meta:
48 model = Release
49 exclude = ['project']
46 50
47ALREADY_EXISTS_FMT = _("""A file named "%s" already exists for %s. To fix """
48 + "problems with that you should create a new release.")
49
50
51class ProjectRegisterForm(forms.Form):
52 name = forms.CharField()
53 license = forms.CharField(required=False)
54 metadata_version = forms.CharField(initial="1.0")
55 author = forms.CharField(required=False)
56 home_page = forms.CharField(required=False)
57 download_url = forms.CharField(required=False)
58 summary = forms.CharField(required=False)
59 description = forms.CharField(required=False)
60 author_email = forms.CharField(required=False)
61 version = forms.CharField()
62 platform = forms.CharField(required=False)
63
64 PermissionDeniedError = PermissionDeniedError
65 AlreadyExistsError = AlreadyExistsError
66
67 def save(self, classifiers, user, file=None):
68 values = dict(self.cleaned_data)
69 name = values["name"]
70 version = values.pop("version")
71 platform = values.pop("platform", "UNKNOWN")
72 values["owner"] = user
73
74 try:
75 project = Project.objects.get(name=name)
76 except Project.DoesNotExist:
77 project = Project.objects.create(**values)
78 else:
79 # If the project already exists,
80 # be sure that the current user owns this object.
81 if project.owner != user:
82 raise self.PermissionDeniedError(
83 "%s doesn't own that project." % user.username)
84 [setattr(project, field_name, field_value)
85 for field_name, field_value in values.items()]
86 project.save()
87
88
89 for classifier in classifiers:
90 project.classifiers.add(
91 Classifier.objects.get_or_create(name=classifier)[0])
92
93 # If the old file already exists, django will append a _ after the
94 # filename, however with .tar.gz files django does the "wrong" thing
95 # and saves it as project-0.1.2.tar_.gz. So remove it before
96 # django sees anything.
97 allow_overwrite = getattr(settings,
98 "DJANGOPYPI_ALLOW_VERSION_OVERWRITE", False)
99
100 if file:
101 try:
102 release = Release.objects.get(version=version,
103 platform=platform, project=project)
104 if os.path.exists(release.distribution.path):
105 if not allow_overwrite:
106 raise self.AlreadyExistsError(ALREADY_EXISTS_FMT % (
107 release.filename, release))
108 os.remove(release.distribution.path)
109
110 release.delete()
111 except (Release.DoesNotExist, ValueError):
112 pass
113
114 release, created = Release.objects.get_or_create(version=version,
115 platform=platform,
116 project=project)
117 if file:
118 release.distribution.save(file.name, file, save=True)
119 release.save()
diff --git a/djangopypi/models.py b/djangopypi/models.py
index d6df975..b4b1e34 100644
--- a/djangopypi/models.py
+++ b/djangopypi/models.py
@@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
31""" 31"""
32 32
33import os 33import os
34from django.conf import settings
34from django.db import models 35from django.db import models
35from django.utils.translation import ugettext_lazy as _ 36from django.utils.translation import ugettext_lazy as _
36from django.contrib.auth.models import User 37from django.contrib.auth.models import User
@@ -63,6 +64,8 @@ ARCHITECTURES = (
63 ("ultrasparc", "UltraSparc"), 64 ("ultrasparc", "UltraSparc"),
64) 65)
65 66
67UPLOAD_TO = getattr(settings,
68 "DJANGOPYPI_RELEASE_UPLOAD_TO", 'dist')
66 69
67class Classifier(models.Model): 70class Classifier(models.Model):
68 name = models.CharField(max_length=255, unique=True) 71 name = models.CharField(max_length=255, unique=True)
@@ -107,7 +110,7 @@ class Project(models.Model):
107 110
108class Release(models.Model): 111class Release(models.Model):
109 version = models.CharField(max_length=128) 112 version = models.CharField(max_length=128)
110 distribution = models.FileField(upload_to="dists") 113 distribution = models.FileField(upload_to=UPLOAD_TO)
111 md5_digest = models.CharField(max_length=255, blank=True) 114 md5_digest = models.CharField(max_length=255, blank=True)
112 platform = models.CharField(max_length=255, blank=True) 115 platform = models.CharField(max_length=255, blank=True)
113 signature = models.CharField(max_length=128, blank=True) 116 signature = models.CharField(max_length=128, blank=True)
diff --git a/djangopypi/views.py b/djangopypi/views.py
index 54d58dc..3c6d03d 100644
--- a/djangopypi/views.py
+++ b/djangopypi/views.py
@@ -30,19 +30,27 @@ POSSIBILITY OF SUCH DAMAGE.
30 30
31""" 31"""
32 32
33import os
34
35from django.conf import settings
33from django.http import Http404, HttpResponse, HttpResponseBadRequest 36from django.http import Http404, HttpResponse, HttpResponseBadRequest
34from django.http import QueryDict, HttpResponseForbidden 37from django.http import QueryDict, HttpResponseForbidden
35from django.shortcuts import render_to_response 38from django.shortcuts import render_to_response
36from djangopypi.models import Project 39from djangopypi.models import Project, Classifier, Release, UPLOAD_TO
37from djangopypi.forms import ProjectRegisterForm 40from djangopypi.forms import ProjectForm, ReleaseForm
38from django.template import RequestContext 41from django.template import RequestContext
39from django.utils.datastructures import MultiValueDict 42from django.utils.datastructures import MultiValueDict
43from django.utils.translation import ugettext_lazy as _
40from django.core.files.uploadedfile import SimpleUploadedFile 44from django.core.files.uploadedfile import SimpleUploadedFile
41from django.contrib.auth import authenticate, login 45from django.contrib.auth import authenticate, login
42from djangopypi.http import HttpResponseNotImplemented 46from djangopypi.http import HttpResponseNotImplemented
43from djangopypi.http import HttpResponseUnauthorized 47from djangopypi.http import HttpResponseUnauthorized
44 48
45 49
50ALREADY_EXISTS_FMT = _("""A file named "%s" already exists for %s. To fix """
51 + "problems with that you should create a new release.")
52
53
46def parse_weird_post_data(raw_post_data): 54def parse_weird_post_data(raw_post_data):
47 """ For some reason Django can't parse the HTTP POST data 55 """ For some reason Django can't parse the HTTP POST data
48 sent by ``distutils`` register/upload commands. 56 sent by ``distutils`` register/upload commands.
@@ -74,7 +82,7 @@ def parse_weird_post_data(raw_post_data):
74 if "filename" in headers: 82 if "filename" in headers:
75 file = SimpleUploadedFile(headers["filename"], content, 83 file = SimpleUploadedFile(headers["filename"], content,
76 content_type="application/gzip") 84 content_type="application/gzip")
77 files[headers["name"]] = file 85 files["distribution"] = [file]
78 elif headers["name"] in post_data: 86 elif headers["name"] in post_data:
79 post_data[headers["name"]].append(content) 87 post_data[headers["name"]].append(content)
80 else: 88 else:
@@ -85,7 +93,7 @@ def parse_weird_post_data(raw_post_data):
85 else: 93 else:
86 post_data[headers["name"]] = [content] 94 post_data[headers["name"]] = [content]
87 95
88 return MultiValueDict(post_data), files 96 return MultiValueDict(post_data), MultiValueDict(files)
89 97
90 98
91def login_basic_auth(request): 99def login_basic_auth(request):
@@ -100,30 +108,76 @@ def login_basic_auth(request):
100 return authenticate(username=username, password=password) 108 return authenticate(username=username, password=password)
101 109
102 110
111def submit_project_or_release(user, post_data, files):
112 """Registers/updates a project or release"""
113 try:
114 project = Project.objects.get(name=post_data['name'])
115 if project.owner != user:
116 return HttpResponseForbidden(
117 "That project is owned by someone else!")
118 except Project.DoesNotExist:
119 project = None
120
121 project_form = ProjectForm(post_data, instance=project)
122 if project_form.is_valid():
123 project = project_form.save(commit=False)
124 project.owner = user
125 project.save()
126 for c in post_data.getlist('classifiers'):
127 classifier, created = Classifier.objects.get_or_create(name=c)
128 project.classifiers.add(classifier)
129 if files:
130 allow_overwrite = getattr(settings,
131 "DJANGOPYPI_ALLOW_VERSION_OVERWRITE", False)
132 try:
133 release = Release.objects.get(version=post_data['version'],
134 project=project,
135 distribution=UPLOAD_TO + '/' +
136 files['distribution']._name)
137 if not allow_overwrite:
138 return HttpResponseForbidden(ALREADY_EXISTS_FMT % (
139 release.filename, release))
140 except Release.DoesNotExist:
141 release = None
142
143 # If the old file already exists, django will append a _ after the
144 # filename, however with .tar.gz files django does the "wrong"
145 # thing and saves it as project-0.1.2.tar_.gz. So remove it before
146 # django sees anything.
147 release_form = ReleaseForm(post_data, files, instance=release)
148 if release_form.is_valid():
149 if release and os.path.exists(release.distribution.path):
150 os.remove(release.distribution.path)
151 release = release_form.save(commit=False)
152 release.project = project
153 release.save()
154 else:
155 return HttpResponseBadRequest(
156 "ERRORS: %s" % release_form.errors)
157 else:
158 return HttpResponseBadRequest("ERRORS: %s" % project_form.errors)
159
160 return HttpResponse()
161
162
103def simple(request, template_name="djangopypi/simple.html"): 163def simple(request, template_name="djangopypi/simple.html"):
104 if request.method == "POST": 164 if request.method == "POST":
105 user = login_basic_auth(request)
106 if not user:
107 return HttpResponseUnauthorized('PyPI')
108 login(request, user)
109 if not request.user.is_authenticated():
110 return HttpResponseForbidden(
111 "Not logged in, or invalid username/password.")
112 post_data, files = parse_weird_post_data(request.raw_post_data) 165 post_data, files = parse_weird_post_data(request.raw_post_data)
113 action = post_data.get(":action") 166 action = post_data.get(":action")
114 classifiers = post_data.getlist("classifiers") 167 if action == 'file_upload':
115 register_form = ProjectRegisterForm(post_data.copy()) 168 user = login_basic_auth(request)
116 if register_form.is_valid(): 169 if not user:
117 try: 170 return HttpResponseUnauthorized('PyPI')
118 register_form.save(classifiers, request.user, 171
119 file=files.get("content")) 172 login(request, user)
120 except register_form.PermissionDeniedError, e: 173 if not request.user.is_authenticated():
121 return HttpResonseForbidden( 174 return HttpResponseForbidden(
122 "That project is owned by someone else!") 175 "Not logged in, or invalid username/password.")
123 except register_form.AlreadyExistsError, e: 176
124 return HttpResponseForbidden(e) 177 return submit_project_or_release(user, post_data, files)
125 return HttpResponse("Successfully registered.") 178
126 return HttpResponse("ERRORS: %s" % register_form.errors) 179 return HttpResponseNotImplemented(
180 "The :action %s is not implemented" % action)
127 181
128 dists = Project.objects.all().order_by("name") 182 dists = Project.objects.all().order_by("name")
129 context = RequestContext(request, { 183 context = RequestContext(request, {