Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ b1cb2583

History | View | Annotate | Download (33.4 kB)

1 abd8467c Giorgos Korfiatis
# Copyright 2011, 2012, 2013 GRNET S.A. All rights reserved.
2 5ce3ce4f Sofia Papagiannaki
#
3 f36af44a Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 f36af44a Antony Chazapis
# without modification, are permitted provided that the following
5 f36af44a Antony Chazapis
# conditions are met:
6 5ce3ce4f Sofia Papagiannaki
#
7 f36af44a Antony Chazapis
#   1. Redistributions of source code must retain the above
8 f36af44a Antony Chazapis
#      copyright notice, this list of conditions and the following
9 f36af44a Antony Chazapis
#      disclaimer.
10 5ce3ce4f Sofia Papagiannaki
#
11 f36af44a Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 f36af44a Antony Chazapis
#      copyright notice, this list of conditions and the following
13 f36af44a Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 f36af44a Antony Chazapis
#      provided with the distribution.
15 5ce3ce4f Sofia Papagiannaki
#
16 f36af44a Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 f36af44a Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 f36af44a Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 f36af44a Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 f36af44a Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 f36af44a Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 f36af44a Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 f36af44a Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 f36af44a Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 f36af44a Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 f36af44a Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 f36af44a Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 5ce3ce4f Sofia Papagiannaki
#
29 f36af44a Antony Chazapis
# The views and conclusions contained in the software and
30 f36af44a Antony Chazapis
# documentation are those of the authors and should not be
31 f36af44a Antony Chazapis
# interpreted as representing official policies, either expressed
32 f36af44a Antony Chazapis
# or implied, of GRNET S.A.
33 f36af44a Antony Chazapis
34 f36af44a Antony Chazapis
import logging
35 f36af44a Antony Chazapis
36 f36af44a Antony Chazapis
from django.utils.translation import ugettext as _
37 f9224cc0 Sofia Papagiannaki
from django.core.mail import send_mail, get_connection
38 f36af44a Antony Chazapis
from django.core.urlresolvers import reverse
39 8998f09a Sofia Papagiannaki
from django.contrib.auth import login as auth_login, logout as auth_logout
40 3c22bad0 Giorgos Korfiatis
from django.db.models import Q
41 27e26a41 Sofia Papagiannaki
42 734107ef Kostas Papadimitriou
from synnefo_branding.utils import render_to_string
43 734107ef Kostas Papadimitriou
44 d2c9adac Christos Stavrakakis
from synnefo.lib import join_urls
45 8998f09a Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation, ProjectMembership, \
46 1b52192e Giorgos Korfiatis
    ProjectApplication, Project, new_chain, Resource, ProjectLock
47 8998f09a Sofia Papagiannaki
from astakos.im.quotas import qh_sync_user, get_pending_app_quota, \
48 8998f09a Sofia Papagiannaki
    register_pending_apps, qh_sync_project, qh_sync_locked_users, \
49 8998f09a Sofia Papagiannaki
    get_users_for_update, members_to_sync
50 8998f09a Sofia Papagiannaki
from astakos.im.project_notif import membership_change_notify, \
51 8998f09a Sofia Papagiannaki
    membership_enroll_notify, membership_request_notify, \
52 8998f09a Sofia Papagiannaki
    membership_leave_request_notify, application_submit_notify, \
53 8998f09a Sofia Papagiannaki
    application_approve_notify, application_deny_notify, \
54 e872c133 Giorgos Korfiatis
    project_termination_notify, project_suspension_notify, \
55 e872c133 Giorgos Korfiatis
    project_unsuspension_notify, project_reinstatement_notify
56 0a7a4104 Kostas Papadimitriou
from astakos.im import settings
57 8998f09a Sofia Papagiannaki
58 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
59 f36af44a Antony Chazapis
60 f36af44a Antony Chazapis
logger = logging.getLogger(__name__)
61 f36af44a Antony Chazapis
62 5ce3ce4f Sofia Papagiannaki
63 bf0c6de5 Sofia Papagiannaki
def login(request, user):
64 bf0c6de5 Sofia Papagiannaki
    auth_login(request, user)
65 c3c2212a Sofia Papagiannaki
    from astakos.im.models import SessionCatalog
66 c3c2212a Sofia Papagiannaki
    SessionCatalog(
67 c0b26605 Sofia Papagiannaki
        session_key=request.session.session_key,
68 c3c2212a Sofia Papagiannaki
        user=user
69 c3c2212a Sofia Papagiannaki
    ).save()
70 5df4c364 Kostas Papadimitriou
    logger.info('%s logged in.', user.log_display)
71 5df4c364 Kostas Papadimitriou
72 bf0c6de5 Sofia Papagiannaki
73 5df4c364 Kostas Papadimitriou
def logout(request, *args, **kwargs):
74 5df4c364 Kostas Papadimitriou
    user = request.user
75 5df4c364 Kostas Papadimitriou
    auth_logout(request, *args, **kwargs)
76 5764728a Sofia Papagiannaki
    user.delete_online_access_tokens()
77 5df4c364 Kostas Papadimitriou
    logger.info('%s logged out.', user.log_display)
78 111f3da6 Sofia Papagiannaki
79 5ce3ce4f Sofia Papagiannaki
80 683cf244 Sofia Papagiannaki
def send_verification(user, template_name='im/activation_email.txt'):
81 f36af44a Antony Chazapis
    """
82 683cf244 Sofia Papagiannaki
    Send email to user to verify his/her email and activate his/her account.
83 f36af44a Antony Chazapis
    """
84 e3ff6830 Georgios D. Tsoukalas
    url = join_urls(settings.BASE_HOST,
85 e3ff6830 Georgios D. Tsoukalas
                    user.get_activation_url(nxt=reverse('index')))
86 683cf244 Sofia Papagiannaki
    message = render_to_string(template_name, {
87 5ce3ce4f Sofia Papagiannaki
                               'user': user,
88 5ce3ce4f Sofia Papagiannaki
                               'url': url,
89 6c7af65c Georgios D. Tsoukalas
                               'baseurl': settings.BASE_URL,
90 8998f09a Sofia Papagiannaki
                               'site_name': settings.SITENAME,
91 8998f09a Sofia Papagiannaki
                               'support': settings.CONTACT_EMAIL})
