Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ 50f74340

History | View | Annotate | Download (31.9 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 6d583e07 Giorgos Korfiatis
from datetime import datetime
36 f36af44a Antony Chazapis
37 f36af44a Antony Chazapis
from django.utils.translation import ugettext as _
38 f9224cc0 Sofia Papagiannaki
from django.core.mail import send_mail, get_connection
39 f36af44a Antony Chazapis
from django.core.urlresolvers import reverse
40 8998f09a Sofia Papagiannaki
from django.contrib.auth import login as auth_login, logout as auth_logout
41 3c22bad0 Giorgos Korfiatis
from django.db.models import Q
42 27e26a41 Sofia Papagiannaki
43 734107ef Kostas Papadimitriou
from synnefo_branding.utils import render_to_string
44 734107ef Kostas Papadimitriou
45 d2c9adac Christos Stavrakakis
from synnefo.lib import join_urls
46 8998f09a Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation, ProjectMembership, \
47 b2369828 Giorgos Korfiatis
    ProjectApplication, Project, new_chain, Resource
48 8998f09a Sofia Papagiannaki
from astakos.im.quotas import qh_sync_user, get_pending_app_quota, \
49 8998f09a Sofia Papagiannaki
    register_pending_apps, qh_sync_project, qh_sync_locked_users, \
50 8998f09a Sofia Papagiannaki
    get_users_for_update, members_to_sync
51 8998f09a Sofia Papagiannaki
from astakos.im.project_notif import membership_change_notify, \
52 8998f09a Sofia Papagiannaki
    membership_enroll_notify, membership_request_notify, \
53 8998f09a Sofia Papagiannaki
    membership_leave_request_notify, application_submit_notify, \
54 8998f09a Sofia Papagiannaki
    application_approve_notify, application_deny_notify, \
55 8998f09a Sofia Papagiannaki
    project_termination_notify, project_suspension_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 5df4c364 Kostas Papadimitriou
    logger.info('%s logged out.', user.log_display)
77 111f3da6 Sofia Papagiannaki
78 5ce3ce4f Sofia Papagiannaki
79 683cf244 Sofia Papagiannaki
def send_verification(user, template_name='im/activation_email.txt'):
80 f36af44a Antony Chazapis
    """
81 683cf244 Sofia Papagiannaki
    Send email to user to verify his/her email and activate his/her account.
82 f36af44a Antony Chazapis
    """
83 e3ff6830 Georgios D. Tsoukalas
    url = join_urls(settings.BASE_HOST,
84 e3ff6830 Georgios D. Tsoukalas
                    user.get_activation_url(nxt=reverse('index')))
85 683cf244 Sofia Papagiannaki
    message = render_to_string(template_name, {
86 5ce3ce4f Sofia Papagiannaki
                               'user': user,
87 5ce3ce4f Sofia Papagiannaki
                               'url': url,
88 6c7af65c Georgios D. Tsoukalas
                               'baseurl': settings.BASE_URL,
89 8998f09a Sofia Papagiannaki
                               'site_name': settings.SITENAME,
90 8998f09a Sofia Papagiannaki
                               'support': settings.CONTACT_EMAIL})
91 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
92 cfb7dd4f Giorgos Korfiatis
    send_mail(_(astakos_messages.VERIFICATION_EMAIL_SUBJECT), message, sender,
93 cfb7dd4f Giorgos Korfiatis
              [user.email],
94 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
95 e7cb4085 Kostas Papadimitriou
    logger.info("Sent user verirfication email: %s", user.log_display)
96 683cf244 Sofia Papagiannaki
97 5ce3ce4f Sofia Papagiannaki
98 9a06d96f Olga Brani
def _send_admin_notification(template_name,
99 e7cb4085 Kostas Papadimitriou
                             context=None,
100 e7cb4085 Kostas Papadimitriou
                             user=None,
101 e7cb4085 Kostas Papadimitriou
                             msg="",
102 9a06d96f Olga Brani
                             subject='alpha2 testing notification',):
103 683cf244 Sofia Papagiannaki
    """
104 e7cb4085 Kostas Papadimitriou
    Send notification email to settings.HELPDESK + settings.MANAGERS +
105 e7cb4085 Kostas Papadimitriou
    settings.ADMINS.
106 683cf244 Sofia Papagiannaki
    """
107 e7cb4085 Kostas Papadimitriou
    if context is None:
108 e7cb4085 Kostas Papadimitriou
        context = {}
109 e7cb4085 Kostas Papadimitriou
    if not 'user' in context:
110 e7cb4085 Kostas Papadimitriou
        context['user'] = user
111 e7cb4085 Kostas Papadimitriou
112 e7cb4085 Kostas Papadimitriou
    message = render_to_string(template_name, context)
113 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
114 e7cb4085 Kostas Papadimitriou
    recipient_list = [e[1] for e in settings.HELPDESK +
115 e7cb4085 Kostas Papadimitriou
                      settings.MANAGERS + settings.ADMINS]
116 e7cb4085 Kostas Papadimitriou
    send_mail(subject, message, sender, recipient_list,
117 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
118 e7cb4085 Kostas Papadimitriou
    if user:
119 e7cb4085 Kostas Papadimitriou
        msg = 'Sent admin notification (%s) for user %s' % (msg,
120 e7cb4085 Kostas Papadimitriou
                                                            user.log_display)
121 8f5a3a06 Sofia Papagiannaki
    else:
122 e7cb4085 Kostas Papadimitriou
        msg = 'Sent admin notification (%s)' % msg
123 683cf244 Sofia Papagiannaki
124 8998f09a Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg)
125 5ce3ce4f Sofia Papagiannaki
126 e7cb4085 Kostas Papadimitriou
127 e7cb4085 Kostas Papadimitriou
def send_account_pending_moderation_notification(
128 e7cb4085 Kostas Papadimitriou
        user,
129 e7cb4085 Kostas Papadimitriou
        template_name='im/account_pending_moderation_notification.txt'):
130 e7cb4085 Kostas Papadimitriou
    """
131 e7cb4085 Kostas Papadimitriou
    Notify admins that a new user has verified his email address and moderation
132 e7cb4085 Kostas Papadimitriou
    step is required to activate his account.
133 e7cb4085 Kostas Papadimitriou
    """
134 cfb7dd4f Giorgos Korfiatis
    subject = (_(astakos_messages.ACCOUNT_CREATION_SUBJECT) %
135 cfb7dd4f Giorgos Korfiatis
               {'user': user.email})
136 e7cb4085 Kostas Papadimitriou
    return _send_admin_notification(template_name, {}, subject=subject,
137 e7cb4085 Kostas Papadimitriou
                                    user=user, msg="account creation")
138 9a06d96f Olga Brani
139 9a06d96f Olga Brani
140 e7cb4085 Kostas Papadimitriou
def send_account_activated_notification(
141 e7cb4085 Kostas Papadimitriou
        user,
142 e7cb4085 Kostas Papadimitriou
        template_name='im/account_activated_notification.txt'):
143 a0be6a0c Sofia Papagiannaki
    """
144 e7cb4085 Kostas Papadimitriou
    Send email to settings.HELPDESK + settings.MANAGERES + settings.ADMINS
145 e7cb4085 Kostas Papadimitriou
    lists to notify that a new account has been accepted and activated.
146 a0be6a0c Sofia Papagiannaki
    """
147 3abf6c78 Sofia Papagiannaki
    message = render_to_string(
148 3abf6c78 Sofia Papagiannaki
        template_name,
149 3abf6c78 Sofia Papagiannaki
        {'user': user}
150 3abf6c78 Sofia Papagiannaki
    )
151 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
152 e7cb4085 Kostas Papadimitriou
    recipient_list = [e[1] for e in settings.HELPDESK +
153 e7cb4085 Kostas Papadimitriou
                      settings.MANAGERS + settings.ADMINS]
154 cfb7dd4f Giorgos Korfiatis
    send_mail(_(astakos_messages.HELPDESK_NOTIFICATION_EMAIL_SUBJECT) %
155 cfb7dd4f Giorgos Korfiatis
              {'user': user.email},
156 e7cb4085 Kostas Papadimitriou
              message, sender, recipient_list, connection=get_connection())
157 e7cb4085 Kostas Papadimitriou
    msg = 'Sent helpdesk admin notification for %s' % user.email
158 8998f09a Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg)
159 a0be6a0c Sofia Papagiannaki
160 5ce3ce4f Sofia Papagiannaki
161 683cf244 Sofia Papagiannaki
def send_invitation(invitation, template_name='im/invitation.txt'):
162 683cf244 Sofia Papagiannaki
    """
163 683cf244 Sofia Papagiannaki
    Send invitation email.
164 683cf244 Sofia Papagiannaki
    """
165 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.INVITATION_EMAIL_SUBJECT)
166 8c8e318d Kostas Papadimitriou
    url = '%s?code=%d' % (join_urls(settings.BASE_HOST,
167 8c8e318d Kostas Papadimitriou
                                    reverse('index')), invitation.code)
168 aab4d540 Sofia Papagiannaki
    message = render_to_string(template_name, {
169 5ce3ce4f Sofia Papagiannaki
                               'invitation': invitation,
170 5ce3ce4f Sofia Papagiannaki
                               'url': url,
171 6c7af65c Georgios D. Tsoukalas
                               'baseurl': settings.BASE_URL,
172 8998f09a Sofia Papagiannaki
                               'site_name': settings.SITENAME,
173 8998f09a Sofia Papagiannaki
                               'support': settings.CONTACT_EMAIL})
174 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
175 e7cb4085 Kostas Papadimitriou
    send_mail(subject, message, sender, [invitation.username],
176 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
177 e7cb4085 Kostas Papadimitriou
    msg = 'Sent invitation %s' % invitation
178 8998f09a Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg)
179 e7cb4085 Kostas Papadimitriou
    inviter_invitations = invitation.inviter.invitations
180 e7cb4085 Kostas Papadimitriou
    invitation.inviter.invitations = max(0, inviter_invitations - 1)
181 e7cb4085 Kostas Papadimitriou
    invitation.inviter.save()
182 683cf244 Sofia Papagiannaki
183 5ce3ce4f Sofia Papagiannaki
184 683cf244 Sofia Papagiannaki
def send_greeting(user, email_template_name='im/welcome_email.txt'):
185 683cf244 Sofia Papagiannaki
    """
186 e7cb4085 Kostas Papadimitriou
    Send welcome email to an accepted/activated user.
187 5ce3ce4f Sofia Papagiannaki

188 f36af44a Antony Chazapis
    Raises SMTPException, socket.error
189 f36af44a Antony Chazapis
    """
190 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.GREETING_EMAIL_SUBJECT)
191 f36af44a Antony Chazapis
    message = render_to_string(email_template_name, {
192 5ce3ce4f Sofia Papagiannaki
                               'user': user,
193 8c8e318d Kostas Papadimitriou
                               'url': join_urls(settings.BASE_HOST,
194 8c8e318d Kostas Papadimitriou
                                                reverse('index')),
195 6c7af65c Georgios D. Tsoukalas
                               'baseurl': settings.BASE_URL,
196 8998f09a Sofia Papagiannaki
                               'site_name': settings.SITENAME,
197 8998f09a Sofia Papagiannaki
                               'support': settings.CONTACT_EMAIL})
198 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
199 e7cb4085 Kostas Papadimitriou
    send_mail(subject, message, sender, [user.email],
200 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
201 e7cb4085 Kostas Papadimitriou
    msg = 'Sent greeting %s' % user.log_display
202 8998f09a Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg)
203 8f5a3a06 Sofia Papagiannaki
204 5ce3ce4f Sofia Papagiannaki
205 8f5a3a06 Sofia Papagiannaki
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
206 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.FEEDBACK_EMAIL_SUBJECT)
207 7d145e78 Sofia Papagiannaki
    from_email = settings.SERVER_EMAIL
208 0a7a4104 Kostas Papadimitriou
    recipient_list = [e[1] for e in settings.HELPDESK]
209 8f5a3a06 Sofia Papagiannaki
    content = render_to_string(email_template_name, {
210 8f5a3a06 Sofia Papagiannaki
        'message': msg,
211 8f5a3a06 Sofia Papagiannaki
        'data': data,
212 8f5a3a06 Sofia Papagiannaki
        'user': user})
213 e182fc26 Sofia Papagiannaki
    send_mail(subject, content, from_email, recipient_list,
214 e182fc26 Sofia Papagiannaki
              connection=get_connection())
215 e182fc26 Sofia Papagiannaki
    msg = 'Sent feedback from %s' % user.log_display
216 8998f09a Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg)
217 f36af44a Antony Chazapis
218 5ce3ce4f Sofia Papagiannaki
219 73fbaec4 Sofia Papagiannaki
def send_change_email(
220 8fb8d0cf Giorgos Korfiatis
    ec, request, email_template_name='registration/email_change_email.txt'
221 8fb8d0cf Giorgos Korfiatis
):
222 e182fc26 Sofia Papagiannaki
    url = ec.get_url()
