Shopify Chrome Extension For Admin - json

I'm trying to create an extension that adds 2 fields to the admin product page of shopify in order to add a metafield.
I know there are some extensions out there, like ShopifyFD and CustomFields, but mine is really, really simple, i'm by no means trying to copied it, this is very custom for my shopify store.
All I want, is to add 2 specific metafields to the page, and save it when i click the button Save.
That said, Everything is already working, but i'm having a problem during POST/PUT. It keeps returning status '303 See Other' and redirecting me to login, behavior that I do not encounter on neither of the 2 extensions i cited in the beginning. I wonder if the approach i'm using is the problem or what else could it be, so i'm resourcing to your help.
here how the header look like:
Request URL:https://mywebsite.myshopify.com/admin/products/461395295/metafields/9911129091.json
Request Method:PUT
Status Code:303 See Other
Remote Address:23.227.38.70:443
Like I mentioned I used a different approach as ShopifyFD or CustomFields, instead of loading a script, i'm using the content script.
here how my manifest look like:
"content_scripts": [
{
"all_frames": true,
"matches": [
"https://*.myshopify.com/admin/products/*"
],
"run_at": "document_end",
"js": [
"scripts/vendors/jquery.js",
"scripts/vendors/handlebars-v3.0.0.js",
"scripts/vendors/handlebars-helpers.js",
"scripts/utils.js",
"scripts/shopify-product-addon.js"
]
}
]
1 - I replace the current Save button with a new one so i can save the metafields before submitting the native form
2 - I append the POST/PUT method to the new Save button i have replaced
here how my post/put looks like:
Note: record is the values i'm saving.
var metaJSON;
if (record.update) {
metaJSON = {
'metafield': {
'id': record.metafield_id,
'value': record.value,
'value_type': record.value_type
}
}
method = 'PUT';
url = '/admin/' + route_url + '/metafields/' + record.metafield_id + '.json';
} else {
metaJSON = {
'metafield': {
'namespace': record.namespace,
'key': record.key,
'value': record.value,
'value_type': record.value_type
}
};
url = '/admin/' + route_url + '/metafields.json';
method = 'POST';
}
$.ajax({
type: method,
url: url,
data: metaJSON,
dataType: 'json',
success: function(d) {
console.log('SUCCESS');
},
error: function(d) {
console.log('ERROR');
}
});
The problem is that It fails everytime. I wonder what's wrong. Is the method i'm using?
I'm doing pretty much as the ShopifyFD is when posting/putting to the ajax api, just not sure what's missing. the only difference i've found was that on the ShopifyFD, there is a cookie set to request_method=PUT or request_method=POST. I don't know how this cookie is set, because it's not on the script. I even tried to set it manually, but it doesn't work.
As you can see, i have tried pretty much everything.
Does anyone else has any other suggestion?! :P
Thanks

