Esempio n. 1
0
 def __init__(self):
     self._spacemap = SpaceMap()
Esempio n. 2
0
 def __init__(self):
     self._spacemap = SpaceMap()
Esempio n. 3
0
class SpaceManager(RESTDispatch):
    """ Performs actions on Space models at api/v1/space/(?P<space_id>\d+)/
        Space models are a layer on top of spotseeker_server Spot models.
        GET returns requested Space model(s)
        PUT modifies a Space model, conditionally modifies the Spot model supporting it
        POST creates a Space model
    """
    def __init__(self):
        self._spacemap = SpaceMap()

    def GET(self, args, **kwargs):
        if 'space_id' in kwargs:
            return self._space_detail(kwargs['space_id'])

        return self._space_list()

    def PUT(self, args, **kwargs):
        try:
            schema = SpotSchema().get()
            space_id = kwargs['space_id']
            space = Space.objects.get(id=space_id)
            if space.is_deleted:
                self.error404_response()

            if space.spot_id:
                spot = Spot().get(space.spot_id)
            else:
                spot = self._spacemap.pending_spot(space, schema)

            Permitted().can_edit(self._request.user, space, spot)

            data = json.loads(self._request.read())

            for field in data:
                if field and field.startswith("extended_info.has_"):
                    data[field] = data[field].lower()
            fields, missing_fields = self._validate(spot, data)

            pending = json.loads(space.pending) if space.pending else {}

            for field in fields:
                if field == 'editors':
                    try:
                        for editor in SpaceEditor.objects.filter(space=space):
                            editor.delete()
                    except SpaceEditor.DoesNotExist:
                        pass

                    for username in fields[field].split(','):
                        editor = username.strip()
                        if len(editor):
                            space_editor = SpaceEditor(editor=username.strip(),space=space)
                            space_editor.save()
                else:
                    pending[field] = fields[field]

                pending[field] = fields[field]

            if len(missing_fields) > 0:
                space.is_complete = None
                space.is_pending_publication = None
                pending['_missing_fields'] = missing_fields
            else:
                space.is_complete = True

            # SPOT-1303
            if 'manager' in data:
                space.manager = data['manager']

            if 'is_published' in data:
                if data.get('is_published') == True:
                    space_images = SpaceImage.objects.filter(space=space.id)
                    image_links = SpotImageLink.objects.filter(space=space.id,
                                                              is_deleted__isnull=False)
                    if space.is_complete and (space.pending and len(space.pending) != 0
                                              or len(space_images) or len(image_links)):

                        # create/update modified spot
                        spot = self._spacemap.apply_pending(spot, space)

                        if space.spot_id:
                            Spot().put(spot, self._request.user)
                        else:
                            spot = Spot().post(spot, self._request.user)
                            space.spot_id = spot.get('id')

                        # fix up images, adding new, updating spot images
                        for img in image_links:
                            if img.is_deleted:
                                Image(space.spot_id).delete(img.image_id)
                                img.delete()
                            else:
                                Image(space.spot_id).put(img.image_id,
                                                         { 'display_index' : img.display_index },
                                                         self._request.user)

                        for img in space_images:
                            spotimage = Image(space.spot_id).post(img.image.path,
                                                                  img.description,
                                                                  self._request.user)
                            link = SpotImageLink(space=space,
                                                 spot_id=space.spot_id,
                                                 image_id=spotimage.get('id'),
                                                 display_index=img.display_index)
                            link.save()
                            img.delete()

                    pending = {}
                    space.is_complete = None
                    space.is_pending_publication = None
                else: # unpublish
                    # pull spot data into space.pending
                    # remove spot from spot server
                    # spot().delete(spot.id)
                    # images?
                    pass
                    
            elif 'is_pending_publication' in data:
                if data.get('is_pending_publication') == True:
                    if space.is_pending_publication != True:
                        space.is_pending_publication = True
                        if hasattr(settings, 'SS_PUBLISHER_EMAIL'):
                            send_mail('Space Publishing Request',
                                      'A request has been made to publish space\n\t http%s://%s%sspace/%s/' \
                                          % ('s' if self._request.is_secure() else '',
                                             self._request.get_host(),
                                             settings.APP_URL_ROOT,
                                             space.id),
                                      settings.SS_PUBLISHER_FROM,
                                      settings.SS_PUBLISHER_EMAIL,
                                      fail_silently=False)
            else:
                space.is_pending_publication = False

            space.modified_by = self._request.user.username
            space.pending = json.dumps(pending) if len(pending) > 0 else None
            space.save()
            return self.json_response('{"id": "%s"}' % space.id)
        except PermittedException:
            return self.error_response(401, "Unauthorized")
        except Space.DoesNotExist:
            if e.args[0]['status_code'] == 404:
                self.error404_response()
                # no return
        except (SpaceMapException, SpotException, SpotSchemaException) as e:
            return self.error_response(e.args[0]['status_code'],
                                       e.args[0]['status_text'])
        except Exception as ex:
            return self.error_response(400, "Unknown error: %s" % ex)

    def POST(self, args, **kwargs):
        try:
            Permitted().can_create(self._request.user)
            schema = SpotSchema().get()
            space = Space(manager=self._request.user,
                          modified_by=self._request.user)
            spot = self._spacemap.pending_spot(space, schema)

            data = json.loads(self._request.read())

            fields, missing_fields = self._validate(spot, data)
            pending = {}
            for field in fields:
                if field == 'editors':
                    for username in fields[field].split(','):
                        editor = username.strip()
                        if len(editor):
                            space_editor = SpaceEditor(editor=username.strip(),space=space)
                            space_editor.save()
                else:
                    pending[field] = fields[field]

            if len(missing_fields) > 0:
                space.is_complete = None
                pending['_missing_fields'] = missing_fields
            else:
                space.is_complete = True

            for field in space_creation_fields():
                if 'value' in field and 'key' in field['value']:
                    key = field['value']['key']
                    if 'required' in field and (key not in data or bool(data[key]) == False):
                        return self.error_response(400, "Bad Request")

            space.pending = json.dumps(pending) if len(pending) > 0 else None


            space.save()
            return self.json_response('{"id": "%s"}' % space.id)
        except PermittedException:
            return self.error_response(401, "Unauthorized")

    def DELETE(self, args, **kwargs):
        try:
            space_id = kwargs['space_id']
            schema = SpotSchema().get()
            space = Space.objects.get(id=space_id)
            if space.is_deleted:
                raise Space.DoesNotExist

            if space.spot_id:
                spot = Spot().get(space.spot_id)
            else:
                spot = self._spacemap.pending_spot(space, schema)

            Permitted().can_edit(self._request.user, space, spot)
            space.is_deleted = True
            space.save()
            return self.json_response(json.dumps('{}'))
        except Space.DoesNotExist:
            self.error404_response()

    def _validate(self, spot, data):
        fields = {}
        missing_fields = []
        seen_fields = {}
        for section in space_definitions():
            for field in section['fields'] if 'fields' in section else []:
                for value in field['value'] if isinstance(field['value'], list) else [field['value']]:
                    key = value['key']
                    val = data[key] if key in data else None
                    orig_val = self._spot_value(key, spot)
                    if key in data and val != orig_val:
                        fields[key] = val
                        # SPOT-1277
                        if val == None or val == "":
                            orig_val = None

                    if 'required' in field and bool(val) == False and bool(orig_val) == False:
                        s = section.get('section')
                        f = field.get('name')
                        if s + f not in seen_fields:
                            missing_fields.append({ 'section': s, 'field': f })
                            seen_fields[s + f] = True

        if 'available_hours' in data:
            valid_hours = True
            available = {}
            for d in data['available_hours']:
                hours = [0 for i in range(0,2400)]
                for h in data['available_hours'][d]:
                    if len(h) == 2:
                        opn = int("".join(h[0].split(":")))
                        cls = int("".join(h[1].split(":")))
                        if opn < 0 or opn > 2359 or opn % 100 >= 60 or cls < 0 or cls > 2359 or cls % 100 >= 60 or opn >= cls:
                            valid_hours = False
                        else:
                            for i in range(opn, cls):
                                if i % 100 < 60:
                                    hours[i] = 1
                    else:
                        valid_hours = False

                available[d] = []
                opn = 0
                state = 0
                for i in range(0, 2360):
                    if i % 100 < 60:
                        if state != hours[i]:
                            state = hours[i]
                            if hours[i]:
                                opn = i
                            else:
                                available[d].append(self._hours_range([opn, i]))

            if valid_hours:
                fields['available_hours'] = available

        return fields, missing_fields

    def _hours_range(self, hours):
        r = []
        for i in range(0, 2):
            r.append(":".join([self._double_digit(math.trunc(hours[i]/100)),
                               self._double_digit(hours[i]%100)]))

        return r

    def _double_digit(self, d):
        return "{0}{1}".format('0' if d < 10 else '', d)

    def _space_detail(self, space_id):
        try:
            schema = SpotSchema().get()
            space_model = Space.objects.get(id=space_id)
            if space_model.is_deleted:
                raise Space.DoesNotExist

            if space_model.spot_id:
                spot = Spot().get(space_model.spot_id)
            else:
                spot = self._spacemap.pending_spot(space_model, schema)

            Permitted().can_edit(self._request.user, space_model, spot)

            return self.json_response(json.dumps(self._spacemap.space_rep(space_model, spot, schema)))

        except PermittedException:
            return self.error_response(401, "Unauthorized")
        except Space.DoesNotExist:
            self.error404_response()
        except (SpaceMapException, SpotException, SpotSchemaException) as e:
            return self.error_response(e.args[0]['status_code'],
                                       e.args[0]['status_text'])

    def _space_list(self):
        filter = {}
        published = True
        complete = True
        json_rep = []
        seen = {}
        permitted = Permitted()

        try:
            is_admin = permitted.is_admin(self._request.user)
        except PermittedException:
            is_admin = False

        try:
            schema = SpotSchema().get()
        except SpotSchemaException as e:
            return self.error_response(e.args[0]['status_code'],
                                       e.args[0]['status_text'])

        if 'published' in self._request.GET:
            p = self._request.GET.get('published')
            published = True if (p == '1' or p.lower() == 'true') else False
            filter['spot_id__isnull'] = True if (not published) else False

        if 'complete' in self._request.GET:
            i = self._request.GET.get('complete')
            complete = (i == '1' or i.lower() == 'true')
            filter['spot_id__isnull'] = True
            if not complete:
                filter['is_complete__isnull'] = True
            else:
                filter['is_complete'] = True

        if published:
            search_args = {
                #'manager': '',
                #'editors': '',
                'limit': '0'
            }

            try:
                spots = self._get_spots(search_args)
            except Exception, errstr:
                return self.error_response(500, ("%s" % (errstr)))

            for spot in spots:
                try:
                    spot_id = spot.get('id')
                    try:
                        space = Space.objects.get(spot_id=spot_id)
                        if space.is_deleted:
                            continue
                    except Space.DoesNotExist:
                        space = Space(spot_id=spot_id,
                                      manager=spot.get('manager'),
                                      is_complete=True)
                        space.save()

                    if not is_admin:
                        permitted.can_edit(self._request.user, space, spot)

                    if str(spot_id) not in seen:
                        seen[str(spot_id)] = 1
                        json_rep.append(self._spacemap.space_rep(space, spot, schema))

                except PermittedException:
                    pass
                except SpaceMapException as e:
                    return self.error_response(e.args[0]['status_code'],
                                               e.args[0]['status_text'])

        for space in Space.objects.filter(**filter):
            if space.is_deleted or str(space.spot_id) in seen:
                continue

            try:
                if space.spot_id:
                    try:
                        spot = Spot().get(space.spot_id)
                    except SpotException as se:
                        logger.info("No Spot for %s.  Error: %s" % (space.spot_id, se.args[0]))
                        continue
                else:
                    spot = self._spacemap.pending_spot(space, schema)

                if not is_admin:
                    permitted.can_edit(self._request.user, space, spot)

                json_rep.append(self._spacemap.space_rep(space, spot, schema))
            except PermittedException:
                pass
            except SpaceMapException as e:
                return self.error_response(e.args[0]['status_code'],
                                           e.args[0]['status_text'])

        return self.json_response(json.dumps(json_rep))