223 e182fc26 Sofia Papagiannaki
    url = request.build_absolute_uri(url)
224 8fb8d0cf Giorgos Korfiatis
    c = {'url': url, 'site_name': settings.SITENAME,
225 8fb8d0cf Giorgos Korfiatis
         'support': settings.CONTACT_EMAIL,
226 734107ef Kostas Papadimitriou
         'ec': ec}
227 734107ef Kostas Papadimitriou
    message = render_to_string(email_template_name, c)
228 e182fc26 Sofia Papagiannaki
    from_email = settings.SERVER_EMAIL
229 cfb7dd4f Giorgos Korfiatis
    send_mail(_(astakos_messages.EMAIL_CHANGE_EMAIL_SUBJECT), message,
230 cfb7dd4f Giorgos Korfiatis
              from_email,
231 734107ef Kostas Papadimitriou
              [ec.new_email_address], connection=get_connection())
232 e182fc26 Sofia Papagiannaki
    msg = 'Sent change email for %s' % ec.user.log_display
233 8998f09a Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg)
234 f36af44a Antony Chazapis
235 5ce3ce4f Sofia Papagiannaki
236 73fbaec4 Sofia Papagiannaki
def invite(inviter, email, realname):
237 73fbaec4 Sofia Papagiannaki
    inv = Invitation(inviter=inviter, username=email, realname=realname)
238 73fbaec4 Sofia Papagiannaki
    inv.save()
239 73fbaec4 Sofia Papagiannaki
    send_invitation(inv)
240 e30537f1 Sofia Papagiannaki
    inviter.invitations = max(0, inviter.invitations - 1)
241 73fbaec4 Sofia Papagiannaki
    inviter.save()
242 5ce3ce4f Sofia Papagiannaki
243 73fbaec4 Sofia Papagiannaki
244 7a08e179 Giorgos Korfiatis
### PROJECT FUNCTIONS ###
245 fcc1e93f Sofia Papagiannaki
246 f12bcb3d Giorgos Korfiatis
247 f12bcb3d Giorgos Korfiatis
class ProjectError(Exception):
248 f12bcb3d Giorgos Korfiatis
    pass
249 f12bcb3d Giorgos Korfiatis
250 f12bcb3d Giorgos Korfiatis
251 f12bcb3d Giorgos Korfiatis
class ProjectNotFound(ProjectError):
252 f12bcb3d Giorgos Korfiatis
    pass
253 f12bcb3d Giorgos Korfiatis
254 f12bcb3d Giorgos Korfiatis
255 f12bcb3d Giorgos Korfiatis
class ProjectForbidden(ProjectError):
256 f12bcb3d Giorgos Korfiatis
    pass
257 f12bcb3d Giorgos Korfiatis
258 f12bcb3d Giorgos Korfiatis
259 f12bcb3d Giorgos Korfiatis
class ProjectBadRequest(ProjectError):
260 f12bcb3d Giorgos Korfiatis
    pass
261 f12bcb3d Giorgos Korfiatis
262 f12bcb3d Giorgos Korfiatis
263 f12bcb3d Giorgos Korfiatis
class ProjectConflict(ProjectError):
264 f12bcb3d Giorgos Korfiatis
    pass
265 f12bcb3d Giorgos Korfiatis
266 b0686c16 Giorgos Korfiatis
AUTO_ACCEPT_POLICY = 1
267 7a08e179 Giorgos Korfiatis
MODERATED_POLICY = 2
268 7a08e179 Giorgos Korfiatis
CLOSED_POLICY = 3
269 7a08e179 Giorgos Korfiatis
270 7a08e179 Giorgos Korfiatis
POLICIES = [AUTO_ACCEPT_POLICY, MODERATED_POLICY, CLOSED_POLICY]
271 b0686c16 Giorgos Korfiatis
272 73fbaec4 Sofia Papagiannaki
273 a75dbd7b Giorgos Korfiatis
def get_related_project_id(application_id):
274 a75dbd7b Giorgos Korfiatis
    try:
275 a75dbd7b Giorgos Korfiatis
        app = ProjectApplication.objects.get(id=application_id)
276 6d583e07 Giorgos Korfiatis
        return app.chain_id
277 7a08e179 Giorgos Korfiatis
    except ProjectApplication.DoesNotExist:
278 0932ac43 Giorgos Korfiatis
        return None
279 0932ac43 Giorgos Korfiatis
280 7a08e179 Giorgos Korfiatis
281 eb9ff37a Sofia Papagiannaki
def get_project_by_id(project_id):
282 eb9ff37a Sofia Papagiannaki
    try:
283 eb9ff37a Sofia Papagiannaki
        return Project.objects.get(id=project_id)
284 eb9ff37a Sofia Papagiannaki
    except Project.DoesNotExist:
285 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
286 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
287 7a08e179 Giorgos Korfiatis
288 eb9ff37a Sofia Papagiannaki
289 6335ad6f Giorgos Korfiatis
def get_project_for_update(project_id):
290 8dcaa6ac Giorgos Korfiatis
    try:
291 6335ad6f Giorgos Korfiatis
        return Project.objects.get_for_update(id=project_id)
292 6335ad6f Giorgos Korfiatis
    except Project.DoesNotExist:
293 6335ad6f Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
294 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
295 7a08e179 Giorgos Korfiatis
296 8dcaa6ac Giorgos Korfiatis
297 6335ad6f Giorgos Korfiatis
def get_project_of_application_for_update(app_id):
298 3c22bad0 Giorgos Korfiatis
    app = get_application(app_id)
299 6335ad6f Giorgos Korfiatis
    return get_project_for_update(app.chain_id)
300 3c22bad0 Giorgos Korfiatis
301 3c22bad0 Giorgos Korfiatis
302 3c22bad0 Giorgos Korfiatis
def get_application(application_id):
303 19eb3ee6 Giorgos Korfiatis
    try:
304 3c22bad0 Giorgos Korfiatis
        return ProjectApplication.objects.get(id=application_id)
305 19eb3ee6 Giorgos Korfiatis
    except ProjectApplication.DoesNotExist:
306 19eb3ee6 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_APPLICATION_ID) % application_id
307 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
308 19eb3ee6 Giorgos Korfiatis
309 7a08e179 Giorgos Korfiatis
310 6335ad6f Giorgos Korfiatis
def get_project_of_membership_for_update(memb_id):
311 dc946891 Giorgos Korfiatis
    m = get_membership_by_id(memb_id)
