ionic 3 sqlite - How to execute requests from files - sqlite

I am currently developing a mobile app with ionic. On this application there is a local sqlite database.
I am looking to be able to execute queries from files for possible updates of the database.
For example, when you first install the application, the tables are created if they do not exist. If changes are made to these tables after installing the application, the changes are not taken into account.
I would like to create files which can be executed one by one according to PRAGMA user_version.
Something like :
// Get pragma user version, if it's undefined, it's set to 1.
// If user_version < 1, we execute the sql file, then we update the user_version
// to 1.
db.executeSql(`PRAGMA user_version;`, []).then((res)=> {
if(res.rows.item(0).user_version < 1) {
db.sqlBatch(`app/sqlFiles/1.sql`, []).then((res)=>{
console.log(res);
}, (err) => {
console.log("Error : " + JSON.stringify(err));
});
db.executeSql(`PRAGMA user_version = 1;`, []).then((res)=>{
console.log(res);
}, (err) => {
console.log("Error : " + JSON.stringify(err));
});
}
}, (err) => {
console.log("Error : " + JSON.stringify(err));
});
I thought about using a file reader but the file is not found during the execution of the function.
this.fileOpener.open('assets/SQLFile/1.sql', 'text/plain')
.then((file) => {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log("read success");
console.log(evt.target);
};
db.sqlBatch(reader.readAsText(file)).then((res)=>{
console.log(res);
}, (err) => {
console.log("Error : " + JSON.stringify(err));
});
console.log('File is opened');
})
.catch(e => console.log('Error opening file', e));
Will anyone have an idea for doing this kind of thing? (I am looking for a solution that respects good programming practices).
Please note that I am a beginner with ionic and sqlite
Thank you in advance !

But you're getting an error or what? Since the post seems to be valid but the implementation seems to be a little off.
After reading the file, storing the content into a variable, you should execute that "sql query" as usually.
Nevertheless it's not a secure way of do that.
When something in your app change due to an update or upgrade, wouldn't be easier and safer to specify that into the code instead of a single file containing all the database info and scheme?
Edited:
If you want to add custom files to deployment, check this out https://ionicframework.com/docs/developer-resources/app-scripts/

Related

Upload Powerpoint to Google Drive as file

I want to upload Powerpoint files to Google drive. When I do this using the UI (clicking on "Upload File" and uploading a file), things work as I expect. However, when I use the Drive API I get some formatting issues. For example, the shading (text highlight) in my Powerpoint tables is transparent, but when I upload to Drive using the API the shading becomes white.
I have tried to work around this by specifying MIME type as application/vnd.google-apps.file, but when I get the response, the MIME type shows as application/vnd.google-apps.presentation
I am using Google Drive API v3, accessed through the R package googledrive.
Try to use this mimeType : application/vnd.openxmlformats-officedocument.presentationml.presentation
including :
application/vnd.google-apps.file
Here is an example done with NodeJS, try and let me know if it works well for you.
Just in case, try other mimeTypes (url is provided on Reference list, scroll down)
var fileMetadata = {
'name': '___Your File Name Here___',
'mimeType': 'application/vnd.google-apps.file'
};
var media = {
mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
body: fs.createReadStream('___Your File Name Here___.pptx')
};
function uploadFile(auth){
const drive = google.drive({version: 'v3', auth});
drive.files.create({
resource: fileMetadata,
media: media,
fields: 'id'
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
})
}
// RUN script
fs.readFile('credentials.json', (err, content) => {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
authorize(JSON.parse(content), uploadFile);
});
References:
Google mimeTypes (Google Reference)
List of mimeTypes (MDN)

Firebase Storage download url not available after upload

I am using Angular and AngularFire2. I am trying to upload an image to firebase storage, then once that is done I am take that reference and get the download url and upload it to the database. For some reason even though the upload is complete and I have the snapshot, when I try to use that in order to get the URL it's giving me an error that the object does not exist. Any thoughts on what I might be doing wrong?
task.snapshotChanges().pipe(
concatMap(snap => {
return snap.ref.getDownloadURL()
}),
concatMap(url => this.db.collection('library').add({
name: this.image.name,
path: path,
largeUrl: url
}))
).subscribe(ref => {
this.completed = true;
}, error => console.log(error));
error:
Firebase Storage: Object 'library/1542515976022_lemonade-smoothie.jpg' does not exist.
Ok, so my issue was not really understanding concatMap. I thought it wasn't called until the last onNext() of the upload Observable. It was being called on the first onNext(), which means the file had not completely updated. Below is what I ended up doing, although it seems like there should be another way. What I would like is to only switch to the new Observable track if the downloaded bytes equals the total bytes. I'm not sure how to do this with RxJS though. If anyone had any thoughts let me know.
task
.snapshotChanges()
.pipe(finalize(() => this.uploadToDb(path)))
.subscribe();
uploadToDb(path: string) {
this.storage
.ref(path)
.getDownloadURL()
.pipe(
concatMap(url =>
this.db.collection('library').add({
name: this.image.name,
path: path,
largeUrl: url
})
)
)
.subscribe(
ref => (this.completed = true),
error => {
console.log(error);
this.error = true;
}
);
}

Ionic2: get image form URL and save to native storage

Let's say I have a JSON object containing users' profile including firstname, lastname,..., and profileUrl from a web API. I've already saved the text data using Sqlite, and now I want to save those images in native storage and put the file path into the sqlite database replacing the profileUrl.
You can use cordova-plugin-file-transfer for that. There is even an Ionic Native wrapper available: https://ionicframework.com/docs/native/transfer/
Example:
download() {
const url = 'http://www.example.com/file.pdf';
fileTransfer.download(url, this.file.dataDirectory + 'file.pdf').then((entry) => {
console.log('download complete: ' + entry.toURL());
}, (error) => {
// handle error
});
}

How to save a file -in a folder- using FileSystem and CollectionFS ? (yeah, really.)

