Commits

Matthew Marshall committed 98330b1

Front page forms now function (mostly) correct.

  • Participants
  • Parent commits 66c0113

Comments (0)

Files changed (7)

File default_settings.py

     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.sites',
+    'django.contrib.admin',
     'freehg.repos',
 )

File repos/forms.py

+from django import newforms as forms
+
+import re
+
+from freehg.repos.models import Repo
+from django.contrib.auth.models import User
+from django.contrib.auth import authenticate
+
+required_dict = {'class': 'required'}
+username_re = re.compile(r'^\w+$')
+
+class NewRepoForm(forms.Form):
+    user = None
+    reponame = forms.CharField(max_length=30,
+            widget=forms.TextInput(attrs=required_dict))
+    long_name = forms.CharField(max_length=50, required=False)
+    description = forms.CharField(max_length=5000, required=False)
+
+    def clean_reponame(self):
+        reponame = self.cleaned_data.get('reponame', None)
+        if reponame:
+            if not re.search(r'^\w+$', reponame):
+                msg = (u'Repository names can only contain letters, ' +
+                        u'numbers and underscores')
+                raise forms.ValidationError(msg)
+            if self.user:
+                try:
+                    repo = self.user.repo_set.get(name__exact=reponame)
+                except Repo.DoesNotExist:
+                    return reponame
+                raise forms.ValidationError(
+                        u'You already have a repository with this name.')
+
+    def create_repo(self):
+        """
+        Creates a new repository, but doesn't save it.
+
+        This method assumes that self.user is a valid user.
+        """
+        return self.user.repo_set.create(
+                name=self.cleaned_data['reponame'],
+                long_name=self.cleaned_data['long_name'],
+                description=self.cleaned_data['description'])
+
+class NewAccountForm(forms.Form):
+    username = forms.CharField(max_length=30,
+                               widget=forms.TextInput(attrs=required_dict),
+                               label=u'Username')
+    password1 = forms.CharField(widget=forms.PasswordInput(attrs=required_dict),
+                                label=u'Password')
+    password2 = forms.CharField(widget=forms.PasswordInput(attrs=required_dict),
+                                label=u'Password (again, to catch typos)')
+    tos = forms.BooleanField(widget=forms.CheckboxInput(attrs=required_dict),
+                        label=u'I have read and agree to the Terms of Service')
+
+    def clean_username(self):
+        """
+        Validates that the username is alphanumeric and is not already
+        in use.
+        
+        """
+        if 'username' in self.cleaned_data:
+            if not username_re.search(self.cleaned_data['username']):
+                msg = (u'Usernames can only contain letters, ' +
+                        u'numbers and underscores')
+                raise forms.ValidationError(msg)
+            try:
+                user = User.objects.get(
+                        username__exact=self.cleaned_data['username'])
+            except User.DoesNotExist:
+                return self.cleaned_data['username']
+            raise forms.ValidationError(u'This username is already taken. ' +
+                    u'Please choose another.')
+
+    def clean_password2(self):
+        """
+        Validates that the two password inputs match.
+        
+        """
+        if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data and \
+           self.cleaned_data['password1'] == self.cleaned_data['password2']:
+            return self.cleaned_data['password2']
+        raise forms.ValidationError(u'You must type the same password each time')
+    
+    def clean_tos(self):
+        """
+        Validates that the user accepted the Terms of Service.
+        
+        """
+        if self.cleaned_data.get('tos', False):
+            return self.cleaned_data['tos']
+        raise forms.ValidationError(u'You must agree to the terms to register')
+
+
+class LoginForm(forms.Form):
+    username = forms.CharField(max_length=30,
+                               widget=forms.TextInput(attrs=required_dict),
+                               label=u'Username')
+    password = forms.CharField(widget=forms.PasswordInput(attrs=required_dict),
+                                label=u'Password')
+
+    def clean(self):
+        print self._errors
+        if not self._errors:
+            self.user = authenticate(username=self.cleaned_data['username'],
+                    password=self.cleaned_data['password'])
+            if not self.user:
+                raise forms.ValidationError(u'Invalid username and password.')
+            elif not self.user.is_active:
+                raise forms.ValidationError(u'Your account has been disabled.')
+            else:
+                return self.cleaned_data['username']
+        return self.cleaned_data

File repos/models.py

 from django.db import models
+from django.contrib.auth.models import User
+from django.conf import settings
+from django.dispatch import dispatcher
 