312 6335ad6f Giorgos Korfiatis
    return get_project_for_update(m.project_id)
313 dc946891 Giorgos Korfiatis
314 dc946891 Giorgos Korfiatis
315 73fbaec4 Sofia Papagiannaki
def get_user_by_id(user_id):
316 73fbaec4 Sofia Papagiannaki
    try:
317 974ee6a6 Sofia Papagiannaki
        return AstakosUser.objects.get(id=user_id)
318 73fbaec4 Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
319 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_USER_ID) % user_id
320 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
321 7a08e179 Giorgos Korfiatis
322 73fbaec4 Sofia Papagiannaki
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 da4ac460 Giorgos Korfiatis
def enroll_member(project_id, user, request_user=None, reason=None):
508 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
509 f12bcb3d Giorgos Korfiatis
    try:
510 f12bcb3d Giorgos Korfiatis
        project = get_project_for_update(project_id)
511 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound as e:
512 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(e.message)
513 866e5768 Giorgos Korfiatis
    accept_membership_project_checks(project, request_user)
514 e05c541e Giorgos Korfiatis
515 1a14083b Giorgos Korfiatis
    try:
516 1a14083b Giorgos Korfiatis
        membership = get_membership(project_id, user.id)
517 71c741dc Giorgos Korfiatis
        if not membership.check_action("enroll"):
518 1a14083b Giorgos Korfiatis
            m = _(astakos_messages.MEMBERSHIP_ACCEPTED)
519 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(m)
520 da4ac460 Giorgos Korfiatis
        membership.perform_action("join", actor=request_user, reason=reason)
521 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound:
522 da4ac460 Giorgos Korfiatis
        membership = new_membership(project, user, actor=request_user)
523 d4fc6292 Giorgos Korfiatis
524 da4ac460 Giorgos Korfiatis
    membership.perform_action("accept", actor=request_user, reason=reason)
525 e336910f Giorgos Korfiatis
    qh_sync_user(user)
526 f30f0170 Giorgos Korfiatis
    logger.info("User %s has been enrolled in %s." %
527 f30f0170 Giorgos Korfiatis
                (membership.person.log_display, project))
528 570015d2 Giorgos Korfiatis
529 466cc12c Giorgos Korfiatis
    membership_enroll_notify(project, membership.person)
530 907f15db Giorgos Korfiatis
    return membership
531 8dcaa6ac Giorgos Korfiatis
532 7a08e179 Giorgos Korfiatis
533 866e5768 Giorgos Korfiatis
def leave_project_checks(membership, request_user):
534 71c741dc Giorgos Korfiatis
    if not membership.check_action("leave"):
535 866e5768 Giorgos Korfiatis
        m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP)
536 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
537 866e5768 Giorgos Korfiatis
538 c5b0bbb7 Giorgos Korfiatis
    membership_check_allowed(membership, request_user, level=ADMIN_LEVEL)
539 866e5768 Giorgos Korfiatis
    project = membership.project
540 907f15db Giorgos Korfiatis
    checkAlive(project)
541 8dcaa6ac Giorgos Korfiatis
542 03869281 Sofia Papagiannaki
    leave_policy = project.application.member_leave_policy
543 b0686c16 Giorgos Korfiatis
    if leave_policy == CLOSED_POLICY:
544 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)
545 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
546 7a08e179 Giorgos Korfiatis
547 73fbaec4 Sofia Papagiannaki
548 d4660e00 Giorgos Korfiatis
def can_leave_request(project, user):
549 d4660e00 Giorgos Korfiatis
    m = user.get_membership(project)
550 d4660e00 Giorgos Korfiatis
    if m is None:
551 d4660e00 Giorgos Korfiatis
        return False
552 866e5768 Giorgos Korfiatis
    try:
553 866e5768 Giorgos Korfiatis
        leave_project_checks(m, user)
554 f12bcb3d Giorgos Korfiatis
    except ProjectError:
555 866e5768 Giorgos Korfiatis
        return False
556 866e5768 Giorgos Korfiatis
    return True
557 d4660e00 Giorgos Korfiatis
558 d07ce657 Giorgos Korfiatis
559 da4ac460 Giorgos Korfiatis
def leave_project(memb_id, request_user, reason=None):
560 6335ad6f Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
561 dc946891 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
562 866e5768 Giorgos Korfiatis
    leave_project_checks(membership, request_user)
563 3c22bad0 Giorgos Korfiatis
564 bb6a4465 Giorgos Korfiatis
    auto_accepted = False
565 4e057833 Sofia Papagiannaki
    leave_policy = project.application.member_leave_policy
566 b0686c16 Giorgos Korfiatis
    if leave_policy == AUTO_ACCEPT_POLICY:
567 da4ac460 Giorgos Korfiatis
        membership.perform_action("remove", actor=request_user, reason=reason)
568 e336910f Giorgos Korfiatis
        qh_sync_user(request_user)