I didn't figure it out why ShopifyFD works, i would really like to understand thou, but i found another way to make it work.
You need to set the CSRF token before you request the header.
Works like a charm!
$.ajax({
type: method,
url: url,
data: metaJSON,
beforeSend: function (request) {
var token = $("meta[name=csrf-token]").attr('content');
request.setRequestHeader("X-CSRF-Token", token);
},
.
.
.

Related

How to record http requests with Google Chrome extension and persist them

I want to create a Chrome extension, that records HTTP requests (to a pre-defined host) and persists them as a list in local storage so when I call a particular website again the list will be extended.
I want to go with Manifest v3 to make the extension "ready for the future". I created a background script to trigger the request that currently puts all the details into local storage like that (currently this is redundant for demonstration purposes, I also tried it seperated):
chrome.webRequest.onBeforeRequest.addListener(details => {
var urls = [];
chrome.storage.local.get(['data'], function(data){
urls = data.urls;
});
chrome.scripting.executeScript(
{
target: {tabId: details.tabId},
func: recordClick,
args: [details, urls]
},
() => {
urls.push(details);
console.log(urls.length);
chrome.storage.local.set({urls: urls});
});
}, {
urls: ['<all_urls>']
});
There's another function called recordClick() that does the same as in the callback:
function recordClick(details, urls) {
urls.push(details.url);
chrome.storage.local.set({urls: urls});
}
I tried several ways on where to load and save the result but none of them work. When I load the previous urls within the onBeforeRequest trigger, urls is not global and not known within the callback. When I put it outside the trigger definition, it's not reading the storage in realtime. I also tried to load the urls in a content script, loaded at "Document start". I tried to load the urls in the backend script at the top, and so on.
Seems like I have a timing problem: The trigger always loads an empty list or the variable is not global. I'm not able to extend the list. No matter where I put the storage functions.
Is my plan feasable at all? What am I'm doing wrong?
thanks!
Since chrome.storage.local.get is asynchronous, you should move chrome.scripting.executeScript into the callback of it.
onComplete may be suitable for your purpose, instead of onBeforeRequest.
chrome.webRequest.onBeforeRequest.addListener(details => {
chrome.storage.local.get('urls', function(data){
let urls = [];
if( data.urls ) {
urls = data.urls;
}
urls.push(details);
chrome.storage.local.set({urls: urls}, function() {
console.log('Value is set to ');
console.log(urls);
});
chrome.scripting.executeScript( {
target: {tabId: details.tabId},
func: function(details, urls){ console.log("executed script") },
args: [details, urls]
},
() => {
console.log("injected")
});
});
},
{ urls: ['<all_urls>'] }
);

Chrome Extension: How to change headers on every page request programmatically?

I'm currently developing a Chrome Extension and need to add/change a header value, but only on a specific page. Something like this:
chrome.onPageRequest(function(host) {
if(host == 'google.com') {
chrome.response.addHeader('X-Auth', 'abc123');
}
});
Any help would be greatly appreciated :)
You can use the chrome.webRequest API for that purpose. You'll need the following:
Declare the appropriate permissions in your manifest:
...
"permissions": [
...
"webRequest",
"*://*.google.com/*"
]
Register a listener for the chrome.webRequest.onHeadersReceived() event and modify the headers. In order to be able to modify the headers, you need to define the 'responseHeaders' extra info (see 3rd arguments of listener function):
chrome.webRequest.onHeadersReceived.addListener(function(details) {
console.log(details);
details.responseHeaders.push({
name: 'X-Auth',
value: 'abc123'
});
return { responseHeaders: details.responseHeaders };
}, {
urls: ['*://*.google.com/*']
}, [
"responseHeaders"
]);
Keep in mind that the webRequest permission only works if your background-page is persistent, so remove the corresponding line from your manifest (if it exists - which it should):
...
"background": {
"persistent": false, // <-- Remove this line or set it to `true`
"scripts": [...]
...
Also, keep in mind that pretty often Google redirects requests based on the user's country (e.g. redirecting www.google.com to www.google.gr), in which case the filter will not let them reach your onHeadersReceived listener.

Calling a PHP script on button press with Sencha Architect

I've been looking at the documentation and tutorials for Sencha Architect, and I can't figure it out. What I want to is have a button press post a value to a PHP script on a server, and then retrieve the result from a PHP session variable. From what I've seen, I'm not sure if I can get it to call PHP at all, much less read a session variable.
I realize there may be a few questions in here (connecting the button to a controller/store, calling the script, reading the result), but I don't know enough about Architect to know if they're the correct ones.
EDIT: I think I've got the button connected to a controller, but I'm still not sure how to get it to call the PHP script.
EDIT 2:
I added a BasicFunction to the button, but I can't get it to work. Here's the code:
// Look up the items stack and get a reference to the first form it finds
var form = this.up('formpanel');
var values = form.getValues().getValues()[0];
Ext.Msg.alert('Working', 'Loading...', Ext.emptyfn);
Ext.Ajax.request({
url: 'http://wereani.ml/shorten-app.php',
method: 'POST',
params: {
url: values
},
success: function(response) {
Ext.Msg.alert('Link Shortened', Ext.JSON.decode(response).toString(), function() {
form.reset();
});
},
failure: function(response) {
Ext.Msg.alert('Error', Ext.JSON.decode(response).toString(), function() {
form.reset();
});
}
});
Also, is that the correct way to get the value from the field (itemID:url)? I couldn't find anything in the documentation for Touch about that.
Use an Ext.Ajax request in the listener for the button. docs.sencha.com/touch/2.2.1/?mobile=/api/Ext.Ajax.
The documentation there is pretty straightforward. If you have trouble please post some specifics and I'll try to write you an example.
Good luck, Brad

jQuery and JSON vs IE - SCRIPT5007: Unable to get value of the property

I'm struggling to get this script working. It's basically a simple ajax call to retrieve data from a php which returns a JSON code.
function refreshWindows(){
if(AjaxPull && AjaxPull.readystate != 4){
AjaxPull.abort();
}
AjaxPull = $.ajax({
type: 'POST',
url: $path,
data: {
ajax: true,
mode: 'update',
to: Math.round(currentDate.getTime() / 1000),
from: Math.round(previousDate.getTime() / 1000)
},
dataType: "json",
success: function (data) {
alert(data); //that's for debug
$replies = data.Updates;
$.each($replies ,function(group,value) {
if (value!=''){
$("#group"+group+" .content").append(value);
$("#group"+group+" .content").stop().animate({ scrollTop: $("#group"+group+" .content")[0].scrollHeight }, 800);
if (!$("#group"+group+" .Window").is(':visible')) {
$("#group"+group+" .BottomBox").fadeTo('fast', 0.5).fadeTo('fast', 1.0);
}
}
});
previousDate = currentDate;
currentDate = new Date();
timeController.push( setTimeout(function(){refreshChatWindows();}, 500) );
}
});
}
The error I get in Internet Explorer is:
SCRIPT5007: Unable to get value of the property 'Updates': object is null or undefined
Everything works fine in Firefox and Google Chrome.
Initially my code was made using .get but someone suggested switching to the .ajax - well, it didn't help. I tried using .done(function(data){ but it didn't work either. I also tried sending all of the data in my URL opposite to the data property, it worked fine in FF, but IE still popped the same error. Finally I tried adding different headers to the PHP, like for example header('Content-Type: application/json'); but it didn't change anything. I run out of ideas / possible solutions I could fine on stackoverflow, so any help would be appreciated.
In IE I went to Developer Tools, network tab and tried to see if everything works - yes, the request is being sent correctly with all the data, and a response I receive is correct JSON, just as it is in Firefox:
{"Updates":{"1":"","2":"","3":"","5":"","6":"","7":"","8":""},"time":{"from":"1367489761","to":"1367489761"}}
which gets me really confused, cause I'd have thought that Undefined error might happen only because something is not being sent back in IE for whatever reason, but clearly: It's not the case. I get my JSON back. Only IE for some unknown reason still thinks that data is undefined.
Ok, I found a solution finally.
Basically:
Remove any headers sent by PHP script. Especially: Content-type headers. (luckily - seems like sessions still can be used)
Use }).done(function ( data ) { instead of success: function (data) {
and that's all. Suddenly it started to work. It's very weird. Seems like the shotgun tactic (randomly changing bits of code till it works) is actually a valid way of solving problems. hehehe
I have a similar json call that returns data that looks like this:
{"GetTombstoneDataRestResult":{"AlphaSort":"Arai Junichi","Classification":"A&D Design Object"...etc
In other words, a lot like your json data. To reference it in jQuery, I use the callback name.
$.ajax({
type: "GET",
dataType: "jsonp",
url: url,
success: function (result) {
$('#screenshot').append('<p><strong>Title: ' +
result.GetTombstoneDataRestResult.Title + '</strong><br />Year: ' +
result.GetTombstoneDataRestResult.Dated + '<br />Artist: ' +
result.GetTombstoneDataRestResult.DisplayName + '</p>');
}
});
Looks like you want to try this too:
var replies = data;
$.each(replies.Updates ,function(group,value) {
You have a character called ​ in your JSON.
See a description here:
What's HTML character code 8203?
It's right before your colon here "time"​:
Can you clean your output and validate the JSON and try again?

jQuery $.ajax() is firing the server request but never gets response on google chrome only

I tested this on firefox and ie and worked. But when testing on chrome, I see in the firebug console that the request never loads.
This is the test page: http://gotune.to/index2.php
And here is the function + $.ajax() request.
function getProgress(id) {
$.ajax({
type: 'POST',
cache: false,
url: "getprogress.php",
//Pass our upload identifier as a parameter.
data: {uid: id},
success: function (d) {
//Get the output as an integer.
var progress = parseInt(d, 10);
//If upload progress is not 100, change bar percentage and update again.
if (progress != '100') {
$('#ProgressBar').css('width', progress + '%');
//We aren't done, update again.
getProgress(id);
}
}
});
}
UPDATE
Tried with
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus+" - "+errorThrown);
}
But still not working.
After a web research for this issue if found this:
Turns out it's a bug, in any webkit
based browser all ajax is essentially
blocked until the file upload is
complete. to bypass this you have to
dynamically create an iframe and run
the ajax requests from within it.
So is a problem of the webkit browsers, thanks #ifaour for your time.
THE BUG REPORT CAN BE FOUND HERE: https://bugs.webkit.org/show_bug.cgi?id=23933