Revision 8316698a
b/snf-astakos-app/README | ||
---|---|---|
70 | 70 |
(see: http://code.google.com/intl/el-GR/apis/recaptcha/docs/customization.html) |
71 | 71 |
ASTAKOS_LOGOUT_NEXT Where the user should be redirected after logout |
72 | 72 |
(if not set and no next parameter is defined it renders login page with message) |
73 |
ASTAKOS_RE_USER_EMAIL_PATTERNS [] Email patterns that are automatically activated ex. ['^[a-zA-Z0-9\._-]+@grnet\.gr$'] |
|
73 | 74 |
============================== ============================================================================= =========================================================================================== |
74 | 75 |
|
75 | 76 |
Administrator functions |
b/snf-astakos-app/astakos/im/backends.py | ||
---|---|---|
48 | 48 |
from astakos.im.models import AstakosUser, Invitation |
49 | 49 |
from astakos.im.forms import * |
50 | 50 |
from astakos.im.util import get_invitation |
51 |
from astakos.im.settings import INVITATIONS_ENABLED, DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, MODERATION_ENABLED, SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL |
|
51 |
from astakos.im.settings import INVITATIONS_ENABLED, DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, MODERATION_ENABLED, SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL, RE_USER_EMAIL_PATTERNS
|
|
52 | 52 |
|
53 | 53 |
import socket |
54 | 54 |
import logging |
55 |
import re |
|
55 | 56 |
|
56 | 57 |
logger = logging.getLogger(__name__) |
57 | 58 |
|
... | ... | |
78 | 79 |
raise ImproperlyConfigured('Module "%s" does not define a registration backend named "%s"' % (module, attr)) |
79 | 80 |
return backend_class(request) |
80 | 81 |
|
81 |
class InvitationsBackend(object): |
|
82 |
class SignupBackend(object): |
|
83 |
def _is_preaccepted(self, user): |
|
84 |
# return True if user email matches specific patterns |
|
85 |
for pattern in RE_USER_EMAIL_PATTERNS: |
|
86 |
if re.match(pattern, user.email): |
|
87 |
return True |
|
88 |
return False |
|
89 |
|
|
90 |
class InvitationsBackend(SignupBackend): |
|
82 | 91 |
""" |
83 | 92 |
A registration backend which implements the following workflow: a user |
84 | 93 |
supplies the necessary registation information, if the request contains a valid |
... | ... | |
93 | 102 |
""" |
94 | 103 |
self.request = request |
95 | 104 |
self.invitation = get_invitation(request) |
105 |
super(InvitationsBackend, self).__init__() |
|
96 | 106 |
|
97 | 107 |
def get_signup_form(self, provider): |
98 | 108 |
""" |
... | ... | |
136 | 146 |
If there is a valid, not-consumed invitation code for the specific user |
137 | 147 |
returns True else returns False. |
138 | 148 |
""" |
149 |
if super(InvitationsBackend, self)._is_preaccepted(user): |
|
150 |
return True |
|
139 | 151 |
invitation = self.invitation |
140 | 152 |
if not invitation: |
141 | 153 |
return False |
... | ... | |
145 | 157 |
return False |
146 | 158 |
|
147 | 159 |
@transaction.commit_manually |
148 |
def signup(self, form, admin_email_template_name='im/admin_notification.txt'): |
|
160 |
def signup(self, form, email_template_name='im/activation_email.txt', admin_email_template_name='im/admin_notification.txt'):
|
|
149 | 161 |
""" |
150 | 162 |
Initially creates an inactive user account. If the user is preaccepted |
151 | 163 |
(has a valid invitation code) the user is activated and if the request |
... | ... | |
159 | 171 |
try: |
160 | 172 |
user = form.save() |
161 | 173 |
if self._is_preaccepted(user): |
162 |
user.is_active = True |
|
163 |
user.save() |
|
164 |
message = _('Registration completed. You can now login.') |
|
174 |
if user.email_verified: |
|
175 |
user.is_active = True |
|
176 |
user.save() |
|
177 |
message = _('Registration completed. You can now login.') |
|
178 |
else: |
|
179 |
try: |
|
180 |
_send_verification(self.request, user, email_template_name) |
|
181 |
message = _('Verification sent to %s' % user.email) |
|
182 |
except (SMTPException, socket.error) as e: |
|
183 |
status = messages.ERROR |
|
184 |
name = 'strerror' |
|
185 |
message = getattr(e, name) if hasattr(e, name) else e |
|
165 | 186 |
else: |
166 | 187 |
_send_notification(user, admin_email_template_name) |
167 | 188 |
message = _('Your request for an account was successfully sent \ |
... | ... | |
183 | 204 |
transaction.commit() |
184 | 205 |
return status, message, user |
185 | 206 |
|
186 |
class SimpleBackend(object):
|
|
207 |
class SimpleBackend(SignupBackend):
|
|
187 | 208 |
""" |
188 | 209 |
A registration backend which implements the following workflow: a user |
189 | 210 |
supplies the necessary registation information, an incative user account is |
... | ... | |
191 | 212 |
""" |
192 | 213 |
def __init__(self, request): |
193 | 214 |
self.request = request |
215 |
super(SimpleBackend, self).__init__() |
|
194 | 216 |
|
195 | 217 |
def get_signup_form(self, provider): |
196 | 218 |
""" |
... | ... | |
207 | 229 |
ip = self.request.META.get('REMOTE_ADDR', |
208 | 230 |
self.request.META.get('HTTP_X_REAL_IP', None)) |
209 | 231 |
return globals()[formclass](initial_data, ip=ip) |
210 |
|
|
232 |
|
|
233 |
def _is_preaccepted(self, user): |
|
234 |
if super(SimpleBackend, self)._is_preaccepted(user): |
|
235 |
return True |
|
236 |
if MODERATION_ENABLED: |
|
237 |
return False |
|
238 |
return True |
|
239 |
|
|
211 | 240 |
@transaction.commit_manually |
212 | 241 |
def signup(self, form, email_template_name='im/activation_email.txt', admin_email_template_name='im/admin_notification.txt'): |
213 | 242 |
""" |
... | ... | |
233 | 262 |
""" |
234 | 263 |
user = form.save() |
235 | 264 |
status = messages.SUCCESS |
236 |
if MODERATION_ENABLED:
|
|
265 |
if not self._is_preaccepted(user):
|
|
237 | 266 |
try: |
238 | 267 |
_send_notification(user, admin_email_template_name) |
239 | 268 |
message = _('Your request for an account was successfully sent \ |
b/snf-astakos-app/astakos/im/forms.py | ||
---|---|---|
54 | 54 |
""" |
55 | 55 |
Extends the built in UserCreationForm in several ways: |
56 | 56 |
|
57 |
* Adds email, first_name and last_name field.
|
|
57 |
* Adds email, first_name, last_name, recaptcha_challenge_field, recaptcha_response_field field.
|
|
58 | 58 |
* The username field isn't visible and it is assigned a generated id. |
59 | 59 |
* User created is not active. |
60 | 60 |
""" |
... | ... | |
134 | 134 |
""" |
135 | 135 |
super(InvitedLocalUserCreationForm, self).__init__(*args, **kwargs) |
136 | 136 |
self.fields.keyOrder = ['email', 'inviter', 'first_name', |
137 |
'last_name', 'password1', 'password2'] |
|
137 |
'last_name', 'password1', 'password2', |
|
138 |
'recaptcha_challenge_field', |
|
139 |
'recaptcha_response_field'] |
|
138 | 140 |
#set readonly form fields |
139 | 141 |
self.fields['inviter'].widget.attrs['readonly'] = True |
140 | 142 |
self.fields['email'].widget.attrs['readonly'] = True |
... | ... | |
144 | 146 |
user = super(InvitedLocalUserCreationForm, self).save(commit=False) |
145 | 147 |
level = user.invitation.inviter.level + 1 |
146 | 148 |
user.level = level |
147 |
user.invitations = INVITATIONS_PER_LEVEL[level] |
|
149 |
user.invitations = INVITATIONS_PER_LEVEL.get(level, 0) |
|
150 |
user.email_verified = True |
|
148 | 151 |
if commit: |
149 | 152 |
user.save() |
150 | 153 |
return user |
b/snf-astakos-app/astakos/im/management/commands/inviteuser.py | ||
---|---|---|
36 | 36 |
from smtplib import SMTPException |
37 | 37 |
|
38 | 38 |
from django.core.management.base import BaseCommand, CommandError |
39 |
from django.db.utils import IntegrityError |
|
39 | 40 |
|
40 | 41 |
from astakos.im.functions import invite |
41 | 42 |
|
... | ... | |
63 | 64 |
self.stdout.write("Invitation sent to '%s'\n" % (email,)) |
64 | 65 |
except (SMTPException, socket.error) as e: |
65 | 66 |
raise CommandError("Error sending the invitation") |
67 |
except IntegrityError, e: |
|
68 |
raise CommandError("There is already an invitation for %s" % (email,)) |
|
66 | 69 |
else: |
67 | 70 |
raise CommandError("No invitations left") |
b/snf-astakos-app/astakos/im/management/commands/modifyuser.py | ||
---|---|---|
47 | 47 |
dest='invitations', |
48 | 48 |
metavar='NUM', |
49 | 49 |
help="Update user's invitations"), |
50 |
make_option('--level', |
|
51 |
dest='level', |
|
52 |
metavar='NUM', |
|
53 |
help="Update user's level"), |
|
50 | 54 |
make_option('--password', |
51 | 55 |
dest='password', |
52 | 56 |
metavar='PASSWORD', |
... | ... | |
100 | 104 |
if invitations is not None: |
101 | 105 |
user.invitations = int(invitations) |
102 | 106 |
|
107 |
level = options.get('level') |
|
108 |
if level is not None: |
|
109 |
user.level = int(level) |
|
110 |
|
|
103 | 111 |
password = options.get('password') |
104 | 112 |
if password is not None: |
105 | 113 |
user.set_password(password) |
b/snf-astakos-app/astakos/im/migrations/0003_auto__add_unique_invitation_username.py | ||
---|---|---|
1 |
# encoding: utf-8 |
|
2 |
import datetime |
|
3 |
from south.db import db |
|
4 |
from south.v2 import SchemaMigration |
|
5 |
from django.db import models |
|
6 |
|
|
7 |
class Migration(SchemaMigration): |
|
8 |
|
|
9 |
def forwards(self, orm): |
|
10 |
|
|
11 |
# Adding unique constraint on 'Invitation', fields ['username'] |
|
12 |
db.create_unique('im_invitation', ['username']) |
|
13 |
|
|
14 |
|
|
15 |
def backwards(self, orm): |
|
16 |
|
|
17 |
# Removing unique constraint on 'Invitation', fields ['username'] |
|
18 |
db.delete_unique('im_invitation', ['username']) |
|
19 |
|
|
20 |
|
|
21 |
models = { |
|
22 |
'auth.group': { |
|
23 |
'Meta': {'object_name': 'Group'}, |
|
24 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
25 |
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
|
26 |
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
|
27 |
}, |
|
28 |
'auth.permission': { |
|
29 |
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
|
30 |
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
31 |
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
|
32 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
33 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
|
34 |
}, |
|
35 |
'auth.user': { |
|
36 |
'Meta': {'object_name': 'User'}, |
|
37 |
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
|
38 |
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
|
39 |
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
40 |
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
|
41 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
42 |
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
|
43 |
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
44 |
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
45 |
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
|
46 |
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
47 |
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
|
48 |
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
|
49 |
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
|
50 |
}, |
|
51 |
'contenttypes.contenttype': { |
|
52 |
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
|
53 |
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
54 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
55 |
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
56 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
|
57 |
}, |
|
58 |
'im.astakosuser': { |
|
59 |
'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']}, |
|
60 |
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
|
61 |
'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), |
|
62 |
'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
63 |
'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
64 |
'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
65 |
'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
66 |
'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}), |
|
67 |
'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
|
68 |
'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
69 |
'updated': ('django.db.models.fields.DateTimeField', [], {}), |
|
70 |
'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}) |
|
71 |
}, |
|
72 |
'im.invitation': { |
|
73 |
'Meta': {'object_name': 'Invitation'}, |
|
74 |
'accepted': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
75 |
'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}), |
|
76 |
'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
77 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
78 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
79 |
'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}), |
|
80 |
'is_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
81 |
'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
82 |
'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
83 |
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) |
|
84 |
} |
|
85 |
} |
|
86 |
|
|
87 |
complete_apps = ['im'] |
b/snf-astakos-app/astakos/im/migrations/0004_auto__add_field_astakosuser_email_verified.py | ||
---|---|---|
1 |
# encoding: utf-8 |
|
2 |
import datetime |
|
3 |
from south.db import db |
|
4 |
from south.v2 import SchemaMigration |
|
5 |
from django.db import models |
|
6 |
|
|
7 |
class Migration(SchemaMigration): |
|
8 |
|
|
9 |
def forwards(self, orm): |
|
10 |
|
|
11 |
# Adding field 'AstakosUser.email_verified' |
|
12 |
db.add_column('im_astakosuser', 'email_verified', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) |
|
13 |
|
|
14 |
|
|
15 |
def backwards(self, orm): |
|
16 |
|
|
17 |
# Deleting field 'AstakosUser.email_verified' |
|
18 |
db.delete_column('im_astakosuser', 'email_verified') |
|
19 |
|
|
20 |
|
|
21 |
models = { |
|
22 |
'auth.group': { |
|
23 |
'Meta': {'object_name': 'Group'}, |
|
24 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
25 |
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
|
26 |
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
|
27 |
}, |
|
28 |
'auth.permission': { |
|
29 |
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
|
30 |
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
31 |
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
|
32 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
33 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
|
34 |
}, |
|
35 |
'auth.user': { |
|
36 |
'Meta': {'object_name': 'User'}, |
|
37 |
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
|
38 |
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
|
39 |
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
40 |
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
|
41 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
42 |
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
|
43 |
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
44 |
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
45 |
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
|
46 |
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
47 |
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
|
48 |
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
|
49 |
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
|
50 |
}, |
|
51 |
'contenttypes.contenttype': { |
|
52 |
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
|
53 |
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
54 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
55 |
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
56 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
|
57 |
}, |
|
58 |
'im.astakosuser': { |
|
59 |
'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']}, |
|
60 |
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
|
61 |
'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), |
|
62 |
'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
63 |
'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
64 |
'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
65 |
'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
66 |
'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
67 |
'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}), |
|
68 |
'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
|
69 |
'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
70 |
'updated': ('django.db.models.fields.DateTimeField', [], {}), |
|
71 |
'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}) |
|
72 |
}, |
|
73 |
'im.invitation': { |
|
74 |
'Meta': {'object_name': 'Invitation'}, |
|
75 |
'accepted': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
76 |
'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}), |
|
77 |
'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
78 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
79 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
80 |
'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}), |
|
81 |
'is_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
82 |
'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
83 |
'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
84 |
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) |
|
85 |
} |
|
86 |
} |
|
87 |
|
|
88 |
complete_apps = ['im'] |
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
56 | 56 |
#for invitations |
57 | 57 |
user_level = DEFAULT_USER_LEVEL |
58 | 58 |
level = models.IntegerField('Inviter level', default=user_level) |
59 |
invitations = models.IntegerField('Invitations left', default=INVITATIONS_PER_LEVEL[user_level])
|
|
59 |
invitations = models.IntegerField('Invitations left', default=INVITATIONS_PER_LEVEL.get(user_level, 0))
|
|
60 | 60 |
|
61 | 61 |
auth_token = models.CharField('Authentication Token', max_length=32, |
62 | 62 |
null=True, blank=True) |
... | ... | |
69 | 69 |
# ex. screen_name for twitter, eppn for shibboleth |
70 | 70 |
third_party_identifier = models.CharField('Third-party identifier', max_length=255, null=True, blank=True) |
71 | 71 |
|
72 |
email_verified = models.BooleanField('Email verified?', default=False) |
|
73 |
|
|
72 | 74 |
@property |
73 | 75 |
def realname(self): |
74 | 76 |
return '%s %s' %(self.first_name, self.last_name) |
... | ... | |
127 | 129 |
inviter = models.ForeignKey(AstakosUser, related_name='invitations_sent', |
128 | 130 |
null=True) |
129 | 131 |
realname = models.CharField('Real name', max_length=255) |
130 |
username = models.CharField('Unique ID', max_length=255) |
|
132 |
username = models.CharField('Unique ID', max_length=255, unique=True)
|
|
131 | 133 |
code = models.BigIntegerField('Invitation code', db_index=True) |
132 | 134 |
#obsolete: we keep it just for transfering the data |
133 | 135 |
is_accepted = models.BooleanField('Accepted?', default=False) |
b/snf-astakos-app/astakos/im/settings.py | ||
---|---|---|
61 | 61 |
# Set where the user should be redirected after logout |
62 | 62 |
LOGOUT_NEXT = getattr(settings, 'ASTAKOS_LOGOUT_NEXT', '') |
63 | 63 |
|
64 |
# Set user email patterns that are automatically activated |
|
65 |
RE_USER_EMAIL_PATTERNS = getattr(settings, 'ASTAKOS_RE_USER_EMAIL_PATTERNS', []) |
b/snf-astakos-app/astakos/im/util.py | ||
---|---|---|
75 | 75 |
'password':password, |
76 | 76 |
'affiliation':affiliation, |
77 | 77 |
'level':level, |
78 |
'invitations':INVITATIONS_PER_LEVEL[level],
|
|
78 |
'invitations':INVITATIONS_PER_LEVEL.get(level, 0),
|
|
79 | 79 |
'provider':provider, |
80 | 80 |
'realname':realname, |
81 | 81 |
'first_name':first_name, |
b/snf-astakos-app/astakos/im/views.py | ||
---|---|---|
50 | 50 |
from django.contrib.auth import logout as auth_logout |
51 | 51 |
from django.utils.http import urlencode |
52 | 52 |
from django.http import HttpResponseRedirect |
53 |
from django.db.utils import IntegrityError |
|
53 | 54 |
|
54 | 55 |
from astakos.im.models import AstakosUser, Invitation |
55 | 56 |
from astakos.im.backends import get_backend |
... | ... | |
177 | 178 |
status = messages.ERROR |
178 | 179 |
message = getattr(e, 'strerror', '') |
179 | 180 |
transaction.rollback() |
181 |
except IntegrityError, e: |
|
182 |
status = messages.ERROR |
|
183 |
message = _('There is already invitation for %s' % username) |
|
184 |
transaction.rollback() |
|
180 | 185 |
else: |
181 | 186 |
status = messages.ERROR |
182 | 187 |
message = _('No invitations left') |
... | ... | |
261 | 266 |
Upon successful user creation if ``next`` url parameter is present the user is redirected there |
262 | 267 |
otherwise renders the same page with a success message. |
263 | 268 |
|
264 |
On unsuccessful creation, renders the same page with an error message.
|
|
269 |
On unsuccessful creation, renders ``on_failure`` with an error message.
|
|
265 | 270 |
|
266 | 271 |
**Arguments** |
267 | 272 |
|
... | ... | |
405 | 410 |
return HttpResponseBadRequest('No such user') |
406 | 411 |
|
407 | 412 |
user.is_active = True |
413 |
user.email_verified = True |
|
408 | 414 |
user.save() |
409 | 415 |
return prepare_response(request, user, next, renew=True) |
Also available in: Unified diff