Genericize following. Users can follow any object type.

This commit is contained in:
Paul Osman 2010-10-21 17:01:58 -04:00
Родитель 824dca9be6
Коммит fa72d4dbff
9 изменённых файлов: 65 добавлений и 25 удалений

Просмотреть файл

@ -17,17 +17,13 @@ class DashboardTests(TestCase):
def test_unauthorized_request(self):
"""Unauthorized requests should get a signin template."""
response = self.client.get('/%s/' % (self.locale,))
# NOTE: because we are using jinja2, we can't use the
# assertTemplateUsed method, so we have check for the
# username element in the response body instead.
self.assertContains(response, 'id_username', status_code=200)
self.assertTemplateUsed(response, 'dashboard/splash.html')
def test_authorized_request(self):
"""Authorized requests should land on a personalized dashboard."""
self.client.login(username=self.test_username,
password=self.test_password)
response = self.client.get('/%s/' % (self.locale,))
self.assertContains(response, 'status_update', status_code=200)
self.assertTemplateUsed(response, 'dashboard/dashboard.html')

Просмотреть файл

@ -59,7 +59,7 @@ class TestLocaleURLs(TestCase):
user = User.objects.create_user(
'testuser', 'test@mozilla.com', 'testpass'
)
response = self.client.get('/de/')
response = self.client.get('/de/login/')
self.assertContains(response, 'csrfmiddlewaretoken')
response = self.client.post('/de/login/', {
'username': user.username,

Просмотреть файл

@ -1,5 +1,7 @@
import re
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
@ -8,11 +10,14 @@ from django.template import RequestContext
from projects.models import Project
from projects.forms import ProjectForm
def show(request, slug):
project = get_object_or_404(Project, slug=slug)
following = (request.user.is_authenticated() and
request.user.is_following(project) or False)
return render_to_response('projects/project.html', {
'project': project
'project': project,
'type': ContentType.objects.get_for_model(project),
'following': following,
}, context_instance=RequestContext(request))
def gallery(request):
@ -20,6 +25,7 @@ def gallery(request):
'projects': Project.objects.all()
}, context_instance=RequestContext(request))
@login_required
def create(request):
form = ProjectForm()
if request.method == 'POST':

Просмотреть файл

@ -18,12 +18,14 @@ class Relationship(models.Model):
target = generic.GenericForeignKey('target_content_type', 'target_object_id')
def save(self, *args, **kwargs):
if self.source.pk == self.target.pk:
if (self.source_content_type == self.target_content_type) and (
self.source.pk == self.target.pk):
raise ValidationError(_('Cannot create self referencing relationship.'))
super(Relationship, self).save(*args, **kwargs)
class Meta:
unique_together = (('source_object_id', 'target_object_id'),)
unique_together = ('source_content_type', 'target_content_type',
'source_object_id', 'target_object_id',)
def __unicode__(self):
return "%(from)s => %(to)s" % {
@ -41,8 +43,16 @@ def following(self):
source_object_id=self.id).filter(
source_content_type=ContentType.objects.get_for_model(self))]
def is_following(self, model):
obj_type_id = ContentType.objects.get_for_model(model)
return len(Relationship.objects.filter(
source_object_id=self.id,
target_object_id=model.pk,
target_content_type=obj_type_id)) > 0
User.followers = followers
User.following = following
User.is_following = is_following
def follow_handler(sender, **kwargs):
rel = kwargs.get('instance', None)

Просмотреть файл

@ -1,5 +1,6 @@
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect
from django.utils.translation import ugettext as _
@ -30,25 +31,33 @@ def followers(request):
@login_required
@require_http_methods(['POST'])
def follow(request):
if 'user' not in request.POST:
if 'object_id' not in request.POST or 'object_type_id' not in request.POST:
# todo - report error usefully
return HttpResponse("error")
user = User.objects.get(id=int(request.POST['user']))
rel = Relationship(source=request.user, target=user)
obj_type = ContentType.objects.get(id=int(request.POST['object_type_id']))
target = obj_type.get_object_for_this_type(id=int(request.POST['object_id']))
rel = Relationship(source=request.user, target=target)
rel.save()
# todo - redirect user to whatever page they were on before.
return HttpResponseRedirect(reverse('users_user_list'))
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
@require_http_methods(['POST'])
def unfollow(request):
if 'user' not in request.POST:
if 'object_id' not in request.POST or 'object_type_id' not in request.POST:
# todo - report error usefully
return HttpResponse("error")
user = User.objects.get(id=int(request.POST['user']))
obj_type = ContentType.objects.get(id=int(request.POST['object_type_id']))
target = obj_type.get_object_for_this_type(id=int(request.POST['object_id']))
rel = Relationship.objects.get(
source_object_id__exact=request.user.id,
target_object_id__exact=user.id)
target_object_id__exact=target.pk,
target_content_type__exact=obj_type)
rel.delete()
# todo - redirect user to whatever page they were on before.
return HttpResponseRedirect(reverse('users_user_list'))
return HttpResponseRedirect(request.META['HTTP_REFERER'])

Просмотреть файл

@ -3,6 +3,7 @@ from django.contrib import auth
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, Http404
from django.utils.translation import ugettext as _
@ -138,7 +139,8 @@ def user_list(request):
return render_to_response('users/user_list.html', {
'heading' : _('Users'),
'users' : users,
'following' : [user.id for user in request.user.following()]
'following' : [user.id for user in request.user.following()],
'type': ContentType.objects.get_for_model(request.user),
}, context_instance=RequestContext(request))
@anonymous_only

Просмотреть файл

@ -115,7 +115,7 @@ WELLKNOWN_HOSTMETA_HOSTS = ('localhost:8000',)
MOZILLA_AMCD_HREF = '/meta/amcd.json'
# Auth settings
LOGIN_URL = '/'
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
ACCOUNT_ACTIVATION_DAYS = 7

Просмотреть файл

@ -6,4 +6,19 @@
<p>
{{ project.description }}
</p>
{% if following %}
<form action="{% locale_url relationships_unfollow %}" method="post">
{% csrf_token %}
<input type="hidden" name="object_id" value="{{ project.id }}" />
<input type="hidden" name="object_type_id" value="{{ type.id }}" />
<input type="submit" value="{{ _('Unfollow') }}" />
</form>
{% else %}
<form action="{% locale_url relationships_follow %}" method="post">
{% csrf_token %}
<input type="hidden" name="object_id" value="{{ project.id }}" />
<input type="hidden" name="object_type_id" value="{{ type.id }}" />
<input type="submit" value="{{ _('Follow') }}" />
</form>
{% endif %}
{% endblock %}

Просмотреть файл

@ -16,13 +16,15 @@
{% if user.id in following %}
<form action="{% locale_url relationships_unfollow %}" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ user.id }}" />
<input type="hidden" name="object_type_id" value="{{ type.id }}" />
<input type="hidden" name="object_id" value="{{ user.id }}" />
<input type="submit" value="Unfollow" />
</form>
{% else %}
<form action="{% locale_url relationships_follow %}" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ user.id }}" />
<input type="hidden" name="object_type_id" value="{{ type.id }}" />
<input type="hidden" name="object_id" value="{{ user.id }}" />
<input type="submit" value="Follow" />
</form>
{% endif %}