Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / api / projects.py @ ff5edb80

History | View | Annotate | Download (22.4 kB)

1 ff5edb80 Giorgos Korfiatis
# Copyright 2013-2014 GRNET S.A. All rights reserved.
2 2556cf45 Giorgos Korfiatis
#
3 2556cf45 Giorgos Korfiatis
# Redistribution and use in source and binary forms, with or
4 2556cf45 Giorgos Korfiatis
# without modification, are permitted provided that the following
5 2556cf45 Giorgos Korfiatis
# conditions are met:
6 2556cf45 Giorgos Korfiatis
#
7 2556cf45 Giorgos Korfiatis
#   1. Redistributions of source code must retain the above
8 2556cf45 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
9 2556cf45 Giorgos Korfiatis
#      disclaimer.
10 2556cf45 Giorgos Korfiatis
#
11 2556cf45 Giorgos Korfiatis
#   2. Redistributions in binary form must reproduce the above
12 2556cf45 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
13 2556cf45 Giorgos Korfiatis
#      disclaimer in the documentation and/or other materials
14 2556cf45 Giorgos Korfiatis
#      provided with the distribution.
15 2556cf45 Giorgos Korfiatis
#
16 2556cf45 Giorgos Korfiatis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 2556cf45 Giorgos Korfiatis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 2556cf45 Giorgos Korfiatis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 2556cf45 Giorgos Korfiatis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 2556cf45 Giorgos Korfiatis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 2556cf45 Giorgos Korfiatis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 2556cf45 Giorgos Korfiatis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 2556cf45 Giorgos Korfiatis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 2556cf45 Giorgos Korfiatis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 2556cf45 Giorgos Korfiatis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 2556cf45 Giorgos Korfiatis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 2556cf45 Giorgos Korfiatis
# POSSIBILITY OF SUCH DAMAGE.
28 2556cf45 Giorgos Korfiatis
#
29 2556cf45 Giorgos Korfiatis
# The views and conclusions contained in the software and
30 2556cf45 Giorgos Korfiatis
# documentation are those of the authors and should not be
31 2556cf45 Giorgos Korfiatis
# interpreted as representing official policies, either expressed
32 2556cf45 Giorgos Korfiatis
# or implied, of GRNET S.A.
33 2556cf45 Giorgos Korfiatis
34 a23ac2f7 Giorgos Korfiatis
import re
35 2556cf45 Giorgos Korfiatis
from django.utils import simplejson as json
36 2556cf45 Giorgos Korfiatis
from django.views.decorators.csrf import csrf_exempt
37 2556cf45 Giorgos Korfiatis
from django.http import HttpResponse
38 2556cf45 Giorgos Korfiatis
from django.db.models import Q
39 a3e3917f Giorgos Korfiatis
from django.db import transaction
40 2556cf45 Giorgos Korfiatis
41 2556cf45 Giorgos Korfiatis
from astakos.api.util import json_response
42 2556cf45 Giorgos Korfiatis
43 2556cf45 Giorgos Korfiatis
from snf_django.lib import api
44 2556cf45 Giorgos Korfiatis
from snf_django.lib.api import faults
45 2556cf45 Giorgos Korfiatis
from .util import user_from_token, invert_dict, read_json_body
46 2556cf45 Giorgos Korfiatis
47 2556cf45 Giorgos Korfiatis
from astakos.im import functions
48 2556cf45 Giorgos Korfiatis
from astakos.im.models import (
49 2556cf45 Giorgos Korfiatis
    AstakosUser, Project, ProjectApplication, ProjectMembership,
50 362dadaa Giorgos Korfiatis
    ProjectResourceQuota, ProjectResourceGrant, ProjectLog,
51 362dadaa Giorgos Korfiatis
    ProjectMembershipLog)
52 2556cf45 Giorgos Korfiatis
import synnefo.util.date as date_util
53 362dadaa Giorgos Korfiatis
from synnefo.util import units
54 2556cf45 Giorgos Korfiatis
55 2556cf45 Giorgos Korfiatis
56 2556cf45 Giorgos Korfiatis
MEMBERSHIP_POLICY_SHOW = {
57 2556cf45 Giorgos Korfiatis
    functions.AUTO_ACCEPT_POLICY: "auto",
58 2556cf45 Giorgos Korfiatis
    functions.MODERATED_POLICY:   "moderated",
59 2556cf45 Giorgos Korfiatis
    functions.CLOSED_POLICY:      "closed",
60 2556cf45 Giorgos Korfiatis
}
61 2556cf45 Giorgos Korfiatis
62 2556cf45 Giorgos Korfiatis
MEMBERSHIP_POLICY = invert_dict(MEMBERSHIP_POLICY_SHOW)
63 2556cf45 Giorgos Korfiatis
64 2556cf45 Giorgos Korfiatis
APPLICATION_STATE_SHOW = {
65 2556cf45 Giorgos Korfiatis
    ProjectApplication.PENDING:   "pending",
66 2556cf45 Giorgos Korfiatis
    ProjectApplication.APPROVED:  "approved",
67 2556cf45 Giorgos Korfiatis
    ProjectApplication.REPLACED:  "replaced",
68 2556cf45 Giorgos Korfiatis
    ProjectApplication.DENIED:    "denied",
69 2556cf45 Giorgos Korfiatis
    ProjectApplication.DISMISSED: "dismissed",
70 2556cf45 Giorgos Korfiatis
    ProjectApplication.CANCELLED: "cancelled",
71 2556cf45 Giorgos Korfiatis
}
72 2556cf45 Giorgos Korfiatis
73 2556cf45 Giorgos Korfiatis
PROJECT_STATE_SHOW = {
74 362dadaa Giorgos Korfiatis
    Project.UNINITIALIZED: "uninitialized",
75 362dadaa Giorgos Korfiatis
    Project.NORMAL:        "active",
76 362dadaa Giorgos Korfiatis
    Project.SUSPENDED:     "suspended",
77 362dadaa Giorgos Korfiatis
    Project.TERMINATED:    "terminated",
78 362dadaa Giorgos Korfiatis
    Project.DELETED:       "deleted",
79 2556cf45 Giorgos Korfiatis
}
80 2556cf45 Giorgos Korfiatis
81 2556cf45 Giorgos Korfiatis
PROJECT_STATE = invert_dict(PROJECT_STATE_SHOW)
82 2556cf45 Giorgos Korfiatis
83 2556cf45 Giorgos Korfiatis
MEMBERSHIP_STATE_SHOW = {
84 2556cf45 Giorgos Korfiatis
    ProjectMembership.REQUESTED:       "requested",
85 2556cf45 Giorgos Korfiatis
    ProjectMembership.ACCEPTED:        "accepted",
86 2556cf45 Giorgos Korfiatis
    ProjectMembership.LEAVE_REQUESTED: "leave_requested",
87 2556cf45 Giorgos Korfiatis
    ProjectMembership.USER_SUSPENDED:  "suspended",
88 2556cf45 Giorgos Korfiatis
    ProjectMembership.REJECTED:        "rejected",
89 2556cf45 Giorgos Korfiatis
    ProjectMembership.CANCELLED:       "cancelled",
90 2556cf45 Giorgos Korfiatis
    ProjectMembership.REMOVED:         "removed",
91 2556cf45 Giorgos Korfiatis
}
92 2556cf45 Giorgos Korfiatis
93 2556cf45 Giorgos Korfiatis
94 362dadaa Giorgos Korfiatis
def _grant_details(grants):
95 2556cf45 Giorgos Korfiatis
    resources = {}
