@@ -11,7 +11,7 @@ class UserResource(ModelResource): | |||
class Meta: | |||
queryset = User.objects.all() | |||
resource_name = 'user' | |||
excludes = ['email', 'password', 'is_superuser', 'first_name', | |||
excludes = ['password', 'is_superuser', 'first_name', | |||
'last_name', 'is_active', 'is_staff', 'last_login', 'date_joined'] | |||
include_resource_uri = False | |||
@@ -0,0 +1,38 @@ | |||
from django import forms | |||
from django.utils.translation import ugettext, ugettext_lazy as _ | |||
from django.contrib.auth.models import User | |||
class UserCreationForm(forms.ModelForm): | |||
""" | |||
A form that creates a user, with no privileges, from the given username, | |||
email, and password. | |||
""" | |||
error_messages = { | |||
'duplicate_username': _("A user with that username already exists."), | |||
} | |||
username = forms.RegexField(label=_("Username"), max_length=30, | |||
regex=r'^[\w-]+$') | |||
password = forms.CharField(label=_("Password"), | |||
widget=forms.PasswordInput) | |||
class Meta: | |||
model = User | |||
fields = ("username", "email") | |||
def clean_username(self): | |||
# Since User.username is unique, this check is redundant, | |||
# but it sets a nicer error message than the ORM. See #13147. | |||
username = self.cleaned_data["username"] | |||
try: | |||
User._default_manager.get(username=username) | |||
except User.DoesNotExist: | |||
return username | |||
raise forms.ValidationError(self.error_messages['duplicate_username']) | |||
def save(self, commit=True): | |||
user = super(UserCreationForm, self).save(commit=False) | |||
user.set_password(self.cleaned_data["password"]) | |||
if commit: | |||
user.save() | |||
return user |
@@ -66,15 +66,6 @@ body { | |||
text-align: center; | |||
} | |||
.tags { | |||
padding: 13px 0; | |||
} | |||
.tag { | |||
cursor: pointer; | |||
} | |||
#pins { | |||
top: 70px; | |||
} | |||
@@ -83,14 +74,43 @@ body { | |||
background: #fff; | |||
width: 200px; | |||
box-shadow: 0 1px 3px #bbb; | |||
padding: 20px; | |||
-moz-box-shadow: 0 1px 3px #bbb; | |||
-webkit-box-shadow: 0 1px 3px #bbb; | |||
padding: 15px; | |||
position: absolute; | |||
} | |||
.pin .editable { | |||
border: 2px solid rgba(255, 255, 255, 0.4); | |||
background: rgba(255, 255, 255, 0.4); | |||
border-radius: 4px; | |||
-moz-border-radius: 4px; | |||
-webkit-border-radius: 4px; | |||
position: absolute; | |||
right: 23px; | |||
top: 23px; | |||
display: none; | |||
} | |||
.pin:hover .editable { | |||
display: block; | |||
} | |||
.pin .editable .borderable { | |||
padding: 7px 8px 5px; | |||
border-radius: 4px; | |||
-moz-border-radius: 4px; | |||
-webkit-border-radius: 4px; | |||
background: rgba(0, 0, 0, 0.8); | |||
cursor: pointer; | |||
} | |||
.pin img { | |||
width: 200px; | |||
padding: 0; | |||
margin: 0; | |||
cursor: -webkit-zoom-in; | |||
cursor: -moz-zoom-in; | |||
} | |||
.pin p { | |||
@@ -103,6 +123,36 @@ body { | |||
font-weight: normal; | |||
} | |||
.pin-footer { | |||
background-color: #eee; | |||
font-weight: bold; | |||
margin: 0 -15px -15px -15px; | |||
padding: 15px; | |||
margin-top: 15px; | |||
color: #777; | |||
font-size: 12px; | |||
cursor: default; | |||
} | |||
.pin-footer .dim { | |||
font-weight: normal; | |||
color: #999; | |||
} | |||
.pin-footer .avatar { | |||
width: 30px; | |||
height: 30px; | |||
background-color: #555; | |||
border-radius: 4px; | |||
-moz-border-radius: 4px; | |||
-webkit-border-radius: 4px; | |||
} | |||
.pin-footer .text { | |||
width: 155px; | |||
margin-top: -3px; | |||
} | |||
.pin-options { | |||
margin: 5px; | |||
display: none; | |||
@@ -11,7 +11,7 @@ $(window).load(function() { | |||
var blocks = blockContainer.children('.pin'); | |||
// Size of blocks/pins and the spacing between them | |||
var blockMargin = 20; | |||
var blockMargin = 15; | |||
var blockWidth = 240; | |||
// How many items we can fit in a row and our array for the row heights | |||
@@ -67,6 +67,10 @@ $(window).load(function() { | |||
// Fetch our pins from the api using our current offset | |||
$.get('/api/v1/pin/?format=json&offset='+String(offset), function(pins) { | |||
// Set which items are editable by the current user | |||
for (var i=0; i < pins.objects.length; i++) | |||
pins.objects[i].editable = (pins.objects[i].submitter.username == currentUser); | |||
// Use the fetched pins as our context for our pins template | |||
var template = Handlebars.compile($('#pins-template').html()); | |||
var html = template({pins: pins.objects}); | |||
@@ -51,8 +51,7 @@ | |||
{% compress js inline %} | |||
<script> | |||
var username = "{{ user.username }}"; | |||
var isSuperuser = {{ user.is_superuser|lower }}; | |||
var currentUser = "{{ user.username }}"; | |||
</script> | |||
{% endcompress %} | |||
@@ -3,10 +3,11 @@ from django.http import HttpResponseRedirect | |||
from django.core.urlresolvers import reverse | |||
from django.contrib.auth.decorators import login_required | |||
from django.contrib.auth import logout | |||
from django.contrib.auth.forms import UserCreationForm | |||
from django.contrib import messages | |||
from django.conf import settings | |||
from .forms import UserCreationForm | |||
def home(request): | |||
return HttpResponseRedirect(reverse('pins:recent-pins')) | |||
@@ -20,19 +20,29 @@ | |||
{{#each pins}} | |||
<div class="pin"> | |||
{{#if editable}} | |||
<i class="icon-white icon-pencil"></i> | |||
<div class="editable"> | |||
<div class="borderable"> | |||
<i class="icon-white icon-pencil"></i> | |||
</div> | |||
</div> | |||
{{/if}} | |||
<img src="{{thumbnail}}" /> | |||
{{#if description}} | |||
<p>{{description}}</p> | |||
{{/if}} | |||
{{#if tags}} | |||
<p> | |||
<div class="pin-footer clearfix"> | |||
<div class="avatar pull-left"> | |||
</div> | |||
<div class="text pull-right"> | |||
<span class="dim">pinned by</span> {{submitter.username}} | |||
{{#if tags}} | |||
<span class="dim">in</span> | |||
{{#each tags}} | |||
<span class="label">{{this}}</span> | |||
<span class="tag">{{this}}</span> | |||
{{/each}} | |||
</p> | |||
{{/if}} | |||
{{/if}} | |||
</div> | |||
</div> | |||
</div> | |||
{{/each}} | |||
</script> | |||