Adding custom data to a firebase storage upload? - firebase

I'm uploading files to firebase storage like so:
var storageRef = firebase.storage();
var fileRef = storageRef.ref(file.name);
fileRef.put(file)
.then(function (snapshot) {
console.log('Uploaded a blob or file!');
window.URL.revokeObjectURL(file.preview);
})
After the upload I have a firebase storage trigger:
export const processUploadedFile = functions.storage.object().onChange(event => {
}
What I want to do is upload some additional information with the original upload so that the processUploadedFile knows what to do with it (for example extract the file, move it to a special directory, etc, etc).
I tried using metadata like so:
var newMetadata = {
customMetadata: {
"Test": "value"
}
}
fileRef.put(file, newMetadata)
But on the cloud storage trigger function I don't know how to get the metadata, I logged out fileMetaData like so:
file.getMetadata().then((metaData)=>console.log(metaData))
But did not see my metadata anywhere in there (or in fileMetaData[0].metadata which returned undefined)
Not sure how I can achieve this...

I think providing file meta info will do the trick. Here is the reference. Firebase Storage File metadata. You can pass custom parameters for the file with customMetadata. For instance :
customMetadata: {
'actionType': 'ACTION_CODE',
'action': 'do something info'
}
You can access this metadata with storage trigger and take the action accordingly. Here is how you can achieve that Automatically Extract Images Metadata

I believe there are some properties that cannot be changed as they are not writeable. However, if you indeed want to add a custom data to firebase storage, you can set custom metadata as an object containing String properties. For example:
var myCustomMetadata = {
customMetadata : {
'file_name': 'this is the file name'
}
}
In the case above, the file_name is the custom metadata that you want to create.
After creating a reference to the file in the firebase storage, you can then call the updateMetadata() method on the reference.
For example:
Get the reference to an image file using downloadUrl:
var getRef = firebase.storage().refFromURL(imageUrl);
Use the reference to update the metadata:
getRef.updateMetadata(myCustomMetadata).then(()=>{
//do other things
})

For me, I had to call to Firebase Storage 2x. I'm using Java on an Android device to edit the metadata. First time is to upload the image. Second time is to set the image's metadata.
Instructions to set the Metadata of a Storage file is here= https://firebase.google.com/docs/storage/android/file-metadata
"You can update file metadata at any time after the file upload completes by using the updateMetadata() method. "
Here's my functions:
private void uploadImageToFBStorageAndFS(byte[] profilePic, final StorageUrlEstablished_CL storageUrlCallback) {
String storage_directory = //You get this
StorageReference profileImageRef = FirebaseStorage.getInstance().getReference(storage_directory).child(final_filename);
//1st time, upload the image/bytes.
if (profilePic != null) {
profileImageRef.putBytes(profilePic).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Task<Uri> result = taskSnapshot.getMetadata().getReference().getDownloadUrl();
result.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
updateImageMetadata(profileImageRef);
String urlWhereProfilePicIsStored = uri.toString();
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//Error handling
}
});
}
}
private void updateImageMetadata(StorageReference profileImageRef){
//Some devices, like the Asus tablet, doesn't upload good meta-data with the image.
// Create file metadata including the content type
StorageMetadata metadata = new StorageMetadata.Builder()
.setContentType("image/png")
.setCustomMetadata("myCustomProperty", "Rent App")
.build();
// Update metadata properties
profileImageRef.updateMetadata(metadata);
}

Related

Convert String path to File FLUTTER

I have List containing paths like below
/storage/emulated/0/Whatsapp/Media/Whatsapp Images/IMG-20210623-WA0016.jpg
Converting it to file always returns false.
for (var i = 0; i < tempLocations.length; i++) {
print(tempLocations.length);
File newFile = File(tempLocations[0]);
if (await newFile.exists()) {
print("true");
} else {
print("false");
}
}
How do i convert it to a file?
You can use flutter_absolute_path to get the excat path
A flutter plugin that finds the absolute path of a file in iOS or Android devices.
null safety version
flutter_absolute_path:
git:
url: https://github.com/kornperkus/flutter_absolute_path.git
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> init() async {
/// uri can be of android scheme content or file
/// for iOS PHAsset identifier is supported as well
List<Asset> assets = await selectImagesFromGallery();
List<File> files = [];
for (Asset asset in assets) {
// asset.identifier replace with your path
final filePath =
await FlutterAbsolutePath.getAbsolutePath(asset.identifier);
files.add(File(filePath));
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_files = files;
});
}