96 2556cf45 Giorgos Korfiatis
    for grant in grants:
97 85ae5a4c Giorgos Korfiatis
        if not grant.resource.api_visible:
98 85ae5a4c Giorgos Korfiatis
            continue
99 2556cf45 Giorgos Korfiatis
        resources[grant.resource.name] = {
100 2556cf45 Giorgos Korfiatis
            "member_capacity": grant.member_capacity,
101 2556cf45 Giorgos Korfiatis
            "project_capacity": grant.project_capacity,
102 2556cf45 Giorgos Korfiatis
        }
103 362dadaa Giorgos Korfiatis
    return resources
104 2556cf45 Giorgos Korfiatis
105 362dadaa Giorgos Korfiatis
106 362dadaa Giorgos Korfiatis
def _application_details(application, all_grants):
107 362dadaa Giorgos Korfiatis
    grants = all_grants.get(application.id, [])
108 362dadaa Giorgos Korfiatis
    resources = _grant_details(grants)
109 362dadaa Giorgos Korfiatis
    join_policy = MEMBERSHIP_POLICY_SHOW.get(application.member_join_policy)
110 362dadaa Giorgos Korfiatis
    leave_policy = MEMBERSHIP_POLICY_SHOW.get(application.member_leave_policy)
111 2556cf45 Giorgos Korfiatis
112 2556cf45 Giorgos Korfiatis
    d = {
113 362dadaa Giorgos Korfiatis
        "id": application.id,
114 362dadaa Giorgos Korfiatis
        "state": APPLICATION_STATE_SHOW[application.state],
115 2556cf45 Giorgos Korfiatis
        "name": application.name,
116 362dadaa Giorgos Korfiatis
        "owner": application.owner.uuid if application.owner else None,
117 2556cf45 Giorgos Korfiatis
        "applicant": application.applicant.uuid,
118 2556cf45 Giorgos Korfiatis
        "homepage": application.homepage,
119 2556cf45 Giorgos Korfiatis
        "description": application.description,
120 2556cf45 Giorgos Korfiatis
        "start_date": application.start_date,
121 2556cf45 Giorgos Korfiatis
        "end_date": application.end_date,
122 362dadaa Giorgos Korfiatis
        "comments": application.comments,
123 2556cf45 Giorgos Korfiatis
        "join_policy": join_policy,
124 2556cf45 Giorgos Korfiatis
        "leave_policy": leave_policy,
125 2556cf45 Giorgos Korfiatis
        "max_members": application.limit_on_members_number,
126 362dadaa Giorgos Korfiatis
        "private": application.private,
127 2556cf45 Giorgos Korfiatis
        "resources": resources,
128 2556cf45 Giorgos Korfiatis
    }
129 2556cf45 Giorgos Korfiatis
    return d
130 2556cf45 Giorgos Korfiatis
131 2556cf45 Giorgos Korfiatis
132 2556cf45 Giorgos Korfiatis
def get_projects_details(projects, request_user=None):
133 362dadaa Giorgos Korfiatis
    applications = [p.last_application for p in projects if p.last_application]
134 362dadaa Giorgos Korfiatis
    proj_quotas = ProjectResourceQuota.objects.quotas_per_project(projects)
135 362dadaa Giorgos Korfiatis
    app_grants = ProjectResourceGrant.objects.grants_per_app(applications)
136 2556cf45 Giorgos Korfiatis
    deactivations = ProjectLog.objects.last_deactivations(projects)
137 2556cf45 Giorgos Korfiatis
138 2556cf45 Giorgos Korfiatis
    l = []
139 2556cf45 Giorgos Korfiatis
    for project in projects:
140 362dadaa Giorgos Korfiatis
        join_policy = MEMBERSHIP_POLICY_SHOW[project.member_join_policy]
141 362dadaa Giorgos Korfiatis
        leave_policy = MEMBERSHIP_POLICY_SHOW[project.member_leave_policy]
142 362dadaa Giorgos Korfiatis
        quotas = proj_quotas.get(project.id, [])
143 362dadaa Giorgos Korfiatis
        resources = _grant_details(quotas)
144 362dadaa Giorgos Korfiatis
145 2556cf45 Giorgos Korfiatis
        d = {
146 88f5242e Giorgos Korfiatis
            "id": project.uuid,
147 362dadaa Giorgos Korfiatis
            "state": PROJECT_STATE_SHOW[project.state],
148 2556cf45 Giorgos Korfiatis
            "creation_date": project.creation_date,
149 362dadaa Giorgos Korfiatis
            "name": project.realname,
150 362dadaa Giorgos Korfiatis
            "owner": project.owner.uuid if project.owner else None,
151 362dadaa Giorgos Korfiatis
            "homepage": project.homepage,
152 362dadaa Giorgos Korfiatis
            "description": project.description,
153 362dadaa Giorgos Korfiatis
            "end_date": project.end_date,
154 362dadaa Giorgos Korfiatis
            "join_policy": join_policy,
155 362dadaa Giorgos Korfiatis
            "leave_policy": leave_policy,
156 362dadaa Giorgos Korfiatis
            "max_members": project.limit_on_members_number,
157 362dadaa Giorgos Korfiatis
            "private": project.private,
158 362dadaa Giorgos Korfiatis
            "base_project": project.is_base,
159 362dadaa Giorgos Korfiatis
            "resources": resources,
160 362dadaa Giorgos Korfiatis
            }
161 362dadaa Giorgos Korfiatis
162 2556cf45 Giorgos Korfiatis
        check = functions.project_check_allowed
163 2556cf45 Giorgos Korfiatis
        if check(project, request_user,
164 2556cf45 Giorgos Korfiatis
                 level=functions.APPLICANT_LEVEL, silent=True):
165 362dadaa Giorgos Korfiatis
            application = project.last_application
166 362dadaa Giorgos Korfiatis
            if application:
167 362dadaa Giorgos Korfiatis
                d["last_application"] = _application_details(
168 362dadaa Giorgos Korfiatis
                    application, app_grants)
169 2556cf45 Giorgos Korfiatis
            deact = deactivations.get(project.id)
170 2556cf45 Giorgos Korfiatis
            if deact is not None:
171 2556cf45 Giorgos Korfiatis
                d["deactivation_date"] = deact.date
172 2556cf45 Giorgos Korfiatis
        l.append(d)
173 2556cf45 Giorgos Korfiatis
    return l
174 2556cf45 Giorgos Korfiatis
175 2556cf45 Giorgos Korfiatis
176 2556cf45 Giorgos Korfiatis
def get_project_details(project, request_user=None):
177 2556cf45 Giorgos Korfiatis
    return get_projects_details([project], request_user=request_user)[0]
178 2556cf45 Giorgos Korfiatis
179 2556cf45 Giorgos Korfiatis
180 2556cf45 Giorgos Korfiatis
def get_memberships_details(memberships, request_user):
181 2556cf45 Giorgos Korfiatis
    all_logs = ProjectMembershipLog.objects.last_logs(memberships)
182 2556cf45 Giorgos Korfiatis
183 2556cf45 Giorgos Korfiatis
    l = []
184 2556cf45 Giorgos Korfiatis
    for membership in memberships:
185 2556cf45 Giorgos Korfiatis
        logs = all_logs.get(membership.id, {})
186 2556cf45 Giorgos Korfiatis
        dates = {}
187 2556cf45 Giorgos Korfiatis
        for s, log in logs.iteritems():
188 2556cf45 Giorgos Korfiatis
            dates[MEMBERSHIP_STATE_SHOW[s]] = log.date
189 2556cf45 Giorgos Korfiatis
190 2556cf45 Giorgos Korfiatis
        allowed_actions = functions.membership_allowed_actions(
191 2556cf45 Giorgos Korfiatis
            membership, request_user)
192 2556cf45 Giorgos Korfiatis
        d = {
193 2556cf45 Giorgos Korfiatis
            "id": membership.id,
194 2556cf45 Giorgos Korfiatis
            "user": membership.person.uuid,
195 88f5242e Giorgos Korfiatis
            "project": membership.project.uuid,
196 2556cf45 Giorgos Korfiatis
            "state": MEMBERSHIP_STATE_SHOW[membership.state],
197 2556cf45 Giorgos Korfiatis
            "allowed_actions": allowed_actions,
198 2556cf45 Giorgos Korfiatis
        }
199 2556cf45 Giorgos Korfiatis
        d.update(dates)
200 2556cf45 Giorgos Korfiatis
        l.append(d)
201 2556cf45 Giorgos Korfiatis
    return l
202 2556cf45 Giorgos Korfiatis
203 2556cf45 Giorgos Korfiatis
204 2556cf45 Giorgos Korfiatis
def get_membership_details(membership, request_user):
205 2556cf45 Giorgos Korfiatis
    return get_memberships_details([membership], request_user)[0]
206 2556cf45 Giorgos Korfiatis
207 2556cf45 Giorgos Korfiatis
208 2556cf45 Giorgos Korfiatis
def _query(attr):
209 2556cf45 Giorgos Korfiatis
    def inner(val):
210 2556cf45 Giorgos Korfiatis
        kw = attr + "__in" if isinstance(val, list) else attr
211 2556cf45 Giorgos Korfiatis
        return Q(**{kw: val})
212 2556cf45 Giorgos Korfiatis
    return inner
213 2556cf45 Giorgos Korfiatis
214 2556cf45 Giorgos Korfiatis
215 2556cf45 Giorgos Korfiatis
def _get_project_state(val):
216 2556cf45 Giorgos Korfiatis
    try:
217 2556cf45 Giorgos Korfiatis
        return PROJECT_STATE[val]
218 2556cf45 Giorgos Korfiatis
    except KeyError:
219 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("Unrecognized state %s" % val)
220 2556cf45 Giorgos Korfiatis
221 2556cf45 Giorgos Korfiatis
222 2556cf45 Giorgos Korfiatis
def _project_state_query(val):
223 2556cf45 Giorgos Korfiatis
    if isinstance(val, list):
224 2556cf45 Giorgos Korfiatis
        states = [_get_project_state(v) for v in val]
225 362dadaa Giorgos Korfiatis
        return Q(state__in=states)
226 362dadaa Giorgos Korfiatis
    return Q(state=_get_project_state(val))
227 2556cf45 Giorgos Korfiatis
228 2556cf45 Giorgos Korfiatis
229 2556cf45 Giorgos Korfiatis
PROJECT_QUERY = {
230 362dadaa Giorgos Korfiatis
    "name": _query("realname"),
231 362dadaa Giorgos Korfiatis
    "owner": _query("owner__uuid"),
232 2556cf45 Giorgos Korfiatis
    "state": _project_state_query,
233 2556cf45 Giorgos Korfiatis
}
234 2556cf45 Giorgos Korfiatis
235 2556cf45 Giorgos Korfiatis
236 2556cf45 Giorgos Korfiatis
def make_project_query(filters):
237 2556cf45 Giorgos Korfiatis
    qs = Q()
238 2556cf45 Giorgos Korfiatis
    for attr, val in filters.iteritems():
239 2556cf45 Giorgos Korfiatis
        try:
240 2556cf45 Giorgos Korfiatis
            _q = PROJECT_QUERY[attr]
241 2556cf45 Giorgos Korfiatis
        except KeyError:
242 2556cf45 Giorgos Korfiatis
            raise faults.BadRequest("Unrecognized filter %s" % attr)
243 2556cf45 Giorgos Korfiatis
        qs &= _q(val)
244 2556cf45 Giorgos Korfiatis
    return qs
245 2556cf45 Giorgos Korfiatis
246 2556cf45 Giorgos Korfiatis
247 2556cf45 Giorgos Korfiatis
class ExceptionHandler(object):
248 2556cf45 Giorgos Korfiatis
    def __enter__(self):
249 2556cf45 Giorgos Korfiatis
        pass
250 2556cf45 Giorgos Korfiatis
251 2556cf45 Giorgos Korfiatis
    EXCS = {
252 2556cf45 Giorgos Korfiatis
        functions.ProjectNotFound:   faults.ItemNotFound,
253 2556cf45 Giorgos Korfiatis
        functions.ProjectForbidden:  faults.Forbidden,
254 2556cf45 Giorgos Korfiatis
        functions.ProjectBadRequest: faults.BadRequest,
255 2556cf45 Giorgos Korfiatis
        functions.ProjectConflict:   faults.Conflict,
256 2556cf45 Giorgos Korfiatis
    }