92 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
93 cfb7dd4f Giorgos Korfiatis
    send_mail(_(astakos_messages.VERIFICATION_EMAIL_SUBJECT), message, sender,
94 cfb7dd4f Giorgos Korfiatis
              [user.email],
95 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
96 e7cb4085 Kostas Papadimitriou
    logger.info("Sent user verirfication email: %s", user.log_display)
97 683cf244 Sofia Papagiannaki
98 5ce3ce4f Sofia Papagiannaki
99 9a06d96f Olga Brani
def _send_admin_notification(template_name,
100 e7cb4085 Kostas Papadimitriou
                             context=None,
101 e7cb4085 Kostas Papadimitriou
                             user=None,
102 e7cb4085 Kostas Papadimitriou
                             msg="",
103 9a06d96f Olga Brani
                             subject='alpha2 testing notification',):
104 683cf244 Sofia Papagiannaki
    """
105 e7cb4085 Kostas Papadimitriou
    Send notification email to settings.HELPDESK + settings.MANAGERS +
106 e7cb4085 Kostas Papadimitriou
    settings.ADMINS.
107 683cf244 Sofia Papagiannaki
    """
108 e7cb4085 Kostas Papadimitriou
    if context is None:
109 e7cb4085 Kostas Papadimitriou
        context = {}
110 e7cb4085 Kostas Papadimitriou
    if not 'user' in context:
111 e7cb4085 Kostas Papadimitriou
        context['user'] = user
112 e7cb4085 Kostas Papadimitriou
113 e7cb4085 Kostas Papadimitriou
    message = render_to_string(template_name, context)
114 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
115 e7cb4085 Kostas Papadimitriou
    recipient_list = [e[1] for e in settings.HELPDESK +
116 e7cb4085 Kostas Papadimitriou
                      settings.MANAGERS + settings.ADMINS]
117 e7cb4085 Kostas Papadimitriou
    send_mail(subject, message, sender, recipient_list,
118 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
119 e7cb4085 Kostas Papadimitriou
    if user:
120 e7cb4085 Kostas Papadimitriou
        msg = 'Sent admin notification (%s) for user %s' % (msg,
121 e7cb4085 Kostas Papadimitriou
                                                            user.log_display)
122 8f5a3a06 Sofia Papagiannaki
    else:
123 e7cb4085 Kostas Papadimitriou
        msg = 'Sent admin notification (%s)' % msg
124 683cf244 Sofia Papagiannaki
125 8998f09a Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg)
126 5ce3ce4f Sofia Papagiannaki
127 e7cb4085 Kostas Papadimitriou
128 e7cb4085 Kostas Papadimitriou
def send_account_pending_moderation_notification(
129 e7cb4085 Kostas Papadimitriou
        user,
130 e7cb4085 Kostas Papadimitriou
        template_name='im/account_pending_moderation_notification.txt'):
131 e7cb4085 Kostas Papadimitriou
    """
132 e7cb4085 Kostas Papadimitriou
    Notify admins that a new user has verified his email address and moderation
133 e7cb4085 Kostas Papadimitriou
    step is required to activate his account.
134 e7cb4085 Kostas Papadimitriou
    """
135 cfb7dd4f Giorgos Korfiatis
    subject = (_(astakos_messages.ACCOUNT_CREATION_SUBJECT) %
136 cfb7dd4f Giorgos Korfiatis
               {'user': user.email})
137 e7cb4085 Kostas Papadimitriou
    return _send_admin_notification(template_name, {}, subject=subject,
138 e7cb4085 Kostas Papadimitriou
                                    user=user, msg="account creation")
139 9a06d96f Olga Brani
140 9a06d96f Olga Brani
141 e7cb4085 Kostas Papadimitriou
def send_account_activated_notification(
142 e7cb4085 Kostas Papadimitriou
        user,
143 e7cb4085 Kostas Papadimitriou
        template_name='im/account_activated_notification.txt'):
144 a0be6a0c Sofia Papagiannaki
    """
145 e7cb4085 Kostas Papadimitriou
    Send email to settings.HELPDESK + settings.MANAGERES + settings.ADMINS
146 e7cb4085 Kostas Papadimitriou
    lists to notify that a new account has been accepted and activated.
147 a0be6a0c Sofia Papagiannaki
    """
148 3abf6c78 Sofia Papagiannaki
    message = render_to_string(
149 3abf6c78 Sofia Papagiannaki
        template_name,
150 3abf6c78 Sofia Papagiannaki
        {'user': user}
151 3abf6c78 Sofia Papagiannaki
    )
152 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
153 e7cb4085 Kostas Papadimitriou
    recipient_list = [e[1] for e in settings.HELPDESK +
154 e7cb4085 Kostas Papadimitriou
                      settings.MANAGERS + settings.ADMINS]
155 cfb7dd4f Giorgos Korfiatis
    send_mail(_(astakos_messages.HELPDESK_NOTIFICATION_EMAIL_SUBJECT) %
156 cfb7dd4f Giorgos Korfiatis
              {'user': user.email},
157 e7cb4085 Kostas Papadimitriou
              message, sender, recipient_list, connection=get_connection())
158 d59f5608 Sofia Papagiannaki
    msg = 'Sent helpdesk admin notification for %s'
159 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, user.email)
160 a0be6a0c Sofia Papagiannaki
161 5ce3ce4f Sofia Papagiannaki
162 683cf244 Sofia Papagiannaki
def send_invitation(invitation, template_name='im/invitation.txt'):
163 683cf244 Sofia Papagiannaki
    """
164 683cf244 Sofia Papagiannaki
    Send invitation email.
165 683cf244 Sofia Papagiannaki
    """
166 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.INVITATION_EMAIL_SUBJECT)
167 8c8e318d Kostas Papadimitriou
    url = '%s?code=%d' % (join_urls(settings.BASE_HOST,
168 8c8e318d Kostas Papadimitriou
                                    reverse('index')), invitation.code)
169 aab4d540 Sofia Papagiannaki
    message = render_to_string(template_name, {
170 5ce3ce4f Sofia Papagiannaki
                               'invitation': invitation,
171 5ce3ce4f Sofia Papagiannaki
                               'url': url,
172 6c7af65c Georgios D. Tsoukalas
                               'baseurl': settings.BASE_URL,
173 8998f09a Sofia Papagiannaki
                               'site_name': settings.SITENAME,
174 8998f09a Sofia Papagiannaki
                               'support': settings.CONTACT_EMAIL})
175 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
176 e7cb4085 Kostas Papadimitriou
    send_mail(subject, message, sender, [invitation.username],
177 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
178 d59f5608 Sofia Papagiannaki
    msg = 'Sent invitation %s'
179 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, invitation)
180 e7cb4085 Kostas Papadimitriou
    inviter_invitations = invitation.inviter.invitations
181 e7cb4085 Kostas Papadimitriou
    invitation.inviter.invitations = max(0, inviter_invitations - 1)
182 e7cb4085 Kostas Papadimitriou
    invitation.inviter.save()
183 683cf244 Sofia Papagiannaki
184 5ce3ce4f Sofia Papagiannaki
185 683cf244 Sofia Papagiannaki
def send_greeting(user, email_template_name='im/welcome_email.txt'):
186 683cf244 Sofia Papagiannaki
    """
187 e7cb4085 Kostas Papadimitriou
    Send welcome email to an accepted/activated user.
188 5ce3ce4f Sofia Papagiannaki

189 f36af44a Antony Chazapis
    Raises SMTPException, socket.error
190 f36af44a Antony Chazapis
    """
191 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.GREETING_EMAIL_SUBJECT)
192 f36af44a Antony Chazapis
    message = render_to_string(email_template_name, {
193 5ce3ce4f Sofia Papagiannaki
                               'user': user,
194 8c8e318d Kostas Papadimitriou
                               'url': join_urls(settings.BASE_HOST,
195 8c8e318d Kostas Papadimitriou
                                                reverse('index')),
196 6c7af65c Georgios D. Tsoukalas
                               'baseurl': settings.BASE_URL,
197 8998f09a Sofia Papagiannaki
                               'site_name': settings.SITENAME,
198 8998f09a Sofia Papagiannaki
                               'support': settings.CONTACT_EMAIL})
199 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
200 e7cb4085 Kostas Papadimitriou
    send_mail(subject, message, sender, [user.email],
201 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
202 d59f5608 Sofia Papagiannaki
    msg = 'Sent greeting %s'
203 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, user.log_display)
204 8f5a3a06 Sofia Papagiannaki
205 5ce3ce4f Sofia Papagiannaki
206 8f5a3a06 Sofia Papagiannaki
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
207 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.FEEDBACK_EMAIL_SUBJECT)
208 7d145e78 Sofia Papagiannaki
    from_email = settings.SERVER_EMAIL
209 0a7a4104 Kostas Papadimitriou
    recipient_list = [e[1] for e in settings.HELPDESK]
210 8f5a3a06 Sofia Papagiannaki
    content = render_to_string(email_template_name, {
211 8f5a3a06 Sofia Papagiannaki
        'message': msg,
212 8f5a3a06 Sofia Papagiannaki
        'data': data,
213 8f5a3a06 Sofia Papagiannaki
        'user': user})
214 e182fc26 Sofia Papagiannaki
    send_mail(subject, content, from_email, recipient_list,
215 e182fc26 Sofia Papagiannaki
              connection=get_connection())
216 d59f5608 Sofia Papagiannaki
    msg = 'Sent feedback from %s'
217 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, user.log_display)
218 f36af44a Antony Chazapis
219 5ce3ce4f Sofia Papagiannaki
220 d59f5608 Sofia Papagiannaki
def send_change_email(ec, request,
221 d59f5608 Sofia Papagiannaki
                      email_template_name=
222 d59f5608 Sofia Papagiannaki
                      'registration/email_change_email.txt'):
223 e182fc26 Sofia Papagiannaki
    url = ec.get_url()
224 e182fc26 Sofia Papagiannaki
    url = request.build_absolute_uri(url)
225 80a548e3 Christos Stavrakakis
    c = {'url': url,
226 80a548e3 Christos Stavrakakis
         'site_name': settings.SITENAME,
227 8fb8d0cf Giorgos Korfiatis
         'support': settings.CONTACT_EMAIL,
228 734107ef Kostas Papadimitriou
         'ec': ec}
229 734107ef Kostas Papadimitriou
    message = render_to_string(email_template_name, c)
230 e182fc26 Sofia Papagiannaki
    from_email = settings.SERVER_EMAIL
231 cfb7dd4f Giorgos Korfiatis
    send_mail(_(astakos_messages.EMAIL_CHANGE_EMAIL_SUBJECT), message,
232 cfb7dd4f Giorgos Korfiatis
              from_email,
233 734107ef Kostas Papadimitriou
              [ec.new_email_address], connection=get_connection())
234 d59f5608 Sofia Papagiannaki
    msg = 'Sent change email for %s'
235 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, ec.user.log_display)
236 f36af44a Antony Chazapis
237 5ce3ce4f Sofia Papagiannaki
238 73fbaec4 Sofia Papagiannaki
def invite(inviter, email, realname):
239 73fbaec4 Sofia Papagiannaki
    inv = Invitation(inviter=inviter, username=email, realname=realname)
240 73fbaec4 Sofia Papagiannaki
    inv.save()
