def lodge_reportingsystem(): """Insert a ReportingSystem into the provenance _database""" # only accept RDF documents acceptable_mimes = LDAPI.get_rdf_mimetypes_list() ct = request.content_type if ct not in acceptable_mimes: return api_functions.client_error_response( 'The ReportingSystem posted is not encoded with a valid RDF Content-Type. Must be one of: ' + ', '.join(acceptable_mimes) + '.') # validate ReportingSystem rs = class_reportingsystems.IncomingReportingSystem(request) if not rs.valid(): return api_functions.client_error_response( 'The ReportingSystem posted is not valid for the following reasons: ' + ', '.join(rs.error_messages) + '.') # get the ReportingSystem's URI rs.determine_uri() rs.generate_named_graph_metadata() # store the ReportingSystem if not rs.stored(): return api_functions.server_error_response( 'ReportingSystem posted is valid but cannot be stored for the following reasons: ' + ', '.join(rs.error_messages) + '.') # reply to sender return Response(rs.uri, status=201, mimetype='text/plain')
def lodge_agent(): """Insert an Agent into the provenance _database""" # only accept RDF documents acceptable_mimes = LDAPI.get_rdf_mimetypes_list() ct = request.content_type if ct not in acceptable_mimes: return api_functions.client_error_response( 'The Agent posted is not encoded with a valid RDF Content-Type. Must be one of: ' + ', '.join(acceptable_mimes) + '.') # validate Agent sr = class_agents.IncomingAgent(request.data, request.content_type) if not sr.valid(): return api_functions.client_error_response( 'The Agent posted is not valid for the following reasons: ' + ', '.join(sr.error_messages) + '.') # get the Agent's URI sr.determine_uri() # store the Agent if not sr.stored(): return api_functions.server_error_response( 'The Agent posted is valid but cannot be stored for the following reasons: ' + ', '.join(sr.error_messages) + '.') # reply to sender return Response(sr.uri, status=201, mimetype='text/plain')
def render(self, view, mimetype): if view == 'neighbours': if mimetype in LDAPI.get_rdf_mimetypes_list(): return self._neighbours_rdf(mimetype) elif mimetype == 'text/html': self._get_details() return self._neighbours_html() elif view == 'prov': if mimetype in LDAPI.get_rdf_mimetypes_list(): return Response(self._prov_rdf().serialize( format=LDAPI.get_rdf_parser_for_mimetype(mimetype)), status=200, mimetype=mimetype) elif mimetype == 'text/html': self._get_details() return self._prov_html()
def render(self, view, mimetype): if view == 'neighbours': # no work to be done as we have already loaded the triples if mimetype in LDAPI.get_rdf_mimetypes_list(): return self._neighbours_rdf(mimetype) elif mimetype == 'text/html': self._get_details() return self._neighbours_html() elif view == 'prov': if mimetype in LDAPI.get_rdf_mimetypes_list(): return Response(self._prov_rdf().serialize( format=LDAPI.get_rdf_parser_for_mimetype(mimetype)), status=200, mimetype=mimetype) # TODO: pre-render the viz.js image and serve static image # elif mimetype == 'image/svg': # return Response( # # ) elif mimetype == 'text/html': self._get_details() return self._prov_html()
def lodge_report(): """Insert a Report into the provenance database This function should be edited if any custom actions are to be undertaken by PROMS on reciept of a Report, such as Ppingbacks """ # only accept RDF documents acceptable_mimes = LDAPI.get_rdf_mimetypes_list() ct = request.content_type if ct not in acceptable_mimes: return api_functions.client_error_response( 'The Report posted is not encoded with a valid RDF Content-Type. Must be one of: ' + ', '.join(acceptable_mimes) + '.') # validate Report, using the controller validator class, IncomingReport r = class_reports.IncomingReport(request) if not r.valid(): return api_functions.client_error_response( 'The Report posted is not valid for the following reasons: ' + ', '.join(r.error_messages) + '.') # generate Named Graph metadata r.determine_uri() r.generate_named_graph_metadata() # store the Report # since it is valid and NG metadata has been built, we can store it if not r.stored(): return api_functions.server_error_response( 'Report posted is valid but cannot be stored for the following reasons: ' + ', '.join(r.error_messages) + '.') # Custom Actions # Only try to any custom actions, e.g. Pingbacks, if the module is turned on if conf.MODULES.get('pingbacks').get('valid'): # kick off any Pingbacks for this Report, as per chosen Pingbacks strategies # TODO: split Pingbacks process off into another thread from modules.pingbacks.engine import Engine e = Engine(r.graph, r.uri, url_for('modelx.instance'), url_for('.sparql')) # reply to sender return r.uri, 201
def render(self, view, mimetype): if view == 'reg': # is an RDF format requested? if mimetype in LDAPI.get_rdf_mimetypes_list(): # it is an RDF format so make the graph for serialization self._make_dpr_graph(view) rdflib_format = LDAPI.get_rdf_parser_for_mimetype(mimetype) return Response(self.g.serialize(format=rdflib_format), status=200, mimetype=mimetype) elif mimetype == 'text/html': return render_template( 'class_register.html', class_name=self.request.args.get('_uri'), register=self.register) else: return Response( 'The requested model model is not valid for this class', status=400, mimetype='text/plain')
def lodge_report(): """Insert a Report into the provenance database""" # only accept RDF documents acceptable_mimes = LDAPI.get_rdf_mimetypes_list() ct = request.content_type if ct not in acceptable_mimes: return api_functions.client_error_response( 'The Report posted is not encoded with a valid RDF Content-Type. Must be one of: ' + ', '.join(acceptable_mimes) + '.') # validate Report r = class_reports.IncomingReport(request) print(str(r)) if not r.valid(): return api_functions.client_error_response( 'The Report posted is not valid for the following reasons: ' + ', '.join(r.error_messages) + '.') # get the Report's URI r.determine_uri() r.generate_named_graph_metadata() # store the Report if not r.stored(): return api_functions.server_error_response( 'Report posted is valid but cannot be stored for the following reasons: ' + ', '.join(r.error_messages) + '.') # kick off any Pingbacks for this Report, as per chosen Pingbacks strategies # TODO: split this off into another thread from modules.pingbacks.engine import Engine e = Engine(r.graph, r.uri, url_for('modelx.instance'), url_for('.sparql')) # reply to sender return r.uri, 201
def render_alternates_view(class_uri, class_uri_encoded, instance_uri, instance_uri_encoded, views_formats, mimetype): """Renders an HTML table, a JSON object string or a serialised RDF representation of the alternate views of an object""" if mimetype == 'application/json': del views_formats[ 'renderer'] # the renderer used is not for public consumption! return Response(json.dumps(views_formats), status=200, mimetype='application/json') elif mimetype in LDAPI.get_rdf_mimetypes_list(): g = Graph() LDAPI_O = Namespace('http://promsns.org/def/ldapi#') g.bind('ldapi', LDAPI_O) DCT = Namespace('http://purl.org/dc/terms/') g.bind('dct', DCT) class_uri_ref = URIRef(uriparse.unquote_plus(class_uri)) if instance_uri: instance_uri_ref = URIRef(instance_uri) g.add((instance_uri_ref, RDF.type, class_uri_ref)) else: g.add((class_uri_ref, RDF.type, LDAPI_O.ApiResource)) # alternates model alternates_view = BNode() g.add((alternates_view, RDF.type, LDAPI_O.View)) g.add((alternates_view, DCT.title, Literal('alternates', datatype=XSD.string))) g.add((class_uri_ref, LDAPI_O.view, alternates_view)) # default model default_view = BNode() g.add((default_view, DCT.title, Literal('default', datatype=XSD.string))) g.add((class_uri_ref, LDAPI_O.defaultView, default_view)) default_title = views_formats['default'] # the ApiResource is incorrectly assigned to the class URI for view_name, formats in views_formats.items(): if view_name == 'alternates': for f in formats: g.add((alternates_view, URIRef('http://purl.org/dc/terms/format'), Literal(f, datatype=XSD.string))) elif view_name == 'default': pass elif view_name == 'renderer': pass else: x = BNode() if view_name == default_title: g.add((default_view, RDF.type, x)) g.add((class_uri_ref, LDAPI_O.view, x)) g.add((x, DCT.title, Literal(view_name, datatype=XSD.string))) for f in formats: g.add((x, URIRef('http://purl.org/dc/terms/format'), Literal(f, datatype=XSD.string))) rdflib_format = [ item[1] for item in LDAPI.MIMETYPES_PARSERS if item[0] == mimetype ][0] return Response(g.serialize(format=rdflib_format), status=200, mimetype=mimetype) else: # HTML return render_template('alternates_view.html', class_uri=class_uri, class_uri_encoded=class_uri_encoded, instance_uri=instance_uri, instance_uri_encoded=instance_uri_encoded, views_formats=views_formats)
class IncomingPingback(IncomingClass): acceptable_mimes = LDAPI.get_rdf_mimetypes_list() + ['text/uri-list'] def __init__(self, request): IncomingClass.__init__(self, request) self.pingback_endpoint = request.url self.determine_uri() self._generate_named_graph_uri() def valid(self): """Validates an incoming Pingback using direct tests using the Pingbacks RuleSet""" # PROV Pingbacks can only be of mimtype text/uri-list if self.request.mimetype == 'text/uri-list': print((self.request.headers)) conformant_pingback = ProvPingback(self.request) # ensure that this Pingback has the URI(s) of the Resource(s) it is for if self.request.args.get('resource_uri') is None: error_message = 'No resource URI is indicated for this pingback. Pingbacks sent to a PROMS Server ' \ 'instance must be posted to ' \ 'http://{POROMS_INTANCE}/function/lodge-pingback?resource_uri={RESOURCE_URI}' if self.error_messages is not None: self.error_messages.append(error_message) else: self.error_messages = [error_message] return False elif not LDAPI.is_a_uri(self.request.args.get('resource_uri')): error_message = 'The resource URI indicated for this pingback does not validate as a URI' if self.error_messages is not None: self.error_messages.append(error_message) else: self.error_messages = [error_message] return False # PROMS Pingbacks can only be of an RDF mimetype else: conformant_pingback = PromsPingback(self.request, self.pingback_endpoint) if not conformant_pingback.passed: self.error_messages = conformant_pingback.fail_reasons return False return True def determine_uri(self): pass # no need for this! def _generate_named_graph_uri(self): self.named_graph_uri = settings.PINGBACK_NAMED_GRAPH_BASE_URI + str(uuid.uuid4()) def convert_pingback_to_rdf(self): # the URI of the Named Graph for this Pingback must have been generated before doing this # so we can refer to the graph if self.named_graph_uri is not None: self.graph = Graph() # PROV Pingbacks can only be of mimtype text/uri-list if self.request.mimetype == 'text/uri-list': self._convert_prov_pingback_to_rdf() # PROMS Pingbacks can only be of an RDF mimetype else: self._convert_proms_pingback_to_rdf() else: raise Exception('The Incoming Pingback must have had a URI generated for it by PROMS Server before the data' 'for it is stored. The function determine_uri() generated the URI.') def _convert_prov_pingback_to_rdf(self): # every URI in the PROV-AQ message is treated as a provenance statement about the resource PROV = Namespace('http://www.w3.org/ns/prov#') self.graph.bind('prov', PROV) for uri_line in self.request.data.split('\n'): self.graph.add(( URIRef(self.request.args.get('resource_uri')), PROV.has_provenance, URIRef(uri_line) )) # if there are Link headers about other resources, create DCT provenance indicators for them too if self.request.headers.get('Link'): for link_header in self.request.headers.get('Link').split(','): uri, rel, anchor = link_header.split(';') self.graph.add(( URIRef(uri.strip('<>')), URIRef(rel.strip().replace('rel=', '').strip('"')), URIRef(anchor.strip().replace('anchor=', '').strip('"')) )) def _convert_proms_pingback_to_rdf(self): PROMS = Namespace('http://promsns.org/def/proms#') self.graph.bind('proms', PROMS) # type this pingback specifically self.graph.add(( URIRef(self.named_graph_uri), RDF.type, PROMS.PromsPingback )) # convert the data to RDF (just de-serialise it) self.graph += Graph().parse( data=self.request.data, format=LDAPI.get_rdf_parser_for_mimetype(self.request.mimetype) ) def generate_named_graph_metadata(self): # add graph metadata, regardless of the type of Pingback PROV = Namespace('http://www.w3.org/ns/prov#') self.graph.bind('prov', PROV) PROMS = Namespace('http://promsns.org/def/proms#') self.graph.bind('proms', PROMS) DCT = Namespace('http://purl.org/dc/terms/') self.graph.bind('dct', DCT) # ... the date this Pingback was sent to this PROMS Server self.graph.add(( URIRef(self.named_graph_uri), DCT.dateSubmitted, Literal(datetime.now().isoformat(), datatype=XSD.dateTime) )) # ... who contributed this Pingback self.graph.add(( URIRef(self.named_graph_uri), DCT.contributor, URIRef(self.request.remote_addr) )) # TODO: add other useful metadata variables gleaned from the HTTP message headers # PROV Pingbacks can only be of mimtype text/uri-list if self.request.mimetype == 'text/uri-list': self._generate_prov_pingback_named_graph_metadata() else: self._generate_proms_pingback_named_graph_metadata() def _generate_prov_pingback_named_graph_metadata(self): PROMS = Namespace('http://promsns.org/def/proms#') self.graph.bind('proms', PROMS) # type this pingback specifically self.graph.add(( URIRef(self.named_graph_uri), RDF.type, PROMS.ProvAqPingbackNamedGraph )) def _generate_proms_pingback_named_graph_metadata(self): PROMS = Namespace('http://promsns.org/def/proms#') self.graph.bind('proms', PROMS) # type this pingback specifically self.graph.add(( URIRef(self.named_graph_uri), RDF.type, PROMS.PromsPingbackNamedGraph ))