How to cache images from Firebase in Flutter?

I'm trying to access images in Firebase Storage and cache them locally on the device.
My current attempt uses flutter_cache_manager. The documentation states:
Most common file service will be an [HttpFileService], however one can also make something more specialized. For example you could fetch files from other apps or from local storage.
class HttpFileService implements FileService {
http.Client _httpClient;
HttpFileService({http.Client httpClient}) {
_httpClient = httpClient ?? http.Client();
}
#override
Future<FileServiceResponse> get(String url,
{Map<String, String> headers = const {}}) async {
final req = http.Request('GET', Uri.parse(url));
req.headers.addAll(headers);
final httpResponse = await _httpClient.send(req);
return HttpGetResponse(httpResponse);
}
}
I've tried to extend this class to process the URL for Firebase
class FirebaseHttpFileService extends HttpFileService {
#override
Future<FileServiceResponse> get(String url, {Map<String, String> headers = const {}}) async {
var ref = FirebaseStorage.instance.ref().child(url);
var _url = await ref.getDownloadURL() as String;
return super.get(_url);
}
}
And extend the BaseCacheManager using a template from the GitHub repo, replacing the file service with my new one.
class FirebaseCacheManager extends BaseCacheManager {
static const key = "firebaseCache";
static FirebaseCacheManager _instance;
factory FirebaseCacheManager() {
if (_instance == null) {
_instance = new FirebaseCacheManager._();
}
return _instance;
}
FirebaseCacheManager._() : super(key,
maxAgeCacheObject: Duration(days: 7),
maxNrOfCacheObjects: 20,
fileService: FirebaseHttpFileService());
Future<String> getFilePath() async {
var directory = await getTemporaryDirectory();
return p.join(directory.path, key);
}
}
But I get the following error:
setState() called after dispose(): _ImageState#50d41(lifecycle state: defunct, not mounted, stream: ImageStream#ac6d5(MultiFrameImageStreamCompleter#0c956, [2448×3264] # 1.0x, 3 listeners), pixels: null, loadingProgress: null, frameNumber: null, wasSynchronouslyLoaded: false)
I can process the URL before attempting to retrieve the file but that needlessly wastes time. I've also tried to use other packages like Flutter Cache Image but it seems to crash the app after a short amount of time.
Thanks for any pointers in the right direction!
This problem is actually tied to the errorWidget as seen in the issue here.
The code is working if the error widget is commented out in CachedNetworkImage.

Unable to upload file as FormData to ASP.net from Angular

I am trying to upload a file from my angular code to an ASP.net backend.
My Angular code sends the object using FormData:
public uploadFiles(files) {
console.log(files);
if(files.length < 1) return;
const formData = new FormData();
files.forEach(file => {
console.log(file);
formData.append(file.name, file);
})
this._http.postFile('/order-processing/import-orders','application/x-www-form-urlencoded' ,formData).pipe(finalize(() => {
console.log("Finalized");
})).subscribe((val: any) => {
console.log('ORDER SUBMITTED', val);
}, error => {
console.log(error);
});
}
With the post file method looking like:
public postFile(path: string, contentType:string, body: FormData) : Observable<any> {
let headers = {
'Content-Type': contentType,
'Authorization': this.authToken
}
return this._http.post(environment.API_URL + path, body, {
headers
});
}
My ASP.net endpoint looks like:
[HttpPost, Route("hospitality/order-processing/import-orders")]
[RequestSizeLimit(2147483648)]
[DisableRequestSizeLimit]
public IActionResult UploadFile()
{
try
{
//var req = Request.Form.Files;
var file = Request.Form.Files;
string folderName = "Uploads";
string webRootPath = _hostingEnvironment.WebRootPath;
string newPath = Path.Combine(webRootPath, folderName);
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
}
return Json("Upload Successful.");
}
catch (Exception e)
{
return Json("Failed:" + e);
}
}
If I check the network tab on my browser when I send the file, it says that my object is in the call, great, but for some reason it doesn't get picked up on the backend and when I step through the code it is not there.
I get different errors when I modify this code slightly. The error for the code in the state it is in now is "Form key or value length limit 2048 exceeded", however sometimes I get array out of bounds errors, or content boundary limit exceeded errors, it's enough to make you want to slam you face into your keyboard continually.
The whole point of this is to be able to upload an excel file to ASP.net code running in an AWS lambda, which then inserts rows in a RDS database. Am I going about this the right way? Is there a better way to achieve what I am trying to do? If not then what is wrong with my code that doesn't allow me to upload a file to a Web API?!
Thanks
It seems that you're trying to set the limit of the request but the message states that the problem is with form key or value length.
Try setting the RequestFormLimits and check if that helps.
[HttpPost, Route("hospitality/order-processing/import-orders")]
[RequestFormLimits(KeyLengthLimit = 8192, ValueLengthLimit = 8192)]
public IActionResult UploadFile()

