authClient is not called with the AUTH_ERROR - admin-on-rest

I'm trying to implement custom rest client build on top of simple fetch.
If 401-403 response received, it must "redirect" app to login page.
According documentation, if 401-403 error received, it will magically calls authClient with the AUTH_ERROR, but it doesn't.
Can someone explain, how to connect it?
I'm trying to call rest client from component: It's simple reimplementation of 'simpleRestClient'
componentDidMount() {
restClient(CREATE, 'api/method', {
CurrentTime: new Date()
})
.then(o =>
{
this.setState({ Msg: Object.values(o.data.ServerTime) });
});
}
restclient implementation:
export const fetchJson = (url, options = {}) => {
const requestHeaders =
options.headers ||
new Headers({
Accept: 'application/json',
});
if (
!requestHeaders.has('Content-Type') &&
!(options && options.body && options.body instanceof FormData)
) {
requestHeaders.set('Content-Type', 'application/json');
}
if (options.user && options.user.authenticated && options.user.token) {
requestHeaders.set('Authorization', options.user.token);
}
return fetch(url, { ...options, headers: requestHeaders })
.then(response =>
response.text().then(text => ({
status: response.status,
statusText: response.statusText,
headers: response.headers,
body: text,
}))
)
.then(({ status, statusText, headers, body }) => {
if (status < 200 || status >= 300) {
return Promise.reject(
new HttpError(
(json && json.message) || statusText,
status,
json
)
);
}
let json;
try {
json = JSON.parse(body);
} catch (e) {
// not json, no big deal
}
return { status, headers, body, json };
});
};
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
return fetchJson(url, options);
}

Have you tried rejecting the promise with an Error rather than an HttpError?

Related

How to define a function 'server.remove' identical to 'server.revert'

How to define a function 'server.remove' (removing local files) identical to 'server.revert'.
'server.revert' send 'DELETE' request to '/api' with filename in request body.
I do not quite understand how the function should be organized, try something like that, but it does not work:
mounted() {
this.server = {
url: '/api',
remove: (source, load, error, revert) => {
revert(source);
error('oh my goodness');
load();
},
headers: {
Authorization: 'Bearer ' + this.token,
},
};
},
See here for the function signature, so something like this:
this.server = {
remove: (source, load, error) => {
const request = new XMLHttpRequest();
request.open('DELETE', 'url-to-api/' + source);
request.onload = function () {
if (request.status >= 200 && request.status < 300) {
load(request.responseText);
} else {
error('oh no');
}
};
request.send();
},
}

Download an image to React Native from a Laravel server?

