diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..55953a51369f24fd547985c0a7bfa45ab62e8a78 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# compiled files, swap files, system files, etc. +*.pyc +*.swp +.DS_Store + +# virtualenv files +.Python +/bin/ +/include/ +/lib/ +/lib64/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..743e5cfe5035cc537ac60f7c0c21df1e9b0e4660 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +sudo: false +language: python +python: + - "2.7" +install: + - pip install --upgrade setuptools>=28 + - python setup.py -q install +before_script: + - pip install coverage + - pip install python-coveralls + - pip install pep8 + - cp travis-ci/manage.py manage.py + - python manage.py migrate --noinput +script: + - pep8 spotseeker_restclient/ --exclude=migrations + - coverage run --source=spotseeker_restclient/ --omit=spotseeker_restclient/migrations/* manage.py test spotseeker_restclient +after_script: + - coveralls +notifications: + webhooks: + urls: + - https://yarn.cac.washington.edu/rest/botalyst/v1/travis-ci \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..42e37292b3f6fb5f10212f344af7fde1057f47b1 --- /dev/null +++ b/setup.py @@ -0,0 +1,26 @@ +import os +from setuptools import setup + +README = open(os.path.join(os.path.dirname(__file__), 'README.md')).read() + +# allow setup.py to be run from any path +os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) + +setup( + name='spotseeker_restclient', + version='0.1', + packages=['spotseeker_restclient'], + include_package_data=True, + install_requires = [ + 'setuptools', + 'Django', + 'urllib3', + 'oauth2', + 'requests-oauthlib', + 'PermissionsLogging', + + ], + license='Apache License, Version 2.0', # example license + description='A Django app for consuming the spotseeker REST API', + long_description=README, +) diff --git a/spotseeker_restclient/__init__.py b/spotseeker_restclient/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/spotseeker_restclient/admin.py b/spotseeker_restclient/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e --- /dev/null +++ b/spotseeker_restclient/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/spotseeker_restclient/cache_implementation.py b/spotseeker_restclient/cache_implementation.py new file mode 100644 index 0000000000000000000000000000000000000000..5e4cec4da548ebe7406bc23e72d3367068b4a4d7 --- /dev/null +++ b/spotseeker_restclient/cache_implementation.py @@ -0,0 +1,185 @@ +""" +Contains DAO Cache implementations +""" +from spotseeker_restclient.mock_http import MockHTTP +from spotseeker_restclient.models import CacheEntry, CacheEntryTimed +from spotseeker_restclient.cache_manager import store_cache_entry +from datetime import datetime, timedelta +from django.utils.timezone import make_aware, get_current_timezone + + +class NoCache(object): + """ + This never caches anything. + """ + def getCache(self, service, url, headers): + return None + + def processResponse(self, service, url, response): + pass + + +class TimedCache(object): + """ + This is a base class for Cache implementations that cache for + lengths of time. + """ + def _response_from_cache(self, service, url, headers, max_age_in_seconds, + max_error_age=60 * 5): + + # If max_age_in_seconds is 0, + # make sure we don't get a hit from this same second. + if not max_age_in_seconds: + return None + now = make_aware(datetime.now(), get_current_timezone()) + time_limit = now - timedelta(seconds=max_age_in_seconds) + + query = CacheEntryTimed.objects.filter(service=service, + url=url, + time_saved__gte=time_limit) + + if len(query): + hit = query[0] + + if hit.status != 200 and ( + now - timedelta(seconds=max_error_age) > hit.time_saved): + return None + + response = MockHTTP() + response.status = hit.status + response.data = hit.content + response.headers = hit.getHeaders() + + return { + "response": response, + } + return None + + def _process_response(self, service, url, response, + overwrite_success_with_error_at=60 * 60 * 8): + now = make_aware(datetime.now(), get_current_timezone()) + query = CacheEntryTimed.objects.filter(service=service, + url=url) + + cache_entry = None + if len(query): + cache_entry = query[0] + else: + cache_entry = CacheEntryTimed() + + if response.status != 200: + # Only override a successful cache entry with an error if the + # Successful entry is older than 8 hours - MUWM-509 + if cache_entry.id is not None and cache_entry.status == 200: + save_delta = now - cache_entry.time_saved + extended_cache_delta = timedelta( + seconds=overwrite_success_with_error_at) + + if save_delta < extended_cache_delta: + response = MockHTTP() + response.status = cache_entry.status + response.data = cache_entry.content + return {"response": response} + + cache_entry.service = service + cache_entry.url = url + cache_entry.status = response.status + cache_entry.content = response.data + + # This extra step is needed w/ Live resources because + # HTTPHeaderDict isn't serializable. + header_data = {} + for header in response.headers: + header_data[header] = response.getheader(header) + + cache_entry.headers = header_data + cache_entry.time_saved = now + + try: + store_cache_entry(cache_entry) + except Exception as ex: + # If someone beat us in to saving a cache entry, that's ok. + # We just need a very recent entry. + return + + return + + +class TimeSimpleCache(TimedCache): + """ + This caches all URLs for 60 seconds. Used for testing. + """ + def getCache(self, service, url, headers): + return self._response_from_cache(service, url, headers, 60) + + def processResponse(self, service, url, response): + return self._process_response(service, url, response) + + +class FourHourCache(TimedCache): + """ + This caches all URLs for 4 hours. Provides a basic way to cache + cache resources that don't give a useful expires header, but you don't + want to make a server round trip to validate an etag for. + """ + def getCache(self, service, url, headers): + return self._response_from_cache(service, url, headers, 60 * 60 * 4) + + def processResponse(self, service, url, response): + return self._process_response(service, url, response) + + +class ETagCache(object): + """ + This caches objects just based on ETags. + """ + def getCache(self, service, url, headers): + now = make_aware(datetime.now(), get_current_timezone()) + time_limit = now - timedelta(seconds=60) + + query = CacheEntry.objects.filter(service=service, + url=url) + + if len(query): + hit = query[0] + + response = MockHTTP() + response.status = hit.status + response.data = hit.content + + hit_headers = hit.getHeaders() + + if "ETag" in hit_headers: + headers["If-None-Match"] = hit_headers["ETag"] + + return None + + def processResponse(self, service, url, response): + query = CacheEntryTimed.objects.filter(service=service, + url=url) + + cache_entry = CacheEntryTimed() + if len(query): + cache_entry = query[0] + + if response.status == 304: + if cache_entry is None: + raise Exception("304, but no content??") + + response = MockHTTP() + response.status = cache_entry.status + response.data = cache_entry.content + response.headers = cache_entry.headers + return {"response": response} + else: + now = make_aware(datetime.now(), get_current_timezone()) + cache_entry.service = service + cache_entry.url = url + cache_entry.status = response.status + cache_entry.content = response.data + + cache_entry.headers = response.headers + cache_entry.time_saved = now + store_cache_entry(cache_entry) + + return diff --git a/spotseeker_restclient/cache_manager.py b/spotseeker_restclient/cache_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..3ad87d3cefd041491fe84df8e1d5b837df808cda --- /dev/null +++ b/spotseeker_restclient/cache_manager.py @@ -0,0 +1,50 @@ +""" +This is a class that makes it possible to bulk-save cache entries. +For restclients methods that use threading, this can be used to prevent +innodb gap locks from deadlocking sequential inserts. +""" + +from django.db import IntegrityError + + +__manage_bulk_inserts = False +__bulk_insert_queue = [] + + +def store_cache_entry(entry): + global __manage_bulk_inserts + global __bulk_insert_queue + + if __manage_bulk_inserts: + __bulk_insert_queue.append(entry) + return + else: + entry.save() + + +def save_all_queued_entries(): + global __bulk_insert_queue + + seen_urls = {} + bulk_create = [] + + try: + for entry in __bulk_insert_queue: + if entry.url not in seen_urls: + entry.save() + seen_urls[entry.url] = True + except Exception as ex: + print "Error bulk saving cache entries: ", ex + + __bulk_insert_queue = [] + + +def enable_cache_entry_queueing(): + global __manage_bulk_inserts + __manage_bulk_inserts = True + + +def disable_cache_entry_queueing(): + global __manage_bulk_inserts + __manage_bulk_inserts = False + save_all_queued_entries() diff --git a/spotseeker_restclient/dao.py b/spotseeker_restclient/dao.py new file mode 100644 index 0000000000000000000000000000000000000000..86ca2e85ea6a079f3ef6aff098ea857a8e06b901 --- /dev/null +++ b/spotseeker_restclient/dao.py @@ -0,0 +1,84 @@ +from importlib import import_module +from django.conf import settings +from django.core.exceptions import * +from spotseeker_restclient.cache_implementation import NoCache +from spotseeker_restclient.dao_implementation.spotseeker import File \ + as SpotseekerFile + + +class DAO_BASE(object): + def _getModule(self, settings_key, default_class): + if hasattr(settings, settings_key): + # This is all taken from django's static file finder + module, attr = getattr(settings, settings_key).rsplit('.', 1) + try: + mod = import_module(module) + except ImportError, e: + raise ImproperlyConfigured('Error importing module %s: "%s"' % + (module, e)) + try: + config_module = getattr(mod, attr) + except AttributeError: + raise ImproperlyConfigured('Module "%s" does not define a ' + '"%s" class' % (module, attr)) + return config_module() + else: + return default_class() + + +class MY_DAO(DAO_BASE): + def _getCache(self): + return self._getModule('DAO_CACHE_CLASS', NoCache) + + def _getURL(self, service, url, headers): + dao = self._getDAO() + cache = self._getCache() + cache_response = cache.getCache(service, url, headers) + if cache_response is not None: + if "response" in cache_response: + return cache_response["response"] + if "headers" in cache_response: + headers = cache_response["headers"] + + response = dao.getURL(url, headers) + + cache_post_response = cache.processResponse(service, url, response) + + if cache_post_response is not None: + if "response" in cache_post_response: + return cache_post_response["response"] + + return response + + def _postURL(self, service, url, headers, body=None): + dao = self._getDAO() + response = dao.postURL(url, headers, body) + return response + + def _deleteURL(self, service, url, headers): + dao = self._getDAO() + response = dao.deleteURL(url, headers, "") + return response + + def _putURL(self, service, url, headers, body=None): + dao = self._getDAO() + response = dao.putURL(url, headers, body) + return response + + +class SPOTSEEKER_DAO(MY_DAO): + def getURL(self, url, headers): + return self._getURL('spotseeker', url, headers) + + def putURL(self, url, headers, body): + return self._putURL('spotseeker', url, headers, body) + + def postURL(self, url, headers, body): + return self._postURL('spotseeker', url, headers, body) + + def deleteURL(self, url, headers): + return self._deleteURL('spotseeker', url, headers) + + def _getDAO(self): + return self._getModule('SPOTSEEKER_DAO_CLASS', + SpotseekerFile) diff --git a/spotseeker_restclient/dao_implementation/__init__.py b/spotseeker_restclient/dao_implementation/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/spotseeker_restclient/dao_implementation/live.py b/spotseeker_restclient/dao_implementation/live.py new file mode 100644 index 0000000000000000000000000000000000000000..0c3c4195d199b2a34723c7276231b9f9b0846c63 --- /dev/null +++ b/spotseeker_restclient/dao_implementation/live.py @@ -0,0 +1,38 @@ +""" +Provides access to the http connection pools and +connections for live data from a web service + +""" +import oauth2 + +from django.conf import settings + + +def get_live_url(method, + host, + url, + headers, + body=''): + """ + Return a connection from the pool and perform an HTTP request. + :param con_pool: + is the http connection pool associated with the service + :param method: + HTTP request method (such as GET, POST, PUT, etc.) + :param host: + the url of the server host. + :param headers: + headers to include with the request + :param body: + the POST, PUT body of the request + """ + consumer = oauth2.Consumer(key=settings.SPOTSEEKER_OAUTH_KEY, + secret=settings.SPOTSEEKER_OAUTH_SECRET) + client = oauth2.Client(consumer) + url = host + url + + resp, content = client.request(url, + method=method, + body=body, + headers=headers) + return (resp, content) diff --git a/spotseeker_restclient/dao_implementation/mock.py b/spotseeker_restclient/dao_implementation/mock.py new file mode 100644 index 0000000000000000000000000000000000000000..8470c9c7264d5fbca30aa5f55d6bc8a8a2fd60ff --- /dev/null +++ b/spotseeker_restclient/dao_implementation/mock.py @@ -0,0 +1,226 @@ +import sys +import os +from os.path import abspath, dirname +import re +import json +import logging +import time +import socket +from urllib import quote, unquote, urlencode +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from importlib import import_module +from spotseeker_restclient.mock_http import MockHTTP + + +""" +A centralized the mock data access +""" +# Based on django.template.loaders.app_directories +fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() +app_resource_dirs = [] + +# An issue w/ loading order in management commands means this needs to be +# a function. Otherwise we can be trying to load modules that are trying to +# load this code, and python bails on us. + + +def __initialize_app_resource_dirs(): + if len(app_resource_dirs) > 0: + return + for app in settings.INSTALLED_APPS: + try: + mod = import_module(app) + except ImportError, e: + raise ImproperlyConfigured('ImportError %s: %s' % (app, e.args[0])) + + resource_dir = os.path.join(os.path.dirname(mod.__file__), 'resources') + if os.path.isdir(resource_dir): + # Cheating, to make sure our resources are overridable + data = { + 'path': resource_dir.decode(fs_encoding), + 'app': app, + } + if app == 'restclients': + app_resource_dirs.append(data) + else: + app_resource_dirs.insert(0, data) + + +def get_mockdata_url(service_name, implementation_name, + url, headers): + """ + :param service_name: + possible "spotseeker" + :param implementation_name: + possible values: "file", etc. + """ + + dir_base = dirname(__file__) + __initialize_app_resource_dirs() + + RESOURCE_ROOT = abspath(dir_base + "/../resources/" + + service_name + "/" + implementation_name) + + file_path = None + success = False + start_time = time.time() + + for resource_dir in app_resource_dirs: + response = _load_resource_from_path(resource_dir, service_name, + implementation_name, url, headers) + + if response: + return response + + # If no response has been found in any installed app, return a 404 + logger = logging.getLogger(__name__) + logger.info("404 for url %s, path: %s" % + (url, "resources/%s/%s/%s" % + (service_name, + implementation_name, + convert_to_platform_safe(url)))) + response = MockHTTP() + response.status = 404 + return response + + +def _load_resource_from_path(resource_dir, service_name, + implementation_name, + url, headers): + + RESOURCE_ROOT = os.path.join(resource_dir['path'], + service_name, + implementation_name) + app = resource_dir['app'] + + if url == "///": + # Just a placeholder to put everything else in an else. + # If there are things that need dynamic work, they'd go here + pass + else: + orig_file_path = RESOURCE_ROOT + url + unquoted = unquote(orig_file_path) + paths = [ + convert_to_platform_safe(orig_file_path), + "%s/index.html" % (convert_to_platform_safe(orig_file_path)), + orig_file_path, + "%s/index.html" % orig_file_path, + convert_to_platform_safe(unquoted), + "%s/index.html" % (convert_to_platform_safe(unquoted)), + unquoted, + "%s/index.html" % unquoted, + ] + + file_path = None + handle = None + for path in paths: + try: + file_path = path + handle = open(path) + break + except IOError as ex: + pass + + if handle is None: + return None + + logger = logging.getLogger(__name__) + logger.debug("URL: %s; App: %s; File: %s" % (url, app, file_path)) + + response = MockHTTP() + response.status = 200 + response.data = handle.read() + response.headers = {"X-Data-Source": service_name + " file mock data", + } + + try: + headers = open(handle.name + '.http-headers') + file_values = json.loads(headers.read()) + + if "headers" in file_values: + response.headers = dict(response.headers.items() + + file_values['headers'].items()) + + if 'status' in file_values: + response.status = file_values['status'] + + else: + response.headers = dict(response.headers.items() + + file_values.items()) + + except IOError: + pass + + return response + + +def post_mockdata_url(service_name, implementation_name, + url, headers, body, + dir_base=dirname(__file__)): + """ + :param service_name: + possible "sws", "pws", "book", "hfs", etc. + :param implementation_name: + possible values: "file", etc. + """ + # Currently this post method does not return a response body + response = MockHTTP() + if body is not None: + if "dispatch" in url: + response.status = 200 + else: + response.status = 201 + response.headers = {"X-Data-Source": service_name + " file mock data", + "Content-Type": headers['Content-Type']} + else: + response.status = 400 + response.data = "Bad Request: no POST body" + return response + + +def put_mockdata_url(service_name, implementation_name, + url, headers, body, + dir_base=dirname(__file__)): + """ + :param service_name: + possible "sws", "pws", "book", "hfs", etc. + :param implementation_name: + possible values: "file", etc. + """ + # Currently this put method does not return a response body + response = MockHTTP() + if body is not None: + response.status = 204 + response.headers = {"X-Data-Source": service_name + " file mock data", + "Content-Type": headers['Content-Type']} + else: + response.status = 400 + response.data = "Bad Request: no POST body" + return response + + +def delete_mockdata_url(service_name, implementation_name, + url, headers, + dir_base=dirname(__file__)): + """ + :param service_name: + possible "sws", "pws", "book", "hfs", etc. + :param implementation_name: + possible values: "file", etc. + """ + # Http response code 204 No Content: + # The server has fulfilled the request but does not need to + # return an entity-body + response = MockHTTP() + response.status = 204 + + return response + + +def convert_to_platform_safe(dir_file_name): + """ + :param dir_file_name: a string to be processed + :return: a string with all the reserved characters replaced + """ + return re.sub('[\?|<>=:*,;+&"@]', '_', dir_file_name) diff --git a/spotseeker_restclient/dao_implementation/spotseeker.py b/spotseeker_restclient/dao_implementation/spotseeker.py new file mode 100644 index 0000000000000000000000000000000000000000..b40364892da394789317fc91fceafc2fc0d4771c --- /dev/null +++ b/spotseeker_restclient/dao_implementation/spotseeker.py @@ -0,0 +1,39 @@ +from importlib import import_module +from spotseeker_restclient.dao_implementation.live import get_live_url +from spotseeker_restclient.dao_implementation.mock import get_mockdata_url +from django.conf import settings + + +class File(object): + def getURL(self, url, headers): + return get_mockdata_url("spotseeker", "file", url, headers) + + +class Live(object): + + def getURL(self, url, headers): + + return get_live_url('GET', + settings.SPOTSEEKER_HOST, + url, headers=headers) + + def putURL(self, url, headers, body): + return get_live_url('PUT', + settings.SPOTSEEKER_HOST, + url, + headers=headers, + body=body) + + def postURL(self, url, headers, body): + return get_live_url('POST', + settings.SPOTSEEKER_HOST, + url, + headers=headers, + body=body) + + def deleteURL(self, url, headers, body): + return get_live_url('DELETE', + settings.SPOTSEEKER_HOST, + url, + headers=headers, + body=body) diff --git a/spotseeker_restclient/exceptions.py b/spotseeker_restclient/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..f6c5c2e0b71fc19b27f0d43a07ad50dc1fcfd43e --- /dev/null +++ b/spotseeker_restclient/exceptions.py @@ -0,0 +1,20 @@ +""" +Contains the custom exceptions used by the restclient. +""" + + +class DataFailureException(Exception): + """ + This exception means there was an error fetching content + in one of the rest clients. You can get the url that failed + with .url, the status of the error with .status, and any + message with .msg + """ + def __init__(self, url, status, msg): + self.url = url + self.status = status + self.msg = msg + + def __str__(self): + return ("Error fetching %s. Status code: %s. Message: %s." % + (self.url, self.status, self.msg)) diff --git a/spotseeker_restclient/mock_http.py b/spotseeker_restclient/mock_http.py new file mode 100644 index 0000000000000000000000000000000000000000..e47cea99840af826da014b11a70260ffbe5094d3 --- /dev/null +++ b/spotseeker_restclient/mock_http.py @@ -0,0 +1,31 @@ +""" +Contains objects used by the non-HTTP DAO implementations +""" + + +class MockHTTP(object): + """ + An alternate object to HTTPResponse, for non-HTTP DAO + implementations to use. Implements the API of HTTPResponse + as needed. + """ + status = 0 + data = "" + headers = {} + + def read(self): + """ + Returns the document body of the request. + """ + return self.data + + def getheader(self, field, default=''): + """ + Returns the HTTP response header field, case insensitively + """ + if self.headers: + for header in self.headers: + if field.lower() == header.lower(): + return self.headers[header] + + return default diff --git a/spotseeker_restclient/models/__init__.py b/spotseeker_restclient/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..df086654b8a12f2b5eb5b37ba68330ed336067fb --- /dev/null +++ b/spotseeker_restclient/models/__init__.py @@ -0,0 +1,44 @@ +from django.db import models +import pickle +from base64 import b64encode, b64decode + + +class CacheEntry(models.Model): + service = models.CharField(max_length=50, db_index=True) + url = models.CharField(max_length=255, unique=True, db_index=True) + status = models.PositiveIntegerField() + header_pickle = models.TextField() + content = models.TextField() + headers = None + + class Meta: + unique_together = ('service', 'url') + + def getHeaders(self): + if self.headers is None: + if self.header_pickle is None: + self.headers = {} + else: + self.headers = pickle.loads(b64decode(self.header_pickle)) + return self.headers + + def setHeaders(self, headers): + self.headers = headers + + def save(self, *args, **kwargs): + pickle_content = "" + if self.headers: + pickle_content = pickle.dumps(self.headers) + else: + pickle_content = pickle.dumps({}) + + self.header_pickle = b64encode(pickle_content) + super(CacheEntry, self).save(*args, **kwargs) + + +class CacheEntryTimed(CacheEntry): + time_saved = models.DateTimeField() + + +class CacheEntryExpires(CacheEntry): + time_expires = models.DateTimeField() diff --git a/spotseeker_restclient/models/spot.py b/spotseeker_restclient/models/spot.py new file mode 100644 index 0000000000000000000000000000000000000000..206602188fadcd4d7bf43c332b50bc89925abc27 --- /dev/null +++ b/spotseeker_restclient/models/spot.py @@ -0,0 +1,97 @@ +from django.db import models + + +class SpotType(models.Model): + """ The type of Spot. + """ + name = models.SlugField(max_length=50) + + +class SpotAvailableHours(models.Model): + """ + The hours a Spot is available, i.e. the open or closed hours for the + building the spot is located in. + """ + + day = models.CharField(max_length=9) + + start_time = models.TimeField() + end_time = models.TimeField() + + +class SpotExtendedInfo(models.Model): + """ + Additional institution-provided metadata about a spot. If providing custom + metadata, you should provide a validator for that data, as well. + """ + key = models.CharField(max_length=50) + value = models.CharField(max_length=255) + + +class SpotImage(models.Model): + """ + An image of a Spot. Multiple images can be associated with a Spot, + and Spot objects have a 'Spot.spotimage_set' method that will return all + SpotImage objects for the Spot. + """ + + image_id = models.IntegerField() + url = models.CharField(max_length=255) + description = models.CharField(max_length=200, blank=True) + display_index = models.PositiveIntegerField(null=True, blank=True) + content_type = models.CharField(max_length=40) + width = models.IntegerField() + height = models.IntegerField() + creation_date = models.DateTimeField() + modification_date = models.DateTimeField() + upload_user = models.CharField(max_length=40) + upload_application = models.CharField(max_length=100) + + +class Spot(models.Model): + """ Represents a place for students to study. + """ + spot_id = models.IntegerField() + name = models.CharField(max_length=100, blank=True) + uri = models.CharField(max_length=255) + thumbnail_root = models.CharField(max_length=255) + latitude = models.DecimalField(max_digits=11, decimal_places=8, null=True) + longitude = models.DecimalField(max_digits=11, decimal_places=8, null=True) + height_from_sea_level = models.DecimalField(max_digits=11, + decimal_places=8, + null=True, + blank=True) + building_name = models.CharField(max_length=100, blank=True) + floor = models.CharField(max_length=50, blank=True) + room_number = models.CharField(max_length=25, blank=True) + building_description = models.CharField(max_length=100, blank=True) + capacity = models.IntegerField(null=True, blank=True) + display_access_restrictions = models.CharField(max_length=200, blank=True) + organization = models.CharField(max_length=50, blank=True) + manager = models.CharField(max_length=50, blank=True) + etag = models.CharField(max_length=40) + last_modified = models.DateTimeField() + external_id = models.CharField(max_length=100, + null=True, + blank=True, + default=None, + unique=True) + + +class SpotItem(models.Model): + item_id = models.IntegerField() + name = models.CharField(max_length=100, blank=True) + category = models.CharField(max_length=255) + subcategory = models.CharField(max_length=255) + + +class ItemImage(models.Model): + image_id = models.IntegerField() + description = models.CharField(max_length=200, blank=True) + display_index = models.PositiveIntegerField(null=True, blank=True) + width = models.IntegerField() + height = models.IntegerField() + content_type = models.CharField(max_length=40) + creation_date = models.DateTimeField(auto_now_add=True) + upload_user = models.CharField(max_length=40) + upload_application = models.CharField(max_length=100) diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings b/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings new file mode 100644 index 0000000000000000000000000000000000000000..3c1aace7bc5b0711993936af8ec8e98addd6622a --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings @@ -0,0 +1 @@ +["", "Alder Hall", "Allen Library (ALB)", "Allen Library (ALB) North", "Allen Library (ALB) South", "Architecture Hall (ARC)", "Art Building (ART)", "Beardslee Building (UWBB)", "Birmingham Block (BB)", "Birmingham Hay and Seed (BHS)", "Bothell Bookstore", "Bothell Building UW1", "Bothell Building UW2", "Bothell Library", "Burke Memorial-Washington State Museum (BMM)", "Business Hall (BHQ)", "Cherry Parkes (CP)", "Computer Science and Engineering Building (CSE)", "Discovery Hall (DISC)", "Dougan (DOU)", "Electrical Engineering Building (EEB)", "Engineering Library (ELB)", "Fishery Sciences (FSH)", "Garretson Woodruff & Pratt (GWP)", "Gould Hall (GLD)", "Gowen Hall (GWN)", "HUB (Husky Union Building)", "Haggett Hall (HGT)", "Hitchcock Hall (HCK)", "Husky Hall (HH)", "Husky Village", "Hutchinson Hall (HUT)", "Intramural Activities Building (IMA)", "Joy", "Library", "Longshoremen's Hall (LSH)", "Magnuson Health Sciences Center A (HSA)", "Magnuson Health Sciences Center C (HSC)", "Magnuson Health Sciences Center D (HSD)", "Magnuson Health Sciences Center E (HSE)", "Magnuson Health Sciences Center I (HSI)", "Magnuson Health Sciences Center T (HST)", "Mary Gates Hall (MGH)", "Mattress Factory (MAT)", "McCarty Hall (MCC)", "McMahon Hall (MCM)", "Miller Hall (MLR)", "Molecular Engineering & Sciences (MOL)", "Music Building (MUS)", "Odegaard Undergraduate Library (OUGL)", "Paccar Hall (PCAR)", "Padelford Hall (PDL)", "Physics/Astronomy Building (PAB) Tower", "Pinkerton (PNK)", "Poplar Hall (UTO)", "Science Building (SCI)", "Smith Hall (SMI)", "Snoqualmie (SNO)", "Social Work/Speech & Hearing Sciences Building (SWS)", "South Campus Center (SOCC)", "Suzzallo Library (SUZ)", "Tioga Library Building (TLB)", "Walsh Gardner (WG)", "West Coast Grocery (WCG)", "William H. Foege Genome Sciences (GNOM)", "William H. Gates Hall (LAW)", "William Phillip Hall (WPH)"] \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings?extended_info:campus=seattle b/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings?extended_info:campus=seattle new file mode 100644 index 0000000000000000000000000000000000000000..2627dcc77a5359d5a49c4e16bc989c142cb5a3fc --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings?extended_info:campus=seattle @@ -0,0 +1,45 @@ +[ + "", + "Alder Hall", + "Allen Library (ALB)", + "Allen Library (ALB) North", + "Allen Library (ALB) South", + "Architecture Hall (ARC)", + "Art Building (ART)", + "Burke Memorial-Washington State Museum (BMM)", + "Business Hall (BHQ)", + "Computer Science and Engineering Building (CSE)", + "Electrical Engineering Building (EEB)", + "Engineering Library (ELB)", + "Fishery Sciences (FSH)", + "Gould Hall (GLD)", + "Gowen Hall (GWN)", + "HUB (Husky Union Building)", + "Haggett Hall (HGT)", + "Hitchcock Hall (HCK)", + "Hutchinson Hall (HUT)", + "Intramural Activities Building (IMA)", + "Magnuson Health Sciences Center A (HSA)", + "Magnuson Health Sciences Center C (HSC)", + "Magnuson Health Sciences Center D (HSD)", + "Magnuson Health Sciences Center E (HSE)", + "Magnuson Health Sciences Center I (HSI)", + "Magnuson Health Sciences Center T (HST)", + "Mary Gates Hall (MGH)", + "McCarty Hall (MCC)", + "McMahon Hall (MCM)", + "Miller Hall (MLR)", + "Molecular Engineering & Sciences (MOL)", + "Music Building (MUS)", + "Odegaard Undergraduate Library (OUGL)", + "Paccar Hall (PCAR)", + "Padelford Hall (PDL)", + "Physics/Astronomy Building (PAB) Tower", + "Poplar Hall (UTO)", + "Smith Hall (SMI)", + "Social Work/Speech & Hearing Sciences Building (SWS)", + "South Campus Center (SOCC)", + "Suzzallo Library (SUZ)", + "William H. Foege Genome Sciences (GNOM)", + "William H. Gates Hall (LAW)" +] diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings_extended_info_app_type_food b/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings_extended_info_app_type_food new file mode 100644 index 0000000000000000000000000000000000000000..3c1aace7bc5b0711993936af8ec8e98addd6622a --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/buildings_extended_info_app_type_food @@ -0,0 +1 @@ +["", "Alder Hall", "Allen Library (ALB)", "Allen Library (ALB) North", "Allen Library (ALB) South", "Architecture Hall (ARC)", "Art Building (ART)", "Beardslee Building (UWBB)", "Birmingham Block (BB)", "Birmingham Hay and Seed (BHS)", "Bothell Bookstore", "Bothell Building UW1", "Bothell Building UW2", "Bothell Library", "Burke Memorial-Washington State Museum (BMM)", "Business Hall (BHQ)", "Cherry Parkes (CP)", "Computer Science and Engineering Building (CSE)", "Discovery Hall (DISC)", "Dougan (DOU)", "Electrical Engineering Building (EEB)", "Engineering Library (ELB)", "Fishery Sciences (FSH)", "Garretson Woodruff & Pratt (GWP)", "Gould Hall (GLD)", "Gowen Hall (GWN)", "HUB (Husky Union Building)", "Haggett Hall (HGT)", "Hitchcock Hall (HCK)", "Husky Hall (HH)", "Husky Village", "Hutchinson Hall (HUT)", "Intramural Activities Building (IMA)", "Joy", "Library", "Longshoremen's Hall (LSH)", "Magnuson Health Sciences Center A (HSA)", "Magnuson Health Sciences Center C (HSC)", "Magnuson Health Sciences Center D (HSD)", "Magnuson Health Sciences Center E (HSE)", "Magnuson Health Sciences Center I (HSI)", "Magnuson Health Sciences Center T (HST)", "Mary Gates Hall (MGH)", "Mattress Factory (MAT)", "McCarty Hall (MCC)", "McMahon Hall (MCM)", "Miller Hall (MLR)", "Molecular Engineering & Sciences (MOL)", "Music Building (MUS)", "Odegaard Undergraduate Library (OUGL)", "Paccar Hall (PCAR)", "Padelford Hall (PDL)", "Physics/Astronomy Building (PAB) Tower", "Pinkerton (PNK)", "Poplar Hall (UTO)", "Science Building (SCI)", "Smith Hall (SMI)", "Snoqualmie (SNO)", "Social Work/Speech & Hearing Sciences Building (SWS)", "South Campus Center (SOCC)", "Suzzallo Library (SUZ)", "Tioga Library Building (TLB)", "Walsh Gardner (WG)", "West Coast Grocery (WCG)", "William H. Foege Genome Sciences (GNOM)", "William H. Gates Hall (LAW)", "William Phillip Hall (WPH)"] \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/1 b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/1 new file mode 100644 index 0000000000000000000000000000000000000000..bc9990c874e728f336f28bab2abc0be2497bc7bf --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/1 @@ -0,0 +1,104 @@ +{ + "capacity": 15, + "name": "Banh & Naan, Husky Den", + "external_id": null, + "extended_info": { + "s_pay_cash": "true", + "s_phone": "206-685-4950", + "s_pay_husky": "true", + "app_type": "food", + "s_pay_visa": "true", + "s_pay_mastercard": "true", + "s_food_entrees": "true", + "s_pay_dining": "true", + "location_description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_food_sandwiches": "true", + "s_cuisine_vietnamese": "true", + "s_cuisine_new_and_unmapped_type": "true", + "s_website_url": "https://www.hfs.washington.edu/dining/Default.aspx?id=3620#gsc.tab=0", + "owner": "Housing and Food Services (HFS)", + "campus": "seattle", + "s_cuisine_indian": "true", + "s_menu_url": "https://www.hfs.washington.edu/uploadedFiles/Dining/Dining_Locations/Bahnwebmenu%202014.pdf" + }, + "uri": "/api/v1/spot/1", + "available_hours": { + "monday": [ + ["10:30", "14:30"], + ["15:30", "18:30"] + ], + "tuesday": [ + ["8:30", "9:30"], + ["10:30", "14:30"] + ], + "friday": [ + ["10:30", "15:30"], + ["16:00", "16:30"], + ["17:30", "22:30"] + ], + "wednesday": [ + ["10:30", "14:30"] + ], + "thursday": [ + ["10:30", "14:30"] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "last_modified": "2015-12-15T22:35:41.699054+00:00", + "etag": "f573702e9e71197ff3eaa3c6357845d614580930", + "type": ["food_court"], + "images": [], + "organization": "", + "display_access_restrictions": "", + "id": 1, + "location": { + "floor": "Ground Floor", + "height_from_sea_level": null, + "room_number": "Husky Den", + "longitude": -122.3051094, + "latitude": 47.6552915, + "building_name": "Husky Union Building (HUB)" + }, + "items": [ + { + "id": 796, + "name": "C-19074", + "category": "Digital Camera", + "subcategory": "", + "extended_info": { + "make_model": "Canon Powershot SD1100 IS", + "customer_type": "UW Student", + "auto_item_status": "active" + }, + "images": [ + { + "id": 1, + "url": "/api/v1/spot/3/image/1", + "description": "An Image", + "display_index": 0, + "content-type": "image/jpeg", + "width": 400, + "height": 800, + "creation_date": "6-12-2013", + "modification_date": "6-12-2013", + "upload_user": "acatest", + "upload_application": "manager", + "thumbnail_root": "/asd/" + } + ] + }, + { + "id": 792, + "name": "C-asd1", + "category": "Digital Camera", + "subcategory": "", + "extended_info": { + "make_model": "Canon Powershot SD1100 IS", + "customer_type": "UW Student", + "auto_item_status": "active" + } + } + ] +} diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/123 b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/123 new file mode 100644 index 0000000000000000000000000000000000000000..be7a49ad18eb271c01ad4ae420371d14cb4a4511 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/123 @@ -0,0 +1,53 @@ +{ + "id": "123", + "uri": "/api/v1/spot/123", + "name": "Test Spot", + "type": ["study_room", "cafe"], + "meta_type": ["study", "food"], + "location": { + "longitude": 1.34, + "latitude": 3.60, + "height_from_sea_level": 0.10, + "building_name": "Test Building", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/123/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/123/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "14:00"] ], + "tuesday": [ ["11:00", "14:00" ] ], + "wednesday": [ ["11:00", "14:00"] ], + "thursday": [ ["11:00", "14:00"] ], + "friday": [ ["11:00", "14:00"] ], + "saturday": [], + "sunday": [ ["11:00", "14:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "whiteboards": true, + "field2": 0, + "field3": 0.00 + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +} \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/2 b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/2 new file mode 100644 index 0000000000000000000000000000000000000000..6df765454a4cb749e6f87e33045907b1133f4699 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/2 @@ -0,0 +1,105 @@ +{ + "id": "2", + "uri": "/api/v1/spot/2", + "name": "It's A Market", + "type": ["market"], + "meta_type": ["food"], + "location": { + "longitude": -122.3085307, + "latitude": 47.6558366, + "height_from_sea_level": 0.10, + "building_name": "The Market", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/2/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/2/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "21:00"] ], + "tuesday": [ ["11:00", "21:00" ] ], + "wednesday": [ ["11:00", "21:00"] ], + "thursday": [ ["11:00", "21:00"] ], + "friday": [ ["11:00", "21:00"] ], + "saturday": [], + "sunday": [ ["11:00", "21:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : false, + "s_alert_notes" : "", + + "s_has_reservation" : false, + "s_reservation_notes" : "", + + "s_has_coupon" : false, + "s_coupon_expiration" : "", + "s_coupon_url" : "", + + "s_cuisine_american" : false, + "s_cuisine_bbq" : false, + "s_cuisine_chinese" : false, + "s_cuisine_hawaiian" : true, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : true, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : false, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : false, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : false, + "s_food_espresso" : true, + "s_food_pasta" : false, + "s_food_pizza" : true, + "s_food_salads" : false, + "s_food_sandwiches" : true, + "s_food_smoothies" : true, + "s_food_sushi" : true, + "s_food_tacos" : true, + + "s_pay_cash" : false, + "s_pay_visa" : false, + "s_pay_mastercard" : false, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : false, + "s_open_lunch" : true, + "s_open_dinner" : true, + "s_open_late_night" : true + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +} \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/3 b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/3 new file mode 100644 index 0000000000000000000000000000000000000000..434d939c3b22d2170a0b362cb1b892a959079840 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/3 @@ -0,0 +1,105 @@ +{ + "id": "3", + "uri": "/api/v1/spot/3", + "name": "Truck of Food", + "type": ["food_truck"], + "meta_type": ["food"], + "location": { + "longitude": -122.3080857, + "latitude": 47.6539295, + "height_from_sea_level": 0.10, + "building_name": "Test Building", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/3/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/3/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "14:00"] ], + "tuesday": [ ["11:00", "14:00" ] ], + "wednesday": [ ["11:00", "14:00"] ], + "thursday": [ ["11:00", "14:00"] ], + "friday": [ ["11:00", "14:00"] ], + "saturday": [], + "sunday": [ ["11:00", "14:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "Open to all", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : true, + "s_alert_notes" : "It's a fire sale", + + "s_has_reservation" : true, + "s_reservation_notes" : "", + + "s_has_coupon" : true, + "s_coupon_expiration" : "never", + "s_coupon_url" : "www.uw.com/food/deals", + + "s_cuisine_american" : true, + "s_cuisine_bbq" : true, + "s_cuisine_chinese" : false, + "s_cuisine_hawaiian" : false, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : false, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : true, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : false, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : false, + "s_food_espresso" : false, + "s_food_pasta" : false, + "s_food_pizza" : false, + "s_food_salads" : false, + "s_food_sandwiches" : true, + "s_food_smoothies" : false, + "s_food_sushi" : false, + "s_food_tacos" : false, + + "s_pay_cash" : true, + "s_pay_visa" : true, + "s_pay_mastercard" : true, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : false, + "s_open_lunch" : true, + "s_open_dinner" : false, + "s_open_late_night" : false + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +} \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/4 b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/4 new file mode 100644 index 0000000000000000000000000000000000000000..6a825df4f59f505a195d3a6904e254288c4d4e64 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/4 @@ -0,0 +1,105 @@ +{ + "id": "4", + "uri": "/api/v1/spot/3", + "name": "By George", + "type": ["food_truck"], + "meta_type": ["cafeteria"], + "location": { + "longitude": -122.3125347, + "latitude": 47.656462, + "height_from_sea_level": 0.10, + "building_name": "Odegaard Undergraduate Library", + "floor": 0, + "room_number": "456", + "description": "This is in the bottom floor of the OUGL." + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/4/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/4/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["09:00", "23:59" ] ], + "tuesday": [ ["00:00", "02:00" ], ["07:00", "23:59"] ], + "wednesday": [ ["00:00", "02:00"], ["07:00", "19:00"] ], + "thursday": [ ["07:00", "12:00"], ["13:00", "19:00"] ], + "friday": [ ["11:00", "23:59"] ], + "saturday": [ ["00:00", "02:00"] ], + "sunday": [ ["09:00", "23:59"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "Open to all", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : false, + "s_alert_notes" : "It's a fire sale", + + "s_has_reservation" : false, + "s_reservation_notes" : "", + + "s_has_coupon" : true, + "s_coupon_expiration" : "never", + "s_coupon_url" : "www.uw.com/food/deals", + + "s_cuisine_american" : true, + "s_cuisine_bbq" : true, + "s_cuisine_chinese" : true, + "s_cuisine_hawaiian" : false, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : false, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : false, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : true, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : true, + "s_food_espresso" : true, + "s_food_pasta" : false, + "s_food_pizza" : true, + "s_food_salads" : true, + "s_food_sandwiches" : true, + "s_food_smoothies" : true, + "s_food_sushi" : true, + "s_food_tacos" : false, + + "s_pay_cash" : true, + "s_pay_visa" : true, + "s_pay_mastercard" : true, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : true, + "s_open_lunch" : true, + "s_open_dinner" : true, + "s_open_late_night" : true + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +} diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/5 b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/5 new file mode 100644 index 0000000000000000000000000000000000000000..d2a58d146ce248ee198d862d8b6b9a8ca9de73cb --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/5 @@ -0,0 +1,105 @@ +{ + "id": "5", + "uri": "/api/v1/spot/3", + "name": "By George", + "type": ["food_truck"], + "meta_type": ["cafeteria"], + "location": { + "longitude": -122.3125347, + "latitude": 47.656462, + "height_from_sea_level": 0.10, + "building_name": "Odegaard Undergraduate Library", + "floor": 0, + "room_number": "456", + "description": "This is in the bottom floor of the OUGL." + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/5/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/4/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["02:00", "05:00" ] ], + "tuesday": [ ["05:00", "11:00" ] ], + "wednesday": [ ["11:00", "15:00"] ], + "thursday": [ ["15:00", "22:00"]], + "friday": [ ["22:00", "23:59"] ], + "saturday": [], + "sunday": [] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "Open to all", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : false, + "s_alert_notes" : "It's a fire sale", + + "s_has_reservation" : false, + "s_reservation_notes" : "", + + "s_has_coupon" : true, + "s_coupon_expiration" : "never", + "s_coupon_url" : "www.uw.com/food/deals", + + "s_cuisine_american" : true, + "s_cuisine_bbq" : true, + "s_cuisine_chinese" : true, + "s_cuisine_hawaiian" : false, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : false, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : false, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : true, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : true, + "s_food_espresso" : true, + "s_food_pasta" : false, + "s_food_pizza" : true, + "s_food_salads" : true, + "s_food_sandwiches" : true, + "s_food_smoothies" : true, + "s_food_sushi" : true, + "s_food_tacos" : false, + + "s_pay_cash" : true, + "s_pay_visa" : true, + "s_pay_mastercard" : true, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : true, + "s_open_lunch" : true, + "s_open_dinner" : true, + "s_open_late_night" : true + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +} diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/all b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/all new file mode 100644 index 0000000000000000000000000000000000000000..85fa5ba6bf2357b3305fea0fc8a3c712fd47b05e --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot/all @@ -0,0 +1,236 @@ +[{ + "capacity": 15, + "name": "Banh & Naan, Husky Den", + "external_id": null, + "extended_info": { + "s_pay_cash": "true", + "s_phone": "206-685-4950", + "s_pay_husky": "true", + "app_type": "food", + "s_pay_visa": "true", + "s_pay_mastercard": "true", + "s_food_entrees": "true", + "s_pay_dining": "true", + "location_description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_food_sandwiches": "true", + "s_cuisine_vietnamese": "true", + "s_website_url": "https://www.hfs.washington.edu/dining/Default.aspx?id=3620#gsc.tab=0", + "owner": "Housing and Food Services (HFS)", + "campus": "seattle", + "s_cuisine_indian": "true", + "s_menu_url": "https://www.hfs.washington.edu/uploadedFiles/Dining/Dining_Locations/Bahnwebmenu%202014.pdf" + }, + "uri": "/api/v1/spot/1", + "available_hours": { + "monday": [ + ["10:30", "14:30"], + ["15:30", "18:30"] + ], + "tuesday": [ + ["8:30", "9:30"], + ["10:30", "14:30"] + ], + "friday": [ + ["10:30", "22:30"] + ], + "wednesday": [ + ["10:30", "14:30"] + ], + "thursday": [ + ["10:30", "14:30"] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "last_modified": "2015-12-15T22:35:41.699054+00:00", + "etag": "f573702e9e71197ff3eaa3c6357845d614580930", + "type": ["food_court"], + "images": [], + "organization": "", + "display_access_restrictions": "", + "id": 1, + "location": { + "floor": "Ground Floor", + "height_from_sea_level": null, + "room_number": "Husky Den", + "longitude": -122.3051094, + "latitude": 47.6552915, + "building_name": "Husky Union Building (HUB)" + } +}, { + "id": "2", + "uri": "/api/v1/spot/2", + "name": "This is a study spot", + "type": ["market"], + "location": { + "longitude": -122.3085307, + "latitude": 47.6558366, + "height_from_sea_level": 0.10, + "building_name": "The Market", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [{ + "id": "1", + "url": "/api/v1/spot/2/image/1", + "content-type": "image/jpeg", + "width": 0, + "height": 0, + "creation_date": "Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date": "Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user": "user name", + "upload_application": "application name", + "thumbnail_root": "/api/v1/spot/2/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + }], + "available_hours": { + "monday": [ + ["00:00", "10:00"], + ["11:00", "21:00"] + ], + "tuesday": [ + ["11:00", "21:00"] + ], + "wednesday": [ + ["11:00", "21:00"] + ], + "thursday": [ + ["11:00", "21:00"] + ], + "friday": [ + ["11:00", "21:00"] + ], + "saturday": [], + "sunday": [ + ["11:00", "21:00"] + ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "campus": "seattle" + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +}, { + "id": "3", + "uri": "/api/v1/spot/3", + "name": "Truck of Food", + "type": ["food_truck"], + "meta_type": ["food"], + "location": { + "longitude": -122.3080857, + "latitude": 47.6539295, + "height_from_sea_level": 0.10, + "building_name": "Test Building", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [{ + "id": "1", + "url": "/api/v1/spot/3/image/1", + "content-type": "image/jpeg", + "width": 0, + "height": 0, + "creation_date": "Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date": "Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user": "user name", + "upload_application": "application name", + "thumbnail_root": "/api/v1/spot/3/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + }], + "available_hours": { + "monday": [ + ["00:00", "10:00"], + ["11:00", "14:00"] + ], + "tuesday": [ + ["11:00", "14:00"] + ], + "wednesday": [ + ["11:00", "14:00"] + ], + "thursday": [ + ["11:00", "14:00"] + ], + "friday": [ + ["11:00", "14:00"] + ], + "saturday": [], + "sunday": [ + ["11:00", "14:00"] + ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type": "food", + "campus": "seattle", + "hours_notes": "", + "access_notes": "Open to all", + + + "s_menu_url": "www.yelp.com", + "s_website_url": "www.uw.edu/food", + "s_contact_phone": "2066164000", + + "s_has_alert": true, + "s_alert_notes": "It's a fire sale", + + "s_has_reservation": true, + "s_reservation_notes": "", + + "s_has_coupon": true, + "s_coupon_expiration": "never", + "s_coupon_url": "www.uw.com/food/deals", + + "s_cuisine_american": true, + "s_cuisine_bbq": true, + "s_cuisine_chinese": false, + "s_cuisine_hawaiian": false, + "s_cuisine_indian": false, + "s_cuisine_italian": false, + "s_cuisine_japanese": false, + "s_cuisine_korean": false, + "s_cuisine_mexican": true, + "s_cuisine_vietnamese": false, + + "s_cuisine_light_lunch": false, + + "s_food_appetizers": false, + "s_food_burgers": false, + "s_food_entrees": false, + "s_food_espresso": false, + "s_food_pasta": false, + "s_food_pizza": false, + "s_food_salads": false, + "s_food_sandwiches": true, + "s_food_smoothies": false, + "s_food_sushi": false, + "s_food_tacos": false, + + "s_pay_cash": true, + "s_pay_visa": true, + "s_pay_mastercard": true, + "s_pay_husky": true, + "s_pay_dining": true, + + "s_open_breakfast": false, + "s_open_lunch": true, + "s_open_dinner": false, + "s_open_late_night": false + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +}] \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?extended_info%3Aor_group=s_food_espresso&limit=5&open=True¢er_latitude=47.653717¢er_longitude=-122.307755&distance=1000&extended_info%3Aapp_type=food b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?extended_info%3Aor_group=s_food_espresso&limit=5&open=True¢er_latitude=47.653717¢er_longitude=-122.307755&distance=1000&extended_info%3Aapp_type=food new file mode 100644 index 0000000000000000000000000000000000000000..96443c2499ede7bb74fbbcd4e3235aad09690314 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?extended_info%3Aor_group=s_food_espresso&limit=5&open=True¢er_latitude=47.653717¢er_longitude=-122.307755&distance=1000&extended_info%3Aapp_type=food @@ -0,0 +1,212 @@ +[ +{ + "id": "2", + "uri": "/api/v1/spot/2", + "name": "It's A Market", + "type": ["market"], + "meta_type": ["food"], + "location": { + "longitude": -122.3085307, + "latitude": 47.6558366, + "height_from_sea_level": 0.10, + "building_name": "The Market", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/2/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/2/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "21:00"] ], + "tuesday": [ ["11:00", "21:00" ] ], + "wednesday": [ ["11:00", "21:00"] ], + "thursday": [ ["11:00", "21:00"] ], + "friday": [ ["11:00", "21:00"] ], + "saturday": [], + "sunday": [ ["11:00", "21:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : false, + "s_alert_notes" : "", + + "s_has_reservation" : false, + "s_reservation_notes" : "", + + "s_has_coupon" : false, + "s_coupon_expiration" : "", + "s_coupon_url" : "", + + "s_cuisine_american" : false, + "s_cuisine_bbq" : false, + "s_cuisine_chinese" : false, + "s_cuisine_hawaiian" : true, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : true, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : false, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : false, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : false, + "s_food_espresso" : true, + "s_food_pasta" : false, + "s_food_pizza" : true, + "s_food_salads" : false, + "s_food_sandwiches" : true, + "s_food_smoothies" : true, + "s_food_sushi" : true, + "s_food_tacos" : true, + + "s_pay_cash" : false, + "s_pay_visa" : false, + "s_pay_mastercard" : false, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : false, + "s_open_lunch" : true, + "s_open_dinner" : true, + "s_open_late_night" : true + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +}, +{ + "id": "3", + "uri": "/api/v1/spot/3", + "name": "Truck of Food", + "type": ["food_truck"], + "meta_type": ["food"], + "location": { + "longitude": -122.3080857, + "latitude": 47.6539295, + "height_from_sea_level": 0.10, + "building_name": "Test Building", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/3/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/3/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "14:00"] ], + "tuesday": [ ["11:00", "14:00" ] ], + "wednesday": [ ["11:00", "14:00"] ], + "thursday": [ ["11:00", "14:00"] ], + "friday": [ ["11:00", "14:00"] ], + "saturday": [], + "sunday": [ ["11:00", "14:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "Open to all", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : true, + "s_alert_notes" : "It's a fire sale", + + "s_has_reservation" : true, + "s_reservation_notes" : "", + + "s_has_coupon" : true, + "s_coupon_expiration" : "never", + "s_coupon_url" : "www.uw.com/food/deals", + + "s_cuisine_american" : true, + "s_cuisine_bbq" : true, + "s_cuisine_chinese" : false, + "s_cuisine_hawaiian" : false, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : false, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : true, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : false, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : false, + "s_food_espresso" : true, + "s_food_pasta" : false, + "s_food_pizza" : false, + "s_food_salads" : false, + "s_food_sandwiches" : true, + "s_food_smoothies" : false, + "s_food_sushi" : false, + "s_food_tacos" : false, + + "s_pay_cash" : true, + "s_pay_visa" : true, + "s_pay_mastercard" : true, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : false, + "s_open_lunch" : true, + "s_open_dinner" : false, + "s_open_late_night" : false + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +} +] \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?extended_info%3As_food_pasta=True&type=food_court&extended_info%3Aapp_type=food b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?extended_info%3As_food_pasta=True&type=food_court&extended_info%3Aapp_type=food new file mode 100644 index 0000000000000000000000000000000000000000..a5f3fd9097a2d63540df0ed95e38383c7ed5e0df --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?extended_info%3As_food_pasta=True&type=food_court&extended_info%3Aapp_type=food @@ -0,0 +1,107 @@ +[ + { + "id": "2", + "uri": "/api/v1/spot/2", + "name": "It's A Market", + "type": ["market"], + "meta_type": ["food"], + "location": { + "longitude": -122.3085307, + "latitude": 47.6558366, + "height_from_sea_level": 0.10, + "building_name": "The Market", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/2/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/2/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "21:00"] ], + "tuesday": [ ["11:00", "21:00" ] ], + "wednesday": [ ["11:00", "21:00"] ], + "thursday": [ ["11:00", "21:00"] ], + "friday": [ ["11:00", "21:00"] ], + "saturday": [], + "sunday": [ ["11:00", "21:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : false, + "s_alert_notes" : "", + + "s_has_reservation" : false, + "s_reservation_notes" : "", + + "s_has_coupon" : false, + "s_coupon_expiration" : "", + "s_coupon_url" : "", + + "s_cuisine_american" : false, + "s_cuisine_bbq" : false, + "s_cuisine_chinese" : false, + "s_cuisine_hawaiian" : true, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : true, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : false, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : false, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : false, + "s_food_espresso" : true, + "s_food_pasta" : false, + "s_food_pizza" : true, + "s_food_salads" : false, + "s_food_sandwiches" : true, + "s_food_smoothies" : true, + "s_food_sushi" : true, + "s_food_tacos" : true, + + "s_pay_cash" : false, + "s_pay_visa" : false, + "s_pay_mastercard" : false, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : false, + "s_open_lunch" : true, + "s_open_dinner" : true, + "s_open_late_night" : true + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" + } +] \ No newline at end of file diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?has_items=true b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?has_items=true new file mode 100644 index 0000000000000000000000000000000000000000..cfa8c6324673da384f79a98306b35382bace6097 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?has_items=true @@ -0,0 +1,88 @@ +[{ + "capacity": 15, + "name": "Banh & Naan, Husky Den", + "external_id": null, + "extended_info": { + "s_pay_cash": "true", + "s_phone": "206-685-4950", + "s_pay_husky": "true", + "app_type": "food", + "s_pay_visa": "true", + "s_pay_mastercard": "true", + "s_food_entrees": "true", + "s_pay_dining": "true", + "location_description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_food_sandwiches": "true", + "s_cuisine_vietnamese": "true", + "s_cuisine_new_and_unmapped_type": "true", + "s_website_url": "https://www.hfs.washington.edu/dining/Default.aspx?id=3620#gsc.tab=0", + "owner": "Housing and Food Services (HFS)", + "campus": "seattle", + "s_cuisine_indian": "true", + "s_menu_url": "https://www.hfs.washington.edu/uploadedFiles/Dining/Dining_Locations/Bahnwebmenu%202014.pdf" + }, + "uri": "/api/v1/spot/1", + "available_hours": { + "monday": [ + ["10:30", "14:30"], + ["15:30", "18:30"] + ], + "tuesday": [ + ["8:30", "9:30"], + ["10:30", "14:30"] + ], + "friday": [ + ["10:30", "15:30"], + ["16:00", "16:30"], + ["17:30", "22:30"] + ], + "wednesday": [ + ["10:30", "14:30"] + ], + "thursday": [ + ["10:30", "14:30"] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "last_modified": "2015-12-15T22:35:41.699054+00:00", + "etag": "f573702e9e71197ff3eaa3c6357845d614580930", + "type": ["food_court"], + "images": [], + "organization": "", + "display_access_restrictions": "", + "id": 1, + "location": { + "floor": "Ground Floor", + "height_from_sea_level": null, + "room_number": "Husky Den", + "longitude": -122.3051094, + "latitude": 47.6552915, + "building_name": "Husky Union Building (HUB)" + }, + "items": [ + { + "id": 796, + "name": "C-19074", + "category": "Digital Camera", + "subcategory": "", + "extended_info": { + "make_model": "Canon Powershot SD1100 IS", + "customer_type": "UW Student", + "auto_item_status": "active" + } + }, + { + "id": 792, + "name": "C-asd1", + "category": "Digital Camera", + "subcategory": "", + "extended_info": { + "make_model": "Canon Powershot SD1100 IS", + "customer_type": "UW Student", + "auto_item_status": "active" + } + } + ] +}] diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?item%3Aid=796 b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?item%3Aid=796 new file mode 100644 index 0000000000000000000000000000000000000000..cfa8c6324673da384f79a98306b35382bace6097 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?item%3Aid=796 @@ -0,0 +1,88 @@ +[{ + "capacity": 15, + "name": "Banh & Naan, Husky Den", + "external_id": null, + "extended_info": { + "s_pay_cash": "true", + "s_phone": "206-685-4950", + "s_pay_husky": "true", + "app_type": "food", + "s_pay_visa": "true", + "s_pay_mastercard": "true", + "s_food_entrees": "true", + "s_pay_dining": "true", + "location_description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_food_sandwiches": "true", + "s_cuisine_vietnamese": "true", + "s_cuisine_new_and_unmapped_type": "true", + "s_website_url": "https://www.hfs.washington.edu/dining/Default.aspx?id=3620#gsc.tab=0", + "owner": "Housing and Food Services (HFS)", + "campus": "seattle", + "s_cuisine_indian": "true", + "s_menu_url": "https://www.hfs.washington.edu/uploadedFiles/Dining/Dining_Locations/Bahnwebmenu%202014.pdf" + }, + "uri": "/api/v1/spot/1", + "available_hours": { + "monday": [ + ["10:30", "14:30"], + ["15:30", "18:30"] + ], + "tuesday": [ + ["8:30", "9:30"], + ["10:30", "14:30"] + ], + "friday": [ + ["10:30", "15:30"], + ["16:00", "16:30"], + ["17:30", "22:30"] + ], + "wednesday": [ + ["10:30", "14:30"] + ], + "thursday": [ + ["10:30", "14:30"] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "last_modified": "2015-12-15T22:35:41.699054+00:00", + "etag": "f573702e9e71197ff3eaa3c6357845d614580930", + "type": ["food_court"], + "images": [], + "organization": "", + "display_access_restrictions": "", + "id": 1, + "location": { + "floor": "Ground Floor", + "height_from_sea_level": null, + "room_number": "Husky Den", + "longitude": -122.3051094, + "latitude": 47.6552915, + "building_name": "Husky Union Building (HUB)" + }, + "items": [ + { + "id": 796, + "name": "C-19074", + "category": "Digital Camera", + "subcategory": "", + "extended_info": { + "make_model": "Canon Powershot SD1100 IS", + "customer_type": "UW Student", + "auto_item_status": "active" + } + }, + { + "id": 792, + "name": "C-asd1", + "category": "Digital Camera", + "subcategory": "", + "extended_info": { + "make_model": "Canon Powershot SD1100 IS", + "customer_type": "UW Student", + "auto_item_status": "active" + } + } + ] +}] diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=0&extended_info:app_type=tech b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=0&extended_info:app_type=tech new file mode 100644 index 0000000000000000000000000000000000000000..8137975e4b496739602fb8f011946019986ce6a4 --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=0&extended_info:app_type=tech @@ -0,0 +1,2310 @@ +[ + { + "capacity": null, + "name": "STF Checkout - Health Sciences", + "display_access_restrictions": "", + "extended_info": { + "owner": "cte", + "app_type": "tech", + "campus": "seattle" + }, + "uri": "/api/v1/spot/5258", + "available_hours": { + "monday": [ + [ + "08:00", + "17:00" + ] + ], + "tuesday": [ + [ + "08:00", + "17:00" + ] + ], + "friday": [ + [ + "08:00", + "17:00" + ] + ], + "wednesday": [ + [ + "08:00", + "17:00" + ] + ], + "thursday": [ + [ + "08:00", + "17:00" + ] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "etag": "57dfacda8771c9078c34b8fa8be2cd9ffbed370c", + "location": { + "floor": "1st Floor", + "height_from_sea_level": null, + "room_number": "I-146", + "longitude": -122.308847, + "latitude": 47.650663, + "building_name": "Magnuson Health Sciences Center I (HSI)" + }, + "last_modified": "2016-08-24T21:17:10+00:00", + "items": [ + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "WH10LS30K", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "LG", + "i_checkout_period": "14.0" + }, + "subcategory": "Blu-ray Burner", + "id": 18, + "name": "LG Blu-ray Burner" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "84+ Silver Edition", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "TI", + "i_checkout_period": "31.0" + }, + "subcategory": "Calculator", + "id": 19, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "CP-WX3014WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "31.0" + }, + "subcategory": "Data Projector", + "id": 20, + "name": "Hitachi CP-WX3014N" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "CP-WX3015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "31.0" + }, + "subcategory": "Data Projector", + "id": 21, + "name": "Hitachi CP-WX3015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "CPX4015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "14.0" + }, + "subcategory": "Data Projector", + "id": 22, + "name": "Hitachi CPX4015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Digital Rebel T2i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "31.0" + }, + "subcategory": "Digital Camera", + "id": 23, + "name": "Digital Rebel T2i" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Digital Rebel T2i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 24, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T2i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 25, + "name": "T2i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Digital Rebel T5i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 26, + "name": "T5i Full kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Digital Rebel T5i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 27, + "name": "T5i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T6i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 28, + "name": "T6i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "EOS 70D Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 29, + "name": "Canon EOS 70D" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "PowerShot ELPH 320 HS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 30, + "name": "Canon PowerShot 320 HS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "9", + "i_model": "PowerShot SD1200 IS (Full Quarter)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "50.0" + }, + "subcategory": "Digital Camera", + "id": 31, + "name": "PowerShot SD1200 IS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "0", + "i_model": "GL-2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 32, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "HDMI VIXIA HFS21", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Video Camera", + "id": 33, + "name": "HDMI VIXIA HFS21" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "XA10", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 34, + "name": "Canon XA10 Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GoPro Hero3+", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "GoPro", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 35, + "name": "GoPro Hero3+" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "3", + "i_model": "AG-HMC150 HD", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Panasonic", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 36, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Macro Ring Lite MR-14EX", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Macro Ring Lite Flash", + "id": 37, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "4", + "i_model": "ShutterBoss RC-C1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Vello", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - SLR Remote", + "id": 38, + "name": "SLR Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "35", + "i_model": "Macbook Pro 2011", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "31.0" + }, + "subcategory": "Laptop Computer", + "id": 39, + "name": "Macbook Pro 2011" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "26", + "i_model": "Macbook Pro 2013", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "14.0" + }, + "subcategory": "Laptop Computer", + "id": 40, + "name": "Macbook Pro 2013" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Macbook Pro 2014", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "10.0" + }, + "subcategory": "Laptop Computer", + "id": 41, + "name": "Macbook Pro 2014" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Macbook Pro 2015", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 42, + "name": "Macbook Pro 2015" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Inspiron 15z Ultrabook", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "14.0" + }, + "subcategory": "Laptop Computer", + "id": 43, + "name": "Dell Inspiron 15z Ultrabook" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Latitude E6420", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "31.0" + }, + "subcategory": "Laptop Computer", + "id": 44, + "name": "Dell Latitude E6420" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "20", + "i_model": "Latitude E7450", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 45, + "name": "Dell Latitude E7450" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "Probook 6460b", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "HP", + "i_checkout_period": "52.0" + }, + "subcategory": "Laptop Computer", + "id": 46, + "name": "HP Probook 6460b" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "MSP2 Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Peavey", + "i_checkout_period": "7.0" + }, + "subcategory": "Microphone Stands", + "id": 47, + "name": "Floor Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Desktop Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "QuikLok", + "i_checkout_period": "14.0" + }, + "subcategory": "Microphone Stands", + "id": 48, + "name": "Tabletop Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "AN-Mini", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Anchor", + "i_checkout_period": "14.0" + }, + "subcategory": "Portable Audio System", + "id": 49, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "VP4550", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Interlink", + "i_checkout_period": "14.0" + }, + "subcategory": "Power Point Remote", + "id": 50, + "name": "Power Point Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "83316", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (6 ft)", + "i_checkout_period": "14.0" + }, + "subcategory": "Projection Screen", + "id": 51, + "name": "Dalite" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "87063", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (8 ft)", + "i_checkout_period": "14.0" + }, + "subcategory": "Projection Screen", + "id": 52, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "MKE 400", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sennheiser", + "i_checkout_period": "7.0" + }, + "subcategory": "Shotgun Microphone", + "id": 53, + "name": "Shotgun Microphone" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad 4", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "14.0" + }, + "subcategory": "Tablet Computer", + "id": 54, + "name": "iPad 4" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "10.0" + }, + "subcategory": "Tablet Computer", + "id": 55, + "name": "iPad Air" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air 2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 56, + "name": "Apple iPad Air 2" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GorillaPod Tripod", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Joby", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 57, + "name": "GorillaPod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "Large tripod (755B)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 58, + "name": "Large Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "11", + "i_model": "Medium tripod (190XPROB)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 59, + "name": "Medium Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Small tripod (7001D)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sunpak", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 60, + "name": "Small Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "7", + "i_model": "WS-331M & 510M (Full Quarter)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus Digital Voice Recorder", + "i_checkout_period": "50.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 61, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "13", + "i_model": "WS-510M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus Digital Voice Recorder", + "i_checkout_period": "31.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 62, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "WMS-Pro", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Azden", + "i_checkout_period": "14.0" + }, + "subcategory": "Wireless Microphone System", + "id": 63, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "UWP-V1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sony", + "i_checkout_period": "7.0" + }, + "subcategory": "Wireless Microphone System", + "id": 64, + "name": "Placeholder Name" + } + ], + "images": [], + "organization": "", + "type": [], + "id": 5258, + "external_id": null + }, + { + "capacity": null, + "name": "HUB", + "display_access_restrictions": "", + "extended_info": { + "has_whiteboards": "true", + "app_type": "tech" + }, + "uri": "/api/v1/spot/5239", + "available_hours": { + "monday": [], + "tuesday": [], + "friday": [], + "wednesday": [], + "thursday": [], + "sunday": [], + "saturday": [] + }, + "manager": "", + "etag": "57de1783877e0b2a4e021fd979ccb98605ce6d47", + "location": { + "floor": "", + "height_from_sea_level": null, + "room_number": "", + "longitude": -122.305066, + "latitude": 47.655328, + "building_name": "" + }, + "last_modified": "2016-08-10T22:49:53+00:00", + "items": [], + "images": [], + "organization": "", + "type": [], + "id": 5239, + "external_id": null + }, + { + "capacity": null, + "name": "STF Checkout - Kane Hall", + "display_access_restrictions": "", + "extended_info": { + "owner": "cte", + "app_type": "tech", + "campus": "seattle" + }, + "uri": "/api/v1/spot/5259", + "available_hours": { + "monday": [ + [ + "08:00", + "17:00" + ] + ], + "tuesday": [ + [ + "08:00", + "17:00" + ] + ], + "friday": [ + [ + "08:00", + "17:00" + ] + ], + "wednesday": [ + [ + "08:00", + "17:00" + ] + ], + "thursday": [ + [ + "08:00", + "17:00" + ] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "etag": "156c9006209a544f38e82683835b80414e8c1bcd", + "location": { + "floor": "Basement", + "height_from_sea_level": null, + "room_number": "035", + "longitude": -122.309132, + "latitude": 47.656659, + "building_name": "Kane Hall (KNE)" + }, + "last_modified": "2016-08-25T18:06:19+00:00", + "items": [ + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "WH10LS30K", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "test_item_ei": "test", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "LG", + "i_checkout_period": "14.0" + }, + "subcategory": "Blu-ray Burner", + "id": 65, + "name": "LG Blu-ray Burner" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "84+ Silver Edition", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "TI", + "i_checkout_period": "14.0" + }, + "subcategory": "Calculator", + "id": 66, + "name": "Calculator" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "W1070", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "BenQ", + "i_checkout_period": "7.0" + }, + "subcategory": "Data Projector", + "id": 67, + "name": "BenQ W1070" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "CP-WX3014WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "14.0" + }, + "subcategory": "Data Projector", + "id": 68, + "name": "Hitachi CP-WX3014WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "CP-WX3015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "14.0" + }, + "subcategory": "Data Projector", + "id": 69, + "name": "Hitachi CP-WX3015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "CP-X3011N", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "31.0" + }, + "subcategory": "Data Projector", + "id": 70, + "name": "Hitachi CP-X3011N" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "30", + "i_model": "CPX4015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "7.0" + }, + "subcategory": "Data Projector", + "id": 71, + "name": "Hitachi CPX4015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "Digital Rebel T2i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 72, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Digital Rebel T2i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 73, + "name": "T2i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "Digital Rebel T4i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 74, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Digital Rebel T4i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 75, + "name": "T4i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T5i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 76, + "name": "T5i Full kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T5i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 77, + "name": "T5i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Digital Rebel T6i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 78, + "name": "T6i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "EOS 70D Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 79, + "name": "EOS 70D" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "PowerShot ELPH 320 HS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 80, + "name": "Canon PowerShot 320 HS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "11", + "i_model": "PowerShot SD1100 IS (Full Quarter)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "50.0" + }, + "subcategory": "Digital Camera", + "id": 81, + "name": "PowerShot SD1100 IS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "PowerShot SX20 IS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "31.0" + }, + "subcategory": "Digital Camera", + "id": 82, + "name": "PowerShot SX20 IS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "PowerShot SX60 HS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 83, + "name": "PowerShot SX60 HS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Cintiq DTH-1300", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Wacom", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Pen Tablet", + "id": 84, + "name": "Digital Pen Tablet" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "20", + "i_model": "Intuos4M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Wacom", + "i_checkout_period": "20.0" + }, + "subcategory": "Digital Pen Tablet", + "id": 85, + "name": "Digital Pen Tablet" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "9", + "i_model": "HDMI VIXIA HFS21", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 86, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "VIXIA HF10-High Def", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Video Camera", + "id": 87, + "name": "Digital Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "9", + "i_model": "XA10", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 88, + "name": "Canon XA10 Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "GoPro Hero3+", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "GoPro", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 89, + "name": "GoPro Hero3+" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "AG-HMC150 HD", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Panasonic", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 90, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "CX580V", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sony", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 91, + "name": "Sony CX580V Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "Macro: EF100", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Macro Lens", + "id": 92, + "name": "Macro Lens" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Macro Ring Lite MR-14EX", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Macro Ring Lite Flash", + "id": 93, + "name": "Macro Ring Flash" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "17", + "i_model": "430EX II Speedlite", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Shoe Mount Flash", + "id": 94, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "ShutterBoss RC-C1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Vello", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - SLR Remote", + "id": 95, + "name": "SLR Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "33", + "i_model": "Telephoto Lens: EF70-200mm", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Telephoto Lens", + "id": 96, + "name": "Telephoto Lens" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "32", + "i_model": "Wide Angle: EFS10-22mm", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Wide Angle Lens", + "id": 97, + "name": "Wide Angle Lens" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "250GB Solid State Drive", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Lacie", + "i_checkout_period": "14.0" + }, + "subcategory": "External Hard Drive", + "id": 98, + "name": "SSD External Hard Drive" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "33", + "i_model": "100GB Hard Drive", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Seagate", + "i_checkout_period": "31.0" + }, + "subcategory": "External Hard Drive", + "id": 99, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "49", + "i_model": "Macbook Pro 2011", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 100, + "name": "Macbook Pro 2011" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Macbook Pro 2013", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 101, + "name": "Macbook Pro 2013" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "36", + "i_model": "Macbook Pro 2014", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 102, + "name": "Macbook Pro 2014" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Macbook Pro 2015", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 103, + "name": "Macbook Pro 2015" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Inspiron 15z Ultrabook", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "14.0" + }, + "subcategory": "Laptop Computer", + "id": 104, + "name": "Dell Inspiron 15z Ultrabook" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "36", + "i_model": "Latitude E5440", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "10.0" + }, + "subcategory": "Laptop Computer", + "id": 105, + "name": "Dell Latitude E5440" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Latitude E6420", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "20.0" + }, + "subcategory": "Laptop Computer", + "id": 106, + "name": "Dell Latitude E6420" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "30", + "i_model": "Latitude E7450", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 107, + "name": "Dell Latitude E7450" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "21", + "i_model": "Probook 6460b", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "HP", + "i_checkout_period": "31.0" + }, + "subcategory": "Laptop Computer", + "id": 108, + "name": "HP Probook 6460b" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "MSP2 Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Peavey", + "i_checkout_period": "7.0" + }, + "subcategory": "Microphone Stands", + "id": 109, + "name": "Floor Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Desktop Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "QuikLok", + "i_checkout_period": "7.0" + }, + "subcategory": "Microphone Stands", + "id": 110, + "name": "Tabletop Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "AN-Mini", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Anchor", + "i_checkout_period": "7.0" + }, + "subcategory": "Portable Audio System", + "id": 111, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Passport P-150", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Fender", + "i_checkout_period": "7.0" + }, + "subcategory": "Portable Audio System", + "id": 112, + "name": "Fender Passport Deluxe P-150 (7-day)" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "3", + "i_model": "Passport PD-150", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Fender", + "i_checkout_period": "7.0" + }, + "subcategory": "Portable Audio System", + "id": 113, + "name": "Fender Passport PD-150 (7-day)" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "13", + "i_model": "VP4450", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "InterLink", + "i_checkout_period": "7.0" + }, + "subcategory": "Power Point Remote", + "id": 114, + "name": "Power Point Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "22", + "i_model": "83316", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (6 ft)", + "i_checkout_period": "7.0" + }, + "subcategory": "Projection Screen", + "id": 115, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "87063", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (8 ft)", + "i_checkout_period": "7.0" + }, + "subcategory": "Projection Screen", + "id": 116, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "MKE 400", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sennheiser", + "i_checkout_period": "7.0" + }, + "subcategory": "Shotgun Microphone", + "id": 117, + "name": "Shotgun Microphone" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "iPad 2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "14.0" + }, + "subcategory": "Tablet Computer", + "id": 118, + "name": "iPad 2" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad 4", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 119, + "name": "iPad 4" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 120, + "name": "iPad Air" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air 2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 121, + "name": "Apple iPad Air 2" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GorillaPod Tripod", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Joby", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 122, + "name": "GorillaPod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "7", + "i_model": "Large tripod (755B)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 123, + "name": "Large Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Medium tripod (190XPROB)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 124, + "name": "Medium Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Monopod (MMC3-01M)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 125, + "name": "Monopod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Small tripod (MKCOMPACTACN)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 126, + "name": "Small Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "Small tripod (7001D)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sunpak", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 127, + "name": "Small Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GoPro Pole (Pole 38HD)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "UK Pro", + "i_checkout_period": "7.0" + }, + "subcategory": "Tripod", + "id": 128, + "name": "GoPro Pole" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "19", + "i_model": "WS-331M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus", + "i_checkout_period": "31.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 129, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "28", + "i_model": "WS-510M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus", + "i_checkout_period": "14.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 130, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Pro", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Azden", + "i_checkout_period": "7.0" + }, + "subcategory": "Wireless Microphone System", + "id": 131, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "UWP-V1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sony", + "i_checkout_period": "7.0" + }, + "subcategory": "Wireless Microphone System", + "id": 132, + "name": "Placeholder Name" + } + ], + "images": [], + "organization": "", + "type": [], + "id": 5259, + "external_id": null + }, + { + "capacity": null, + "name": "Tech Stuff R' Us", + "display_access_restrictions": "", + "extended_info": { + "owner": "aca", + "is_hidden": "true", + "app_type": "tech" + }, + "uri": "/api/v1/spot/5230", + "available_hours": { + "monday": [], + "tuesday": [], + "friday": [], + "wednesday": [], + "thursday": [], + "sunday": [], + "saturday": [] + }, + "manager": "", + "etag": "fd530f91ca6a37371378892f6ca09d28c72c9d9e", + "location": { + "floor": "", + "height_from_sea_level": null, + "room_number": "", + "longitude": -122.30963583, + "latitude": 47.65487329, + "building_name": "" + }, + "last_modified": "2016-07-27T22:32:06+00:00", + "items": [], + "images": [], + "organization": "", + "type": [], + "id": 5230, + "external_id": null + }, + { + "capacity": null, + "name": "Academic & Collaborative Applications (ACA)", + "display_access_restrictions": "", + "extended_info": { + "owner": "asfdasdf", + "is_hidden": "true", + "app_type": "tech", + "campus": "seattle" + }, + "uri": "/api/v1/spot/5231", + "available_hours": { + "monday": [], + "tuesday": [], + "friday": [], + "wednesday": [], + "thursday": [], + "sunday": [], + "saturday": [] + }, + "manager": "", + "etag": "dfa57261a44f5ed43e22dfd450183d82527c944e", + "location": { + "floor": "", + "height_from_sea_level": null, + "room_number": "", + "longitude": -122.31625551, + "latitude": 47.66097604, + "building_name": "" + }, + "last_modified": "2016-07-28T17:58:01+00:00", + "items": [], + "images": [], + "organization": "", + "type": [], + "id": 5231, + "external_id": null + } +] diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=0&item:extended_info:i_brand=Apple&extended_info:app_type=tech b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=0&item:extended_info:i_brand=Apple&extended_info:app_type=tech new file mode 100644 index 0000000000000000000000000000000000000000..e3070ab877a853a23ae3f92bb180faca3d568ebf --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=0&item:extended_info:i_brand=Apple&extended_info:app_type=tech @@ -0,0 +1,2199 @@ +[ + { + "capacity": null, + "name": "STF Checkout - Health Sciences", + "display_access_restrictions": "", + "extended_info": { + "owner": "cte", + "app_type": "tech", + "campus": "seattle" + }, + "uri": "/api/v1/spot/5258", + "available_hours": { + "monday": [ + [ + "08:00", + "17:00" + ] + ], + "tuesday": [ + [ + "08:00", + "17:00" + ] + ], + "friday": [ + [ + "08:00", + "17:00" + ] + ], + "wednesday": [ + [ + "08:00", + "17:00" + ] + ], + "thursday": [ + [ + "08:00", + "17:00" + ] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "etag": "57dfacda8771c9078c34b8fa8be2cd9ffbed370c", + "location": { + "floor": "1st Floor", + "height_from_sea_level": null, + "room_number": "I-146", + "longitude": -122.308847, + "latitude": 47.650663, + "building_name": "Magnuson Health Sciences Center I (HSI)" + }, + "last_modified": "2016-08-24T21:17:10+00:00", + "items": [ + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "WH10LS30K", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "LG", + "i_checkout_period": "14.0" + }, + "subcategory": "Blu-ray Burner", + "id": 18, + "name": "LG Blu-ray Burner" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "84+ Silver Edition", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "TI", + "i_checkout_period": "31.0" + }, + "subcategory": "Calculator", + "id": 19, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "CP-WX3014WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "31.0" + }, + "subcategory": "Data Projector", + "id": 20, + "name": "Hitachi CP-WX3014N" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "CP-WX3015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "31.0" + }, + "subcategory": "Data Projector", + "id": 21, + "name": "Hitachi CP-WX3015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "CPX4015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "14.0" + }, + "subcategory": "Data Projector", + "id": 22, + "name": "Hitachi CPX4015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Digital Rebel T2i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "31.0" + }, + "subcategory": "Digital Camera", + "id": 23, + "name": "Digital Rebel T2i" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Digital Rebel T2i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 24, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T2i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 25, + "name": "T2i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Digital Rebel T5i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 26, + "name": "T5i Full kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Digital Rebel T5i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 27, + "name": "T5i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T6i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 28, + "name": "T6i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "EOS 70D Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 29, + "name": "Canon EOS 70D" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "PowerShot ELPH 320 HS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 30, + "name": "Canon PowerShot 320 HS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "9", + "i_model": "PowerShot SD1200 IS (Full Quarter)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "50.0" + }, + "subcategory": "Digital Camera", + "id": 31, + "name": "PowerShot SD1200 IS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "0", + "i_model": "GL-2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 32, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "HDMI VIXIA HFS21", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Video Camera", + "id": 33, + "name": "HDMI VIXIA HFS21" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "XA10", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 34, + "name": "Canon XA10 Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GoPro Hero3+", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "GoPro", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 35, + "name": "GoPro Hero3+" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "3", + "i_model": "AG-HMC150 HD", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Panasonic", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 36, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Macro Ring Lite MR-14EX", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Macro Ring Lite Flash", + "id": 37, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "4", + "i_model": "ShutterBoss RC-C1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Vello", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - SLR Remote", + "id": 38, + "name": "SLR Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "35", + "i_model": "Macbook Pro 2011", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "31.0" + }, + "subcategory": "Laptop Computer", + "id": 39, + "name": "Macbook Pro 2011" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "26", + "i_model": "Macbook Pro 2013", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "14.0" + }, + "subcategory": "Laptop Computer", + "id": 40, + "name": "Macbook Pro 2013" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Macbook Pro 2014", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "10.0" + }, + "subcategory": "Laptop Computer", + "id": 41, + "name": "Macbook Pro 2014" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Macbook Pro 2015", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 42, + "name": "Macbook Pro 2015" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Inspiron 15z Ultrabook", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "14.0" + }, + "subcategory": "Laptop Computer", + "id": 43, + "name": "Dell Inspiron 15z Ultrabook" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Latitude E6420", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "31.0" + }, + "subcategory": "Laptop Computer", + "id": 44, + "name": "Dell Latitude E6420" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "20", + "i_model": "Latitude E7450", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 45, + "name": "Dell Latitude E7450" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "Probook 6460b", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "HP", + "i_checkout_period": "52.0" + }, + "subcategory": "Laptop Computer", + "id": 46, + "name": "HP Probook 6460b" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "MSP2 Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Peavey", + "i_checkout_period": "7.0" + }, + "subcategory": "Microphone Stands", + "id": 47, + "name": "Floor Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Desktop Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "QuikLok", + "i_checkout_period": "14.0" + }, + "subcategory": "Microphone Stands", + "id": 48, + "name": "Tabletop Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "AN-Mini", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Anchor", + "i_checkout_period": "14.0" + }, + "subcategory": "Portable Audio System", + "id": 49, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "VP4550", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Interlink", + "i_checkout_period": "14.0" + }, + "subcategory": "Power Point Remote", + "id": 50, + "name": "Power Point Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "83316", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (6 ft)", + "i_checkout_period": "14.0" + }, + "subcategory": "Projection Screen", + "id": 51, + "name": "Dalite" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "87063", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (8 ft)", + "i_checkout_period": "14.0" + }, + "subcategory": "Projection Screen", + "id": 52, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "MKE 400", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sennheiser", + "i_checkout_period": "7.0" + }, + "subcategory": "Shotgun Microphone", + "id": 53, + "name": "Shotgun Microphone" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad 4", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "14.0" + }, + "subcategory": "Tablet Computer", + "id": 54, + "name": "iPad 4" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "10.0" + }, + "subcategory": "Tablet Computer", + "id": 55, + "name": "iPad Air" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air 2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 56, + "name": "Apple iPad Air 2" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GorillaPod Tripod", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Joby", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 57, + "name": "GorillaPod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "Large tripod (755B)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 58, + "name": "Large Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "11", + "i_model": "Medium tripod (190XPROB)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 59, + "name": "Medium Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Small tripod (7001D)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sunpak", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 60, + "name": "Small Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "7", + "i_model": "WS-331M & 510M (Full Quarter)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus Digital Voice Recorder", + "i_checkout_period": "50.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 61, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "13", + "i_model": "WS-510M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus Digital Voice Recorder", + "i_checkout_period": "31.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 62, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "WMS-Pro", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Azden", + "i_checkout_period": "14.0" + }, + "subcategory": "Wireless Microphone System", + "id": 63, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "6", + "i_model": "UWP-V1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sony", + "i_checkout_period": "7.0" + }, + "subcategory": "Wireless Microphone System", + "id": 64, + "name": "Placeholder Name" + } + ], + "images": [], + "organization": "", + "type": [], + "id": 5258, + "external_id": null + }, + { + "capacity": null, + "name": "STF Checkout - Kane Hall", + "display_access_restrictions": "", + "extended_info": { + "owner": "cte", + "app_type": "tech", + "campus": "seattle" + }, + "uri": "/api/v1/spot/5259", + "available_hours": { + "monday": [ + [ + "08:00", + "17:00" + ] + ], + "tuesday": [ + [ + "08:00", + "17:00" + ] + ], + "friday": [ + [ + "08:00", + "17:00" + ] + ], + "wednesday": [ + [ + "08:00", + "17:00" + ] + ], + "thursday": [ + [ + "08:00", + "17:00" + ] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "etag": "156c9006209a544f38e82683835b80414e8c1bcd", + "location": { + "floor": "Basement", + "height_from_sea_level": null, + "room_number": "035", + "longitude": -122.309132, + "latitude": 47.656659, + "building_name": "Kane Hall (KNE)" + }, + "last_modified": "2016-08-25T18:06:19+00:00", + "items": [ + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "WH10LS30K", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "test_item_ei": "test", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "LG", + "i_checkout_period": "14.0" + }, + "subcategory": "Blu-ray Burner", + "id": 65, + "name": "LG Blu-ray Burner" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "84+ Silver Edition", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "TI", + "i_checkout_period": "14.0" + }, + "subcategory": "Calculator", + "id": 66, + "name": "Calculator" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "W1070", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "BenQ", + "i_checkout_period": "7.0" + }, + "subcategory": "Data Projector", + "id": 67, + "name": "BenQ W1070" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "CP-WX3014WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "14.0" + }, + "subcategory": "Data Projector", + "id": 68, + "name": "Hitachi CP-WX3014WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "CP-WX3015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "14.0" + }, + "subcategory": "Data Projector", + "id": 69, + "name": "Hitachi CP-WX3015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "CP-X3011N", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "31.0" + }, + "subcategory": "Data Projector", + "id": 70, + "name": "Hitachi CP-X3011N" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "30", + "i_model": "CPX4015WN", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Hitachi", + "i_checkout_period": "7.0" + }, + "subcategory": "Data Projector", + "id": 71, + "name": "Hitachi CPX4015WN" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "Digital Rebel T2i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 72, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Digital Rebel T2i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 73, + "name": "T2i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "Digital Rebel T4i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 74, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Digital Rebel T4i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 75, + "name": "T4i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T5i", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 76, + "name": "T5i Full kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Digital Rebel T5i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 77, + "name": "T5i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Digital Rebel T6i Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 78, + "name": "T6i Partial Kit" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "EOS 70D Partial Kit", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 79, + "name": "EOS 70D" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "PowerShot ELPH 320 HS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Camera", + "id": 80, + "name": "Canon PowerShot 320 HS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "11", + "i_model": "PowerShot SD1100 IS (Full Quarter)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "50.0" + }, + "subcategory": "Digital Camera", + "id": 81, + "name": "PowerShot SD1100 IS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "PowerShot SX20 IS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "31.0" + }, + "subcategory": "Digital Camera", + "id": 82, + "name": "PowerShot SX20 IS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "PowerShot SX60 HS", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Camera", + "id": 83, + "name": "PowerShot SX60 HS" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Cintiq DTH-1300", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Wacom", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Pen Tablet", + "id": 84, + "name": "Digital Pen Tablet" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "20", + "i_model": "Intuos4M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Wacom", + "i_checkout_period": "20.0" + }, + "subcategory": "Digital Pen Tablet", + "id": 85, + "name": "Digital Pen Tablet" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "9", + "i_model": "HDMI VIXIA HFS21", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 86, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "VIXIA HF10-High Def", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "14.0" + }, + "subcategory": "Digital Video Camera", + "id": 87, + "name": "Digital Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "9", + "i_model": "XA10", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 88, + "name": "Canon XA10 Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "GoPro Hero3+", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "GoPro", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 89, + "name": "GoPro Hero3+" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "AG-HMC150 HD", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Panasonic", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 90, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "CX580V", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sony", + "i_checkout_period": "7.0" + }, + "subcategory": "Digital Video Camera", + "id": 91, + "name": "Sony CX580V Video Camera" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "Macro: EF100", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Macro Lens", + "id": 92, + "name": "Macro Lens" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Macro Ring Lite MR-14EX", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Macro Ring Lite Flash", + "id": 93, + "name": "Macro Ring Flash" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "17", + "i_model": "430EX II Speedlite", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Shoe Mount Flash", + "id": 94, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "ShutterBoss RC-C1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Vello", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - SLR Remote", + "id": 95, + "name": "SLR Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "33", + "i_model": "Telephoto Lens: EF70-200mm", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Telephoto Lens", + "id": 96, + "name": "Telephoto Lens" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "32", + "i_model": "Wide Angle: EFS10-22mm", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Canon", + "i_checkout_period": "7.0" + }, + "subcategory": "DSLR Accessories - Wide Angle Lens", + "id": 97, + "name": "Wide Angle Lens" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "250GB Solid State Drive", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Lacie", + "i_checkout_period": "14.0" + }, + "subcategory": "External Hard Drive", + "id": 98, + "name": "SSD External Hard Drive" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "33", + "i_model": "100GB Hard Drive", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Seagate", + "i_checkout_period": "31.0" + }, + "subcategory": "External Hard Drive", + "id": 99, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "49", + "i_model": "Macbook Pro 2011", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 100, + "name": "Macbook Pro 2011" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Macbook Pro 2013", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 101, + "name": "Macbook Pro 2013" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "36", + "i_model": "Macbook Pro 2014", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 102, + "name": "Macbook Pro 2014" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Macbook Pro 2015", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 103, + "name": "Macbook Pro 2015" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "Inspiron 15z Ultrabook", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "14.0" + }, + "subcategory": "Laptop Computer", + "id": 104, + "name": "Dell Inspiron 15z Ultrabook" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "36", + "i_model": "Latitude E5440", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "10.0" + }, + "subcategory": "Laptop Computer", + "id": 105, + "name": "Dell Latitude E5440" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Latitude E6420", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "20.0" + }, + "subcategory": "Laptop Computer", + "id": 106, + "name": "Dell Latitude E6420" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "30", + "i_model": "Latitude E7450", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Dell", + "i_checkout_period": "7.0" + }, + "subcategory": "Laptop Computer", + "id": 107, + "name": "Dell Latitude E7450" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "21", + "i_model": "Probook 6460b", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "HP", + "i_checkout_period": "31.0" + }, + "subcategory": "Laptop Computer", + "id": 108, + "name": "HP Probook 6460b" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "MSP2 Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Peavey", + "i_checkout_period": "7.0" + }, + "subcategory": "Microphone Stands", + "id": 109, + "name": "Floor Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Desktop Microphone Stand", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "QuikLok", + "i_checkout_period": "7.0" + }, + "subcategory": "Microphone Stands", + "id": 110, + "name": "Tabletop Microphone Stand" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "AN-Mini", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Anchor", + "i_checkout_period": "7.0" + }, + "subcategory": "Portable Audio System", + "id": 111, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "Passport P-150", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Fender", + "i_checkout_period": "7.0" + }, + "subcategory": "Portable Audio System", + "id": 112, + "name": "Fender Passport Deluxe P-150 (7-day)" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "3", + "i_model": "Passport PD-150", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Fender", + "i_checkout_period": "7.0" + }, + "subcategory": "Portable Audio System", + "id": 113, + "name": "Fender Passport PD-150 (7-day)" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "13", + "i_model": "VP4450", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "InterLink", + "i_checkout_period": "7.0" + }, + "subcategory": "Power Point Remote", + "id": 114, + "name": "Power Point Remote" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "22", + "i_model": "83316", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (6 ft)", + "i_checkout_period": "7.0" + }, + "subcategory": "Projection Screen", + "id": 115, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "87063", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Da-Lite (8 ft)", + "i_checkout_period": "7.0" + }, + "subcategory": "Projection Screen", + "id": 116, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "MKE 400", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sennheiser", + "i_checkout_period": "7.0" + }, + "subcategory": "Shotgun Microphone", + "id": 117, + "name": "Shotgun Microphone" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "18", + "i_model": "iPad 2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "14.0" + }, + "subcategory": "Tablet Computer", + "id": 118, + "name": "iPad 2" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad 4", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 119, + "name": "iPad 4" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 120, + "name": "iPad Air" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "10", + "i_model": "iPad Air 2", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Apple", + "i_checkout_period": "7.0" + }, + "subcategory": "Tablet Computer", + "id": 121, + "name": "Apple iPad Air 2" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GorillaPod Tripod", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Joby", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 122, + "name": "GorillaPod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "7", + "i_model": "Large tripod (755B)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 123, + "name": "Large Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "24", + "i_model": "Medium tripod (190XPROB)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 124, + "name": "Medium Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "Monopod (MMC3-01M)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 125, + "name": "Monopod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Small tripod (MKCOMPACTACN)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Manfrotto", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 126, + "name": "Small Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "8", + "i_model": "Small tripod (7001D)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sunpak", + "i_checkout_period": "14.0" + }, + "subcategory": "Tripod", + "id": 127, + "name": "Small Tripod" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "5", + "i_model": "GoPro Pole (Pole 38HD)", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "UK Pro", + "i_checkout_period": "7.0" + }, + "subcategory": "Tripod", + "id": 128, + "name": "GoPro Pole" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "19", + "i_model": "WS-331M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus", + "i_checkout_period": "31.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 129, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "28", + "i_model": "WS-510M", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Olympus", + "i_checkout_period": "14.0" + }, + "subcategory": "Voice Recorder/MP3 player", + "id": 130, + "name": "Voice Recorder" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "15", + "i_model": "Pro", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Azden", + "i_checkout_period": "7.0" + }, + "subcategory": "Wireless Microphone System", + "id": 131, + "name": "Placeholder Name" + }, + { + "category": "Placeholder Category", + "extended_info": { + "i_quantity": "25", + "i_model": "UWP-V1", + "i_access_role_students": "true", + "i_reservation_required": "true", + "i_has_access_restriction": "true", + "i_is_active": "true", + "i_access_limit_role": "true", + "i_reservaion_required": "true", + "i_brand": "Sony", + "i_checkout_period": "7.0" + }, + "subcategory": "Wireless Microphone System", + "id": 132, + "name": "Placeholder Name" + } + ], + "images": [], + "organization": "", + "type": [], + "id": 5259, + "external_id": null + } +] diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=5¢er_latitude=47.653811¢er_longitude=-122.307815&distance=100000&fuzzy_hours_start=Tuesday%2C05%3A00&fuzzy_hours_end=Tuesday%2C11%3A00&extended_info%3Aapp_type=food b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=5¢er_latitude=47.653811¢er_longitude=-122.307815&distance=100000&fuzzy_hours_start=Tuesday%2C05%3A00&fuzzy_hours_end=Tuesday%2C11%3A00&extended_info%3Aapp_type=food new file mode 100644 index 0000000000000000000000000000000000000000..adbc6a5beb7191f7dd1f3de4bab4647a95c56ecf --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot?limit=5¢er_latitude=47.653811¢er_longitude=-122.307815&distance=100000&fuzzy_hours_start=Tuesday%2C05%3A00&fuzzy_hours_end=Tuesday%2C11%3A00&extended_info%3Aapp_type=food @@ -0,0 +1,410 @@ +[ + { + "extended_info":{ + "s_pay_cash":"true", + "s_phone":"206-543-7977", + "s_pay_husky":"true", + "app_type":"food", + "s_food_espresso":"true", + "s_pay_mastercard":"true", + "s_pay_dining":"true", + "location_description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_cuisine_american":"true", + "s_website_url":"https://www.hfs.washington.edu/espresso/", + "owner":"Housing and Food Services (HFS)", + "campus":"seattle", + "s_pay_visa":"true" + }, + "manager":"Test Manager", + "last_modified":"2012-07-13T05:00:00+00:00", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/123/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/123/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "display_access_restrictions":"", + "id":40, + "capacity":0, + "name":"TestSpot1", + "external_id":null, + "uri":"/api/v1/spot/40", + "available_hours":{ + "monday":[ + [ + "10:30", + "14:30" + ] + ], + "tuesday":[ + [ + "10:30", + "14:30" + ] + ], + "friday":[ + [ + "10:30", + "14:30" + ] + ], + "wednesday":[ + [ + "10:30", + "14:30" + ] + ], + "thursday":[ + [ + "10:30", + "14:30" + ] + ], + "sunday":[ + + ], + "saturday":[ + + ] + }, + "etag":"123456789", + "location":{ + "floor":"", + "height_from_sea_level":0.10, + "room_number":"", + "longitude":-12, + "latitude":47, + "building_name":"TestBuilding" + }, + "organization":"Test Org", + "type":[ + + ] + }, + { + "extended_info":{ + "s_pay_cash":"true", + "s_phone":"206-221-6651", + "s_pay_husky":"true", + "app_type":"food", + "s_food_espresso":"true", + "s_pay_mastercard":"true", + "s_pay_dining":"true", + "location_description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_cuisine_american":"true", + "s_website_url":"https://www.hfs.washington.edu/espresso/", + "owner":"Housing and Food Services (HFS)", + "campus":"seattle", + "s_pay_visa":"true" + }, + "manager":"", + "last_modified":"2015-12-09T00:32:45.017650+00:00", + "images":[ + + ], + "display_access_restrictions":"", + "id":17, + "capacity":null, + "name":"Mary Gates Hall Espresso", + "external_id":null, + "uri":"/api/v1/spot/17", + "available_hours":{ + "monday":[ + [ + "10:30", + "14:30" + ] + ], + "tuesday":[ + [ + "10:30", + "14:30" + ] + ], + "friday":[ + [ + "10:30", + "14:30" + ] + ], + "wednesday":[ + [ + "10:30", + "14:30" + ] + ], + "thursday":[ + [ + "10:30", + "14:30" + ] + ], + "sunday":[ + + ], + "saturday":[ + + ] + }, + "etag":"696e626e1d42fdbc97a3a4bfbe96c63e8047a834", + "location":{ + "floor":"", + "height_from_sea_level":null, + "room_number":"", + "longitude":-122.307733, + "latitude":47.654591, + "building_name":"Mary Gates Hall (MGH)" + }, + "organization":"", + "type":[ + + ] + }, + { + "extended_info":{ + "s_pay_cash":"true", + "s_phone":"206-616-3327", + "s_pay_husky":"true", + "app_type":"food", + "s_food_espresso":"true", + "s_pay_mastercard":"true", + "s_pay_dining":"true", + "location_description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_cuisine_american":"true", + "s_website_url":"https://www.hfs.washington.edu/espresso/", + "owner":"Housing and Food Services (HFS)", + "campus":"seattle", + "s_pay_visa":"true" + }, + "manager":"", + "last_modified":"2012-07-13T05:00:00+00:00", + "images":[ + + ], + "display_access_restrictions":"", + "id":36, + "capacity":null, + "name":"Suzzallo Espresso", + "external_id":null, + "uri":"/api/v1/spot/36", + "available_hours":{ + "monday":[ + [ + "10:30", + "14:30" + ] + ], + "tuesday":[ + [ + "10:30", + "14:30" + ] + ], + "friday":[ + [ + "10:30", + "14:30" + ] + ], + "wednesday":[ + [ + "10:30", + "14:30" + ] + ], + "thursday":[ + [ + "10:30", + "14:30" + ] + ], + "sunday":[ + + ], + "saturday":[ + + ] + }, + "etag":"b6cd80cd5edf7f58ffb2b8cbc1211fa72521e080", + "location":{ + "floor":"", + "height_from_sea_level":null, + "room_number":"", + "longitude":-122.308667, + "latitude":47.65582, + "building_name":"Suzzallo Library (SUZ)" + }, + "organization":"", + "type":[ + + ] + }, + { + "extended_info":{ + "s_pay_cash":"true", + "s_phone":"206-616-8860", + "s_pay_husky":"true", + "app_type":"food", + "s_food_espresso":"true", + "s_pay_mastercard":"true", + "s_pay_dining":"true", + "location_description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_cuisine_american":"true", + "s_website_url":"https://www.hfs.washington.edu/espresso/", + "owner":"Housing and Food Services (HFS)", + "campus":"seattle", + "s_pay_visa":"true" + }, + "manager":"", + "last_modified":"2015-12-09T00:32:50.128144+00:00", + "images":[ + + ], + "display_access_restrictions":"", + "id":29, + "capacity":null, + "name":"Reboot", + "external_id":null, + "uri":"/api/v1/spot/29", + "available_hours":{ + "monday":[ + [ + "10:30", + "14:30" + ] + ], + "tuesday":[ + [ + "10:30", + "14:30" + ] + ], + "friday":[ + [ + "10:30", + "14:30" + ] + ], + "wednesday":[ + [ + "10:30", + "14:30" + ] + ], + "thursday":[ + [ + "10:30", + "14:30" + ] + ], + "sunday":[ + + ], + "saturday":[ + + ] + }, + "etag":"71991d0a4ad1be170b8d571ff2cc9adbb1018eea", + "location":{ + "floor":"", + "height_from_sea_level":null, + "room_number":"", + "longitude":-122.30592, + "latitude":47.653262, + "building_name":"Computer Science and Engineering Building (CSE)" + }, + "organization":"", + "type":[ + + ] + }, + { + "extended_info":{ + "s_pay_cash":"true", + "s_phone":"206-616-2739", + "s_pay_husky":"true", + "app_type":"food", + "s_food_espresso":"true", + "s_pay_mastercard":"true", + "s_pay_dining":"true", + "location_description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_cuisine_american":"true", + "s_website_url":"https://www.hfs.washington.edu/espresso/", + "owner":"Housing and Food Services (HFS)", + "campus":"seattle", + "s_pay_visa":"true" + }, + "manager":"", + "last_modified":"2015-12-09T00:32:43.727679+00:00", + "images":[ + + ], + "display_access_restrictions":"", + "id":12, + "capacity":null, + "name":"H-bar", + "external_id":null, + "uri":"/api/v1/spot/12", + "available_hours":{ + "monday":[ + [ + "10:30", + "14:30" + ] + ], + "tuesday":[ + [ + "10:30", + "14:30" + ] + ], + "friday":[ + [ + "10:30", + "14:30" + ] + ], + "wednesday":[ + [ + "10:30", + "14:30" + ] + ], + "thursday":[ + [ + "10:30", + "14:30" + ] + ], + "sunday":[ + + ], + "saturday":[ + + ] + }, + "etag":"dc954f467b55f9814ac3a551e6d8b2afe9796574", + "location":{ + "floor":"", + "height_from_sea_level":null, + "room_number":"", + "longitude":-122.31114, + "latitude":47.653616, + "building_name":"Physics / Astronomy Building (PAB)" + }, + "organization":"", + "type":[ + + ] + } +] diff --git a/spotseeker_restclient/resources/spotseeker/file/api/v1/spot_limit_0_extended_info%3Aapp_type_food b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot_limit_0_extended_info%3Aapp_type_food new file mode 100644 index 0000000000000000000000000000000000000000..df114503dfa25f8223364694fd185fac8a46cd4d --- /dev/null +++ b/spotseeker_restclient/resources/spotseeker/file/api/v1/spot_limit_0_extended_info%3Aapp_type_food @@ -0,0 +1,272 @@ +[{ + "capacity": 15, + "name": "Banh & Naan, Husky Den", + "external_id": null, + "extended_info": { + "s_pay_cash": "true", + "s_phone": "206-685-4950", + "s_pay_husky": "true", + "app_type": "food", + "s_pay_visa": "true", + "s_pay_mastercard": "true", + "s_food_entrees": "true", + "s_pay_dining": "true", + "location_description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in consequat purus. Suspendisse euismod scelerisque malesuada. Aenean eu hendrerit lorem, egestas ullamcorper lacus. Sed dignissim nunc non dolor vulputate, in volutpat metus laoreet.", + "s_food_sandwiches": "true", + "s_cuisine_vietnamese": "true", + "s_website_url": "https://www.hfs.washington.edu/dining/Default.aspx?id=3620#gsc.tab=0", + "owner": "Housing and Food Services (HFS)", + "campus": "seattle", + "s_cuisine_indian": "true", + "s_menu_url": "https://www.hfs.washington.edu/uploadedFiles/Dining/Dining_Locations/Bahnwebmenu%202014.pdf" + }, + "uri": "/api/v1/spot/1", + "available_hours": { + "monday": [ + ["10:30", "14:30"], + ["15:30", "18:30"] + ], + "tuesday": [ + ["8:30", "9:30"], + ["10:30", "14:30"] + ], + "friday": [ + ["10:30", "22:30"] + ], + "wednesday": [ + ["10:30", "14:30"] + ], + "thursday": [ + ["10:30", "14:30"] + ], + "sunday": [], + "saturday": [] + }, + "manager": "", + "last_modified": "2015-12-15T22:35:41.699054+00:00", + "etag": "f573702e9e71197ff3eaa3c6357845d614580930", + "type": ["food_court"], + "images": [], + "organization": "", + "display_access_restrictions": "", + "id": 1, + "location": { + "floor": "Ground Floor", + "height_from_sea_level": null, + "room_number": "Husky Den", + "longitude": -122.3051094, + "latitude": 47.6552915, + "building_name": "Husky Union Building (HUB)" + } +}, +{ + "id": "2", + "uri": "/api/v1/spot/2", + "name": "It's A Market", + "type": ["market"], + "meta_type": ["food"], + "location": { + "longitude": -122.3085307, + "latitude": 47.6558366, + "height_from_sea_level": 0.10, + "building_name": "The Market", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/2/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/2/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "21:00"] ], + "tuesday": [ ["11:00", "21:00" ] ], + "wednesday": [ ["11:00", "21:00"] ], + "thursday": [ ["11:00", "21:00"] ], + "friday": [ ["11:00", "21:00"] ], + "saturday": [], + "sunday": [ ["11:00", "21:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : false, + "s_alert_notes" : "", + + "s_has_reservation" : false, + "s_reservation_notes" : "", + + "s_has_coupon" : false, + "s_coupon_expiration" : "", + "s_coupon_url" : "", + + "s_cuisine_american" : false, + "s_cuisine_bbq" : false, + "s_cuisine_chinese" : false, + "s_cuisine_hawaiian" : true, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : true, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : false, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : false, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : false, + "s_food_espresso" : true, + "s_food_pasta" : false, + "s_food_pizza" : true, + "s_food_salads" : false, + "s_food_sandwiches" : true, + "s_food_smoothies" : true, + "s_food_sushi" : true, + "s_food_tacos" : true, + + "s_pay_cash" : false, + "s_pay_visa" : false, + "s_pay_mastercard" : false, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : false, + "s_open_lunch" : true, + "s_open_dinner" : true, + "s_open_late_night" : true + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +}, +{ + "id": "3", + "uri": "/api/v1/spot/3", + "name": "Truck of Food", + "type": ["food_truck"], + "meta_type": ["food"], + "location": { + "longitude": -122.3080857, + "latitude": 47.6539295, + "height_from_sea_level": 0.10, + "building_name": "Test Building", + "floor": 0, + "room_number": "456", + "description": "This is a building" + }, + "capacity": 0, + "display_access_restrictions": "none", + "images": [ + { + "id":"1", + "url":"/api/v1/spot/3/image/1", + "content-type":"image/jpeg", + "width":0, + "height":0, + "creation_date":"Sun, 06 Nov 1994 08:49:37 GMT", + "modification_date":"Mon, 07 Nov 1994 01:49:37 GMT", + "upload_user":"user name", + "upload_application":"application name", + "thumbnail_root":"/api/v1/spot/3/image/1/thumb", + "description": "Information about the image", + "display_index": 0 + } + ], + "available_hours":{ + "monday": [ ["00:00", "10:00" ], ["11:00", "14:00"] ], + "tuesday": [ ["11:00", "14:00" ] ], + "wednesday": [ ["11:00", "14:00"] ], + "thursday": [ ["11:00", "14:00"] ], + "friday": [ ["11:00", "14:00"] ], + "saturday": [], + "sunday": [ ["11:00", "14:00"] ] + }, + "organization": "Test Org", + "manager": "Mr Test Org", + "extended_info": { + "app_type" : "food", + "campus" : "seattle", + "hours_notes" : "", + "access_notes" : "Open to all", + + + "s_menu_url" : "www.yelp.com", + "s_website_url" : "www.uw.edu/food", + "s_contact_phone" : "2066164000", + + "s_has_alert" : true, + "s_alert_notes" : "It's a fire sale", + + "s_has_reservation" : true, + "s_reservation_notes" : "", + + "s_has_coupon" : true, + "s_coupon_expiration" : "never", + "s_coupon_url" : "www.uw.com/food/deals", + + "s_cuisine_american" : true, + "s_cuisine_bbq" : true, + "s_cuisine_chinese" : false, + "s_cuisine_hawaiian" : false, + "s_cuisine_indian" : false, + "s_cuisine_italian" : false, + "s_cuisine_japanese" : false, + "s_cuisine_korean" : false, + "s_cuisine_mexican" : true, + "s_cuisine_vietnamese" : false, + + "s_cuisine_light_lunch" : false, + + "s_food_appetizers" : false, + "s_food_burgers" : false, + "s_food_entrees" : false, + "s_food_espresso" : false, + "s_food_pasta" : false, + "s_food_pizza" : false, + "s_food_salads" : false, + "s_food_sandwiches" : true, + "s_food_smoothies" : false, + "s_food_sushi" : false, + "s_food_tacos" : false, + + "s_pay_cash" : true, + "s_pay_visa" : true, + "s_pay_mastercard" : true, + "s_pay_husky" : true, + "s_pay_dining" : true, + + "s_open_breakfast" : false, + "s_open_lunch" : true, + "s_open_dinner" : false, + "s_open_late_night" : false + }, + "last_modified": "2012-07-13T05:00:00+00:00", + "etag": "686897696a7c876b7e", + "external_id": "asd123" +} +] diff --git a/spotseeker_restclient/spotseeker.py b/spotseeker_restclient/spotseeker.py new file mode 100644 index 0000000000000000000000000000000000000000..40f583a0debd0e4f089b3fac1d9c4c8b4f5fcb08 --- /dev/null +++ b/spotseeker_restclient/spotseeker.py @@ -0,0 +1,391 @@ +import StringIO +from spotseeker_restclient.dao import SPOTSEEKER_DAO +from spotseeker_restclient.exceptions import DataFailureException +from spotseeker_restclient.models.spot import Spot, SpotAvailableHours, \ + SpotExtendedInfo, SpotImage, SpotType, SpotItem, ItemImage +from spotseeker_restclient.dao_implementation.spotseeker import File +import json +from django.utils.dateparse import parse_datetime, parse_time +from django.core.exceptions import ImproperlyConfigured +from django.conf import settings +from urllib import urlencode +import requests +from requests_oauthlib import OAuth1 + + +class Spotseeker(object): + + def post_image(self, spot_id, image): + url = "api/v1/spot/%s/image" % spot_id + dao = SPOTSEEKER_DAO() + if isinstance(dao._getDAO(), File): + resp = dao.putURL(url, {}) + content = resp.data + return content + else: + try: + headers = {"X-OAuth-User": settings.OAUTH_USER} + auth = OAuth1(settings.SPOTSEEKER_OAUTH_KEY, + settings.SPOTSEEKER_OAUTH_SECRET) + full_url = settings.SPOTSEEKER_HOST + "/" + url + files = {'image': ('image.jpg', StringIO.StringIO(image))} + + # Using requests lib here as urllib does not have good support + # for multipart form uploads. + r = requests.post(full_url, + files=files, + auth=auth, + headers=headers) + if r.status_code != 201: + raise DataFailureException(url, r.status_code, r.content) + except AttributeError: + raise ImproperlyConfigured("Must set OAUTH_ keys in settings") + + def delete_image(self, spot_id, image_id, etag): + url = "/api/v1/spot/%s/image/%s" % (spot_id, image_id) + dao = SPOTSEEKER_DAO() + + if isinstance(dao._getDAO(), File): + resp = {'status': 200} + else: + try: + headers = {"X-OAuth-User": settings.OAUTH_USER, + "If-Match": etag} + resp, content = dao.deleteURL(url, + headers) + except AttributeError: + raise ImproperlyConfigured("Must set OAUTH_USER in settings") + + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + + def post_item_image(self, item_id, image): + url = "api/v1/item/%s/image" % item_id + dao = SPOTSEEKER_DAO() + if isinstance(dao._getDAO(), File): + resp = dao.putURL(url, {}) + content = resp.data + return content + else: + try: + headers = {"X-OAuth-User": settings.OAUTH_USER} + auth = OAuth1(settings.SPOTSEEKER_OAUTH_KEY, + settings.SPOTSEEKER_OAUTH_SECRET) + full_url = settings.SPOTSEEKER_HOST + "/" + url + files = {'image': ('image.jpg', StringIO.StringIO(image))} + + # Using requests lib here as urllib does not have good support + # for multipart form uploads. + r = requests.post(full_url, + files=files, + auth=auth, + headers=headers) + if r.status_code != 201: + raise DataFailureException(url, r.status_code, r.content) + except AttributeError as ex: + raise ImproperlyConfigured("Must set OAUTH_ keys in settings") + + def delete_item_image(self, item_id, image_id, etag): + url = "/api/v1/item/%s/image/%s" % (item_id, image_id) + dao = SPOTSEEKER_DAO() + + if isinstance(dao._getDAO(), File): + resp = {'status': 200} + else: + try: + headers = {"X-OAuth-User": settings.OAUTH_USER, + "If-Match": etag} + resp, content = dao.deleteURL(url, + headers) + except AttributeError: + raise ImproperlyConfigured("Must set OAUTH_USER in settings") + + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + + def put_spot(self, spot_id, spot_json, etag): + url = "/api/v1/spot/%s" % spot_id + dao = SPOTSEEKER_DAO() + + if isinstance(dao._getDAO(), File): + resp = dao.putURL(url, {}) + content = resp.data + else: + try: + headers = {"X-OAuth-User": settings.OAUTH_USER, + "If-Match": etag} + resp, content = dao.putURL(url, + headers, + spot_json) + except AttributeError: + raise ImproperlyConfigured("Must set OAUTH_USER in settings") + + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + + def delete_spot(self, spot_id, etag): + url = "/api/v1/spot/%s" % spot_id + dao = SPOTSEEKER_DAO() + if isinstance(dao._getDAO(), File): + resp = dao.deleteURL(url, {}) + content = resp.data + else: + try: + headers = {"X-OAuth-User": settings.OAUTH_USER, + "If-Match": etag} + resp, content = dao.deleteURL(url, + headers) + except AttributeError: + raise ImproperlyConfigured("Must set OAUTH_USER in settings") + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + + def post_spot(self, spot_json): + url = "/api/v1/spot/" + dao = SPOTSEEKER_DAO() + + if isinstance(dao._getDAO(), File): + resp = dao.postURL(url, {}) + content = resp.data + else: + try: + headers = {"X-OAuth-User": settings.OAUTH_USER, + "Content-Type": "application/json" + } + resp, content = dao.postURL(url, + headers, + spot_json) + except AttributeError: + raise ImproperlyConfigured("Must set OAUTH_USER in settings") + + if resp.status != 201: + raise DataFailureException(url, resp.status, content) + return resp + + def get_spot_by_id(self, spot_id): + url = "/api/v1/spot/%s" % spot_id + dao = SPOTSEEKER_DAO() + if isinstance(dao._getDAO(), File): + resp = dao.getURL(url, {}) + content = resp.data + else: + resp, content = dao.getURL(url, {}) + + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + return self._spot_from_data(json.loads(content)) + + def get_building_list(self, campus, app_type=None): + url = "/api/v1/buildings?extended_info:campus=" + campus + if app_type: + url += "&extended_info:app_type=" + app_type + + dao = SPOTSEEKER_DAO() + if isinstance(dao._getDAO(), File): + resp = dao.getURL(url, {}) + content = resp.data + else: + resp, content = dao.getURL(url, {}) + + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + return json.loads(content) + + def search_spots(self, query_tuple): + """ + Returns a list of spots matching the passed parameters. + """ + + dao = SPOTSEEKER_DAO() + url = "/api/v1/spot?" + urlencode(query_tuple) + + if isinstance(dao._getDAO(), File): + resp = dao.getURL(url, {}) + content = resp.data + else: + resp, content = dao.getURL(url, {}) + + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + + results = json.loads(content) + + spots = [] + for res in results: + spots.append(self._spot_from_data(res)) + + return spots + + def all_spots(self): + """ + Returns a list of all spots. + """ + + dao = SPOTSEEKER_DAO() + url = "/api/v1/spot/all" + + if isinstance(dao._getDAO(), File): + resp = dao.getURL(url, {}) + content = resp.data + else: + resp, content = dao.getURL(url, {}) + + if resp.status != 200: + raise DataFailureException(url, resp.status, content) + + results = json.loads(content) + + spots = [] + for res in results: + spots.append(self._spot_from_data(res)) + + return spots + + def _spot_from_data(self, spot_data): + spot = Spot() + + spot.spot_id = spot_data["id"] + spot.name = spot_data["name"] + spot.uri = spot_data["uri"] + spot.latitude = spot_data["location"]["latitude"] + spot.longitude = spot_data["location"]["longitude"] + spot.height_from_sea_level = \ + spot_data["location"]["height_from_sea_level"] + spot.building_name = spot_data["location"]["building_name"] + spot.building_description = spot_data["location"].get("description", + None) + spot.floor = spot_data["location"]["floor"] + spot.room_number = spot_data["location"]["room_number"] + spot.capacity = spot_data["capacity"] + spot.display_access_restrictions = \ + spot_data["display_access_restrictions"] + spot.organization = spot_data["organization"] + spot.manager = spot_data["manager"] + spot.etag = spot_data["etag"] + spot.external_id = spot_data["external_id"] + + spot.last_modified = parse_datetime(spot_data["last_modified"]) + spot.spot_types = self._spot_types_from_data(spot_data["type"]) + + spot.spot_availability = \ + self._spot_availability_from_data(spot_data["available_hours"]) + spot.images = self._spot_images_from_data(spot_data["images"]) + spot.extended_info = \ + self._extended_info_from_data(spot_data["extended_info"]) + spot.items = [] + if "items" in spot_data and len(spot_data["items"]) > 0: + spot.items = self._items_from_data(spot_data["items"]) + + return spot + + def _items_from_data(self, item_data): + spot_items = [] + for item in item_data: + spot_item = SpotItem() + spot_item.item_id = item["id"] + spot_item.name = item["name"] + spot_item.category = item["category"] + spot_item.subcategory = item["subcategory"] + spot_item.images = [] + if "images" in item and len(item["images"]) > 0: + spot_item.images = self._item_images_from_data(item["images"]) + spot_item.extended_info = \ + self._extended_info_from_data(item["extended_info"]) + spot_items.append(spot_item) + return spot_items + + def _spot_types_from_data(self, type_data): + spot_types = [] + for spot_type in type_data: + spot_types.append(SpotType(name=spot_type)) + return spot_types + + def _spot_availability_from_data(self, avaliblity_data): + availability = [] + + for day in avaliblity_data: + for hours in avaliblity_data[day]: + available_hours = SpotAvailableHours() + available_hours.day = day + available_hours.start_time = parse_time(hours[0]) + available_hours.end_time = parse_time(hours[1]) + availability.append(available_hours) + return availability + + def _spot_images_from_data(self, image_data): + images = [] + + for image in image_data: + spot_image = SpotImage() + spot_image.image_id = image["id"] + spot_image.url = image["url"] + spot_image.description = image["description"] + spot_image.display_index = image["display_index"] + spot_image.content_type = image["content-type"] + spot_image.width = image["width"] + spot_image.height = image["height"] + spot_image.creation_date = parse_datetime(image["creation_date"]) + spot_image.modification_date = \ + parse_datetime(image["modification_date"]) + spot_image.upload_user = image["upload_user"] + spot_image.upload_application = image["upload_application"] + spot_image.thumbnail_root = image["thumbnail_root"] + + images.append(spot_image) + + return images + + def _item_images_from_data(self, image_data): + images = [] + + for image in image_data: + item_image = ItemImage() + item_image.image_id = image["id"] + item_image.url = image["url"] + item_image.description = image["description"] + item_image.display_index = image["display_index"] + item_image.content_type = image["content-type"] + item_image.width = image["width"] + item_image.height = image["height"] + item_image.creation_date = parse_datetime(image["creation_date"]) + item_image.upload_user = image["upload_user"] + item_image.upload_application = image["upload_application"] + item_image.thumbnail_root = image["thumbnail_root"] + + images.append(item_image) + + return images + + def _extended_info_from_data(self, info_data): + extended_info = [] + + for attribute in info_data: + spot_extended_info = SpotExtendedInfo(key=attribute, + value=info_data[attribute]) + extended_info.append(spot_extended_info) + return extended_info + + def get_item_image(self, parent_id, image_id, width=None): + return self._get_image("item", parent_id, image_id, width) + + def get_spot_image(self, parent_id, image_id, width=None): + return self._get_image("spot", parent_id, image_id, width) + + def _get_image(self, image_app_type, parent_id, image_id, width=None): + dao = SPOTSEEKER_DAO() + if width is not None: + url = "/api/v1/%s/%s/image/%s/thumb/constrain/width:%s" % ( + image_app_type, + parent_id, + image_id, + width) + else: + url = "/api/v1/%s/%s/image/%s" % (image_app_type, + parent_id, + image_id) + if isinstance(dao._getDAO(), File): + resp = dao.getURL(url, {}) + content = resp.data + else: + resp, content = dao.getURL(url, {}) + return resp, content diff --git a/spotseeker_restclient/test/__init__.py b/spotseeker_restclient/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/spotseeker_restclient/test/spot.py b/spotseeker_restclient/test/spot.py new file mode 100644 index 0000000000000000000000000000000000000000..fea3a7f8452bc5d2db86868d5380e431a3012a97 --- /dev/null +++ b/spotseeker_restclient/test/spot.py @@ -0,0 +1,144 @@ +from django.test import TestCase +from spotseeker_restclient.spotseeker import Spotseeker +from spotseeker_restclient.exceptions import DataFailureException +from django.utils.dateparse import parse_datetime, parse_time +from django.test.utils import override_settings + +DAO = "spotseeker_restclient.dao_implementation.spotseeker.File" + + +@override_settings(SPOTSEEKER_DAO_CLASS=DAO) +class SpotseekerTest(TestCase): + + def test_get_spot(self): + spot_client = Spotseeker() + + spot_data = spot_client.get_spot_by_id('123') + + self.assertEqual(spot_data.spot_id, "123") + self.assertEqual(spot_data.name, "Test Spot") + self.assertEqual(spot_data.uri, "/api/v1/spot/123") + self.assertEqual(spot_data.latitude, 3.60) + self.assertEqual(spot_data.longitude, 1.34) + self.assertEqual(spot_data.height_from_sea_level, 0.10) + self.assertEqual(spot_data.building_name, "Test Building") + self.assertEqual(spot_data.floor, 0) + self.assertEqual(spot_data.room_number, "456") + self.assertEqual(spot_data.capacity, 0) + self.assertEqual(spot_data.display_access_restrictions, "none") + self.assertEqual(spot_data.organization, "Test Org") + self.assertEqual(spot_data.manager, "Mr Test Org") + self.assertEqual(spot_data.etag, "686897696a7c876b7e") + self.assertEqual(spot_data.external_id, "asd123") + self.assertEqual(spot_data.last_modified, + parse_datetime("2012-07-13T05:00:00+00:00")) + + self.assertEqual(len(spot_data.images), 1) + self.assertEqual(spot_data.images[0].image_id, "1") + self.assertEqual(spot_data.images[0].url, + "/api/v1/spot/123/image/1") + self.assertEqual(spot_data.images[0].content_type, "image/jpeg") + self.assertEqual(spot_data.images[0].width, 0) + self.assertEqual(spot_data.images[0].height, 0) + self.assertEqual(spot_data.images[0].creation_date, + parse_datetime("Sun, 06 Nov 1994 08:49:37 GMT")) + self.assertEqual(spot_data.images[0].modification_date, + parse_datetime("Mon, 07 Nov 1994 01:49:37 GMT")) + self.assertEqual(spot_data.images[0].upload_user, + "user name") + self.assertEqual(spot_data.images[0].upload_application, + "application name") + self.assertEqual(spot_data.images[0].thumbnail_root, + "/api/v1/spot/123/image/1/thumb") + self.assertEqual(spot_data.images[0].description, + "Information about the image") + self.assertEqual(spot_data.images[0].display_index, 0) + + self.assertEqual(len(spot_data.spot_availability), 7) + + def test_spot_items(self): + spot_client = Spotseeker() + spot_data = spot_client.get_spot_by_id('1') + self.assertEqual(len(spot_data.items), 2) + item1 = spot_data.items[0] + self.assertEqual(item1.item_id, 796) + self.assertEqual(item1.name, "C-19074") + self.assertEqual(item1.category, "Digital Camera") + self.assertEqual(item1.subcategory, "") + self.assertEqual(len(item1.images), 1), + self.assertEqual(item1.images[0].image_id, 1), + + def test_bad_spot(self): + spot_client = Spotseeker() + self.assertRaises(DataFailureException, + spot_client.get_spot_by_id, 999) + + def test_search_spots(self): + """ Tests search_spots function with mock data provided in the + file named : spot?limit=5¢er_latitude=47.653811& + center_longitude=-122.307815&distance=100000& + fuzzy_hours_start=Tuesday%2C05%3A00&fuzzy_hours_end= + Tuesday%2C11%3A00&extended_info%3Aapp_type=food + tests mock data is accessible if filename matches order + of query_tuple passed. + """ + + spot_client = Spotseeker() + query_tuple = [ + ('limit', 5), ('center_latitude', u'47.653811'), + ('center_longitude', u'-122.307815'), + ('distance', 100000), + ('fuzzy_hours_start', 'Tuesday,05:00'), + ('fuzzy_hours_end', 'Tuesday,11:00'), + ('extended_info:app_type', 'food')] + + spot_data_list = spot_client.search_spots(query_tuple) + spot_data = spot_data_list[0] + + self.assertEqual(len(spot_data_list), 5) + self.assertEqual(spot_data.spot_id, 40) + self.assertEqual(spot_data.name, "TestSpot1") + self.assertEqual(spot_data.uri, "/api/v1/spot/40") + self.assertEqual(spot_data.latitude, 47) + self.assertEqual(spot_data.longitude, -12) + self.assertEqual(spot_data.height_from_sea_level, 0.10) + self.assertEqual(spot_data.building_name, "TestBuilding") + self.assertEqual(spot_data.capacity, 0) + self.assertEqual(spot_data.organization, "Test Org") + self.assertEqual(spot_data.manager, "Test Manager") + self.assertEqual(spot_data.etag, "123456789") + self.assertEqual(spot_data.last_modified, + parse_datetime("2012-07-13T05:00:00+00:00")) + + self.assertEqual(len(spot_data.images), 1) + self.assertEqual(spot_data.images[0].image_id, "1") + self.assertEqual(spot_data.images[0].url, + "/api/v1/spot/123/image/1") + self.assertEqual(spot_data.images[0].content_type, "image/jpeg") + self.assertEqual(spot_data.images[0].width, 0) + self.assertEqual(spot_data.images[0].height, 0) + self.assertEqual(spot_data.images[0].creation_date, + parse_datetime("Sun, 06 Nov 1994 08:49:37 GMT")) + self.assertEqual(spot_data.images[0].modification_date, + parse_datetime("Mon, 07 Nov 1994 01:49:37 GMT")) + self.assertEqual(spot_data.images[0].upload_user, + "user name") + self.assertEqual(spot_data.images[0].upload_application, + "application name") + self.assertEqual(spot_data.images[0].thumbnail_root, + "/api/v1/spot/123/image/1/thumb") + self.assertEqual(spot_data.images[0].description, + "Information about the image") + self.assertEqual(spot_data.images[0].display_index, 0) + + self.assertEqual(len(spot_data.spot_availability), 5) + + def test_building_list(self): + spot_client = Spotseeker() + buildings = spot_client.get_building_list("seattle") + self.assertEqual(len(buildings), 43) + + def test_get_all_spots(self): + spot_client = Spotseeker() + spots = spot_client.all_spots() + self.assertEqual(len(spots), 3) diff --git a/spotseeker_restclient/tests.py b/spotseeker_restclient/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..aed2c7d71b737cff70eeee55c5831eb6e773c37d --- /dev/null +++ b/spotseeker_restclient/tests.py @@ -0,0 +1,3 @@ +from django.utils import unittest + +from spotseeker_restclient.test.spot import SpotseekerTest diff --git a/spotseeker_restclient/views.py b/spotseeker_restclient/views.py new file mode 100644 index 0000000000000000000000000000000000000000..91ea44a218fbd2f408430959283f0419c921093e --- /dev/null +++ b/spotseeker_restclient/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/travis-ci/__init__.py b/travis-ci/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/travis-ci/manage.py b/travis-ci/manage.py new file mode 100644 index 0000000000000000000000000000000000000000..5c3018effb9c8e3ba52bd988c4e9a3befa3a573c --- /dev/null +++ b/travis-ci/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "travis-ci.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/travis-ci/settings.py b/travis-ci/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..4d1dea87dbf28a718431832a6bbfb7c85f0721f1 --- /dev/null +++ b/travis-ci/settings.py @@ -0,0 +1,97 @@ +""" +Django settings for project project. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.7/ref/settings/ +""" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +import os +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +TEMPLATE_DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'spotseeker_restclient' +) + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.RemoteUserMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.RemoteUserBackend', +) + +ROOT_URLCONF = 'travis-ci.urls' + +WSGI_APPLICATION = 'travis-ci.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.7/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + +# Internationalization +# https://docs.djangoproject.com/en/1.7/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'America/Los_Angeles' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.7/howto/static-files/ + +STATIC_URL = '/static/' + +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', + # 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +COMPRESS_ENABLED = False diff --git a/travis-ci/urls.py b/travis-ci/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..034813207ffd49d881578c95239887a1149e4e71 --- /dev/null +++ b/travis-ci/urls.py @@ -0,0 +1,8 @@ +from django.conf.urls import patterns, include, url +from django.contrib import admin + +urlpatterns = patterns('', + # Examples: + # url(r'^$', 'project.views.home', name='home'), + # url(r'^blog/', include('blog.urls')), +) diff --git a/travis-ci/wsgi.py b/travis-ci/wsgi.py new file mode 100644 index 0000000000000000000000000000000000000000..bf88c8804fe3dc3c9cb9a6e37109b6c04909a8f2 --- /dev/null +++ b/travis-ci/wsgi.py @@ -0,0 +1,14 @@ +""" +WSGI config for project project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ +""" + +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "travis-ci.settings") + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application()