-# Create your models here.
+import os.path
+import shutil
+
+from mercurial import hg, ui
+
+class Repo(models.Model):
+    # 'name' is the name used in the url and filesystem.
+    name = models.CharField(max_length=30)
+
+    long_name = models.CharField(max_length=50, blank=True)
+    description = models.TextField(max_length=5000, blank=True)
+
+    owner = models.ForeignKey(User)
+    allow_push = models.ManyToManyField(User, related_name="allow_push_set",
+            blank=True)
+
+    class Admin:
+        list_display = ("name", "owner")
+        search_fields = ("name", "owner__username")
+
+    class Meta:
+        unique_together = (("name", "owner"),)
+
+    @property
+    def file_path(self):
+        return settings.REPO_PATH+'/'+self.owner.username+"/"+self.name
+
+    @property
+    def hgrc_filename(self):
+        return self.file_path + "/.hg/hgrc"
+
+    def get_absolute_url(self):
+        return "/~%s/%s/" % (self.owner.username, self.name)
+
+    @property
+    def manage_url(self):
+        return "/repos/manage/%s/%s/" % (self.owner.username, self.name)
+
+    def __str__(self):
+        return "%s/%s" % (self.owner.username, self.name)
+
+    def __repr__(self):
+        return "<Repo %s %s>" % (self.owner.username, self.name)
+
+    def write_hgrc(self):
+        assert(os.path.exists(self.file_path+"/.hg"))
+        f = open(self.hgrc_filename, 'w')
+        f.write("[web]\n")
+        f.write("push_ssl = false\n")
+        f.write("allow_push = %s\n" % self.owner.username)
+        f.close()
+
+def save_repo(instance):
+    repo = instance
+    if not os.path.exists(repo.file_path):
+        os.makedirs(repo.file_path)
+        hg.repository(ui.ui(), repo.file_path, create=True)
+    repo.write_hgrc()
+    return True
+dispatcher.connect(save_repo, signal=models.signals.post_save, sender=Repo)
+
+def delete_repo(instance):
+    repo = instance
+    if os.path.exists(repo.file_path):
+        shutil.rmtree(repo.file_path)
+        return True
+dispatcher.connect(delete_repo, signal=models.signals.post_delete, sender=Repo)

File repos/views.py

-# Create your views here.
+from freehg.repos.models import Repo
+from django.contrib.auth.models import User
+from django.shortcuts import get_object_or_404, render_to_response
+from django.template import RequestContext
+from django.contrib.auth import login, authenticate
+from django.http import HttpResponseRedirect
+
+from freehg.repos.forms import NewRepoForm, NewAccountForm, LoginForm
+
+def frontpage(request):
+    if request.POST.get('reponame', False):
+        repo_form = NewRepoForm(request.POST)
+    else:
+        repo_form = NewRepoForm()
+
+    if request.user.is_authenticated():
+        repo_form.user = request.user
+        new_account_form = login_form = None
+    else:
+        if 'newaccount' in request.POST:
+            new_account_form = NewAccountForm(request.POST, prefix='new')
+            if new_account_form.is_valid():
+                user = User.objects.create_user(
+                        new_account_form.cleaned_data['username'],
+                        '',
+                        new_account_form.cleaned_data['password1'])
+                user.save()
+                user = authenticate(
+                        username=new_account_form.cleaned_data['username'],
+                        password=new_account_form.cleaned_data['password1'])
+                login(request, user)
+                user.message_set.create(message=
+                        "Your account has been created. Welcome to FreeHG.org!")
+                repo_form.user = user
+        else:
+            new_account_form = NewAccountForm(prefix='new')
+        if 'login' in request.POST:
+            login_form = LoginForm(request.POST)
+            if login_form.is_valid():
+                user = login_form.user
+                login(request, user)
+                user.message_set.create(message="You have been logged in.")
+                repo_form.user = user
+        else:
+            login_form = LoginForm()
+
+    if repo_form.user and repo_form.is_bound and repo_form.is_valid():
+        repo = repo_form.create_repo()
+        repo.save()
+        request.user.message_set.create(message=
+                "Repository '%s' created." % repo.name)
+        return HttpResponseRedirect('/')
+
+    return render_to_response('frontpage.html',
+        dict(
+            repo_form=repo_form,
+            new_account_form=new_account_form,
+            login_form=login_form,
+        ), context_instance=RequestContext(request)
+    )

File templates/base.html

+<html>
+<head>
+<title>{% block title %}{% endblock %} - FreeHG.org</title>
+</head>
+<body>
+
+    {% if messages %}
+    <ul id="usermessages">
+        {% for message in messages %}
+        <li>{{ message }}</li>
+        {% endfor %}
+    </ul>
+    {% endif %}
+    
+{% block content %}
+
+{% endblock %}
+
+</body>
+</html>

File templates/frontpage.html

+{% extends "base.html" %}
+
+{% block title %}Easy Mercurial Hosting{% endblock %}
+
+{% block content %}
+
+<form action='.' method='POST'>
+<div>
+    <table>
+    {{ repo_form }}
+    </table>
+</div>
+{% if user.is_authenticated %}
+    <input type='submit' name='createrepo' value='Create repository for {{user.username}}' />
+{% else %}
+    <div style="width:49%;float:left;">
+    <table>
+    {{ new_account_form }}
+    </table>
+    <input type='submit' name='newaccount'  value='Create new account' />
+    </div>
+
+    <div style="width:49%;float:right;">
+    <table>{{ login_form }}</table>
+    <input type='submit' name='login' value='Login' />
+    </div>
+{% endif %}
+</form>
+
+{% endblock %}
 
 urlpatterns = patterns('',
     # Example:
-    # (r'^freehg/', include('freehg.foo.urls')),
+    #(r'^freehg/', include('freehg.foo.urls')),
+    (r'^$', 'freehg.repos.views.frontpage'),
 
     # Uncomment this for admin:
-#     (r'^admin/', include('django.contrib.admin.urls')),
+    (r'^admin/', include('django.contrib.admin.urls')),
 )