569 f30f0170 Giorgos Korfiatis
        logger.info("User %s has left %s." %
570 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
571 bb6a4465 Giorgos Korfiatis
        auto_accepted = True
572 73fbaec4 Sofia Papagiannaki
    else:
573 da4ac460 Giorgos Korfiatis
        membership.perform_action("leave_request", actor=request_user,
574 da4ac460 Giorgos Korfiatis
                                  reason=reason)
575 f30f0170 Giorgos Korfiatis
        logger.info("User %s requested to leave %s." %
576 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
577 bb6a4465 Giorgos Korfiatis
        membership_leave_request_notify(project, membership.person)
578 bb6a4465 Giorgos Korfiatis
    return auto_accepted
579 73fbaec4 Sofia Papagiannaki
580 7a08e179 Giorgos Korfiatis
581 ff67242a Giorgos Korfiatis
def join_project_checks(project):
582 907f15db Giorgos Korfiatis
    checkAlive(project)
583 8dcaa6ac Giorgos Korfiatis
584 974ee6a6 Sofia Papagiannaki
    join_policy = project.application.member_join_policy
585 b0686c16 Giorgos Korfiatis
    if join_policy == CLOSED_POLICY:
586 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)
587 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
588 7a08e179 Giorgos Korfiatis
589 73fbaec4 Sofia Papagiannaki
590 d4660e00 Giorgos Korfiatis
def can_join_request(project, user):
591 34244dfa Giorgos Korfiatis
    try:
592 34244dfa Giorgos Korfiatis
        join_project_checks(project)
593 f12bcb3d Giorgos Korfiatis
    except ProjectError:
594 d4660e00 Giorgos Korfiatis
        return False
595 34244dfa Giorgos Korfiatis
596 d4660e00 Giorgos Korfiatis
    m = user.get_membership(project)
597 1a14083b Giorgos Korfiatis
    if not m:
598 1a14083b Giorgos Korfiatis
        return True
599 71c741dc Giorgos Korfiatis
    return m.check_action("join")
600 1a14083b Giorgos Korfiatis
601 1a14083b Giorgos Korfiatis
602 da4ac460 Giorgos Korfiatis
def new_membership(project, user, actor=None, reason=None):
603 1a14083b Giorgos Korfiatis
    m = ProjectMembership.objects.create(project=project, person=user)
604 da4ac460 Giorgos Korfiatis
    m._log_create(None, ProjectMembership.REQUESTED, actor=actor,
605 da4ac460 Giorgos Korfiatis
                  reason=reason)
606 1a14083b Giorgos Korfiatis
    return m
607 d4660e00 Giorgos Korfiatis
608 d07ce657 Giorgos Korfiatis
609 da4ac460 Giorgos Korfiatis
def join_project(project_id, request_user, reason=None):
610 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
611 ff67242a Giorgos Korfiatis
    join_project_checks(project)
612 d07ce657 Giorgos Korfiatis
613 1a14083b Giorgos Korfiatis
    try:
614 1a14083b Giorgos Korfiatis
        membership = get_membership(project.id, request_user.id)
615 71c741dc Giorgos Korfiatis
        if not membership.check_action("join"):
616 866e5768 Giorgos Korfiatis
            msg = _(astakos_messages.MEMBERSHIP_ASSOCIATED)
617 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(msg)
618 da4ac460 Giorgos Korfiatis
        membership.perform_action("join", actor=request_user, reason=reason)
619 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound:
620 da4ac460 Giorgos Korfiatis
        membership = new_membership(project, request_user, actor=request_user,
621 da4ac460 Giorgos Korfiatis
                                    reason=reason)
622 73fbaec4 Sofia Papagiannaki
623 4e057833 Sofia Papagiannaki
    join_policy = project.application.member_join_policy
624 7a08e179 Giorgos Korfiatis
    if (join_policy == AUTO_ACCEPT_POLICY and (
625 7a08e179 Giorgos Korfiatis
            not project.violates_members_limit(adding=1))):
626 da4ac460 Giorgos Korfiatis
        membership.perform_action("accept", actor=request_user, reason=reason)
627 e336910f Giorgos Korfiatis
        qh_sync_user(request_user)
628 f30f0170 Giorgos Korfiatis
        logger.info("User %s joined %s." %
629 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
630 bb6a4465 Giorgos Korfiatis
    else:
631 bb6a4465 Giorgos Korfiatis
        membership_request_notify(project, membership.person)
632 f30f0170 Giorgos Korfiatis
        logger.info("User %s requested to join %s." %
633 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
634 e1723ca1 Giorgos Korfiatis
    return membership
635 8dcaa6ac Giorgos Korfiatis
636 7a08e179 Giorgos Korfiatis
637 866e5768 Giorgos Korfiatis
MEMBERSHIP_ACTION_CHECKS = {
638 866e5768 Giorgos Korfiatis
    "leave":  leave_project_checks,
639 866e5768 Giorgos Korfiatis
    "cancel": cancel_membership_checks,
640 866e5768 Giorgos Korfiatis
    "accept": accept_membership_checks,
641 866e5768 Giorgos Korfiatis
    "reject": reject_membership_checks,
642 866e5768 Giorgos Korfiatis
    "remove": remove_membership_checks,
643 866e5768 Giorgos Korfiatis
}
644 866e5768 Giorgos Korfiatis
645 866e5768 Giorgos Korfiatis
646 866e5768 Giorgos Korfiatis
def membership_allowed_actions(membership, request_user):
647 866e5768 Giorgos Korfiatis
    allowed = []
648 866e5768 Giorgos Korfiatis
    for action, check in MEMBERSHIP_ACTION_CHECKS.iteritems():
649 866e5768 Giorgos Korfiatis
        try:
650 866e5768 Giorgos Korfiatis
            check(membership, request_user)
651 866e5768 Giorgos Korfiatis
            allowed.append(action)
652 f12bcb3d Giorgos Korfiatis
        except ProjectError:
653 866e5768 Giorgos Korfiatis
            pass
654 866e5768 Giorgos Korfiatis
    return allowed
655 866e5768 Giorgos Korfiatis
656 866e5768 Giorgos Korfiatis
657 6da04174 Giorgos Korfiatis
def submit_application(owner=None,
658 6da04174 Giorgos Korfiatis
                       name=None,
659 c4028837 Giorgos Korfiatis
                       project_id=None,
660 6da04174 Giorgos Korfiatis
                       homepage=None,
661 6da04174 Giorgos Korfiatis
                       description=None,
662 6da04174 Giorgos Korfiatis
                       start_date=None,
663 6da04174 Giorgos Korfiatis
                       end_date=None,
664 6da04174 Giorgos Korfiatis
                       member_join_policy=None,
665 6da04174 Giorgos Korfiatis
                       member_leave_policy=None,
666 6da04174 Giorgos Korfiatis
                       limit_on_members_number=None,
667 6da04174 Giorgos Korfiatis
                       comments=None,
668 b2369828 Giorgos Korfiatis
                       resources=None,
669 6da04174 Giorgos Korfiatis
                       request_user=None):
670 69c822cc Giorgos Korfiatis
671 c4028837 Giorgos Korfiatis
    project = None
672 c4028837 Giorgos Korfiatis
    if project_id is not None:
673 6335ad6f Giorgos Korfiatis
        project = get_project_for_update(project_id)
674 c5b0bbb7 Giorgos Korfiatis
        project_check_allowed(project, request_user, level=APPLICANT_LEVEL)
675 ee4aa6eb Giorgos Korfiatis
676 b2369828 Giorgos Korfiatis
    policies = validate_resource_policies(resources)
677 b2369828 Giorgos Korfiatis
678 9770ba6c Giorgos Korfiatis
    force = request_user.is_project_admin()
679 c4028837 Giorgos Korfiatis
    ok, limit = qh_add_pending_app(owner, project, force)
680 9770ba6c Giorgos Korfiatis
    if not ok:
681 c7c0ec58 Giorgos Korfiatis
        m = _(astakos_messages.REACHED_PENDING_APPLICATION_LIMIT) % limit
682 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
683 c7c0ec58 Giorgos Korfiatis
684 6da04174 Giorgos Korfiatis
    application = ProjectApplication(
685 6da04174 Giorgos Korfiatis
        applicant=request_user,
686 6da04174 Giorgos Korfiatis
        owner=owner,
687 6da04174 Giorgos Korfiatis
        name=name,
688 6da04174 Giorgos Korfiatis
        homepage=homepage,
689 6da04174 Giorgos Korfiatis
        description=description,
690 6da04174 Giorgos Korfiatis
        start_date=start_date,
691 6da04174 Giorgos Korfiatis
        end_date=end_date,
692 6da04174 Giorgos Korfiatis
        member_join_policy=member_join_policy,
693 6da04174 Giorgos Korfiatis
        member_leave_policy=member_leave_policy,
694 6da04174 Giorgos Korfiatis
        limit_on_members_number=limit_on_members_number,
695 6da04174 Giorgos Korfiatis
        comments=comments)
696 1352dabb Kostas Papadimitriou
697 c4028837 Giorgos Korfiatis
    if project is None:
698 6d583e07 Giorgos Korfiatis
        chain = new_chain()
699 6d583e07 Giorgos Korfiatis
        application.chain_id = chain.chain
700 6d583e07 Giorgos Korfiatis
        application.save()
701 6d583e07 Giorgos Korfiatis
        Project.objects.create(id=chain.chain, application=application)
702 3e3743f2 Giorgos Korfiatis
    else:
703 c4028837 Giorgos Korfiatis
        application.chain = project
704 6d583e07 Giorgos Korfiatis
        application.save()
705 c4028837 Giorgos Korfiatis
        if project.application.state != ProjectApplication.APPROVED:
706 c4028837 Giorgos Korfiatis
            project.application = application
707 c4028837 Giorgos Korfiatis
            project.save()
708 6d583e07 Giorgos Korfiatis
709 6d583e07 Giorgos Korfiatis
        pending = ProjectApplication.objects.filter(
710 c4028837 Giorgos Korfiatis
            chain=project,
711 6d583e07 Giorgos Korfiatis
            state=ProjectApplication.PENDING).exclude(id=application.id)
712 3e3743f2 Giorgos Korfiatis
        for app in pending:
713 3e3743f2 Giorgos Korfiatis
            app.state = ProjectApplication.REPLACED
714 3e3743f2 Giorgos Korfiatis
            app.save()
715 3e3743f2 Giorgos Korfiatis
716 b2369828 Giorgos Korfiatis
    if policies is not None:
717 b2369828 Giorgos Korfiatis
        set_resource_policies(application, policies)
718 f30f0170 Giorgos Korfiatis
    logger.info("User %s submitted %s." %
719 f30f0170 Giorgos Korfiatis
                (request_user.log_display, application.log_display))
720 a3eb3a95 Giorgos Korfiatis
    application_submit_notify(application)
721 a3eb3a95 Giorgos Korfiatis
    return application
722 73fbaec4 Sofia Papagiannaki
723 7a08e179 Giorgos Korfiatis
724 b2369828 Giorgos Korfiatis
def validate_resource_policies(policies):
725 b2369828 Giorgos Korfiatis
    if not isinstance(policies, dict):
726 b2369828 Giorgos Korfiatis
        raise ProjectBadRequest("Malformed resource policies")
727 b2369828 Giorgos Korfiatis
728 b2369828 Giorgos Korfiatis
    resource_names = policies.keys()
729 b2369828 Giorgos Korfiatis
    resources = Resource.objects.filter(name__in=resource_names)
730 b2369828 Giorgos Korfiatis
    resource_d = {}
731 b2369828 Giorgos Korfiatis
    for resource in resources:
732 b2369828 Giorgos Korfiatis
        resource_d[resource.name] = resource
733 b2369828 Giorgos Korfiatis
734 b2369828 Giorgos Korfiatis
    found = resource_d.keys()
735 b2369828 Giorgos Korfiatis
    nonex = [name for name in resource_names if name not in found]
736 b2369828 Giorgos Korfiatis
    if nonex:
737 f12bcb3d Giorgos Korfiatis
        raise ProjectBadRequest("Malformed resource policies")
738 b2369828 Giorgos Korfiatis
739 b2369828 Giorgos Korfiatis
    pols = []
740 b2369828 Giorgos Korfiatis
    for resource_name, specs in policies.iteritems():
741 b2369828 Giorgos Korfiatis
        p_capacity = specs.get("project_capacity")
742 b2369828 Giorgos Korfiatis
        m_capacity = specs.get("member_capacity")
743 b2369828 Giorgos Korfiatis
744 b2369828 Giorgos Korfiatis
        if p_capacity is not None and not isinstance(p_capacity, (int, long)):
745 f12bcb3d Giorgos Korfiatis
            raise ProjectBadRequest("Malformed resource policies")
746 b2369828 Giorgos Korfiatis
        if not isinstance(m_capacity, (int, long)):
747 f12bcb3d Giorgos Korfiatis
            raise ProjectBadRequest("Malformed resource policies")
748 b2369828 Giorgos Korfiatis
        pols.append((resource_d[resource_name], m_capacity, p_capacity))
749 b2369828 Giorgos Korfiatis
    return pols
750 b2369828 Giorgos Korfiatis
751 b2369828 Giorgos Korfiatis
752 b2369828 Giorgos Korfiatis
def set_resource_policies(application, policies):
753 b2369828 Giorgos Korfiatis
    for resource, m_capacity, p_capacity in policies:
754 b2369828 Giorgos Korfiatis
        g = application.projectresourcegrant_set
755 b2369828 Giorgos Korfiatis
        g.create(resource=resource,
756 b2369828 Giorgos Korfiatis
                 member_capacity=m_capacity,
757 b2369828 Giorgos Korfiatis
                 project_capacity=p_capacity)
758 b2369828 Giorgos Korfiatis
759 b2369828 Giorgos Korfiatis
760 64d0c13e Giorgos Korfiatis
def cancel_application(application_id, request_user=None, reason=""):
761 6335ad6f Giorgos Korfiatis
    get_project_of_application_for_update(application_id)
762 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
763 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=APPLICANT_LEVEL)
764 3c638f72 Giorgos Korfiatis
765 01bdbd17 Giorgos Korfiatis
    if not application.can_cancel():
766 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_CANCEL %
767 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
768 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
769 3c638f72 Giorgos Korfiatis
770 9770ba6c Giorgos Korfiatis
    qh_release_pending_app(application.owner)
771 9770ba6c Giorgos Korfiatis
772 3c638f72 Giorgos Korfiatis
    application.cancel()
773 f30f0170 Giorgos Korfiatis
    logger.info("%s has been cancelled." % (application.log_display))
774 3c638f72 Giorgos Korfiatis
775 7a08e179 Giorgos Korfiatis
776 64d0c13e Giorgos Korfiatis
def dismiss_application(application_id, request_user=None, reason=""):
777 6335ad6f Giorgos Korfiatis
    get_project_of_application_for_update(application_id)
778 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
779 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=APPLICANT_LEVEL)
780 3c638f72 Giorgos Korfiatis
781 01bdbd17 Giorgos Korfiatis
    if not application.can_dismiss():
782 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_DISMISS %
783 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
784 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
785 3c638f72 Giorgos Korfiatis
786 3c638f72 Giorgos Korfiatis
    application.dismiss()
787 f30f0170 Giorgos Korfiatis
    logger.info("%s has been dismissed." % (application.log_display))
788 3c638f72 Giorgos Korfiatis
789 7a08e179 Giorgos Korfiatis
790 64d0c13e Giorgos Korfiatis
def deny_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 01bdbd17 Giorgos Korfiatis
794 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=ADMIN_LEVEL)
795 d07ce657 Giorgos Korfiatis
796 01bdbd17 Giorgos Korfiatis
    if not application.can_deny():
