Skip to content

Commit

Permalink
Implement support for SPARQL queries and PartShops with spoofed URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryan Bartley committed Jan 17, 2019
1 parent 442c97b commit 85d2a16
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 72 deletions.
6 changes: 3 additions & 3 deletions source/combinatorialderivation.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ namespace sbol
Identified(type, uri, version),
variable(this, SBOL_VARIABLE, SBOL_COMPONENT, '0', '1', ValidationRules({})),
repeat(this, SBOL_OPERATOR, '1', '1', ValidationRules({}), repeat),
variants(this, SBOL_VARIANTS, SBOL_COMPONENT_DEFINITION, '0', '1', ValidationRules({})),
variantCollections(this, SBOL_VARIANT_COLLECTIONS, SBOL_COLLECTION, '0', '1', ValidationRules({})),
variantDerivations(this, SBOL_VARIANT_DERIVATIONS, SBOL_COMBINATORIAL_DERIVATION, '0', '1', ValidationRules({}))
variants(this, SBOL_VARIANTS, SBOL_COMPONENT_DEFINITION, '0', '*', ValidationRules({})),
variantCollections(this, SBOL_VARIANT_COLLECTIONS, SBOL_COLLECTION, '0', '*', ValidationRules({})),
variantDerivations(this, SBOL_VARIANT_DERIVATIONS, SBOL_COMBINATORIAL_DERIVATION, '0', '*', ValidationRules({}))
{
};

Expand Down
161 changes: 126 additions & 35 deletions source/partshop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,49 @@ void replace(string& text, string target, string replacement)
};

// A utility function for encoding text into UTF8 for http requests
void encode_http(string& text)
void encode_url(string& text)
{
string UTF8_AMPERSAND = "%26";
string UTF8_EQUALS = "%3D";
string UTF8_LESS_THAN = "%3C";
string UTF8_GREATER_THAN = "%3E";
string UTF8_COLON = "%3A";
string UTF8_HASH = "%23";
string UTF8_APOSTROPHE = "%27";
string UTF8_SPACE = "%20";
string UTF8_SLASH = "%2F";

replace(text, "&", UTF8_AMPERSAND);
replace(text, "=", UTF8_EQUALS);
replace(text, "<", UTF8_LESS_THAN);
replace(text, ">", UTF8_GREATER_THAN);
replace(text, ":", UTF8_COLON);
replace(text, "#", UTF8_HASH);
replace(text, "'", UTF8_APOSTROPHE);
replace(text, " ", UTF8_SPACE);
replace(text, "/", UTF8_SLASH);
// string UTF8_AMPERSAND = "%26";
// string UTF8_EQUALS = "%3D";
// string UTF8_LESS_THAN = "%3C";
// string UTF8_GREATER_THAN = "%3E";
// string UTF8_COLON = "%3A";
// string UTF8_HASH = "%23";
// string UTF8_APOSTROPHE = "%27";
// string UTF8_SPACE = "%20";
// string UTF8_SLASH = "%2F";
// string UTF8_CURLYBRACE_OPEN = "%7B";
// string UTF8_CURLYBRACE_CLOSED = "%7D";
// string UTF8_SEMICOLON = "%3B";
// string UTF8_DOT = "%2E";
// string UTF8_QUOTE = "%22";
// string UTF8_QUESTION_MARK = "%3F";
// string UTF8_OPEN_PARENTHESES = "%28";
// string UTF8_CLOSE_PARENTHESES = "%29";
// string UTF8_LINEFEED = "%0A";
// string UTF8_CARRIAGE_RETURN = "%0D";

// replace(text, "&", UTF8_AMPERSAND);
// replace(text, "=", UTF8_EQUALS);
// replace(text, "<", UTF8_LESS_THAN);
// replace(text, ">", UTF8_GREATER_THAN);
// replace(text, ":", UTF8_COLON);
// replace(text, "#", UTF8_HASH);
// replace(text, "'", UTF8_APOSTROPHE);
// replace(text, " ", UTF8_SPACE);
// replace(text, "/", UTF8_SLASH);
// replace(text, "{", UTF8_CURLYBRACE_OPEN);
// replace(text, "}", UTF8_CURLYBRACE_CLOSED);
// replace(text, ";", UTF8_SEMICOLON);
// replace(text, ".", UTF8_DOT);
// replace(text, "\"", UTF8_DOT);
// replace(text, "?", UTF8_DOT);
// replace(text, ".", UTF8_DOT);
// replace(text, "(", UTF8_DOT);
// replace(text, ")", UTF8_DOT);
CURL *curl;
char * encoded_text = curl_easy_escape(curl, text.c_str(), text.size());
text = string(encoded_text);
};

