From 73c4ebde29d9e43fe7fad98e4ee65cbd6ca68cc7 Mon Sep 17 00:00:00 2001 From: eric Date: Mon, 3 Oct 2011 12:36:04 -0400 Subject: [PATCH] allow username setting and tagline in profile started work on user profiles, with "tagline" field the first a user signs in this google, they are redirected to a page where they can set their username --- core/migrations/0012_auto__add_userprofile.py | 131 ++++++++++++++++++ core/models.py | 3 + frontend/forms.py | 38 +++++ frontend/templates/base.html | 10 +- .../templates/profiles/create_profile.html | 15 ++ frontend/templates/profiles/edit_profile.html | 16 +++ .../templates/profiles/profile_detail.html | 13 ++ frontend/templates/profiles/profile_list.html | 9 ++ .../registration/user_change_form.html | 19 +++ frontend/views.py | 21 +++ settings/common.py | 5 + urls.py | 4 + 12 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 core/migrations/0012_auto__add_userprofile.py create mode 100644 frontend/forms.py create mode 100644 frontend/templates/profiles/create_profile.html create mode 100644 frontend/templates/profiles/edit_profile.html create mode 100644 frontend/templates/profiles/profile_detail.html create mode 100644 frontend/templates/profiles/profile_list.html create mode 100644 frontend/templates/registration/user_change_form.html diff --git a/core/migrations/0012_auto__add_userprofile.py b/core/migrations/0012_auto__add_userprofile.py new file mode 100644 index 00000000..daf5a3e7 --- /dev/null +++ b/core/migrations/0012_auto__add_userprofile.py @@ -0,0 +1,131 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'UserProfile' + db.create_table('core_userprofile', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)), + ('tagline', self.gf('django.db.models.fields.CharField')(max_length=140, blank=True)), + )) + db.send_create_signal('core', ['UserProfile']) + + + def backwards(self, orm): + + # Deleting model 'UserProfile' + db.delete_table('core_userprofile') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'core.author': { + 'Meta': {'object_name': 'Author'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), + 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Work']"}) + }, + 'core.campaign': { + 'Meta': {'object_name': 'Campaign'}, + 'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'deadline': ('django.db.models.fields.DateTimeField', [], {}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '10000'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}), + 'target': ('django.db.models.fields.FloatField', [], {}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"}) + }, + 'core.edition': { + 'Meta': {'object_name': 'Edition'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}), + 'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}), + 'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), + 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"}) + }, + 'core.editioncover': { + 'Meta': {'object_name': 'EditionCover'}, + 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'covers'", 'to': "orm['core.Edition']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'openlibrary_id': ('django.db.models.fields.IntegerField', [], {}) + }, + 'core.subject': { + 'Meta': {'object_name': 'Subject'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"}) + }, + 'core.userprofile': { + 'Meta': {'object_name': 'UserProfile'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'}) + }, + 'core.wishlist': { + 'Meta': {'object_name': 'Wishlist'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}), + 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'to': "orm['core.Work']"}) + }, + 'core.work': { + 'Meta': {'object_name': 'Work'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}) + } + } + + complete_apps = ['core'] diff --git a/core/models.py b/core/models.py index 61044456..9b8525c4 100755 --- a/core/models.py +++ b/core/models.py @@ -85,5 +85,8 @@ class Wishlist(models.Model): user = models.OneToOneField(User, related_name='wishlist') works = models.ManyToManyField('Work', related_name='wishlists') +class UserProfile(models.Model): + user = models.ForeignKey(User, unique=True) + tagline = models.CharField(max_length=140, blank=True) from regluit.core import signals diff --git a/frontend/forms.py b/frontend/forms.py new file mode 100644 index 00000000..ef2484e1 --- /dev/null +++ b/frontend/forms.py @@ -0,0 +1,38 @@ +from django import forms +from django.db import models +#from django.forms import Form, ModelForm, Textarea, CharField, ValidationError, RegexField +from regluit.core.models import UserProfile +from django.contrib.auth.models import User +from django.utils.translation import ugettext_lazy as _ + +class ProfileForm(forms.ModelForm): + class Meta: + model = UserProfile + exclude = 'user' + widgets = { + 'tagline': forms.Textarea(attrs={'cols': 70, 'rows': 2}), + } + +class UserData(forms.Form): + username = forms.RegexField( + label=_("New Username"), + max_length=30, + regex=r'^[\w.@+-]+$', + help_text = _("30 characters or less."), + error_messages = { + 'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.") + } + ) + # oldusername = forms.CharField(max_length=30) + + + def clean_username(self): + username = self.data["username"] + oldusername = self.data["oldusername"] + if username != oldusername: + try: + User.objects.get(username=username) + except User.DoesNotExist: + return username + raise forms.ValidationError(_("Another user with that username already exists.")) + raise forms.ValidationError(_("Your username is already "+oldusername)) \ No newline at end of file diff --git a/frontend/templates/base.html b/frontend/templates/base.html index d1acd444..2475e4e0 100644 --- a/frontend/templates/base.html +++ b/frontend/templates/base.html @@ -1,6 +1,7 @@ {# raw url references raise test errors in tests for django registration; this is a workaround #} {% url privacy as privacyurl %} +{% url regluit.frontend.views.edit_user as editurl %} unglue.it {% block title %}{% endblock %} @@ -45,9 +46,12 @@ diff --git a/frontend/templates/profiles/create_profile.html b/frontend/templates/profiles/create_profile.html new file mode 100644 index 00000000..d06891f3 --- /dev/null +++ b/frontend/templates/profiles/create_profile.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block title %}Create Profile{% endblock %} + +{% block content %} +
+

