In my Flutter mobile app while loading profile image of users through NetworkImage(), I am getting 403 status code in response.
How can I handle this by displaying an Image from my assets folder in case of 403 status code or if image URL is broken etc.
Currently I've handled it by sending a HTTP GET request to the image URL and checking if the status code is 200. If it is 200 I use the NetworkImage() or else I use AssetImage() to load the image and use a FutureBuilder() to build the Widget.
While this works perfectly, I feel this a lot of trouble for handling such a small scenario and it can be done in a better way that I am unaware of.
What is the best way to handle such scenarios?
Please try below approach. Here, If image is available, It will load network image else it will redirect to the error callback. In error callback you can return the widget you want. In your case, you want to load from asset so you can use it like as below. If you want to check error status code, you need to parse the exception that I have print.
Image.network('https://www.outbrain.com/techblog/wp-content/uploads/2017/05/road-sign-361513_960_720.jpg',
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
print("Exception >> ${exception.toString()}");
return Image.asset('assets/images/lake.jpg');
},
)
You did it simple for this scenario, I didnt see any trouble:
if (response.statusCode == 200) {
return NetworkImage();
} else {
return AssetImage();
}
I achieved this by using precacheImage. This will precache your image to flutter cache. It also has a onError function where you can handle errors while caching the image.
String validatedUrl;
precacheImage(
NetworkImage(urlToCheck),
context,
onError: (
exception,
stacktrace,
) {
print(exception.toString());
setState(() {
validatedUrl = '';
});
},
).whenComplete(() {
if (validatedUrl == null) {
setState(() {
validatedUrl = urlToCheck;
});
}
});
Then validatedUrl is either null, empty or carries the validated url.
null -> not validated yet
empty -> error while downloading image
url -> successfully downloaded image
Related
I am now using the below cloud code to only update "downloads" column on my parse server running on AWS EC2 instance. But I am getting the error code 141(invalid function)
Parse.Cloud.define("updateDownloads", async (request) => {
const query = new Parse.Query(request.params.className);
query.get(request.params.objectId)
.then((watchFace) => {
downloads = watchFace.get("downloads")
watchFace.set("downloads", downloads + 1);
await watchFace.save(null, { useMasterKey: true });
return "download updated";
}, (error) => {
return "something went wrong";
});
});
I have place my code in /opt/bitnami/cloud/main.js.
I even tried adding “cloud”: “/opt/bitnami/cloud/main.js” in config.json file but then the parse server gives 503 Service Unavailable error. So I removed it.
If you don't add the cloud code main.js file to your parse server configuration, parse server will never find your function, and that's why you get the invalid function error.
If you get error when adding the file, you are either adding it in a wrong way (you need to check your parse server initialization code) or the config.json is in wrong format or the cloud code has a problem.
The best way to figure it out is by checking your logs.
At a first glance, a problem that I see (may have others) is the usage of await in a function that is not async. You are also using a combination of async and then, which is little strange.
I'd recommend you to change the code to something like:
Parse.Cloud.define("updateDownloads", async (request) => {
const query = new Parse.Query(request.params.className);
const watchFace = await query.get(request.params.objectId);
const downloads = watchFace.get("downloads");
watchFace.set("downloads", downloads + 1); // You can use inc function to avoid concurrency problem
await watchFace.save(null, { useMasterKey: true });
return "download updated";
});
So yesterday I was developing some sort of offline functionality. Therefore, I added an ApiService that returns Observables.
Currently, I fetch my access_token for jwt-Authentication and then use this token to generate Headers for my API-Request. After a successful request, I save the result to my storage. This works fine. Now here is the problem I want to check for an unsuccessful request (e.g. servers are down, app is offline) and then return my stored result from storage. But I can't get it to work.
Here is my code:
getJobs(): Observable<any> {
this.auth.checkToken()
return from(this.storage.get(ACCESS_TOKEN)).pipe(
switchMap(token => {
let options = this.auth.addToken(token)
return this.http.get(API_URL + "jobs", options)
}),
map(res => {
if (res) {
this.storage.set(JOBS, res)
return res
} else {
return from(this.storage.get(JOBS))
}
}),
catchError(() => {
return from(this.storage.get(JOBS))
})
)
}
Further investigations have shown that after the server or the app is offline neither the map() nor the catchError() functions were executed.
UPDATE:
The solution provided by DJ House is correct. My Code works perfectly in my browser but if I build my app with ionic cordova build android it gets stuck after the this.http.get(...) So it's clearly and issue with cordova
SOLUTION:
Wow! Something magical happened! I've found out that the catchError method gets called BUT after almost 2 Minutes, which is way to slow... So I will implement a timeout.
Thanks
flixoflax
The main issue that you may be facing is you are using the map incorrectly. Map acts upon a normal value (usually, its not an observable) and returns a new value. map() should always return the same type of value. In your map() you are either return the response (which I am assuming is of type Jobs) OR you are return an Observable<Jobs>. This will cause your subscribers to need verbose logic to handle that.
It looks like you are trying to use that map() to set your local storage with the returned jobs from your api. I would recommend using tap() since you aren't trying to change the value you are returning.
function getJobs(): Observable<any> {
this.auth.checkToken()
return from(this.storage.get(ACCESS_TOKEN)).pipe(
switchMap(token => {
let options = this.auth.addToken(token)
return this.http.get(API_URL + "jobs", options)
}),
// change to tap()
tap(res => {
if (res) {
this.storage.set(JOBS, res)
}
}),
catchError(() => {
return from(this.storage.get(JOBS))
})
)
}
If the switchMap throws an error, the tap will be skipped. That will ensure you only set storage if you recieve a value from the API. If you always want to set the storage (even if the API threw an error) then move the tap() to be after the catchError().
Can you please try moving the catchError operator as first operator inside pipe method. This is to ensure that you catch error as soon as you recieve it from observable. Please change it like below:
getJobs(): Observable<any> {
this.auth.checkToken()
return from(this.storage.get(ACCESS_TOKEN)).pipe(
switchMap(token => {
let options = this.auth.addToken(token)
return this.http.get(API_URL + "jobs", options)
}),
catchError(() => {
return from(this.storage.get(JOBS))
})
map(res => {
if (res) {
this.storage.set(JOBS, res)
return res
} else {
return from(this.storage.get(JOBS))
}
}),
)
}
I am having a problem with uploading an image in ios apollo client. after I upload an image I get a GraphQlError "createReadStream is not a function".
I could not figure out what has gone wrong?
Mutation
mutation UploadPhoto($input: UploadPhotoInput){
uploadClientPhoto(input: $input){
photo
}
}
Type Detail
type UploadPhotoInput {
photo: Upload
}
type UploadPhotoResponse {
photo: String
}
Following code is not working
class Network {
static let shared = Network()
private lazy var networkTransport = HTTPNetworkTransport(url: URL(string: "http://192.168.10.29:5001/graphql")!, session: .init(configuration: URLSessionConfiguration.default))
private(set) lazy var apolloCient = ApolloClient(networkTransport: networkTransport)
}
Upload image
if let data = singlePhoto.image.jpegData(compressionQuality: 0.8) {
let name = UUID().uuidString
let file = GraphQLFile(fieldName: "\(name)", originalName: "\(name).png",mimeType: "image/png" ,data: data)
let uploadInput = UploadPhotoInput(photo: file.originalName)
let uploadMutation = UploadPhotoMutation(input: uploadInput)
Network.shared.apolloCient.upload(operation: uploadMutation, context: nil, files: [file]) { (result) in
switch result {
case .success(let success):
print(success.data)
case .failure(let error):
print(error.localizedDescription)
}
}
}
This certainly sounds frustrating. I've heard of similar issues with other networking clients, though.
Sounds like apolloCient.upload won't send a GraphQL Multipart Request.
Looks like this blog post covers exactly how to set this up - even including an example repo made for React Native.
Hope that's helpful!
Iam new in ionic with sharepoint
I have developed a Mobile app using ionic3 with sharepoint.
Now i have to get user profile picture in my app.
I have tried these are the way can't achieve here is my tried code.
First way tried like this
Passing Url:-
"https://abc.sharepoint.com/sites/QA/_layouts/15/userphoto.aspx?size=M&accountname=admin#abc.onmicrosoft.com"
Second way tried like this
Passing Url:-
These url iam geting using people picker result. PictureURL property
"https://abc.sharepoint.com/User Photos/Profile Pictures/admin_abc_onmicrosoft_com_MThumb.jpg"
These Second method always return
401 UNAUTHORIZED
Above url using to call this method.
public downloadFile(url: string, fileName: string) {
let options = this._apiHeaderForImageURL();
this._http.get(url, options)
.subscribe((data) => {
//here converting a blob to base 64 For internal view purpose in image src
var reader = new FileReader();
reader.readAsDataURL(data.blob());
reader.onloadend = function () {
console.log("Base64", reader.result);
}
//Here Writing a blob file to storage
this.file.writeFile(this.file.externalRootDirectory, fileName, data.blob(), { replace: true })
.then((success) => {
console.log("File Writed Successfully", success);
}).catch((err) => {
console.log("Error While Wrinting File", err);
});
});
}
public _apiHeaderForImageURL() {
let headers = new Headers({ 'Content-Type': 'image/jpeg' });
headers.append('Authorization', 'Bearer ' + localStorage.getItem("token"));
let options = new RequestOptions({ headers: headers, responseType: 3 });
return options;
}
The first api call worked fine result also sucess but image not displayed properly. Thats the problem iam facing.
The result comes an default image like this only.
pls help me to achieve this. Any help warmly accepted.
Iam doning long time stuff to achieve this still i cant achieve pls give some idea.
Is any other way is available to get user picture in ionic 3 using sharepoint?
I'm trying to implement a user registration system, on android with node as my backend server.
I'm using Node 4.4.5, on localhost, and using the package "email-verification" - https://www.npmjs.com/package/email-verification
So on request from android, a confirmation email with a verification link is sent, which is working fine.
When the link is clicked, a GET request is made, which confirms the user, adds it to the MongoDB database, and a JSON response is sent.
An email is sent to the user that the account is confirmed.
After sending the confirmation email, the server crashes.
Here's my code--
router.get('/email-verification/:URL', function(req, res, next){
var url = req.params.URL;
console.log('email-verify-start');
nev.confirmTempUser(url, function(err, user) {
console.log('error is :' + err);
if (user) {
nev.sendConfirmationEmail(user.email, function(err, info) {
if (err) {
console.log('sending_conf_email_failed');
return res.json({'email': 'sending_conf_email_failed'});
}
console.log('user_confirmed');
res.json({
'email': 'user_confirmed'
});
console.log('Done, and confirmed');
});
} else {
console.log('conf_temp_ser_failed');
return res.json({'email': 'conf_temp_ser_failed'});
}
});
});
And here's my log--
error is :null
user_confirmed
Done, and confirmed
GET /register/email-verification/SfC9VlnUv91RkFBHDURIbHodnYme0RdfbTYBj0I4oXyywrpW 200 5177.724 ms - 26
h:\myapp\coep_updates\node_modules\email-verification\node_modules\nodemailer\node_modules\nodemailer-smtp-transport\src\smtp-transport.js:136
return callback(null, info);
^
TypeError: callback is not a function
at h:\myapp\coep_updates\node_modules\email-verification\node_modules\nodemailer\node_modules\nodemailer-smtp-transport\src\smtp-transport.js:136:20
at h:\myapp\coep_updates\node_modules\email-verification\node_modules\nodemailer\node_modules\nodemailer-smtp-transport\node_modules\smtp-connection\src\smtp-connection.js:279:20
at SMTPConnection._actionStream (h:\myapp\coep_updates\node_modules\email-verification\node_modules\nodemailer\node_modules\nodemailer-smtp-transport\node_modules\smtp-connection\src\smtp-connection.js:966:16)
at SMTPConnection.<anonymous> (h:\myapp\coep_updates\node_modules\email-verification\node_modules\nodemailer\node_modules\nodemailer-smtp-transport\node_modules\smtp-connection\src\smtp-connection.js:594:14)
at SMTPConnection._processResponse (h:\myapp\coep_updates\node_modules\email-verification\node_modules\nodemailer\node_modules\nodemailer-smtp-transport\node_modules\smtp-connection\src\smtp-connection.js:516:16)
at SMTPConnection._onData (h:\myapp\coep_updates\node_modules\email-verification\node_modules\nodemailer\node_modules\nodemailer-smtp-transport\node_modules\smtp-connection\src\smtp-connection.js:353:10)
at emitOne (events.js:77:13)
at TLSSocket.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:153:18)
at TLSSocket.Readable.push (_stream_readable.js:111:10)
at TLSWrap.onread (net.js:531:20)
Process finished with exit code 1
Till the server crashes, everything's working fine. I receive all emails and responses are sent properly, I even see the JSON response {"email":"user_confirmed"} on my browser. The only problem is that the server crashes afterwards.
EDIT 1
I tried adding return statements-- Still the same problem. I added them here--
return res.json({
'email': 'user_confirmed'
});
I also tried adding a return--
res.json({
'email': 'user_confirmed'
});
return;
No luck till now...
EDIT 2
Ok. so this is actually an open issue on GitHUB, this is reported as a bug.
https://github.com/whitef0x0/node-email-verification/issues/44
So, I tried the GitHUB the solution this way and it is now working flawlessly, even though an official fix is not released...
In the source folder of the module, in the file 'index.js' -->
Go to line 340 --
You'll see this line
callback = options.shouldSendConfirmation;
Change it to -->
callback = function(){};
Hope this helps...
You could change your nev.sendConfirmationEmail method to include the callback as the third argument:
nev.sendConfirmationEmail(user.email, function(err, info) {
if (err) {
console.log('sending_conf_email_failed');
return res.json({'email': 'sending_conf_email_failed'});
}
console.log('user_confirmed');
res.json({
'email': 'user_confirmed'
});
console.log('Done, and confirmed');
}, function(){});