// Advanced search
Expand Down Expand Up @@ -119,7 +141,7 @@ SearchResponse& sbol::PartShop::search(SearchQuery& q)
else
throw SBOLError(SBOL_ERROR_INVALID_ARGUMENT, "Invalid limit parameter specified");

encode_http(parameters);
encode_url(parameters);
parameters = url + "/remoteSearch/" + parameters;

/* First set the URL that is about to receive our GET. */
Expand Down Expand Up @@ -202,7 +224,7 @@ SearchResponse& sbol::PartShop::search(std::string search_text, rdf_type object_
// Encode as a literal
parameters += "'" + search_text + "'&";

encode_http(parameters);
encode_url(parameters);

// Specify how many records to retrieve
parameters += "/?offset=" + to_string(offset) + "&limit=" + to_string(limit);
Expand Down Expand Up @@ -253,6 +275,11 @@ SearchResponse& sbol::PartShop::search(std::string search_text, rdf_type object_
return search_response;
};

std::string sbol::PartShop::getKey()
{
return key;
};

// General search
SearchResponse& sbol::PartShop::search(std::string search_text, rdf_type object_type, int offset, int limit)
{
Expand Down Expand Up @@ -281,7 +308,7 @@ SearchResponse& sbol::PartShop::search(std::string search_text, rdf_type object_
// Specify partial search text. Specify how many records to retrieve
parameters = parameters + search_text;

encode_http(search_text);
encode_url(search_text);

// Specify how many records to retrieve
parameters += "/?offset=" + to_string(offset) + "&limit=" + to_string(limit);
Expand Down Expand Up @@ -388,7 +415,7 @@ int sbol::PartShop::searchCount(SearchQuery& q)
}
}

encode_http(parameters);
encode_url(parameters);
parameters = url + "/searchCount/" + parameters;

/* First set the URL that is about to receive our GET. */
Expand Down Expand Up @@ -459,7 +486,7 @@ int sbol::PartShop::searchCount(std::string search_text, rdf_type object_type, s
// Encode as a literal
parameters += "'" + search_text + "'&";

encode_http(parameters);
encode_url(parameters);

parameters = parseURLDomain(url) + "/remoteSearch/" + parameters;

Expand Down Expand Up @@ -523,7 +550,7 @@ int sbol::PartShop::searchCount(std::string search_text, rdf_type object_type)
// Specify partial search text. Specify how many records to retrieve
parameters = parameters + search_text;

encode_http(search_text);
encode_url(search_text);

parameters = url + "/searchCount/" + parameters;

Expand Down Expand Up @@ -578,8 +605,10 @@ int getch(void)
}
#endif

void sbol::PartShop::login(std::string email, std::string password)
void sbol::PartShop::login(std::string user_id, std::string password)
{
this->user = user_id;

if (password == "")
{
cout << "Password: ";
Expand Down Expand Up @@ -611,7 +640,8 @@ void sbol::PartShop::login(std::string email, std::string password)
string response;
CURL *curl;
CURLcode res;

long http_response_code = 0;

/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);

Expand All @@ -631,7 +661,7 @@ void sbol::PartShop::login(std::string email, std::string password)
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

/* Now specify the POST data */
string parameters = "email=" + email + "&" + "password=" + password;
string parameters = "email=" + user_id + "&" + "password=" + password;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, parameters.c_str());

/* Now specify the callback to read the response into string */
Expand All @@ -643,17 +673,20 @@ void sbol::PartShop::login(std::string email, std::string password)
/* Check for errors */
if(res != CURLE_OK)
throw SBOLError(SBOL_ERROR_BAD_HTTP_REQUEST, "Login failed due to an HTTP error: " + string(curl_easy_strerror(res)));


curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_response_code);


/* always cleanup */
curl_easy_cleanup(curl);
}
curl_slist_free_all(headers);
curl_global_cleanup();

if (response == "Your password was not recognized.")
std::cout << response << std::endl;
else
key = response;
if (http_response_code != 200)
throw SBOLError(SBOL_ERROR_BAD_HTTP_REQUEST, "Login failed due to a " + to_string(http_response_code) + " HTTP error: " + response);

key = response;
};