797 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_DENY %
798 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
799 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
800 19eb3ee6 Giorgos Korfiatis
801 9770ba6c Giorgos Korfiatis
    qh_release_pending_app(application.owner)
802 9770ba6c Giorgos Korfiatis
803 2b745492 Giorgos Korfiatis
    application.deny(reason)
804 f30f0170 Giorgos Korfiatis
    logger.info("%s has been denied with reason \"%s\"." %
805 f30f0170 Giorgos Korfiatis
                (application.log_display, reason))
806 19eb3ee6 Giorgos Korfiatis
    application_deny_notify(application)
807 19eb3ee6 Giorgos Korfiatis
808 7a08e179 Giorgos Korfiatis
809 3c22bad0 Giorgos Korfiatis
def check_conflicting_projects(application):
810 6d583e07 Giorgos Korfiatis
    project = application.chain
811 3c22bad0 Giorgos Korfiatis
    new_project_name = application.name
812 8dcaa6ac Giorgos Korfiatis
    try:
813 3c22bad0 Giorgos Korfiatis
        q = Q(name=new_project_name) & ~Q(state=Project.TERMINATED)
814 3c22bad0 Giorgos Korfiatis
        conflicting_project = Project.objects.get(q)
815 3c22bad0 Giorgos Korfiatis
        if (conflicting_project != project):
816 3c22bad0 Giorgos Korfiatis
            m = (_("cannot approve: project with name '%s' "
817 8fb8d0cf Giorgos Korfiatis
                   "already exists (id: %s)") %
818 8fb8d0cf Giorgos Korfiatis
                 (new_project_name, conflicting_project.id))
819 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(m)  # invalid argument
820 3c22bad0 Giorgos Korfiatis
    except Project.DoesNotExist:
821 3c22bad0 Giorgos Korfiatis
        pass
822 3c22bad0 Giorgos Korfiatis
823 3c22bad0 Giorgos Korfiatis
824 3c22bad0 Giorgos Korfiatis
def approve_application(app_id, request_user=None, reason=""):
825 6335ad6f Giorgos Korfiatis
    project = get_project_of_application_for_update(app_id)
826 3c22bad0 Giorgos Korfiatis
    application = get_application(app_id)
827 8dcaa6ac Giorgos Korfiatis
828 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=ADMIN_LEVEL)
829 d07ce657 Giorgos Korfiatis
830 01bdbd17 Giorgos Korfiatis
    if not application.can_approve():
831 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_APPROVE %
832 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
833 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
834 01bdbd17 Giorgos Korfiatis
835 6d583e07 Giorgos Korfiatis
    check_conflicting_projects(application)
836 3c22bad0 Giorgos Korfiatis
837 3c22bad0 Giorgos Korfiatis
    # Pre-lock members and owner together in order to impose an ordering
838 3c22bad0 Giorgos Korfiatis
    # on locking users
839 6d583e07 Giorgos Korfiatis
    members = members_to_sync(project)
840 3c22bad0 Giorgos Korfiatis
    uids_to_sync = [member.id for member in members]
841 3c22bad0 Giorgos Korfiatis
    owner = application.owner
842 3c22bad0 Giorgos Korfiatis
    uids_to_sync.append(owner.id)
843 3c22bad0 Giorgos Korfiatis
    get_users_for_update(uids_to_sync)
844 3c22bad0 Giorgos Korfiatis
845 3c22bad0 Giorgos Korfiatis
    qh_release_pending_app(owner, locked=True)
846 3c22bad0 Giorgos Korfiatis
    application.approve(reason)
847 6d583e07 Giorgos Korfiatis
    project.application = application
848 6d583e07 Giorgos Korfiatis
    project.name = application.name
849 6d583e07 Giorgos Korfiatis
    project.save()
850 6d583e07 Giorgos Korfiatis
    if project.is_deactivated():
851 6d583e07 Giorgos Korfiatis
        project.resume()
852 3c22bad0 Giorgos Korfiatis
    qh_sync_locked_users(members)
853 f30f0170 Giorgos Korfiatis
    logger.info("%s has been approved." % (application.log_display))
854 a3eb3a95 Giorgos Korfiatis
    application_approve_notify(application)
855 eb9ff37a Sofia Papagiannaki
856 7a08e179 Giorgos Korfiatis
857 7eadc230 Giorgos Korfiatis
def check_expiration(execute=False):
858 7eadc230 Giorgos Korfiatis
    objects = Project.objects
859 7eadc230 Giorgos Korfiatis
    expired = objects.expired_projects()
860 7eadc230 Giorgos Korfiatis
    if execute:
861 7eadc230 Giorgos Korfiatis
        for project in expired:
862 9f715f94 Giorgos Korfiatis
            terminate(project.pk)
863 7eadc230 Giorgos Korfiatis
864 7eadc230 Giorgos Korfiatis
    return [project.expiration_info() for project in expired]
