Commit 8fbcaab3 authored by Olga Brani's avatar Olga Brani
Browse files

Merge branch '0.6.4' of https://code.grnet.gr/git/astakos into 0.6.4

Conflicts:
	snf-astakos-app/astakos/im/forms.py
	snf-astakos-app/astakos/im/templates/im/astakosgroup_detail.html
	snf-astakos-app/astakos/im/templates/im/astakosgroup_list.html
parents 43562af8 6a5e73b4
......@@ -104,7 +104,7 @@ class ActivationBackend(object):
def handle_activation(self, user, \
activation_template_name='im/activation_email.txt', \
greeting_template_name='im/welcome_email.txt', \
admin_email_template_name='im/admin_notification.txt', \
admin_email_template_name='im/account_notification.txt', \
switch_accounts_email_template_name='im/switch_accounts_email.txt'):
"""
If the user is already active returns immediately.
......@@ -132,7 +132,11 @@ class ActivationBackend(object):
send_activation(user, activation_template_name)
return VerificationSent()
else:
send_admin_notification(user, admin_email_template_name)
send_admin_notification(
template_name=admin_email_template_name,
dictionary={'user':user, 'group_creation':True},
subject='%s alpha2 testing account notification' % SITENAME
)
return NotificationSent()
except BaseException, e:
logger.exception(e)
......
......@@ -36,6 +36,7 @@ from astakos.im.settings import IM_MODULES, INVITATIONS_ENABLED, IM_STATIC_URL,
GLOBAL_MESSAGES, PROFILE_EXTRA_LINKS
from astakos.im.api import get_menu
from astakos.im.util import get_query
from astakos.im.models import GroupKind
from django.conf import settings
from django.core.urlresolvers import reverse
......@@ -79,3 +80,6 @@ def menu(request):
for item in menu_items:
item['is_active'] = absolute(request.path) == item['url']
return {'menu':menu_items}
def group_kinds(request):
return {'group_kinds': GroupKind.objects.exclude(name='default').values_list('name', flat=True)}
\ No newline at end of file
......@@ -490,56 +490,61 @@ class ExtendedPasswordChangeForm(PasswordChangeForm):
user.save()
return user
from django.conf import settings
settings.DATE_FORMAT = '%d/%m/%Y'
settings.DATE_INPUT_FORMATS = ['%d/%m/%Y']
def get_astakos_group_creation_form(request):
class AstakosGroupCreationForm(forms.ModelForm):
issue_date = forms.DateField( initial=datetime.now())
# TODO set initial in exact one month
expiration_date = forms.DateField( initial = datetime.now() + timedelta(days=30))
kind = forms.ModelChoiceField(queryset=GroupKind.objects.all(), empty_label=None)
name = forms.URLField()
class Meta:
model = AstakosGroup
def __init__(self, *args, **kwargs):
super(AstakosGroupCreationForm, self).__init__(*args, **kwargs)
self.fields.keyOrder = ['kind', 'name', 'desc', 'issue_date',
'expiration_date', 'estimated_participants',
'moderation_enabled']
def save(self, commit=True):
g = super(AstakosGroupCreationForm, self).save(commit=False)
if commit:
g.save()
g.owner = [request.user]
g.approve_member(request.user)
return g
class AstakosGroupCreationForm(forms.ModelForm):
# issue_date = forms.DateField(widget=SelectDateWidget())
# expiration_date = forms.DateField(widget=SelectDateWidget())
kind = forms.ModelChoiceField(
queryset=GroupKind.objects.all(),
label="",
widget=forms.HiddenInput()
)
name = forms.URLField()
return AstakosGroupCreationForm
def get_astakos_group_policy_creation_form(astakosgroup):
class AstakosGroupPolicyCreationForm(forms.ModelForm):
choices = Resource.objects.filter(~Q(astakosgroup=astakosgroup))
resource = forms.ModelChoiceField(queryset=choices, empty_label=None)
# TODO check that it does not hit the db
group = forms.ModelChoiceField(queryset=AstakosGroup.objects.all(), initial=astakosgroup, widget=forms.HiddenInput())
class Meta:
model = AstakosGroupQuota
class Meta:
model = AstakosGroup
return AstakosGroupPolicyCreationForm
def __init__(self, *args, **kwargs):
try:
resources = kwargs.pop('resources')
except KeyError:
resources = {}
super(AstakosGroupCreationForm, self).__init__(*args, **kwargs)
self.fields.keyOrder = ['kind', 'name', 'desc', 'issue_date',
'expiration_date', 'estimated_participants',
'moderation_enabled']
for id, r in resources.iteritems():
self.fields['resource_%s' % id] = forms.IntegerField(
label=r,
required=False,
help_text=_('Leave it blank for no additional quota.')
)
def resources(self):
for name, value in self.cleaned_data.items():
prefix, delimiter, suffix = name.partition('resource_')
if suffix:
# yield only those having a value
if not value:
continue
yield (suffix, value)
class AstakosGroupSearchForm(forms.Form):
q = forms.CharField(max_length=200, label='Group Identifier')
q = forms.CharField(max_length=200, label='')
class MembershipCreationForm(forms.ModelForm):
# TODO check not to hit the db
group = forms.ModelChoiceField(queryset=AstakosGroup.objects.all(), widget=forms.HiddenInput())
person = forms.ModelChoiceField(queryset=AstakosUser.objects.all(), widget=forms.HiddenInput())
date_requested = forms.DateField(widget=forms.HiddenInput(), input_formats="%d/%m/%Y")
group = forms.ModelChoiceField(
queryset=AstakosGroup.objects.all(),
widget=forms.HiddenInput()
)
person = forms.ModelChoiceField(
queryset=AstakosUser.objects.all(),
widget=forms.HiddenInput()
)
date_requested = forms.DateField(
widget=forms.HiddenInput(),
input_formats="%d/%m/%Y"
)
class Meta:
model = Membership
......
......@@ -105,30 +105,29 @@ def send_activation(user, template_name='im/activation_email.txt'):
user.activation_sent = datetime.now()
user.save()
def send_admin_notification(user, template_name='im/admin_notification.txt'):
def send_admin_notification(template_name,
dictionary={},
subject='alpha2 testing notification',
):
"""
Send email to DEFAULT_ADMIN_EMAIL to notify for a new user registration.
Send notification email to DEFAULT_ADMIN_EMAIL.
Raises SendNotificationError
"""
if not DEFAULT_ADMIN_EMAIL:
return
message = render_to_string(template_name, {
'user': user,
'baseurl': BASEURL,
'site_name': SITENAME,
'support': DEFAULT_CONTACT_EMAIL})
message = render_to_string(template_name, dictionary)
sender = DEFAULT_FROM_EMAIL
try:
send_mail('%s alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_ADMIN_EMAIL])
send_mail(subject, message, sender, [DEFAULT_ADMIN_EMAIL])
except (SMTPException, socket.error) as e:
logger.exception(e)
raise SendNotificationError()
else:
msg = 'Sent admin notification for user %s' % user.email
msg = 'Sent admin notification for user %s' % dictionary
logger._log(LOGGING_LEVEL, msg, [])
def send_helpdesk_notification(user, template_name='im/helpdesk_notification.txt'):
def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
"""
Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
......@@ -136,19 +135,23 @@ def send_helpdesk_notification(user, template_name='im/helpdesk_notification.txt
"""
if not DEFAULT_CONTACT_EMAIL:
return
message = render_to_string(template_name, {
'user': user,
'baseurl': BASEURL,
'site_name': SITENAME,
'support': DEFAULT_ADMIN_EMAIL})
message = render_to_string(
template_name,
{'user': user}
)
sender = DEFAULT_FROM_EMAIL
try:
send_mail('%s alpha2 testing account activated' % SITENAME, message, sender, [DEFAULT_CONTACT_EMAIL])
send_mail(
'%s alpha2 testing account activated' % SITENAME,
message,
sender,
[DEFAULT_CONTACT_EMAIL]
)
except (SMTPException, socket.error) as e:
logger.exception(e)
raise SendNotificationError()
else:
msg = 'Sent helpdesk admin notification for user %s' % user.email
msg = 'Sent helpdesk admin notification for %s' % user.email
logger._log(LOGGING_LEVEL, msg, [])
def send_invitation(invitation, template_name='im/invitation.txt'):
......
......@@ -65,8 +65,8 @@ class Command(BaseCommand):
if options.get('pending'):
groups = filter(lambda g: g.is_disabled, groups)
labels = ('id', 'name', 'enabled', 'permissions')
columns = (3, 12, 12, 50)
labels = ('id', 'name', 'enabled', 'moderation', 'permissions')
columns = (3, 25, 12, 12, 50)
if not options.get('csv'):
line = ' '.join(l.rjust(w) for l, w in zip(labels, columns))
......@@ -78,6 +78,7 @@ class Command(BaseCommand):
fields = ( str(group.id),
group.name,
format_bool(group.is_enabled),
format_bool(group.moderation_enabled),
','.join(p.codename for p in group.permissions.all()))
if options.get('csv'):
......
......@@ -103,7 +103,7 @@ class Command(BaseCommand):
if options['active']:
user.is_active = True
if options['admin']:
user.is_admin = True
user.is_superuser = True
try:
user.save()
......
......@@ -154,12 +154,10 @@ class AstakosGroup(Group):
self.save()
def approve_member(self, person):
try:
self.membership_set.create(person=person, date_joined=datetime.now())
except IntegrityError:
m = self.membership_set.get(person=person)
m.date_joined = datetime.now()
m.save()
m, created = self.membership_set.get_or_create(person=person)
# update date_joined in any case
m.date_joined=datetime.now()
m.save()
def disapprove_member(self, person):
self.membership_set.remove(person=person)
......@@ -175,15 +173,24 @@ class AstakosGroup(Group):
@property
def quota(self):
d = {}
for q in self.astakosgroupquota_set.all():
d[q.resource.name] = q.limit
d = defaultdict(int)
for q in self.astakosgroupquota_set.all():
d[q.resource] += q.limit
return d
@property
def has_undefined_policies(self):
# TODO: can avoid query?
return Resource.objects.filter(~Q(astakosgroup=self)).exists()
@property
def owners(self):
return self.owner.all()
@owners.setter
def owners(self, l):
self.owner = l
map(self.approve_member, l)
class AstakosUser(User):
"""
......@@ -325,7 +332,7 @@ class AstakosUser(User):
logger._log(LOGGING_LEVEL, msg, [])
def __unicode__(self):
return self.username
return '%s (%s)' % (self.realname, self.email)
def conflicting_email(self):
q = AstakosUser.objects.exclude(username = self.username)
......@@ -567,4 +574,8 @@ def superuser_post_save(sender, instance, **kwargs):
if instance.is_superuser:
create_astakos_user(instance)
post_save.connect(superuser_post_save, sender=User)
\ No newline at end of file
post_save.connect(superuser_post_save, sender=User)
def get_resources():
# use cache
return Resource.objects.select_related().all()
\ No newline at end of file
......@@ -57,6 +57,7 @@ context_processors = [
'astakos.im.context_processors.invitations',
'astakos.im.context_processors.menu',
'astakos.im.context_processors.custom_messages',
'astakos.im.context_processors.group_kinds',
'synnefo.lib.context_processors.cloudbar'
]
......
--- A translation in English follows ---
{% if group_creation %}
Έχει δημιουργηθεί ο παρακάτω λογαριασμός:
{% else %}
Έχει ενεργοποιηθεί ο παρακάτω λογαριασμός:
{% endif %}
Email: {{user.email}}
First name: {{user.first_name}}
......@@ -9,10 +13,16 @@ Is active: {{user.is_active}}
Level: {{user.level}}
Invitations: {{user.invitations}}
{% if group_creation %}
Για την ενεργοποίησή του μπορείτε να χρησιμοποιήσετε το command line εργαλείο snf-manage user_send_activation
{% endif %}
--
{% if group_creation %}
The following account has been created:
{% else %}
The following account has been activated:
{% endif %}
Email: {{user.email}}
First name: {{user.first_name}}
......@@ -21,4 +31,6 @@ Is active: {{user.is_active}}
Level: {{user.level}}
Invitations: {{user.invitations}}
{% if group_creation %}
For its activation you can use the command line tool snf-manage user_send_activation
{% endif %}
\ No newline at end of file
......@@ -96,21 +96,6 @@
{% else %}
<p>No members yet!</p>
{% endif %}
</div>
{% if user in object.owner.all and more_policies %}
<div class="full-dotted">
<form action="{% url group_policies_add object.id %}" method="post" class="withlabels">{% csrf_token %}
<h2>NEW POLICY</h2>
{% include "im/form_render.html" %}
<div class="form-row submit">
<input type="submit" class="submit altcol" value="ADD POLICY" />
</div>
</form>
</div>
{% endif %}
</div>
</div>
{% endblock %}
......@@ -7,7 +7,7 @@
<h2><span>NEW GROUP</span></h2>
{% include "im/form_render.html" %}
<div class="form-row submit">
<input type="submit" class="submit altcol" value="ADD POLICIES" />
<input type="submit" class="submit altcol" value="SUBMIT" />
</div>
</form>
</div>
......
......@@ -5,12 +5,8 @@
{% block page.body %}
<div class="maincol {% block innerpage.class %}{% endblock %}">
{% if form %}
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p>
<p>You can use the following form to search for a project:</p>
<form action="{% url group_search %}" method="post" class="withlabels">{% csrf_token %}
<form action="{% url group_search %}" method="post" class="innerlabels signup">{% csrf_token %}
<h2><span>Search group:</span></h2>
{% include "im/form_render.html" %}
<div class="form-row submit">
<input type="submit" class="submit altcol" value="SEARCH" />
......@@ -144,6 +140,5 @@
<h2>No groups found!</h2>
{% endif %}
{% endif %}
</div>
</div>
{% endblock %}
--- A translation in English follows ---
Έχει δημιουργηθεί το παρακάτω group:
Id: {{group.id}}}
Name: {{group.name}}
Type: {{group.kind}}
Issue date: {{group.issue_date|date:"d/m/Y"}}
Expiration date: {{group.expiration_date|date:"d/m/Y"}}
Moderation: {{group.moderation_enabled}}
Owner: {{owner}}
Policies:
{% for p in policies %}
{{p}}
{% endfor %}
Για την ενεργοποίησή του μπορείτε να χρησιμοποιήσετε το command line εργαλείο:
snf-manage group_update <group_id> --enable
--
The following account has been created:
Id: {{group.id}}}
Name: {{group.name}}
Type: {{group.kind}}
Issue date: {{group.issue_date|date:"d/m/Y"}}
Expiration date: {{group.expiration_date|date:"d/m/Y"}}
Moderation: {{group.moderation_enabled}}
Owner: {{owner}}
Policies:
{% for p in policies %}
{{p}}
{% endfor %}
For its activation you can use the command line tool:
snf-manage group_update <group_id> --enable
......@@ -50,11 +50,9 @@ urlpatterns = patterns('astakos.im.views',
url(r'^approval_terms/(?P<term_id>\d+)/?$', 'approval_terms'),
url(r'^password/?$', 'change_password', {}, name='password_change'),
url(r'^resources/?$', 'resource_list', {}, name='resource_list'),
url(r'^group/add/?$', 'group_add', {}, name='group_add'),
url(r'^group/add/(?P<kind_name>\w+)?$', 'group_add', {}, name='group_add'),
url(r'^group/list/?$', 'group_list', {}, name='group_list'),
url(r'^group/(?P<group_id>\d+)/?$', 'group_detail', {}, name='group_detail'),
#url(r'^group/(?P<group_id>\d+)/policies/list/?$', 'group_policies_list', {}, name='group_policies_list'),
url(r'^group/(?P<group_id>\d+)/policies/add/?$', 'group_policies_add', {}, name='group_policies_add'),
url(r'^group/search/?$', 'group_search', {}, name='group_search'),
url(r'^group/(?P<group_id>\d+)/join/?$', 'group_join', {}, name='group_join'),
url(r'^group/(?P<group_id>\d+)/leave/?$', 'group_leave', {}, name='group_leave'),
......
......@@ -57,12 +57,13 @@ from django.utils.translation import ugettext as _
from django.views.generic.create_update import *
from django.views.generic.list_detail import *
from astakos.im.models import AstakosUser, Invitation, ApprovalTerms, AstakosGroup
from astakos.im.models import AstakosUser, Invitation, ApprovalTerms, AstakosGroup, Resource
from astakos.im.activation_backends import get_backend, SimpleBackend
from astakos.im.util import get_context, prepare_response, set_cookie, get_query
from astakos.im.forms import *
from astakos.im.functions import send_greeting, send_feedback, SendMailError, \
invite as invite_func, logout as auth_logout, activate as activate_func, switch_account_to_shibboleth
invite as invite_func, logout as auth_logout, activate as activate_func, \
switch_account_to_shibboleth, send_admin_notification, SendNotificationError
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, LOGOUT_NEXT, LOGGING_LEVEL
logger = logging.getLogger(__name__)
......@@ -455,10 +456,19 @@ def activate(request, greeting_email_template_name='im/welcome_email.txt', helpd
return index(request)
try:
local_user = AstakosUser.objects.get(~Q(id = user.id), email=user.email, is_active=True)
local_user = AstakosUser.objects.get(
~Q(id = user.id),
email=user.email,
is_active=True
)
except AstakosUser.DoesNotExist:
try:
activate_func(user, greeting_email_template_name, helpdesk_email_template_name, verify_email=True)
activate_func(
user,
greeting_email_template_name,
helpdesk_email_template_name,
verify_email=True
)
response = prepare_response(request, user, next, renew=True)
transaction.commit()
return response
......@@ -475,7 +485,11 @@ def activate(request, greeting_email_template_name='im/welcome_email.txt', helpd
return index(request)
else:
try:
user = switch_account_to_shibboleth(user, local_user, greeting_email_template_name)
user = switch_account_to_shibboleth(
user,
local_user,
greeting_email_template_name
)
response = prepare_response(request, user, next, renew=True)
transaction.commit()
return response
......@@ -589,15 +603,85 @@ def change_email(request, activation_key=None,
@signed_terms_required
@login_required
def group_add(request):
return create_object(request,
form_class=get_astakos_group_creation_form(request),
post_save_redirect = '/im/group/%(id)s/')
def group_add(request, kind_name='default'):
try:
kind = GroupKind.objects.get(name = kind_name)
except:
return HttpResponseBadRequest(_('No such group kind'))
template_loader=loader
post_save_redirect='/im/group/%(id)s/'
context_processors=None
model, form_class = get_model_and_form_class(
model=None,
form_class=AstakosGroupCreationForm
)
resources = dict( (str(r.id), r) for r in Resource.objects.select_related().all() )
policies = []
if request.method == 'POST':
form = form_class(request.POST, request.FILES, resources=resources)
if form.is_valid():
new_object = form.save()
# save owner
new_object.owners = [request.user]
# save quota policies
for (rid, limit) in form.resources():
try:
r = resources[rid]
except KeyError, e:
logger.exception(e)
# TODO Should I stay or should I go???
continue
else:
new_object.astakosgroupquota_set.create(
resource = r,
limit = limit
)
policies.append('%s %d' % (r, limit))
msg = _("The %(verbose_name)s was created successfully.") %\
{"verbose_name": model._meta.verbose_name}
messages.success(request, msg, fail_silently=True)
# send notification
try:
send_admin_notification(
template_name='im/group_creation_notification.txt',
dictionary={
'group':new_object,
'owner':request.user,
'policies':policies,
},
subject='%s alpha2 testing group creation notification' % SITENAME
)
except SendNotificationError, e:
messages.error(request, e, fail_silently=True)
return redirect(post_save_redirect, new_object)
else:
now = datetime.now()
data = {
'kind':kind,
'issue_date':now,
'expiration_date':now + timedelta(days=30)
}
form = form_class(data, resources=resources)
# Create the template, context, response
template_name = "%s/%s_form.html" % (
model._meta.app_label,
model._meta.object_name.lower()
)
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'form': form
}, context_processors)
return HttpResponse(t.render(c))
@signed_terms_required
@login_required
def group_list(request):
list = AstakosGroup.objects.filter(membership__person=request.user)
list = request.user.astakos_groups.select_related().all()