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
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
user.save()
return user
-def get_astakos_group_creation_form(request):
- class AstakosGroupCreationForm(forms.ModelForm):
- issue_date = forms.DateField(widget=SelectDateWidget(), initial=datetime.now())
- # TODO set initial in exact one month
- expiration_date = forms.DateField(widget=SelectDateWidget(), 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='')
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
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))
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'):
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)
@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):
"""
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
'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'
]
<p>No policies</p>
{% endif %}
</div>
- {% if user in object.owner.all and more_policies %}
- <div class="rightcol">
- <form action="{% url group_policies_add object.id %}" method="post" class="innerlabels signup">{% csrf_token %}
- <h2><span>NEW POLICY</span></h2>
- {% include "im/form_render.html" %}
- <div class="form-row submit">
- <input type="submit" class="submit altcol" value="+" />
- </div>
- </form>
- </div>
- {% endif %}
</div>
{% endblock %}
<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>
</form>
{% else %}
<p class="submit-rt">
- <a href="{% url group_add %}" class="submit">Create a group</a>
- <a href="{% url group_search %}" class="submit">Join a group</a>
+ {% for gname in group_kinds %}
+ <a href="{% url group_add gname %}" class="submit">Create {{gname}}</a>
+ {% endfor %}
+ <a href="{% url group_search %}" class="submit">Join group</a>
</p>
{% endif %}
{% if object_list %}
</thead>
<tbody>
{% for o in object_list %}
+ {% with o.owner.all as owners %}
+ {% with o.members as members %}
+ {% with o.approved_members as approved_members %}
<tr>
<td><a class="extra-link" href="{% url group_detail o.id %}">{{o.name}}</a></td>
<td>{{o.kind}}</td>
<td>{{o.issue_date|date:"d/m/Y"}}</td>
<td>{{o.expiration_date|date:"d/m/Y"}}</td>
- <td>{% if user in o.owner.all %}Yes{% else %}No{% endif %}</td>
- <td>{{ o.approved_members|length }}/{{ o.members|length }}</td>
+ <td>{% if user in owners %}Yes{% else %}No{% endif %}</td>
+ <td>{{ approved_members|length }}/{{ members|length }}</td>
<td>{% if o.is_enabled %}Yes{% else %}No{% endif %}</td>
<td>{% if o.moderation_enabled%}Yes{% else %}No{% endif %}</td>
- {% if user in o.approved_members %}
+ {% if user in approved_members %}
<td>Active</td>
- {% if user not in o.owner.all %}
+ {% if user not in owners %}
<td>
<form action="{% url group_leave o.id %}" method="post"class="login innerlabels">{% csrf_token %}
<div class="form-row submit clearfix">
</td>
{% endif %}
{% else %}
- {% if user in o.members %}
+ {% if user in members %}
<td>Pending</td>
{% else %}
<td>Not member</td>
{% endif %}
{% endif %}
</tr>
+ {% endwith %}
+ {% endwith %}
+ {% endwith %}
{% endfor %}
</tbody>
</table>
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'),
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 *
@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_name=None,
+ template_loader=loader
+ extra_context=None
+ post_save_redirect='/im/group/%(id)s/'
+ login_required=False
+ context_processors=None
+ model, form_class = get_model_and_form_class(
+ model=None,
+ form_class=AstakosGroupCreationForm
+ )
+ # TODO better approach???
+ resources = dict( (str(r.id), r) for r in Resource.objects.select_related().all() )
+ if request.method == 'POST':
+ form = form_class(request.POST, request.FILES, resources=resources)
+ if form.is_valid():
+ new_object = form.save()
+ new_object.owners = [request.user]
+ for (rid, limit) in form.resources():
+ try:
+ r = resources[rid]
+ except KeyError, e:
+ logger.exception(e)
+ # Should I stay or should I go???
+ continue
+ else:
+ new_object.astakosgroupquota_set.create(
+ resource = r,
+ limit = limit
+ )
+ msg = _("The %(verbose_name)s was created successfully.") %\
+ {"verbose_name": model._meta.verbose_name}
+ messages.success(request, msg, 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()
return object_list(request, queryset=list)
@signed_terms_required
except AstakosGroup.DoesNotExist:
return HttpResponseBadRequest(_('Invalid group.'))
return object_detail(request,
- AstakosGroup.objects.all(),
- object_id=group_id,
- extra_context = {'form':get_astakos_group_policy_creation_form(group),
- 'quota':group.quota,
- 'more_policies':group.has_undefined_policies})
-
-@signed_terms_required
-@login_required
-def group_policies_list(request, group_id):
- list = AstakosGroupQuota.objects.filter(group__id=group_id)
- return object_list(request, queryset=list)
+ AstakosGroup.objects.all(),
+ object_id=group_id,
+ extra_context = {'quota':group.quota}
+ )
@signed_terms_required
@login_required
-def group_policies_add(request, group_id):
- try:
- group = AstakosGroup.objects.select_related().get(id=group_id)
- except AstakosGroup.DoesNotExist:
- return HttpResponseBadRequest(_('Invalid group.'))
- return create_object(request,
- form_class=get_astakos_group_policy_creation_form(group),
- template_name = 'im/astakosgroup_detail.html',
- post_save_redirect = reverse('group_detail', kwargs=dict(group_id=group_id)),
- extra_context = {'group':group,
- 'quota':group.quota,
- 'more_policies':group.has_undefined_policies})
-@signed_terms_required
-@login_required
def group_approval_request(request, group_id):
return HttpResponse()
queryset = AstakosGroup.objects.select_related().filter(name=q)
f = MembershipCreationForm
for g in queryset:
- join_forms[g.name] = f(dict(group=g,
- person=request.user,
- date_requested=datetime.now().strftime("%d/%m/%Y")))
- return object_list(request,
- queryset,
- template_name='im/astakosgroup_list.html',
- extra_context=dict(form=form, is_search=True, join_forms=join_forms))
- return render_response(template='im/astakosgroup_list.html',
- form = form,
- context_instance=get_context(request))
+ join_forms[g.name] = f(
+ dict(
+ group=g,
+ person=request.user,
+ date_requested=datetime.now().strftime("%d/%m/%Y")
+ )
+ )
+ return object_list(
+ request,
+ queryset,
+ template_name='im/astakosgroup_list.html',
+ extra_context=dict(
+ form=form,
+ is_search=True,
+ join_forms=join_forms
+ )
+ )
+ return render_response(
+ template='im/astakosgroup_list.html',
+ form = form,
+ context_instance=get_context(request)
+ )
@signed_terms_required
@login_required
def group_join(request, group_id):
- return create_object(request,
- model=Membership,
- template_name='im/astakosgroup_list.html',
- post_save_redirect = reverse('group_detail', kwargs=dict(group_id=group_id)))
+ return create_object(
+ request,
+ model=Membership,
+ template_name='im/astakosgroup_list.html',
+ post_save_redirect = reverse(
+ 'group_detail',
+ kwargs=dict(group_id=group_id)
+ )
+ )
@signed_terms_required
@login_required
def group_leave(request, group_id):
try:
- m = Membership.objects.select_related().get(group__id=group_id, person=request.user)
+ m = Membership.objects.select_related().get(
+ group__id=group_id,
+ person=request.user
+ )
except Membership.DoesNotExist:
return HttpResponseBadRequest(_('Invalid membership.'))
if request.user in m.group.owner.all():
return HttpResponseForbidden(_('Owner can not leave the group.'))
- return delete_object(request,
- model=Membership,
- object_id = m.id,
- template_name='im/astakosgroup_list.html',
- post_delete_redirect = reverse('group_detail', kwargs=dict(group_id=group_id)))
+ return delete_object(
+ request,
+ model=Membership,
+ object_id = m.id,
+ template_name='im/astakosgroup_list.html',
+ post_delete_redirect = reverse(
+ 'group_detail',
+ kwargs=dict(group_id=group_id)
+ )
+ )
def handle_membership():
def decorator(func):
@wraps(func)
def wrapper(request, group_id, user_id):
try:
- m = Membership.objects.select_related().get(group__id=group_id, person__id=user_id)
+ m = Membership.objects.select_related().get(
+ group__id=group_id,
+ person__id=user_id
+ )
except Membership.DoesNotExist:
return HttpResponseBadRequest(_('Invalid membership.'))
else:
if request.user not in m.group.owner.all():
return HttpResponseForbidden(_('User is not a group owner.'))
func(request, m)
- return render_response(template='im/astakosgroup_detail.html',
- context_instance=get_context(request),
- object=m.group,
- quota=m.group.quota,
- more_policies=m.group.has_undefined_policies)
+ return render_response(
+ template='im/astakosgroup_detail.html',
+ context_instance=get_context(request),
+ object=m.group,
+ quota=m.group.quota,
+ more_policies=m.group.has_undefined_policies
+ )
return wrapper
return decorator
@signed_terms_required
@login_required
def resource_list(request):
- return render_response(template='im/astakosuserquota_list.html',
- context_instance=get_context(request),
- quota=request.user.quota)
\ No newline at end of file
+ return render_response(
+ template='im/astakosuserquota_list.html',
+ context_instance=get_context(request),
+ quota=request.user.quota
+ )
\ No newline at end of file