import requests
from wtforms.validators import InputRequired, Email, URL, Length, EqualTo, \
Optional
from wtforms import ValidationError
from rdfframework import RdfDataType, get_framework as rdfw
from rdfframework.utilities import make_triple, iri, clean_iri, fw_config,\
make_list, uri
__author__ = "Mike Stabile, Jeremy Nelson"
[docs]class UniqueValue(object):
''' a custom validator for use with wtforms
* checks to see if the value already exists in the triplestore'''
def __init__(self, message=None):
if not message:
message = u'The field must be a unique value'
self.message = message
def __call__(self, form, field):
# get the test query
debug = True
_sparql = self._make_unique_value_qry(form, field)
if debug: print(_sparql)
# run the test query
_unique_test_results = requests.post(\
fw_config().get('TRIPLESTORE_URL'),
data={"query": _sparql, "format": "json"})
_unique_test = _unique_test_results.json().get('results').get( \
'bindings', [])
# evaluate the results; True result in the query denotes that the
# value already exists
if len(_unique_test) > 0:
_unique_test = _unique_test[0].get(\
'uniqueValueViolation', {}).get('value', False)
else:
_unique_test = False
if _unique_test:
raise ValidationError(self.message)
def _make_unique_value_qry(self, form, field):
debug = False
_sparql_args = []
# determine the property and class details of the field
_prop_uri = field.kds_propUri
_class_uri = field.kds_classUri
_range = field.rdfs_range
# make the base triples for the query
if _prop_uri:
_data_value = RdfDataType(None,
class_uri=_class_uri,
prop_uri=_prop_uri).sparql(field.data)
_sparql_args.append(make_triple("?uri", "a", iri(uri(_class_uri))))
_sparql_args.append(make_triple("?uri",
iri(uri(_prop_uri)),
_data_value))
# see if the form is based on a set of triplestore data. if it is
# remove that triple from consideration in the query
if hasattr(form, "data_subject_uri"):
_subject_uri = form.data_subject_uri
_lookup_class_uri = form.data_class_uri
# if the subject class is the same as the field class
if _lookup_class_uri == _class_uri and _subject_uri:
_sparql_args.append("FILTER(?uri!={}) .".format(\
iri(_subject_uri)))
if debug: x=y
# If not need to determine how the subject is related to the field
# property
elif _subject_uri:
# class links shows the relationship between the classes in a form
_class_links = form.dependancies
_linked_lookup_class_uri = None
# cycle through the class links to find the subject linkage
for _rdf_class in _class_links:
for _prop in _class_links[_rdf_class]:
if _lookup_class_uri == _prop.get("kds_classUri"):
_linked_lookup_class_uri = _rdf_class
_linked_lookup_prop = _prop.get("kds_propUri")
break
# if there is a direct link between the subject class and
# field class add the sparql arguments
if _linked_lookup_class_uri == _class_uri:
_sparql_args.append(\
"OPTIONAL{{?uri {} ?linkedUri}} .".format(\
iri(uri(_linked_lookup_prop))))
else:
# find the indirect linkage i.e.
# field in class A that links to class B with a lookup
# subject in class C
for _rdf_class in _class_links:
for _prop in _class_links[_rdf_class]:
if _class_uri == _prop.get("kds_classUri"):
_linked_field_class_uri = _rdf_class
_linked_field_prop = _prop.get("kds_propUri")
break
if _linked_lookup_class_uri == _linked_field_class_uri:
_sparql_args.append("OPTIONAL {")
_sparql_args.append("?pass {} ?uri .".format(\
iri(uri(_linked_field_prop))))
_sparql_args.append("?pass {} ?linkedUri .".format(\
iri(uri(_linked_lookup_prop))))
_sparql_args.append("} .")
_sparql_args.append(\
"BIND(IF(bound(?linkedUri),?linkedUri,'') AS ?link)")
_sparql_args.append("FILTER(?link!={}).".format(\
iri(_subject_uri)))
return '''{}\nSELECT (COUNT(?uri)>0 AS ?uniqueValueViolation)
{{\n{}\n}}\nGROUP BY ?uri'''.format(rdfw().get_prefix(),
"\n\t".join(_sparql_args))