Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
itminedu
synnefo
Commits
48e72b9f
Commit
48e72b9f
authored
Aug 27, 2012
by
Sofia Papagiannaki
Browse files
Progress VII
* add policies during group creation * improve performance (reduce db access)
parent
7585f252
Changes
10
Show whitespace changes
Inline
Side-by-side
snf-astakos-app/astakos/im/context_processors.py
View file @
48e72b9f
...
...
@@ -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
snf-astakos-app/astakos/im/forms.py
View file @
48e72b9f
...
...
@@ -490,53 +490,61 @@ class ExtendedPasswordChangeForm(PasswordChangeForm):
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
)
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
()
class
Meta
:
model
=
AstakosGroup
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'
]
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
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
return
AstakosGroupPolicyCreationForm
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
...
...
snf-astakos-app/astakos/im/management/commands/group_list.py
View file @
48e72b9f
...
...
@@ -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'
):
...
...
snf-astakos-app/astakos/im/models.py
View file @
48e72b9f
...
...
@@ -154,11 +154,9 @@ 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
,
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
):
...
...
@@ -175,9 +173,9 @@ class AstakosGroup(Group):
@
property
def
quota
(
self
):
d
=
{}
d
=
defaultdict
(
int
)
for
q
in
self
.
astakosgroupquota_set
.
all
():
d
[
q
.
resource
.
name
]
=
q
.
limit
d
[
q
.
resource
]
+
=
q
.
limit
return
d
@
property
...
...
@@ -185,6 +183,15 @@ class AstakosGroup(Group):
# 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
):
"""
Extends ``django.contrib.auth.models.User`` by defining additional fields.
...
...
@@ -568,3 +575,7 @@ def superuser_post_save(sender, instance, **kwargs):
create_astakos_user
(
instance
)
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
snf-astakos-app/astakos/im/synnefo_settings.py
View file @
48e72b9f
...
...
@@ -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'
]
...
...
snf-astakos-app/astakos/im/templates/im/astakosgroup_detail.html
View file @
48e72b9f
...
...
@@ -95,16 +95,5 @@
<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 %}
snf-astakos-app/astakos/im/templates/im/astakosgroup_form.html
View file @
48e72b9f
...
...
@@ -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>
...
...
snf-astakos-app/astakos/im/templates/im/astakosgroup_list.html
View file @
48e72b9f
...
...
@@ -14,8 +14,10 @@
</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 %}
...
...
@@ -36,18 +38,21 @@
</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 owner
s
%}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 owner
s
%}
<td>
<form
action=
"{% url group_leave o.id %}"
method=
"post"
class=
"login innerlabels"
>
{% csrf_token %}
<div
class=
"form-row submit clearfix"
>
...
...
@@ -57,7 +62,7 @@
</td>
{% endif %}
{% else %}
{% if user in
o.
members %}
{% if user in members %}
<td>
Pending
</td>
{% else %}
<td>
Not member
</td>
...
...
@@ -76,6 +81,9 @@
{% endif %}
{% endif %}
</tr>
{% endwith %}
{% endwith %}
{% endwith %}
{% endfor %}
</tbody>
</table>
...
...
snf-astakos-app/astakos/im/urls.py
View file @
48e72b9f
...
...
@@ -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'
),
...
...
snf-astakos-app/astakos/im/views.py
View file @
48e72b9f
...
...
@@ -57,7 +57,7 @@ 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
*
...
...
@@ -589,15 +589,69 @@ 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_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
=
A
stakos
G
roup
.
objects
.
filter
(
membership__person
=
request
.
user
)
list
=
request
.
user
.
a
stakos
_g
roup
s
.
select_related
().
all
(
)
return
object_list
(
request
,
queryset
=
list
)
@
signed_terms_required
...
...
@@ -610,32 +664,11 @@ def group_detail(request, group_id):
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
})
extra_context
=
{
'quota'
:
group
.
quota
}
)
@
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
)
@
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
()
...
...
@@ -653,57 +686,87 @@ def group_search(request, extra_context={}, **kwargs):
queryset
=
AstakosGroup
.
objects
.
select_related
().
filter
(
name
=
q
)
f
=
MembershipCreationForm
for
g
in
queryset
:
join_forms
[
g
.
name
]
=
f
(
dict
(
group
=
g
,
join_forms
[
g
.
name
]
=
f
(
dict
(
group
=
g
,
person
=
request
.
user
,
date_requested
=
datetime
.
now
().
strftime
(
"%d/%m/%Y"
)))
return
object_list
(
request
,
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'
,
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
))
context_instance
=
get_context
(
request
)
)
@
signed_terms_required
@
login_required
def
group_join
(
request
,
group_id
):
return
create_object
(
request
,
return
create_object
(
request
,
model
=
Membership
,
template_name
=
'im/astakosgroup_list.html'
,
post_save_redirect
=
reverse
(
'group_detail'
,
kwargs
=
dict
(
group_id
=
group_id
)))
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
,
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
)))
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'
,
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
)
more_policies
=
m
.
group
.
has_undefined_policies
)
return
wrapper
return
decorator
...
...
@@ -738,6 +801,8 @@ def disapprove_member(request, membership):
@
signed_terms_required
@
login_required
def
resource_list
(
request
):
return
render_response
(
template
=
'im/astakosuserquota_list.html'
,
return
render_response
(
template
=
'im/astakosuserquota_list.html'
,
context_instance
=
get_context
(
request
),
quota
=
request
.
user
.
quota
)
\ No newline at end of file
quota
=
request
.
user
.
quota
)
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment