Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ 9a94c0f1

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

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