Create a new profile for {{ user }}

+ +
+ {% csrf_token %} + {{ form }} + +
+
+{% endblock content %} \ No newline at end of file diff --git a/frontend/templates/profiles/edit_profile.html b/frontend/templates/profiles/edit_profile.html new file mode 100644 index 00000000..50f6bc3d --- /dev/null +++ b/frontend/templates/profiles/edit_profile.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} + +{% block title %}Edit Profile{% endblock %} + +{% block content %} +
+

Edit profile for {{ user }}

+ +
+ {% csrf_token %} + {{ form.as_p }} + +
+{{ debug }} +
+{% endblock content %} \ No newline at end of file diff --git a/frontend/templates/profiles/profile_detail.html b/frontend/templates/profiles/profile_detail.html new file mode 100644 index 00000000..a1b4f57a --- /dev/null +++ b/frontend/templates/profiles/profile_detail.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %}Edit Profile{% endblock %} + +{% block content %} +
+

Profile for {{ user }}

+ +

TagLine: {{ profile.tagline }}

+

Edit Again

+

{{user}}'s Unglue.it Page

+
+{% endblock content %} \ No newline at end of file diff --git a/frontend/templates/profiles/profile_list.html b/frontend/templates/profiles/profile_list.html new file mode 100644 index 00000000..175c4e9e --- /dev/null +++ b/frontend/templates/profiles/profile_list.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} + +{% block title %}Profile List{% endblock %} + +{% block content %} +
+Sorry, you can't list the profiles on this site. +
+{% endblock content %} \ No newline at end of file diff --git a/frontend/templates/registration/user_change_form.html b/frontend/templates/registration/user_change_form.html new file mode 100644 index 00000000..4523849f --- /dev/null +++ b/frontend/templates/registration/user_change_form.html @@ -0,0 +1,19 @@ +{% extends "registration/registration_base.html" %} +{% block title %}Change User Data{% endblock %} +{% block content %} +
+

Changing your Username.

+ +

If you change your Username, the web address for your profile page will change as well.

+ +

Your current Username: {{ user.username }}

+
+ {% csrf_token %} + {{ form.as_p }} + +
+

Edit Your Profile

+
+{% endblock %} + + diff --git a/frontend/views.py b/frontend/views.py index 568bb286..0244f03b 100755 --- a/frontend/views.py +++ b/frontend/views.py @@ -1,5 +1,6 @@ from django.template import RequestContext from django.contrib.auth.models import User +# from django.contrib.auth.forms import UserChangeForm from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.views.decorators.csrf import csrf_exempt @@ -10,6 +11,8 @@ from django.shortcuts import render, render_to_response, get_object_or_404 from regluit.core import models, bookloader from regluit.core.search import gluejar_search +from regluit.frontend.forms import UserData + def home(request): if request.user.is_authenticated(): return HttpResponseRedirect(reverse('supporter', @@ -25,6 +28,24 @@ def supporter(request, supporter_username): } return render(request, 'supporter.html', context) + +def edit_user(request): + form=UserData() + if not request.user.is_authenticated(): + return HttpResponseRedirect(reverse('auth_login')) + oldusername=request.user.username + if request.method == 'POST': + # surely there's a better way to add data to the POST data? + postcopy=request.POST.copy() + postcopy['oldusername']=oldusername + form = UserData(postcopy) + if form.is_valid(): # All validation rules pass, go and change the username + request.user.username=form.cleaned_data['username'] + request.user.save() + return HttpResponseRedirect(reverse('home')) # Redirect after POST + return render(request,'registration/user_change_form.html', {'form': form},) + + def search(request): q = request.GET.get('q', None) results = gluejar_search(q) diff --git a/settings/common.py b/settings/common.py index abb49079..65395ed8 100644 --- a/settings/common.py +++ b/settings/common.py @@ -107,6 +107,7 @@ INSTALLED_APPS = ( 'registration', 'social_auth', 'tastypie', + 'profiles', ) # A sample logging configuration. The only tangible logging @@ -169,6 +170,8 @@ AUTHENTICATION_BACKENDS = ( SOCIAL_AUTH_ENABLED_BACKENDS = ['google', 'facebook', 'twitter'] SOCIAL_AUTH_ASSOCIATE_BY_MAIL = True +SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/accounts/edit/' + FACEBOOK_EXTENDED_PERMISSIONS = ['email'] LOGIN_URL = "/accounts/login/" @@ -178,3 +181,5 @@ LOGOUT_URL = "/accounts/logout/" USER_AGENT = "unglue.it.bot v0.0.1 " SOUTH_TESTS_MIGRATE = False + +AUTH_PROFILE_MODULE = "core.userprofile" \ No newline at end of file diff --git a/urls.py b/urls.py index fefe5034..42d61ca9 100755 --- a/urls.py +++ b/urls.py @@ -1,11 +1,15 @@ from django.conf.urls.defaults import * +from frontend.forms import ProfileForm urlpatterns = patterns('', url(r'^accounts/activate/complete/$','django.contrib.auth.views.login', {'template_name': 'registration/activation_complete.html'}), + (r'^accounts/edit/$', 'regluit.frontend.views.edit_user'), (r'^accounts/', include('registration.backends.default.urls')), (r'^socialauth/', include('social_auth.urls')), (r'^api/', include('regluit.api.urls')), + ('^profiles/edit/$', 'profiles.views.edit_profile', {'form_class': ProfileForm,}), + (r'^profiles/', include('profiles.urls')), (r'', include('regluit.frontend.urls')), (r'', include('regluit.payment.urls')) )