Example #1
0
 def test_errors(self):
     form = SpotForm({})
     errors = form.errors
     self.assertTrue("name" in errors,
                     "Default spot form requires a spot name")
     self.assertFalse("capacity" in errors,
                      "Default spot form doesn't require a spot name")
Example #2
0
class SpotAdmin(admin.ModelAdmin):
    """ The admin model for a Spot.
    The ETag is excluded because it is generated on Spot save.
    """
    form = SpotForm.implementation()

    list_display = ("name", "building_name", "floor", "room_number",
                    "capacity", "organization", "manager")
    list_filter = ["spottypes", "building_name", "organization", "manager"]

    actions = ['delete_model']

    def get_actions(self, request):
        actions = super(SpotAdmin, self).get_actions(request)
        del actions['delete_selected']
        return actions

    def delete_model(self, request, spots):
        if type(spots) is Spot:
            spots.delete()
        else:
            for spot in spots.all():
                spot.delete()

    delete_model.short_description = "Delete selected spots"
Example #3
0
 def test_errors(self):
     """Assert that an empty form produces validation errors"""
     form = SpotForm({})
     errors = form.errors
     self.assertIn('name', errors)
     # Capacity is not required, so it should not have an error
     self.assertNotIn('capacity', errors)
Example #4
0
    def build_and_save_from_input(self, request, spot):
        body = request.read()
        try:
            new_values = json.loads(body)
        except Exception as e:
            response = HttpResponse('{"error":"Unable to parse JSON"}')
            response.status_code = 400
            return response

        form = SpotForm(new_values)
        if not form.is_valid():
            if request.method == 'POST':
                spot.delete()
            response = HttpResponse(json.dumps(form.errors))
            response.status_code = 400
            return response

        existing_info = spot.json_data_structure()
        for key in spot.json_data_structure():
            if spot.json_data_structure().get(key) is None or spot.json_data_structure().get(key) == {} or spot.json_data_structure().get(key) == '' or spot.json_data_structure().get(key) == [] or key == 'last_modified' or key == 'eTag':
                del existing_info[key]
        if existing_info != new_values:
            errors = []
            #Validate the data POST and record errors and don't make the spot
            if "name" in new_values:
                if new_values["name"]:
                    spot.name = new_values["name"]
                else:
                    errors.append("Invalid name")
            else:
                error.append("Name not provided")

            if "capacity" in new_values:
                if new_values["capacity"]:
                    try:
                        spot.capacity = int(new_values["capacity"])
                    except:
                        pass
            elif spot.capacity is not None:
                spot.capacity = None

            if "type" in new_values:
                for value in new_values["type"]:
                    try:
                        value = SpotType.objects.get(name=value)
                        spot.spottypes.add(value)
                    except:
                        pass
            elif spot.spottypes is not None:
                spot.spottypes.remove()

            if "location" in new_values:
                loc_vals = new_values["location"]
                if "latitude" in loc_vals and "longitude" in loc_vals:
                    try:
                        spot.latitude = float(loc_vals["latitude"])
                        spot.longitude = float(loc_vals["longitude"])

                        # The 2 up there are just to throw the exception below.  They need to not actually be floats
                        spot.latitude = loc_vals["latitude"]
                        spot.longitude = loc_vals["longitude"]
                    except:
                        pass
                        errors.append("Invalid latitude and longitude: %s, %s" % (loc_vals["latitude"], loc_vals["longitude"]))
                else:
                    errors.append("Latitude and longitude not provided")

                if "height_from_sea_level" in loc_vals:
                    try:
                        spot.height_from_sea_level = float(loc_vals["height_from_sea_level"])
                    except:
                        pass
                elif spot.height_from_sea_level is not None:
                    spot.height_from_sea_level = None

                if "building_name" in loc_vals:
                    spot.building_name = loc_vals["building_name"]
                elif spot.building_name != '':
                    spot.building_name = ''
                if "floor" in loc_vals:
                    spot.floor = loc_vals["floor"]
                elif spot.floor != '':
                    spot.floor = ''
                if "room_number" in loc_vals:
                    spot.room_number = loc_vals["room_number"]
                elif spot.room_number != '':
                    spot.room_number = ''
                if "description" in loc_vals:
                    spot.description = loc_vals["description"]
                # TO DO: see if there is a better way of doing the following check
                else:
                    try:
                        if spot.description is not None:
                            spot.description = None
                    except:
                        pass
            else:
                errors.append("Location data not provided")

            if "organization" in new_values:
                spot.organization = new_values["organization"]
            elif spot.organization != '':
                spot.organization = ''
            if "manager" in new_values:
                spot.manager = new_values["manager"]
            elif spot.manager != '':
                spot.manager = ''

            if len(errors) == 0:
                spot.save()
            else:
                spot.delete()
                response = HttpResponse('{"error":"' + str(errors) + '"}')
                response.status_code = 400
                return response

            queryset = SpotAvailableHours.objects.filter(spot=spot)
            queryset.delete()

            if "extended_info" in new_values:
                for item in new_values["extended_info"]:
                    try:
                        info_obj = SpotExtendedInfo.objects.get(spot=spot, key=item)
                        info_obj.value = new_values["extended_info"][item]
                        info_obj.save()
                    except:
                        SpotExtendedInfo.objects.create(key=item, value=new_values["extended_info"][item], spot=spot)
                for info in SpotExtendedInfo.objects.filter(spot=spot).values():
                    if info['key'] not in new_values['extended_info']:
                        SpotExtendedInfo.objects.filter(spot=spot, key=info['key']).delete()
            elif "extended_info" not in new_values:
                SpotExtendedInfo.objects.filter(spot=spot).all().delete()

            try:
                available_hours = new_values["available_hours"]
                for day in [["m", "monday"],
                            ["t", "tuesday"],
                            ["w", "wednesday"],
                            ["th", "thursday"],
                            ["f", "friday"],
                            ["sa", "saturday"],
                            ["su", "sunday"]]:
                    if day[1] in available_hours:
                        day_hours = available_hours[day[1]]
                        for window in day_hours:
                            SpotAvailableHours.objects.create(spot=spot, day=day[0], start_time=window[0], end_time=window[1])
            except:
                pass