257 2556cf45 Giorgos Korfiatis
258 2556cf45 Giorgos Korfiatis
    def __exit__(self, exc_type, value, traceback):
259 2556cf45 Giorgos Korfiatis
        if value is not None:  # exception
260 2556cf45 Giorgos Korfiatis
            try:
261 2556cf45 Giorgos Korfiatis
                e = self.EXCS[exc_type]
262 2556cf45 Giorgos Korfiatis
            except KeyError:
263 2556cf45 Giorgos Korfiatis
                return False  # reraise
264 2556cf45 Giorgos Korfiatis
            raise e(value.message)
265 2556cf45 Giorgos Korfiatis
266 2556cf45 Giorgos Korfiatis
267 2556cf45 Giorgos Korfiatis
@csrf_exempt
268 2556cf45 Giorgos Korfiatis
def projects(request):
269 2556cf45 Giorgos Korfiatis
    method = request.method
270 2556cf45 Giorgos Korfiatis
    if method == "GET":
271 2556cf45 Giorgos Korfiatis
        return get_projects(request)
272 2556cf45 Giorgos Korfiatis
    elif method == "POST":
273 2556cf45 Giorgos Korfiatis
        return create_project(request)
274 2aba7764 Sofia Papagiannaki
    return api.api_method_not_allowed(request, allowed_methods=['GET', 'POST'])
275 2556cf45 Giorgos Korfiatis
276 2556cf45 Giorgos Korfiatis
277 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="GET", token_required=True, user_required=False)
278 2556cf45 Giorgos Korfiatis
@user_from_token
279 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
280 2556cf45 Giorgos Korfiatis
def get_projects(request):
281 2556cf45 Giorgos Korfiatis
    user = request.user
282 a1ff970b Giorgos Korfiatis
    filters = {}
283 a1ff970b Giorgos Korfiatis
    for key in PROJECT_QUERY.keys():
284 a1ff970b Giorgos Korfiatis
        value = request.GET.get(key)
285 a1ff970b Giorgos Korfiatis
        if value is not None:
286 a1ff970b Giorgos Korfiatis
            filters[key] = value
287 a1ff970b Giorgos Korfiatis
    mode = request.GET.get("mode", "default")
288 2556cf45 Giorgos Korfiatis
    query = make_project_query(filters)
289 edc51a21 Giorgos Korfiatis
    projects = _get_projects(query, mode=mode, request_user=user)
290 2556cf45 Giorgos Korfiatis
    data = get_projects_details(projects, request_user=user)
291 2556cf45 Giorgos Korfiatis
    return json_response(data)
292 2556cf45 Giorgos Korfiatis
293 2556cf45 Giorgos Korfiatis
294 edc51a21 Giorgos Korfiatis
def _get_projects(query, mode="default", request_user=None):
295 2556cf45 Giorgos Korfiatis
    projects = Project.objects.filter(query)
296 2556cf45 Giorgos Korfiatis
297 edc51a21 Giorgos Korfiatis
    if mode == "member":
298 edc51a21 Giorgos Korfiatis
        membs = request_user.projectmembership_set.\
299 edc51a21 Giorgos Korfiatis
            actually_accepted_and_active()
300 2556cf45 Giorgos Korfiatis
        memb_projects = membs.values_list("project", flat=True)
301 2556cf45 Giorgos Korfiatis
        is_memb = Q(id__in=memb_projects)
302 edc51a21 Giorgos Korfiatis
        projects = projects.filter(is_memb)
303 edc51a21 Giorgos Korfiatis
    elif mode == "default":
304 edc51a21 Giorgos Korfiatis
        if not request_user.is_project_admin():
305 edc51a21 Giorgos Korfiatis
            membs = request_user.projectmembership_set.any_accepted()
306 edc51a21 Giorgos Korfiatis
            memb_projects = membs.values_list("project", flat=True)
307 edc51a21 Giorgos Korfiatis
            is_memb = Q(id__in=memb_projects)
308 edc51a21 Giorgos Korfiatis
            owned = Q(owner=request_user)
309 edc51a21 Giorgos Korfiatis
            active = (Q(state=Project.NORMAL) &
310 edc51a21 Giorgos Korfiatis
                      Q(private=False))
311 edc51a21 Giorgos Korfiatis
            projects = projects.filter(is_memb | owned | active)
312 edc51a21 Giorgos Korfiatis
    else:
313 edc51a21 Giorgos Korfiatis
        raise faults.BadRequest("Unrecognized mode '%s'." % mode)
314 362dadaa Giorgos Korfiatis
    return projects.select_related("last_application")
315 2556cf45 Giorgos Korfiatis
316 2556cf45 Giorgos Korfiatis
317 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="POST", token_required=True, user_required=False)
318 2556cf45 Giorgos Korfiatis
@user_from_token
319 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
320 2556cf45 Giorgos Korfiatis
def create_project(request):
321 2556cf45 Giorgos Korfiatis
    user = request.user
322 b694875c Christos Stavrakakis
    data = request.body
323 2556cf45 Giorgos Korfiatis
    app_data = json.loads(data)
324 362dadaa Giorgos Korfiatis
    return submit_new_project(app_data, user)
325 2556cf45 Giorgos Korfiatis
326 2556cf45 Giorgos Korfiatis
327 2556cf45 Giorgos Korfiatis
@csrf_exempt
328 2556cf45 Giorgos Korfiatis
def project(request, project_id):
329 2556cf45 Giorgos Korfiatis
    method = request.method
330 2556cf45 Giorgos Korfiatis
    if method == "GET":
331 2556cf45 Giorgos Korfiatis
        return get_project(request, project_id)
332 d9fca80b Giorgos Korfiatis
    if method == "PUT":
333 2556cf45 Giorgos Korfiatis
        return modify_project(request, project_id)
334 d9fca80b Giorgos Korfiatis
    return api.api_method_not_allowed(request, allowed_methods=['GET', 'PUT'])
335 2556cf45 Giorgos Korfiatis
336 2556cf45 Giorgos Korfiatis
337 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="GET", token_required=True, user_required=False)
338 2556cf45 Giorgos Korfiatis
@user_from_token
339 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
340 2556cf45 Giorgos Korfiatis
def get_project(request, project_id):
341 2556cf45 Giorgos Korfiatis
    user = request.user
342 2556cf45 Giorgos Korfiatis
    with ExceptionHandler():
343 2556cf45 Giorgos Korfiatis
        project = _get_project(project_id, request_user=user)
344 2556cf45 Giorgos Korfiatis
    data = get_project_details(project, user)
345 2556cf45 Giorgos Korfiatis
    return json_response(data)