Esempio n. 4
0
class SpaceManager(RESTDispatch):
    """ Performs actions on Space models at api/v1/space/(?P<space_id>\d+)/
        Space models are a layer on top of spotseeker_server Spot models.
        GET returns requested Space model(s)
        PUT modifies a Space model, conditionally modifies the Spot model supporting it
        POST creates a Space model
    """
    def __init__(self):
        self._spacemap = SpaceMap()

    def GET(self, args, **kwargs):
        if 'space_id' in kwargs:
            return self._space_detail(kwargs['space_id'])

        return self._space_list()

    def PUT(self, args, **kwargs):
        try:
            schema = SpotSchema().get()
            space_id = kwargs['space_id']
            space = Space.objects.get(id=space_id)
            if space.is_deleted:
                self.error404_response()

            if space.spot_id:
                spot = Spot().get(space.spot_id)
            else:
                spot = self._spacemap.pending_spot(space, schema)

            Permitted().can_edit(self._request.user, space, spot)

            data = json.loads(self._request.read())

            for field in data:
                if field and field.startswith("extended_info.has_"):
                    data[field] = data[field].lower()
            fields, missing_fields = self._validate(spot, data)

            pending = json.loads(space.pending) if space.pending else {}

            for field in fields:
                if field == 'editors':
                    try:
                        for editor in SpaceEditor.objects.filter(space=space):
                            editor.delete()
                    except SpaceEditor.DoesNotExist:
                        pass

                    for username in fields[field].split(','):
                        editor = username.strip()
                        if len(editor):
                            space_editor = SpaceEditor(editor=username.strip(),
                                                       space=space)
                            space_editor.save()
                else:
                    pending[field] = fields[field]

                pending[field] = fields[field]

            if len(missing_fields) > 0:
                space.is_complete = None
                space.is_pending_publication = None
                pending['_missing_fields'] = missing_fields
            else:
                space.is_complete = True

            # SPOT-1303
            if 'manager' in data:
                space.manager = data['manager']

            if 'is_published' in data:
                if data.get('is_published') == True:
                    space_images = SpaceImage.objects.filter(space=space.id)
                    image_links = SpotImageLink.objects.filter(
                        space=space.id, is_deleted__isnull=False)
                    if space.is_complete and (
                            space.pending and len(space.pending) != 0
                            or len(space_images) or len(image_links)):

                        # create/update modified spot
                        spot = self._spacemap.apply_pending(spot, space)

                        if space.spot_id:
                            Spot().put(spot, self._request.user)
                        else:
                            spot = Spot().post(spot, self._request.user)
                            space.spot_id = spot.get('id')

                        # fix up images, adding new, updating spot images
                        for img in image_links:
                            if img.is_deleted:
                                Image(space.spot_id).delete(img.image_id)
                                img.delete()
                            else:
                                Image(space.spot_id).put(
                                    img.image_id,
                                    {'display_index': img.display_index},
                                    self._request.user)

                        for img in space_images:
                            spotimage = Image(space.spot_id).post(
                                img.image.path, img.description,
                                self._request.user)
                            link = SpotImageLink(
                                space=space,
                                spot_id=space.spot_id,
                                image_id=spotimage.get('id'),
                                display_index=img.display_index)
                            link.save()
                            img.delete()

                    pending = {}
                    space.is_complete = None
                    space.is_pending_publication = None
                else:  # unpublish
                    # pull spot data into space.pending
                    # remove spot from spot server
                    # spot().delete(spot.id)
                    # images?
                    pass

            elif 'is_pending_publication' in data:
                if data.get('is_pending_publication') == True:
                    if space.is_pending_publication != True:
                        space.is_pending_publication = True
                        if hasattr(settings, 'SS_PUBLISHER_EMAIL'):
                            send_mail('Space Publishing Request',
                                      'A request has been made to publish space\n\t http%s://%s%sspace/%s/' \
                                          % ('s' if self._request.is_secure() else '',
                                             self._request.get_host(),
                                             settings.APP_URL_ROOT,
                                             space.id),
                                      settings.SS_PUBLISHER_FROM,
                                      settings.SS_PUBLISHER_EMAIL,
                                      fail_silently=False)
            else:
                space.is_pending_publication = False

            space.modified_by = self._request.user.username
            space.pending = json.dumps(pending) if len(pending) > 0 else None
            space.save()
            return self.json_response('{"id": "%s"}' % space.id)
        except PermittedException:
            return self.error_response(401, "Unauthorized")
        except Space.DoesNotExist:
            if e.args[0]['status_code'] == 404:
                self.error404_response()
                # no return
        except (SpaceMapException, SpotException, SpotSchemaException) as e:
            return self.error_response(e.args[0]['status_code'],
                                       e.args[0]['status_text'])
        except Exception as ex:
            return self.error_response(400, "Unknown error: %s" % ex)

    def POST(self, args, **kwargs):
        try:
            Permitted().can_create(self._request.user)
            schema = SpotSchema().get()
            space = Space(manager=self._request.user,
                          modified_by=self._request.user)
            spot = self._spacemap.pending_spot(space, schema)

            data = json.loads(self._request.read())

            fields, missing_fields = self._validate(spot, data)
            pending = {}
            for field in fields:
                if field == 'editors':
                    for username in fields[field].split(','):
                        editor = username.strip()
                        if len(editor):
                            space_editor = SpaceEditor(editor=username.strip(),
                                                       space=space)
                            space_editor.save()
                else:
                    pending[field] = fields[field]

            if len(missing_fields) > 0:
                space.is_complete = None
                pending['_missing_fields'] = missing_fields
            else:
                space.is_complete = True

            for field in space_creation_fields():
                if 'value' in field and 'key' in field['value']:
                    key = field['value']['key']
                    if 'required' in field and (key not in data
                                                or bool(data[key]) == False):
                        return self.error_response(400, "Bad Request")

            space.pending = json.dumps(pending) if len(pending) > 0 else None

            space.save()
            return self.json_response('{"id": "%s"}' % space.id)
        except PermittedException:
            return self.error_response(401, "Unauthorized")

    def DELETE(self, args, **kwargs):
        try:
            space_id = kwargs['space_id']
            schema = SpotSchema().get()
            space = Space.objects.get(id=space_id)
            if space.is_deleted:
                raise Space.DoesNotExist

            if space.spot_id:
                spot = Spot().get(space.spot_id)
            else:
                spot = self._spacemap.pending_spot(space, schema)

            Permitted().can_edit(self._request.user, space, spot)
            space.is_deleted = True
            space.save()
            return self.json_response(json.dumps('{}'))
        except Space.DoesNotExist:
            self.error404_response()

    def _validate(self, spot, data):
        fields = {}
        missing_fields = []
        seen_fields = {}
        for section in space_definitions():
            for field in section['fields'] if 'fields' in section else []:
                for value in field['value'] if isinstance(
                        field['value'], list) else [field['value']]:
                    key = value['key']
                    val = data[key] if key in data else None
                    orig_val = self._spot_value(key, spot)
                    if key in data and val != orig_val:
                        fields[key] = val
                        # SPOT-1277
                        if val == None or val == "":
                            orig_val = None

                    if 'required' in field and bool(val) == False and bool(
                            orig_val) == False:
                        s = section.get('section')
                        f = field.get('name')
                        if s + f not in seen_fields:
                            missing_fields.append({'section': s, 'field': f})
                            seen_fields[s + f] = True

        if 'available_hours' in data:
            valid_hours = True
            available = {}
            for d in data['available_hours']:
                hours = [0 for i in range(0, 2400)]
                for h in data['available_hours'][d]:
                    if len(h) == 2:
                        opn = int("".join(h[0].split(":")))
                        cls = int("".join(h[1].split(":")))
                        if opn < 0 or opn > 2359 or opn % 100 >= 60 or cls < 0 or cls > 2359 or cls % 100 >= 60 or opn >= cls:
                            valid_hours = False
                        else:
                            for i in range(opn, cls):
                                if i % 100 < 60:
                                    hours[i] = 1
                    else:
                        valid_hours = False

                available[d] = []
                opn = 0
                state = 0
                for i in range(0, 2360):
                    if i % 100 < 60:
                        if state != hours[i]:
                            state = hours[i]
                            if hours[i]:
                                opn = i
                            else:
                                available[d].append(self._hours_range([opn,
                                                                       i]))

            if valid_hours:
                fields['available_hours'] = available

        return fields, missing_fields

    def _hours_range(self, hours):
        r = []
        for i in range(0, 2):
            r.append(":".join([
                self._double_digit(math.trunc(hours[i] / 100)),
                self._double_digit(hours[i] % 100)
            ]))

        return r

    def _double_digit(self, d):
        return "{0}{1}".format('0' if d < 10 else '', d)

    def _space_detail(self, space_id):
        try:
            schema = SpotSchema().get()
            space_model = Space.objects.get(id=space_id)
            if space_model.is_deleted:
                raise Space.DoesNotExist

            if space_model.spot_id:
                spot = Spot().get(space_model.spot_id)
            else:
                spot = self._spacemap.pending_spot(space_model, schema)

            Permitted().can_edit(self._request.user, space_model, spot)

            return self.json_response(
                json.dumps(self._spacemap.space_rep(space_model, spot,
                                                    schema)))

        except PermittedException:
            return self.error_response(401, "Unauthorized")
        except Space.DoesNotExist:
            self.error404_response()
        except (SpaceMapException, SpotException, SpotSchemaException) as e:
            return self.error_response(e.args[0]['status_code'],
                                       e.args[0]['status_text'])

    def _space_list(self):
        filter = {}
        published = True
        complete = True
        json_rep = []
        seen = {}
        permitted = Permitted()

        try:
            is_admin = permitted.is_admin(self._request.user)
        except PermittedException:
            is_admin = False

        try:
            schema = SpotSchema().get()
        except SpotSchemaException as e:
            return self.error_response(e.args[0]['status_code'],
                                       e.args[0]['status_text'])

        if 'published' in self._request.GET:
            p = self._request.GET.get('published')
            published = True if (p == '1' or p.lower() == 'true') else False
            filter['spot_id__isnull'] = True if (not published) else False

        if 'complete' in self._request.GET:
            i = self._request.GET.get('complete')
            complete = (i == '1' or i.lower() == 'true')
            filter['spot_id__isnull'] = True
            if not complete:
                filter['is_complete__isnull'] = True
            else:
                filter['is_complete'] = True

        if published:
            search_args = {
                #'manager': '',
                #'editors': '',
                'limit': '0'
            }

            try:
                spots = self._get_spots(search_args)
            except Exception, errstr:
                return self.error_response(500, ("%s" % (errstr)))

            for spot in spots:
                try:
                    spot_id = spot.get('id')
                    try:
                        space = Space.objects.get(spot_id=spot_id)
                        if space.is_deleted:
                            continue
                    except Space.DoesNotExist:
                        space = Space(spot_id=spot_id,
                                      manager=spot.get('manager'),
                                      is_complete=True)
                        space.save()

                    if not is_admin:
                        permitted.can_edit(self._request.user, space, spot)

                    if str(spot_id) not in seen:
                        seen[str(spot_id)] = 1
                        json_rep.append(
                            self._spacemap.space_rep(space, spot, schema))

                except PermittedException:
                    pass
                except SpaceMapException as e:
                    return self.error_response(e.args[0]['status_code'],
                                               e.args[0]['status_text'])

        for space in Space.objects.filter(**filter):
            if space.is_deleted or str(space.spot_id) in seen:
                continue

            try:
                if space.spot_id:
                    try:
                        spot = Spot().get(space.spot_id)
                    except SpotException as se:
                        logger.info("No Spot for %s.  Error: %s" %
                                    (space.spot_id, se.args[0]))
                        continue
                else:
                    spot = self._spacemap.pending_spot(space, schema)

                if not is_admin:
                    permitted.can_edit(self._request.user, space, spot)

                json_rep.append(self._spacemap.space_rep(space, spot, schema))
            except PermittedException:
                pass
            except SpaceMapException as e:
                return self.error_response(e.args[0]['status_code'],
                                           e.args[0]['status_text'])

        return self.json_response(json.dumps(json_rep))