865 7eadc230 Giorgos Korfiatis
866 7a08e179 Giorgos Korfiatis
867 d07ce657 Giorgos Korfiatis
def terminate(project_id, request_user=None):
868 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
869 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
870 907f15db Giorgos Korfiatis
    checkAlive(project)
871 5b9e9530 Giorgos Korfiatis
872 5b9e9530 Giorgos Korfiatis
    project.terminate()
873 e336910f Giorgos Korfiatis
    qh_sync_project(project)
874 f30f0170 Giorgos Korfiatis
    logger.info("%s has been terminated." % (project))
875 570015d2 Giorgos Korfiatis
876 a3eb3a95 Giorgos Korfiatis
    project_termination_notify(project)
877 eb9ff37a Sofia Papagiannaki
878 7a08e179 Giorgos Korfiatis
879 d07ce657 Giorgos Korfiatis
def suspend(project_id, request_user=None):
880 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
881 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
882 db99f198 Giorgos Korfiatis
    checkAlive(project)
883 db99f198 Giorgos Korfiatis
884 db99f198 Giorgos Korfiatis
    project.suspend()
885 e336910f Giorgos Korfiatis
    qh_sync_project(project)
886 f30f0170 Giorgos Korfiatis
    logger.info("%s has been suspended." % (project))
887 570015d2 Giorgos Korfiatis
888 a3eb3a95 Giorgos Korfiatis
    project_suspension_notify(project)
889 db99f198 Giorgos Korfiatis
890 7a08e179 Giorgos Korfiatis
891 d07ce657 Giorgos Korfiatis
def resume(project_id, request_user=None):
892 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
893 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
894 db99f198 Giorgos Korfiatis
895 db99f198 Giorgos Korfiatis
    if not project.is_suspended:
896 3805be31 Giorgos Korfiatis
        m = _(astakos_messages.NOT_SUSPENDED_PROJECT) % project.id
897 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
898 db99f198 Giorgos Korfiatis
899 db99f198 Giorgos Korfiatis
    project.resume()
900 e336910f Giorgos Korfiatis
    qh_sync_project(project)
901 f30f0170 Giorgos Korfiatis
    logger.info("%s has been unsuspended." % (project))
902 ff67242a Giorgos Korfiatis
903 7a08e179 Giorgos Korfiatis
904 3f5851eb Giorgos Korfiatis
def _partition_by(f, l):
905 3f5851eb Giorgos Korfiatis
    d = {}
906 3f5851eb Giorgos Korfiatis
    for x in l:
907 3f5851eb Giorgos Korfiatis
        group = f(x)
908 3f5851eb Giorgos Korfiatis
        group_l = d.get(group, [])
909 3f5851eb Giorgos Korfiatis
        group_l.append(x)
910 3f5851eb Giorgos Korfiatis
        d[group] = group_l
911 3f5851eb Giorgos Korfiatis
    return d
912 3f5851eb Giorgos Korfiatis
913 3f5851eb Giorgos Korfiatis
914 3f5851eb Giorgos Korfiatis
def count_pending_app(users):
915 103086a4 Giorgos Korfiatis
    users = list(users)
916 3f5851eb Giorgos Korfiatis
    apps = ProjectApplication.objects.filter(state=ProjectApplication.PENDING,
917 3f5851eb Giorgos Korfiatis
                                             owner__in=users)
918 3f5851eb Giorgos Korfiatis
    apps_d = _partition_by(lambda a: a.owner.uuid, apps)
919 3f5851eb Giorgos Korfiatis
920 3f5851eb Giorgos Korfiatis
    usage = {}
921 3f5851eb Giorgos Korfiatis
    for user in users:
922 3f5851eb Giorgos Korfiatis
        uuid = user.uuid
923 3f5851eb Giorgos Korfiatis
        usage[uuid] = len(apps_d.get(uuid, []))
924 3f5851eb Giorgos Korfiatis
    return usage
925 3f5851eb Giorgos Korfiatis
926 3f5851eb Giorgos Korfiatis
927 c4028837 Giorgos Korfiatis
def get_pending_app_diff(user, project):
928 c4028837 Giorgos Korfiatis
    if project is None:
929 9770ba6c Giorgos Korfiatis
        diff = 1
930 9770ba6c Giorgos Korfiatis
    else:
931 9770ba6c Giorgos Korfiatis
        objs = ProjectApplication.objects
932 c4028837 Giorgos Korfiatis
        q = objs.filter(chain=project, state=ProjectApplication.PENDING)
933 9770ba6c Giorgos Korfiatis
        count = q.count()
934 9770ba6c Giorgos Korfiatis
        diff = 1 - count
935 3c22bad0 Giorgos Korfiatis
    return diff
936 3c22bad0 Giorgos Korfiatis
937 3c22bad0 Giorgos Korfiatis
938 c4028837 Giorgos Korfiatis
def qh_add_pending_app(user, project=None, force=False):
939 3c22bad0 Giorgos Korfiatis
    user = AstakosUser.forupdate.get_for_update(id=user.id)
940 c4028837 Giorgos Korfiatis
    diff = get_pending_app_diff(user, project)
941 3c22bad0 Giorgos Korfiatis
    return register_pending_apps(user, diff, force)
942 3c22bad0 Giorgos Korfiatis
943 c7c0ec58 Giorgos Korfiatis
944 c4028837 Giorgos Korfiatis
def check_pending_app_quota(user, project=None):
945 c4028837 Giorgos Korfiatis
    diff = get_pending_app_diff(user, project)
946 3c22bad0 Giorgos Korfiatis
    quota = get_pending_app_quota(user)
947 3c22bad0 Giorgos Korfiatis
    limit = quota['limit']
948 3c22bad0 Giorgos Korfiatis
    usage = quota['usage']
949 3c22bad0 Giorgos Korfiatis
    if usage + diff > limit:
950 3c22bad0 Giorgos Korfiatis
        return False, limit
951 3c22bad0 Giorgos Korfiatis
    return True, None
952 c7c0ec58 Giorgos Korfiatis
953 c7c0ec58 Giorgos Korfiatis
954 3c22bad0 Giorgos Korfiatis
def qh_release_pending_app(user, locked=False):
955 3c22bad0 Giorgos Korfiatis
    if not locked:
956 3c22bad0 Giorgos Korfiatis
        user = AstakosUser.forupdate.get_for_update(id=user.id)
957 9e3af524 Giorgos Korfiatis
    register_pending_apps(user, -1)