I am looking to download an image stored on a server into my React Native app.
I had a function that looked like this:
public function image(Request $request, $id)
{
$company = Company::find($id);
$filePath = storage_path() . '/app/' . $company->image;
return response()->file($filePath);
}
And it returned nothing I could read within the app when I tried the following function:
setCompany = async () => {
let company = await AsyncStorage.getItem('currentCompany');
company = JSON.parse(company);
if (company.image !== null) {
let image = await getCompanyPicture({company_id: company.id});
console.log('Here: ', image);
// This is blank, react native returns a warning about data not being of a readable type
}
this.setState({company});
};
I am able to get the image in base_64 using this method:
public function image(Request $request, $id)
{
$company = Company::find($id);
$file_path = storage_path('/app/' . $company->image);
if (file_exists($file_path)) {
$fileData = file_get_contents($file_path);
$fileEncode = base64_encode($fileData);
return response()->json(['status' => 'success', 'data' => ['file' => $fileEncode, 'file_path' => $file_path]]);
}
return response()->json(['status' => 'failure', 'data' => ['file' => null, 'file_path' => $file_path]]);
}
Here is my Axios method too just in case:
export const sendRequest = async (url, data, token, method) => {
let headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Method': 'POST, GET, DELETE, PUT',
};
if (typeof token !== 'undefined' && token !== 'undefined' && token.length) {
headers.Authorization = 'Bearer ' + token;
}
if (method === 'get' && data) {
url +=
'?' +
Object.keys(data)
.map((value) => {
return value + '=' + data[value];
})
.join('&');
data = null;
}
return await axios({
headers: headers,
method: method ? method : 'post',
url: url,
data: data,
})
.then((response) => {
return response;
})
.then((json) => {
return json.data;
})
.catch((error) => {
console.error(error);
if (
error.message !== 'Network Error' &&
error.response.status !== 500 &&
error.response.status !== 413
) {
return error.response.data;
} else if (error.message === 'Network Error') {
return {
status: 'error',
message: 'Unable to connect to server',
};
} else if (error.response.status === 500) {
return {
status: 'error',
message: 'Internal Server Error',
};
} else if (error.response.status === 413) {
return {
status: 'error',
message: 'The file(s) size is too large',
};
} else {
return {
status: 'error',
message: error.message,
};
}
});
};
If anyone could comment on the performance impact of using base_64 instead of the straight file download that would also be helpful
But ultimately I would like a solution for handling the Laravel response()->file() if possible (which I'll use if base_64 is less efficient)
I'm not sure about RN code syntax, but I've ready code with jQuery+poorJS, which looks like this:
$.ajax({
url: "load-image-url", // URL FOR GET REQUEST
cache:false,
xhr: function() { // ACTUALLY THIS PART CAN BE USED AND CUSTOMIZED BY YOU
let xhr = new XMLHttpRequest();
xhr.responseType= 'blob'
return xhr;
},
success: function(data) {
let url = window.URL || window.webkitURL;
$('#image').attr('src', url.createObjectURL(data));
},
error: function(err) {
// console.log(err);
}
}).fail(function() {
$('#ss_product_image').attr('src', "default-image-url.jpg");
});
In my example I've used GET request (but you can try to modify it and test if you want, honestly IDK about that).
This is the back-end part:
public function image(Request $request, $id)
{
// HERE YOU NEED TO GET YOUR IMAGE (using $id or/and $request params) CONTENT FROM SOMEWHERE YOU WANT
$content = <CONTENT>;
return response()->make($content, 200, [
'Content-Type' => (new \finfo(FILEINFO_MIME))->buffer($content),
'Content-length' => strlen($content),
]);
}
I was able to solve this issue by using rn-blob-fetch.
The files are downloaded into a temp cache which can then be accessed for previewing and saving.
this is my function now:
downloadFiles = async (isReply) => {
let {enquiry, reply} = this.state;
this.setState({isLoading: true});
const token = await AsyncStorage.getItem('userToken');
let filePaths = [];
let fileCount = 0;
let files = enquiry.files;
if (isReply) {
files = reply.files;
}
const dirToSave =
Platform.OS == 'ios'
? RNFetchBlob.fs.dirs.DocumentDir
: RNFetchBlob.fs.dirs.DownloadDir;
new Promise((resolve, reject) => {
for (var i = 0; i < files.length; i++) {
var id = files[i].file_id;
var name = files[i].file.file_name;
var ext = extension(name);
const configOptions = Platform.select({
ios: {
appendExt: ext,
fileCache: true,
title: name,
path: `${dirToSave}/${name}`,
},
android: {
useDownloadManager: true,
notification: true,
mediaScannable: true,
fileCache: true,
title: name,
path: `${dirToSave}/${name}`,
},
});
var mime = content(ext);
let headers = {
'Content-Type': mime,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Method': 'POST, GET, DELETE, PUT',
Authorization: 'Bearer ' + token,
};
RNFetchBlob.config(configOptions)
.fetch('GET', BASE_API + '/enquiries/files/download/' + id, headers)
.then(async (response) => {
RNFetchBlob.fs.writeFile(
configOptions.path,
response.data,
'base64',
);
filePaths.push({
title: configOptions.title,
path: configOptions.path,
ext: extension(configOptions.title),
mime,
});
fileCount++;
if (fileCount >= files.length) {
resolve('Download Successful!');
}
})
.catch((error) => {
console.log('File Download Error: ', error.message);
reject('Download Failed');
});
}
})
.then((data) => {
this.setState({isLoading: false, filePaths});
})
.catch((error) => {
console.log('Download Promise Error: ', error);
this.setState({isLoading: false});
});
};
previewDocument = (id) => {
let {filePaths} = this.state;
if (Platform.OS == 'ios') {
RNFetchBlob.ios.openDocument(filePaths[id].path);
} else if (Platform.OS == 'android') {
RNFetchBlob.android.actionViewIntent(
filePaths[id].path,
filePaths[id].mime,
);
}
};

How do I get the message using Office.js in a react add-in

I am building a new react Outlook add-in and need to be able to download the current email.
The Office.js API has the getFileAsync method off the Office.context.document object but not the Office.context.mailbox.item object.
also as a requirement this needs to work in both Office online and local installs of Outlook.
In the existing com add-in I had direct access to the mail item.
Here is the code that I currently have to call into the API, but this only retrieves metadata.
/*
https://learn.microsoft.com/en-us/outlook/add-ins/use-rest-api#get-the-item-id
*/
public getMessageViaRest = () => {
const context: Office.AsyncContextOptions & { isRest: boolean } = {
isRest: true
};
Office.context.mailbox.getCallbackTokenAsync(context, (tokenResults) => {
if (tokenResults.status === Office.AsyncResultStatus.Failed) {
this.setState({ error: 'Failed to get rest api auth token' });
return;
}
const apiId: string = Office.context.mailbox.convertToRestId(Office.context.mailbox.item.itemId, 'v2.0');
const apiUrl = Office.context.mailbox.restUrl + '/v2.0/me/messages/' + apiId;
try {
fetch(apiUrl, {
method: 'GET',
headers: new Headers({
Authorization: 'Bearer ' + tokenResults.value
})
}).then((response) => {
response.json().then((body) => {
for (const key in body) {
this.state.details.push({ name: key, value: JSON.stringify(body[key]) });
}
this.forceUpdate();
});
});
} catch (error) {
this.setState({ error: JSON.stringify(error) });
}
});
}
Its not perfect but the REST Api does have an end point that will return the file's EML contents.
public downloadViaRest = () => {
const context: Office.AsyncContextOptions & { isRest: boolean } = {
isRest: true
};
Office.context.mailbox.getCallbackTokenAsync(context, (tokenResults) => {
if (tokenResults.status === Office.AsyncResultStatus.Failed) {
this.setState({ error: 'Failed to get rest api auth token' });
return;
}
const apiId: string = Office.context.mailbox.convertToRestId(Office.context.mailbox.item.itemId, 'v2.0');
const apiUrl = Office.context.mailbox.restUrl + '/v2.0/me/messages/' + apiId + '/$value';
try {
fetch(apiUrl, {
method: 'GET',
headers: new Headers({
Authorization: 'Bearer ' + tokenResults.value
})
}).then((response) => {
response.blob().then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'Message.eml';
a.click();
});
});
} catch (error) {
}
});
}