Firebase dynamic link support custom parameters?

I am writing a App for a Open Source Conference.
Originally each attendees will receive different link via email or SMS like
https://example.com/?token=fccfc8bfa07643a1ca8015cbe74f5f17
then use this link to open app, we can know the user is which attendee by the token.
Firebase release a new feature Dynamic Links in I/O 2016, it provide better experience for users.
I had try that, but I can't find any way to pass the custom parameters (the token) in dynamic links, how to use the same link with different parameters to my users?
Thanks.
I don't think you can use the short url:
https://<my app>.app.goo.gl/Gk3m
unless you create one for each user, but you can use the long url:
https://<my app>.app.goo.gl/?link=https://example.com/?token=fccfc8bfa07643a1ca8015cbe74f5f17 ...(add other parameters as needed)
and set new token for each user.
I assume you generate the tokens automatically. In that case you can use this to shorten the links.
1) From https://console.firebase.google.com/ (no need for custom parameter here.)
2) Create link somewhere, f.e. on your confluence page (here we add our parameter):
https://PROJECTNAME.page.link/?link=https://PROJECTNAME.page.link/LINKNAME?PARAMETER=1&ofl=https://www.PROJECTNAME.com/
PARAMETER is your custom parameter.
ofl is a link where to go if click the link from another platform (PC, Mac).
3) Getting link data from android project Kotlin code:
Firebase.dynamicLinks
.getDynamicLink(intent)
.addOnSuccessListener { pendingDynamicLinkData ->
val parameter: String =
pendingDynamicLinkData?.link?.getQueryParameter("PARAMETER").orEmpty()
}
If you want to use dynamic links with custom arguments with REST, here is an example of a payload:
{
"dynamicLinkInfo": {
"dynamicLinkDomain": "example.app.goo.gl",
"link": "http://someurl.com?my_first_param=test&my_second_param=test2"
},
"suffix": {
"option":"UNGUESSABLE"
}
}
Make sure your remove 'https://' from your dynamicLinkDomain
Julien
Case A. If you want the short link to expand to a link with multiple parameters:
In the part where you setup a dynamic link, any parameter you append to the deep link URL will go on all platforms (web, iOS, android)
Case B. If you want to use dynamic parameters, you should use the api to create a short link
see documentation
Now you can create short links using the Firebase SDK through the FirebaseDynamicLinks.getInstance().createDynamicLink():
https://firebase.google.com/docs/dynamic-links/android/create
Sample code:
Task shortLinkTask = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("https://example.com/"))
.setDynamicLinkDomain("abc123.app.goo.gl")
// Set parameters
// ...
.buildShortDynamicLink()
.addOnCompleteListener(this, new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if (task.isSuccessful()) {
// Short link created
Uri shortLink = task.getResult().getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
} else {
// Error
}
}
});
Create a dynamic link
Go to link details
Copy the long dynamic link and add your parameter in the link parameter of the URL, e.g., PARAMETER=132323
https://link.projectname.com/?link=https://link.projectname.com/LINK?PARAMETER=132323&apn=com.projectname.app&afl=https://link.projectname.com/LINK
1 First Change your Dynamic Link in firebase console from http://exampleandroid/test to http://exampleandroid/test?data 2. You send the query paramter data with this
DynamicLink dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
// .setLink(dynamicLinkUri)
.setLink(Uri.parse("http://exampleandroid/test?data=dsads"))
.setDomainUriPrefix("https://App_Name.page.link")
// Open links with this app on Android
.setAndroidParameters(new DynamicLink.AndroidParameters.Builder().build())
// Open links with com.example.ios on iOS
.setIosParameters(new DynamicLink.IosParameters.Builder("com.appinventiv.ios").build())
.buildDynamicLink();
dynamicLinkUri = dynamicLink.getUri();
You can add extra parameter to your link to generate Short URL from Firebase.
Here I given example of Short URL generation using Firebase API.
Here ServiceRequestHelper(this).PostCall is my generic class to make API request
String url = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=YOUR_KEY";
try {
PackageManager manager = this.getPackageManager();
PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
JSONObject jsonObject = new JSONObject();
JSONObject androidInfoObject = new JSONObject();
androidInfoObject.put("androidPackageName", getApplicationContext().getPackageName());
androidInfoObject.put("androidMinPackageVersionCode",String.valueOf(info.versionCode));
JSONObject iosInfoObject = new JSONObject();
iosInfoObject.put("iosBundleId", "tettares.Test_ID");
JSONObject dynamicLinkInfoObj = new JSONObject();
dynamicLinkInfoObj.put("dynamicLinkDomain", "wgv3v.app.goo.gl");
dynamicLinkInfoObj.put("link", "https://test.in/?UserId=14&UserName=Naveen"); // Pass your extra paramters to here
dynamicLinkInfoObj.put("androidInfo", androidInfoObject);
dynamicLinkInfoObj.put("iosInfo", iosInfoObject);
JSONObject suffixObject = new JSONObject();
suffixObject.put("option" , "SHORT");
jsonObject.put("dynamicLinkInfo", dynamicLinkInfoObj);
jsonObject.put("suffix", suffixObject);
Log.d("JSON Object : " , jsonObject.toString());
new ServiceRequestHelper(this).PostCall(url, jsonObject, false, new CallBackJson() {
#Override
public void done(JSONObject result) throws JSONException {
try {
if (result.has("shortLink")) {
DEEP_LINK_URL = result.getString("shortLink"); }
} catch(Exception e)
{
e.printStackTrace();
}
}
});
} catch (JSONException | PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
In Your Receiving Activity:
boolean autoLaunchDeepLink = false;
AppInvite.AppInviteApi.getInvitation(mGoogleApiClient, this, autoLaunchDeepLink)
.setResultCallback(
new ResultCallback<AppInviteInvitationResult>() {
#Override
public void onResult(#NonNull AppInviteInvitationResult result) {
if (result.getStatus().isSuccess()) {
// Extract deep link from Intent
Intent intent = result.getInvitationIntent();
String deepLink = AppInviteReferral.getDeepLink(intent);
// Handle the deep link. For example, open the linked
// content, or apply promotional credit to the user's
// account.
// [START_EXCLUDE]
// Display deep link in the UI
Log.d(TAG, "deeplink URL: " + deeplink); // Here you get https://test.in/?UserId=14&UserName=Naveen
// [END_EXCLUDE]
} else {
Log.d(TAG, "getInvitation: no deep link found.");
}
}
});
I tried all above but none work. So I think you should change the link http://example.com/?userid=123tohttp://example.com/userid/123
No need of all the hustle
Don't shorten the url if you want to pass parameters
Write the links like this.
//APP_CODE is firebase link
String link = "https://APP_CODE.app.goo.gl/?refferer=" + userId;
Intent intent = new AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
.setMessage(getString(R.string.invitation_custom_message)))
.setDeepLink(Uri.parse(link))
.setCustomImage(Uri.parse(getString(R.string.invitation_custom_image)))
.setCallToActionText(getString(R.string.invitation_cta))
.build();
startActivityForResult(intent, REQUEST_INVITE);
For web apps, which generating dynamic links..
const data = {
dynamicLinkInfo: {
domainUriPrefix: 'subdomain.page.link',
link: url,
},
suffix: {
option: 'SHORT'
}
};
return fetch(`https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=${environment.firebaseConfig.apiKey}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
}).then(res => res.json()).then(response => response.shortLink).catch(console.error);

how to read multi part form data in .net web api controller

public class Sampleontroller:apicontroller
{
public void PostBodyMethod() {
HttpRequestMessage request=this.request;
//How to read the multi part data in the method
}
}
I am sending a multi part data to webapi controller.
How to read the contents in the method?
An 'async' example:
public async Task<HttpResponseMessage> PostSurveys()
{
// Verify that this is an HTML Form file upload request
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
//Destination folder
string uploadFolder = "mydestinationfolder";
// Create a stream provider for setting up output streams that saves the output under -uploadFolder-
// If you want full control over how the stream is saved then derive from MultipartFormDataStreamProvider and override what you need.
MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider(uploadFolder );
MultipartFileStreamProvider multipartFileStreamProvider = await Request.Content.ReadAsMultipartAsync(streamProvider);
// Get the file names.
foreach (MultipartFileData file in streamProvider.FileData)
{
//Do something awesome with the files..
}
}
Have a look at the article by Mike Wasson:
http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2
Or if you are doing file uploads, here: www.strathweb.com/2012/08/a-guide-to-asynchronous-file-uploads-in-asp-net-web-api-rtm/

Resources