Commit 0d2b3b3b authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

Merge branch 'hotfix-0.14.2' into develop

Conflicts:
	snf-astakos-app/astakos/im/views/projects.py
	snf-cyclades-app/synnefo/logic/backend.py
	snf-django-lib/snf_django/lib/astakos.py
	version
parents a8765f48 7cc443ce
......@@ -514,15 +514,14 @@ def leave_project_checks(project):
def can_leave_request(project, user):
leave_policy = project.application.member_leave_policy
if leave_policy == CLOSED_POLICY:
try:
leave_project_checks(project)
except PermissionDenied:
return False
m = user.get_membership(project)
if m is None:
return False
if m.state != ProjectMembership.ACCEPTED:
return False
return True
return m.can_leave()
def leave_project(project_id, request_user):
......@@ -562,13 +561,13 @@ def join_project_checks(project):
def can_join_request(project, user):
join_policy = project.application.member_join_policy
if join_policy == CLOSED_POLICY:
try:
join_project_checks(project)
except PermissionDenied:
return False
m = user.get_membership(project)
if m:
return False
return True
return not(m)
def join_project(project_id, request_user):
......
......@@ -1915,15 +1915,7 @@ class Project(models.Model):
### Other
def count_pending_memberships(self):
memb_set = self.projectmembership_set
memb_count = memb_set.filter(state=ProjectMembership.REQUESTED).count()
return memb_count
def count_actually_accepted_memberships(self):
memb_set = self.projectmembership_set
memb_count = memb_set.filter(state=ProjectMembership.LEAVE_REQUESTED)
memb_count = memb_set.filter(state=ProjectMembership.ACCEPTED).count()
return memb_count
return self.projectmembership_set.requested().count()
def members_count(self):
return self.approved_memberships.count()
......@@ -1967,7 +1959,7 @@ CHAIN_STATE = {
class ProjectMembershipManager(ForUpdateManager):
def any_accepted(self):
q = self.model.Q_ACTUALLY_ACCEPTED
q = self.model.Q_ACCEPTED_STATES
return self.filter(q)
def actually_accepted(self):
......@@ -2016,7 +2008,7 @@ class ProjectMembership(models.Model):
objects = ProjectMembershipManager()
# Compiled queries
Q_ACCEPTED_STATES = ~Q(state=REQUESTED) & ~Q(state=REMOVED)
Q_ACCEPTED_STATES = Q(state__in=ACCEPTED_STATES)
Q_ACTUALLY_ACCEPTED = Q(state=ACCEPTED) | Q(state=LEAVE_REQUESTED)
MEMBERSHIP_STATE_DISPLAY = {
......
......@@ -358,7 +358,7 @@ def member_action_extra_context(membership, table, col):
_('Are you sure you want to accept this member?')]
confirms = [True, True]
if membership.state in ProjectMembership.ACTUALLY_ACCEPTED:
if membership.state in ProjectMembership.ACCEPTED_STATES:
urls = ['astakos.im.views.project_remove_member']
actions = [_('Remove')]
prompts = [_('Are you sure you want to remove this member?')]
......
......@@ -133,7 +133,7 @@
<dl class="alt-style">
<dt>Max participants</dt>
<dd>
{% if object.limit_on_members_number %}
{% if object.limit_on_members_number != None %}
{{object.limit_on_members_number}}
{% else %}Not set{% endif %}
</dd>
......@@ -150,9 +150,10 @@
<dt><a href="{% url project_approved_members object.chain %}" title="view approved members">Approved members</a></dt>
<dd>{{ approved_members_count }}
<span class="faint">
{% if object.limit_on_members_number %}
({% substract object.limit_on_members_number approved_members_count%} memberships remain)
{% if remaining_memberships_count != None %}
({{ remaining_memberships_count }}
membership{{ remaining_memberships_count|pluralize }}
remain{{ remaining_memberships_count|pluralize:"s," }})
{% else %}&nbsp;{% endif %}
</span>
</dd>
......
......@@ -1336,12 +1336,13 @@ class TestWebloginRedirect(TestCase):
# scheme preserved
self.assertTrue(url.startswith('pithos://localhost/'))
# redirect contains token param
params = urlparse.urlparse(urlparse.urlparse(url).path, 'https').query
params = urlparse.urlparse(url, 'https').query
params = urlparse.parse_qs(params)
self.assertEqual(params['token'][0],
AstakosUser.objects.get().auth_token)
# does not contain uuid
self.assertFalse('uuid' in params)
# reverted for 0.14.2 to support old pithos desktop clients
#self.assertFalse('uuid' in params)
# invalid cases
r = self.client.get(invalid_scheme, follow=True)
......
......@@ -279,13 +279,19 @@ def addmembers(request, chain_id, addmembers_form):
messages.error(request, e)
MEMBERSHIP_STATUS_FILTER = {
0: lambda x: x.requested(),
1: lambda x: x.any_accepted(),
}
def common_detail(request, chain_or_app_id, project_view=True,
template_name='im/projects/project_detail.html',
members_status_filter=None):
project = None
approved_members_count = 0
pending_members_count = 0
remaining_memberships_count = 0
remaining_memberships_count = None
if project_view:
chain_id = chain_or_app_id
if request.method == 'POST':
......@@ -301,18 +307,19 @@ def common_detail(request, chain_or_app_id, project_view=True,
else:
addmembers_form = AddProjectMembersForm() # initialize form
approved_members_count = 0
pending_members_count = 0
remaining_memberships_count = 0
project, application = get_by_chain_or_404(chain_id)
if project:
members = project.projectmembership_set.select_related()
approved_members_count = \
project.count_actually_accepted_memberships()
members = project.projectmembership_set
approved_members_count = project.members_count()
pending_members_count = project.count_pending_memberships()
if members_status_filter in (ProjectMembership.REQUESTED,
ProjectMembership.ACCEPTED):
members = members.filter(state=members_status_filter)
_limit = application.limit_on_members_number
if _limit is not None:
remaining_memberships_count = \
max(0, _limit - approved_members_count)
flt = MEMBERSHIP_STATUS_FILTER.get(members_status_filter)
if flt is not None:
members = flt(members)
members = members.select_related()
members_table = tables.ProjectMembersTable(project,
members,
user=request.user,
......@@ -377,8 +384,8 @@ def common_detail(request, chain_or_app_id, project_view=True,
'can_join_request': can_join_req,
'can_leave_request': can_leave_req,
'members_status_filter': members_status_filter,
})
'remaining_memberships_count': remaining_memberships_count,
})
@require_http_methods(["GET", "POST"])
@cookie_fix
......
......@@ -115,6 +115,7 @@ def login(request):
logger.info('Token reset for %s' % user.username)
parts = list(urlsplit(next))
parts[3] = urlencode({
'uuid': request.user.uuid,
'token': request.user.auth_token
})
url = urlunsplit(parts)
......
......@@ -88,7 +88,7 @@ def modify_limit():
def reconcile():
command = ['snf-manage', 'reconcile-resources-astakos', '--fix']
command = ['snf-manage', 'reconcile-resources-astakos', '--fix', '--force']
print 'Running "%s"...' % ' '.join(command)
r = call(command)
......
......@@ -78,8 +78,7 @@ INSTALL_REQUIRES = [
'astakosclient',
'snf-django-lib',
'snf-branding',
'snf-webproject',
'multiprocessing',
'snf-webproject'
]
EXTRAS_REQUIRES = {
......
......@@ -31,8 +31,11 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
import logging
from astakosclient import AstakosClient
from astakosclient.errors import Unauthorized
from astakosclient.errors import (Unauthorized, NoUUID, NoUserName,
AstakosClientException)
def user_for_token(client, token, usage=False):
......@@ -74,6 +77,10 @@ class UserCache(object):
"""uuid<->displayname user 'cache'"""
def __init__(self, astakos_url, astakos_token, split=100, logger=None):
if logger is None:
logger = logging.getLogger(__name__)
self.logger = logger
self.astakos = AstakosClient(astakos_url, retry=2,
use_pool=True, logger=logger)
self.astakos_token = astakos_token
......@@ -85,36 +92,63 @@ class UserCache(object):
def fetch_names(self, uuid_list):
total = len(uuid_list)
split = self.split
count = 0
for start in range(0, total, split):
end = start + split
try:
names = self.astakos.service_get_usernames(
self.astakos_token, uuid_list[start:end])
count += len(names)
self.users.update(names)
except:
except AstakosClientException:
pass
except Exception as err:
self.logger.error("Unexpected error while fetching "
"user display names: %s" % repr(err))
diff = (total - count)
assert(diff >= 0), "fetched more displaynames than requested"
if diff:
self.logger.debug("Failed to fetch %d displaynames", diff)
def get_uuid(self, name):
uuid = name
if not name in self.users:
try:
self.users[name] = \
self.astakos.service_get_uuid(
self.astakos_token, name)
except:
self.users[name] = name
uuid = self.astakos.service_get_uuid(
self.astakos_token, name)
except NoUUID:
self.logger.debug("Failed to fetch uuid for %s", name)
except AstakosClientException:
pass
except Exception as err:
self.logger.error("Unexpected error while fetching "
"user uuid %s: %s" % (name, repr(err)))
finally:
self.users[name] = uuid
return self.users[name]
def get_name(self, uuid):
"""Do the uuid-to-email resolving"""
name = "-"
if not uuid in self.users:
try:
self.users[uuid] = \
self.astakos.service_get_username(
self.astakos_token, uuid)
except:
self.users[uuid] = "-"
name = self.astakos.service_get_username(
self.astakos_token, uuid)
except NoUserName:
self.logger.debug("Failed to fetch display name for %s", uuid)
except AstakosClientException:
pass
except Exception as err:
self.logger.error("Unexpected error while fetching "
"user displayname %s: %s"
% (uuid, repr(err)))
finally:
self.users[uuid] = name
return self.users[uuid]
......@@ -483,7 +483,6 @@ class Node(DBWorker):
or_(self.nodes.c.parent.in_(select_children),
self.nodes.c.node.in_(select_children)))
s = select([func.sum(self.versions.c.size)])
s = s.group_by(self.versions.c.cluster)
s = s.where(self.nodes.c.node == self.versions.c.node)
s = s.where(self.nodes.c.node.in_(select_descendants))
s = s.where(self.versions.c.cluster == cluster)
......
# This is a comment!
0.14next
0.14.2next
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment