Revision ae497612
b/snf-astakos-app/astakos/im/activation_backends.py | ||
---|---|---|
41 | 41 |
from astakos.im.functions import (send_verification, send_activation, |
42 | 42 |
send_account_creation_notification, |
43 | 43 |
send_group_creation_notification, activate) |
44 |
from astakos.im.settings import INVITATIONS_ENABLED, MODERATION_ENABLED, SITENAME, RE_USER_EMAIL_PATTERNS |
|
44 |
from astakos.im.settings import (INVITATIONS_ENABLED, MODERATION_ENABLED, |
|
45 |
SITENAME, RE_USER_EMAIL_PATTERNS |
|
46 |
) |
|
47 |
from astakos.im.messages import as astakos_messages |
|
45 | 48 |
|
46 | 49 |
import logging |
47 | 50 |
import re |
... | ... | |
226 | 229 |
|
227 | 230 |
class VerificationSent(ActivationResult): |
228 | 231 |
def __init__(self): |
229 |
message = _('Verification sent.')
|
|
232 |
message = _(astakos_messages.VERIFICATION_SENT)
|
|
230 | 233 |
super(VerificationSent, self).__init__(message) |
231 | 234 |
|
232 | 235 |
|
233 | 236 |
class SwitchAccountsVerificationSent(ActivationResult): |
234 | 237 |
def __init__(self, email): |
235 |
message = _('This email is already associated with another \ |
|
236 |
local account. To change this account to a shibboleth \ |
|
237 |
one follow the link in the verification email sent \ |
|
238 |
to %s. Otherwise just ignore it.' % email) |
|
238 |
message = _(astakos_messages.SWITCH_ACCOUNT_LINK_SENT) |
|
239 | 239 |
super(SwitchAccountsVerificationSent, self).__init__(message) |
240 | 240 |
|
241 | 241 |
|
242 | 242 |
class NotificationSent(ActivationResult): |
243 | 243 |
def __init__(self): |
244 |
message = _('Your request for an account was successfully received and is now pending \ |
|
245 |
approval. You will be notified by email in the next few days. Thanks for \ |
|
246 |
your interest in ~okeanos! The GRNET team.') |
|
244 |
message = _(astakos_messages.NOTIFACATION_SENT) |
|
247 | 245 |
super(NotificationSent, self).__init__(message) |
248 | 246 |
|
249 | 247 |
|
250 | 248 |
class RegistationCompleted(ActivationResult): |
251 | 249 |
def __init__(self): |
252 |
message = _('Registration completed. You can now login.')
|
|
250 |
message = _(astakos_messages.REGISTRATION_COMPLETED)
|
|
253 | 251 |
super(RegistationCompleted, self).__init__(message) |
b/snf-astakos-app/astakos/im/endpoints/quotaholder.py | ||
---|---|---|
47 | 47 |
|
48 | 48 |
ENTITY_KEY = '1' |
49 | 49 |
|
50 |
inf = float('inf') |
|
51 |
|
|
50 | 52 |
logger = logging.getLogger(__name__) |
51 | 53 |
|
54 |
inf = float('inf') |
|
52 | 55 |
|
53 | 56 |
def call(func_name): |
54 | 57 |
"""Decorator function for QuotaholderHTTP client calls.""" |
... | ... | |
88 | 91 |
for resource, uplimit in user.quota.iteritems(): |
89 | 92 |
key = ENTITY_KEY |
90 | 93 |
quantity = None |
91 |
capacity = uplimit |
|
94 |
capacity = uplimit if uplimit != inf else None
|
|
92 | 95 |
import_limit = None |
93 | 96 |
export_limit = None |
94 | 97 |
flags = 0 |
b/snf-astakos-app/astakos/im/forms.py | ||
---|---|---|
60 | 60 |
|
61 | 61 |
from astakos.im.util import reserved_email, get_query |
62 | 62 |
|
63 |
import astakos.im.messages as astakos_messages |
|
64 |
|
|
63 | 65 |
import logging |
64 | 66 |
import hashlib |
65 | 67 |
import recaptcha.client.captcha as captcha |
... | ... | |
116 | 118 |
def clean_email(self): |
117 | 119 |
email = self.cleaned_data['email'] |
118 | 120 |
if not email: |
119 |
raise forms.ValidationError(_("This field is required"))
|
|
121 |
raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
|
|
120 | 122 |
if reserved_email(email): |
121 |
raise forms.ValidationError(_("This email is already used"))
|
|
123 |
raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
|
|
122 | 124 |
return email |
123 | 125 |
|
124 | 126 |
def clean_has_signed_terms(self): |
125 | 127 |
has_signed_terms = self.cleaned_data['has_signed_terms'] |
126 | 128 |
if not has_signed_terms: |
127 |
raise forms.ValidationError(_('You have to agree with the terms'))
|
|
129 |
raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
|
|
128 | 130 |
return has_signed_terms |
129 | 131 |
|
130 | 132 |
def clean_recaptcha_response_field(self): |
... | ... | |
142 | 144 |
rrf = self.cleaned_data['recaptcha_response_field'] |
143 | 145 |
check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip) |
144 | 146 |
if not check.is_valid: |
145 |
raise forms.ValidationError( |
|
146 |
_('You have not entered the correct words')) |
|
147 |
raise forms.ValidationError(_(astakos_messages.CAPTCHA_VALIDATION_ERR)) |
|
147 | 148 |
|
148 | 149 |
def save(self, commit=True): |
149 | 150 |
""" |
... | ... | |
222 | 223 |
def clean_email(self): |
223 | 224 |
email = self.cleaned_data['email'] |
224 | 225 |
if not email: |
225 |
raise forms.ValidationError(_("This field is required"))
|
|
226 |
raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
|
|
226 | 227 |
return email |
227 | 228 |
|
228 | 229 |
def clean_has_signed_terms(self): |
229 | 230 |
has_signed_terms = self.cleaned_data['has_signed_terms'] |
230 | 231 |
if not has_signed_terms: |
231 |
raise forms.ValidationError(_('You have to agree with the terms'))
|
|
232 |
raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
|
|
232 | 233 |
return has_signed_terms |
233 | 234 |
|
234 | 235 |
def save(self, commit=True): |
... | ... | |
287 | 288 |
email = self.cleaned_data['email'] |
288 | 289 |
for user in AstakosUser.objects.filter(email=email): |
289 | 290 |
if user.provider == 'shibboleth': |
290 |
raise forms.ValidationError(_("This email is already associated with another shibboleth account."))
|
|
291 |
raise forms.ValidationError(_(astakos_messages.SHIBBOLETH_EMAIL_USED))
|
|
291 | 292 |
elif not user.is_active: |
292 |
raise forms.ValidationError(_("This email is already associated with an inactive account. \ |
|
293 |
You need to wait to be activated before being able to switch to a shibboleth account.")) |
|
293 |
raise forms.ValidationError(_(astakos_messages.SHIBBOLETH_INACTIVE_ACC)) |
|
294 | 294 |
super(ShibbolethUserCreationForm, self).clean_email() |
295 | 295 |
return email |
296 | 296 |
|
... | ... | |
343 | 343 |
rrf = self.cleaned_data['recaptcha_response_field'] |
344 | 344 |
check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip) |
345 | 345 |
if not check.is_valid: |
346 |
raise forms.ValidationError( |
|
347 |
_('You have not entered the correct words')) |
|
346 |
raise forms.ValidationError(_(astakos_messages.CAPTCHA_VALIDATION_ERR)) |
|
348 | 347 |
|
349 | 348 |
def clean(self): |
350 | 349 |
super(LoginForm, self).clean() |
351 | 350 |
if self.user_cache and self.user_cache.provider not in ('local', ''): |
352 |
raise forms.ValidationError(_('Local login is not the current authentication method for this account.'))
|
|
351 |
raise forms.ValidationError(_(astakos_messages.SUSPENDED_LOCAL_ACC))
|
|
353 | 352 |
return self.cleaned_data |
354 | 353 |
|
355 | 354 |
|
... | ... | |
419 | 418 |
try: |
420 | 419 |
user = AstakosUser.objects.get(email=email, is_active=True) |
421 | 420 |
if not user.has_usable_password(): |
422 |
raise forms.ValidationError( |
|
423 |
_("This account has not a usable password.")) |
|
421 |
raise forms.ValidationError(_(astakos_messages.UNUSABLE_PASSWORD)) |
|
424 | 422 |
except AstakosUser.DoesNotExist: |
425 |
raise forms.ValidationError(_('That e-mail address doesn\'t have an associated user account. Are you sure you\'ve registered?'))
|
|
423 |
raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
|
|
426 | 424 |
return email |
427 | 425 |
|
428 | 426 |
def save( |
... | ... | |
460 | 458 |
def clean_new_email_address(self): |
461 | 459 |
addr = self.cleaned_data['new_email_address'] |
462 | 460 |
if AstakosUser.objects.filter(email__iexact=addr): |
463 |
raise forms.ValidationError(_(u'This email address is already in use. Please supply a different email address.'))
|
|
461 |
raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
|
|
464 | 462 |
return addr |
465 | 463 |
|
466 | 464 |
def save(self, email_template_name, request, commit=True): |
... | ... | |
485 | 483 |
def clean_has_signed_terms(self): |
486 | 484 |
has_signed_terms = self.cleaned_data['has_signed_terms'] |
487 | 485 |
if not has_signed_terms: |
488 |
raise forms.ValidationError(_('You have to agree with the terms'))
|
|
486 |
raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
|
|
489 | 487 |
return has_signed_terms |
490 | 488 |
|
491 | 489 |
|
... | ... | |
503 | 501 |
username = self.cleaned_data['username'] |
504 | 502 |
try: |
505 | 503 |
Invitation.objects.get(username=username) |
506 |
raise forms.ValidationError( |
|
507 |
_('There is already invitation for this email.')) |
|
504 |
raise forms.ValidationError(_(astakos_messages.INVITATION_EMAIL_EXISTS)) |
|
508 | 505 |
except Invitation.DoesNotExist: |
509 | 506 |
pass |
510 | 507 |
return username |
... | ... | |
690 | 687 |
class AddGroupMembersForm(forms.Form): |
691 | 688 |
q = forms.CharField( |
692 | 689 |
max_length=800, widget=forms.Textarea, label=_('Add users'), |
693 |
help_text=_('Add comma separated user emails, eg. user1@user.com, user2@user.com'),
|
|
690 |
help_text=_(astakos_messages.ADD_GROUP_MEMBERS_Q_HELP),
|
|
694 | 691 |
required=True) |
695 | 692 |
|
696 | 693 |
def clean(self): |
... | ... | |
700 | 697 |
db_entries = AstakosUser.objects.filter(email__in=users) |
701 | 698 |
unknown = list(set(users) - set(u.email for u in db_entries)) |
702 | 699 |
if unknown: |
703 |
raise forms.ValidationError( |
|
704 |
_('Unknown users: %s' % ','.join(unknown))) |
|
700 |
raise forms.ValidationError(_(astakos_messages.UNKNOWN_USERS) % ','.join(unknown)) |
|
705 | 701 |
self.valid_users = db_entries |
706 | 702 |
return self.cleaned_data |
707 | 703 |
|
b/snf-astakos-app/astakos/im/functions.py | ||
---|---|---|
61 | 61 |
FEEDBACK_EMAIL_SUBJECT, |
62 | 62 |
EMAIL_CHANGE_EMAIL_SUBJECT) |
63 | 63 |
import astakos.im.models |
64 |
import astakos.im.messages as astakos_messages |
|
64 | 65 |
|
65 | 66 |
logger = logging.getLogger(__name__) |
66 | 67 |
|
... | ... | |
303 | 304 |
|
304 | 305 |
class SendAdminNotificationError(SendMailError): |
305 | 306 |
def __init__(self): |
306 |
self.message = _('Failed to send notification')
|
|
307 |
self.message = _(astakos_messages.ADMIN_NOTIFICATION_SEND_ERR)
|
|
307 | 308 |
super(SendAdminNotificationError, self).__init__() |
308 | 309 |
|
309 | 310 |
|
310 | 311 |
class SendVerificationError(SendMailError): |
311 | 312 |
def __init__(self): |
312 |
self.message = _('Failed to send verification')
|
|
313 |
self.message = _(astakos_messages.VERIFICATION_SEND_ERR)
|
|
313 | 314 |
super(SendVerificationError, self).__init__() |
314 | 315 |
|
315 | 316 |
|
316 | 317 |
class SendInvitationError(SendMailError): |
317 | 318 |
def __init__(self): |
318 |
self.message = _('Failed to send invitation')
|
|
319 |
self.message = _(astakos_messages.INVITATION_SEND_ERR)
|
|
319 | 320 |
super(SendInvitationError, self).__init__() |
320 | 321 |
|
321 | 322 |
|
322 | 323 |
class SendGreetingError(SendMailError): |
323 | 324 |
def __init__(self): |
324 |
self.message = _('Failed to send greeting')
|
|
325 |
self.message = _(astakos_messages.GREETING_SEND_ERR)
|
|
325 | 326 |
super(SendGreetingError, self).__init__() |
326 | 327 |
|
327 | 328 |
|
328 | 329 |
class SendFeedbackError(SendMailError): |
329 | 330 |
def __init__(self): |
330 |
self.message = _('Failed to send feedback')
|
|
331 |
self.message = _(astakos_messages.FEEDBACK_SEND_ERR)
|
|
331 | 332 |
super(SendFeedbackError, self).__init__() |
332 | 333 |
|
333 | 334 |
|
334 | 335 |
class ChangeEmailError(SendMailError): |
335 | 336 |
def __init__(self): |
336 |
self.message = _('Failed to send change email')
|
|
337 |
self.message = self.message = _(astakos_messages.CHANGE_EMAIL_SEND_ERR)
|
|
337 | 338 |
super(ChangeEmailError, self).__init__() |
338 | 339 |
|
339 | 340 |
|
340 | 341 |
class SendNotificationError(SendMailError): |
341 | 342 |
def __init__(self): |
342 |
self.message = _('Failed to send notification email')
|
|
343 |
self.message = _(astakos_messages.NOTIFICATION_SEND_ERR)
|
|
343 | 344 |
super(SendNotificationError, self).__init__() |
/dev/null | ||
---|---|---|
1 |
# Copyright 2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
from optparse import make_option |
|
35 |
|
|
36 |
from django.core.management.base import BaseCommand, CommandError |
|
37 |
from django.contrib.auth.models import Group, Permission |
|
38 |
from django.contrib.contenttypes.models import ContentType |
|
39 |
from django.core.exceptions import ValidationError |
|
40 |
|
|
41 |
from astakos.im.models import AstakosUser |
|
42 |
from ._common import remove_user_permission, add_user_permission |
|
43 |
|
|
44 |
|
|
45 |
class Command(BaseCommand): |
|
46 |
args = "<user ID>" |
|
47 |
help = "Modify a user's attributes" |
|
48 |
|
|
49 |
option_list = BaseCommand.option_list + ( |
|
50 |
make_option('--invitations', |
|
51 |
dest='invitations', |
|
52 |
metavar='NUM', |
|
53 |
help="Update user's invitations"), |
|
54 |
make_option('--level', |
|
55 |
dest='level', |
|
56 |
metavar='NUM', |
|
57 |
help="Update user's level"), |
|
58 |
make_option('--password', |
|
59 |
dest='password', |
|
60 |
metavar='PASSWORD', |
|
61 |
help="Set user's password"), |
|
62 |
make_option('--provider', |
|
63 |
dest='provider', |
|
64 |
metavar='PROVIDER', |
|
65 |
help="Set user's provider"), |
|
66 |
make_option('--renew-token', |
|
67 |
action='store_true', |
|
68 |
dest='renew_token', |
|
69 |
default=False, |
|
70 |
help="Renew the user's token"), |
|
71 |
make_option('--renew-password', |
|
72 |
action='store_true', |
|
73 |
dest='renew_password', |
|
74 |
default=False, |
|
75 |
help="Renew the user's password"), |
|
76 |
make_option('--set-admin', |
|
77 |
action='store_true', |
|
78 |
dest='admin', |
|
79 |
default=False, |
|
80 |
help="Give user admin rights"), |
|
81 |
make_option('--set-noadmin', |
|
82 |
action='store_true', |
|
83 |
dest='noadmin', |
|
84 |
default=False, |
|
85 |
help="Revoke user's admin rights"), |
|
86 |
make_option('--set-active', |
|
87 |
action='store_true', |
|
88 |
dest='active', |
|
89 |
default=False, |
|
90 |
help="Change user's state to inactive"), |
|
91 |
make_option('--set-inactive', |
|
92 |
action='store_true', |
|
93 |
dest='inactive', |
|
94 |
default=False, |
|
95 |
help="Change user's state to inactive"), |
|
96 |
make_option('--add-group', |
|
97 |
dest='add-group', |
|
98 |
help="Add user group"), |
|
99 |
make_option('--delete-group', |
|
100 |
dest='delete-group', |
|
101 |
help="Delete user group"), |
|
102 |
make_option('--add-permission', |
|
103 |
dest='add-permission', |
|
104 |
help="Add user permission"), |
|
105 |
make_option('--delete-permission', |
|
106 |
dest='delete-permission', |
|
107 |
help="Delete user permission"), |
|
108 |
) |
|
109 |
|
|
110 |
def handle(self, *args, **options): |
|
111 |
if len(args) != 1: |
|
112 |
raise CommandError("Please provide a user ID") |
|
113 |
|
|
114 |
if args[0].isdigit(): |
|
115 |
user = AstakosUser.objects.get(id=int(args[0])) |
|
116 |
else: |
|
117 |
raise CommandError("Invalid ID") |
|
118 |
|
|
119 |
if not user: |
|
120 |
raise CommandError("Unknown user") |
|
121 |
|
|
122 |
if options.get('admin'): |
|
123 |
user.is_superuser = True |
|
124 |
elif options.get('noadmin'): |
|
125 |
user.is_superuser = False |
|
126 |
|
|
127 |
if options.get('active'): |
|
128 |
user.is_active = True |
|
129 |
elif options.get('inactive'): |
|
130 |
user.is_active = False |
|
131 |
|
|
132 |
invitations = options.get('invitations') |
|
133 |
if invitations is not None: |
|
134 |
user.invitations = int(invitations) |
|
135 |
|
|
136 |
groupname = options.get('add-group') |
|
137 |
if groupname is not None: |
|
138 |
try: |
|
139 |
group = Group.objects.get(name=groupname) |
|
140 |
user.groups.add(group) |
|
141 |
except Group.DoesNotExist, e: |
|
142 |
self.stdout.write( |
|
143 |
"Group named %s does not exist\n" % groupname) |
|
144 |
|
|
145 |
groupname = options.get('delete-group') |
|
146 |
if groupname is not None: |
|
147 |
try: |
|
148 |
group = Group.objects.get(name=groupname) |
|
149 |
user.groups.remove(group) |
|
150 |
except Group.DoesNotExist, e: |
|
151 |
self.stdout.write( |
|
152 |
"Group named %s does not exist\n" % groupname) |
|
153 |
|
|
154 |
pname = options.get('add-permission') |
|
155 |
if pname is not None: |
|
156 |
try: |
|
157 |
r, created = add_user_permission(user, pname) |
|
158 |
if created: |
|
159 |
self.stdout.write( |
|
160 |
'Permission: %s created successfully\n' % pname) |
|
161 |
if r > 0: |
|
162 |
self.stdout.write( |
|
163 |
'Permission: %s added successfully\n' % pname) |
|
164 |
elif r == 0: |
|
165 |
self.stdout.write( |
|
166 |
'User has already permission: %s\n' % pname) |
|
167 |
except Exception, e: |
|
168 |
raise CommandError(e) |
|
169 |
|
|
170 |
pname = options.get('delete-permission') |
|
171 |
if pname is not None and not user.has_perm(pname): |
|
172 |
try: |
|
173 |
r = remove_user_permission(user, pname) |
|
174 |
if r < 0: |
|
175 |
self.stdout.write( |
|
176 |
'Invalid permission codename: %s\n' % pname) |
|
177 |
elif r == 0: |
|
178 |
self.stdout.write('User has not permission: %s\n' % pname) |
|
179 |
elif r > 0: |
|
180 |
self.stdout.write( |
|
181 |
'Permission: %s removed successfully\n' % pname) |
|
182 |
except Exception, e: |
|
183 |
raise CommandError(e) |
|
184 |
|
|
185 |
level = options.get('level') |
|
186 |
if level is not None: |
|
187 |
user.level = int(level) |
|
188 |
|
|
189 |
password = options.get('password') |
|
190 |
if password is not None: |
|
191 |
user.set_password(password) |
|
192 |
|
|
193 |
provider = options.get('provider') |
|
194 |
if provider is not None: |
|
195 |
user.provider = provider |
|
196 |
|
|
197 |
password = None |
|
198 |
if options['renew_password']: |
|
199 |
password = AstakosUser.objects.make_random_password() |
|
200 |
user.set_password(password) |
|
201 |
|
|
202 |
if options['renew_token']: |
|
203 |
user.renew_token() |
|
204 |
|
|
205 |
try: |
|
206 |
user.save() |
|
207 |
except ValidationError, e: |
|
208 |
raise CommandError(e) |
|
209 |
|
|
210 |
if password: |
|
211 |
self.stdout.write('User\'s new password: %s\n' % password) |
b/snf-astakos-app/astakos/im/management/commands/user-update.py | ||
---|---|---|
1 |
# Copyright 2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
from optparse import make_option |
|
35 |
|
|
36 |
from django.core.management.base import BaseCommand, CommandError |
|
37 |
from django.contrib.auth.models import Group, Permission |
|
38 |
from django.contrib.contenttypes.models import ContentType |
|
39 |
from django.core.exceptions import ValidationError |
|
40 |
|
|
41 |
from astakos.im.models import AstakosUser |
|
42 |
from ._common import remove_user_permission, add_user_permission |
|
43 |
|
|
44 |
|
|
45 |
class Command(BaseCommand): |
|
46 |
args = "<user ID>" |
|
47 |
help = "Modify a user's attributes" |
|
48 |
|
|
49 |
option_list = BaseCommand.option_list + ( |
|
50 |
make_option('--invitations', |
|
51 |
dest='invitations', |
|
52 |
metavar='NUM', |
|
53 |
help="Update user's invitations"), |
|
54 |
make_option('--level', |
|
55 |
dest='level', |
|
56 |
metavar='NUM', |
|
57 |
help="Update user's level"), |
|
58 |
make_option('--password', |
|
59 |
dest='password', |
|
60 |
metavar='PASSWORD', |
|
61 |
help="Set user's password"), |
|
62 |
make_option('--provider', |
|
63 |
dest='provider', |
|
64 |
metavar='PROVIDER', |
|
65 |
help="Set user's provider"), |
|
66 |
make_option('--renew-token', |
|
67 |
action='store_true', |
|
68 |
dest='renew_token', |
|
69 |
default=False, |
|
70 |
help="Renew the user's token"), |
|
71 |
make_option('--renew-password', |
|
72 |
action='store_true', |
|
73 |
dest='renew_password', |
|
74 |
default=False, |
|
75 |
help="Renew the user's password"), |
|
76 |
make_option('--set-admin', |
|
77 |
action='store_true', |
|
78 |
dest='admin', |
|
79 |
default=False, |
|
80 |
help="Give user admin rights"), |
|
81 |
make_option('--set-noadmin', |
|
82 |
action='store_true', |
|
83 |
dest='noadmin', |
|
84 |
default=False, |
|
85 |
help="Revoke user's admin rights"), |
|
86 |
make_option('--set-active', |
|
87 |
action='store_true', |
|
88 |
dest='active', |
|
89 |
default=False, |
|
90 |
help="Change user's state to inactive"), |
|
91 |
make_option('--set-inactive', |
|
92 |
action='store_true', |
|
93 |
dest='inactive', |
|
94 |
default=False, |
|
95 |
help="Change user's state to inactive"), |
|
96 |
make_option('--add-group', |
|
97 |
dest='add-group', |
|
98 |
help="Add user group"), |
|
99 |
make_option('--delete-group', |
|
100 |
dest='delete-group', |
|
101 |
help="Delete user group"), |
|
102 |
make_option('--add-permission', |
|
103 |
dest='add-permission', |
|
104 |
help="Add user permission"), |
|
105 |
make_option('--delete-permission', |
|
106 |
dest='delete-permission', |
|
107 |
help="Delete user permission"), |
|
108 |
) |
|
109 |
|
|
110 |
def handle(self, *args, **options): |
|
111 |
if len(args) != 1: |
|
112 |
raise CommandError("Please provide a user ID") |
|
113 |
|
|
114 |
if args[0].isdigit(): |
|
115 |
user = AstakosUser.objects.get(id=int(args[0])) |
|
116 |
else: |
|
117 |
raise CommandError("Invalid ID") |
|
118 |
|
|
119 |
if not user: |
|
120 |
raise CommandError("Unknown user") |
|
121 |
|
|
122 |
if options.get('admin'): |
|
123 |
user.is_superuser = True |
|
124 |
elif options.get('noadmin'): |
|
125 |
user.is_superuser = False |
|
126 |
|
|
127 |
if options.get('active'): |
|
128 |
user.is_active = True |
|
129 |
elif options.get('inactive'): |
|
130 |
user.is_active = False |
|
131 |
|
|
132 |
invitations = options.get('invitations') |
|
133 |
if invitations is not None: |
|
134 |
user.invitations = int(invitations) |
|
135 |
|
|
136 |
groupname = options.get('add-group') |
|
137 |
if groupname is not None: |
|
138 |
try: |
|
139 |
group = Group.objects.get(name=groupname) |
|
140 |
user.groups.add(group) |
|
141 |
except Group.DoesNotExist, e: |
|
142 |
self.stdout.write( |
|
143 |
"Group named %s does not exist\n" % groupname) |
|
144 |
|
|
145 |
groupname = options.get('delete-group') |
|
146 |
if groupname is not None: |
|
147 |
try: |
|
148 |
group = Group.objects.get(name=groupname) |
|
149 |
user.groups.remove(group) |
|
150 |
except Group.DoesNotExist, e: |
|
151 |
self.stdout.write( |
|
152 |
"Group named %s does not exist\n" % groupname) |
|
153 |
|
|
154 |
pname = options.get('add-permission') |
|
155 |
if pname is not None: |
|
156 |
try: |
|
157 |
r, created = add_user_permission(user, pname) |
|
158 |
if created: |
|
159 |
self.stdout.write( |
|
160 |
'Permission: %s created successfully\n' % pname) |
|
161 |
if r > 0: |
|
162 |
self.stdout.write( |
|
163 |
'Permission: %s added successfully\n' % pname) |
|
164 |
elif r == 0: |
|
165 |
self.stdout.write( |
|
166 |
'User has already permission: %s\n' % pname) |
|
167 |
except Exception, e: |
|
168 |
raise CommandError(e) |
|
169 |
|
|
170 |
pname = options.get('delete-permission') |
|
171 |
if pname is not None and not user.has_perm(pname): |
|
172 |
try: |
|
173 |
r = remove_user_permission(user, pname) |
|
174 |
if r < 0: |
|
175 |
self.stdout.write( |
|
176 |
'Invalid permission codename: %s\n' % pname) |
|
177 |
elif r == 0: |
|
178 |
self.stdout.write('User has not permission: %s\n' % pname) |
|
179 |
elif r > 0: |
|
180 |
self.stdout.write( |
|
181 |
'Permission: %s removed successfully\n' % pname) |
|
182 |
except Exception, e: |
|
183 |
raise CommandError(e) |
|
184 |
|
|
185 |
level = options.get('level') |
|
186 |
if level is not None: |
|
187 |
user.level = int(level) |
|
188 |
|
|
189 |
password = options.get('password') |
|
190 |
if password is not None: |
|
191 |
user.set_password(password) |
|
192 |
|
|
193 |
provider = options.get('provider') |
|
194 |
if provider is not None: |
|
195 |
user.provider = provider |
|
196 |
|
|
197 |
password = None |
|
198 |
if options['renew_password']: |
|
199 |
password = AstakosUser.objects.make_random_password() |
|
200 |
user.set_password(password) |
|
201 |
|
|
202 |
if options['renew_token']: |
|
203 |
user.renew_token() |
|
204 |
|
|
205 |
try: |
|
206 |
user.save() |
|
207 |
except ValidationError, e: |
|
208 |
raise CommandError(e) |
|
209 |
|
|
210 |
if password: |
|
211 |
self.stdout.write('User\'s new password: %s\n' % password) |
b/snf-astakos-app/astakos/im/messages.py | ||
---|---|---|
1 |
# Copyright 2011-2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
ACCOUNT_AUTHENTICATION_FAILED = 'Cannot authenticate account.' |
|
35 |
ACCOUNT_INACTIVE = 'Inactive account.' |
|
36 |
ACCOUNT_ALREADY_ACTIVE = 'Account is already active.' |
|
37 |
TOKEN_UNKNOWN = 'There is no user matching this token.' |
|
38 |
|
|
39 |
INVITATION_SENT = 'Invitation sent to %(emails.' |
|
40 |
PROFILE_UPDATED = 'Profile has been updated successfully.' |
|
41 |
FEEDBACK_SENT = 'Feedback successfully sent.' |
|
42 |
EMAIL_CHANGED = 'Account email has been changed successfully.' |
|
43 |
EMAIL_CHANGE_REGISTERED = 'Change email request has been registered succefully. \ |
|
44 |
You are going to receive a verification email in the new address.' |
|
45 |
|
|
46 |
OBJECT_CREATED = 'The %(verbose_names was created successfully.' |
|
47 |
MEMBER_JOINED_GROUP = '%(realnames has been successfully joined the group.' |
|
48 |
MEMBER_REMOVED = '%(realnames has been successfully removed from the group.' |
|
49 |
BILLING_ERROR = 'Service response status: %(status)d' |
|
50 |
LOGOUT_SUCCESS = 'You have successfully logged out.' |
|
51 |
|
|
52 |
GENERIC_ERROR = 'Something wrong has happened. \ |
|
53 |
Please contact the administrators for more details.' |
|
54 |
|
|
55 |
MAX_INVITATION_NUMBER_REACHED = 'There are no invitations left.' |
|
56 |
GROUP_MAX_PARTICIPANT_NUMBER_REACHED = 'Group maximum participant number has been reached.' |
|
57 |
NO_APPROVAL_TERMS = 'There are no approval terms.' |
|
58 |
PENDING_EMAIL_CHANGE_REQUEST = 'There is already a pending change email request.' |
|
59 |
OBJECT_CREATED_FAILED = 'The %(verbose_names creation failed: %(reasons.' |
|
60 |
GROUP_JOIN_FAILURE = 'Failed to join group.' |
|
61 |
GROUPKIND_UNKNOWN = 'There is no such a group kind' |
|
62 |
NOT_MEMBER = 'User is not member of the group.' |
|
63 |
NOT_OWNER = 'User is not a group owner.' |
|
64 |
OWNER_CANNOT_LEAVE_GROUP = 'Owner cannot leave the group.' |
|
65 |
|
|
66 |
# Field validation fields |
|
67 |
REQUIRED_FIELD = 'This field is required.' |
|
68 |
EMAIL_USED = 'This email address is already in use. Please supply a different email address.' |
|
69 |
SHIBBOLETH_EMAIL_USED = 'This email is already associated with another shibboleth account.' |
|
70 |
SHIBBOLETH_INACTIVE_ACC = 'This email is already associated with an inactive account. \ |
|
71 |
You need to wait to be activated before being able to switch to a shibboleth account.' |
|
72 |
|
|
73 |
SIGN_TERMS = 'You have to agree with the terms.' |
|
74 |
CAPTCHA_VALIDATION_ERR = 'You have not entered the correct words.' |
|
75 |
SUSPENDED_LOCAL_ACC = 'Local login is not the current authentication method for this account.' |
|
76 |
UNUSABLE_PASSWORD = 'This account has not a usable password.' |
|
77 |
EMAIL_UNKNOWN = 'That e-mail address doesn\'t have an associated user account. \ |
|
78 |
Are you sure you\'ve registered?' |
|
79 |
INVITATION_EMAIL_EXISTS = 'There is already invitation for this email.' |
|
80 |
INVITATION_CONSUMED_ERR = 'Invitation is used.' |
|
81 |
UNKNOWN_USERS = 'Unknown users: %s' |
|
82 |
UNIQUE_EMAIL_IS_ACTIVE_CONSTRAIN_ERR = 'Another account with the same email & is_active combination found.' |
|
83 |
INVALID_ACTIVATION_KEY = 'Invalid activation key.' |
|
84 |
NEW_EMAIL_ADDR_RESERVED = 'The new email address is reserved.' |
|
85 |
EMAIL_RESERVED = 'Email: %(email)s is reserved' |
|
86 |
|
|
87 |
# Field help text |
|
88 |
ADD_GROUP_MEMBERS_Q_HELP = 'Add comma separated user emails, eg. user1@user.com, user2@user.com' |
|
89 |
ASTAKOSUSER_GROUPS_HELP = 'In addition to the permissions manually assigned, \ |
|
90 |
this user will also get all permissions granted to each group he/she is in.' |
|
91 |
EMAIL_CHANGE_NEW_ADDR_HELP = 'Your old email address will be used until you verify your new one.' |
|
92 |
|
|
93 |
EMAIL_SEND_ERR = 'Failed to send %s.' |
|
94 |
ADMIN_NOTIFICATION_SEND_ERR = EMAIL_SEND_ERR % 'admin notification' |
|
95 |
VERIFICATION_SEND_ERR = EMAIL_SEND_ERR % 'verification' |
|
96 |
INVITATION_SEND_ERR = EMAIL_SEND_ERR % 'invitation' |
|
97 |
GREETING_SEND_ERR = EMAIL_SEND_ERR % 'greeting' |
|
98 |
FEEDBACK_SEND_ERR = EMAIL_SEND_ERR % 'feedback' |
|
99 |
CHANGE_EMAIL_SEND_ERR = EMAIL_SEND_ERR % 'feedback' |
|
100 |
NOTIFICATION_SEND_ERR = EMAIL_SEND_ERR % 'notification' |
|
101 |
|
|
102 |
|
|
103 |
MISSING_NEXT_PARAMETER = 'No next parameter' |
|
104 |
|
|
105 |
VERIFICATION_SENT = 'Verification sent.' |
|
106 |
|
|
107 |
SWITCH_ACCOUNT_LINK_SENT = 'This email is already associated with another local account. \ |
|
108 |
To change this account to a shibboleth one follow the link in the verification email sent to %(emails. \ |
|
109 |
Otherwise just ignore it.' |
|
110 |
NOTIFACATION_SENT = 'Your request for an account was successfully received and is now pending approval. \ |
|
111 |
You will be notified by email in the next few days. \ |
|
112 |
Thanks for your interest in ~okeanos! The GRNET team.' |
|
113 |
REGISTRATION_COMPLETED = 'Registration completed. You can now login.' |
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
44 | 44 |
from django.db import models, IntegrityError |
45 | 45 |
from django.contrib.auth.models import User, UserManager, Group, Permission |
46 | 46 |
from django.utils.translation import ugettext as _ |
47 |
from django.db import transaction |
|
47 | 48 |
from django.core.exceptions import ValidationError |
48 | 49 |
from django.db import transaction |
49 | 50 |
from django.db.models.signals import (pre_save, post_save, post_syncdb, |
... | ... | |
63 | 64 |
from astakos.im.tasks import propagate_groupmembers_quota |
64 | 65 |
from astakos.im.functions import send_invitation |
65 | 66 |
|
67 |
import astakos.im.messages as astakos_messages |
|
68 |
|
|
66 | 69 |
logger = logging.getLogger(__name__) |
67 | 70 |
|
68 | 71 |
DEFAULT_CONTENT_TYPE = None |
... | ... | |
228 | 231 |
self.save() |
229 | 232 |
quota_disturbed.send(sender=self, users=self.approved_members) |
230 | 233 |
|
234 |
@transaction.commit_manually |
|
231 | 235 |
def approve_member(self, person): |
232 | 236 |
m, created = self.membership_set.get_or_create(person=person) |
233 | 237 |
# update date_joined in any case |
234 |
m.date_joined = datetime.now() |
|
235 |
m.save() |
|
238 |
try: |
|
239 |
m.approve() |
|
240 |
except: |
|
241 |
transaction.rollback() |
|
242 |
raise |
|
243 |
else: |
|
244 |
transaction.commit() |
|
236 | 245 |
|
237 |
def disapprove_member(self, person): |
|
238 |
self.membership_set.remove(person=person) |
|
246 |
# def disapprove_member(self, person):
|
|
247 |
# self.membership_set.remove(person=person)
|
|
239 | 248 |
|
240 | 249 |
@property |
241 | 250 |
def members(self): |
... | ... | |
340 | 349 |
|
341 | 350 |
astakos_groups = models.ManyToManyField( |
342 | 351 |
AstakosGroup, verbose_name=_('agroups'), blank=True, |
343 |
help_text=_("""In addition to the permissions manually assigned, this |
|
344 |
user will also get all permissions granted to each group |
|
345 |
he/she is in."""), |
|
352 |
help_text=_(astakos_messages.ASTAKOSUSER_GROUPS_HELP), |
|
346 | 353 |
through='Membership') |
347 | 354 |
|
348 | 355 |
__has_signed_terms = False |
... | ... | |
519 | 526 |
q = q.filter(email=self.email) |
520 | 527 |
q = q.filter(is_active=self.is_active) |
521 | 528 |
if q.count() != 0: |
522 |
raise ValidationError({'__all__': [_('Another account with the same email & is_active combination found.')]})
|
|
529 |
raise ValidationError({'__all__': [_(astakos_messages.UNIQUE_EMAIL_IS_ACTIVE_CONSTRAIN_ERR)]})
|
|
523 | 530 |
|
524 | 531 |
@property |
525 | 532 |
def signed_terms(self): |
... | ... | |
564 | 571 |
return False |
565 | 572 |
|
566 | 573 |
def approve(self): |
574 |
if self.group.max_participants: |
|
575 |
assert len(self.group.approved_members) + 1 <= self.group.max_participants |
|
567 | 576 |
self.date_joined = datetime.now() |
568 | 577 |
self.save() |
569 | 578 |
quota_disturbed.send(sender=self, users=(self.person,)) |
... | ... | |
690 | 699 |
except AstakosUser.DoesNotExist: |
691 | 700 |
pass |
692 | 701 |
else: |
693 |
raise ValueError(_('The new email address is reserved.'))
|
|
702 |
raise ValueError(_(astakos_messages.NEW_EMAIL_ADDR_RESERVED))
|
|
694 | 703 |
# update user |
695 | 704 |
user = AstakosUser.objects.get(pk=email_change.user_id) |
696 | 705 |
user.email = email_change.new_email_address |
... | ... | |
698 | 707 |
email_change.delete() |
699 | 708 |
return user |
700 | 709 |
except EmailChange.DoesNotExist: |
701 |
raise ValueError(_('Invalid activation key'))
|
|
710 |
raise ValueError(_(astakos_messages.INVALID_ACTIVATION_KEY))
|
|
702 | 711 |
|
703 | 712 |
|
704 | 713 |
class EmailChange(models.Model): |
705 | 714 |
new_email_address = models.EmailField(_(u'new e-mail address'), |
706 |
help_text=_(u'Your old email address will be used until you verify your new one.'))
|
|
715 |
help_text=_(astakos_messages.EMAIL_CHANGE_NEW_ADDR_HELP))
|
|
707 | 716 |
user = models.ForeignKey( |
708 | 717 |
AstakosUser, unique=True, related_name='emailchange_user') |
709 | 718 |
requested_at = models.DateTimeField(default=datetime.now()) |
... | ... | |
851 | 860 |
post_save.connect(send_quota_disturbed, sender=AstakosUserQuota) |
852 | 861 |
post_delete.connect(send_quota_disturbed, sender=AstakosUserQuota) |
853 | 862 |
post_save.connect(send_quota_disturbed, sender=AstakosGroupQuota) |
854 |
post_delete.connect(send_quota_disturbed, sender=AstakosGroupQuota) |
|
863 |
post_delete.connect(send_quota_disturbed, sender=AstakosGroupQuota) |
b/snf-astakos-app/astakos/im/target/local.py | ||
---|---|---|
43 | 43 |
from astakos.im.forms import LoginForm |
44 | 44 |
from astakos.im.settings import RATELIMIT_RETRIES_ALLOWED |
45 | 45 |
|
46 |
import astakos.im.messages as astakos_messages |
|
47 |
|
|
46 | 48 |
from ratelimit.decorators import ratelimit |
47 | 49 |
|
48 | 50 |
retries = RATELIMIT_RETRIES_ALLOWED - 1 |
... | ... | |
72 | 74 |
|
73 | 75 |
message = None |
74 | 76 |
if not user: |
75 |
message = _('Cannot authenticate account')
|
|
77 |
message = _(astakos_messages.ACCOUNT_AUTHENTICATION_FAILED)
|
|
76 | 78 |
elif not user.is_active: |
77 |
message = _('Inactive account')
|
|
79 |
message = _(astakos_messages.ACCOUNT_INACTIVE)
|
|
78 | 80 |
if message: |
79 | 81 |
messages.error(request, message) |
80 | 82 |
return render_to_response(on_failure, |
b/snf-astakos-app/astakos/im/target/redirect.py | ||
---|---|---|
45 | 45 |
from astakos.im.util import set_cookie |
46 | 46 |
from astakos.im.functions import login as auth_login, logout |
47 | 47 |
|
48 |
import astakos.im.messages as astakos_messages |
|
49 |
|
|
48 | 50 |
import logging |
49 | 51 |
|
50 | 52 |
logger = logging.getLogger(__name__) |
... | ... | |
62 | 64 |
""" |
63 | 65 |
next = request.GET.get('next') |
64 | 66 |
if not next: |
65 |
return HttpResponseBadRequest(_('No next parameter'))
|
|
67 |
return HttpResponseBadRequest(_(astakos_messages.MISSING_NEXT_PARAMETER))
|
|
66 | 68 |
force = request.GET.get('force', None) |
67 | 69 |
response = HttpResponse() |
68 | 70 |
if force == '': |
b/snf-astakos-app/astakos/im/target/shibboleth.py | ||
---|---|---|
43 | 43 |
from astakos.im.forms import LoginForm |
44 | 44 |
from astakos.im.activation_backends import get_backend, SimpleBackend |
45 | 45 |
|
46 |
import astakos.im.messages as astakos_messages |
|
46 | 47 |
|
47 | 48 |
class Tokens: |
48 | 49 |
# these are mapped by the Shibboleth SP software |
... | ... | |
89 | 90 |
request.GET.get('next'), |
90 | 91 |
'renew' in request.GET) |
91 | 92 |
else: |
92 |
message = _('Inactive account')
|
|
93 |
message = _(astakos_messages.ACCOUNT_INACTIVE)
|
|
93 | 94 |
messages.error(request, message) |
94 | 95 |
return render_response(on_login_template, |
95 | 96 |
login_form=LoginForm(request=request), |
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_detail.html | ||
---|---|---|
75 | 75 |
{% endif %} |
76 | 76 |
{% endfor %} |
77 | 77 |
</dd> |
78 |
<dt>Max participants</dt> |
|
79 |
<dd>{% if object.max_participants%}{{object.max_participants}}{% else %} {% endif %}</dd> |
|
78 | 80 |
</dl> |
79 | 81 |
</div> |
80 | 82 |
|
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_form.html | ||
---|---|---|
1 | 1 |
{% extends "im/account_base.html" %} |
2 | 2 |
|
3 |
{% load filters %} |
|
4 |
{% block headjs %} |
|
5 |
{{ block.super }} |
|
6 |
<script src="{{ IM_STATIC_URL }}js/quotas.js"></script> |
|
7 |
{% endblock %} |
|
3 | 8 |
{% block page.body %} |
4 |
<div class="projects"> |
|
5 |
<div class="maincol {% block innerpage.class %}{% endblock %}"> |
|
6 |
<form action="" method="post" |
|
7 |
class="withlabels">{% csrf_token %} |
|
8 |
<h2><span>CREATE {{ kind|upper }}</span></h2> |
|
9 |
{% include "im/form_render.html" %} |
|
10 |
<div class="form-row submit"> |
|
11 |
<input type="submit" class="submit altcol" value="SUBMIT" /> |
|
12 |
</div> |
|
13 |
</form> |
|
9 |
|
|
10 |
|
|
11 |
<form action="" method="post" class="withlabels quotas-form">{% csrf_token %} |
|
12 |
|
|
13 |
<fieldset class="with-info"> |
|
14 |
<legend> |
|
15 |
1. CREATE GROUP |
|
16 |
<span class="info"> |
|
17 |
<em>more info</em> |
|
18 |
<span>Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text</span> |
|
19 |
</span> |
|
20 |
</legend> |
|
21 |
|
|
22 |
{% include "im/form_render.html" %} |
|
23 |
|
|
24 |
<!-- |
|
25 |
<div class="double-checks"> |
|
26 |
<label>Max users per group</label> |
|
27 |
<div class="form-row"> |
|
28 |
<p class="clearfix"> |
|
29 |
<label for="members_unlimited">Unlimited</label> |
|
30 |
<input type="checkbox" id="members_unlimited" name="members_unlimited" class="unlimited" checked="checked"> |
|
31 |
<span class="info"> |
|
32 |
<em>more info</em> |
|
33 |
<span>Help Text Help Text Help Text Text Help Text Help Text</span> |
|
34 |
</span> |
|
35 |
</p> |
|
36 |
</div> |
|
37 |
<div class="form-row"> |
|
38 |
<p class="clearfix"> |
|
39 |
<label for="members_limited">Limited</label> |
|
40 |
<input type="checkbox" id="members_limited" name="members_limited" class="limited"> |
|
41 |
<input type="text" id="members_uplimit" name="members_uplimit" /> |
|
42 |
|
|
43 |
</p> |
|
44 |
|
|
45 |
</div> |
|
46 |
|
|
47 |
</div> |
|
48 |
--> |
|
49 |
</fieldset> |
|
50 |
|
|
51 |
<fieldset id="icons"> |
|
52 |
<legend> |
|
53 |
2. CHOOSE RESOURCES |
|
54 |
<span class="info"> |
|
55 |
<em>more info</em> |
|
56 |
<span>Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text</span> |
|
57 |
</span> |
|
58 |
</legend> |
|
59 |
|
|
60 |
{% with resource_catalog|lookup:'resources' as resources %} |
|
61 |
{% with resource_catalog|lookup:'groups' as groups %} |
|
62 |
<ul class="clearfix"> |
|
63 |
{% for g, rs in groups.items %} |
|
64 |
{% with resource_presentation|lookup:g as group_info %} |
|
65 |
<li> |
|
66 |
<a href="#{{ g }}" id="{{'group_'|add:g}}"><img src="/static/im/images/create-{{ g }}.png" alt="vm"/></a> |
|
67 |
<input type="hidden" name="{{ 'is_selected_'|add:g }}" id="{{ 'id_is_selected_'|add:g }}" value="0"> |
|
68 |
<p class="msg">{{ group_info.help_text }}</p> |
|
69 |
</li> |
|
70 |
{% endwith %} |
|
71 |
{% endfor %} |
|
72 |
</ul> |
|
73 |
|
|
74 |
</fieldset> |
|
75 |
|
|
76 |
<div class="foo"> |
|
77 |
|
|
78 |
</div> |
|
79 |
<div class="not-foo"> |
|
80 |
{% for g, rs in groups.items %} |
|
81 |
|
|
82 |
<div class="group {{'group_'|add:g}}" id="{{ g }}"> |
|
83 |
<a href="#icons" class="delete">X remove resource</a> |
|
84 |
{% for r in rs %} |
|
85 |
{% with resource_presentation|lookup:r as resource_info %} |
|
86 |
{% with resources|lookup:r as resource%} |
|
87 |
<fieldset class="quota storage"> |
|
88 |
<legend> |
|
89 |
{% if resource_info.is_abbreviation %} |
|
90 |
{{ r|get_value_after_dot|upper }} |
|
91 |
{% else %} |
|
92 |
{{ r|get_value_after_dot|capfirst }} |
|
93 |
{% endif %} |
|
94 |
<span class="info"> |
|
95 |
<em>more info</em> |
|
96 |
<span>{{ resource_info.help_text }}</span> |
|
97 |
</span> |
|
98 |
</legend> |
|
99 |
<!-- <div class="form-row"> |
|
100 |
<p class="clearfix"> |
|
101 |
<label for="num_storage">Total storage</label> |
|
102 |
<input type="text" name="num_storage"> |
|
103 |
<span class="extra-img"> </span> |
|
104 |
<span class="info"><em>more info</em><span>Help Text</span></span> |
|
105 |
</p> |
|
106 |
</div>--> |
|
107 |
<div class="double-checks"> |
|
108 |
<label> |
|
109 |
Max {% if resource_info.is_abbreviation %}{{ r|get_value_after_dot|upper }}{% else %}{{ r|get_value_after_dot }}{% endif %}{% if not resource.unit %}s {% endif %} per user |
|
110 |
{% if resource.unit %} |
|
111 |
({{ resource.unit }}) |
|
112 |
{% endif %} |
|
113 |
</label> |
|
114 |
<div class="form-row"> |
|
115 |
<p class="clearfix"> |
|
116 |
<label for="{{r|add:'_unlimited'}}">Unlimited</label> |
|
117 |
<input type="checkbox" id="{{'id_'|add:r|add:'_unlimited'}}" name="{{r|add:'_unlimited'}}" class="unlimited radio" checked="checked"> |
|
118 |
</p> |
|
119 |
</div> |
|
120 |
<div class="form-row"> |
|
121 |
<p class="clearfix"> |
|
122 |
<label for="{{r|add:'_limited'}}">Limited</label> |
|
123 |
<input type="checkbox" id="id_storage_per_user_limited" name="{{r|add:'_limited'}}" class="radio limited"> |
|
124 |
<input type="text" id="{{'id_'|add:r|add:'_uplimit'}}" name="{{r|add:'_uplimit'}}"/> |
|
125 |
</p> |
|
126 |
</div> |
|
127 |
|
|
128 |
</div> |
|
129 |
</fieldset> |
|
130 |
{% endwith %} |
|
131 |
{% endwith %} |
|
132 |
{% endfor %} |
|
133 |
</div> |
|
134 |
|
|
135 |
{% endfor %} |
|
14 | 136 |
</div> |
15 |
</div> |
|
16 |
{% endblock %} |
|
137 |
{% endwith %} |
|
138 |
{% endwith %} |
|
139 |
|
|
140 |
<div class="form-row submit"> |
|
141 |
<input type="submit" value="SUBMIT" class="submit altcol" autocomplete="off"> |
|
142 |
</div> |
|
143 |
</form> |
|
144 |
|
|
145 |
<script> |
|
146 |
|
|
147 |
</script> |
|
148 |
|
|
149 |
{% endblock %} |
/dev/null | ||
---|---|---|
1 |
{% extends "im/account_base.html" %} |
|
2 |
|
|
3 |
{% load filters %} |
|
4 |
{% block headjs %} |
|
5 |
{{ block.super }} |
|
6 |
<script src="{{ IM_STATIC_URL }}js/quotas.js"></script> |
|
7 |
{% endblock %} |
|
8 |
{% block page.body %} |
|
9 |
|
|
10 |
|
|
11 |
<form action="" method="post" class="withlabels quotas-form">{% csrf_token %} |
|
12 |
|
|
13 |
<fieldset class="with-info"> |
|
14 |
<legend> |
|
15 |
1. CREATE GROUP |
|
16 |
<span class="info"> |
|
17 |
<em>more info</em> |
|
18 |
<span>Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text</span> |
|
19 |
</span> |
|
20 |
</legend> |
|
21 |
|
|
22 |
{% include "im/form_render.html" %} |
|
23 |
|
|
24 |
<!-- |
|
25 |
<div class="double-checks"> |
|
26 |
<label>Max users per group</label> |
|
27 |
<div class="form-row"> |
|
28 |
<p class="clearfix"> |
|
29 |
<label for="members_unlimited">Unlimited</label> |
|
30 |
<input type="checkbox" id="members_unlimited" name="members_unlimited" class="unlimited" checked="checked"> |
|
31 |
<span class="info"> |
|
32 |
<em>more info</em> |
|
33 |
<span>Help Text Help Text Help Text Text Help Text Help Text</span> |
|
34 |
</span> |
|
35 |
</p> |
|
36 |
</div> |
|
37 |
<div class="form-row"> |
|
38 |
<p class="clearfix"> |
|
39 |
<label for="members_limited">Limited</label> |
|
40 |
<input type="checkbox" id="members_limited" name="members_limited" class="limited"> |
|
41 |
<input type="text" id="members_uplimit" name="members_uplimit" /> |
|
42 |
|
|
43 |
</p> |
|
44 |
|
|
45 |
</div> |
|
46 |
|
|
47 |
</div> |
|
48 |
--> |
|
49 |
</fieldset> |
|
50 |
|
|
51 |
<fieldset id="icons"> |
|
52 |
<legend> |
|
53 |
2. CHOOSE RESOURCES |
|
54 |
<span class="info"> |
|
55 |
<em>more info</em> |
|
56 |
<span>Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text</span> |
|
57 |
</span> |
|
58 |
</legend> |
|
59 |
|
|
60 |
{% with resource_catalog|lookup:'resources' as resources %} |
|
61 |
{% with resource_catalog|lookup:'groups' as groups %} |
|
62 |
<ul class="clearfix"> |
|
63 |
{% for g, rs in groups.items %} |
|
64 |
{% with resource_presentation|lookup:g as group_info %} |
|
65 |
<li> |
|
66 |
<a href="#{{ g }}" id="{{'group_'|add:g}}"><img src="/static/im/images/create-{{ g }}.png" alt="vm"/></a> |
|
67 |
<input type="hidden" name="{{ 'is_selected_'|add:g }}" id="{{ 'id_is_selected_'|add:g }}" value="0"> |
|
68 |
<p class="msg">{{ group_info.help_text }}</p> |
|
69 |
</li> |
|
70 |
{% endwith %} |
|
71 |
{% endfor %} |
|
72 |
</ul> |
|
73 |
|
|
74 |
</fieldset> |
|
75 |
|
|
76 |
<div class="foo"> |
|
77 |
|
|
78 |
</div> |
|
79 |
<div class="not-foo"> |
|
80 |
{% for g, rs in groups.items %} |
|
81 |
|
|
82 |
<div class="group {{'group_'|add:g}}" id="{{ g }}"> |
|
83 |
<a href="#icons" class="delete">X remove resource</a> |
|
84 |
{% for r in rs %} |
|
85 |
{% with resource_presentation|lookup:r as resource_info %} |
|
86 |
{% with resources|lookup:r as resource%} |
|
87 |
<fieldset class="quota"> |
|
88 |
<legend> |
|
89 |
{% if resource_info.is_abbreviation %} |
|
90 |
{{ r|get_value_after_dot|upper }} |
|
91 |
{% else %} |
|
92 |
{{ r|get_value_after_dot|capfirst }} |
|
93 |
{% endif %} |
|
94 |
<span class="info"> |
|
95 |
<em>more info</em> |
|
96 |
<span>{{ resource_info.help_text }}</span> |
|
97 |
</span> |
|
98 |
</legend> |
|
99 |
<!-- <div class="form-row"> |
|
100 |
<p class="clearfix"> |
|
101 |
<label for="num_storage">Total storage</label> |
|
102 |
<input type="text" name="num_storage"> |
|
103 |
<span class="extra-img"> </span> |
|
104 |
<span class="info"><em>more info</em><span>Help Text</span></span> |
|
105 |
</p> |
|
106 |
</div>--> |
|
107 |
<!-- |
|
108 |
<div class="double-checks"> |
|
109 |
<label> |
|
110 |
Max {% if resource_info.is_abbreviation %}{{ r|get_value_after_dot|upper }}{% else %}{{ r|get_value_after_dot }}{% endif %}{% if not resource.unit %}s {% endif %} per user |
|
111 |
{% if resource.unit %} |
|
112 |
({{ resource.unit }}) |
|
113 |
{% endif %} |
|
114 |
</label> |
|
115 |
<div class="form-row"> |
|
116 |
<p class="clearfix"> |
|
117 |
<label for="{{r|add:'_unlimited'}}">Unlimited</label> |
|
118 |
<input type="checkbox" id="{{'id_'|add:r|add:'_unlimited'}}" name="{{r|add:'_unlimited'}}_proxy" class="unlimited radio" checked="checked"> |
|
119 |
</p> |
|
120 |
</div> |
|
121 |
<div class="form-row"> |
|
122 |
<p class="clearfix"> |
|
123 |
<label for="{{r|add:'_limited'}}">Limited</label> |
|
124 |
<input type="checkbox" id="id_storage_per_user_limited" name="{{r|add:'_limited'}}_proxy" class="radio limited"> |
|
125 |
<input type="text" |
|
126 |
id="{{'id_'|add:r|add:'_uplimit'}}" |
|
127 |
name="{{r|add:'_uplimit'}}_proxy" |
|
128 |
placeholder="{{ resource_info.placeholder}} " |
|
129 |
{% if resource.unit == 'bytes' %} |
|
130 |
class="dehumanize" |
|
131 |
{% endif %} |
|
132 |
/> |
|
133 |
</p> |
|
134 |
<p class="msg"></p> |
|
135 |
</div> |
|
136 |
|
|
137 |
</div> |
|
138 |
--> |
|
139 |
<div class="form-row"> |
|
140 |
<p class="clearfix"> |
|
141 |
<label for="num_storage"> |
|
142 |
Max {% if resource_info.is_abbreviation %}{{ r|get_value_after_dot|upper }}{% else %}{{ r|get_value_after_dot }}{% endif %}{% if not resource.unit %}s {% endif %} per user |
|
143 |
</label> |
|
144 |
<input type="text" |
|
145 |
id="{{'id_'|add:r|add:'_uplimit'}}_proxy" |
|
146 |
name="{{r|add:'_uplimit'}}_proxy" |
|
147 |
placeholder="{{ resource_info.placeholder}} " |
|
148 |
{% if resource.unit == 'bytes' %} |
|
149 |
class="dehumanize" |
|
150 |
{% endif %} |
|
151 |
/> |
|
152 |
<span class="extra-img"> </span> |
|
153 |
<span class="info"><em>more info</em><span>Help Text</span></span> |
|
154 |
</p> |
|
155 |
<p class="msg"></p> |
|
156 |
</div> |
|
157 |
|
|
158 |
|
|
159 |
</fieldset> |
|
160 |
{% endwith %} |
|
161 |
{% endwith %} |
|
162 |
{% endfor %} |
|
163 |
</div> |
|
164 |
|
|
165 |
{% endfor %} |
|
166 |
</div> |
|
167 |
{% endwith %} |
|
168 |
{% endwith %} |
|
169 |
|
|
170 |
<div class="form-row submit"> |
|
171 |
<input type="submit" value="CONTINUE" class="submit altcol" autocomplete="off"> |
|
172 |
</div> |
|
173 |
</form> |
|
174 |
|
|
175 |
<script> |
|
176 |
|
|
177 |
</script> |
|
178 |
|
|
179 |
{% endblock %} |
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_form_demo_bak.html | ||
---|---|---|
1 |
{% extends "im/account_base.html" %} |
|
2 |
|
|
3 |
{% load filters %} |
|
4 |
{% block headjs %} |
|
5 |
{{ block.super }} |
|
6 |
<script src="{{ IM_STATIC_URL }}js/quotas.js"></script> |
|
7 |
{% endblock %} |
|
8 |
{% block page.body %} |
|
9 |
|
|
10 |
|
|
11 |
<form action="" method="post" class="withlabels quotas-form">{% csrf_token %} |
|
12 |
|
|
13 |
<fieldset class="with-info"> |
|
14 |
<legend> |
|
15 |
1. CREATE GROUP |
|
16 |
<span class="info"> |
|
17 |
<em>more info</em> |
|
18 |
<span>Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text</span> |
|
19 |
</span> |
|
20 |
</legend> |
|
21 |
|
|
22 |
{% include "im/form_render.html" %} |
|
23 |
|
|
24 |
<!-- |
|
25 |
<div class="double-checks"> |
|
26 |
<label>Max users per group</label> |
|
27 |
<div class="form-row"> |
|
28 |
<p class="clearfix"> |
|
29 |
<label for="members_unlimited">Unlimited</label> |
|
30 |
<input type="checkbox" id="members_unlimited" name="members_unlimited" class="unlimited" checked="checked"> |
|
31 |
<span class="info"> |
|
32 |
<em>more info</em> |
|
33 |
<span>Help Text Help Text Help Text Text Help Text Help Text</span> |
|
34 |
</span> |
|
35 |
</p> |
|
36 |
</div> |
|
37 |
<div class="form-row"> |
|
38 |
<p class="clearfix"> |
|
39 |
<label for="members_limited">Limited</label> |
|
40 |
<input type="checkbox" id="members_limited" name="members_limited" class="limited"> |
|
41 |
<input type="text" id="members_uplimit" name="members_uplimit" /> |
|
42 |
|
|
43 |
</p> |
|
44 |
|
|
45 |
</div> |
|
46 |
|
|
47 |
</div> |
|
48 |
--> |
|
49 |
</fieldset> |
|
50 |
|
|
51 |
<fieldset id="icons"> |
|
52 |
<legend> |
|
53 |
2. CHOOSE RESOURCES |
|
54 |
<span class="info"> |
|
55 |
<em>more info</em> |
|
56 |
<span>Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text Help Text</span> |
|
57 |
</span> |
|
58 |
</legend> |
|
59 |
|
|
60 |
{% with resource_catalog|lookup:'resources' as resources %} |
|
61 |
{% with resource_catalog|lookup:'groups' as groups %} |
|
62 |
<ul class="clearfix"> |
|
63 |
{% for g, rs in groups.items %} |
|
64 |
{% with resource_presentation|lookup:g as group_info %} |
|
65 |
<li> |
|
66 |
<a href="#{{ g }}" id="{{'group_'|add:g}}"><img src="/static/im/images/create-{{ g }}.png" alt="vm"/></a> |
|
67 |
<input type="hidden" name="{{ 'is_selected_'|add:g }}" id="{{ 'id_is_selected_'|add:g }}" value="0"> |
|
68 |
<p class="msg">{{ group_info.help_text }}</p> |
|
69 |
</li> |
|
70 |
{% endwith %} |
|
71 |
{% endfor %} |
|
72 |
</ul> |
|
73 |
|
|
74 |
</fieldset> |
|
75 |
|
|
76 |
<div class="foo"> |
|
77 |
|
|
78 |
</div> |
|
79 |
<div class="not-foo"> |
|
80 |
{% for g, rs in groups.items %} |
|
81 |
|
|
82 |
<div class="group {{'group_'|add:g}}" id="{{ g }}"> |
|
83 |
<a href="#icons" class="delete">X remove resource</a> |
|
84 |
{% for r in rs %} |
|
85 |
{% with resource_presentation|lookup:r as resource_info %} |
|
86 |
{% with resources|lookup:r as resource%} |
|
87 |
<fieldset class="quota"> |
|
88 |
<legend> |
|
89 |
{% if resource_info.is_abbreviation %} |
|
90 |
{{ r|get_value_after_dot|upper }} |
|
91 |
{% else %} |
|
92 |
{{ r|get_value_after_dot|capfirst }} |
|
93 |
{% endif %} |
|
94 |
<span class="info"> |
|
95 |
<em>more info</em> |
|
96 |
<span>{{ resource_info.help_text }}</span> |
|
97 |
</span> |
|
98 |
</legend> |
|
99 |
<!-- <div class="form-row"> |
|
100 |
<p class="clearfix"> |
|
101 |
<label for="num_storage">Total storage</label> |
|
102 |
<input type="text" name="num_storage"> |
|
103 |
<span class="extra-img"> </span> |
|
104 |
<span class="info"><em>more info</em><span>Help Text</span></span> |
|
105 |
</p> |
|
106 |
</div>--> |
|
107 |
<!-- |
|
108 |
<div class="double-checks"> |
|
109 |
<label> |
|
110 |
Max {% if resource_info.is_abbreviation %}{{ r|get_value_after_dot|upper }}{% else %}{{ r|get_value_after_dot }}{% endif %}{% if not resource.unit %}s {% endif %} per user |
|
111 |
{% if resource.unit %} |
|
112 |
({{ resource.unit }}) |
|
113 |
{% endif %} |
Also available in: Unified diff