def run(): tagValues = SecureTagValueAPI(session.auth.user) try: result = tagValues.get([objectID], [path]) except PermissionDeniedError as error: session.log.exception(error) path_, operation = error.pathsAndOperations[0] raise TNonexistentTag(path_) except UnknownPathError as error: session.log.exception(error) raise TNonexistentTag(path) if not result: raise TNoInstanceOnObject(path, objectId) else: tagValue = result[objectID][path] value = tagValue.value # FIXME This is a bit crap, but its easier than modifying # Thrift-related logic. if isinstance(value, dict): mimeType = value['mime-type'].encode('utf-8') value = createBinaryThriftValue(value['contents'], mimeType) elif isinstance(value, UUID): value = createThriftValue(str(value)) else: value = createThriftValue(value) return (value, tagValue)
def _parseOldPayloadDict(cls, tagValueDict): """ Get a list of Tag/Value pairs from a given payload dictionary. @param tagValueDict: A payload C{dict} representing the tag/value pairs. @return: A list of L{TagPathAndValue} objects. """ # tagsAndValues is what we'll pass to the facade to # indicate what values to put on the objects that match the query. tagsAndValues = [] # Check the JSON tag/value specification to make sure all values # are primitive types we know how to handle. # FIXME: we could use a JSON schema library to facilitate this. for tag in tagValueDict: try: value = tagValueDict[tag][valueKey] except TypeError: # requestTagValueDict[tag] is not a dict. raise error.InvalidPayloadField(tag) except KeyError: # valueKey not present in requestTagValueDict[tag]. raise error.PayloadFieldMissing(valueKey) valueType = type(value) if valueType in (bool, int, float, unicode, types.NoneType): # This is a valid primitive type. Nothing to do. tvalue = createThriftValue(value) elif valueType is list: # Make sure we have a list of strings. strlist = [] for s in value: if isinstance(s, unicode): s = s.encode('utf-8') elif not isinstance(s, str): raise error.UnsupportedJSONType() strlist.append(s) tvalue = createThriftValue(strlist) else: raise error.UnsupportedJSONType() tagsAndValues.append(TagPathAndValue(tag, tvalue)) return tagsAndValues
def _parseOldPayloadDict(cls, tagValueDict): """ Get a list of Tag/Value pairs from a given payload dictionary. @param tagValueDict: A payload C{dict} representing the tag/value pairs. @return: A list of L{TagPathAndValue} objects. """ # tagsAndValues is what we'll pass to the facade to # indicate what values to put on the objects that match the query. tagsAndValues = [] # Check the JSON tag/value specification to make sure all values # are primitive types we know how to handle. # FIXME: we could use a JSON schema library to facilitate this. for tag in tagValueDict: try: value = tagValueDict[tag][valueKey] except TypeError: # requestTagValueDict[tag] is not a dict. raise error.InvalidPayloadField(tag) except KeyError: # valueKey not present in requestTagValueDict[tag]. raise error.PayloadFieldMissing(valueKey) valueType = type(value) if valueType in (bool, int, float, unicode, types.NoneType): # This is a valid primitive type. Nothing to do. tvalue = createThriftValue(value) elif valueType is list: # Make sure we have a list of strings. strlist = [] for s in value: if isinstance(s, unicode): s = s.encode('utf-8') elif not isinstance(s, str): raise error.UnsupportedJSONType() strlist.append(s) tvalue = createThriftValue(strlist) else: raise error.UnsupportedJSONType() tagsAndValues.append(TagPathAndValue(tag, tvalue)) return tagsAndValues
def run(): tagValues = SecureTagValueAPI(session.auth.user) try: values = tagValues.get([objectID], [path]) return createThriftValue(len(values.keys()) > 0) except UnknownPathError as error: session.log.exception(error) raise TNonexistentTag(path.encode('utf-8')) except PermissionDeniedError as error: session.log.exception(error) path_, operation = error.pathsAndOperations[0] raise TNonexistentTag(path_)
def deferred_render_PUT(self, request): """ The following code is reproduced almost verbatim in deferred_render_PUT in about.py. So if you change this code, you'll likely need to change that, and vice versa. """ usage = registry.findUsage(httpObjectCategoryName, 'PUT', TagInstanceResource) payload = registry.checkRequest(usage, request) contentType = request.getHeader('content-type') if contentType is None: if payload is None: contentTypeFirstComponent = contentTypeForPrimitiveJSON else: raise error.NoContentTypeHeader() else: # Get the lowercased first component of the content type, as # split by semicolon (the HTTP standard for separating the # content type from other tags, such as charset). # # Doing it this way allows us to ignore any other crud in the # content-type, for example a charset, when the content type is # our own contentTypeForPrimitiveJSON. See # https://oodl.es/trac/fluiddb/ticket/572 and the # testPrimitiveTypesWithCharsetAlsoInContentType test in # integration/wsfe/test_tagValues.py for more details # # We only need to rstrip the first component of the content # type as twisted.web does a strip on the whole header value # (so the left side is already stripped). contentTypeFirstComponent = \ contentType.split(';')[0].lower().rstrip() if contentTypeFirstComponent == contentTypeForPrimitiveJSON: if payload is None: value = None else: value = payloads.parseJSONPayload(payload) tv = type(value) if tv in (bool, int, float, unicode, types.NoneType): tvalue = createThriftValue(value) elif tv is list: strlist = [] for s in value: if isinstance(s, unicode): s = s.encode("utf-8") elif not isinstance(s, str): raise error.UnsupportedJSONType() strlist.append(s) tvalue = createThriftValue(strlist) else: raise error.UnsupportedJSONType() else: tvalue = createBinaryThriftValue(payload, contentType) # log.msg("PUT: tvalue is %r" % tvalue) yield self.facadeClient.setTagInstance( self.session, self.path, self.objectId, tvalue) request.setResponseCode(usage.successCode) defer.returnValue(None)
def testRatingForObjectAboutBarcelona(self): """ Run a series of tests on the ntoll/rating tag on the object about barcelona: - the tag should initially not be present. - we should successfully be able to do a PUT. - we should then be able to do a GET, HEAD, and DELETE in that order. - a final GET should then indicate the tag is gone. """ about = 'barcelona' tag = 'ntoll/rating' rating = 6 objectIdAboutBarcelona = util.generateObjectId() fakeQueryResolver = FakeQueryResolver(about, [objectIdAboutBarcelona], self) fakeTagsClient = FakeTagsClient() facadeClient = FakeFacadeClient(fakeTagsClient=fakeTagsClient, fakeQueryResolver=fakeQueryResolver) session = FakeSession() resource = AboutTagInstanceResource(facadeClient, session, about, tag) # Test GET when there is no instance on the object. d = defer.Deferred() request = FakeRequest('GET', d) request.content = StringIO.StringIO() resource.render(request) yield d self.assertEqual(request.status, http.NOT_FOUND) # Test PUT. payload = json.dumps(rating) headers = { 'Content-Length': [str(len(payload))], 'Content-Type': [contentTypeForPrimitiveJSON], } d = defer.Deferred() request = FakeRequest('PUT', d, headers) request.content = StringIO.StringIO(payload) resource.render(request) yield d self.assertEqual(request.status, http.NO_CONTENT) self.assertEqual( guessValue(fakeTagsClient.values[tag][objectIdAboutBarcelona]), rating) # Check that the right path, objectId, and value was passed to the # fake tags client. self.assertEqual(fakeTagsClient.values, { tag: { objectIdAboutBarcelona: createThriftValue(rating) }, }) # Test GET. d = defer.Deferred() request = FakeRequest('GET', d) request.content = StringIO.StringIO() resource.render(request) body = yield d self.assertEqual(request.status, http.OK) self.assertEqual(request.getResponseHeader('Content-Type'), contentTypeForPrimitiveJSON) receivedRating = json.loads(body) self.assertEqual(receivedRating, rating) # Test HEAD d = defer.Deferred() request = FakeRequest('HEAD', d) request.content = StringIO.StringIO() resource.render(request) body = yield d self.assertEqual(request.status, http.OK) self.assertEqual(body, '') # Test DELETE d = defer.Deferred() request = FakeRequest('DELETE', d) request.content = StringIO.StringIO() resource.render(request) body = yield d self.assertEqual(request.status, http.NO_CONTENT) # Test GET when, finally, there is no instance on the object. d = defer.Deferred() request = FakeRequest('GET', d) request.content = StringIO.StringIO() resource.render(request) yield d self.assertEqual(request.status, http.NOT_FOUND) # Check that the value really was deleted. self.assertEqual(fakeTagsClient.values, {tag: {}})
def testRatingForObjectAboutBarcelona(self): """ Run a series of tests on the ntoll/rating tag on the object about barcelona: - the tag should initially not be present. - we should successfully be able to do a PUT. - we should then be able to do a GET, HEAD, and DELETE in that order. - a final GET should then indicate the tag is gone. """ about = 'barcelona' tag = 'ntoll/rating' rating = 6 objectIdAboutBarcelona = util.generateObjectId() fakeQueryResolver = FakeQueryResolver( about, [objectIdAboutBarcelona], self) fakeTagsClient = FakeTagsClient() facadeClient = FakeFacadeClient(fakeTagsClient=fakeTagsClient, fakeQueryResolver=fakeQueryResolver) session = FakeSession() resource = AboutTagInstanceResource(facadeClient, session, about, tag) # Test GET when there is no instance on the object. d = defer.Deferred() request = FakeRequest('GET', d) request.content = StringIO.StringIO() resource.render(request) yield d self.assertEqual(request.status, http.NOT_FOUND) # Test PUT. payload = json.dumps(rating) headers = { 'Content-Length': [str(len(payload))], 'Content-Type': [contentTypeForPrimitiveJSON], } d = defer.Deferred() request = FakeRequest('PUT', d, headers) request.content = StringIO.StringIO(payload) resource.render(request) yield d self.assertEqual(request.status, http.NO_CONTENT) self.assertEqual( guessValue(fakeTagsClient.values[tag][objectIdAboutBarcelona]), rating) # Check that the right path, objectId, and value was passed to the # fake tags client. self.assertEqual(fakeTagsClient.values, { tag: {objectIdAboutBarcelona: createThriftValue(rating)}, }) # Test GET. d = defer.Deferred() request = FakeRequest('GET', d) request.content = StringIO.StringIO() resource.render(request) body = yield d self.assertEqual(request.status, http.OK) self.assertEqual(request.getResponseHeader('Content-Type'), contentTypeForPrimitiveJSON) receivedRating = json.loads(body) self.assertEqual(receivedRating, rating) # Test HEAD d = defer.Deferred() request = FakeRequest('HEAD', d) request.content = StringIO.StringIO() resource.render(request) body = yield d self.assertEqual(request.status, http.OK) self.assertEqual(body, '') # Test DELETE d = defer.Deferred() request = FakeRequest('DELETE', d) request.content = StringIO.StringIO() resource.render(request) body = yield d self.assertEqual(request.status, http.NO_CONTENT) # Test GET when, finally, there is no instance on the object. d = defer.Deferred() request = FakeRequest('GET', d) request.content = StringIO.StringIO() resource.render(request) yield d self.assertEqual(request.status, http.NOT_FOUND) # Check that the value really was deleted. self.assertEqual(fakeTagsClient.values, {tag: {}})
def deferred_render_PUT(self, request): """ PUT a tag value onto an object. Return a Deferred that fires with None when the tag value has been set by the facade. This code, apart from the yield self._setObjectId(), is taken verbatim from deferred_render_PUT in objects.py. So if you change this code, you'll likely need to change that, and vice versa. @param request: The HTTP request. @return: A C{Deferred} that fires with C{None} once the request has completed. """ usage = registry.findUsage(httpAboutCategoryName, 'PUT', AboutTagInstanceResource) payload = registry.checkRequest(usage, request) contentType = request.getHeader('content-type') if contentType is None: if payload is None: contentType = contentTypeForPrimitiveJSON else: raise error.NoContentTypeHeader() else: contentType = contentType.lower() if contentType == contentTypeForPrimitiveJSON: if payload is None: value = None else: value = payloads.parseJSONPayload(payload) tv = type(value) if tv in (bool, int, float, unicode, types.NoneType): tvalue = createThriftValue(value) elif tv is list: strlist = [] for s in value: if isinstance(s, unicode): s = s.encode("utf-8") elif not isinstance(s, str): raise error.UnsupportedJSONType() strlist.append(s) tvalue = createThriftValue(strlist) else: raise error.UnsupportedJSONType() else: tvalue = createBinaryThriftValue(payload, contentType) try: yield self._setObjectId() except error.NoSuchObject: # There is no object with this about value. So we create it. # This is consistent with /objects, which doesn't require an # object id to have been returned from createObject in order # for people to PUT tag values onto it. self.objectId = yield self.facadeClient.createObject( session=self.session, about=self.about) yield self.facadeClient.setTagInstance(self.session, self.path, self.objectId, tvalue) request.setResponseCode(usage.successCode) defer.returnValue(None)
def deferred_render_PUT(self, request): """ PUT a tag value onto an object. Return a Deferred that fires with None when the tag value has been set by the facade. This code, apart from the yield self._setObjectId(), is taken verbatim from deferred_render_PUT in objects.py. So if you change this code, you'll likely need to change that, and vice versa. @param request: The HTTP request. @return: A C{Deferred} that fires with C{None} once the request has completed. """ usage = registry.findUsage(httpAboutCategoryName, 'PUT', AboutTagInstanceResource) payload = registry.checkRequest(usage, request) contentType = request.getHeader('content-type') if contentType is None: if payload is None: contentType = contentTypeForPrimitiveJSON else: raise error.NoContentTypeHeader() else: contentType = contentType.lower() if contentType == contentTypeForPrimitiveJSON: if payload is None: value = None else: value = payloads.parseJSONPayload(payload) tv = type(value) if tv in (bool, int, float, unicode, types.NoneType): tvalue = createThriftValue(value) elif tv is list: strlist = [] for s in value: if isinstance(s, unicode): s = s.encode("utf-8") elif not isinstance(s, str): raise error.UnsupportedJSONType() strlist.append(s) tvalue = createThriftValue(strlist) else: raise error.UnsupportedJSONType() else: tvalue = createBinaryThriftValue(payload, contentType) try: yield self._setObjectId() except error.NoSuchObject: # There is no object with this about value. So we create it. # This is consistent with /objects, which doesn't require an # object id to have been returned from createObject in order # for people to PUT tag values onto it. self.objectId = yield self.facadeClient.createObject( session=self.session, about=self.about) yield self.facadeClient.setTagInstance( self.session, self.path, self.objectId, tvalue) request.setResponseCode(usage.successCode) defer.returnValue(None)
def getTagInstance(self, session, path, objectId): """ Returns an object previously stored in C{values}. """ tvalue = createThriftValue(self.values[objectId][path]) return defer.succeed((tvalue, None))
def __init__(self, path=None, value=None): if not isinstance(value, ThriftValue): value = createThriftValue(value) self.path = path self.value = value
def deferred_render_PUT(self, request): """ The following code is reproduced almost verbatim in deferred_render_PUT in about.py. So if you change this code, you'll likely need to change that, and vice versa. """ usage = registry.findUsage(httpObjectCategoryName, 'PUT', TagInstanceResource) payload = registry.checkRequest(usage, request) contentType = request.getHeader('content-type') if contentType is None: if payload is None: contentTypeFirstComponent = contentTypeForPrimitiveJSON else: raise error.NoContentTypeHeader() else: # Get the lowercased first component of the content type, as # split by semicolon (the HTTP standard for separating the # content type from other tags, such as charset). # # Doing it this way allows us to ignore any other crud in the # content-type, for example a charset, when the content type is # our own contentTypeForPrimitiveJSON. See # https://oodl.es/trac/fluiddb/ticket/572 and the # testPrimitiveTypesWithCharsetAlsoInContentType test in # integration/wsfe/test_tagValues.py for more details # # We only need to rstrip the first component of the content # type as twisted.web does a strip on the whole header value # (so the left side is already stripped). contentTypeFirstComponent = \ contentType.split(';')[0].lower().rstrip() if contentTypeFirstComponent == contentTypeForPrimitiveJSON: if payload is None: value = None else: value = payloads.parseJSONPayload(payload) tv = type(value) if tv in (bool, int, float, unicode, types.NoneType): tvalue = createThriftValue(value) elif tv is list: strlist = [] for s in value: if isinstance(s, unicode): s = s.encode("utf-8") elif not isinstance(s, str): raise error.UnsupportedJSONType() strlist.append(s) tvalue = createThriftValue(strlist) else: raise error.UnsupportedJSONType() else: tvalue = createBinaryThriftValue(payload, contentType) # log.msg("PUT: tvalue is %r" % tvalue) yield self.facadeClient.setTagInstance(self.session, self.path, self.objectId, tvalue) request.setResponseCode(usage.successCode) defer.returnValue(None)