241 73fbaec4 Sofia Papagiannaki
    send_invitation(inv)
242 e30537f1 Sofia Papagiannaki
    inviter.invitations = max(0, inviter.invitations - 1)
243 73fbaec4 Sofia Papagiannaki
    inviter.save()
244 5ce3ce4f Sofia Papagiannaki
245 73fbaec4 Sofia Papagiannaki
246 7a08e179 Giorgos Korfiatis
### PROJECT FUNCTIONS ###
247 fcc1e93f Sofia Papagiannaki
248 f12bcb3d Giorgos Korfiatis
249 f12bcb3d Giorgos Korfiatis
class ProjectError(Exception):
250 f12bcb3d Giorgos Korfiatis
    pass
251 f12bcb3d Giorgos Korfiatis
252 f12bcb3d Giorgos Korfiatis
253 f12bcb3d Giorgos Korfiatis
class ProjectNotFound(ProjectError):
254 f12bcb3d Giorgos Korfiatis
    pass
255 f12bcb3d Giorgos Korfiatis
256 f12bcb3d Giorgos Korfiatis
257 f12bcb3d Giorgos Korfiatis
class ProjectForbidden(ProjectError):
258 f12bcb3d Giorgos Korfiatis
    pass
259 f12bcb3d Giorgos Korfiatis
260 f12bcb3d Giorgos Korfiatis
261 f12bcb3d Giorgos Korfiatis
class ProjectBadRequest(ProjectError):
262 f12bcb3d Giorgos Korfiatis
    pass
263 f12bcb3d Giorgos Korfiatis
264 f12bcb3d Giorgos Korfiatis
265 f12bcb3d Giorgos Korfiatis
class ProjectConflict(ProjectError):
266 f12bcb3d Giorgos Korfiatis
    pass
267 f12bcb3d Giorgos Korfiatis
268 b0686c16 Giorgos Korfiatis
AUTO_ACCEPT_POLICY = 1
269 7a08e179 Giorgos Korfiatis
MODERATED_POLICY = 2
270 7a08e179 Giorgos Korfiatis
CLOSED_POLICY = 3
271 7a08e179 Giorgos Korfiatis
272 7a08e179 Giorgos Korfiatis
POLICIES = [AUTO_ACCEPT_POLICY, MODERATED_POLICY, CLOSED_POLICY]
273 b0686c16 Giorgos Korfiatis
274 73fbaec4 Sofia Papagiannaki
275 a75dbd7b Giorgos Korfiatis
def get_related_project_id(application_id):
276 a75dbd7b Giorgos Korfiatis
    try:
277 a75dbd7b Giorgos Korfiatis
        app = ProjectApplication.objects.get(id=application_id)
278 6d583e07 Giorgos Korfiatis
        return app.chain_id
279 7a08e179 Giorgos Korfiatis
    except ProjectApplication.DoesNotExist:
280 0932ac43 Giorgos Korfiatis
        return None
281 0932ac43 Giorgos Korfiatis
282 7a08e179 Giorgos Korfiatis
283 eb9ff37a Sofia Papagiannaki
def get_project_by_id(project_id):
284 eb9ff37a Sofia Papagiannaki
    try:
285 2556cf45 Giorgos Korfiatis
        return Project.objects.select_related(
286 2556cf45 Giorgos Korfiatis
            "application", "application__owner",
287 2556cf45 Giorgos Korfiatis
            "application__applicant").get(id=project_id)
288 eb9ff37a Sofia Papagiannaki
    except Project.DoesNotExist:
289 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
290 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
291 7a08e179 Giorgos Korfiatis
292 eb9ff37a Sofia Papagiannaki
293 6335ad6f Giorgos Korfiatis
def get_project_for_update(project_id):
294 8dcaa6ac Giorgos Korfiatis
    try:
295 c7e03d20 Giorgos Korfiatis
        return Project.objects.select_for_update().get(id=project_id)
296 6335ad6f Giorgos Korfiatis
    except Project.DoesNotExist:
297 6335ad6f Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
298 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
299 7a08e179 Giorgos Korfiatis
300 8dcaa6ac Giorgos Korfiatis
301 6335ad6f Giorgos Korfiatis
def get_project_of_application_for_update(app_id):
302 3c22bad0 Giorgos Korfiatis
    app = get_application(app_id)
303 6335ad6f Giorgos Korfiatis
    return get_project_for_update(app.chain_id)
304 3c22bad0 Giorgos Korfiatis
305 3c22bad0 Giorgos Korfiatis
306 1b52192e Giorgos Korfiatis
def get_project_lock():
307 c7e03d20 Giorgos Korfiatis
    ProjectLock.objects.select_for_update().get(pk=1)
308 1b52192e Giorgos Korfiatis
309 1b52192e Giorgos Korfiatis
310 3c22bad0 Giorgos Korfiatis
def get_application(application_id):
311 19eb3ee6 Giorgos Korfiatis
    try:
312 3c22bad0 Giorgos Korfiatis
        return ProjectApplication.objects.get(id=application_id)
313 19eb3ee6 Giorgos Korfiatis
    except ProjectApplication.DoesNotExist:
314 19eb3ee6 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_APPLICATION_ID) % application_id
315 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
316 19eb3ee6 Giorgos Korfiatis
317 7a08e179 Giorgos Korfiatis
318 6335ad6f Giorgos Korfiatis
def get_project_of_membership_for_update(memb_id):
319 dc946891 Giorgos Korfiatis
    m = get_membership_by_id(memb_id)
320 6335ad6f Giorgos Korfiatis
    return get_project_for_update(m.project_id)
321 dc946891 Giorgos Korfiatis
322 dc946891 Giorgos Korfiatis
323 3c049f6d Giorgos Korfiatis
def get_user_by_uuid(uuid):
324 3c049f6d Giorgos Korfiatis
    try:
325 3c049f6d Giorgos Korfiatis
        return AstakosUser.objects.get(uuid=uuid)
326 3c049f6d Giorgos Korfiatis
    except AstakosUser.DoesNotExist:
327 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_USER_ID) % uuid
328 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
329 3c049f6d Giorgos Korfiatis
330 97e93991 Kostas Papadimitriou
331 3c22bad0 Giorgos Korfiatis
def get_membership(project_id, user_id):
332 73fbaec4 Sofia Papagiannaki
    try:
333 3c22bad0 Giorgos Korfiatis
        objs = ProjectMembership.objects.select_related('project', 'person')
334 3c22bad0 Giorgos Korfiatis
        return objs.get(project__id=project_id, person__id=user_id)
335 73fbaec4 Sofia Papagiannaki
    except ProjectMembership.DoesNotExist:
336 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
337 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
338 7a08e179 Giorgos Korfiatis
339 73fbaec4 Sofia Papagiannaki
340 866e5768 Giorgos Korfiatis
def get_membership_by_id(memb_id):
341 7f3c4920 Giorgos Korfiatis
    try:
342 3c22bad0 Giorgos Korfiatis
        objs = ProjectMembership.objects.select_related('project', 'person')
343 866e5768 Giorgos Korfiatis
        return objs.get(id=memb_id)
344 7f3c4920 Giorgos Korfiatis
    except ProjectMembership.DoesNotExist:
345 7f3c4920 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
346 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
347 7f3c4920 Giorgos Korfiatis
348 7f3c4920 Giorgos Korfiatis
349 c5b0bbb7 Giorgos Korfiatis
ALLOWED_CHECKS = [
350 c5b0bbb7 Giorgos Korfiatis
    (lambda u, a: not u or u.is_project_admin()),
351 c5b0bbb7 Giorgos Korfiatis
    (lambda u, a: a.owner == u),
352 c5b0bbb7 Giorgos Korfiatis
    (lambda u, a: a.applicant == u),
353 c5b0bbb7 Giorgos Korfiatis
    (lambda u, a: a.chain.overall_state() == Project.O_ACTIVE
354 c5b0bbb7 Giorgos Korfiatis
     or bool(a.chain.projectmembership_set.any_accepted().filter(person=u))),
355 c5b0bbb7 Giorgos Korfiatis
]
356 c5b0bbb7 Giorgos Korfiatis
357 c5b0bbb7 Giorgos Korfiatis
ADMIN_LEVEL = 0
358 c5b0bbb7 Giorgos Korfiatis
OWNER_LEVEL = 1
359 c5b0bbb7 Giorgos Korfiatis
APPLICANT_LEVEL = 2
360 c5b0bbb7 Giorgos Korfiatis
ANY_LEVEL = 3
361 c5b0bbb7 Giorgos Korfiatis
362 c5b0bbb7 Giorgos Korfiatis
363 c5b0bbb7 Giorgos Korfiatis
def _check_yield(b, silent=False):
364 c5b0bbb7 Giorgos Korfiatis
    if b:
365 c5b0bbb7 Giorgos Korfiatis
        return True
366 d07ce657 Giorgos Korfiatis
367 c5b0bbb7 Giorgos Korfiatis
    if silent:
368 c5b0bbb7 Giorgos Korfiatis
        return False
369 d07ce657 Giorgos Korfiatis
370 d07ce657 Giorgos Korfiatis
    m = _(astakos_messages.NOT_ALLOWED)
371 f12bcb3d Giorgos Korfiatis
    raise ProjectForbidden(m)
372 d07ce657 Giorgos Korfiatis
373 907f15db Giorgos Korfiatis
374 c5b0bbb7 Giorgos Korfiatis
def membership_check_allowed(membership, request_user,
375 c5b0bbb7 Giorgos Korfiatis
                             level=OWNER_LEVEL, silent=False):
376 c5b0bbb7 Giorgos Korfiatis
    r = project_check_allowed(
377 c5b0bbb7 Giorgos Korfiatis
        membership.project, request_user, level, silent=True)
378 c5b0bbb7 Giorgos Korfiatis
379 c5b0bbb7 Giorgos Korfiatis
    return _check_yield(r or membership.person == request_user, silent)
380 c5b0bbb7 Giorgos Korfiatis
381 c5b0bbb7 Giorgos Korfiatis
382 c5b0bbb7 Giorgos Korfiatis
def project_check_allowed(project, request_user,
383 c5b0bbb7 Giorgos Korfiatis
                          level=OWNER_LEVEL, silent=False):
384 c5b0bbb7 Giorgos Korfiatis
    return app_check_allowed(project.application, request_user, level, silent)
385 c5b0bbb7 Giorgos Korfiatis
386 c5b0bbb7 Giorgos Korfiatis
387 c5b0bbb7 Giorgos Korfiatis
def app_check_allowed(application, request_user,
388 c5b0bbb7 Giorgos Korfiatis
                      level=OWNER_LEVEL, silent=False):
389 c5b0bbb7 Giorgos Korfiatis
    checks = (f(request_user, application) for f in ALLOWED_CHECKS[:level+1])
390 c5b0bbb7 Giorgos Korfiatis
    return _check_yield(any(checks), silent)
391 c5b0bbb7 Giorgos Korfiatis
392 c5b0bbb7 Giorgos Korfiatis
393 907f15db Giorgos Korfiatis
def checkAlive(project):
394 907f15db Giorgos Korfiatis
    if not project.is_alive:
395 3805be31 Giorgos Korfiatis
        m = _(astakos_messages.NOT_ALIVE_PROJECT) % project.id
396 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
397 7a08e179 Giorgos Korfiatis
398 907f15db Giorgos Korfiatis
399 866e5768 Giorgos Korfiatis
def accept_membership_project_checks(project, request_user):
400 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user)
401 907f15db Giorgos Korfiatis
    checkAlive(project)
402 b0686c16 Giorgos Korfiatis
403 b0686c16 Giorgos Korfiatis
    join_policy = project.application.member_join_policy
404 b0686c16 Giorgos Korfiatis
    if join_policy == CLOSED_POLICY:
405 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)
406 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
407 b0686c16 Giorgos Korfiatis
408 8dcaa6ac Giorgos Korfiatis
    if project.violates_members_limit(adding=1):
409 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_NUMBER_LIMIT_REACHED)
410 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
411 73fbaec4 Sofia Papagiannaki
412 d07ce657 Giorgos Korfiatis
413 866e5768 Giorgos Korfiatis
def accept_membership_checks(membership, request_user):
414 71c741dc Giorgos Korfiatis
    if not membership.check_action("accept"):
415 14f7f6a5 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
416 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
417 d4fc6292 Giorgos Korfiatis
418 866e5768 Giorgos Korfiatis
    project = membership.project
419 866e5768 Giorgos Korfiatis
    accept_membership_project_checks(project, request_user)
420 866e5768 Giorgos Korfiatis
421 866e5768 Giorgos Korfiatis
422 da4ac460 Giorgos Korfiatis
def accept_membership(memb_id, request_user=None, reason=None):
423 866e5768 Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
424 866e5768 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
425 866e5768 Giorgos Korfiatis
    accept_membership_checks(membership, request_user)
426 7f3c4920 Giorgos Korfiatis
    user = membership.person
427 da4ac460 Giorgos Korfiatis
    membership.perform_action("accept", actor=request_user, reason=reason)
428 e336910f Giorgos Korfiatis
    qh_sync_user(user)
429 f30f0170 Giorgos Korfiatis
    logger.info("User %s has been accepted in %s." %
430 7f3c4920 Giorgos Korfiatis
                (user.log_display, project))
431 73fbaec4 Sofia Papagiannaki
432 7f3c4920 Giorgos Korfiatis
    membership_change_notify(project, user, 'accepted')
433 73fbaec4 Sofia Papagiannaki
    return membership
434 73fbaec4 Sofia Papagiannaki
435 7a08e179 Giorgos Korfiatis
436 866e5768 Giorgos Korfiatis
def reject_membership_checks(membership, request_user):
437 71c741dc Giorgos Korfiatis
    if not membership.check_action("reject"):
438 866e5768 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
439 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
440 866e5768 Giorgos Korfiatis
441 866e5768 Giorgos Korfiatis
    project = membership.project
442 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user)
443 907f15db Giorgos Korfiatis
    checkAlive(project)
444 e47fb17a Sofia Papagiannaki
445 d07ce657 Giorgos Korfiatis
446 da4ac460 Giorgos Korfiatis
def reject_membership(memb_id, request_user=None, reason=None):
447 6335ad6f Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
448 dc946891 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
449 866e5768 Giorgos Korfiatis
    reject_membership_checks(membership, request_user)
450 7f3c4920 Giorgos Korfiatis
    user = membership.person
451 da4ac460 Giorgos Korfiatis
    membership.perform_action("reject", actor=request_user, reason=reason)
452 f30f0170 Giorgos Korfiatis
    logger.info("Request of user %s for %s has been rejected." %
453 7f3c4920 Giorgos Korfiatis
                (user.log_display, project))
454 73fbaec4 Sofia Papagiannaki
455 7f3c4920 Giorgos Korfiatis
    membership_change_notify(project, user, 'rejected')
456 73fbaec4 Sofia Papagiannaki
    return membership
457 73fbaec4 Sofia Papagiannaki
458 7a08e179 Giorgos Korfiatis
459 866e5768 Giorgos Korfiatis
def cancel_membership_checks(membership, request_user):
460 71c741dc Giorgos Korfiatis
    if not membership.check_action("cancel"):
461 aad0e329 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
462 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
463 aad0e329 Giorgos Korfiatis
464 c5b0bbb7 Giorgos Korfiatis
    membership_check_allowed(membership, request_user, level=ADMIN_LEVEL)
465 3c22bad0 Giorgos Korfiatis
    project = membership.project
466 866e5768 Giorgos Korfiatis
    checkAlive(project)
467 866e5768 Giorgos Korfiatis
468 866e5768 Giorgos Korfiatis
469 da4ac460 Giorgos Korfiatis
def cancel_membership(memb_id, request_user, reason=None):
470 866e5768 Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
471 866e5768 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
472 866e5768 Giorgos Korfiatis
    cancel_membership_checks(membership, request_user)
473 da4ac460 Giorgos Korfiatis
    membership.perform_action("cancel", actor=request_user, reason=reason)
474 f30f0170 Giorgos Korfiatis
    logger.info("Request of user %s for %s has been cancelled." %
475 f30f0170 Giorgos Korfiatis
                (membership.person.log_display, project))
476 aad0e329 Giorgos Korfiatis
477 7a08e179 Giorgos Korfiatis
478 866e5768 Giorgos Korfiatis
def remove_membership_checks(membership, request_user=None):
479 71c741dc Giorgos Korfiatis
    if not membership.check_action("remove"):
480 866e5768 Giorgos Korfiatis
        m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP)
481 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
482 866e5768 Giorgos Korfiatis
483 866e5768 Giorgos Korfiatis
    project = membership.project
484 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user)
485 907f15db Giorgos Korfiatis
    checkAlive(project)
486 73fbaec4 Sofia Papagiannaki
487 b0686c16 Giorgos Korfiatis
    leave_policy = project.application.member_leave_policy
488 b0686c16 Giorgos Korfiatis
    if leave_policy == CLOSED_POLICY:
489 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)
490 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
491 7a08e179 Giorgos Korfiatis
492 b0686c16 Giorgos Korfiatis
493 da4ac460 Giorgos Korfiatis
def remove_membership(memb_id, request_user=None, reason=None):
494 6335ad6f Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
495 dc946891 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
496 866e5768 Giorgos Korfiatis
    remove_membership_checks(membership, request_user)
497 7f3c4920 Giorgos Korfiatis
    user = membership.person