I think I'm missing something. I have read a lot of posts/examples and I can't save images on my system (I work locally).
What is my goal ?
I'm trying to save a file submitted by the user in a folder (server-side). Does it sound easy ? Maybe.
What's the issue ?
Short answer : I can't figure out how to save the file in my folder.
Do you want more information ?
The story of a file upload
I have read that to use the path parameter like new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" }) , I have to declare my collection server-side. But when I call Avatars.insert() (Avatars is the name of my collection), it seems like it doesn't exists. This makes sense because this collection exists only on the server.
So I've tried to declare the collection both server-side and client-side (I've read some examples about that) and that works ! The file is correctly added to MongoDB, but my folder is still empty (I'm not sure but I think this is because Avatars.insert() is called client-side so the collection used is the client-side one, the one which cannot take path parameter).
But no problem ! I've created 2 Meteor methods (one client-side and one server-side) called "updateAvatarFile". With this "trick", I'm able to do Meteor.call("updateAvatarFile", field.files[0]), which calls both server-side and client-side methods. So I can do some UI stuff in the client-side one and upload the file in the other. But I can't pass the file as a parameter.
field.files[0] contains the file client-side but server-side it's an empty object. My question is : How can I upload a file ?
I can't do it client-side (because I can't use path parameter) but I can pass the file to the server. I'm sure that I'm missing something but I can't figure what.
Here is how I go :
// /client/views/templates/settings.js
Template.settings.events({
'submit #updateAvatar': function (e, template) {
e.preventDefault();
const field = document.getElementsByName('avatar')[0];
Meteor.call('updateAvatarFile', field.files[0]);
}
});
// /client/lib/clientMethods.js
Meteor.methods({
'updateAvatarFile': function (file) {
// blabla
}
});
// /server/lib/serverMethods.js
Meteor.methods({
'updateAvatarFile': function (file) {
Avatars.insert(file, function (err, fileObj) {
if (err) {
console.log(err);
} else {
console.log(fileObj);
}
});
}
});
// /server/collections/serverAvatarCollection.js
Avatars = new FS.Collection("avatars", {
stores: [
new FS.Store.FileSystem("original", { path: "/public/images/user/avatar" }),
new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" })
],
filter: {
maxSize: 1000000, //1Mo
allow: { contentTypes: ['image/*'] }
},
onInvalid: function (message) {
//throw new Meteor.Error(403, message);
}
});
// /client/collections/clientAvatarCollection.js
// (this one is actually in a comment block)
Avatars = new FS.Collection("avatars", {
stores: [
new FS.Store.FileSystem("original"),
new FS.Store.FileSystem("thumb")
],
filter: {
maxSize: 1000000, //1Mo
allow: { contentTypes: ['image/*'] }
},
onInvalid: function (message) {
alert(message);
}
});
I've also tried to insert the file with the client-side method but I've got the same result (the file is added to MongoDB but not saved into a folder).
Using different path values didn't work either.
EDIT : Or maybe I'm trying to use the wrong package ? To my mind, transform a picture to chunks and save them into MongoDB sounds really weird and bad. Do you have any adivces ?
EDIT 2 :
answer to Michel Floyd (sorry about that, the character limit is annoying).
First, thanks for your answer !
1. At the moment, I'm just trying Meteor so I have both autopublish and insecure installed. Not publishing/subscribing to my collection cannot cause an issue, is that right ?
2. Before your answer I've tried to set up a collection available for both server and client by putting my avatarCollection.js in /collections. I was thinking that path which doesn't contains server or client are automatically available for the two sides. So what is the difference between /collections and /lib ? (I know that all files in a "lib" folder are loaded first). Is it a bad practice to put collections in /collections ? Maybe should I create a /lib/collections folder ?
3. (the last point, sorry for the long comment) I've tried what you advised above but it doesn't seems to work (or I am doing something wrong, again ><). When I use Avatars.insert(), CollectionFS don't save the file on my local storage. I've also checked the root of my HDD in case CollectionFS interpreted / to be the root of my machine but it doesn't. In the other hand, CollectionFS have created 4 collections in MongoDB (cfs._tempstore.chunks, cfs.avatars.filerecord, cfs_gridfs._tempstore.chunks and cfs_gridfs._tempstore.files) - the gridfs is weird. I have GridFS installed but I use FileSystem -. Those tables are not empty. That's why I think CollectionFS split my file into chunks and save them in MongoDB.
You're generally on the right track. CollectionFS uses storage adapters to deal with actual file storage. You can put files on S3, gridFS, or your local file system as you're trying to do. Putting the file contents in Mongo directly is usually avoided.
Firstly, define your collection:
Avatars = new FS.Collection("avatars", {
stores: [
new FS.Store.FileSystem("original", { path: "/public/images/user/avatar" }),
new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" })
],
filter: {
maxSize: 1000000, //1Mo
allow: { contentTypes: ['image/*'] }
},
onInvalid: function (message) {
//throw new Meteor.Error(403, message);
}
});
in /lib! This will make it available to both the server and the client.
Secondly, make sure you publish your avatars collection from the server and subscribe to it from the client. I don't see any publish/subscribe code in your question. You need it.
Thirdly, if you just do:
Avatars.insert(...);
on the client with a file then CollectionFS then CollectionFS will take care of storing it for you. The thing is, it won't be instantly available. It can take a little while for the actual upload and storage to happen. You can look at fileObj.isUploaded for example to see if the file is ready.

Getting an open graph action approved - change publish_stream to publish_action

