Commit 08d8d2ed3e8269028ee23806e33dd35ce84fc60a
Exists in
master
and in
39 other branches
Merge branch 'master' of github.com:TracyWebTech/colab
Showing
6 changed files
with
127 additions
and
7 deletions
Show diff stats
src/accounts/forms.py
@@ -5,11 +5,24 @@ from django.contrib.auth import get_user_model | @@ -5,11 +5,24 @@ from django.contrib.auth import get_user_model | ||
5 | from django.utils.translation import ugettext_lazy as _ | 5 | from django.utils.translation import ugettext_lazy as _ |
6 | 6 | ||
7 | from super_archives.models import MailingList | 7 | from super_archives.models import MailingList |
8 | - | 8 | +from .utils.validators import validate_social_account |
9 | 9 | ||
10 | User = get_user_model() | 10 | User = get_user_model() |
11 | 11 | ||
12 | 12 | ||
13 | +class SocialAccountField(forms.Field): | ||
14 | + def __init__(self, *args, **kwargs): | ||
15 | + self.url = kwargs.pop('url', None) | ||
16 | + super(SocialAccountField, self).__init__(*args, **kwargs) | ||
17 | + | ||
18 | + def validate(self, value): | ||
19 | + super(SocialAccountField, self).validate(value) | ||
20 | + | ||
21 | + if value and not validate_social_account(value, self.url): | ||
22 | + raise forms.ValidationError(_('Social account does not exist'), | ||
23 | + code='social-account-doesnot-exist') | ||
24 | + | ||
25 | + | ||
13 | class UserForm(forms.ModelForm): | 26 | class UserForm(forms.ModelForm): |
14 | required = ('first_name', 'last_name', 'email', 'username') | 27 | required = ('first_name', 'last_name', 'email', 'username') |
15 | 28 | ||
@@ -34,12 +47,16 @@ class UserCreationForm(UserForm): | @@ -34,12 +47,16 @@ class UserCreationForm(UserForm): | ||
34 | 47 | ||
35 | 48 | ||
36 | class UserUpdateForm(UserForm): | 49 | class UserUpdateForm(UserForm): |
50 | + | ||
37 | class Meta: | 51 | class Meta: |
38 | model = User | 52 | model = User |
39 | fields = ('username', 'first_name', 'last_name', | 53 | fields = ('username', 'first_name', 'last_name', |
40 | 'institution', 'role', 'twitter', 'facebook', | 54 | 'institution', 'role', 'twitter', 'facebook', |
41 | 'google_talk', 'webpage') | 55 | 'google_talk', 'webpage') |
42 | 56 | ||
57 | + twitter = SocialAccountField(url='https://twitter.com/', required=False) | ||
58 | + facebook = SocialAccountField(url='https://graph.facebook.com/', required=False) | ||
59 | + | ||
43 | 60 | ||
44 | class ListsForm(forms.Form): | 61 | class ListsForm(forms.Form): |
45 | LISTS_NAMES = ((list.name, list.name) for list in MailingList.objects.all()) | 62 | LISTS_NAMES = ((list.name, list.name) for list in MailingList.objects.all()) |
src/accounts/migrations/0005_remove_host_from_social_accounts.py
0 → 100644
@@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +import datetime | ||
3 | +from south.db import db | ||
4 | +from south.v2 import DataMigration | ||
5 | +from django.db import models | ||
6 | + | ||
7 | +class Migration(DataMigration): | ||
8 | + | ||
9 | + def forwards(self, orm): | ||
10 | + for user in orm.User.objects.iterator(): | ||
11 | + if user.twitter: | ||
12 | + user.twitter = user.twitter.split('/')[-1] | ||
13 | + if user.facebook: | ||
14 | + user.facebook = user.facebook.split('/')[-1] | ||
15 | + user.save() | ||
16 | + | ||
17 | + def backwards(self, orm): | ||
18 | + "Write your backwards methods here." | ||
19 | + | ||
20 | + models = { | ||
21 | + u'accounts.user': { | ||
22 | + 'Meta': {'object_name': 'User'}, | ||
23 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
24 | + 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
25 | + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
26 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
27 | + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), | ||
28 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
29 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
30 | + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
31 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
32 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
33 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
34 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
35 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
36 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
37 | + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
38 | + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
39 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
40 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), | ||
41 | + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), | ||
42 | + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}) | ||
43 | + }, | ||
44 | + u'auth.group': { | ||
45 | + 'Meta': {'object_name': 'Group'}, | ||
46 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
47 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
48 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
49 | + }, | ||
50 | + u'auth.permission': { | ||
51 | + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
52 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
53 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
54 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
55 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
56 | + }, | ||
57 | + u'contenttypes.contenttype': { | ||
58 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
59 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
60 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
61 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
62 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
66 | + complete_apps = ['accounts'] | ||
67 | + symmetrical = True |
src/accounts/models.py
1 | 1 | ||
2 | +import urlparse | ||
3 | + | ||
2 | from django.db import models | 4 | from django.db import models |
3 | from django.contrib.auth.models import AbstractUser | 5 | from django.contrib.auth.models import AbstractUser |
4 | - | ||
5 | from django.core.urlresolvers import reverse | 6 | from django.core.urlresolvers import reverse |
6 | 7 | ||
7 | 8 | ||
@@ -17,6 +18,12 @@ class User(AbstractUser): | @@ -17,6 +18,12 @@ class User(AbstractUser): | ||
17 | def get_absolute_url(self): | 18 | def get_absolute_url(self): |
18 | return reverse('user_profile', kwargs={'username': self.username}) | 19 | return reverse('user_profile', kwargs={'username': self.username}) |
19 | 20 | ||
21 | + def twitter_link(self): | ||
22 | + return urlparse.urljoin('https://twitter.com', self.twitter) | ||
23 | + | ||
24 | + def facebook_link(self): | ||
25 | + return urlparse.urljoin('https://www.facebook.com', self.facebook) | ||
26 | + | ||
20 | # We need to have `email` field set as unique but Django does not | 27 | # We need to have `email` field set as unique but Django does not |
21 | # support field overriding (at least not until 1.6). | 28 | # support field overriding (at least not until 1.6). |
22 | # The following workaroud allows to change email field to unique | 29 | # The following workaroud allows to change email field to unique |
src/accounts/templates/accounts/user_detail.html
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | {% block main-content %} | 9 | {% block main-content %} |
10 | 10 | ||
11 | <div id="user-profile" class="row"> | 11 | <div id="user-profile" class="row"> |
12 | - <div class="vcard col-lg-3 col-md-3 col-sm-4"> | 12 | + <div class="vcard col-lg-4 col-md-4 col-sm-4"> |
13 | <div class="thumbnail"> | 13 | <div class="thumbnail"> |
14 | {% gravatar user_.email 200 %} | 14 | {% gravatar user_.email 200 %} |
15 | </div> | 15 | </div> |
@@ -43,23 +43,26 @@ | @@ -43,23 +43,26 @@ | ||
43 | </li> | 43 | </li> |
44 | {% endif %} | 44 | {% endif %} |
45 | {% if request.user.is_active %} | 45 | {% if request.user.is_active %} |
46 | + <li> | ||
46 | {% if user_.twitter %} | 47 | {% if user_.twitter %} |
47 | - <li><span class="icon-twitter icon-fixed-width"></span> {{ user_.twitter }}</li> | 48 | + <span class="icon-twitter icon-fixed-width"></span> <a target="_blank" href="{{ user_.twitter_link }}" title="{% trans 'Twitter account' %}">{{ user_.twitter }}</a> |
48 | {% endif %} | 49 | {% endif %} |
49 | {% if user_.facebook %} | 50 | {% if user_.facebook %} |
50 | - <li><span class="icon-facebook icon-fixed-width"></span> {{ user_.facebook }}</li> | 51 | + <span class="icon-facebook icon-fixed-width"></span> <a target="_blank" href="{{ user_.facebook_link }}" title="{% trans 'Facebook account' %}">{{ user_.facebook }}</a> |
51 | {% endif %} | 52 | {% endif %} |
53 | + </li> | ||
54 | + | ||
52 | {% if user_.google_talk %} | 55 | {% if user_.google_talk %} |
53 | <li><span class="icon-google-plus icon-fixed-width"></span> {{ user_.google_talk }}</li> | 56 | <li><span class="icon-google-plus icon-fixed-width"></span> {{ user_.google_talk }}</li> |
54 | {% endif %} | 57 | {% endif %} |
55 | {% if user_.webpage %} | 58 | {% if user_.webpage %} |
56 | - <li><span class="icon-link icon-fixed-width"></span> {{ user_.webpage }}</li> | 59 | + <li><span class="icon-link icon-fixed-width"></span> <a target="_blank" href="{{ user_.webpage }}" title="{% trans 'Personal webpage' %}">{{ user_.webpage }}</a></li> |
57 | {% endif %} | 60 | {% endif %} |
58 | {% endif %} | 61 | {% endif %} |
59 | </ul> | 62 | </ul> |
60 | </div> | 63 | </div> |
61 | 64 | ||
62 | - <div class="col-lg-5 col-md-5 col-sm-8"> | 65 | + <div class="col-lg-4 col-md-4 col-sm-8"> |
63 | <div class="panel panel-default"> | 66 | <div class="panel panel-default"> |
64 | <div class="panel-heading"> | 67 | <div class="panel-heading"> |
65 | <h3 class="panel-title">{% trans "Contributions by Area" %}</h3> | 68 | <h3 class="panel-title">{% trans "Contributions by Area" %}</h3> |
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | + | ||
2 | +import urllib2 | ||
3 | +import urlparse | ||
4 | + | ||
5 | + | ||
6 | +def validate_social_account(account, url): | ||
7 | + """Verifies if a social account is valid. | ||
8 | + | ||
9 | + Examples: | ||
10 | + | ||
11 | + >>> validate_social_account('seocam', 'http://twitter.com') | ||
12 | + True | ||
13 | + | ||
14 | + >>> validate_social_account('seocam-fake-should-fail', 'http://twitter.com') | ||
15 | + False | ||
16 | + """ | ||
17 | + | ||
18 | + request = urllib2.Request(urlparse.urljoin(url, account)) | ||
19 | + request.get_method = lambda: 'HEAD' | ||
20 | + | ||
21 | + try: | ||
22 | + response = urllib2.urlopen(request) | ||
23 | + except urllib2.HTTPError: | ||
24 | + return False | ||
25 | + | ||
26 | + return response.code == 200 |