498 da4ac460 Giorgos Korfiatis
    membership.perform_action("remove", actor=request_user, reason=reason)
499 e336910f Giorgos Korfiatis
    qh_sync_user(user)
500 f30f0170 Giorgos Korfiatis
    logger.info("User %s has been removed from %s." %
501 7f3c4920 Giorgos Korfiatis
                (user.log_display, project))
502 73fbaec4 Sofia Papagiannaki
503 7f3c4920 Giorgos Korfiatis
    membership_change_notify(project, user, 'removed')
504 73fbaec4 Sofia Papagiannaki
    return membership
505 73fbaec4 Sofia Papagiannaki
506 7a08e179 Giorgos Korfiatis
507 2556cf45 Giorgos Korfiatis
def enroll_member_by_email(project_id, email, request_user=None, reason=None):
508 2556cf45 Giorgos Korfiatis
    try:
509 733f013d Giorgos Korfiatis
        user = AstakosUser.objects.accepted().get(email=email)
510 2556cf45 Giorgos Korfiatis
        return enroll_member(project_id, user, request_user, reason=reason)
511 2556cf45 Giorgos Korfiatis
    except AstakosUser.DoesNotExist:
512 733f013d Giorgos Korfiatis
        raise ProjectConflict(astakos_messages.UNKNOWN_USERS % email)
513 2556cf45 Giorgos Korfiatis
514 2556cf45 Giorgos Korfiatis
515 da4ac460 Giorgos Korfiatis
def enroll_member(project_id, user, request_user=None, reason=None):
516 f12bcb3d Giorgos Korfiatis
    try:
517 f12bcb3d Giorgos Korfiatis
        project = get_project_for_update(project_id)
518 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound as e:
519 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(e.message)
520 866e5768 Giorgos Korfiatis
    accept_membership_project_checks(project, request_user)
521 e05c541e Giorgos Korfiatis
522 1a14083b Giorgos Korfiatis
    try:
523 1a14083b Giorgos Korfiatis
        membership = get_membership(project_id, user.id)
524 71c741dc Giorgos Korfiatis
        if not membership.check_action("enroll"):
525 1a14083b Giorgos Korfiatis
            m = _(astakos_messages.MEMBERSHIP_ACCEPTED)
526 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(m)
527 a5aa11ee Giorgos Korfiatis
        membership.perform_action("enroll", actor=request_user, reason=reason)
528 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound:
529 a5aa11ee Giorgos Korfiatis
        membership = new_membership(project, user, actor=request_user,
530 a5aa11ee Giorgos Korfiatis
                                    enroll=True)
531 d4fc6292 Giorgos Korfiatis
532 e336910f Giorgos Korfiatis
    qh_sync_user(user)
533 f30f0170 Giorgos Korfiatis
    logger.info("User %s has been enrolled in %s." %
534 f30f0170 Giorgos Korfiatis
                (membership.person.log_display, project))
535 570015d2 Giorgos Korfiatis
536 466cc12c Giorgos Korfiatis
    membership_enroll_notify(project, membership.person)
537 907f15db Giorgos Korfiatis
    return membership
538 8dcaa6ac Giorgos Korfiatis
539 7a08e179 Giorgos Korfiatis
540 866e5768 Giorgos Korfiatis
def leave_project_checks(membership, request_user):
541 71c741dc Giorgos Korfiatis
    if not membership.check_action("leave"):
542 866e5768 Giorgos Korfiatis
        m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP)
543 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
544 866e5768 Giorgos Korfiatis
545 c5b0bbb7 Giorgos Korfiatis
    membership_check_allowed(membership, request_user, level=ADMIN_LEVEL)
546 866e5768 Giorgos Korfiatis
    project = membership.project
547 907f15db Giorgos Korfiatis
    checkAlive(project)
548 8dcaa6ac Giorgos Korfiatis
549 03869281 Sofia Papagiannaki
    leave_policy = project.application.member_leave_policy
550 b0686c16 Giorgos Korfiatis
    if leave_policy == CLOSED_POLICY:
551 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)
552 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
553 7a08e179 Giorgos Korfiatis
554 73fbaec4 Sofia Papagiannaki
555 d4660e00 Giorgos Korfiatis
def can_leave_request(project, user):
556 d4660e00 Giorgos Korfiatis
    m = user.get_membership(project)
557 d4660e00 Giorgos Korfiatis
    if m is None:
558 d4660e00 Giorgos Korfiatis
        return False
559 866e5768 Giorgos Korfiatis
    try:
560 866e5768 Giorgos Korfiatis
        leave_project_checks(m, user)
561 f12bcb3d Giorgos Korfiatis
    except ProjectError:
562 866e5768 Giorgos Korfiatis
        return False
563 866e5768 Giorgos Korfiatis
    return True
564 d4660e00 Giorgos Korfiatis
565 d07ce657 Giorgos Korfiatis
566 da4ac460 Giorgos Korfiatis
def leave_project(memb_id, request_user, reason=None):
567 6335ad6f Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
568 dc946891 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
569 866e5768 Giorgos Korfiatis
    leave_project_checks(membership, request_user)
570 3c22bad0 Giorgos Korfiatis
571 bb6a4465 Giorgos Korfiatis
    auto_accepted = False
572 4e057833 Sofia Papagiannaki
    leave_policy = project.application.member_leave_policy
573 b0686c16 Giorgos Korfiatis
    if leave_policy == AUTO_ACCEPT_POLICY:
574 da4ac460 Giorgos Korfiatis
        membership.perform_action("remove", actor=request_user, reason=reason)
575 e336910f Giorgos Korfiatis
        qh_sync_user(request_user)
