I would like to retrieve the IP address and the precise moment of the click when clicking on the "Download" button and insert it into the database.
I have already implemented the retrieval of the IP address and the click date.
const button = document.querySelector(".expand");
button.addEventListener("click", () => {
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.ipify.org?format=json", true);
console.log("coucou");
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
const date = new Date();
console.log("Adresse IP : " + data.ip + ", Date : " + date.toLocaleDateString("fr") );
}
};
xhr.send();
});
To note that the code is for a Prestashop module version > 1.7.
The goal of this module is to retrieve the invoices from the Sage 100c ERP to send them to the Prestashop customer space. An intermediate program takes care of doing the INSERT INTO in the database, but the columns: lastDownloadDate and lastDownloadIP are empty during the insert. So I would like the IP and date information to be transmitted when clicking on the download button.
The code of the insert on the C# connector Sage-Prestashop :
Model.Prestashop.PsAEcInvoiceHistory newInvoice = new Model.Prestashop.PsAEcInvoiceHistory()
{
IDCustomer = IDCustomer,
InvoiceNumber = (Core.Global.GetConfig().ModuleAECInvoiceHistoryReference && !string.IsNullOrEmpty(Piece.DO_Ref)) ? Piece.DO_Piece + " - " + Piece.DO_Ref : Piece.DO_Piece,
InvoiceNumberPrestashop = orderPrestashop,
File = ftp_filename,
FileName = Piece.DO_Piece + ".pdf",
InvoiceDate = (Piece.DO_Date != null) ? Piece.DO_Date.Value : DateTime.Now,
TotalAmountTaxInCl = (Piece.TotalAmountTaxExcl.HasValue && Piece.TotalTaxAmount.HasValue) ? Piece.TotalAmountTaxExcl.Value + Piece.TotalTaxAmount.Value : 0,
TotalAmountTaxExCl = Piece.TotalAmountTaxExcl ?? 0,
TypeDocument = TypeDoc,
InvoiceLastDownload = null,
InvoiceLastIp = ""
};PsAECInvoiceHistoryRepository.Add(newInvoice);
Thank you for guiding me in my research.
Using fetch but nothing works
Related
I am trying to catch the specific error when a certain API key expires or it reaches its daily response limit(assuming 1000 per day).
const moviesearchEngine=()=>{
let searchBox = document.querySelector('.searchBox');
let movieTitle = document.querySelector('.movieTitle');
let yearofRelease = document.querySelector('.yearofRelease');
let genre = document.querySelector('.genre');
let director = document.querySelector('.director');
let plot = document.querySelector('.plot');
const apiCall = ()=>{
let params = new URLSearchParams({
t:searchBox.value,
apikey:`key`
})
let api = `http://www.omdbapi.com/?${params}`;
//fetching the api orelse showing the error
fetch(api).then((response)=>{
return response.json();
}).then((data)=>{
//assigning the data to variable
console.log(data)
})
}
apiCall();
}
Please Go through your desired API's documention and you would be looking for this sort of information mentioned in the Usage limits section of this api page. If you fail to find anything useful then please contact the support of your desired API.
Then you can proceed like this -
var endpoint = 'http://ip-api.com/json/?fields=status,message,countryCode';
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var response = JSON.parse(this.responseText);
if(response.status !== 'success') {
console.log('query failed: ' + response.message);
return
}
// Redirect
if(response.countryCode == "US") {
window.location.replace("https://google.com/");
}
if(response.countryCode == "CA") {
window.location.replace("https://google.ca/");
}
}
};
xhr.open('GET', endpoint, true);
xhr.send();
Source
Before I start, here is the API. Super simple: https://www.cryptonator.com/api
To note, I have worked with api before, but i used a await async function, but for some reason I couldn't get that to work....but I found a tutorial for doing this with XML http request, so I decided to just move forwards doing it in XML because I was able to make a simple Bitcoin ticker.
I am building a simple widget to display the prices of Bitcoin, Litecoin, and Ethereum using the cryptonator API. Like I said above, I made a bitcoin ticker with the first function ( see code below ), and it works great. However, I am having issues trying to get 3 different currencies.
Here is what I am trying to do.
var url = "https://api.cryptonator.com/api/ticker/btc-usd";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
function parseJson(json) {
var usdValue = json["ticker"]["price"];
document.getElementById("data").innerHTML = usdValue;
var usdValue = usdValue.replace(/[^\d.\-]/g, "");
var usd = parseFloat(usdValue);
document.getElementById("data").innerHTML = "$ " + usd.toFixed(2);
}
//
//
var xmlhttp2 = new XMLHttpRequest();
var url2 = "https://api.cryptonator.com/api/ticker/ltc-usd";
xmlhttp2.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp2.open("GET", url2, true);
xmlhttp2.send();
function parseJson(json) {
var LTCusdValue = json["ticker"]["price"];
// document.getElementById("data2").innerHTML = LTCusdValue;
var LTCusdValue = LTCusdValue.replace(/[^\d.\-]/g, "");
var LTCusd = parseFloat(LTCusdValue);
document.getElementById("data2").innerHTML = "$ " + LTCusd.toFixed(2);
}
//
//
//
var xmlhttp3 = new XMLHttpRequest();
var url3 = "https://api.cryptonator.com/api/ticker/eth-usd";
xmlhttp3.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp3.open("GET", url3, true);
xmlhttp3.send();
function parseJson(json) {
var ETHusdValue = json["ticker"]["price"];
// document.getElementById("data3").innerHTML = ETHusdValue;
var ETHusdValue = ETHusdValue.replace(/[^\d.\-]/g, "");
var ETHusd = parseFloat(ETHusdValue);
document.getElementById("data3").innerHTML = "$ " + ETHusd.toFixed(2);
}
As you can see, I am trying to make 3 request to 3 different APis, but it isn't working. If I comment out all but one of these functions, it works fine. My issues comes when i try to use all 3 at once. If i use Bitcoin and Litecoin only, it will actually work, but will just break again once I try to use the 3rd function ( to get ethereum price ).
The parseJson function is defined three times. This means that every time you write the function it will overwrite the previous definition. So in your case only the last parseJson function will be used for all three requests. You could do a couple of things.
Write three different variations. (Bad practice)
Though this would be the less favorable of the options. It will require you to have repeated code copied multiple times. This can be done more efficiently.
function parseJson1(json) {
...
}
function parseJson2(json) {
...
}
function parseJson3(json) {
...
}
Add an argument to the function. (Good practice)
Give the parseJson function a second argument that selects the element to output the value. This should be the id of the element you'll want to select.
This is the better solution because it only requires you to write a function once and call it multiple times accounting for the variations.
function parseJson(json, id) {
var output = document.getElementById(id); // Select the element based on the id.
if (output === null) { // If element is not found, stop the function.
return;
}
var price = json["ticker"]["price"];
var usdValue = price.replace(/[^\d.\-]/g, "");
var usd = parseFloat(usdValue);
output.innerHTML = "$ " + usd.toFixed(2);
}
The last technique is applicable to the rest of your code. Be aware of repeating yourself. You'll write much cleaner and better code when you only have to write something once.
If I understood you well you can create a method for all cryptos and avoid repeting the same code. If you run the example below you will be able to see all cryptos and also it's easy to add new ones:
const URL = 'https://api.cryptonator.com/api/ticker/'
const cryptos = ['btc', 'ltc', 'eth']
cryptos.map(crypto => {
fetch(`${URL}${crypto}-usd`)
.then(data => data.json())
.then(({ ticker: { base, price } }) => console.log(`${base}: ${(+price).toFixed(2)}`))
})
We are using fetch that is modern XHR. Hope this help.
You should be able to write an async wrapper function for this using a Promise.. This will allow you to use async/await with XHR..
To make using XHR a lot easier, you can use the built in fetch API.. According to this, most browsers support fetch.. All in all, I prefer using fetch over axios, XHR, etc.. but since you specifically asked about XHR, that is how I answered.
If you did not want to await each response, you can do something like this:
// basic XHR wrapper function for 'get'
function getXHR(url) {
return new Promise(function(resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
this.status == 200
? resolve(this.responseText)
: reject(this.status);
}
};
xhr.send();
});
}
const ethElement = document.getElementById("eth");
const bcElement = document.getElementById("bc");
const lcElement = document.getElementById("lc");
// etherium
getXHR("https://api.cryptonator.com/api/ticker/eth-usd")
.then(eth => {
// Can turn into JSON like this:
//const ethJson = JSON.parse(eth);
ethElement.innerHTML = eth;
})
// bitcoin
getXHR("https://api.cryptonator.com/api/ticker/btc-usd")
.then(bc => {
// Can turn into JSON like this:
//const bcJson = JSON.parse(bc);
bcElement.innerHTML = bc;
})
// litecoin
getXHR("https://api.cryptonator.com/api/ticker/ltc-usd")
.then(lc => {
// Can turn into JSON like this:
//const lcJson = JSON.parse(lc);
lcElement.innerHTML = lc;
})
<h1>eth:</h1>
<pre id="eth"></pre>
<h1>bc:</h1>
<pre id="bc"></pre>
<h1>litecoin:</h1>
<pre id="lc"></pre>
I have created the following demo to show you how to accomplish this using async/await:
Init(); // call 'main' function
// basic XHR wrapper function for 'get'
function getXHR(url) {
return new Promise(function(resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
this.status == 200
? resolve(this.responseText)
: reject(this.status);
}
};
xhr.send();
});
}
// "Main" function
async function Init() {
const ethElement = document.getElementById("eth");
const bcElement = document.getElementById("bc");
const lcElement = document.getElementById("lc");
// etherium
const eth = await getXHR("https://api.cryptonator.com/api/ticker/eth-usd");
const ethJson = JSON.parse(eth);
ethElement.innerHTML = ethJson.ticker.price + " " + ethJson.ticker.target;
// bitcoin
const bc = await getXHR("https://api.cryptonator.com/api/ticker/btc-usd");
const bcJson = JSON.parse(bc);
bcElement.innerHTML = bcJson.ticker.price + " " + bcJson.ticker.target;
// litecoin
const lc = await getXHR("https://api.cryptonator.com/api/ticker/ltc-usd");
const lcJson = JSON.parse(lc);
lcElement.innerHTML = lcJson.ticker.price + " " + lcJson.ticker.target;
}
div h1,
div p {
display: inline;
vertical-align: top;
font-family: 'Open Sans', sans-serif;
line-height: 38px;
}
<div>
<h1>eth:</h1>
<p id="eth"></p>
</div>
<div>
<h1>btc:</h1>
<p id="bc"></p>
</div>
<div>
<h1>ltc:</h1>
<p id="lc"></p>
</div>
Hey everybody I have a problem.
I am building a website and I want to fetch data from two different xml files with two different functions.
ShowResult is used to get a game score and the name of a specific user.
GiveFeedback also needs the score from the first function to fetch a fitting feedback about this score from a different xml file.
I don´t get an error Message. My only problem is that the second function (giveFeedback) isn´t able to fetch data from the xml because it needs a variable (score) from the first function (showResults). Both functions work on their own but I am unable to “transfer” the score data from showResults to giveFeedback.
How can I transfer the score data to the function GiveFeedback or is there a better way to resolve this problem?
Thanks!
i tried some solutions (global variable, inserting the first function in the second,..) which were already posted but unfortunately i didn´t managed to get it running.
<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
showResult(xhttp.responseXML);
}
};
xhttp.open("GET", "user.xml", true);
xhttp.send();
function showResult(xml) {
var name = "";
var score = "";
path1 = "/userdb/user/name";
path2 = "/userdb/user/score";
var nodes = xml.evaluate(path1, xml, null, XPathResult.ANY_TYPE, null); var result = nodes.iterateNext();
name = result.childNodes[0].nodeValue;
var nodes = xml.evaluate(path2, xml, null, XPathResult.ANY_TYPE, null); var result = nodes.iterateNext();
//Thats wehere the variable (score) is, which i need for the second function (giveFeedback)
score = result.childNodes[0].nodeValue;
document.getElementById("user").innerHTML = "Congratulations " + name + ", you made " + score;
}
var xhttp2 = new XMLHttpRequest();
xhttp2.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
givefeedback(xhttp2.responseXML);
}
};
xhttp2.open("GET", "feedback.xml", true);
xhttp2.send();
function givefeedback(xml) {
var feedback = "";
// This is where it´s needed
if (score > 1){
path = "/feedback/congratulations[percentage=25]/text";
}
else if (score > 8){
path = "/feedback/congratulations[percentage=50]/text";
}
var nod = xml.evaluate(path, xml, null, XPathResult.ANY_TYPE, null);
var res = nod.iterateNext();
feedback = res.childNodes[0].nodeValue;
document.getElementById("feedback").innerHTML = feedback;
}
</script>
i managed to resolve my problem.
first of all i had to declare a global variable outside the functions.
Then i had to convert the fetched variable (score) to a Number.
I am trying to change page but without any reloading
here's what I do:
AJAX:
app.ajax.client.request = function(headers, path, method, queryObj, payload, cb) {
// Set defaults
headers = typeof(headers) == 'object' && headers !== null ? headers : {};
path = typeof(path) == 'string' ? path : '/';
method = typeof(method) == 'string' && ['POST','PUT','DELETE','GET'].indexOf(method.toUpperCase()) > -1 ? method.toUpperCase() : 'GET';
queryObj = typeof(queryObj) == 'object' && queryObj !== null ? queryObj : {};
payload = typeof(payload) == 'object' && payload !== null ? payload : {};
cb = typeof(cb) == 'function' ? cb : false;
// For each query string parameter sent, add it to the path
let requestUrl = path + '?';
let counter = 0;
// Set the request url based on the query object
for (let i in queryObj) {
if (queryObj.hasOwnProperty(i)) {
counter++
if (counter > 1) {
requestUrl += '&';
}
requestUrl += i + '=' + queryObj[i];
}
}
// Form the http request as a JSON type
let xhr = new XMLHttpRequest();
xhr.open(method, requestUrl, true);
xhr.setRequestHeader('Content-Type', 'application/json');
// For each header sent, add it to the request
for (let i in headers) {
if (headers.hasOwnProperty(i)) {
xhr.setRequestHeader(i, headers[i]);
}
}
// When the request comes back, handle the response
xhr.onreadystatechange = function() {
// Set the parameters that will be called back
let readyState = xhr.readyState;
let statusCode = xhr.status;
let responseReturned = xhr.responseText;
// Parse the response
let parsedResponse = app.isJsonString(responseReturned);
if (parsedResponse) { // If the response text is a JSON, callback parsedResponse, if not, callback the not parsed response instead
cb(readyState, statusCode, parsedResponse);
} else {
cb(readyState, statusCode, responseReturned);
}
}
// Send the payload as JSON
let payloadString = JSON.stringify(payload);
xhr.send(payloadString);
}
Client Requests:
app.changeToIndexPage = function(e) {
e.preventDefault();
if (!app.mainContainer.hasClass('index')) {
app.closePage(); // show a loading screen
history.pushState({}, '', '/'); //Set the url to the index's url
setTimeout(function() {
app.ajax.client.request(undefined, 'public/request/index.txt', 'GET', undefined, undefined, function(readyState, statusCode, response) { // Get the request
console.log(readyState);
if (readyState < 3) {
app.preloader.addClass('loading');
} else if (readyState == 4 && statusCode == 200) {
app.navContainer.attr('class', app.navContainer.attr('class').replace(/index|project|about|contact/g, 'index'));
setTimeout(function() {
app.mainContainer.html(response);
}, 500);
}
});
}, 100);
}
}
So, for example:
If I am not on the index page, and wanted to go to the index page, i can run the changeToIndexPage function, and the ajax will request the needed file and change the html element based on the needed action. The only problem that I had is, are there any better solution??
If you're going to take the approach of fetching pages with AJAX and slapping them into the document, which I wouldn't recommend in the first place, you should have a generalized function to do so.
That function should have a signature like function navigate(path) { ... }. It should add the history entry, fetch the appropriate document and insert it onto the page.
Then, you'll need to attach an event listener to catch popState events, so when the user presses the back button you retrieve the path from the history entry that was popped and pass it to navigate().
Again, if you're looking to build an SPA I wouldn't recommend building it like this. One of the major benefits of SPAs are the performance gain from rendering your documents on the client, which this approach doesn't leverage. Consider using a component-based client-side rendering library like React or Angular.
I'm having trouble with reading the content of a "TaskAttachment" that I uploaded from one extension to another.
I'm using this code to get the "TaskAttachment", I'm getting it with the right name and URL, (Which I get have access to without nay authentication, e.g. from another clean browser)
var taskClient = DT_Client.getClient();
taskClient.getPlanAttachments(vsoContext.project.id, "build", build.orchestrationPlan.planId, "MyExtType").then((taskAttachments) => {
$.each(taskAttachments, (index, taskAttachment) => {
if (taskAttachment._links && taskAttachment._links.self && taskAttachment._links.self.href) {
var link = taskAttachment._links.self.href;
var attachmentName = taskAttachment.name;
var fileContent = readText(link);
...
And this javascript function to read the content
...
var readText = function readTextFile(file)
{
alert("file = " + file);
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, false);
rawFile.onreadystatechange = function ()
{
alert("rawFile.readyState = " + rawFile.readyState);
alert("rawFile.status = " + rawFile.status);
alert("rawFile.responseText = " + rawFile.responseText);
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
alert(allText);
return allText;
}
}
}
rawFile.send(null);
return "Failed to get data..";
}
The problem is that I'm getting 401 error message :
"IIS 7.5 Detailed Error - 401.2 - Unauthorized"
How can I read this file content? Is there a better way to transfer data from a "Build Step Extension" to a "UI Extension" that present the data in the build summary page (new tab)?
According to "IIS 7.5 Detailed Error - 401.2 - Unauthorized" It's most likely due to directory permissions set in the file system.
Make sure Anonymous access is enabled on IIS -> Authentication.
Right click on it, then click on Edit, and choose a domain\username and password.
I just managed to read the attachment data using the "getAttachmentContent" method:
I'm not sure why MS doesn't put any reference to this function in the tutorial, after long digging in the documentation \ Q&A I found it.
taskClient.getPlanAttachments(vsoContext.project.id, "build", build.orchestrationPlan.planId, "My_Attachment_Type").then((taskAttachments) => {
$.each(taskAttachments, (index, taskAttachment) => {
if (taskAttachment._links && taskAttachment._links.self && taskAttachment._links.self.href) {
var recId = taskAttachment.recordId;
var timelineId = taskAttachment.timelineId;
taskClient.getAttachmentContent(vsoContext.project.id, "build", build.orchestrationPlan.planId,timelineId,recId,"My_Attachment_Type",taskAttachment.name).then((attachementContent)=> {
function arrayBufferToString(buffer){
var arr = new Uint8Array(buffer);
var str = String.fromCharCode.apply(String, arr);
return str;
}
var data = arrayBufferToString(attachementContent);