diff --git a/src/main/java/com/metaweb/gridworks/GridworksServlet.java b/src/main/java/com/metaweb/gridworks/GridworksServlet.java index 7425aa924..5147b0166 100644 --- a/src/main/java/com/metaweb/gridworks/GridworksServlet.java +++ b/src/main/java/com/metaweb/gridworks/GridworksServlet.java @@ -29,6 +29,8 @@ import com.metaweb.gridworks.commands.edit.ExportProjectCommand; import com.metaweb.gridworks.commands.edit.ExtendDataCommand; import com.metaweb.gridworks.commands.edit.ImportProjectCommand; import com.metaweb.gridworks.commands.edit.JoinMultiValueCellsCommand; +import com.metaweb.gridworks.commands.edit.MQLReadCommand; +import com.metaweb.gridworks.commands.edit.MQLWriteCommand; import com.metaweb.gridworks.commands.edit.MassEditCommand; import com.metaweb.gridworks.commands.edit.RemoveColumnCommand; import com.metaweb.gridworks.commands.edit.RemoveRowsCommand; @@ -145,6 +147,8 @@ public class GridworksServlet extends HttpServlet { _commands.put("deauthorize", new DeAuthorizeCommand()); _commands.put("upload-data", new UploadDataCommand()); + _commands.put("mqlread", new MQLReadCommand()); + _commands.put("mqlwrite", new MQLWriteCommand()); } @Override diff --git a/src/main/java/com/metaweb/gridworks/commands/edit/MQLReadCommand.java b/src/main/java/com/metaweb/gridworks/commands/edit/MQLReadCommand.java new file mode 100644 index 000000000..cc408a0b1 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/commands/edit/MQLReadCommand.java @@ -0,0 +1,31 @@ +package com.metaweb.gridworks.commands.edit; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.metaweb.gridworks.commands.Command; +import com.metaweb.gridworks.oauth.OAuthUtilities; +import com.metaweb.gridworks.oauth.Provider; +import com.metaweb.gridworks.util.FreebaseUtils; + +public class MQLReadCommand extends Command { + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + try { + Provider provider = OAuthUtilities.getProvider(request); + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + String query = request.getParameter("query"); + String result = FreebaseUtils.mqlread(provider,query); + response.getWriter().write(result); + } catch (Exception e) { + respondException(response, e); + } + } +} diff --git a/src/main/java/com/metaweb/gridworks/commands/edit/MQLWriteCommand.java b/src/main/java/com/metaweb/gridworks/commands/edit/MQLWriteCommand.java new file mode 100644 index 000000000..d41de01ac --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/commands/edit/MQLWriteCommand.java @@ -0,0 +1,41 @@ +package com.metaweb.gridworks.commands.edit; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.metaweb.gridworks.commands.Command; +import com.metaweb.gridworks.oauth.Credentials; +import com.metaweb.gridworks.oauth.OAuthUtilities; +import com.metaweb.gridworks.oauth.Provider; +import com.metaweb.gridworks.util.FreebaseUtils; + +public class MQLWriteCommand extends Command { + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + try { + Provider provider = OAuthUtilities.getProvider(request); + + Credentials access_credentials = Credentials.getCredentials(request, provider, Credentials.Type.ACCESS); + + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + + if (access_credentials != null) { + String query = request.getParameter("query"); + System.out.println(query); + String result = FreebaseUtils.mqlwrite(access_credentials, provider, query); + response.getWriter().write(result); + } else { + respond(response, "401 Unauthorized", "You don't have the right credentials"); + } + } catch (Exception e) { + respondException(response, e); + } + } +} diff --git a/src/main/java/com/metaweb/gridworks/commands/edit/UploadDataCommand.java b/src/main/java/com/metaweb/gridworks/commands/edit/UploadDataCommand.java index 15c756e28..adc1435d2 100644 --- a/src/main/java/com/metaweb/gridworks/commands/edit/UploadDataCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/edit/UploadDataCommand.java @@ -32,8 +32,9 @@ public class UploadDataCommand extends Command { String source_name = request.getParameter("source_name"); String source_id = request.getParameter("source_id"); + String graph = request.getParameter("graph"); - String result = FreebaseUtils.uploadTriples(request, source_name, source_id, triples.toString()); + String result = FreebaseUtils.uploadTriples(request, graph, source_name, source_id, triples.toString()); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Type", "application/json"); diff --git a/src/main/java/com/metaweb/gridworks/util/FreebaseUtils.java b/src/main/java/com/metaweb/gridworks/util/FreebaseUtils.java index 585b16040..92e3511f2 100644 --- a/src/main/java/com/metaweb/gridworks/util/FreebaseUtils.java +++ b/src/main/java/com/metaweb/gridworks/util/FreebaseUtils.java @@ -45,6 +45,14 @@ public class FreebaseUtils { return "http://" + host + "/api/service/user_info"; } + private static String getMQLWriteURL(String host) { + return "http://" + host + "/api/service/mqlwrite"; + } + + private static String getMQLReadURL(String host) { + return "http://" + host + "/api/service/mqlread"; + } + public static String getUserInfo(Credentials credentials, Provider provider) throws OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, ClientProtocolException, IOException { @@ -66,8 +74,62 @@ public class FreebaseUtils { // return the results return EntityUtils.toString(httpResponse.getEntity()); } + + public static String mqlwrite(Credentials credentials, Provider provider, String query) + throws OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, ClientProtocolException, IOException, JSONException { + OAuthConsumer consumer = OAuthUtilities.getConsumer(credentials, provider); + + JSONObject envelope = new JSONObject(); + envelope.put("query", new JSONObject(query)); + + List formparams = new ArrayList(); + formparams.add(new BasicNameValuePair("query", envelope.toString())); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8"); + + HttpPost httpRequest = new HttpPost(getMQLWriteURL(provider.getHost())); + httpRequest.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "Gridworks " + Gridworks.getVersion()); + httpRequest.setEntity(entity); + + // this is required by the Metaweb API to avoid XSS + httpRequest.setHeader("X-Requested-With", "1"); + + // sign the request with the oauth library + consumer.sign(httpRequest); + + // execute the request + HttpClient httpClient = new DefaultHttpClient(); + HttpResponse httpResponse = httpClient.execute(httpRequest); - public static String uploadTriples(HttpServletRequest request, String source_name, String source_id, String triples) + // return the results + return EntityUtils.toString(httpResponse.getEntity()); + } + + public static String mqlread(Provider provider, String query) + throws ClientProtocolException, IOException, JSONException { + + JSONObject envelope = new JSONObject(); + envelope.put("query", new JSONObject(query)); + + List formparams = new ArrayList(); + formparams.add(new BasicNameValuePair("query", envelope.toString())); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8"); + + HttpPost httpRequest = new HttpPost(getMQLReadURL(provider.getHost())); + httpRequest.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "Gridworks " + Gridworks.getVersion()); + httpRequest.setEntity(entity); + + // this is required by the Metaweb API to avoid XSS + httpRequest.setHeader("X-Requested-With", "1"); + + // execute the request + HttpClient httpClient = new DefaultHttpClient(); + HttpResponse httpResponse = httpClient.execute(httpRequest); + + // return the results + return EntityUtils.toString(httpResponse.getEntity()); + } + + public static String uploadTriples(HttpServletRequest request, String graph, String source_name, String source_id, String triples) throws OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, ClientProtocolException, JSONException, IOException { Provider provider = OAuthUtilities.getProvider(FREEBASE_HOST); @@ -88,7 +150,7 @@ public class FreebaseUtils { formparams.add(new BasicNameValuePair("action_type", "LOAD_TRIPLE")); formparams.add(new BasicNameValuePair("operator", GRIDWORKS_ID)); formparams.add(new BasicNameValuePair("mdo_info", mdo_info.toString())); - formparams.add(new BasicNameValuePair("graphport", provider.getHost().equals(FREEBASE_HOST) ? "otg" : "sandbox")); + formparams.add(new BasicNameValuePair("graphport", graph)); formparams.add(new BasicNameValuePair("payload", triples)); formparams.add(new BasicNameValuePair("check_params", "false")); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8"); @@ -121,5 +183,4 @@ public class FreebaseUtils { throw new RuntimeException("Invalid credentials"); } } - } diff --git a/src/main/webapp/scripts/dialogs/freebase-loading-dialog.js b/src/main/webapp/scripts/dialogs/freebase-loading-dialog.js index 137722216..1152d72f3 100644 --- a/src/main/webapp/scripts/dialogs/freebase-loading-dialog.js +++ b/src/main/webapp/scripts/dialogs/freebase-loading-dialog.js @@ -1,5 +1,6 @@ function FreebaseLoadingDialog() { this._createDialog(); + this._signedin = false; } FreebaseLoadingDialog.prototype._createDialog = function() { @@ -33,109 +34,175 @@ FreebaseLoadingDialog.prototype._createDialog = function() { var selector = $('').addClass("freebase-loading-graph-selector").html("Load this data into " + '' + - '' + '' ).buttonset().appendTo(right_footer); - var load_button = $('').text("Load").appendTo(right_footer); + var load_button = $('').text("Load").appendTo(right_footer); var provider = "www.freebase.com"; - var check_authorization = function(autoload) { + var check_authorization = function(cont) { $.get("/command/check-authorization/" + provider, function(data) { - if ("status" in data && data.status == "200 OK") { + if ("status" in data && data.code == "/api/status/ok") { authorization.html('Signed in as: ' + data.username + ' | Sign Out').show(); DOM.bind(authorization).signout.click(function() { + self._signedin = false; + load_button.attr("disabled","disabled"); Sign.signout(check_authorization,provider); }); - if (autoload) { - self._load(); - } else { - load_button.unbind().click(function() { - self._load(); - }); - } - } else { - authorization.html("").hide(); load_button.unbind().click(function() { + self._load(); + }); + self._signedin = true; + $("#freebase-loading-source-name").keyup(); + if (typeof cont == "function") cont(data); + } else { + authorization.html('Sign into Freebase to enable loading').show(); + DOM.bind(authorization).signin.click(function() { Sign.signin(function() { - check_authorization(true); + check_authorization(cont); },provider); }); } },"json"); }; - $.post( - "/command/export-rows", - { - project: theProject.id, - format : "tripleloader" - }, - function(data) { - if (data == null || data == "") { - body.html( - '
'+ - '

This dataset has no triples

' + - '

Have you aligned it with the Freebase schemas yet?

' + - '
' - ); - left_footer.hide(); - center_footer.hide(); - selector.hide(); - load_button.text("Close").unbind().click(function() { - self._dismiss(); - }); - } else { - body.html( - '
' + data + '
' + - '
' + - '
Describe the data you\'re about to load ¬
' + - '' + - '
' - ); - self._elmts = DOM.bind(frame); - check_authorization(false); + var check_allowed = function(user_id, cont) { + var mql_query = { + id : user_id, + "!/type/usergroup/member": [{ + "id": "/en/metaweb_staff" + }] + }; + + $.post("/command/mqlread/" + provider, + { "query" : JSON.stringify(mql_query) }, + function(data) { + if ("status" in data && data.code == "/api/status/ok") { + if (typeof cont == "function") cont((data.result != null)); + } else { + self._show_error("Error checking if user is a staff member", data); + } + }, + "json" + ); + }; + + var make_topic = function(new_topic_id, topic_type, cont) { + var mql_query = { + "create": "unless_exists", + "name": new_topic_id, + "type": topic_type, + "id": null, + "guid": null + }; + + $.post("/command/mqlwrite/" + provider, + { "query" : JSON.stringify(mql_query) }, + function(data) { + if ("status" in data && data.code == "/api/status/ok") { + self._elmts.source_id.val(data.result.id); + if (typeof cont == "function") cont(); + } else { + self._show_error("Error creating new topic", data); + } + }, + "json" + ); + }; + + var show_triples = function(cont) { + $.post("/command/export-rows", + { + project: theProject.id, + format : "tripleloader" + }, + function(data) { + if (data == null || data == "") { + body.html( + '
'+ + '

This dataset has no triples

' + + '

Have you aligned it with the Freebase schemas yet?

' + + '
' + ); + + self._end(); + } else { + body.html( + '
' + + '' + + '' + + '
Name this data load ¬ required
' + + '
Source ID ¬ optional
' + + '
' + + '
' + data + '
' + ); + self._elmts = DOM.bind(frame); + + self._elmts.source_name.keyup(function() { + if (self._signedin && $(this).val() != "") { + load_button.removeAttr("disabled"); + } else { + load_button.attr("disabled","disabled"); + } + }); + + self._elmts.source_id.suggest({ + "type": "/dataworld/information_source", + "soft": true, + "suggest_new": "Click here to add a new information source" + }).bind("fb-select-new", function(e, val) { + make_topic(val, "/dataworld/information_source"); + }); + + if (typeof cont == "function") cont(); + } + + self._level = DialogSystem.showDialog(frame); } - self._level = DialogSystem.showDialog(frame); - } - ); + ); + }; + + show_triples(function() { + check_authorization(function(data) { + check_allowed(data.id, function(is_allowed) { + if (is_allowed) { + $("#freebase-loading-graph-selector-freebase").removeAttr("disabled").button("refresh"); + } + }); + }); + }); }; FreebaseLoadingDialog.prototype._load = function() { var self = this; var freebase = self._elmts.freebase.attr("checked"); + var get_peacock_url = function(url) { + return "http://peacock.freebaseapps.com/stats/data.labs/" + url.split("/").slice(-2).join("/"); + } + var doLoad = function() { $.post("/command/upload-data", { project: theProject.id, "graph" : (freebase) ? "otg" : "sandbox", - "info" : self._elmts.info.val() + "source_name" : self._elmts.source_name.val(), + "source_id" : self._elmts.source_id.val() }, function(data) { var body = $(".dialog-body"); - if ("status" in data && data.status == "200 OK") { + if ("status" in data && "code" in data.status && data.status.code == 200) { body.html( '
' + - '

Data successfully loaded

' + - '

' + data.message + '

' + + '

' + data.result.added + ' triples successfully scheduled for loading

' + + '

Follow the loading progress here

' + '
' ); + self._end(); } else { - body.html( - '
' + - '

Error loading data

' + - '

' + data.message + '

' + - '
' + data.stack.replace(/\\n/g,'\n').replace(/\\t/g,'\t') + '

' + - '
' - ); + self._show_error("Error loading data",error); } - self._elmts.load.text("Close").unbind().click(function() { - self._dismiss(); - }); - self._elmts.cancel.hide(); - self._elmts.authorization.hide(); - self._elmts.selector.hide(); }, "json" ); @@ -144,7 +211,7 @@ FreebaseLoadingDialog.prototype._load = function() { if (freebase) { var dialog = $( '
' + - '
Are you sure this data is ready to be uploaded into Freebase?
' + + '
Are you sure this data is ready to be uploaded into Freebase?
' + '
' ).dialog({ resizable: false, @@ -152,7 +219,7 @@ FreebaseLoadingDialog.prototype._load = function() { height: 230, modal: true, buttons: { - 'yes': function() { + 'yes, I know what I\'m doing': function() { $(this).dialog('close'); doLoad(); }, @@ -170,3 +237,24 @@ FreebaseLoadingDialog.prototype._dismiss = function() { DialogSystem.dismissUntil(this._level - 1); }; +FreebaseLoadingDialog.prototype._show_error = function(msg, error) { + var body = $(".dialog-body"); + body.html( + '
' + + '

' + msg + '

' + + '

' + error.message + '

' + + (('stack' in error) ? '
' + error.stack.replace(/\\n/g,'\n').replace(/\\t/g,'\t') + '

' : "") + + '
' + ); + this._end(); +}; + +FreebaseLoadingDialog.prototype._end = function() { + var self = this; + self._elmts.load.text("Close").unbind().click(function() { + self._dismiss(); + }); + self._elmts.cancel.hide(); + self._elmts.authorization.hide(); + self._elmts.selector.hide(); +}; \ No newline at end of file diff --git a/src/main/webapp/styles/dialogs/freebase-loading-dialog.css b/src/main/webapp/styles/dialogs/freebase-loading-dialog.css index 8b76b2f18..fcc3956f5 100644 --- a/src/main/webapp/styles/dialogs/freebase-loading-dialog.css +++ b/src/main/webapp/styles/dialogs/freebase-loading-dialog.css @@ -25,7 +25,7 @@ } .freebase-loading-tripleloader-info { - margin-top: 1em; + margin-bottom: 0.5em; } .freebase-loading-tripleloader-info textarea {