576 f30f0170 Giorgos Korfiatis
        logger.info("User %s has left %s." %
577 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
578 bb6a4465 Giorgos Korfiatis
        auto_accepted = True
579 73fbaec4 Sofia Papagiannaki
    else:
580 da4ac460 Giorgos Korfiatis
        membership.perform_action("leave_request", actor=request_user,
581 da4ac460 Giorgos Korfiatis
                                  reason=reason)
582 f30f0170 Giorgos Korfiatis
        logger.info("User %s requested to leave %s." %
583 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
584 bb6a4465 Giorgos Korfiatis
        membership_leave_request_notify(project, membership.person)
585 bb6a4465 Giorgos Korfiatis
    return auto_accepted
586 73fbaec4 Sofia Papagiannaki
587 7a08e179 Giorgos Korfiatis
588 ff67242a Giorgos Korfiatis
def join_project_checks(project):
589 907f15db Giorgos Korfiatis
    checkAlive(project)
590 8dcaa6ac Giorgos Korfiatis
591 974ee6a6 Sofia Papagiannaki
    join_policy = project.application.member_join_policy
592 b0686c16 Giorgos Korfiatis
    if join_policy == CLOSED_POLICY:
593 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)
594 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
595 7a08e179 Giorgos Korfiatis
596 73fbaec4 Sofia Papagiannaki
597 b10ceccd Giorgos Korfiatis
Nothing = type('Nothing', (), {})
598 b10ceccd Giorgos Korfiatis
599 b10ceccd Giorgos Korfiatis
600 b10ceccd Giorgos Korfiatis
def can_join_request(project, user, membership=Nothing):
601 34244dfa Giorgos Korfiatis
    try:
602 34244dfa Giorgos Korfiatis
        join_project_checks(project)
603 f12bcb3d Giorgos Korfiatis
    except ProjectError:
604 d4660e00 Giorgos Korfiatis
        return False
605 34244dfa Giorgos Korfiatis
606 b10ceccd Giorgos Korfiatis
    m = (membership if membership is not Nothing
607 b10ceccd Giorgos Korfiatis
         else user.get_membership(project))
608 1a14083b Giorgos Korfiatis
    if not m:
609 1a14083b Giorgos Korfiatis
        return True
610 71c741dc Giorgos Korfiatis
    return m.check_action("join")
611 1a14083b Giorgos Korfiatis
612 1a14083b Giorgos Korfiatis
613 a5aa11ee Giorgos Korfiatis
def new_membership(project, user, actor=None, reason=None, enroll=False):
614 a5aa11ee Giorgos Korfiatis
    state = (ProjectMembership.ACCEPTED if enroll
615 a5aa11ee Giorgos Korfiatis
             else ProjectMembership.REQUESTED)
616 a5aa11ee Giorgos Korfiatis
    m = ProjectMembership.objects.create(
617 a5aa11ee Giorgos Korfiatis
        project=project, person=user, state=state)
618 a5aa11ee Giorgos Korfiatis
    m._log_create(None, state, actor=actor, reason=reason)
619 1a14083b Giorgos Korfiatis
    return m
620 d4660e00 Giorgos Korfiatis
621 d07ce657 Giorgos Korfiatis
622 da4ac460 Giorgos Korfiatis
def join_project(project_id, request_user, reason=None):
623 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
624 ff67242a Giorgos Korfiatis
    join_project_checks(project)
625 d07ce657 Giorgos Korfiatis
626 1a14083b Giorgos Korfiatis
    try:
627 1a14083b Giorgos Korfiatis
        membership = get_membership(project.id, request_user.id)
628 71c741dc Giorgos Korfiatis
        if not membership.check_action("join"):
629 866e5768 Giorgos Korfiatis
            msg = _(astakos_messages.MEMBERSHIP_ASSOCIATED)
630 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(msg)
631 da4ac460 Giorgos Korfiatis
        membership.perform_action("join", actor=request_user, reason=reason)
632 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound:
633 da4ac460 Giorgos Korfiatis
        membership = new_membership(project, request_user, actor=request_user,
634 da4ac460 Giorgos Korfiatis
                                    reason=reason)
635 73fbaec4 Sofia Papagiannaki
636 4e057833 Sofia Papagiannaki
    join_policy = project.application.member_join_policy
637 7a08e179 Giorgos Korfiatis
    if (join_policy == AUTO_ACCEPT_POLICY and (
638 7a08e179 Giorgos Korfiatis
            not project.violates_members_limit(adding=1))):
639 da4ac460 Giorgos Korfiatis
        membership.perform_action("accept", actor=request_user, reason=reason)
640 e336910f Giorgos Korfiatis
        qh_sync_user(request_user)
641 f30f0170 Giorgos Korfiatis
        logger.info("User %s joined %s." %
642 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
643 bb6a4465 Giorgos Korfiatis
    else:
644 bb6a4465 Giorgos Korfiatis
        membership_request_notify(project, membership.person)
645 f30f0170 Giorgos Korfiatis
        logger.info("User %s requested to join %s." %
646 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
647 e1723ca1 Giorgos Korfiatis
    return membership
648 8dcaa6ac Giorgos Korfiatis
649 7a08e179 Giorgos Korfiatis
650 866e5768 Giorgos Korfiatis
MEMBERSHIP_ACTION_CHECKS = {
651 866e5768 Giorgos Korfiatis
    "leave":  leave_project_checks,
652 866e5768 Giorgos Korfiatis
    "cancel": cancel_membership_checks,
653 866e5768 Giorgos Korfiatis
    "accept": accept_membership_checks,
654 866e5768 Giorgos Korfiatis
    "reject": reject_membership_checks,
655 866e5768 Giorgos Korfiatis
    "remove": remove_membership_checks,
656 866e5768 Giorgos Korfiatis
}
657 866e5768 Giorgos Korfiatis
658 866e5768 Giorgos Korfiatis
659 866e5768 Giorgos Korfiatis
def membership_allowed_actions(membership, request_user):
660 866e5768 Giorgos Korfiatis
    allowed = []
661 866e5768 Giorgos Korfiatis
    for action, check in MEMBERSHIP_ACTION_CHECKS.iteritems():
662 866e5768 Giorgos Korfiatis
        try:
663 866e5768 Giorgos Korfiatis
            check(membership, request_user)
664 866e5768 Giorgos Korfiatis
            allowed.append(action)
665 f12bcb3d Giorgos Korfiatis
        except ProjectError:
666 866e5768 Giorgos Korfiatis
            pass
667 866e5768 Giorgos Korfiatis
    return allowed
668 866e5768 Giorgos Korfiatis
669 866e5768 Giorgos Korfiatis
670 6da04174 Giorgos Korfiatis
def submit_application(owner=None,
671 6da04174 Giorgos Korfiatis
                       name=None,
672 c4028837 Giorgos Korfiatis
                       project_id=None,
673 6da04174 Giorgos Korfiatis
                       homepage=None,
674 6da04174 Giorgos Korfiatis
                       description=None,
675 6da04174 Giorgos Korfiatis
                       start_date=None,
676 6da04174 Giorgos Korfiatis
                       end_date=None,
677 6da04174 Giorgos Korfiatis
                       member_join_policy=None,
678 6da04174 Giorgos Korfiatis
                       member_leave_policy=None,
679 6da04174 Giorgos Korfiatis
                       limit_on_members_number=None,
680 6da04174 Giorgos Korfiatis
                       comments=None,
681 b2369828 Giorgos Korfiatis
                       resources=None,
682 6da04174 Giorgos Korfiatis
                       request_user=None):
683 69c822cc Giorgos Korfiatis
684 c4028837 Giorgos Korfiatis
    project = None
685 c4028837 Giorgos Korfiatis
    if project_id is not None:
686 6335ad6f Giorgos Korfiatis
        project = get_project_for_update(project_id)
687 c5b0bbb7 Giorgos Korfiatis
        project_check_allowed(project, request_user, level=APPLICANT_LEVEL)
688 ee4aa6eb Giorgos Korfiatis
689 b2369828 Giorgos Korfiatis
    policies = validate_resource_policies(resources)
690 b2369828 Giorgos Korfiatis
691 9770ba6c Giorgos Korfiatis
    force = request_user.is_project_admin()
692 c4028837 Giorgos Korfiatis
    ok, limit = qh_add_pending_app(owner, project, force)
693 9770ba6c Giorgos Korfiatis
    if not ok:
694 c7c0ec58 Giorgos Korfiatis
        m = _(astakos_messages.REACHED_PENDING_APPLICATION_LIMIT) % limit
695 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
696 c7c0ec58 Giorgos Korfiatis
697 6da04174 Giorgos Korfiatis
    application = ProjectApplication(
698 6da04174 Giorgos Korfiatis
        applicant=request_user,
699 6da04174 Giorgos Korfiatis
        owner=owner,
700 6da04174 Giorgos Korfiatis
        name=name,
701 6da04174 Giorgos Korfiatis
        homepage=homepage,
702 6da04174 Giorgos Korfiatis
        description=description,
703 6da04174 Giorgos Korfiatis
        start_date=start_date,
704 6da04174 Giorgos Korfiatis
        end_date=end_date,
705 6da04174 Giorgos Korfiatis
        member_join_policy=member_join_policy,
706 6da04174 Giorgos Korfiatis
        member_leave_policy=member_leave_policy,
707 6da04174 Giorgos Korfiatis
        limit_on_members_number=limit_on_members_number,
708 6da04174 Giorgos Korfiatis
        comments=comments)
709 1352dabb Kostas Papadimitriou
710 c4028837 Giorgos Korfiatis
    if project is None:
711 6d583e07 Giorgos Korfiatis
        chain = new_chain()
712 6d583e07 Giorgos Korfiatis
        application.chain_id = chain.chain
713 6d583e07 Giorgos Korfiatis
        application.save()
714 6d583e07 Giorgos Korfiatis
        Project.objects.create(id=chain.chain, application=application)
715 3e3743f2 Giorgos Korfiatis
    else:
716 c4028837 Giorgos Korfiatis
        application.chain = project
717 6d583e07 Giorgos Korfiatis
        application.save()
718 c4028837 Giorgos Korfiatis
        if project.application.state != ProjectApplication.APPROVED:
719 c4028837 Giorgos Korfiatis
            project.application = application
720 c4028837 Giorgos Korfiatis
            project.save()
721 6d583e07 Giorgos Korfiatis
722 6d583e07 Giorgos Korfiatis
        pending = ProjectApplication.objects.filter(
723 c4028837 Giorgos Korfiatis
            chain=project,
724 6d583e07 Giorgos Korfiatis
            state=ProjectApplication.PENDING).exclude(id=application.id)
725 3e3743f2 Giorgos Korfiatis
        for app in pending:
726 3e3743f2 Giorgos Korfiatis
            app.state = ProjectApplication.REPLACED
727 3e3743f2 Giorgos Korfiatis
            app.save()
728 3e3743f2 Giorgos Korfiatis
729 b2369828 Giorgos Korfiatis
    if policies is not None:
730 b2369828 Giorgos Korfiatis
        set_resource_policies(application, policies)
731 f30f0170 Giorgos Korfiatis
    logger.info("User %s submitted %s." %
732 f30f0170 Giorgos Korfiatis
                (request_user.log_display, application.log_display))
733 a3eb3a95 Giorgos Korfiatis
    application_submit_notify(application)
734 a3eb3a95 Giorgos Korfiatis
    return application
735 73fbaec4 Sofia Papagiannaki
736 7a08e179 Giorgos Korfiatis
737 b2369828 Giorgos Korfiatis
def validate_resource_policies(policies):
738 b2369828 Giorgos Korfiatis
    if not isinstance(policies, dict):
739 b2369828 Giorgos Korfiatis
        raise ProjectBadRequest("Malformed resource policies")
740 b2369828 Giorgos Korfiatis
741 b2369828 Giorgos Korfiatis
    resource_names = policies.keys()
742 85ae5a4c Giorgos Korfiatis
    resources = Resource.objects.filter(name__in=resource_names,
743 85ae5a4c Giorgos Korfiatis
                                        api_visible=True)
744 b2369828 Giorgos Korfiatis
    resource_d = {}
745 b2369828 Giorgos Korfiatis
    for resource in resources:
746 b2369828 Giorgos Korfiatis
        resource_d[resource.name] = resource
747 b2369828 Giorgos Korfiatis
748 b2369828 Giorgos Korfiatis
    found = resource_d.keys()
749 b2369828 Giorgos Korfiatis
    nonex = [name for name in resource_names if name not in found]
750 b2369828 Giorgos Korfiatis
    if nonex:
751 f12bcb3d Giorgos Korfiatis
        raise ProjectBadRequest("Malformed resource policies")
752 b2369828 Giorgos Korfiatis
753 b2369828 Giorgos Korfiatis
    pols = []
754 b2369828 Giorgos Korfiatis
    for resource_name, specs in policies.iteritems():
755 b2369828 Giorgos Korfiatis
        p_capacity = specs.get("project_capacity")
756 b2369828 Giorgos Korfiatis
        m_capacity = specs.get("member_capacity")
757 b2369828 Giorgos Korfiatis
758 b2369828 Giorgos Korfiatis
        if p_capacity is not None and not isinstance(p_capacity, (int, long)):
759 f12bcb3d Giorgos Korfiatis
            raise ProjectBadRequest("Malformed resource policies")
760 b2369828 Giorgos Korfiatis
        if not isinstance(m_capacity, (int, long)):
761 f12bcb3d Giorgos Korfiatis
            raise ProjectBadRequest("Malformed resource policies")
762 b2369828 Giorgos Korfiatis
        pols.append((resource_d[resource_name], m_capacity, p_capacity))
763 b2369828 Giorgos Korfiatis
    return pols
764 b2369828 Giorgos Korfiatis
765 b2369828 Giorgos Korfiatis
766 b2369828 Giorgos Korfiatis
def set_resource_policies(application, policies):
767 b2369828 Giorgos Korfiatis
    for resource, m_capacity, p_capacity in policies:
768 b2369828 Giorgos Korfiatis
        g = application.projectresourcegrant_set
769 b2369828 Giorgos Korfiatis
        g.create(resource=resource,
770 b2369828 Giorgos Korfiatis
                 member_capacity=m_capacity,
771 b2369828 Giorgos Korfiatis
                 project_capacity=p_capacity)
772 b2369828 Giorgos Korfiatis
773 b2369828 Giorgos Korfiatis
774 64d0c13e Giorgos Korfiatis
def cancel_application(application_id, request_user=None, reason=""):
775 6335ad6f Giorgos Korfiatis
    get_project_of_application_for_update(application_id)
776 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
777 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=APPLICANT_LEVEL)
778 3c638f72 Giorgos Korfiatis
779 01bdbd17 Giorgos Korfiatis
    if not application.can_cancel():
780 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_CANCEL %
781 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
782 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
783 3c638f72 Giorgos Korfiatis
784 9770ba6c Giorgos Korfiatis
    qh_release_pending_app(application.owner)
785 9770ba6c Giorgos Korfiatis
786 88beea39 Giorgos Korfiatis
    application.cancel(actor=request_user, reason=reason)
787 f30f0170 Giorgos Korfiatis
    logger.info("%s has been cancelled." % (application.log_display))
788 3c638f72 Giorgos Korfiatis
789 7a08e179 Giorgos Korfiatis
790 64d0c13e Giorgos Korfiatis
def dismiss_application(application_id, request_user=None, reason=""):
791 6335ad6f Giorgos Korfiatis
    get_project_of_application_for_update(application_id)
792 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
793 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=APPLICANT_LEVEL)
794 3c638f72 Giorgos Korfiatis
795 01bdbd17 Giorgos Korfiatis
    if not application.can_dismiss():
796 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_DISMISS %
797 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
798 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
799 3c638f72 Giorgos Korfiatis
800 88beea39 Giorgos Korfiatis
    application.dismiss(actor=request_user, reason=reason)
801 f30f0170 Giorgos Korfiatis
    logger.info("%s has been dismissed." % (application.log_display))
802 3c638f72 Giorgos Korfiatis
803 7a08e179 Giorgos Korfiatis
804 64d0c13e Giorgos Korfiatis
def deny_application(application_id, request_user=None, reason=""):
805 6335ad6f Giorgos Korfiatis
    get_project_of_application_for_update(application_id)
806 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
807 01bdbd17 Giorgos Korfiatis
808 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=ADMIN_LEVEL)
809 d07ce657 Giorgos Korfiatis
810 01bdbd17 Giorgos Korfiatis
    if not application.can_deny():