346 2556cf45 Giorgos Korfiatis
347 2556cf45 Giorgos Korfiatis
348 2556cf45 Giorgos Korfiatis
def _get_project(project_id, request_user=None):
349 88f5242e Giorgos Korfiatis
    project = functions.get_project_by_uuid(project_id)
350 2556cf45 Giorgos Korfiatis
    functions.project_check_allowed(
351 2556cf45 Giorgos Korfiatis
        project, request_user, level=functions.ANY_LEVEL)
352 2556cf45 Giorgos Korfiatis
    return project
353 2556cf45 Giorgos Korfiatis
354 2556cf45 Giorgos Korfiatis
355 d9fca80b Giorgos Korfiatis
@api.api_method(http_method="PUT", token_required=True, user_required=False)
356 2556cf45 Giorgos Korfiatis
@user_from_token
357 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
358 2556cf45 Giorgos Korfiatis
def modify_project(request, project_id):
359 2556cf45 Giorgos Korfiatis
    user = request.user
360 b694875c Christos Stavrakakis
    data = request.body
361 2556cf45 Giorgos Korfiatis
    app_data = json.loads(data)
362 362dadaa Giorgos Korfiatis
    return submit_modification(app_data, user, project_id=project_id)
363 2556cf45 Giorgos Korfiatis
364 2556cf45 Giorgos Korfiatis
365 2556cf45 Giorgos Korfiatis
def _get_date(d, key):
366 2556cf45 Giorgos Korfiatis
    date_str = d.get(key)
367 2556cf45 Giorgos Korfiatis
    if date_str is not None:
368 2556cf45 Giorgos Korfiatis
        try:
369 2556cf45 Giorgos Korfiatis
            return date_util.isoparse(date_str)
370 2556cf45 Giorgos Korfiatis
        except:
371 2556cf45 Giorgos Korfiatis
            raise faults.BadRequest("Invalid %s" % key)
372 2556cf45 Giorgos Korfiatis
    else:
373 2556cf45 Giorgos Korfiatis
        return None
374 2556cf45 Giorgos Korfiatis
375 2556cf45 Giorgos Korfiatis
376 362dadaa Giorgos Korfiatis
def _get_maybe_string(d, key, default=None):
377 2556cf45 Giorgos Korfiatis
    value = d.get(key)
378 2556cf45 Giorgos Korfiatis
    if value is not None and not isinstance(value, basestring):
379 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("%s must be string" % key)
380 362dadaa Giorgos Korfiatis
    if value is None:
381 362dadaa Giorgos Korfiatis
        return default
382 2556cf45 Giorgos Korfiatis
    return value
383 2556cf45 Giorgos Korfiatis
384 2556cf45 Giorgos Korfiatis
385 362dadaa Giorgos Korfiatis
def _get_maybe_boolean(d, key, default=None):
386 62d30634 Giorgos Korfiatis
    value = d.get(key)
387 62d30634 Giorgos Korfiatis
    if value is not None and not isinstance(value, bool):
388 62d30634 Giorgos Korfiatis
        raise faults.BadRequest("%s must be boolean" % key)
389 362dadaa Giorgos Korfiatis
    if value is None:
390 362dadaa Giorgos Korfiatis
        return default
391 62d30634 Giorgos Korfiatis
    return value
392 62d30634 Giorgos Korfiatis
393 62d30634 Giorgos Korfiatis
394 a23ac2f7 Giorgos Korfiatis
DOMAIN_VALUE_REGEX = re.compile(
395 a23ac2f7 Giorgos Korfiatis
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
396 a23ac2f7 Giorgos Korfiatis
    re.IGNORECASE)
397 a23ac2f7 Giorgos Korfiatis
398 a23ac2f7 Giorgos Korfiatis
399 a23ac2f7 Giorgos Korfiatis
def valid_project_name(name):
400 a23ac2f7 Giorgos Korfiatis
    return DOMAIN_VALUE_REGEX.match(name) is not None
401 a23ac2f7 Giorgos Korfiatis
402 a23ac2f7 Giorgos Korfiatis
403 362dadaa Giorgos Korfiatis
def _parse_max_members(s):
404 362dadaa Giorgos Korfiatis
    try:
405 362dadaa Giorgos Korfiatis
        max_members = units.parse(s)
406 362dadaa Giorgos Korfiatis
        if max_members < 0:
407 362dadaa Giorgos Korfiatis
            raise faults.BadRequest("Invalid max_members")
408 362dadaa Giorgos Korfiatis
        return max_members
409 362dadaa Giorgos Korfiatis
    except units.ParseError:
410 362dadaa Giorgos Korfiatis
        raise faults.BadRequest("Invalid max_members")
411 362dadaa Giorgos Korfiatis
412 362dadaa Giorgos Korfiatis
413 362dadaa Giorgos Korfiatis
def submit_new_project(app_data, user):
414 2556cf45 Giorgos Korfiatis
    uuid = app_data.get("owner")
415 2556cf45 Giorgos Korfiatis
    if uuid is None:
416 2556cf45 Giorgos Korfiatis
        owner = user
417 2556cf45 Giorgos Korfiatis
    else:
418 2556cf45 Giorgos Korfiatis
        try:
419 733f013d Giorgos Korfiatis
            owner = AstakosUser.objects.accepted().get(uuid=uuid)
420 2556cf45 Giorgos Korfiatis
        except AstakosUser.DoesNotExist:
421 2556cf45 Giorgos Korfiatis
            raise faults.BadRequest("User does not exist.")
422 2556cf45 Giorgos Korfiatis
423 2556cf45 Giorgos Korfiatis
    try:
424 2556cf45 Giorgos Korfiatis
        name = app_data["name"]
425 2556cf45 Giorgos Korfiatis
    except KeyError:
426 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("Name missing.")
427 2556cf45 Giorgos Korfiatis
428 a23ac2f7 Giorgos Korfiatis
    if not valid_project_name(name):
429 a23ac2f7 Giorgos Korfiatis
        raise faults.BadRequest("Project name should be in domain format")
430 a23ac2f7 Giorgos Korfiatis
431 2556cf45 Giorgos Korfiatis
    join_policy = app_data.get("join_policy", "moderated")
432 2556cf45 Giorgos Korfiatis
    try:
433 2556cf45 Giorgos Korfiatis
        join_policy = MEMBERSHIP_POLICY[join_policy]
434 2556cf45 Giorgos Korfiatis
    except KeyError:
435 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("Invalid join policy")
436 2556cf45 Giorgos Korfiatis
437 2556cf45 Giorgos Korfiatis
    leave_policy = app_data.get("leave_policy", "auto")
438 2556cf45 Giorgos Korfiatis
    try:
439 2556cf45 Giorgos Korfiatis
        leave_policy = MEMBERSHIP_POLICY[leave_policy]
440 2556cf45 Giorgos Korfiatis
    except KeyError:
441 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("Invalid leave policy")
442 2556cf45 Giorgos Korfiatis
443 2556cf45 Giorgos Korfiatis
    start_date = _get_date(app_data, "start_date")
444 2556cf45 Giorgos Korfiatis
    end_date = _get_date(app_data, "end_date")
445 2556cf45 Giorgos Korfiatis
446 2556cf45 Giorgos Korfiatis
    if end_date is None:
447 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("Missing end date")
448 2556cf45 Giorgos Korfiatis
449 362dadaa Giorgos Korfiatis
    try:
450 362dadaa Giorgos Korfiatis
        max_members = _parse_max_members(app_data["max_members"])
451 362dadaa Giorgos Korfiatis
    except KeyError:
452 362dadaa Giorgos Korfiatis
        max_members = units.PRACTICALLY_INFINITE
453 2556cf45 Giorgos Korfiatis
454 62d30634 Giorgos Korfiatis
    private = bool(_get_maybe_boolean(app_data, "private"))
455 362dadaa Giorgos Korfiatis
    homepage = _get_maybe_string(app_data, "homepage", "")
456 362dadaa Giorgos Korfiatis
    description = _get_maybe_string(app_data, "description", "")
457 362dadaa Giorgos Korfiatis
    comments = _get_maybe_string(app_data, "comments", "")
458 362dadaa Giorgos Korfiatis
    resources = app_data.get("resources", {})
459 362dadaa Giorgos Korfiatis
460 362dadaa Giorgos Korfiatis
    submit = functions.submit_application
461 362dadaa Giorgos Korfiatis
    with ExceptionHandler():
462 362dadaa Giorgos Korfiatis
        application = submit(
463 362dadaa Giorgos Korfiatis
            owner=owner,
464 362dadaa Giorgos Korfiatis
            name=name,
465 362dadaa Giorgos Korfiatis
            project_id=None,
466 362dadaa Giorgos Korfiatis
            homepage=homepage,
467 362dadaa Giorgos Korfiatis
            description=description,
468 362dadaa Giorgos Korfiatis
            start_date=start_date,
469 362dadaa Giorgos Korfiatis
            end_date=end_date,
470 362dadaa Giorgos Korfiatis
            member_join_policy=join_policy,
471 362dadaa Giorgos Korfiatis
            member_leave_policy=leave_policy,
472 362dadaa Giorgos Korfiatis
            limit_on_members_number=max_members,
473 362dadaa Giorgos Korfiatis
            private=private,
474 362dadaa Giorgos Korfiatis
            comments=comments,
475 362dadaa Giorgos Korfiatis
            resources=resources,
476 362dadaa Giorgos Korfiatis
            request_user=user)
477 362dadaa Giorgos Korfiatis
478 362dadaa Giorgos Korfiatis
    result = {"application": application.id,
479 362dadaa Giorgos Korfiatis
              "id": application.chain.uuid,
480 362dadaa Giorgos Korfiatis
              }
481 362dadaa Giorgos Korfiatis
    return json_response(result, status_code=201)
482 362dadaa Giorgos Korfiatis
483 362dadaa Giorgos Korfiatis
484 362dadaa Giorgos Korfiatis
def submit_modification(app_data, user, project_id):
485 362dadaa Giorgos Korfiatis
    owner = app_data.get("owner")
486 362dadaa Giorgos Korfiatis
    if owner is not None:
487 362dadaa Giorgos Korfiatis
        try:
488 362dadaa Giorgos Korfiatis
            owner = AstakosUser.objects.accepted().get(uuid=owner)
489 362dadaa Giorgos Korfiatis
        except AstakosUser.DoesNotExist:
490 362dadaa Giorgos Korfiatis
            raise faults.BadRequest("User does not exist.")
491 362dadaa Giorgos Korfiatis
492 362dadaa Giorgos Korfiatis
    name = app_data.get("name")
493 362dadaa Giorgos Korfiatis
494 362dadaa Giorgos Korfiatis
    if name is not None and not valid_project_name(name):
495 362dadaa Giorgos Korfiatis
        raise faults.BadRequest("Project name should be in domain format")
496 362dadaa Giorgos Korfiatis
497 362dadaa Giorgos Korfiatis
    join_policy = app_data.get("join_policy")
498 362dadaa Giorgos Korfiatis
    if join_policy is not None:
499 362dadaa Giorgos Korfiatis
        try:
500 362dadaa Giorgos Korfiatis
            join_policy = MEMBERSHIP_POLICY[join_policy]
501 362dadaa Giorgos Korfiatis
        except KeyError:
502 362dadaa Giorgos Korfiatis
            raise faults.BadRequest("Invalid join policy")
503 362dadaa Giorgos Korfiatis
504 362dadaa Giorgos Korfiatis
    leave_policy = app_data.get("leave_policy")
505 362dadaa Giorgos Korfiatis
    if leave_policy is not None:
506 362dadaa Giorgos Korfiatis
        try:
507 362dadaa Giorgos Korfiatis
            leave_policy = MEMBERSHIP_POLICY[leave_policy]
508 362dadaa Giorgos Korfiatis
        except KeyError:
509 362dadaa Giorgos Korfiatis
            raise faults.BadRequest("Invalid leave policy")
510 362dadaa Giorgos Korfiatis
511 362dadaa Giorgos Korfiatis
    start_date = _get_date(app_data, "start_date")
512 362dadaa Giorgos Korfiatis
    end_date = _get_date(app_data, "end_date")
513 362dadaa Giorgos Korfiatis
514 362dadaa Giorgos Korfiatis
    max_members = app_data.get("max_members")
515 362dadaa Giorgos Korfiatis
    if max_members is not None:
516 362dadaa Giorgos Korfiatis
        max_members = _parse_max_members(max_members)
517 362dadaa Giorgos Korfiatis
518 362dadaa Giorgos Korfiatis
    private = _get_maybe_boolean(app_data, "private")
519 2556cf45 Giorgos Korfiatis
    homepage = _get_maybe_string(app_data, "homepage")
520 2556cf45 Giorgos Korfiatis
    description = _get_maybe_string(app_data, "description")
521 2556cf45 Giorgos Korfiatis
    comments = _get_maybe_string(app_data, "comments")
522 2556cf45 Giorgos Korfiatis
    resources = app_data.get("resources", {})
523 2556cf45 Giorgos Korfiatis
524 2556cf45 Giorgos Korfiatis
    submit = functions.submit_application
525 2556cf45 Giorgos Korfiatis
    with ExceptionHandler():
