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
b17f9027
Commit
b17f9027
authored
Dec 03, 2012
by
Olga Brani
Browse files
Bug fixes
Style improvents Authorisation methods page
parent
b655c9c1
Changes
9
Hide whitespace changes
Inline
Side-by-side
snf-astakos-app/astakos/im/static/im/css/modules.css
View file @
b17f9027
...
...
@@ -458,8 +458,6 @@ form.quotas-form legend span.info span { width:395px; }
.stats
.green
.img-wrap
{
background-position
:
-263px
7px
;
}
.projects
.editable
form
textarea
{
width
:
70%
;
height
:
50px
;
max-width
:
70%
;
width
:
270px
;
height
:
120px
;}
/* temp style to hide extra menu for groups */
.navigation
ul
+
ul
{
display
:
none
;
}
table
.msg-wrap
{
position
:
relative
;
}
table
.msg-wrap
.dialog
{
position
:
absolute
;
border
:
1px
dashed
#ccc
;
padding
:
15px
;
width
:
200px
;
bottom
:
30px
;
left
:
0
;
background
:
#fff
;
display
:
none
;
}
...
...
@@ -487,8 +485,17 @@ form.quotas-form span.error-msg:hover em { background-position:-58px -3px; }
.content
.how-it-works
a
.submit
:focus
{
border-color
:
#B3B3B3
}
.content
.how-it-works
a
.submit
:focus:hover
{
border-color
:
#55B577
}
.auth_methods
{
margin
:
3em
0
;
}
.auth_methods
.wrap
{
}
.auth_methods
h2
{
font-size
:
1.154em
;
}
.auth_methods
table
{
width
:
100%
;
color
:
#222
;
margin
:
1em
0
;
}
.auth_methods
table
th
{
font-weight
:
normal
;
color
:
#3582AC
}
\ No newline at end of file
.auth_methods
ul
{
margin
:
1em
0
;
padding
:
0
;
list-style
:
none
outside
none
;
}
.auth_methods
ul
li
{
margin
:
0
0
1em
0
;
padding
:
0
;
list-style
:
none
outside
none
;
font-size
:
1.154em
;
}
.auth_methods
ul
li
>
a
{
padding-right
:
20px
;
background
:
url(../images/arrow-down_green.png)
no-repeat
center
right
;
color
:
#55B577
}
.auth_methods
ul
li
>
a
.up
{
background-image
:
url(../images/arrow-up_green.png)
;
}
.auth_methods
ul
li
.wrap
{
font-size
:
0.867em
;
margin-top
:
1em
;
display
:
none
;
}
.auth_methods
ul
li
.actions
a
{
margin-right
:
20px
;
}
.auth_methods
ul
li
a
.red
{
color
:
#F24E53
;
}
.auth_methods
ul
.notassigned
{
margin-top
:
3em
;
}
.auth_methods
ul
.notassigned
li
>
a
{
background
:
transparent
;
color
:
#F89A1C
}
.auth_methods
.dialog-wrap
{
display
:
inline
;
position
:
relative
;
}
.auth_methods
.dialog
{
background
:
#fff
;
border
:
1px
dashed
#ccc
;
position
:
absolute
;
bottom
:
30px
;
left
:
0
;
padding
:
15px
;
width
:
220px
;
display
:
none
;}
.auth_methods
.dialog
.submit
{
min-width
:
30px
;
padding
:
5px
22px
;
}
.content
input
:-webkit-autofill
{
background
:
transparent
;
}
snf-astakos-app/astakos/im/static/im/images/arrow-down_green.png
0 → 100644
View file @
b17f9027
236 Bytes
snf-astakos-app/astakos/im/static/im/images/arrow-down_yellow.png
0 → 100644
View file @
b17f9027
248 Bytes
snf-astakos-app/astakos/im/static/im/images/arrow-up_green.png
0 → 100644
View file @
b17f9027
238 Bytes
snf-astakos-app/astakos/im/static/im/js/common.js
View file @
b17f9027
...
...
@@ -288,6 +288,34 @@ $(document).ready(function() {
$
(
'
.hidden-submit .form-row.submit
'
).
show
(
500
);
});
$
(
'
.auth_methods
'
).
find
(
'
li>a
'
).
click
(
function
(
e
){
e
.
preventDefault
();
$
(
this
).
siblings
(
'
.wrap
'
).
toggle
(
'
slow
'
);
$
(
this
).
toggleClass
(
'
up
'
);
});
$
(
'
.auth_methods a.red
'
).
click
(
function
(
e
){
e
.
preventDefault
();
$
(
this
).
siblings
(
'
.dialog
'
).
show
();
})
$
(
'
.auth_methods .dialog .no
'
).
click
(
function
(
e
){
e
.
preventDefault
();
console
.
log
(
$
(
this
));
$
(
this
).
parents
(
'
.dialog
'
).
hide
();
})
setTimeout
(
function
()
{
if
(
$
(
'
input#id_username
'
).
val
()){
$
(
'
input#id_username
'
).
siblings
(
'
label
'
).
css
(
'
opacity
'
,
'
0
'
);
};
if
(
$
(
'
input#id_password
'
).
val
()){
$
(
'
input#id_password
'
).
siblings
(
'
label
'
).
css
(
'
opacity
'
,
'
0
'
);
}
},
100
);
});
$
(
window
).
resize
(
function
()
{
...
...
snf-astakos-app/astakos/im/templates/im/invitations.html
View file @
b17f9027
{% extends "im/account_base.html" %}
{% block page.body %}
<div
class=
"full
bottom-bordered
clearfix"
>
<div
class=
"full clearfix"
>
<div
class=
"lt-div"
>
<p>
Invite someone else
</p>
</div>
...
...
@@ -22,7 +22,7 @@
</div>
<div
class=
"full
{% block innerpage.class %}{% endblock %}
"
>
<div
class=
"full
full-dotted
"
>
<h2>
You have
<em>
{{ inviter.invitations }}
</em>
invitation{{ inviter.invitations|pluralize }} left.
</h2>
{% if sent|length %}
...
...
snf-astakos-app/astakos/im/templates/im/profile.html
View file @
b17f9027
...
...
@@ -13,58 +13,64 @@
<input
type=
"hidden"
name=
"auth"
value=
"{{ user.auth_token }}"
>
<input
type=
"submit"
class=
"submit altcol"
value=
"UPDATE"
/>
</div>
</form>
<div
class=
"auth_methods"
>
<br
/><br
/>
<div
class=
"assigned"
>
<h4>
Authentication methods
</h4>
<p>
You can login to your account using the following methods
</p>
<ul
class=
"auth_providers"
>
{% for provider in user_providers %}
<li>
<h2>
{{ provider.settings.title }}
<span
class=
"actions"
style=
"margin-left: 40px"
>
{% for name, url in provider.settings.extra_actions %}
<a
href=
"{{ url }}"
title=
"{{ name }}"
>
{{ name }}
</a>
{% endfor %}
{% if provider.can_remove %}
<a
href=
"{% url remove_auth_provider provider.pk %}"
title=
"disble"
>
Remove
</a>
{% endif %}
</span>
</h2>
<p>
{{ provider.details_display }}
</p>
<br
/>
</li>
{% empty %}
<li>
No available authentication methods
</li>
{% endfor %}
</ul>
</div>
<div
class=
"notassigned"
>
<p>
You can add the following authentication methods to your account
</p>
<ul
class=
"auth_providers"
>
{% for provider in user_available_providers %}
<li>
<h2><a
href=
"{{ provider.add_url }}"
>
{{ provider.title }}
</a></h2>
<p>
{{ provider.add_description }}
</p>
<br
/>
</li>
{% empty %}
No available providers.
{% endfor %}
</ul>
</div>
<div
class=
"full-dotted"
>
<div
class=
"auth_methods"
>
<h2>
ENABLED AUTHENTICATION METHODS
</h2>
<ul>
{% for provider in user_providers %}
<li>
<a
href=
"#"
>
{{ provider.settings.title }}
</a>
<div
class=
"wrap"
>
<p>
{{ provider.details_display }}
</p>
<div
class=
"actions"
>
{% for name, url in provider.settings.extra_actions %}
<a
href=
"{{ url }}"
title=
"{{ name }}"
>
{{ name }}
</a>
{% endfor %}
{% if provider.can_remove %}
<div
class=
"dialog-wrap"
>
<a
href=
"#"
title=
"disable"
class=
"red"
>
Disable x
</a>
<div
class=
"dialog"
>
Are you sure you want to disable this method?
<a
href=
"{% url remove_auth_provider provider.pk %}"
class=
"yes submit"
>
Yes
</a>
<a
href=
"#"
class=
"no submit"
>
No
</a>
</div>
</div>
{% endif %}
</div>
</div>
</li>
{% empty %}
<li>
No available authentication methods
</li>
{% endfor %}
</ul>
<ul
class=
"notassigned"
>
<li>
<a
href=
"#"
>
+ Add new authentication method
</a>
<div
class=
"wrap"
>
{% for provider in user_available_providers %}
<p><a
href=
"{{ provider.add_url }}"
>
{{ provider.title }}
</a>
( {{ provider.add_description }})
</p>
{% empty %}
No available providers
{% endfor %}
</div>
</li>
</ul>
</div>
</div>
</form>
<div
class=
"two-cols-links"
>
<p><a
href=
"{% url password_change %}"
>
Change Password
</a></p>
<p>
<a
href=
"https://okeanos.grnet.gr/home/"
>
Back to ~okeanos
</a>
<a
href=
"https://cyclades.okeanos.grnet.gr/ui/"
>
Take me to cyclades
</a>
<a
href=
"https://pithos.okeanos.grnet.gr/ui/"
>
Take me to pithos+
</a>
</p>
<div
class=
"full-dotted"
>
<ul
class=
"options"
>
<li><a
href=
"https://okeanos.grnet.gr/home/"
class=
"blue"
>
Back to ~okeanos >
</a></li>
<li><a
href=
"https://cyclades.okeanos.grnet.gr/ui/"
class=
"blue"
>
Take me to cyclades >
</a></li>
<li><a
href=
"https://pithos.okeanos.grnet.gr/ui/"
class=
"blue"
>
Take me to pithos+ >
</a></li>
</ul>
</div>
{% endblock body %}
snf-astakos-app/astakos/im/templates/im/profile_bak.html
0 → 100644
View file @
b17f9027
{% extends "im/account_base.html" %}
{% block body %}
<form
action=
{%url
edit_profile
%}
method=
"post"
class=
"withlabels hidden-submit"
>
{% csrf_token %}
{% with profile_form as form %}
{% include "im/form_render.html" %}
{% endwith %}
<div
class=
"form-row submit"
>
<input
type=
"hidden"
name=
"next"
value=
"{{ next }}"
>
<input
type=
"hidden"
name=
"auth"
value=
"{{ user.auth_token }}"
>
<input
type=
"submit"
class=
"submit altcol"
value=
"UPDATE"
/>
</div>
<div
class=
"auth_methods"
>
<br
/><br
/>
<div
class=
"assigned"
>
<h2><a
href=
"#"
>
Available authentication methods
</a></h2>
<p>
You can login to your account using the following methods
</p>
<ul
class=
"auth_providers"
>
{% for provider in user_providers %}
<li>
<h2>
{{ provider.settings.title }}
<span
class=
"actions"
style=
"margin-left: 40px"
>
{% for name, url in provider.settings.extra_actions %}
<a
href=
"{{ url }}"
title=
"{{ name }}"
>
{{ name }}
</a>
{% endfor %}
{% if provider.can_remove %}
<a
href=
"{% url remove_auth_provider provider.pk %}"
title=
"disble"
>
Remove
</a>
{% endif %}
</span>
</h2>
<p>
{{ provider.details_display }}
</p>
<br
/>
</li>
{% empty %}
<li>
No available authentication methods
</li>
{% endfor %}
</ul>
</div>
<div
class=
"notassigned"
>
<p>
You can add the following authentication methods to your account
</p>
<ul
class=
"auth_providers"
>
{% for provider in user_available_providers %}
<li>
<h2><a
href=
"{{ provider.add_url }}"
>
{{ provider.title }}
</a></h2>
<p>
{{ provider.add_description }}
</p>
<br
/>
</li>
{% empty %}
No available providers.
{% endfor %}
</ul>
</div>
</div>
</form>
<div
class=
"two-cols-links"
>
<p><a
href=
"{% url password_change %}"
>
Change Password
</a></p>
<p>
<a
href=
"https://okeanos.grnet.gr/home/"
>
Back to ~okeanos
</a>
<a
href=
"https://cyclades.okeanos.grnet.gr/ui/"
>
Take me to cyclades
</a>
<a
href=
"https://pithos.okeanos.grnet.gr/ui/"
>
Take me to pithos+
</a>
</p>
</div>
{% endblock body %}
snf-astakos-app/astakos/im/views.py
View file @
b17f9027
...
...
@@ -57,6 +57,7 @@ from django.views.generic.create_update import (delete_object,
get_model_and_form_class
)
from
django.views.generic.list_detail
import
object_list
from
django.core.xheaders
import
populate_xheaders
from
django.core.exceptions
import
ValidationError
,
PermissionDenied
from
django.template.loader
import
render_to_string
from
django.views.decorators.http
import
require_http_methods
...
...
@@ -64,7 +65,7 @@ from astakos.im.activation_backends import get_backend, SimpleBackend
from
astakos.im.models
import
(
AstakosUser
,
ApprovalTerms
,
AstakosGroup
,
EmailChange
,
GroupKind
,
Membership
,
RESOURCE_SEPARATOR
)
RESOURCE_SEPARATOR
,
AstakosUserAuthProvider
)
from
astakos.im.util
import
get_context
,
prepare_response
,
get_query
,
restrict_next
from
astakos.im.forms
import
(
LoginForm
,
InvitationForm
,
ProfileForm
,
FeedbackForm
,
SignApprovalTermsForm
,
...
...
@@ -87,6 +88,8 @@ from astakos.im.tasks import request_billing
from
astakos.im.api.callpoint
import
AstakosCallpoint
import
astakos.im.messages
as
astakos_messages
from
astakos.im
import
settings
from
astakos.im
import
auth_providers
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -109,6 +112,26 @@ def render_response(template, tab=None, status=200, context_instance=None, **kwa
response
=
HttpResponse
(
html
,
status
=
status
)
return
response
def
requires_auth_provider
(
provider_id
,
**
perms
):
"""
"""
def
decorator
(
func
,
*
args
,
**
kwargs
):
@
wraps
(
func
)
def
wrapper
(
request
,
*
args
,
**
kwargs
):
provider
=
auth_providers
.
get_provider
(
provider_id
)
if
not
provider
or
not
provider
.
is_active
():
raise
PermissionDenied
if
provider
:
for
pkey
,
value
in
perms
.
iteritems
():
attr
=
'is_available_for_%s'
%
pkey
.
lower
()
if
getattr
(
provider
,
attr
)()
!=
value
:
raise
PermissionDenied
return
func
(
request
,
*
args
)
return
wrapper
return
decorator
def
requires_anonymous
(
func
):
"""
...
...
@@ -169,7 +192,7 @@ def index(request, login_template_name='im/login.html', profile_template_name='i
template_name
=
login_template_name
if
request
.
user
.
is_authenticated
():
return
HttpResponseRedirect
(
reverse
(
'astakos.im.views.edit_profile'
))
return
render_response
(
template_name
,
login_form
=
LoginForm
(
request
=
request
),
...
...
@@ -319,11 +342,19 @@ def edit_profile(request, template_name='im/profile.html', extra_context=None):
except
ValueError
,
ve
:
messages
.
success
(
request
,
ve
)
elif
request
.
method
==
"GET"
:
if
not
request
.
user
.
is_verified
:
request
.
user
.
is_verified
=
True
request
.
user
.
save
()
request
.
user
.
is_verified
=
True
request
.
user
.
save
()
# existing providers
user_providers
=
request
.
user
.
get_active_auth_providers
()
# providers that user can add
user_available_providers
=
request
.
user
.
get_available_auth_providers
()
return
render_response
(
template_name
,
profile_form
=
form
,
user_providers
=
user_providers
,
user_available_providers
=
user_available_providers
,
context_instance
=
get_context
(
request
,
extra_context
))
...
...
@@ -370,6 +401,9 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
return
HttpResponseRedirect
(
reverse
(
'edit_profile'
))
provider
=
get_query
(
request
).
get
(
'provider'
,
'local'
)
if
not
auth_providers
.
get_provider
(
provider
).
is_available_for_create
():
raise
PermissionDenied
id
=
get_query
(
request
).
get
(
'id'
)
try
:
instance
=
AstakosUser
.
objects
.
get
(
id
=
id
)
if
id
else
None
...
...
@@ -390,7 +424,9 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
result
=
backend
.
handle_activation
(
user
)
status
=
messages
.
SUCCESS
message
=
result
.
message
user
.
save
()
form
.
store_user
(
user
,
request
)
if
'additional_email'
in
form
.
cleaned_data
:
additional_email
=
form
.
cleaned_data
[
'additional_email'
]
if
additional_email
!=
user
.
email
:
...
...
@@ -406,6 +442,7 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
transaction
.
commit
()
return
response
messages
.
add_message
(
request
,
status
,
message
)
transaction
.
commit
()
return
render_response
(
on_success
,
context_instance
=
get_context
(
...
...
@@ -655,6 +692,10 @@ def change_email(request, activation_key=None,
def
send_activation
(
request
,
user_id
,
template_name
=
'im/login.html'
,
extra_context
=
None
):
if
settings
.
MODERATION_ENABLED
:
raise
PermissionDenied
extra_context
=
extra_context
or
{}
try
:
u
=
AstakosUser
.
objects
.
get
(
id
=
user_id
)
...
...
@@ -677,107 +718,107 @@ def send_activation(request, user_id, template_name='im/login.html', extra_conte
)
class
ResourcePresentation
():
def
__init__
(
self
,
data
):
self
.
data
=
data
def
update_from_result
(
self
,
result
):
if
result
.
is_success
:
for
r
in
result
.
data
:
rname
=
'%s%s%s'
%
(
r
.
get
(
'service'
),
RESOURCE_SEPARATOR
,
r
.
get
(
'name'
))
if
not
rname
in
self
.
data
[
'resources'
]:
self
.
data
[
'resources'
][
rname
]
=
{}
self
.
data
[
'resources'
][
rname
].
update
(
r
)
self
.
data
[
'resources'
][
rname
][
'id'
]
=
rname
group
=
r
.
get
(
'group'
)
if
not
group
in
self
.
data
[
'groups'
]:
self
.
data
[
'groups'
][
group
]
=
{}
self
.
data
[
'groups'
][
r
.
get
(
'group'
)].
update
({
'name'
:
r
.
get
(
'group'
)})
def
test
(
self
,
quota_dict
):
for
k
,
v
in
quota_dict
.
iteritems
():
rname
=
k
value
=
v
if
not
rname
in
self
.
data
[
'resources'
]:
self
.
data
[
'resources'
][
rname
]
=
{}
self
.
data
[
'resources'
][
rname
][
'value'
]
=
value
def
update_from_result_report
(
self
,
result
):
if
result
.
is_success
:
for
r
in
result
.
data
:
rname
=
r
.
get
(
'name'
)
if
not
rname
in
self
.
data
[
'resources'
]:
self
.
data
[
'resources'
][
rname
]
=
{}
self
.
data
[
'resources'
][
rname
].
update
(
r
)
self
.
data
[
'resources'
][
rname
][
'id'
]
=
rname
group
=
r
.
get
(
'group'
)
if
not
group
in
self
.
data
[
'groups'
]:
self
.
data
[
'groups'
][
group
]
=
{}
self
.
data
[
'groups'
][
r
.
get
(
'group'
)].
update
({
'name'
:
r
.
get
(
'group'
)})
def
get_group_resources
(
self
,
group
):
return
dict
(
filter
(
lambda
t
:
t
[
1
].
get
(
'group'
)
==
group
,
self
.
data
[
'resources'
].
iteritems
()))
def
get_groups_resources
(
self
):
for
g
in
self
.
data
[
'groups'
]:
yield
g
,
self
.
get_group_resources
(
g
)
def
get_quota
(
self
,
group_quotas
):
for
r
,
v
in
group_quotas
.
iteritems
():
rname
=
str
(
r
)
quota
=
self
.
data
[
'resources'
].
get
(
rname
)
quota
[
'value'
]
=
v
yield
quota
def
get_policies
(
self
,
policies_data
):
for
policy
in
policies_data
:
rname
=
'%s%s%s'
%
(
policy
.
get
(
'service'
),
RESOURCE_SEPARATOR
,
policy
.
get
(
'resource'
))
policy
.
update
(
self
.
data
[
'resources'
].
get
(
rname
))
yield
policy
def
__repr__
(
self
):
return
self
.
data
.
__repr__
()
def
__iter__
(
self
,
*
args
,
**
kwargs
):
return
self
.
data
.
__iter__
(
*
args
,
**
kwargs
)
def
__getitem__
(
self
,
*
args
,
**
kwargs
):
return
self
.
data
.
__getitem__
(
*
args
,
**
kwargs
)
def
get
(
self
,
*
args
,
**
kwargs
):
return
self
.
data
.
get
(
*
args
,
**
kwargs
)
@
require_http_methods
([
"GET"
,
"POST"
])
@
signed_terms_required
@
login_required
def
group_add
(
request
,
kind_name
=
'default'
):
result
=
callpoint
.
list_resources
()
resource_catalog
=
ResourcePresentation
(
RESOURCES_PRESENTATION_DATA
)
resource_catalog
.
update_from_result
(
result
)
if
not
result
.
is_success
:
messages
.
error
(
request
,
'Unable to retrieve system resources: %s'
%
result
.
reason
)
try
:
kind
=
GroupKind
.
objects
.
get
(
name
=
kind_name
)
except
:
return
HttpResponseBadRequest
(
_
(
astakos_messages
.
GROUPKIND_UNKNOWN
))
post_save_redirect
=
'/im/group/%(id)s/'
context_processors
=
None
...
...
@@ -785,7 +826,7 @@ def group_add(request, kind_name='default'):
model
=
None
,
form_class
=
AstakosGroupCreationForm
)
if
request
.
method
==
'POST'
:
form
=
form_class
(
request
.
POST
,
request
.
FILES
)
if
form
.
is_valid
():
...
...
@@ -796,7 +837,7 @@ def group_add(request, kind_name='default'):
policies
=
resource_catalog
.
get_policies
(
form
.
policies
()),
resource_catalog
=
resource_catalog
,
)
else
:
now
=
datetime
.
now
()
data
=
{
...
...
@@ -806,7 +847,7 @@ def group_add(request, kind_name='default'):
data
[
'is_selected_%s'
%
group
]
=
False
for
resource
in
resources
:
data
[
'%s_uplimit'
%
resource
]
=
''
form
=
form_class
(
data
)
# Create the template, context, response
...
...
@@ -839,7 +880,7 @@ def group_add_complete(request):
msg
=
_
(
astakos_messages
.
OBJECT_CREATED
)
%
\
{
"verbose_name"
:
model
.
_meta
.
verbose_name
}
messages
.
success
(
request
,
msg
,
fail_silently
=
True
)
# send notification
try
:
send_group_creation_notification
(
...
...
@@ -857,7 +898,7 @@ def group_add_complete(request):
else
:
d
=
{
"verbose_name"
:
model
.
_meta
.
verbose_name
,
"reason"
:
result
.
reason
}
msg
=
_
(
astakos_messages
.
OBJECT_CREATED_FAILED
)
%
d
msg
=
_
(
astakos_messages
.
OBJECT_CREATED_FAILED
)
%
d
messages
.
error
(
request
,
msg
,
fail_silently
=
True
)
return
render_response
(
template
=
'im/astakosgroup_form_summary.html'
,
...
...
@@ -895,17 +936,17 @@ def group_list(request):
im_astakosuser_owner.astakosgroup_id = im_astakosgroup.group_ptr_id)
LEFT JOIN auth_user as owner ON (
im_astakosuser_owner.astakosuser_id = owner.id)
WHERE im_membership.person_id = %s
WHERE im_membership.person_id = %s
"""
%
(
DB_REPLACE_GROUP_SCHEME
,
request
.
user
.
id
,
request
.
user
.
id
)
if
sorting
:
query
=
query
+
" ORDER BY %s ASC"
%
sorting
query
=
query
+
" ORDER BY %s ASC"
%
sorting
else
:
query
=
query
+
" ORDER BY groupname ASC"
query
=
query
+
" ORDER BY groupname ASC"
q
=
AstakosGroup
.
objects
.
raw
(
query
)
# Create the template, context, response
template_name
=
"%s/%s_list.html"
%
(
q
.
model
.
_meta
.
app_label
,
...
...
@@ -987,21 +1028,21 @@ def group_detail(request, group_id):
form
=
MembersSortForm
({
'sort_by'
:
sorting
})
if
form
.
is_valid
():
sorting
=
form
.
cleaned_data
.
get
(
'sort_by'
)