std::string sbol::PartShop::submit(Document& doc, std::string collection, int overwrite)
Expand Down Expand Up @@ -1008,7 +1041,7 @@ std::string http_get_request(std::string get_request, unordered_map<string, stri
std::string response;
CURL *curl;
CURLcode res;

/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);

Expand Down Expand Up @@ -1080,6 +1113,8 @@ void PartShop::pull(std::string uri, Document& doc, bool recursive)
query = uri; // User has specified full URI
else if (uri.find(parseURLDomain(resource)) != std::string::npos)
query = uri; // User has specified full URI
else if (uri.find(spoofed_resource) != std::string::npos)
query = uri.replace(uri.find(spoofed_resource), spoofed_resource.size(), resource);
else
query = resource + "/" + uri; // Assume user has only specified displayId
try
Expand All @@ -1105,6 +1140,62 @@ void PartShop::pull(std::string uri, Document& doc, bool recursive)
doc.resource_namespaces.insert(resource);
};

void sbol::PartShop::spoof(std::string spoofed_url)
{
spoofed_resource = spoofed_url;
};

std::string sbol::PartShop::sparqlQuery(std::string query)
{
string endpoint = parseURLDomain(this->resource) + "/sparql?query=";
string resource;
if (spoofed_resource == "")
resource = this->resource;
else
resource = this->spoofed_resource;

size_t p = query.find("WHERE");
if (p != std::string::npos)
{
string from_clause = " FROM <" + parseURLDomain(resource) + "/user/" + user + "> ";
query = query.insert(p, from_clause);
}
encode_url(query);
query = endpoint + query;

unordered_map<string, string> headers;
unordered_map<string, string> header_response;
headers["X-authorization"] = key;
headers["Accept"] = "application/json";

string response;
if (Config::getOption("verbose") == "True")
std::cout << "Issuing SPARQL:\n" << query << std::endl;
response = http_get_request(query, &headers);

return response;
};

void sbol::PartShop::remove(string uri)
{
if (spoofed_resource != "")
{
size_t p = uri.find(resource);
if (p != std::string::npos)
{
uri = uri.insert(p, spoofed_resource);
}
}
string endpoint = uri + "/remove";

unordered_map<string, string> headers;
unordered_map<string, string> header_response;
headers["X-authorization"] = key;
headers["Accept"] = "application/json";

http_get_request(endpoint, &headers);
};

string PartShop::getURL()
{
return resource;
Expand Down
26 changes: 20 additions & 6 deletions source/partshop.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,20 +155,32 @@ namespace sbol
{
private:
std::string resource;
std::string spoofed_resource;
std::string key;

std::string user;

public:
/// Construct an interface to an instance of SynBioHub or other parts repository
/// @param The URL of the online repository
PartShop(std::string url) :
resource(url)
PartShop(std::string url, std::string spoofed_url = "") :
resource(url),
key(""),
spoofed_resource(spoofed_url)
{
};

/// Return the count of objects contained in a PartShop
/// @tparam SBOLClass The type of SBOL object, usually a ComponentDefinition
template < class SBOLClass > int count();

/// Issue a SPARQL query
std::string sparqlQuery(std::string query);

/// Specify the URL of a resource that is simulated or spoofed by this PartShop
void spoof(std::string spoofed_url);

void remove(std::string uri);

/// Retrieve an object from an online resource
/// @param uri The identity of the SBOL object you want to retrieve
/// @param doc A document to add the data to
Expand All @@ -178,7 +190,7 @@ namespace sbol
/// @param uris A vector of URIs for multiple SBOL objects you want to retrieve
/// @param doc A document to add the data to
void pull(std::vector<std::string> uris, Document& doc, bool recursive = true );

template < class SBOLClass > void pull(std::string uri, Document& doc, bool recursive = true);

/// Returns all Collections that are not members of any other Collections
Expand Down Expand Up @@ -240,12 +252,14 @@ namespace sbol
/// In order to submit to a PartShop, you must login first. Register on [SynBioHub](http://synbiohub.org) to obtain account credentials.
/// @param email The email associated with the user's SynBioHub account
/// @param password The user's password
void login(std::string email, std::string password = "");
void login(std::string user_id, std::string password = "");

/// Returns the network address of the PartShop
/// @return The URL of the online repository
std::string getURL();


std::string getKey();

/// Upload and attach a file to a TopLevel object in a PartShop.
/// @param top_level_uri The identity of the object to which the file will be attached
/// @param file_name A path to the file attachment
Expand Down
Loading

0 comments on commit 85d2a16

Please sign in to comment.