Example #5
0
    def GET(self, request):
        """ Json data that should contain every single piece of information that any spot might contain.
            The keys will be what info spots might contains, and the values will be what the possible
            types are for the actual values. If there is a list of values (even only a list of size 1)
            those are the only values that will pass validations.
        """
        schema = {
            "uri": "auto",
            "available_hours": "hours_string",
            "location": {},
            "type": [],
            "extended_info": {},
            "images": [],
        }

        location_descriptors = [
            "latitude", "longitude", "height_from_sea_level", "building_name",
            "floor", "room_number"
        ]

        internal_type_map = {
            "AutoField": "int",
            "BigIntegerField": "int",
            "BooleanField": "boolean",
            "CharField": "unicode",
            "CommaSeparatedIntegerField": "unicode",
            "DateField": "date",
            "DateTimeField": "datetime",
            "DecimalField": "decimal",
            "EmailField": "unicode",
            "FileField": "unicode",
            "FilePathField": "unicode",
            "FloatField": "float",
            "ForeignKey": "unicode",
            "ImageField": "unicode",
            "IntegerField": "int",
            "IPAddressField": "unicode",
            "GenericIPAddressField": "unicode",
            "ManyToManyField": "unicode",
            "NullBooleanField": "boolean",
            "OneToOneField": "unicode",
            "PositiveIntegerField": "int",
            "PositiveSmallIntegerField": "int",
            "SlugField": "unicode",
            "SmallIntegerField": "int",
            "TextField": "unicode",
            "TimeField": "time",
            "URLField": "url",
        }

        # To grab regular spot info
        spot_field_array = models.get_model('spotseeker_server',
                                            'Spot')._meta.fields
        for field in spot_field_array:
            if field.auto_created or not field.editable or field.name == "etag":  # pk (id), auto_now=True, auto_now_add=True, and "etag"
                schema.update({field.name: "auto"})
            elif field.get_internal_type() in internal_type_map:
                if field.name in location_descriptors:
                    schema["location"].update({
                        field.name:
                        internal_type_map[field.get_internal_type()]
                    })
                else:
                    schema.update({
                        field.name:
                        internal_type_map[field.get_internal_type()]
                    })
            else:
                if field.name in location_descriptors:
                    schema["location"].update(
                        {field.name: field.get_internal_type()})
                else:
                    schema.update({field.name: field.get_internal_type()})

        # To grab spot image info
        spot_image_field_array = models.get_model('spotseeker_server',
                                                  'SpotImage')._meta.fields
        schema_image = {}
        for field in spot_image_field_array:
            if field.auto_created or not field.editable or field.name == "etag":  # pk (id), auto_now=True, auto_now_add=True, and "etag"
                schema_image.update({field.name: "auto"})
            elif field.get_internal_type() in internal_type_map:
                schema_image.update(
                    {field.name: internal_type_map[field.get_internal_type()]})
            else:
                schema_image.update({field.name: field.get_internal_type()})
        schema["images"].append(schema_image)

        # To grab all of the different spot types
        for spot_type in SpotType.objects.all():
            schema["type"].append(spot_type.name)

        # To grab all of the extended info
        try:
            validated_ei = SpotForm.implementation().validated_extended_info
            org_form_exists = True
        except:
            org_form_exists = False
        for key_dict in SpotExtendedInfo.objects.values("key").distinct():
            key = key_dict["key"]
            if org_form_exists and key in validated_ei:
                schema["extended_info"].update({key: validated_ei[key]})
            else:
                schema["extended_info"].update({key: "unicode"})

        return JSONResponse(schema)
Example #6
0
    def build_and_save_from_input(self, request, spot):
        body = request.read()
        try:
            json_values = json.loads(body)
        except Exception as e:
            raise RESTException("Unable to parse JSON", status_code=400)

        partial_update = False
        stash = {}
        is_new = spot is None

        spot_pre_build.send(
            sender=SpotForm.implementation(),
            request=request,
            json_values=json_values,
            spot=spot,
            partial_update=partial_update,
            stash=stash
        )

        self._build_spot_types(json_values, spot, partial_update)
        self._build_spot_location(json_values)

        spot_pre_save.send(
            sender=SpotForm.implementation(),
            request=request,
            json_values=json_values,
            spot=spot,
            partial_update=partial_update,
            stash=stash
        )

        # Remve excluded fields
        excludefields = set(SpotForm.implementation().Meta.exclude)
        for fieldname in excludefields:
            if fieldname in json_values:
                del json_values[fieldname]

        if spot is not None and partial_update:
            # Copy over the existing values
            for field in spot._meta.fields:
                if field.name in excludefields:
                    continue
                if field.name not in json_values:
                    json_values[field.name] = getattr(spot, field.name)

            # spottypes is not included in the above copy, do it manually
            if 'spottypes' not in json_values:
                json_values['spottypes'] = [t.pk for t in spot.spottypes.all()]

        form = SpotForm(json_values, instance=spot)
        if not form.is_valid():
            raise RESTFormInvalidError(form)

        spot = form.save()

        spot_post_save.send(
            sender=SpotForm.implementation(),
            request=request,
            spot=spot,
            partial_update=partial_update,
            stash=stash
        )

        # gets the current etag
        spot = Spot.get_with_external(spot.pk)

        if is_new:
            response = HttpResponse(status=201)
            response['Location'] = spot.rest_url()
        else:
            response = JSONResponse(spot.json_data_structure(), status=200)
        response["ETag"] = spot.etag

        spot_post_build.send(
            sender=SpotForm.implementation(),
            request=request,
            response=response,
            spot=spot,
            partial_update=partial_update,
            stash=stash
        )

        return response
Example #7
0
 def test_default(self):
     form = SpotForm({})
     self.assertEqual(
         form.__class__,
         DefaultSpotForm({}).__class__,
         "Tests shouldn't be run with a defined SPOTSEEKER_SPOT_FORM")
Example #8
0
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver

from geoposition import Geoposition
from geoposition.forms import GeopositionField
import logging
from spotseeker_server.admin import SpotAdmin
from spotseeker_server.forms.spot import SpotForm as SSSpotForm, SpotExtendedInfoForm as SSSpotExtendedInfoForm
from spotseeker_server.models import SpotAvailableHours, SpotImage, SpaceReview
import re

from .models import UIUCSpot, UIUCSpaceReview, HostAuthRule

logger = logging.getLogger(__name__)

SpotForm = SSSpotForm.implementation()
SpotExtendedInfoForm = SSSpotExtendedInfoForm.implementation()

SPOT_BOOLEAN_FIELDS = (
    'has_whiteboards',
    'has_outlets',
    'has_printing',
    'has_scanner',
    'has_displays',
    'has_projector',
    'has_computers',
    'has_natural_light',
    'reservable',
    )