526 2556cf45 Giorgos Korfiatis
        application = submit(
527 2556cf45 Giorgos Korfiatis
            owner=owner,
528 2556cf45 Giorgos Korfiatis
            name=name,
529 2556cf45 Giorgos Korfiatis
            project_id=project_id,
530 2556cf45 Giorgos Korfiatis
            homepage=homepage,
531 2556cf45 Giorgos Korfiatis
            description=description,
532 2556cf45 Giorgos Korfiatis
            start_date=start_date,
533 2556cf45 Giorgos Korfiatis
            end_date=end_date,
534 2556cf45 Giorgos Korfiatis
            member_join_policy=join_policy,
535 2556cf45 Giorgos Korfiatis
            member_leave_policy=leave_policy,
536 2556cf45 Giorgos Korfiatis
            limit_on_members_number=max_members,
537 62d30634 Giorgos Korfiatis
            private=private,
538 2556cf45 Giorgos Korfiatis
            comments=comments,
539 2556cf45 Giorgos Korfiatis
            resources=resources,
540 2556cf45 Giorgos Korfiatis
            request_user=user)
541 2556cf45 Giorgos Korfiatis
542 2556cf45 Giorgos Korfiatis
    result = {"application": application.id,
543 88f5242e Giorgos Korfiatis
              "id": application.chain.uuid,
544 2556cf45 Giorgos Korfiatis
              }
545 2556cf45 Giorgos Korfiatis
    return json_response(result, status_code=201)
546 2556cf45 Giorgos Korfiatis
547 2556cf45 Giorgos Korfiatis
548 2556cf45 Giorgos Korfiatis
def get_action(actions, input_data):
549 2556cf45 Giorgos Korfiatis
    action = None
550 2556cf45 Giorgos Korfiatis
    data = None
551 2556cf45 Giorgos Korfiatis
    for option in actions.keys():
552 2556cf45 Giorgos Korfiatis
        if option in input_data:
553 2556cf45 Giorgos Korfiatis
            if action:
554 2556cf45 Giorgos Korfiatis
                raise faults.BadRequest("Multiple actions not supported")
555 2556cf45 Giorgos Korfiatis
            else:
556 2556cf45 Giorgos Korfiatis
                action = option
557 2556cf45 Giorgos Korfiatis
                data = input_data[action]
558 2556cf45 Giorgos Korfiatis
    if not action:
559 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("No recognized action")
560 2556cf45 Giorgos Korfiatis
    return actions[action], data
561 2556cf45 Giorgos Korfiatis
562 2556cf45 Giorgos Korfiatis
563 2556cf45 Giorgos Korfiatis
PROJECT_ACTION = {
564 2556cf45 Giorgos Korfiatis
    "terminate": functions.terminate,
565 2556cf45 Giorgos Korfiatis
    "suspend":   functions.suspend,
566 2556cf45 Giorgos Korfiatis
    "unsuspend": functions.unsuspend,
567 2556cf45 Giorgos Korfiatis
    "reinstate": functions.reinstate,
568 2556cf45 Giorgos Korfiatis
}
569 2556cf45 Giorgos Korfiatis
570 2556cf45 Giorgos Korfiatis
571 2556cf45 Giorgos Korfiatis
APPLICATION_ACTION = {
572 2556cf45 Giorgos Korfiatis
    "approve": functions.approve_application,
573 362dadaa Giorgos Korfiatis
    "deny":    functions.deny_application,
574 2556cf45 Giorgos Korfiatis
    "dismiss": functions.dismiss_application,
575 362dadaa Giorgos Korfiatis
    "cancel":  functions.cancel_application,
576 2556cf45 Giorgos Korfiatis
}
577 2556cf45 Giorgos Korfiatis
578 2556cf45 Giorgos Korfiatis
579 362dadaa Giorgos Korfiatis
PROJECT_ACTION.update(APPLICATION_ACTION)
580 362dadaa Giorgos Korfiatis
APP_ACTION_FUNCS = APPLICATION_ACTION.values()
581 362dadaa Giorgos Korfiatis
582 362dadaa Giorgos Korfiatis
583 2556cf45 Giorgos Korfiatis
@csrf_exempt
584 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="POST", token_required=True, user_required=False)
585 2556cf45 Giorgos Korfiatis
@user_from_token
586 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
587 362dadaa Giorgos Korfiatis
def project_action(request, project_id):
588 2556cf45 Giorgos Korfiatis
    user = request.user
589 b694875c Christos Stavrakakis
    data = request.body
590 2556cf45 Giorgos Korfiatis
    input_data = json.loads(data)
591 2556cf45 Giorgos Korfiatis
592 362dadaa Giorgos Korfiatis
    func, action_data = get_action(PROJECT_ACTION, input_data)
593 2556cf45 Giorgos Korfiatis
    with ExceptionHandler():
594 362dadaa Giorgos Korfiatis
        kwargs = {"request_user": user,
595 362dadaa Giorgos Korfiatis
                  "reason": action_data.get("reason", ""),
596 362dadaa Giorgos Korfiatis
                  }
597 362dadaa Giorgos Korfiatis
        if func in APP_ACTION_FUNCS:
598 362dadaa Giorgos Korfiatis
            kwargs["application_id"] = action_data["app_id"]
599 362dadaa Giorgos Korfiatis
        func(project_id=project_id, **kwargs)
600 2556cf45 Giorgos Korfiatis
    return HttpResponse()
601 2556cf45 Giorgos Korfiatis
602 2556cf45 Giorgos Korfiatis
603 2556cf45 Giorgos Korfiatis
@csrf_exempt
604 2556cf45 Giorgos Korfiatis
def memberships(request):
605 2556cf45 Giorgos Korfiatis
    method = request.method
606 2556cf45 Giorgos Korfiatis
    if method == "GET":
607 2556cf45 Giorgos Korfiatis
        return get_memberships(request)
608 2556cf45 Giorgos Korfiatis
    elif method == "POST":
609 2556cf45 Giorgos Korfiatis
        return post_memberships(request)
610 2aba7764 Sofia Papagiannaki
    return api.api_method_not_allowed(request, allowed_methods=['GET', 'POST'])
611 2556cf45 Giorgos Korfiatis
612 2556cf45 Giorgos Korfiatis
613 2556cf45 Giorgos Korfiatis
def make_membership_query(input_data):
614 2556cf45 Giorgos Korfiatis
    project_id = input_data.get("project")
615 2556cf45 Giorgos Korfiatis
    if project_id is not None:
616 88f5242e Giorgos Korfiatis
        return Q(project__uuid=project_id)
617 2556cf45 Giorgos Korfiatis
    return Q()
618 2556cf45 Giorgos Korfiatis
619 2556cf45 Giorgos Korfiatis
620 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="GET", token_required=True, user_required=False)
621 2556cf45 Giorgos Korfiatis
@user_from_token
622 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
623 2556cf45 Giorgos Korfiatis
def get_memberships(request):
624 2556cf45 Giorgos Korfiatis
    user = request.user