UPDATED CODE:
I have an open graph action pending approval. I received a message back from Facebook saying this:
Your code is currently configured to publish a stream story. You must change your code so that when the test user triggers the action it produces an open graph story. Please make the appropriate changes and resubmit.
I followed all the tutorials regarding publishing actions and my tests all published successfully to my app timeline. The problem is that my app (which is a page tab) is already up and running - so I want to update it and add these new actions.
Are Facebook looking at the code in my current page tab - which is using the fmbl posttofeed share button - or are they looking at the tests I carried out with the new action? Is anyone able to shed some light on this?
This is the code I have in my test page that I used to publish the actions:
function postShare()
{
FB.api(
'/me/namespace:share',
'post',
{ photo: 'https://domain.com' },
function(response) {
if (!response || response.error) {
alert('Error occurred : ' + response.error);
} else {
alert('Share was successful! Action ID: ' + response.id);
}
});
}
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
// Init the SDK upon load
window.fbAsyncInit = function() {
FB.init({
appId : 'APP ID', // App ID
channelUrl : '//channel url', // Path to your Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// listen for and handle auth.statusChange events
FB.Event.subscribe('auth.statusChange', function(response) {
if (response.authResponse) {
// user has auth'd your app and is logged into Facebook
FB.api('/me', function(me){
if (me.name) {
document.getElementById('auth-displayname').innerHTML = me.name;
}
})
document.getElementById('auth-loggedout').style.display = 'none';
document.getElementById('auth-loggedin').style.display = 'block';
} else {
// user has not auth'd your app, or is not logged into Facebook
document.getElementById('auth-loggedout').style.display = 'block';
document.getElementById('auth-loggedin').style.display = 'none';
}
});
// respond to clicks on the login and logout links
document.getElementById('auth-loginlink').addEventListener('click', function(){
FB.login();
});
document.getElementById('auth-logoutlink').addEventListener('click', function(){
FB.logout();
});
}
function loginUser() {
FB.login(function(response) { }, {scope:'publish_actions, email'});
}
I can't see how this is configured to publish a stream story and not an open graph story? Can anyone help with this is it's driving me insane and can't find anything out there to suggest what I'm doing is not publishing an action.
If, however when they are reviewing my actions they are looking at the code in my live app then of course it is not set up to trigger any open graph stories - as they haven't been approved yet!
Any help would be hugely appreciated.
Many thanks
Your question isn't entirely clear, but both the publish_actions and publish_stream Permissions both allow you to post Open Graph actions. The publish_stream permission however covers many other publishing types and is also optional, and if users remove that permission you won't be able to post OG actions for those users.
Update your authentication code to request publish_actions instead / as well
Finally got it working. Steps:
1. Added "Publish_action" Permission
2. Tested on FB Graph API Explorer successfully
3. Modified my Javascript (similar code as the postShare() method above)
FB.api('/me/namespace:purchase',
'post',
{ product: 'samples.ogp.me/367683346642550'; },
function(response) {
if (!response || response.error) {
alert('Error occured'+response.error);
} else {
alert('Post was successful! Action ID: ' + response.id);
}
});
The Facebook testers need the actual code running at your production server. They are going to use a Facebook test user to execute all the steps you described when you submitted the action. They won't use the already published stories. They will probably use the "Open Graph Test User".
You have two options here:
Try to publish the action with every user and if it doesn't work, publish the stream (so that the test user get the action published but your real user publish using the old code)
--- OR ---
Identify if the user is a test user (by recording the test users ids) and serve him the new code.
Anyway, the real action flow must be executable on the production server.
Basically you cannot post something to an album or any other kind of post when you are using an open graph story. For example the following is not allowed:
$data = $facebook->api('/me/photos', 'post', $args);//disallowed
$facebook->api(
'me/invig-test:share',
'POST',
array(
'app_id' => $configParam['appId'],
'type' => "test:photo",
'photo' => "http://samples.ogp.me/574859819237737",
'title' => "a photo",
'image[0][url]'=>"http://www.testapp.com/".$imgFile,
'image[0][user_generated]'=>'true',
'message' => $comments,
'fb:explicitly_shared'=>true,
)
);
Instead only do the "share":
$facebook->api(
'me/invig-test:share',
'POST',
array(
'app_id' => $configParam['appId'],
'type' => "test:photo",
'photo' => "http://samples.ogp.me/574859819237737",
'title' => "a photo",
'image[0][url]'=>"http://www.testapp.com/".$imgFile,
'image[0][user_generated]'=>'true',
'message' => $comments,
'fb:explicitly_shared'=>true,
)
);

Resources