SPOT_INTEGER_FIELDS = (
Example #9
0
    def GET(self, request):
        """ Json data that should contain every single piece of information
            that any spot might contain.

            The keys will be what info spots might contains, and the values
            will be what the possible types are for the actual values. If
            there is a list of values (even only a list of size 1)
            those are the only values that will pass validations.
        """
        schema = {
            "uri": "auto",
            "available_hours": "hours_string",
            "location": {},
            "type": [],
            "extended_info": {},
            "images": [],
        }

        location_descriptors = [
            "latitude",
            "longitude",
            "height_from_sea_level",
            "building_name",
            "floor",
            "room_number"
        ]

        internal_type_map = {
            "AutoField": "int",
            "BigIntegerField": "int",
            "BooleanField": "boolean",
            "CharField": "unicode",
            "CommaSeparatedIntegerField": "unicode",
            "DateField": "date",
            "DateTimeField": "datetime",
            "DecimalField": "decimal",
            "EmailField": "unicode",
            "FileField": "unicode",
            "FilePathField": "unicode",
            "FloatField": "float",
            "ForeignKey": "unicode",
            "ImageField": "unicode",
            "IntegerField": "int",
            "IPAddressField": "unicode",
            "GenericIPAddressField": "unicode",
            "ManyToManyField": "unicode",
            "NullBooleanField": "boolean",
            "OneToOneField": "unicode",
            "PositiveIntegerField": "int",
            "PositiveSmallIntegerField": "int",
            "SlugField": "unicode",
            "SmallIntegerField": "int",
            "TextField": "unicode",
            "TimeField": "time",
            "URLField": "url",
        }

        # To grab regular spot info
        spot_field_array = \
            models.get_model('spotseeker_server', 'Spot')._meta.fields
        for field in spot_field_array:
            if is_auto_field(field):
                schema[field.name] = 'auto'
            else:
                field_itype = field.get_internal_type()
                if field_itype in internal_type_map:
                    field_itype = internal_type_map[field_itype]

                if field.name in location_descriptors:
                    schema['location'][field.name] = field_itype
                else:
                    schema[field.name] = field_itype

        # To grab spot image info
        spot_image_field_array = models.get_model('spotseeker_server',
                                                  'SpotImage')._meta.fields
        schema_image = {}
        for field in spot_image_field_array:
            if is_auto_field(field):
                schema_image[field.name] = 'auto'
            else:
                itype = field.get_internal_type()
                if itype in internal_type_map:
                    itype = internal_type_map[itype]
                schema_image[field.name] = itype
        schema['images'].append(schema_image)

        # To grab all of the different spot types
        for spot_type in SpotType.objects.all():
            schema["type"].append(spot_type.name)

        # To grab all of the extended info
        try:
            validated_ei = SpotForm.implementation().validated_extended_info
            org_form_exists = True
        except:
            org_form_exists = False
        for key_dict in SpotExtendedInfo.objects.values("key").distinct():
            key = key_dict["key"]
            if org_form_exists:
                schema['extended_info'][key] = validated_ei.get(key, 'unicode')

        return JSONResponse(schema)
Example #10
0
    def build_and_save_from_input(self, request, spot):
        body = request.read()
        try:
            json_values = json.loads(body)
        except Exception as e:
            raise RESTException("Unable to parse JSON", status_code=400)

        partial_update = False
        stash = {}
        is_new = spot is None

        spot_pre_build.send(sender=SpotForm.implementation(),
                            request=request,
                            json_values=json_values,
                            spot=spot,
                            partial_update=partial_update,
                            stash=stash)

        self._build_spot_types(json_values, spot, partial_update)
        self._build_spot_location(json_values)

        spot_pre_save.send(sender=SpotForm.implementation(),
                           request=request,
                           json_values=json_values,
                           spot=spot,
                           partial_update=partial_update,
                           stash=stash)

        # Remve excluded fields
        excludefields = set(SpotForm.implementation().Meta.exclude)
        for fieldname in excludefields:
            if fieldname in json_values:
                del json_values[fieldname]

        if spot is not None and partial_update:
            # Copy over the existing values
            for field in spot._meta.fields:
                if field.name in excludefields:
                    continue
                if not field.name in json_values:
                    json_values[field.name] = getattr(spot, field.name)

            # spottypes is not included in the above copy, do it manually
            if not 'spottypes' in json_values:
                json_values['spottypes'] = [t.pk for t in spot.spottypes.all()]

        form = SpotForm(json_values, instance=spot)
        if not form.is_valid():
            raise RESTFormInvalidError(form)

        spot = form.save()

        spot_post_save.send(sender=SpotForm.implementation(),
                            request=request,
                            spot=spot,
                            partial_update=partial_update,
                            stash=stash)

        # gets the current etag
        spot = Spot.get_with_external(spot.pk)

        if is_new:
            response = HttpResponse(status=201)
            response['Location'] = spot.rest_url()
        else:
            response = JSONResponse(spot.json_data_structure(), status=200)
        response["ETag"] = spot.etag

        spot_post_build.send(sender=SpotForm.implementation(),
                             request=request,
                             response=response,
                             spot=spot,
                             partial_update=partial_update,
                             stash=stash)

        return response
Example #11
0
 def test_default(self):
     form = SpotForm({})
     self.assertIs(
         type(form), DefaultSpotForm,
         "Tests shouldn't be run with a defined "
         "SPOTSEEKER_SPOT_FORM")
Example #12
0
    def build_and_save_from_input(self, request, spot):
        body = request.read()
        try:
            new_values = json.loads(body)
        except Exception as e:
            response = HttpResponse('{"error":"Unable to parse JSON"}')
            response.status_code = 400
            return response

        form = SpotForm(new_values)
        if not form.is_valid():
            spot.delete()
            response = HttpResponse(json.dumps(form.errors))
            response.status_code = 400
            return response

        errors = []
        #Validate the data POST and record errors and don't make the spot
        if "name" in new_values:
            if new_values["name"]:
                spot.name = new_values["name"]
            else:
                errors.append("Invalid name")
        else:
            error.append("Name not provided")

        if "capacity" in new_values:
            if new_values["capacity"]:
                try:
                    spot.capacity = int(new_values["capacity"])
                except:
                    pass

        if "type" in new_values:
            for value in new_values["type"]:
                try:
                    value = SpotType.objects.get(name=value)
                    spot.spottypes.add(value)
                except:
                    pass
        if "location" in new_values:
            loc_vals = new_values["location"]
            if "latitude" in loc_vals and "longitude" in loc_vals:
                try:
                    spot.latitude = float(loc_vals["latitude"])
                    spot.longitude = float(loc_vals["longitude"])

                    # The 2 up there are just to throw the exception below.  They need to not actually be floats
                    spot.latitude = loc_vals["latitude"]
                    spot.longitude = loc_vals["longitude"]
                except:
                    pass
                    errors.append("Invalid latitude and longitude: %s, %s" % (loc_vals["latitude"], loc_vals["longitude"]))
            else:
                errors.append("Latitude and longitude not provided")

            if "height_from_sea_level" in loc_vals:
                try:
                    spot.height_from_sea_level = float(loc_vals["height_from_sea_level"])
                except:
                    pass

            if "building_name" in loc_vals:
                spot.building_name = loc_vals["building_name"]
            if "floor" in loc_vals:
                spot.floor = loc_vals["floor"]
            if "room_number" in loc_vals:
                spot.room_number = loc_vals["room_number"]
            if "description" in loc_vals:
                spot.description = loc_vals["description"]
        else:
            errors.append("Location data not provided")

        if "organization" in new_values:
            spot.organization = new_values["organization"]
        if "manager" in new_values:
            spot.manager = new_values["manager"]

        if len(errors) == 0:
            spot.save()
        else:
            spot.delete()
            response = HttpResponse('{"error":"' + str(errors) + '"}')
            response.status_code = 400
            return response

        queryset = SpotAvailableHours.objects.filter(spot=spot)
        queryset.delete()

        if "extended_info" in new_values:
            for item in new_values["extended_info"]:
                SpotExtendedInfo.objects.create(key=item, value=new_values["extended_info"][item], spot=spot)

        try:
            available_hours = new_values["available_hours"]
            for day in [["m", "monday"],
                        ["t", "tuesday"],
                        ["w", "wednesday"],
                        ["th", "thursday"],
                        ["f", "friday"],
                        ["sa", "saturday"],
                        ["su", "sunday"]]:
                if day[1] in available_hours:
                    day_hours = available_hours[day[1]]
                    for window in day_hours:
                        SpotAvailableHours.objects.create(spot=spot, day=day[0], start_time=window[0], end_time=window[1])
        except:
            pass