Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ 9202a57d

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

186 f36af44a Antony Chazapis
    Raises SMTPException, socket.error
187 f36af44a Antony Chazapis
    """
188 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.GREETING_EMAIL_SUBJECT)
189 f36af44a Antony Chazapis
    message = render_to_string(email_template_name, {
190 5ce3ce4f Sofia Papagiannaki
                               'user': user,
191 8c8e318d Kostas Papadimitriou
                               'url': join_urls(settings.BASE_HOST,
192 8c8e318d Kostas Papadimitriou
                                                reverse('index')),
193 6c7af65c Georgios D. Tsoukalas
                               'baseurl': settings.BASE_URL,
194 8998f09a Sofia Papagiannaki
                               'site_name': settings.SITENAME,
195 8998f09a Sofia Papagiannaki
                               'support': settings.CONTACT_EMAIL})
196 1cbce16f Sofia Papagiannaki
    sender = settings.SERVER_EMAIL
197 e7cb4085 Kostas Papadimitriou
    send_mail(subject, message, sender, [user.email],
198 e7cb4085 Kostas Papadimitriou
              connection=get_connection())
199 d59f5608 Sofia Papagiannaki
    msg = 'Sent greeting %s'
200 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, user.log_display)
201 8f5a3a06 Sofia Papagiannaki
202 5ce3ce4f Sofia Papagiannaki
203 8f5a3a06 Sofia Papagiannaki
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
204 cfb7dd4f Giorgos Korfiatis
    subject = _(astakos_messages.FEEDBACK_EMAIL_SUBJECT)
205 7d145e78 Sofia Papagiannaki
    from_email = settings.SERVER_EMAIL
206 0a7a4104 Kostas Papadimitriou
    recipient_list = [e[1] for e in settings.HELPDESK]
207 8f5a3a06 Sofia Papagiannaki
    content = render_to_string(email_template_name, {
208 8f5a3a06 Sofia Papagiannaki
        'message': msg,
209 8f5a3a06 Sofia Papagiannaki
        'data': data,
210 8f5a3a06 Sofia Papagiannaki
        'user': user})
211 e182fc26 Sofia Papagiannaki
    send_mail(subject, content, from_email, recipient_list,
212 e182fc26 Sofia Papagiannaki
              connection=get_connection())
213 d59f5608 Sofia Papagiannaki
    msg = 'Sent feedback from %s'
214 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, user.log_display)
215 f36af44a Antony Chazapis
216 5ce3ce4f Sofia Papagiannaki
217 d59f5608 Sofia Papagiannaki
def send_change_email(ec, request,
218 d59f5608 Sofia Papagiannaki
                      email_template_name=
219 d59f5608 Sofia Papagiannaki
                      'registration/email_change_email.txt'):
220 e182fc26 Sofia Papagiannaki
    url = ec.get_url()
221 e182fc26 Sofia Papagiannaki
    url = request.build_absolute_uri(url)
222 80a548e3 Christos Stavrakakis
    c = {'url': url,
223 80a548e3 Christos Stavrakakis
         'site_name': settings.SITENAME,
224 8fb8d0cf Giorgos Korfiatis
         'support': settings.CONTACT_EMAIL,
225 734107ef Kostas Papadimitriou
         'ec': ec}
226 734107ef Kostas Papadimitriou
    message = render_to_string(email_template_name, c)
227 e182fc26 Sofia Papagiannaki
    from_email = settings.SERVER_EMAIL
228 cfb7dd4f Giorgos Korfiatis
    send_mail(_(astakos_messages.EMAIL_CHANGE_EMAIL_SUBJECT), message,
229 cfb7dd4f Giorgos Korfiatis
              from_email,
230 734107ef Kostas Papadimitriou
              [ec.new_email_address], connection=get_connection())
231 d59f5608 Sofia Papagiannaki
    msg = 'Sent change email for %s'
232 d59f5608 Sofia Papagiannaki
    logger.log(settings.LOGGING_LEVEL, msg, ec.user.log_display)
233 f36af44a Antony Chazapis
234 5ce3ce4f Sofia Papagiannaki
235 73fbaec4 Sofia Papagiannaki
def invite(inviter, email, realname):
236 73fbaec4 Sofia Papagiannaki
    inv = Invitation(inviter=inviter, username=email, realname=realname)
237 73fbaec4 Sofia Papagiannaki
    inv.save()
238 73fbaec4 Sofia Papagiannaki
    send_invitation(inv)
239 e30537f1 Sofia Papagiannaki
    inviter.invitations = max(0, inviter.invitations - 1)
240 73fbaec4 Sofia Papagiannaki
    inviter.save()
241 5ce3ce4f Sofia Papagiannaki
242 73fbaec4 Sofia Papagiannaki
243 7a08e179 Giorgos Korfiatis
### PROJECT FUNCTIONS ###
244 fcc1e93f Sofia Papagiannaki
245 f12bcb3d Giorgos Korfiatis
246 f12bcb3d Giorgos Korfiatis
class ProjectError(Exception):
247 f12bcb3d Giorgos Korfiatis
    pass
248 f12bcb3d Giorgos Korfiatis
249 f12bcb3d Giorgos Korfiatis
250 f12bcb3d Giorgos Korfiatis
class ProjectNotFound(ProjectError):
251 f12bcb3d Giorgos Korfiatis
    pass
252 f12bcb3d Giorgos Korfiatis
253 f12bcb3d Giorgos Korfiatis
254 f12bcb3d Giorgos Korfiatis
class ProjectForbidden(ProjectError):
255 f12bcb3d Giorgos Korfiatis
    pass
256 f12bcb3d Giorgos Korfiatis
257 f12bcb3d Giorgos Korfiatis
258 f12bcb3d Giorgos Korfiatis
class ProjectBadRequest(ProjectError):
259 f12bcb3d Giorgos Korfiatis
    pass
260 f12bcb3d Giorgos Korfiatis
261 f12bcb3d Giorgos Korfiatis
262 f12bcb3d Giorgos Korfiatis
class ProjectConflict(ProjectError):
263 f12bcb3d Giorgos Korfiatis
    pass
264 f12bcb3d Giorgos Korfiatis
265 b0686c16 Giorgos Korfiatis
AUTO_ACCEPT_POLICY = 1
266 7a08e179 Giorgos Korfiatis
MODERATED_POLICY = 2
267 7a08e179 Giorgos Korfiatis
CLOSED_POLICY = 3
268 7a08e179 Giorgos Korfiatis
269 7a08e179 Giorgos Korfiatis
POLICIES = [AUTO_ACCEPT_POLICY, MODERATED_POLICY, CLOSED_POLICY]
270 b0686c16 Giorgos Korfiatis
271 73fbaec4 Sofia Papagiannaki
272 a75dbd7b Giorgos Korfiatis
def get_related_project_id(application_id):
273 a75dbd7b Giorgos Korfiatis
    try:
274 a75dbd7b Giorgos Korfiatis
        app = ProjectApplication.objects.get(id=application_id)
275 6d583e07 Giorgos Korfiatis
        return app.chain_id
276 7a08e179 Giorgos Korfiatis
    except ProjectApplication.DoesNotExist:
277 0932ac43 Giorgos Korfiatis
        return None
278 0932ac43 Giorgos Korfiatis
279 7a08e179 Giorgos Korfiatis
280 eb9ff37a Sofia Papagiannaki
def get_project_by_id(project_id):
281 eb9ff37a Sofia Papagiannaki
    try:
282 2556cf45 Giorgos Korfiatis
        return Project.objects.select_related(
283 2556cf45 Giorgos Korfiatis
            "application", "application__owner",
284 2556cf45 Giorgos Korfiatis
            "application__applicant").get(id=project_id)
285 eb9ff37a Sofia Papagiannaki
    except Project.DoesNotExist:
286 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
287 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
288 7a08e179 Giorgos Korfiatis
289 eb9ff37a Sofia Papagiannaki
290 88f5242e Giorgos Korfiatis
def get_project_by_uuid(uuid):
291 88f5242e Giorgos Korfiatis
    try:
292 88f5242e Giorgos Korfiatis
        return Project.objects.get(uuid=uuid)
293 88f5242e Giorgos Korfiatis
    except Project.DoesNotExist:
294 88f5242e Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % uuid
295 88f5242e Giorgos Korfiatis
        raise ProjectNotFound(m)
296 88f5242e Giorgos Korfiatis
297 88f5242e Giorgos Korfiatis
298 6335ad6f Giorgos Korfiatis
def get_project_for_update(project_id):
299 8dcaa6ac Giorgos Korfiatis
    try:
300 88f5242e Giorgos Korfiatis
        try:
301 88f5242e Giorgos Korfiatis
            project_id = int(project_id)
302 88f5242e Giorgos Korfiatis
            return Project.objects.select_for_update().get(id=project_id)
303 88f5242e Giorgos Korfiatis
        except ValueError:
304 88f5242e Giorgos Korfiatis
            return Project.objects.select_for_update().get(uuid=project_id)
305 6335ad6f Giorgos Korfiatis
    except Project.DoesNotExist:
306 6335ad6f Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
307 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
308 7a08e179 Giorgos Korfiatis
309 8dcaa6ac Giorgos Korfiatis
310 6335ad6f Giorgos Korfiatis
def get_project_of_application_for_update(app_id):
311 3c22bad0 Giorgos Korfiatis
    app = get_application(app_id)
312 6335ad6f Giorgos Korfiatis
    return get_project_for_update(app.chain_id)
313 3c22bad0 Giorgos Korfiatis
314 3c22bad0 Giorgos Korfiatis
315 1b52192e Giorgos Korfiatis
def get_project_lock():
316 c7e03d20 Giorgos Korfiatis
    ProjectLock.objects.select_for_update().get(pk=1)
317 1b52192e Giorgos Korfiatis
318 1b52192e Giorgos Korfiatis
319 3c22bad0 Giorgos Korfiatis
def get_application(application_id):
320 19eb3ee6 Giorgos Korfiatis
    try:
321 3c22bad0 Giorgos Korfiatis
        return ProjectApplication.objects.get(id=application_id)
322 19eb3ee6 Giorgos Korfiatis
    except ProjectApplication.DoesNotExist:
323 19eb3ee6 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_PROJECT_APPLICATION_ID) % application_id
324 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
325 19eb3ee6 Giorgos Korfiatis
326 7a08e179 Giorgos Korfiatis
327 6335ad6f Giorgos Korfiatis
def get_project_of_membership_for_update(memb_id):
328 dc946891 Giorgos Korfiatis
    m = get_membership_by_id(memb_id)
329 6335ad6f Giorgos Korfiatis
    return get_project_for_update(m.project_id)
330 dc946891 Giorgos Korfiatis
331 dc946891 Giorgos Korfiatis
332 3c049f6d Giorgos Korfiatis
def get_user_by_uuid(uuid):
333 3c049f6d Giorgos Korfiatis
    try:
334 3c049f6d Giorgos Korfiatis
        return AstakosUser.objects.get(uuid=uuid)
335 3c049f6d Giorgos Korfiatis
    except AstakosUser.DoesNotExist:
336 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.UNKNOWN_USER_ID) % uuid
337 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
338 3c049f6d Giorgos Korfiatis
339 97e93991 Kostas Papadimitriou
340 3c22bad0 Giorgos Korfiatis
def get_membership(project_id, user_id):
341 73fbaec4 Sofia Papagiannaki
    try:
342 3c22bad0 Giorgos Korfiatis
        objs = ProjectMembership.objects.select_related('project', 'person')
343 3c22bad0 Giorgos Korfiatis
        return objs.get(project__id=project_id, person__id=user_id)
344 73fbaec4 Sofia Papagiannaki
    except ProjectMembership.DoesNotExist:
345 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
346 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
347 7a08e179 Giorgos Korfiatis
348 73fbaec4 Sofia Papagiannaki
349 866e5768 Giorgos Korfiatis
def get_membership_by_id(memb_id):
350 7f3c4920 Giorgos Korfiatis
    try:
351 3c22bad0 Giorgos Korfiatis
        objs = ProjectMembership.objects.select_related('project', 'person')
352 866e5768 Giorgos Korfiatis
        return objs.get(id=memb_id)
353 7f3c4920 Giorgos Korfiatis
    except ProjectMembership.DoesNotExist:
354 7f3c4920 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
355 f12bcb3d Giorgos Korfiatis
        raise ProjectNotFound(m)
356 7f3c4920 Giorgos Korfiatis
357 7f3c4920 Giorgos Korfiatis
358 c5b0bbb7 Giorgos Korfiatis
ADMIN_LEVEL = 0
359 c5b0bbb7 Giorgos Korfiatis
OWNER_LEVEL = 1
360 362dadaa Giorgos Korfiatis
APPLICANT_LEVEL = 1
361 362dadaa Giorgos Korfiatis
ANY_LEVEL = 2
362 c5b0bbb7 Giorgos Korfiatis
363 c5b0bbb7 Giorgos Korfiatis
364 362dadaa Giorgos Korfiatis
def is_admin(user):
365 362dadaa Giorgos Korfiatis
    return not user or user.is_project_admin()
366 362dadaa Giorgos Korfiatis
367 d07ce657 Giorgos Korfiatis
368 362dadaa Giorgos Korfiatis
def _failure(silent=False):
369 c5b0bbb7 Giorgos Korfiatis
    if silent:
370 c5b0bbb7 Giorgos Korfiatis
        return False
371 d07ce657 Giorgos Korfiatis
372 d07ce657 Giorgos Korfiatis
    m = _(astakos_messages.NOT_ALLOWED)
373 f12bcb3d Giorgos Korfiatis
    raise ProjectForbidden(m)
374 d07ce657 Giorgos Korfiatis
375 907f15db Giorgos Korfiatis
376 c5b0bbb7 Giorgos Korfiatis
def membership_check_allowed(membership, request_user,
377 c5b0bbb7 Giorgos Korfiatis
                             level=OWNER_LEVEL, silent=False):
378 c5b0bbb7 Giorgos Korfiatis
    r = project_check_allowed(
379 c5b0bbb7 Giorgos Korfiatis
        membership.project, request_user, level, silent=True)
380 c5b0bbb7 Giorgos Korfiatis
381 362dadaa Giorgos Korfiatis
    if r or membership.person == request_user:
382 362dadaa Giorgos Korfiatis
        return True
383 362dadaa Giorgos Korfiatis
    return _failure(silent)
384 c5b0bbb7 Giorgos Korfiatis
385 c5b0bbb7 Giorgos Korfiatis
386 c5b0bbb7 Giorgos Korfiatis
def project_check_allowed(project, request_user,
387 c5b0bbb7 Giorgos Korfiatis
                          level=OWNER_LEVEL, silent=False):
388 362dadaa Giorgos Korfiatis
    if is_admin(request_user):
389 362dadaa Giorgos Korfiatis
        return True
390 362dadaa Giorgos Korfiatis
    if level <= ADMIN_LEVEL:
391 362dadaa Giorgos Korfiatis
        return _failure(silent)
392 362dadaa Giorgos Korfiatis
393 362dadaa Giorgos Korfiatis
    if project.owner == request_user:
394 362dadaa Giorgos Korfiatis
        return True
395 362dadaa Giorgos Korfiatis
    if level <= OWNER_LEVEL:
396 362dadaa Giorgos Korfiatis
        return _failure(silent)
397 362dadaa Giorgos Korfiatis
398 362dadaa Giorgos Korfiatis
    if project.state == Project.NORMAL and not project.private \
399 362dadaa Giorgos Korfiatis
            or bool(project.projectmembership_set.any_accepted().
400 362dadaa Giorgos Korfiatis
                    filter(person=request_user)):
401 362dadaa Giorgos Korfiatis
            return True
402 362dadaa Giorgos Korfiatis
    return _failure(silent)
403 c5b0bbb7 Giorgos Korfiatis
404 c5b0bbb7 Giorgos Korfiatis
405 c5b0bbb7 Giorgos Korfiatis
def app_check_allowed(application, request_user,
406 c5b0bbb7 Giorgos Korfiatis
                      level=OWNER_LEVEL, silent=False):
407 362dadaa Giorgos Korfiatis
    if is_admin(request_user):
408 362dadaa Giorgos Korfiatis
        return True
409 362dadaa Giorgos Korfiatis
    if level <= ADMIN_LEVEL:
410 362dadaa Giorgos Korfiatis
        return _failure(silent)
411 362dadaa Giorgos Korfiatis
412 362dadaa Giorgos Korfiatis
    if application.applicant == request_user:
413 362dadaa Giorgos Korfiatis
        return True
414 362dadaa Giorgos Korfiatis
    return _failure(silent)
415 c5b0bbb7 Giorgos Korfiatis
416 c5b0bbb7 Giorgos Korfiatis
417 907f15db Giorgos Korfiatis
def checkAlive(project):
418 907f15db Giorgos Korfiatis
    if not project.is_alive:
419 88f5242e Giorgos Korfiatis
        m = _(astakos_messages.NOT_ALIVE_PROJECT) % project.uuid
420 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
421 7a08e179 Giorgos Korfiatis
422 907f15db Giorgos Korfiatis
423 866e5768 Giorgos Korfiatis
def accept_membership_project_checks(project, request_user):
424 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user)
425 907f15db Giorgos Korfiatis
    checkAlive(project)
426 b0686c16 Giorgos Korfiatis
427 362dadaa Giorgos Korfiatis
    join_policy = project.member_join_policy
428 b0686c16 Giorgos Korfiatis
    if join_policy == CLOSED_POLICY:
429 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)
430 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
431 b0686c16 Giorgos Korfiatis
432 8dcaa6ac Giorgos Korfiatis
    if project.violates_members_limit(adding=1):
433 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_NUMBER_LIMIT_REACHED)
434 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
435 73fbaec4 Sofia Papagiannaki
436 d07ce657 Giorgos Korfiatis
437 866e5768 Giorgos Korfiatis
def accept_membership_checks(membership, request_user):
438 71c741dc Giorgos Korfiatis
    if not membership.check_action("accept"):
439 14f7f6a5 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
440 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
441 d4fc6292 Giorgos Korfiatis
442 866e5768 Giorgos Korfiatis
    project = membership.project
443 866e5768 Giorgos Korfiatis
    accept_membership_project_checks(project, request_user)
444 866e5768 Giorgos Korfiatis
445 866e5768 Giorgos Korfiatis
446 da4ac460 Giorgos Korfiatis
def accept_membership(memb_id, request_user=None, reason=None):
447 866e5768 Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
448 866e5768 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
449 866e5768 Giorgos Korfiatis
    accept_membership_checks(membership, request_user)
450 7f3c4920 Giorgos Korfiatis
    user = membership.person
451 da4ac460 Giorgos Korfiatis
    membership.perform_action("accept", actor=request_user, reason=reason)
452 a53ec93b Giorgos Korfiatis
    quotas.qh_sync_membership(membership)
453 f30f0170 Giorgos Korfiatis
    logger.info("User %s has been accepted in %s." %
454 7f3c4920 Giorgos Korfiatis
                (user.log_display, project))
455 73fbaec4 Sofia Papagiannaki
456 7f3bbafa Giorgos Korfiatis
    project_notif.membership_change_notify(project, user, 'accepted')
457 73fbaec4 Sofia Papagiannaki
    return membership
458 73fbaec4 Sofia Papagiannaki
459 7a08e179 Giorgos Korfiatis
460 866e5768 Giorgos Korfiatis
def reject_membership_checks(membership, request_user):
461 71c741dc Giorgos Korfiatis
    if not membership.check_action("reject"):
462 866e5768 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
463 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
464 866e5768 Giorgos Korfiatis
465 866e5768 Giorgos Korfiatis
    project = membership.project
466 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user)
467 907f15db Giorgos Korfiatis
    checkAlive(project)
468 e47fb17a Sofia Papagiannaki
469 d07ce657 Giorgos Korfiatis
470 da4ac460 Giorgos Korfiatis
def reject_membership(memb_id, request_user=None, reason=None):
471 6335ad6f Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
472 dc946891 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
473 866e5768 Giorgos Korfiatis
    reject_membership_checks(membership, request_user)
474 7f3c4920 Giorgos Korfiatis
    user = membership.person
475 da4ac460 Giorgos Korfiatis
    membership.perform_action("reject", actor=request_user, reason=reason)
476 f30f0170 Giorgos Korfiatis
    logger.info("Request of user %s for %s has been rejected." %
477 7f3c4920 Giorgos Korfiatis
                (user.log_display, project))
478 73fbaec4 Sofia Papagiannaki
479 7f3bbafa Giorgos Korfiatis
    project_notif.membership_change_notify(project, user, 'rejected')
480 73fbaec4 Sofia Papagiannaki
    return membership
481 73fbaec4 Sofia Papagiannaki
482 7a08e179 Giorgos Korfiatis
483 866e5768 Giorgos Korfiatis
def cancel_membership_checks(membership, request_user):
484 71c741dc Giorgos Korfiatis
    if not membership.check_action("cancel"):
485 aad0e329 Giorgos Korfiatis
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
486 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
487 aad0e329 Giorgos Korfiatis
488 c5b0bbb7 Giorgos Korfiatis
    membership_check_allowed(membership, request_user, level=ADMIN_LEVEL)
489 3c22bad0 Giorgos Korfiatis
    project = membership.project
490 866e5768 Giorgos Korfiatis
    checkAlive(project)
491 866e5768 Giorgos Korfiatis
492 866e5768 Giorgos Korfiatis
493 da4ac460 Giorgos Korfiatis
def cancel_membership(memb_id, request_user, reason=None):
494 866e5768 Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
495 866e5768 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
496 866e5768 Giorgos Korfiatis
    cancel_membership_checks(membership, request_user)
497 da4ac460 Giorgos Korfiatis
    membership.perform_action("cancel", actor=request_user, reason=reason)
498 f30f0170 Giorgos Korfiatis
    logger.info("Request of user %s for %s has been cancelled." %
499 f30f0170 Giorgos Korfiatis
                (membership.person.log_display, project))
500 aad0e329 Giorgos Korfiatis
501 7a08e179 Giorgos Korfiatis
502 866e5768 Giorgos Korfiatis
def remove_membership_checks(membership, request_user=None):
503 71c741dc Giorgos Korfiatis
    if not membership.check_action("remove"):
504 866e5768 Giorgos Korfiatis
        m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP)
505 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
506 866e5768 Giorgos Korfiatis
507 866e5768 Giorgos Korfiatis
    project = membership.project
508 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user)
509 907f15db Giorgos Korfiatis
    checkAlive(project)
510 73fbaec4 Sofia Papagiannaki
511 362dadaa Giorgos Korfiatis
    leave_policy = project.member_leave_policy
512 b0686c16 Giorgos Korfiatis
    if leave_policy == CLOSED_POLICY:
513 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)
514 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
515 7a08e179 Giorgos Korfiatis
516 b0686c16 Giorgos Korfiatis
517 da4ac460 Giorgos Korfiatis
def remove_membership(memb_id, request_user=None, reason=None):
518 6335ad6f Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
519 dc946891 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
520 866e5768 Giorgos Korfiatis
    remove_membership_checks(membership, request_user)
521 7f3c4920 Giorgos Korfiatis
    user = membership.person
522 da4ac460 Giorgos Korfiatis
    membership.perform_action("remove", actor=request_user, reason=reason)
523 a53ec93b Giorgos Korfiatis
    quotas.qh_sync_membership(membership)
524 f30f0170 Giorgos Korfiatis
    logger.info("User %s has been removed from %s." %
525 7f3c4920 Giorgos Korfiatis
                (user.log_display, project))
526 73fbaec4 Sofia Papagiannaki
527 7f3bbafa Giorgos Korfiatis
    project_notif.membership_change_notify(project, user, 'removed')
528 73fbaec4 Sofia Papagiannaki
    return membership
529 73fbaec4 Sofia Papagiannaki
530 7a08e179 Giorgos Korfiatis
531 2556cf45 Giorgos Korfiatis
def enroll_member_by_email(project_id, email, request_user=None, reason=None):
532 2556cf45 Giorgos Korfiatis
    try:
533 733f013d Giorgos Korfiatis
        user = AstakosUser.objects.accepted().get(email=email)
534 2556cf45 Giorgos Korfiatis
        return enroll_member(project_id, user, request_user, reason=reason)
535 2556cf45 Giorgos Korfiatis
    except AstakosUser.DoesNotExist:
536 733f013d Giorgos Korfiatis
        raise ProjectConflict(astakos_messages.UNKNOWN_USERS % email)
537 2556cf45 Giorgos Korfiatis
538 2556cf45 Giorgos Korfiatis
539 da4ac460 Giorgos Korfiatis
def enroll_member(project_id, user, request_user=None, reason=None):
540 f12bcb3d Giorgos Korfiatis
    try:
541 f12bcb3d Giorgos Korfiatis
        project = get_project_for_update(project_id)
542 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound as e:
543 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(e.message)
544 866e5768 Giorgos Korfiatis
    accept_membership_project_checks(project, request_user)
545 e05c541e Giorgos Korfiatis
546 1a14083b Giorgos Korfiatis
    try:
547 88f5242e Giorgos Korfiatis
        membership = get_membership(project.id, user.id)
548 71c741dc Giorgos Korfiatis
        if not membership.check_action("enroll"):
549 1a14083b Giorgos Korfiatis
            m = _(astakos_messages.MEMBERSHIP_ACCEPTED)
550 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(m)
551 a5aa11ee Giorgos Korfiatis
        membership.perform_action("enroll", actor=request_user, reason=reason)
552 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound:
553 a5aa11ee Giorgos Korfiatis
        membership = new_membership(project, user, actor=request_user,
554 a5aa11ee Giorgos Korfiatis
                                    enroll=True)
555 d4fc6292 Giorgos Korfiatis
556 a53ec93b Giorgos Korfiatis
    quotas.qh_sync_membership(membership)
557 f30f0170 Giorgos Korfiatis
    logger.info("User %s has been enrolled in %s." %
558 f30f0170 Giorgos Korfiatis
                (membership.person.log_display, project))
559 570015d2 Giorgos Korfiatis
560 7f3bbafa Giorgos Korfiatis
    project_notif.membership_enroll_notify(project, membership.person)
561 907f15db Giorgos Korfiatis
    return membership
562 8dcaa6ac Giorgos Korfiatis
563 7a08e179 Giorgos Korfiatis
564 866e5768 Giorgos Korfiatis
def leave_project_checks(membership, request_user):
565 71c741dc Giorgos Korfiatis
    if not membership.check_action("leave"):
566 866e5768 Giorgos Korfiatis
        m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP)
567 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
568 866e5768 Giorgos Korfiatis
569 c5b0bbb7 Giorgos Korfiatis
    membership_check_allowed(membership, request_user, level=ADMIN_LEVEL)
570 866e5768 Giorgos Korfiatis
    project = membership.project
571 907f15db Giorgos Korfiatis
    checkAlive(project)
572 8dcaa6ac Giorgos Korfiatis
573 362dadaa Giorgos Korfiatis
    leave_policy = project.member_leave_policy
574 b0686c16 Giorgos Korfiatis
    if leave_policy == CLOSED_POLICY:
575 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)
576 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
577 7a08e179 Giorgos Korfiatis
578 73fbaec4 Sofia Papagiannaki
579 9efd0075 Kostas Papadimitriou
def can_cancel_join_request(project, user):
580 9efd0075 Kostas Papadimitriou
    m = user.get_membership(project)
581 9efd0075 Kostas Papadimitriou
    if m is None:
582 9efd0075 Kostas Papadimitriou
        return False
583 9efd0075 Kostas Papadimitriou
    return m.state in [m.REQUESTED]
584 9efd0075 Kostas Papadimitriou
585 9efd0075 Kostas Papadimitriou
586 d4660e00 Giorgos Korfiatis
def can_leave_request(project, user):
587 d4660e00 Giorgos Korfiatis
    m = user.get_membership(project)
588 d4660e00 Giorgos Korfiatis
    if m is None:
589 d4660e00 Giorgos Korfiatis
        return False
590 866e5768 Giorgos Korfiatis
    try:
591 866e5768 Giorgos Korfiatis
        leave_project_checks(m, user)
592 f12bcb3d Giorgos Korfiatis
    except ProjectError:
593 866e5768 Giorgos Korfiatis
        return False
594 866e5768 Giorgos Korfiatis
    return True
595 d4660e00 Giorgos Korfiatis
596 d07ce657 Giorgos Korfiatis
597 da4ac460 Giorgos Korfiatis
def leave_project(memb_id, request_user, reason=None):
598 6335ad6f Giorgos Korfiatis
    project = get_project_of_membership_for_update(memb_id)
599 dc946891 Giorgos Korfiatis
    membership = get_membership_by_id(memb_id)
600 866e5768 Giorgos Korfiatis
    leave_project_checks(membership, request_user)
601 3c22bad0 Giorgos Korfiatis
602 bb6a4465 Giorgos Korfiatis
    auto_accepted = False
603 362dadaa Giorgos Korfiatis
    leave_policy = project.member_leave_policy
604 b0686c16 Giorgos Korfiatis
    if leave_policy == AUTO_ACCEPT_POLICY:
605 da4ac460 Giorgos Korfiatis
        membership.perform_action("remove", actor=request_user, reason=reason)
606 a53ec93b Giorgos Korfiatis
        quotas.qh_sync_membership(membership)
607 f30f0170 Giorgos Korfiatis
        logger.info("User %s has left %s." %
608 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
609 bb6a4465 Giorgos Korfiatis
        auto_accepted = True
610 73fbaec4 Sofia Papagiannaki
    else:
611 da4ac460 Giorgos Korfiatis
        membership.perform_action("leave_request", actor=request_user,
612 da4ac460 Giorgos Korfiatis
                                  reason=reason)
613 f30f0170 Giorgos Korfiatis
        logger.info("User %s requested to leave %s." %
614 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
615 84498bca Giorgos Korfiatis
        project_notif.membership_request_notify(
616 84498bca Giorgos Korfiatis
            project, membership.person, "leave")
617 bb6a4465 Giorgos Korfiatis
    return auto_accepted
618 73fbaec4 Sofia Papagiannaki
619 7a08e179 Giorgos Korfiatis
620 ff67242a Giorgos Korfiatis
def join_project_checks(project):
621 907f15db Giorgos Korfiatis
    checkAlive(project)
622 8dcaa6ac Giorgos Korfiatis
623 362dadaa Giorgos Korfiatis
    join_policy = project.member_join_policy
624 b0686c16 Giorgos Korfiatis
    if join_policy == CLOSED_POLICY:
625 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)
626 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
627 7a08e179 Giorgos Korfiatis
628 73fbaec4 Sofia Papagiannaki
629 b10ceccd Giorgos Korfiatis
Nothing = type('Nothing', (), {})
630 b10ceccd Giorgos Korfiatis
631 b10ceccd Giorgos Korfiatis
632 b10ceccd Giorgos Korfiatis
def can_join_request(project, user, membership=Nothing):
633 34244dfa Giorgos Korfiatis
    try:
634 34244dfa Giorgos Korfiatis
        join_project_checks(project)
635 f12bcb3d Giorgos Korfiatis
    except ProjectError:
636 d4660e00 Giorgos Korfiatis
        return False
637 34244dfa Giorgos Korfiatis
638 b10ceccd Giorgos Korfiatis
    m = (membership if membership is not Nothing
639 b10ceccd Giorgos Korfiatis
         else user.get_membership(project))
640 1a14083b Giorgos Korfiatis
    if not m:
641 1a14083b Giorgos Korfiatis
        return True
642 71c741dc Giorgos Korfiatis
    return m.check_action("join")
643 1a14083b Giorgos Korfiatis
644 1a14083b Giorgos Korfiatis
645 a5aa11ee Giorgos Korfiatis
def new_membership(project, user, actor=None, reason=None, enroll=False):
646 a5aa11ee Giorgos Korfiatis
    state = (ProjectMembership.ACCEPTED if enroll
647 a5aa11ee Giorgos Korfiatis
             else ProjectMembership.REQUESTED)
648 a5aa11ee Giorgos Korfiatis
    m = ProjectMembership.objects.create(
649 d1c95ad9 Giorgos Korfiatis
        project=project, person=user, state=state, initialized=enroll)
650 a5aa11ee Giorgos Korfiatis
    m._log_create(None, state, actor=actor, reason=reason)
651 1a14083b Giorgos Korfiatis
    return m
652 d4660e00 Giorgos Korfiatis
653 d07ce657 Giorgos Korfiatis
654 da4ac460 Giorgos Korfiatis
def join_project(project_id, request_user, reason=None):
655 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
656 ff67242a Giorgos Korfiatis
    join_project_checks(project)
657 d07ce657 Giorgos Korfiatis
658 1a14083b Giorgos Korfiatis
    try:
659 1a14083b Giorgos Korfiatis
        membership = get_membership(project.id, request_user.id)
660 71c741dc Giorgos Korfiatis
        if not membership.check_action("join"):
661 866e5768 Giorgos Korfiatis
            msg = _(astakos_messages.MEMBERSHIP_ASSOCIATED)
662 f12bcb3d Giorgos Korfiatis
            raise ProjectConflict(msg)
663 da4ac460 Giorgos Korfiatis
        membership.perform_action("join", actor=request_user, reason=reason)
664 f12bcb3d Giorgos Korfiatis
    except ProjectNotFound:
665 da4ac460 Giorgos Korfiatis
        membership = new_membership(project, request_user, actor=request_user,
666 da4ac460 Giorgos Korfiatis
                                    reason=reason)
667 73fbaec4 Sofia Papagiannaki
668 362dadaa Giorgos Korfiatis
    join_policy = project.member_join_policy
669 7a08e179 Giorgos Korfiatis
    if (join_policy == AUTO_ACCEPT_POLICY and (
670 7a08e179 Giorgos Korfiatis
            not project.violates_members_limit(adding=1))):
671 da4ac460 Giorgos Korfiatis
        membership.perform_action("accept", actor=request_user, reason=reason)
672 a53ec93b Giorgos Korfiatis
        quotas.qh_sync_membership(membership)
673 f30f0170 Giorgos Korfiatis
        logger.info("User %s joined %s." %
674 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
675 bb6a4465 Giorgos Korfiatis
    else:
676 84498bca Giorgos Korfiatis
        project_notif.membership_request_notify(
677 84498bca Giorgos Korfiatis
            project, membership.person, "join")
678 f30f0170 Giorgos Korfiatis
        logger.info("User %s requested to join %s." %
679 3c22bad0 Giorgos Korfiatis
                    (request_user.log_display, project))
680 e1723ca1 Giorgos Korfiatis
    return membership
681 8dcaa6ac Giorgos Korfiatis
682 7a08e179 Giorgos Korfiatis
683 866e5768 Giorgos Korfiatis
MEMBERSHIP_ACTION_CHECKS = {
684 866e5768 Giorgos Korfiatis
    "leave":  leave_project_checks,
685 866e5768 Giorgos Korfiatis
    "cancel": cancel_membership_checks,
686 866e5768 Giorgos Korfiatis
    "accept": accept_membership_checks,
687 866e5768 Giorgos Korfiatis
    "reject": reject_membership_checks,
688 866e5768 Giorgos Korfiatis
    "remove": remove_membership_checks,
689 866e5768 Giorgos Korfiatis
}
690 866e5768 Giorgos Korfiatis
691 866e5768 Giorgos Korfiatis
692 866e5768 Giorgos Korfiatis
def membership_allowed_actions(membership, request_user):
693 866e5768 Giorgos Korfiatis
    allowed = []
694 866e5768 Giorgos Korfiatis
    for action, check in MEMBERSHIP_ACTION_CHECKS.iteritems():
695 866e5768 Giorgos Korfiatis
        try:
696 866e5768 Giorgos Korfiatis
            check(membership, request_user)
697 866e5768 Giorgos Korfiatis
            allowed.append(action)
698 f12bcb3d Giorgos Korfiatis
        except ProjectError:
699 866e5768 Giorgos Korfiatis
            pass
700 866e5768 Giorgos Korfiatis
    return allowed
701 866e5768 Giorgos Korfiatis
702 866e5768 Giorgos Korfiatis
703 2c960473 Giorgos Korfiatis
def make_base_project(username):
704 2c960473 Giorgos Korfiatis
    chain = new_chain()
705 2c960473 Giorgos Korfiatis
    proj = create_project(
706 2c960473 Giorgos Korfiatis
        id=chain.chain,
707 2c960473 Giorgos Korfiatis
        last_application=None,
708 2c960473 Giorgos Korfiatis
        owner=None,
709 2c960473 Giorgos Korfiatis
        realname="tmp",
710 2c960473 Giorgos Korfiatis
        homepage="",
711 2c960473 Giorgos Korfiatis
        description=("base project for user " + username),
712 2c960473 Giorgos Korfiatis
        end_date=(datetime.now() + relativedelta(years=100)),
713 2c960473 Giorgos Korfiatis
        member_join_policy=CLOSED_POLICY,
714 2c960473 Giorgos Korfiatis
        member_leave_policy=CLOSED_POLICY,
715 2c960473 Giorgos Korfiatis
        limit_on_members_number=1,
716 2c960473 Giorgos Korfiatis
        private=True,
717 2c960473 Giorgos Korfiatis
        is_base=True)
718 2c960473 Giorgos Korfiatis
    proj.realname = "base:" + proj.uuid
719 2c960473 Giorgos Korfiatis
    proj.save()
720 2c960473 Giorgos Korfiatis
    # No quota are set; they will be filled in upon user acceptance
721 2c960473 Giorgos Korfiatis
    return proj
722 2c960473 Giorgos Korfiatis
723 2c960473 Giorgos Korfiatis
724 2c960473 Giorgos Korfiatis
def enable_base_project(user):
725 2c960473 Giorgos Korfiatis
    project = user.base_project
726 2c960473 Giorgos Korfiatis
    _fill_from_skeleton(project)
727 2c960473 Giorgos Korfiatis
    project.activate()
728 2c960473 Giorgos Korfiatis
    new_membership(project, user, enroll=True)
729 2c960473 Giorgos Korfiatis
    quotas.qh_sync_project(project)
730 2c960473 Giorgos Korfiatis
731 2c960473 Giorgos Korfiatis
732 5dc97d69 Giorgos Korfiatis
MODIFY_KEYS_MAIN = ["owner", "realname", "homepage", "description"]
733 5dc97d69 Giorgos Korfiatis
MODIFY_KEYS_EXTRA = ["end_date", "member_join_policy", "member_leave_policy",
734 5dc97d69 Giorgos Korfiatis
                     "limit_on_members_number", "private"]
735 5dc97d69 Giorgos Korfiatis
MODIFY_KEYS = MODIFY_KEYS_MAIN + MODIFY_KEYS_EXTRA
736 5dc97d69 Giorgos Korfiatis
737 5dc97d69 Giorgos Korfiatis
738 5dc97d69 Giorgos Korfiatis
def modifies_main_fields(request):
739 5dc97d69 Giorgos Korfiatis
    return set(request.keys()).intersection(MODIFY_KEYS_MAIN)
740 5dc97d69 Giorgos Korfiatis
741 5dc97d69 Giorgos Korfiatis
742 5dc97d69 Giorgos Korfiatis
def modify_project(project_id, request):
743 5dc97d69 Giorgos Korfiatis
    project = get_project_for_update(project_id)
744 5dc97d69 Giorgos Korfiatis
    if project.state not in Project.INITIALIZED_STATES:
745 5dc97d69 Giorgos Korfiatis
        m = _(astakos_messages.UNINITIALIZED_NO_MODIFY) % project.uuid
746 5dc97d69 Giorgos Korfiatis
        raise ProjectConflict(m)
747 5dc97d69 Giorgos Korfiatis
748 5dc97d69 Giorgos Korfiatis
    if project.is_base:
749 5dc97d69 Giorgos Korfiatis
        main_fields = modifies_main_fields(request)
750 5dc97d69 Giorgos Korfiatis
        if main_fields:
751 5dc97d69 Giorgos Korfiatis
            m = (_(astakos_messages.BASE_NO_MODIFY_FIELDS)
752 5dc97d69 Giorgos Korfiatis
                 % ", ".join(map(str, main_fields)))
753 5dc97d69 Giorgos Korfiatis
            raise ProjectBadRequest(m)
754 5dc97d69 Giorgos Korfiatis
755 5dc97d69 Giorgos Korfiatis
    new_name = request.get("realname")
756 5dc97d69 Giorgos Korfiatis
    if new_name is not None and project.is_alive:
757 5dc97d69 Giorgos Korfiatis
        check_conflicting_projects(project, new_name)
758 5dc97d69 Giorgos Korfiatis
        project.realname = new_name
759 5dc97d69 Giorgos Korfiatis
        project.name = new_name
760 5dc97d69 Giorgos Korfiatis
        project.save()
761 5dc97d69 Giorgos Korfiatis
762 5dc97d69 Giorgos Korfiatis
    _modify_projects(Project.objects.filter(id=project.id), request)
763 5dc97d69 Giorgos Korfiatis
764 5dc97d69 Giorgos Korfiatis
765 5dc97d69 Giorgos Korfiatis
def modify_projects_in_bulk(flt, request):
766 5dc97d69 Giorgos Korfiatis
    main_fields = modifies_main_fields(request)
767 5dc97d69 Giorgos Korfiatis
    if main_fields:
768 5dc97d69 Giorgos Korfiatis
        raise ProjectBadRequest("Cannot modify field(s) '%s' in bulk" %
769 5dc97d69 Giorgos Korfiatis
                                ", ".join(map(str, main_fields)))
770 5dc97d69 Giorgos Korfiatis
771 5dc97d69 Giorgos Korfiatis
    projects = Project.objects.initialized(flt).select_for_update()
772 5dc97d69 Giorgos Korfiatis
    _modify_projects(projects, request)
773 5dc97d69 Giorgos Korfiatis
774 5dc97d69 Giorgos Korfiatis
775 5dc97d69 Giorgos Korfiatis
def _modify_projects(projects, request):
776 5dc97d69 Giorgos Korfiatis
    upds = {}
777 5dc97d69 Giorgos Korfiatis
    for key in MODIFY_KEYS:
778 5dc97d69 Giorgos Korfiatis
        value = request.get(key)
779 5dc97d69 Giorgos Korfiatis
        if value is not None:
780 5dc97d69 Giorgos Korfiatis
            upds[key] = value
781 5dc97d69 Giorgos Korfiatis
    projects.update(**upds)
782 5dc97d69 Giorgos Korfiatis
783 5dc97d69 Giorgos Korfiatis
    changed_resources = set()
784 5dc97d69 Giorgos Korfiatis
    pquotas = []
785 5dc97d69 Giorgos Korfiatis
    req_policies = request.get("resources", {})
786 5dc97d69 Giorgos Korfiatis
    req_policies = validate_resource_policies(req_policies, admin=True)
787 5dc97d69 Giorgos Korfiatis
    for project in projects:
788 5dc97d69 Giorgos Korfiatis
        for resource, m_capacity, p_capacity in req_policies:
789 5dc97d69 Giorgos Korfiatis
            changed_resources.add(resource)
790 5dc97d69 Giorgos Korfiatis
            pquotas.append(
791 5dc97d69 Giorgos Korfiatis
                ProjectResourceQuota(
792 5dc97d69 Giorgos Korfiatis
                    project=project,
793 5dc97d69 Giorgos Korfiatis
                    resource=resource,
794 5dc97d69 Giorgos Korfiatis
                    member_capacity=m_capacity,
795 5dc97d69 Giorgos Korfiatis
                    project_capacity=p_capacity))
796 5dc97d69 Giorgos Korfiatis
    ProjectResourceQuota.objects.\
797 5dc97d69 Giorgos Korfiatis
        filter(project__in=projects, resource__in=changed_resources).delete()
798 5dc97d69 Giorgos Korfiatis
    ProjectResourceQuota.objects.bulk_create(pquotas)
799 5dc97d69 Giorgos Korfiatis
    quotas.qh_sync_projects(projects)
800 5dc97d69 Giorgos Korfiatis
801 5dc97d69 Giorgos Korfiatis
802 6da04174 Giorgos Korfiatis
def submit_application(owner=None,
803 6da04174 Giorgos Korfiatis
                       name=None,
804 c4028837 Giorgos Korfiatis
                       project_id=None,
805 6da04174 Giorgos Korfiatis
                       homepage=None,
806 6da04174 Giorgos Korfiatis
                       description=None,
807 6da04174 Giorgos Korfiatis
                       start_date=None,
808 6da04174 Giorgos Korfiatis
                       end_date=None,
809 6da04174 Giorgos Korfiatis
                       member_join_policy=None,
810 6da04174 Giorgos Korfiatis
                       member_leave_policy=None,
811 6da04174 Giorgos Korfiatis
                       limit_on_members_number=None,
812 62d30634 Giorgos Korfiatis
                       private=False,
813 6da04174 Giorgos Korfiatis
                       comments=None,
814 b2369828 Giorgos Korfiatis
                       resources=None,
815 6da04174 Giorgos Korfiatis
                       request_user=None):
816 69c822cc Giorgos Korfiatis
817 c4028837 Giorgos Korfiatis
    project = None
818 c4028837 Giorgos Korfiatis
    if project_id is not None:
819 6335ad6f Giorgos Korfiatis
        project = get_project_for_update(project_id)
820 c5b0bbb7 Giorgos Korfiatis
        project_check_allowed(project, request_user, level=APPLICANT_LEVEL)
821 362dadaa Giorgos Korfiatis
        if project.state not in Project.INITIALIZED_STATES:
822 362dadaa Giorgos Korfiatis
            raise ProjectConflict("Cannot modify an uninitialized project.")
823 ee4aa6eb Giorgos Korfiatis
824 b2369828 Giorgos Korfiatis
    policies = validate_resource_policies(resources)
825 b2369828 Giorgos Korfiatis
826 9770ba6c Giorgos Korfiatis
    force = request_user.is_project_admin()
827 362dadaa Giorgos Korfiatis
    ok, limit = qh_add_pending_app(request_user, project, force)
828 9770ba6c Giorgos Korfiatis
    if not ok:
829 c7c0ec58 Giorgos Korfiatis
        m = _(astakos_messages.REACHED_PENDING_APPLICATION_LIMIT) % limit
830 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
831 c7c0ec58 Giorgos Korfiatis
832 362dadaa Giorgos Korfiatis
    if project is None:
833 362dadaa Giorgos Korfiatis
        chain = new_chain()
834 362dadaa Giorgos Korfiatis
        project = create_project(
835 362dadaa Giorgos Korfiatis
            id=chain.chain,
836 362dadaa Giorgos Korfiatis
            owner=owner,
837 362dadaa Giorgos Korfiatis
            realname=name,
838 362dadaa Giorgos Korfiatis
            homepage=homepage,
839 362dadaa Giorgos Korfiatis
            description=description,
840 362dadaa Giorgos Korfiatis
            end_date=end_date,
841 362dadaa Giorgos Korfiatis
            member_join_policy=member_join_policy,
842 362dadaa Giorgos Korfiatis
            member_leave_policy=member_leave_policy,
843 362dadaa Giorgos Korfiatis
            limit_on_members_number=limit_on_members_number,
844 362dadaa Giorgos Korfiatis
            private=private)
845 362dadaa Giorgos Korfiatis
        if policies is not None:
846 362dadaa Giorgos Korfiatis
            set_project_resources(project, policies)
847 362dadaa Giorgos Korfiatis
848 362dadaa Giorgos Korfiatis
    application = ProjectApplication.objects.create(
849 6da04174 Giorgos Korfiatis
        applicant=request_user,
850 362dadaa Giorgos Korfiatis
        chain=project,
851 6da04174 Giorgos Korfiatis
        owner=owner,
852 6da04174 Giorgos Korfiatis
        name=name,
853 6da04174 Giorgos Korfiatis
        homepage=homepage,
854 6da04174 Giorgos Korfiatis
        description=description,
855 6da04174 Giorgos Korfiatis
        start_date=start_date,
856 6da04174 Giorgos Korfiatis
        end_date=end_date,
857 6da04174 Giorgos Korfiatis
        member_join_policy=member_join_policy,
858 6da04174 Giorgos Korfiatis
        member_leave_policy=member_leave_policy,
859 6da04174 Giorgos Korfiatis
        limit_on_members_number=limit_on_members_number,
860 62d30634 Giorgos Korfiatis
        private=private,
861 6da04174 Giorgos Korfiatis
        comments=comments)
862 362dadaa Giorgos Korfiatis
    if policies is not None:
863 362dadaa Giorgos Korfiatis
        set_application_resources(application, policies)
864 1352dabb Kostas Papadimitriou
865 362dadaa Giorgos Korfiatis
    project.last_application = application
866 362dadaa Giorgos Korfiatis
    project.save()
867 362dadaa Giorgos Korfiatis
868 362dadaa Giorgos Korfiatis
    ProjectApplication.objects.\
869 362dadaa Giorgos Korfiatis
        filter(chain=project, state=ProjectApplication.PENDING).\
870 362dadaa Giorgos Korfiatis
        exclude(id=application.id).\
871 362dadaa Giorgos Korfiatis
        update(state=ProjectApplication.REPLACED)
872 3e3743f2 Giorgos Korfiatis
873 f30f0170 Giorgos Korfiatis
    logger.info("User %s submitted %s." %
874 f30f0170 Giorgos Korfiatis
                (request_user.log_display, application.log_display))
875 84498bca Giorgos Korfiatis
    project_notif.application_notify(application, "submit")
876 a3eb3a95 Giorgos Korfiatis
    return application
877 73fbaec4 Sofia Papagiannaki
878 7a08e179 Giorgos Korfiatis
879 5dc97d69 Giorgos Korfiatis
def validate_resource_policies(policies, admin=False):
880 b2369828 Giorgos Korfiatis
    if not isinstance(policies, dict):
881 b2369828 Giorgos Korfiatis
        raise ProjectBadRequest("Malformed resource policies")
882 b2369828 Giorgos Korfiatis
883 b2369828 Giorgos Korfiatis
    resource_names = policies.keys()
884 5dc97d69 Giorgos Korfiatis
    resources = Resource.objects.filter(name__in=resource_names)
885 5dc97d69 Giorgos Korfiatis
    if not admin:
886 5dc97d69 Giorgos Korfiatis
        resources = resources.filter(api_visible=True)
887 5dc97d69 Giorgos Korfiatis
888 b2369828 Giorgos Korfiatis
    resource_d = {}
889 b2369828 Giorgos Korfiatis
    for resource in resources:
890 b2369828 Giorgos Korfiatis
        resource_d[resource.name] = resource
891 b2369828 Giorgos Korfiatis
892 b2369828 Giorgos Korfiatis
    found = resource_d.keys()
893 b2369828 Giorgos Korfiatis
    nonex = [name for name in resource_names if name not in found]
894 b2369828 Giorgos Korfiatis
    if nonex:
895 f12bcb3d Giorgos Korfiatis
        raise ProjectBadRequest("Malformed resource policies")
896 b2369828 Giorgos Korfiatis
897 b2369828 Giorgos Korfiatis
    pols = []
898 b2369828 Giorgos Korfiatis
    for resource_name, specs in policies.iteritems():
899 b2369828 Giorgos Korfiatis
        p_capacity = specs.get("project_capacity")
900 b2369828 Giorgos Korfiatis
        m_capacity = specs.get("member_capacity")
901 b2369828 Giorgos Korfiatis
902 362dadaa Giorgos Korfiatis
        if not isinstance(p_capacity, (int, long)) or \
903 362dadaa Giorgos Korfiatis
                not isinstance(m_capacity, (int, long)):
904 f12bcb3d Giorgos Korfiatis
            raise ProjectBadRequest("Malformed resource policies")
905 b2369828 Giorgos Korfiatis
        pols.append((resource_d[resource_name], m_capacity, p_capacity))
906 b2369828 Giorgos Korfiatis
    return pols
907 b2369828 Giorgos Korfiatis
908 b2369828 Giorgos Korfiatis
909 362dadaa Giorgos Korfiatis
def set_application_resources(application, policies):
910 362dadaa Giorgos Korfiatis
    grants = []
911 b2369828 Giorgos Korfiatis
    for resource, m_capacity, p_capacity in policies:
912 362dadaa Giorgos Korfiatis
        grants.append(
913 362dadaa Giorgos Korfiatis
            ProjectResourceGrant(
914 362dadaa Giorgos Korfiatis
                project_application=application,
915 362dadaa Giorgos Korfiatis
                resource=resource,
916 362dadaa Giorgos Korfiatis
                member_capacity=m_capacity,
917 362dadaa Giorgos Korfiatis
                project_capacity=p_capacity))
918 362dadaa Giorgos Korfiatis
    ProjectResourceGrant.objects.bulk_create(grants)
919 b2369828 Giorgos Korfiatis
920 b2369828 Giorgos Korfiatis
921 362dadaa Giorgos Korfiatis
def set_project_resources(project, policies):
922 362dadaa Giorgos Korfiatis
    grants = []
923 362dadaa Giorgos Korfiatis
    for resource, m_capacity, p_capacity in policies:
924 362dadaa Giorgos Korfiatis
        grants.append(
925 362dadaa Giorgos Korfiatis
            ProjectResourceQuota(
926 362dadaa Giorgos Korfiatis
                project=project,
927 362dadaa Giorgos Korfiatis
                resource=resource,
928 362dadaa Giorgos Korfiatis
                member_capacity=m_capacity,
929 362dadaa Giorgos Korfiatis
                project_capacity=p_capacity))
930 362dadaa Giorgos Korfiatis
    ProjectResourceQuota.objects.bulk_create(grants)
931 362dadaa Giorgos Korfiatis
932 362dadaa Giorgos Korfiatis
933 362dadaa Giorgos Korfiatis
def check_app_relevant(application, project, project_id):
934 362dadaa Giorgos Korfiatis
    if project_id is not None and project.uuid != project_id or \
935 362dadaa Giorgos Korfiatis
            project.last_application != application:
936 362dadaa Giorgos Korfiatis
        pid = project_id if project_id is not None else project.uuid
937 362dadaa Giorgos Korfiatis
        m = (_("%s is not a pending application for project %s.") %
938 362dadaa Giorgos Korfiatis
             (application.id, pid))
939 362dadaa Giorgos Korfiatis
        raise ProjectConflict(m)
940 362dadaa Giorgos Korfiatis
941 362dadaa Giorgos Korfiatis
942 362dadaa Giorgos Korfiatis
def cancel_application(application_id, project_id=None, request_user=None,
943 362dadaa Giorgos Korfiatis
                       reason=""):
944 362dadaa Giorgos Korfiatis
    project = get_project_of_application_for_update(application_id)
945 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
946 362dadaa Giorgos Korfiatis
    check_app_relevant(application, project, project_id)
947 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=APPLICANT_LEVEL)
948 3c638f72 Giorgos Korfiatis
949 01bdbd17 Giorgos Korfiatis
    if not application.can_cancel():
950 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_CANCEL %
951 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
952 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
953 3c638f72 Giorgos Korfiatis
954 362dadaa Giorgos Korfiatis
    qh_release_pending_app(application.applicant)
955 9770ba6c Giorgos Korfiatis
956 88beea39 Giorgos Korfiatis
    application.cancel(actor=request_user, reason=reason)
957 362dadaa Giorgos Korfiatis
    if project.state == Project.UNINITIALIZED:
958 362dadaa Giorgos Korfiatis
        project.set_deleted()
959 f30f0170 Giorgos Korfiatis
    logger.info("%s has been cancelled." % (application.log_display))
960 3c638f72 Giorgos Korfiatis
961 7a08e179 Giorgos Korfiatis
962 362dadaa Giorgos Korfiatis
def dismiss_application(application_id, project_id=None, request_user=None,
963 362dadaa Giorgos Korfiatis
                        reason=""):
964 362dadaa Giorgos Korfiatis
    project = get_project_of_application_for_update(application_id)
965 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
966 362dadaa Giorgos Korfiatis
    check_app_relevant(application, project, project_id)
967 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=APPLICANT_LEVEL)
968 3c638f72 Giorgos Korfiatis
969 01bdbd17 Giorgos Korfiatis
    if not application.can_dismiss():
970 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_DISMISS %
971 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
972 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
973 3c638f72 Giorgos Korfiatis
974 88beea39 Giorgos Korfiatis
    application.dismiss(actor=request_user, reason=reason)
975 362dadaa Giorgos Korfiatis
    if project.state == Project.UNINITIALIZED:
976 362dadaa Giorgos Korfiatis
        project.set_deleted()
977 f30f0170 Giorgos Korfiatis
    logger.info("%s has been dismissed." % (application.log_display))
978 3c638f72 Giorgos Korfiatis
979 7a08e179 Giorgos Korfiatis
980 362dadaa Giorgos Korfiatis
def deny_application(application_id, project_id=None, request_user=None,
981 362dadaa Giorgos Korfiatis
                     reason=""):
982 362dadaa Giorgos Korfiatis
    project = get_project_of_application_for_update(application_id)
983 3c22bad0 Giorgos Korfiatis
    application = get_application(application_id)
984 362dadaa Giorgos Korfiatis
    check_app_relevant(application, project, project_id)
985 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=ADMIN_LEVEL)
986 d07ce657 Giorgos Korfiatis
987 01bdbd17 Giorgos Korfiatis
    if not application.can_deny():
988 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_DENY %
989 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
990 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
991 19eb3ee6 Giorgos Korfiatis
992 362dadaa Giorgos Korfiatis
    qh_release_pending_app(application.applicant)
993 9770ba6c Giorgos Korfiatis
994 88beea39 Giorgos Korfiatis
    application.deny(actor=request_user, reason=reason)
995 f30f0170 Giorgos Korfiatis
    logger.info("%s has been denied with reason \"%s\"." %
996 f30f0170 Giorgos Korfiatis
                (application.log_display, reason))
997 84498bca Giorgos Korfiatis
    project_notif.application_notify(application, "deny")
998 19eb3ee6 Giorgos Korfiatis
999 7a08e179 Giorgos Korfiatis
1000 362dadaa Giorgos Korfiatis
def check_conflicting_projects(project, new_project_name):
1001 8dcaa6ac Giorgos Korfiatis
    try:
1002 362dadaa Giorgos Korfiatis
        q = Q(name=new_project_name) & ~Q(id=project.id)
1003 3c22bad0 Giorgos Korfiatis
        conflicting_project = Project.objects.get(q)
1004 362dadaa Giorgos Korfiatis
        m = (_("cannot approve: project with name '%s' "
1005 362dadaa Giorgos Korfiatis
               "already exists (id: %s)") %
1006 362dadaa Giorgos Korfiatis
             (new_project_name, conflicting_project.uuid))
1007 362dadaa Giorgos Korfiatis
        raise ProjectConflict(m)  # invalid argument
1008 3c22bad0 Giorgos Korfiatis
    except Project.DoesNotExist:
1009 3c22bad0 Giorgos Korfiatis
        pass
1010 3c22bad0 Giorgos Korfiatis
1011 3c22bad0 Giorgos Korfiatis
1012 362dadaa Giorgos Korfiatis
def approve_application(application_id, project_id=None, request_user=None,
1013 362dadaa Giorgos Korfiatis
                        reason=""):
1014 1b52192e Giorgos Korfiatis
    get_project_lock()
1015 362dadaa Giorgos Korfiatis
    project = get_project_of_application_for_update(application_id)
1016 362dadaa Giorgos Korfiatis
    application = get_application(application_id)
1017 362dadaa Giorgos Korfiatis
    check_app_relevant(application, project, project_id)
1018 c5b0bbb7 Giorgos Korfiatis
    app_check_allowed(application, request_user, level=ADMIN_LEVEL)
1019 d07ce657 Giorgos Korfiatis
1020 01bdbd17 Giorgos Korfiatis
    if not application.can_approve():
1021 7a08e179 Giorgos Korfiatis
        m = _(astakos_messages.APPLICATION_CANNOT_APPROVE %
1022 7a08e179 Giorgos Korfiatis
              (application.id, application.state_display()))
1023 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
1024 01bdbd17 Giorgos Korfiatis
1025 362dadaa Giorgos Korfiatis
    if application.name:
1026 362dadaa Giorgos Korfiatis
        check_conflicting_projects(project, application.name)
1027 3c22bad0 Giorgos Korfiatis
1028 a53ec93b Giorgos Korfiatis
    qh_release_pending_app(application.applicant)
1029 88beea39 Giorgos Korfiatis
    application.approve(actor=request_user, reason=reason)
1030 362dadaa Giorgos Korfiatis
1031 362dadaa Giorgos Korfiatis
    if project.state == Project.UNINITIALIZED:
1032 362dadaa Giorgos Korfiatis
        _fill_from_skeleton(project)
1033 362dadaa Giorgos Korfiatis
    else:
1034 362dadaa Giorgos Korfiatis
        _apply_modifications(project, application)
1035 362dadaa Giorgos Korfiatis
    project.activate(actor=request_user, reason=reason)
1036 362dadaa Giorgos Korfiatis
1037 a53ec93b Giorgos Korfiatis
    quotas.qh_sync_project(project)
1038 f30f0170 Giorgos Korfiatis
    logger.info("%s has been approved." % (application.log_display))
1039 84498bca Giorgos Korfiatis
    project_notif.application_notify(application, "approve")
1040 2c960473 Giorgos Korfiatis
    return project
1041 eb9ff37a Sofia Papagiannaki
1042 7a08e179 Giorgos Korfiatis
1043 362dadaa Giorgos Korfiatis
def _fill_from_skeleton(project):
1044 362dadaa Giorgos Korfiatis
    current_resources = set(ProjectResourceQuota.objects.
1045 362dadaa Giorgos Korfiatis
                            filter(project=project).
1046 362dadaa Giorgos Korfiatis
                            values_list("resource_id", flat=True))
1047 362dadaa Giorgos Korfiatis
    resources = Resource.objects.all()
1048 362dadaa Giorgos Korfiatis
    new_quotas = []
1049 362dadaa Giorgos Korfiatis
    for resource in resources:
1050 362dadaa Giorgos Korfiatis
        if resource.id not in current_resources:
1051 362dadaa Giorgos Korfiatis
            limit = quotas.pick_limit_scheme(project, resource)
1052 362dadaa Giorgos Korfiatis
            new_quotas.append(
1053 362dadaa Giorgos Korfiatis
                ProjectResourceQuota(
1054 362dadaa Giorgos Korfiatis
                    project=project,
1055 362dadaa Giorgos Korfiatis
                    resource=resource,
1056 362dadaa Giorgos Korfiatis
                    member_capacity=limit,
1057 362dadaa Giorgos Korfiatis
                    project_capacity=limit))
1058 362dadaa Giorgos Korfiatis
    ProjectResourceQuota.objects.bulk_create(new_quotas)
1059 362dadaa Giorgos Korfiatis
1060 362dadaa Giorgos Korfiatis
1061 362dadaa Giorgos Korfiatis
def _apply_modifications(project, application):
1062 362dadaa Giorgos Korfiatis
    FIELDS = [
1063 362dadaa Giorgos Korfiatis
        ("owner", "owner"),
1064 362dadaa Giorgos Korfiatis
        ("name", "realname"),
1065 362dadaa Giorgos Korfiatis
        ("homepage", "homepage"),
1066 362dadaa Giorgos Korfiatis
        ("description", "description"),
1067 362dadaa Giorgos Korfiatis
        ("end_date", "end_date"),
1068 362dadaa Giorgos Korfiatis
        ("member_join_policy", "member_join_policy"),
1069 362dadaa Giorgos Korfiatis
        ("member_leave_policy", "member_leave_policy"),
1070 362dadaa Giorgos Korfiatis
        ("limit_on_members_number", "limit_on_members_number"),
1071 362dadaa Giorgos Korfiatis
        ("private", "private"),
1072 362dadaa Giorgos Korfiatis
        ]
1073 362dadaa Giorgos Korfiatis
1074 362dadaa Giorgos Korfiatis
    changed = False
1075 362dadaa Giorgos Korfiatis
    for appfield, projectfield in FIELDS:
1076 362dadaa Giorgos Korfiatis
        value = getattr(application, appfield)
1077 362dadaa Giorgos Korfiatis
        if value is not None:
1078 362dadaa Giorgos Korfiatis
            changed = True
1079 362dadaa Giorgos Korfiatis
            setattr(project, projectfield, value)
1080 362dadaa Giorgos Korfiatis
    if changed:
1081 362dadaa Giorgos Korfiatis
        project.save()
1082 362dadaa Giorgos Korfiatis
1083 362dadaa Giorgos Korfiatis
    grants = application.projectresourcegrant_set.all()
1084 362dadaa Giorgos Korfiatis
    pquotas = []
1085 362dadaa Giorgos Korfiatis
    resources = []
1086 362dadaa Giorgos Korfiatis
    for grant in grants:
1087 362dadaa Giorgos Korfiatis
        resources.append(grant.resource)
1088 362dadaa Giorgos Korfiatis
        pquotas.append(
1089 362dadaa Giorgos Korfiatis
            ProjectResourceQuota(
1090 362dadaa Giorgos Korfiatis
                project=project,
1091 362dadaa Giorgos Korfiatis
                resource=grant.resource,
1092 362dadaa Giorgos Korfiatis
                member_capacity=grant.member_capacity,
1093 362dadaa Giorgos Korfiatis
                project_capacity=grant.project_capacity))
1094 362dadaa Giorgos Korfiatis
    ProjectResourceQuota.objects.\
1095 362dadaa Giorgos Korfiatis
        filter(project=project, resource__in=resources).delete()
1096 362dadaa Giorgos Korfiatis
    ProjectResourceQuota.objects.bulk_create(pquotas)
1097 362dadaa Giorgos Korfiatis
1098 362dadaa Giorgos Korfiatis
1099 7eadc230 Giorgos Korfiatis
def check_expiration(execute=False):
1100 7eadc230 Giorgos Korfiatis
    objects = Project.objects
1101 7eadc230 Giorgos Korfiatis
    expired = objects.expired_projects()
1102 7eadc230 Giorgos Korfiatis
    if execute:
1103 7eadc230 Giorgos Korfiatis
        for project in expired:
1104 9f715f94 Giorgos Korfiatis
            terminate(project.pk)
1105 7eadc230 Giorgos Korfiatis
1106 7eadc230 Giorgos Korfiatis
    return [project.expiration_info() for project in expired]
1107 7eadc230 Giorgos Korfiatis
1108 7a08e179 Giorgos Korfiatis
1109 88beea39 Giorgos Korfiatis
def terminate(project_id, request_user=None, reason=None):
1110 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
1111 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
1112 907f15db Giorgos Korfiatis
    checkAlive(project)
1113 5b9e9530 Giorgos Korfiatis
1114 88beea39 Giorgos Korfiatis
    project.terminate(actor=request_user, reason=reason)
1115 7f3bbafa Giorgos Korfiatis
    quotas.qh_sync_project(project)
1116 f30f0170 Giorgos Korfiatis
    logger.info("%s has been terminated." % (project))
1117 570015d2 Giorgos Korfiatis
1118 84498bca Giorgos Korfiatis
    project_notif.project_notify(project, "terminate")
1119 eb9ff37a Sofia Papagiannaki
1120 7a08e179 Giorgos Korfiatis
1121 88beea39 Giorgos Korfiatis
def suspend(project_id, request_user=None, reason=None):
1122 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
1123 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
1124 db99f198 Giorgos Korfiatis
    checkAlive(project)
1125 db99f198 Giorgos Korfiatis
1126 88beea39 Giorgos Korfiatis
    project.suspend(actor=request_user, reason=reason)
1127 7f3bbafa Giorgos Korfiatis
    quotas.qh_sync_project(project)
1128 f30f0170 Giorgos Korfiatis
    logger.info("%s has been suspended." % (project))
1129 570015d2 Giorgos Korfiatis
1130 84498bca Giorgos Korfiatis
    project_notif.project_notify(project, "suspend")
1131 db99f198 Giorgos Korfiatis
1132 7a08e179 Giorgos Korfiatis
1133 e872c133 Giorgos Korfiatis
def unsuspend(project_id, request_user=None, reason=None):
1134 6335ad6f Giorgos Korfiatis
    project = get_project_for_update(project_id)
1135 c5b0bbb7 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
1136 db99f198 Giorgos Korfiatis
1137 db99f198 Giorgos Korfiatis
    if not project.is_suspended:
1138 88f5242e Giorgos Korfiatis
        m = _(astakos_messages.NOT_SUSPENDED_PROJECT) % project.uuid
1139 f12bcb3d Giorgos Korfiatis
        raise ProjectConflict(m)
1140 db99f198 Giorgos Korfiatis
1141 88beea39 Giorgos Korfiatis
    project.resume(actor=request_user, reason=reason)
1142 7f3bbafa Giorgos Korfiatis
    quotas.qh_sync_project(project)
1143 f30f0170 Giorgos Korfiatis
    logger.info("%s has been unsuspended." % (project))
1144 84498bca Giorgos Korfiatis
    project_notif.project_notify(project, "unsuspend")
1145 e872c133 Giorgos Korfiatis
1146 e872c133 Giorgos Korfiatis
1147 e872c133 Giorgos Korfiatis
def reinstate(project_id, request_user=None, reason=None):
1148 e872c133 Giorgos Korfiatis
    get_project_lock()
1149 e872c133 Giorgos Korfiatis
    project = get_project_for_update(project_id)
1150 e872c133 Giorgos Korfiatis
    project_check_allowed(project, request_user, level=ADMIN_LEVEL)
1151 e872c133 Giorgos Korfiatis
1152 e872c133 Giorgos Korfiatis
    if not project.is_terminated:
1153 88f5242e Giorgos Korfiatis
        m = _(astakos_messages.NOT_TERMINATED_PROJECT) % project.uuid
1154 e872c133 Giorgos Korfiatis
        raise ProjectConflict(m)
1155 e872c133 Giorgos Korfiatis
1156 362dadaa Giorgos Korfiatis
    check_conflicting_projects(project, project.realname)
1157 e872c133 Giorgos Korfiatis
    project.resume(actor=request_user, reason=reason)
1158 7f3bbafa Giorgos Korfiatis
    quotas.qh_sync_project(project)
1159 e872c133 Giorgos Korfiatis
    logger.info("%s has been reinstated" % (project))
1160 84498bca Giorgos Korfiatis
    project_notif.project_notify(project, "reinstate")
1161 ff67242a Giorgos Korfiatis
1162 7a08e179 Giorgos Korfiatis
1163 3f5851eb Giorgos Korfiatis
def _partition_by(f, l):
1164 3f5851eb Giorgos Korfiatis
    d = {}
1165 3f5851eb Giorgos Korfiatis
    for x in l:
1166 3f5851eb Giorgos Korfiatis
        group = f(x)
1167 3f5851eb Giorgos Korfiatis
        group_l = d.get(group, [])
1168 3f5851eb Giorgos Korfiatis
        group_l.append(x)
1169 3f5851eb Giorgos Korfiatis
        d[group] = group_l
1170 3f5851eb Giorgos Korfiatis
    return d
1171 3f5851eb Giorgos Korfiatis
1172 3f5851eb Giorgos Korfiatis
1173 3f5851eb Giorgos Korfiatis
def count_pending_app(users):
1174 103086a4 Giorgos Korfiatis
    users = list(users)
1175 3f5851eb Giorgos Korfiatis
    apps = ProjectApplication.objects.filter(state=ProjectApplication.PENDING,
1176 3f5851eb Giorgos Korfiatis
                                             owner__in=users)
1177 3f5851eb Giorgos Korfiatis
    apps_d = _partition_by(lambda a: a.owner.uuid, apps)
1178 3f5851eb Giorgos Korfiatis
1179 3f5851eb Giorgos Korfiatis
    usage = {}
1180 3f5851eb Giorgos Korfiatis
    for user in users:
1181 3f5851eb Giorgos Korfiatis
        uuid = user.uuid
1182 f8cac8c7 Giorgos Korfiatis
        set_path(usage,
1183 f8cac8c7 Giorgos Korfiatis
                 [uuid, user.base_project.uuid, quotas.PENDING_APP_RESOURCE],
1184 f8cac8c7 Giorgos Korfiatis
                 len(apps_d.get(uuid, [])), createpath=True)
1185 3f5851eb Giorgos Korfiatis
    return usage
1186 3f5851eb Giorgos Korfiatis
1187 3f5851eb Giorgos Korfiatis
1188 74c9dfca Giorgos Korfiatis
def get_pending_app_diff(project):
1189 c4028837 Giorgos Korfiatis
    if project is None:
1190 9770ba6c Giorgos Korfiatis
        diff = 1
1191 9770ba6c Giorgos Korfiatis
    else:
1192 9770ba6c Giorgos Korfiatis
        objs = ProjectApplication.objects
1193 c4028837 Giorgos Korfiatis
        q = objs.filter(chain=project, state=ProjectApplication.PENDING)
1194 9770ba6c Giorgos Korfiatis
        count = q.count()
1195 9770ba6c Giorgos Korfiatis
        diff = 1 - count
1196 3c22bad0 Giorgos Korfiatis
    return diff
1197 3c22bad0 Giorgos Korfiatis
1198 3c22bad0 Giorgos Korfiatis
1199 a53ec93b Giorgos Korfiatis
def qh_add_pending_app(user, project=None, force=False, assign_project=None):
1200 a53ec93b Giorgos Korfiatis
    if assign_project is None:
1201 a53ec93b Giorgos Korfiatis
        assign_project = user.base_project
1202 74c9dfca Giorgos Korfiatis
    diff = get_pending_app_diff(project)
1203 a53ec93b Giorgos Korfiatis
    return quotas.register_pending_apps(user, assign_project,
1204 a53ec93b Giorgos Korfiatis
                                        diff, force=force)
1205 3c22bad0 Giorgos Korfiatis
1206 c7c0ec58 Giorgos Korfiatis
1207 c4028837 Giorgos Korfiatis
def check_pending_app_quota(user, project=None):
1208 74c9dfca Giorgos Korfiatis
    diff = get_pending_app_diff(project)
1209 7f3bbafa Giorgos Korfiatis
    quota = quotas.get_pending_app_quota(user)
1210 3c22bad0 Giorgos Korfiatis
    limit = quota['limit']
1211 3c22bad0 Giorgos Korfiatis
    usage = quota['usage']
1212 3c22bad0 Giorgos Korfiatis
    if usage + diff > limit:
1213 3c22bad0 Giorgos Korfiatis
        return False, limit
1214 3c22bad0 Giorgos Korfiatis
    return True, None
1215 c7c0ec58 Giorgos Korfiatis
1216 c7c0ec58 Giorgos Korfiatis
1217 a53ec93b Giorgos Korfiatis
def qh_release_pending_app(user, assign_project=None):
1218 a53ec93b Giorgos Korfiatis
    if assign_project is None:
1219 a53ec93b Giorgos Korfiatis
        assign_project = user.base_project
1220 a53ec93b Giorgos Korfiatis
    quotas.register_pending_apps(user, assign_project, -1)