811 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_DENY %
812 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
813 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
814 19eb3ee6 Giorgos Korfiatis
815 9770ba6c Giorgos Korfiatis
    qh_release_pending_app(application.owner)
816 9770ba6c Giorgos Korfiatis
817 88beea39 Giorgos Korfiatis
    application.deny(actor=request_user, reason=reason)
818 f30f0170 Giorgos Korfiatis
    logger.info("%s has been denied with reason \"%s\"." %
819 f30f0170 Giorgos Korfiatis
                (application.log_display, reason))
820 19eb3ee6 Giorgos Korfiatis
    application_deny_notify(application)
821 19eb3ee6 Giorgos Korfiatis
822 7a08e179 Giorgos Korfiatis
823 3c22bad0 Giorgos Korfiatis
def check_conflicting_projects(application):
824 6d583e07 Giorgos Korfiatis
    project = application.chain
825 3c22bad0 Giorgos Korfiatis
    new_project_name = application.name
826 8dcaa6ac Giorgos Korfiatis
    try:
827 3c22bad0 Giorgos Korfiatis
        q = Q(name=new_project_name) & ~Q(state=Project.TERMINATED)
828 3c22bad0 Giorgos Korfiatis
        conflicting_project = Project.objects.get(q)
829 3c22bad0 Giorgos Korfiatis
        if (conflicting_project != project):
830 3c22bad0 Giorgos Korfiatis
            m = (_("cannot approve: project with name '%s' "
831 8fb8d0cf Giorgos Korfiatis
                   "already exists (id: %s)") %
832 8fb8d0cf Giorgos Korfiatis
                 (new_project_name, conflicting_project.id))
833 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(m)  # invalid argument
834 3c22bad0 Giorgos Korfiatis
    except Project.DoesNotExist:
835 3c22bad0 Giorgos Korfiatis
        pass
836 3c22bad0 Giorgos Korfiatis
837 3c22bad0 Giorgos Korfiatis
838 3c22bad0 Giorgos Korfiatis
def approve_application(app_id, request_user=None, reason=""):
839 1b52192e Giorgos Korfiatis
    get_project_lock()
840 6335ad6f Giorgos Korfiatis
    project = get_project_of_application_for_update(app_id)
841 3c22bad0 Giorgos Korfiatis
    application = get_application(app_id)
842 8dcaa6ac Giorgos Korfiatis
843 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=ADMIN_LEVEL)
844 d07ce657 Giorgos Korfiatis
845 01bdbd17 Giorgos Korfiatis
    if not application.can_approve():
846 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_APPROVE %
847 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
848 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
849 01bdbd17 Giorgos Korfiatis
850 6d583e07 Giorgos Korfiatis
    check_conflicting_projects(application)
851 3c22bad0 Giorgos Korfiatis
852 3c22bad0 Giorgos Korfiatis
    # Pre-lock members and owner together in order to impose an ordering
853 3c22bad0 Giorgos Korfiatis
    # on locking users
854 6d583e07 Giorgos Korfiatis
    members = members_to_sync(project)
855 3c22bad0 Giorgos Korfiatis
    uids_to_sync = [member.id for member in members]
856 3c22bad0 Giorgos Korfiatis
    owner = application.owner
857 3c22bad0 Giorgos Korfiatis
    uids_to_sync.append(owner.id)
858 3c22bad0 Giorgos Korfiatis
    get_users_for_update(uids_to_sync)
859 3c22bad0 Giorgos Korfiatis
860 3c22bad0 Giorgos Korfiatis
    qh_release_pending_app(owner, locked=True)
861 88beea39 Giorgos Korfiatis
    application.approve(actor=request_user, reason=reason)
862 6d583e07 Giorgos Korfiatis
    project.application = application
863 6d583e07 Giorgos Korfiatis
    project.name = application.name
864 6d583e07 Giorgos Korfiatis
    project.save()
865 6d583e07 Giorgos Korfiatis
    if project.is_deactivated():
866 1b52192e Giorgos Korfiatis
        project.resume(actor=request_user, reason="APPROVE")