625 a1ff970b Giorgos Korfiatis
    query = make_membership_query(request.GET)
626 2556cf45 Giorgos Korfiatis
    memberships = _get_memberships(query, request_user=user)
627 2556cf45 Giorgos Korfiatis
    data = get_memberships_details(memberships, user)
628 2556cf45 Giorgos Korfiatis
    return json_response(data)
629 2556cf45 Giorgos Korfiatis
630 2556cf45 Giorgos Korfiatis
631 2556cf45 Giorgos Korfiatis
def _get_memberships(query, request_user=None):
632 2556cf45 Giorgos Korfiatis
    memberships = ProjectMembership.objects
633 2556cf45 Giorgos Korfiatis
    if not request_user.is_project_admin():
634 362dadaa Giorgos Korfiatis
        owned = Q(project__owner=request_user)
635 2556cf45 Giorgos Korfiatis
        memb = Q(person=request_user)
636 2556cf45 Giorgos Korfiatis
        memberships = memberships.filter(owned | memb)
637 2556cf45 Giorgos Korfiatis
638 2556cf45 Giorgos Korfiatis
    return memberships.select_related(
639 362dadaa Giorgos Korfiatis
        "project", "project__owner", "person").filter(query)
640 2556cf45 Giorgos Korfiatis
641 2556cf45 Giorgos Korfiatis
642 2556cf45 Giorgos Korfiatis
def join_project(data, request_user):
643 2556cf45 Giorgos Korfiatis
    project_id = data.get("project")
644 2556cf45 Giorgos Korfiatis
    with ExceptionHandler():
645 2556cf45 Giorgos Korfiatis
        membership = functions.join_project(project_id, request_user)
646 2556cf45 Giorgos Korfiatis
    response = {"id": membership.id}
647 2556cf45 Giorgos Korfiatis
    return json_response(response)
648 2556cf45 Giorgos Korfiatis
649 2556cf45 Giorgos Korfiatis
650 2556cf45 Giorgos Korfiatis
def enroll_user(data, request_user):
651 2556cf45 Giorgos Korfiatis
    project_id = data.get("project")
652 2556cf45 Giorgos Korfiatis
    email = data.get("user")
653 2556cf45 Giorgos Korfiatis
    with ExceptionHandler():
654 2556cf45 Giorgos Korfiatis
        m = functions.enroll_member_by_email(
655 2556cf45 Giorgos Korfiatis
            project_id, email, request_user)
656 2556cf45 Giorgos Korfiatis
657 2556cf45 Giorgos Korfiatis
    response = {"id": m.id}
658 2556cf45 Giorgos Korfiatis
    return json_response(response)
659 2556cf45 Giorgos Korfiatis
660 2556cf45 Giorgos Korfiatis
661 2556cf45 Giorgos Korfiatis
MEMBERSHIPS_ACTION = {
662 2556cf45 Giorgos Korfiatis
    "join":   join_project,
663 2556cf45 Giorgos Korfiatis
    "enroll": enroll_user,
664 2556cf45 Giorgos Korfiatis
}
665 2556cf45 Giorgos Korfiatis
666 2556cf45 Giorgos Korfiatis
667 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="POST", token_required=True, user_required=False)
668 2556cf45 Giorgos Korfiatis
@user_from_token
669 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
670 2556cf45 Giorgos Korfiatis
def post_memberships(request):
671 2556cf45 Giorgos Korfiatis
    user = request.user
672 b694875c Christos Stavrakakis
    data = request.body
673 2556cf45 Giorgos Korfiatis
    input_data = json.loads(data)
674 2556cf45 Giorgos Korfiatis
    func, action_data = get_action(MEMBERSHIPS_ACTION, input_data)
675 2556cf45 Giorgos Korfiatis
    return func(action_data, user)
676 2556cf45 Giorgos Korfiatis
677 2556cf45 Giorgos Korfiatis
678 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="GET", token_required=True, user_required=False)
679 2556cf45 Giorgos Korfiatis
@user_from_token
680 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
681 2556cf45 Giorgos Korfiatis
def membership(request, memb_id):
682 2556cf45 Giorgos Korfiatis
    user = request.user
683 2556cf45 Giorgos Korfiatis
    with ExceptionHandler():
684 2556cf45 Giorgos Korfiatis
        m = _get_membership(memb_id, request_user=user)
685 2556cf45 Giorgos Korfiatis
    data = get_membership_details(m, user)
686 2556cf45 Giorgos Korfiatis
    return json_response(data)
687 2556cf45 Giorgos Korfiatis
688 2556cf45 Giorgos Korfiatis
689 2556cf45 Giorgos Korfiatis
def _get_membership(memb_id, request_user=None):
690 2556cf45 Giorgos Korfiatis
    membership = functions.get_membership_by_id(memb_id)
691 2556cf45 Giorgos Korfiatis
    functions.membership_check_allowed(membership, request_user)
692 2556cf45 Giorgos Korfiatis
    return membership
693 2556cf45 Giorgos Korfiatis
694 2556cf45 Giorgos Korfiatis
695 2556cf45 Giorgos Korfiatis
MEMBERSHIP_ACTION = {
696 2556cf45 Giorgos Korfiatis
    "leave":  functions.leave_project,
697 2556cf45 Giorgos Korfiatis
    "cancel": functions.cancel_membership,
698 2556cf45 Giorgos Korfiatis
    "accept": functions.accept_membership,
699 2556cf45 Giorgos Korfiatis
    "reject": functions.reject_membership,
700 2556cf45 Giorgos Korfiatis
    "remove": functions.remove_membership,
701 2556cf45 Giorgos Korfiatis
}
702 2556cf45 Giorgos Korfiatis
703 2556cf45 Giorgos Korfiatis
704 2556cf45 Giorgos Korfiatis
@csrf_exempt
705 2556cf45 Giorgos Korfiatis
@api.api_method(http_method="POST", token_required=True, user_required=False)
706 2556cf45 Giorgos Korfiatis
@user_from_token
707 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
708 2556cf45 Giorgos Korfiatis
def membership_action(request, memb_id):
709 2556cf45 Giorgos Korfiatis
    user = request.user
710 2556cf45 Giorgos Korfiatis
    input_data = read_json_body(request, default={})
711 2556cf45 Giorgos Korfiatis
    func, action_data = get_action(MEMBERSHIP_ACTION, input_data)
712 2556cf45 Giorgos Korfiatis
    with ExceptionHandler():
713 2556cf45 Giorgos Korfiatis
        func(memb_id, user, reason=action_data)
714 2556cf45 Giorgos Korfiatis
    return HttpResponse()