Network Request failed while sending image to server with react native

i want to send image to a server and getting the result with a json format but the application returns a Network Request failed error
react native 0.6 using genymotion as emulator
i tried RNFetchblob but the result take a long time to get response (5 min )
also i tried axios but it response with empty data with 200 ok
this is the function that import the image
OnClick = () => {
ImagePicker.showImagePicker(options, response => {
console.log("Response = ", response);
if (response.didCancel) {
console.log("User cancelled image picker");
} else if (response.error) {
console.log("Image Picker Error: ", response.error);
} else {
let source = { uri: response.uri };
// You can also display the image using data:
//let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
avatarSource: source,
data: response.data,
BtnDisabled: false
});
console.log();
}
});
};
and this method that sends the image
Send = async () => {
let url = "http://web001.XXX.com:8000/api/prediction/check_prediction/";
let UplodedFile = new FormData();
UplodedFile.append('file',{ type:'image/jpeg', uri : this.state.avatarSource , name:'file.jpeg'});
fetch(url, {
method: 'POST',
body:UplodedFile
})
.then(response => response.json())
.then(response => {
console.log("success");
console.log(response);
})
.catch(error => {
console.error(error);
});
i expect json format
ScreenShot here
can you change your code like this?
OnClick = () => {
ImagePicker.showImagePicker(options, response => {
console.log("Response = ", response);
if (response.didCancel) {
console.log("User cancelled image picker");
} else if (response.error) {
console.log("Image Picker Error: ", response.error);
} else {
let source = { uri: response.uri };
// You can also display the image using data:
//let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
pickerResponse: response,
data: response.data,
BtnDisabled: false
});
console.log();
}
});
};
Send = async () => {
let url = "http://web001.XXX.com:8000/api/prediction/check_prediction/";
let UplodedFile = new FormData();
UplodedFile.append('file',{ type:'image/jpeg', uri : this.state.pickerResponse.path , name:'file.jpeg'});
axios({
method: "post",
url: url,
data: UplodedFile
})
.then(response => {
console.log("success");
console.log(response);
})
.catch(error => {
console.error(error);
});

How to turn on Autorization?

"By default, an admin-on-rest app doesn’t require authentication".
I have written an application with AOR and Loopback API, etc, and it works well. Except for one thing, I can't turn on turn on authentication. Any username/password will work, just like in the Demo.
From what I can see all required components load, AuthClient etc., Loopback is configured and is waiting for user authorization requests but never gets any.
I copy/pasted a lot of Demo's parts...
Any hints please?
I use the unchanged authClient from kimkha aor loopback
import storage from './storage';
export const authClient = (loginApiUrl, noAccessPage = '/login') => {
return (type, params) => {
if (type === 'AUTH_LOGIN') {
const request = new Request(loginApiUrl, {
method: 'POST',
body: JSON.stringify(params),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({ ttl, ...data }) => {
storage.save('lbtoken', data, ttl);
});
}
if (type === 'AUTH_LOGOUT') {
storage.remove('lbtoken');
return Promise.resolve();
}
if (type === 'AUTH_ERROR') {
const { status } = params;
if (status === 401 || status === 403) {
storage.remove('lbtoken');
return Promise.reject();
}
return Promise.resolve();
}
if (type === 'AUTH_CHECK') {
const token = storage.load('lbtoken');
if (token && token.id) {
return Promise.resolve();
} else {
storage.remove('lbtoken');
return Promise.reject({ redirectTo: noAccessPage });
}
}
return Promise.reject('Unkown method');
};
};

Resources