867 3c22bad0 Giorgos Korfiatis
    qh_sync_locked_users(members)
868 f30f0170 Giorgos Korfiatis
    logger.info("%s has been approved." % (application.log_display))
869 a3eb3a95 Giorgos Korfiatis
    application_approve_notify(application)
870 eb9ff37a Sofia Papagiannaki
871 7a08e179 Giorgos Korfiatis
872 7eadc230 Giorgos Korfiatis
def check_expiration(execute=False):
873 7eadc230 Giorgos Korfiatis
    objects = Project.objects
874 7eadc230 Giorgos Korfiatis
    expired = objects.expired_projects()
875 7eadc230 Giorgos Korfiatis
    if execute:
876 7eadc230 Giorgos Korfiatis
        for project in expired:
877 9f715f94 Giorgos Korfiatis
            terminate(project.pk)
878 7eadc230 Giorgos Korfiatis
879 7eadc230 Giorgos Korfiatis
    return [project.expiration_info() for project in expired]
880 7eadc230 Giorgos Korfiatis
881 7a08e179 Giorgos Korfiatis
882 88beea39 Giorgos Korfiatis
def terminate(project_id, request_user=None, reason=None):
883 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
884 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
885 907f15db Giorgos Korfiatis
    checkAlive(project)
886 5b9e9530 Giorgos Korfiatis
887 88beea39 Giorgos Korfiatis
    project.terminate(actor=request_user, reason=reason)
888 e336910f Giorgos Korfiatis
    qh_sync_project(project)
889 f30f0170 Giorgos Korfiatis
    logger.info("%s has been terminated." % (project))
890 570015d2 Giorgos Korfiatis
891 a3eb3a95 Giorgos Korfiatis
    project_termination_notify(project)
892 eb9ff37a Sofia Papagiannaki
893 7a08e179 Giorgos Korfiatis
894 88beea39 Giorgos Korfiatis
def suspend(project_id, request_user=None, reason=None):
895 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
896 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
897 db99f198 Giorgos Korfiatis
    checkAlive(project)
898 db99f198 Giorgos Korfiatis
899 88beea39 Giorgos Korfiatis
    project.suspend(actor=request_user, reason=reason)
900 e336910f Giorgos Korfiatis
    qh_sync_project(project)
901 f30f0170 Giorgos Korfiatis
    logger.info("%s has been suspended." % (project))
902 570015d2 Giorgos Korfiatis
903 a3eb3a95 Giorgos Korfiatis
    project_suspension_notify(project)
904 db99f198 Giorgos Korfiatis
905 7a08e179 Giorgos Korfiatis
906 e872c133 Giorgos Korfiatis
def unsuspend(project_id, request_user=None, reason=None):
907 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
908 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
909 db99f198 Giorgos Korfiatis
910 db99f198 Giorgos Korfiatis
    if not project.is_suspended:
911 3805be31 Giorgos Korfiatis
        m = _(astakos_messages.NOT_SUSPENDED_PROJECT) % project.id
912 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
913 db99f198 Giorgos Korfiatis
914 88beea39 Giorgos Korfiatis
    project.resume(actor=request_user, reason=reason)
915 e336910f Giorgos Korfiatis
    qh_sync_project(project)
916 f30f0170 Giorgos Korfiatis
    logger.info("%s has been unsuspended." % (project))
917 e872c133 Giorgos Korfiatis
    project_unsuspension_notify(project)
918 e872c133 Giorgos Korfiatis
919 e872c133 Giorgos Korfiatis
920 e872c133 Giorgos Korfiatis
def reinstate(project_id, request_user=None, reason=None):
921 e872c133 Giorgos Korfiatis
    get_project_lock()
922 e872c133 Giorgos Korfiatis
    project = get_project_for_update(project_id)
923 e872c133 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
924 e872c133 Giorgos Korfiatis
925 e872c133 Giorgos Korfiatis
    if not project.is_terminated:
926 e872c133 Giorgos Korfiatis
        m = _(astakos_messages.NOT_TERMINATED_PROJECT) % project.id
927 e872c133 Giorgos Korfiatis
        raise ProjectConflict(m)
928 e872c133 Giorgos Korfiatis
929 e872c133 Giorgos Korfiatis
    check_conflicting_projects(project.application)
930 e872c133 Giorgos Korfiatis
    project.resume(actor=request_user, reason=reason)
931 e872c133 Giorgos Korfiatis
    qh_sync_project(project)
932 e872c133 Giorgos Korfiatis
    logger.info("%s has been reinstated" % (project))
933 e872c133 Giorgos Korfiatis
    project_reinstatement_notify(project)
934 ff67242a Giorgos Korfiatis
935 7a08e179 Giorgos Korfiatis
936 3f5851eb Giorgos Korfiatis
def _partition_by(f, l):
937 3f5851eb Giorgos Korfiatis
    d = {}
938 3f5851eb Giorgos Korfiatis
    for x in l:
939 3f5851eb Giorgos Korfiatis
        group = f(x)
940 3f5851eb Giorgos Korfiatis
        group_l = d.get(group, [])
941 3f5851eb Giorgos Korfiatis
        group_l.append(x)
942 3f5851eb Giorgos Korfiatis
        d[group] = group_l
943 3f5851eb Giorgos Korfiatis
    return d
944 3f5851eb Giorgos Korfiatis
945 3f5851eb Giorgos Korfiatis
946 3f5851eb Giorgos Korfiatis
def count_pending_app(users):
947 103086a4 Giorgos Korfiatis
    users = list(users)
948 3f5851eb Giorgos Korfiatis
    apps = ProjectApplication.objects.filter(state=ProjectApplication.PENDING,
949 3f5851eb Giorgos Korfiatis
                                             owner__in=users)
950 3f5851eb Giorgos Korfiatis
    apps_d = _partition_by(lambda a: a.owner.uuid, apps)
951 3f5851eb Giorgos Korfiatis
952 3f5851eb Giorgos Korfiatis
    usage = {}
953 3f5851eb Giorgos Korfiatis
    for user in users:
954 3f5851eb Giorgos Korfiatis
        uuid = user.uuid
955 3f5851eb Giorgos Korfiatis
        usage[uuid] = len(apps_d.get(uuid, []))
956 3f5851eb Giorgos Korfiatis
    return usage
957 3f5851eb Giorgos Korfiatis
958 3f5851eb Giorgos Korfiatis
959 c4028837 Giorgos Korfiatis
def get_pending_app_diff(user, project):
960 c4028837 Giorgos Korfiatis
    if project is None:
961 9770ba6c Giorgos Korfiatis
        diff = 1
962 9770ba6c Giorgos Korfiatis
    else:
963 9770ba6c Giorgos Korfiatis
        objs = ProjectApplication.objects
964 c4028837 Giorgos Korfiatis
        q = objs.filter(chain=project, state=ProjectApplication.PENDING)
965 9770ba6c Giorgos Korfiatis
        count = q.count()
966 9770ba6c Giorgos Korfiatis
        diff = 1 - count
967 3c22bad0 Giorgos Korfiatis
    return diff
968 3c22bad0 Giorgos Korfiatis
969 3c22bad0 Giorgos Korfiatis
970 c4028837 Giorgos Korfiatis
def qh_add_pending_app(user, project=None, force=False):
971 c7e03d20 Giorgos Korfiatis
    user = AstakosUser.objects.select_for_update().get(id=user.id)
972 c4028837 Giorgos Korfiatis
    diff = get_pending_app_diff(user, project)
973 3c22bad0 Giorgos Korfiatis
    return register_pending_apps(user, diff, force)
974 3c22bad0 Giorgos Korfiatis
975 c7c0ec58 Giorgos Korfiatis
976 c4028837 Giorgos Korfiatis
def check_pending_app_quota(user, project=None):
977 c4028837 Giorgos Korfiatis
    diff = get_pending_app_diff(user, project)
978 3c22bad0 Giorgos Korfiatis
    quota = get_pending_app_quota(user)
979 3c22bad0 Giorgos Korfiatis
    limit = quota['limit']
980 3c22bad0 Giorgos Korfiatis
    usage = quota['usage']
981 3c22bad0 Giorgos Korfiatis
    if usage + diff > limit:
982 3c22bad0 Giorgos Korfiatis
        return False, limit
983 3c22bad0 Giorgos Korfiatis
    return True, None
984 c7c0ec58 Giorgos Korfiatis
985 c7c0ec58 Giorgos Korfiatis
986 3c22bad0 Giorgos Korfiatis
def qh_release_pending_app(user, locked=False):
987 3c22bad0 Giorgos Korfiatis
    if not locked:
988 c7e03d20 Giorgos Korfiatis
        user = AstakosUser.objects.select_for_update().get(id=user.id)
989 9e3af524 Giorgos Korfiatis
    register_pending_apps(user, -1)