Friday, August 24, 2018

Overwrite on Core Data value

hello I need to overwrite value on CoreData if already is. For example if already on CoreData I have Josh I need to delete this and next save new Josh

func save(value:String, forkey:String) {
    let context = getContext()
    let entity = NSEntityDescription.entity(forEntityName: "Lastname", in: context)

    let add = NSManagedObject(entity: entity!, insertInto: context)
    add.setValue(value, forKey: forkey)

    do {
        try context.save()
        print("save ->  \(value)")
    } catch {
        print("err \(error)")
    }
}

Solved

  • Fetch the object.
  • Create a new object if there is none.
  • Update the attributes.
  • Save the context.

func save(value:String, for key:String) {
    let context = getContext()
    let request = NSFetchRequest(entityName: "Lastname")
    let predicate = NSPredicate(format:"%K == %@", value, key)
    request.predicate = predicate
    do {
       let fetchResults = try context.executeFetchRequest(request)
       let object : NSManagedObject 
       if fetchResults.isEmpty {
          let entity = NSEntityDescription.entity(forEntityName: "Lastname", in: context)
          object = NSManagedObject(entity: entity!, insertInto: context)
       } else }
          object = fetchResults[0]
       }

       object.setValue(value, forKey: key)

       try context.save()
       print("save ->  \(value)")
    } catch {
        print("err \(error)")
    }
}

Note: I'm not using Swift 2 anymore, a compiler error might occur.


We can check whether values are there or not. Then update and Create values in database

class func checkAndUpdateAtIndex(entry_id: String, comment_text: String, comment_name: String, comment_pic: String, comment_date: String, comment_id: String, comment_isDeleted: String, comment_userid: String) {
    let context: NSManagedObjectContext = DataAccess.shared.managedObjectContext
    let request = NSFetchRequest(entityName: "Comment")
    request.predicate = NSPredicate(format: "comment_id = %@", comment_id)

    if let fetchResults = (try? DataAccess.shared.managedObjectContext.executeFetchRequest(request)) as? [NSManagedObject] {
        if fetchResults.count != 0{
            //update value
            var managedObject = fetchResults as! [Comment]
            managedObject[0].setValue(entry_id, forKey: "entry_id")
            managedObject[0].setValue(comment_text, forKey: "comment_text")
            managedObject[0].setValue(comment_name, forKey: "comment_name")
            managedObject[0].setValue(comment_pic, forKey: "comment_pic")

        }else {  
            // create new entity if not found
            let newItems = NSEntityDescription.insertNewObjectForEntityForName("Comment", inManagedObjectContext: context) as! Comment

            newItems.entry_id = entry_id
            newItems.comment_text = comment_text
            newItems.comment_name = comment_name
            newItems.comment_pic = comment_pic            
        }


            do {
                try context.save()
            } catch {}
    }
}

In this Update method I'm firstly getting that entity which we want to update and then storing new values in that place.


Monday, August 20, 2018

What exactly happens when I install an android application?

My guess is that the contents of .apk package are extracted somewhere, and the application is registered at some directory so that the application launcher or whatever can find it. But is that all? If that is the case, is the original manifest.xml read every time the app is launched or it gets pre-processed into some other form?

Solved

Some basics

The .apk-file

An .apk-file is not magical at all. It's just a bundle of files which represent the content of an Android application. If you open it in a archive-tool (like 7Zip), you can browser and extract it's contents.

Android is Linux

The basic Android-System is a Linux system. Android uses a custom Linux kernel with some extra functionality on power-saving and some speed-improvements. The internal storage of an Android device is formatted with the YAFFS2-filesystem, which fully features the Linux-like access-concepts.

The used file-system might differ by manufacture or Android-Version. Newer devices often use ext3, while Samsung uses it's own file-system: RFS

This is one important aspect of the Sandbox-system, which is used by Android.

Compiling applications

What happens to the .java-files?

First, they are compiled by the normal Java compiler. After they are compiled (to .class-files), the dx-tool from the Android SDK then converts/transpiles those "normal" java-classes into Dalvik-Bytecode.

This "special" java-code is then interpreted by the DVM (Dalvik Virtual Machine), which is based on the opensource JRE-implementation Apache Harmony.

Update: In newer versions of Android, the convert/transpile step can be skipped when jack is used. This way, the .java files are directly compiled into the .dx format.

Also, since version 4.4 (KitKat) Android has the new ART runtime, which officially replaced Dalvik in Android 5 (Lollipop).

What happens to the resources i put into the /asset-directory?

Android offers the /assets-directory to add some binary raw-files (e.g. a SQLite Database). Files which are put into this directory are not compiled or optimized.

If you put your files into this directory, this is the kind of behavior you would expect from Android.

What happens to the resources i put into the /res/raw-directory?

Like the /assets-directory, you can also put binary (or other) raw-files in here (e.g. HTML-files for the Help-page). These files are compiled/optimized (if possible).

What happens to the Manifest and the other XML-files?

The Android-Manifest and also the other XML-files (Layouts, Strings, etc.) are stored and "compiled" into a binary XML-format. This is a speed-optimization.

The Sandbox

From Android OS point of view, a single Application owns:

  • it's own process,
  • it's own OS-User (like on Linux),
  • it's own DVM,
  • it's own place in the heap and
  • it's own place on the filesystem.

So yes, every Android app has it's own user which has the proper rights to access it's place in the internal storage (which is protected by standard Linux filesystem rights-management) and it's own DVM-process (which can't be accessed from outside of the application).

To give the application the possibility to leave the Sandbox (e.g. to connect to the Internet), the permissions declared in the Android Manifest are used.

Steps during the installation

So from the above explanations, it should be clear what happens when an Android-Application is installed:

  1. The new user for the Application is created.
  2. With this new users rights, the Applications directory in the internal storage is created.
  3. The contents of the .apk-file are being extracted there.
  4. The Android-Manifest is parsed and the declared intent-filters are registered (e.g. the android.intent.category.LAUNCHER-filter for the applications standard entry point).
  5. Now the application is ready for it's first launch.

When you install an app, Android System copies its APK to "/data/app" folder and it named it by the package name followed by the installations number (how many times you install or update the app).

I tried to install an app manually by copying its APK and paste it in the /data/app folder and rebooted my device then it appears as an installed app and works perfectly.

Also I noticed in the link2SD app that any installed app has the folowing:

Apk located in /data/app/package-number.apk

Dex located in /data/dalvik-cache/data@app@package-number.apk@classes.dex

Lib located in /data/data/package/lib

Data located in /data/data/package

Cache located in /data/data/package/cache


Android defines an intent as "an abstract description of an operation to be performed." Not only do intents let you use activities made by others, but they are also used to launch applications. I'm sure you've seen these lines in every app you've written:


  
  

This intent filter allows the launcher to find the starting activity of each app. Lookup "intent resolution" for more details on this process... I'd say it's more elegant than simply registering the application at some random directory.

As stated in, http://developer.android.com/guide/topics/intents/intents-filters.html, "Android system populates the application launcher, the top-level screen that shows the applications that are available for the user to launch, by finding all the activities with intent filters that specify the "android.intent.action.MAIN" action and "android.intent.category.LAUNCHER" category. It then displays the icons and labels of those activities in the launcher"


Sunday, August 19, 2018

Sentry's sourcemaps/artifacts don't work

I'm building, minifying and generating sourcemaps of my app with webpack. Artifacts are sent to sentry.io with webpack-sentry-plugin.

The javascript code is run from localhost:8080/js/app.js. It contains //# sourceMappingURL=app.js.map at the end. Sourcemaps work correctly at Chrome devtools.

Sentry's Releases/Artifacts contain the following files:

js/app.js
js/app.js.map

Anyway, when Sentry logs an error, stacktrace is from the minified file. It's not using the sourcemaps.

What am I doing wrong in my setup? Or what other info should I give to get help?

Solved

I posted this question at forum.sentry.io and got the answer from a guy called @benvinegar.

Here is the thing: when sending a sourcemap/artifact, we provide the file and also a filename. The filename is meant to be the complete URL where the sourcemap would be located if it was uploaded to the host together with the minified JS files. That is: if our minified Javascript is located at www.example.com/js/app.js, then the sourcemap/artifact filename must be www.example.com/js/app.js.map. Otherwise, we can name it ~/js/app.js.map if we want the sourcemap to apply to other situations like running the app at localhost:8080/js/app.js.

As I'm using webpack-sentry-plugin, it was just a matter of adding the following property to the plugin:

{
  plugins: [
    new SentryPlugin({
      filenameTransform: filename => '~/' + filename
    })
  ]
}

Friday, August 17, 2018

nodes passport Error: Unknown authentication strategy "local-login"

I have been trying to get local authentication work with passport on nodejs and as far as i can tell all of my code it is correct but i keep getting the same annoying error about "unknown authentication strategy so maybe someone else can help me with this problem my code is shown below.

Here is my code for passport configuration in nodejs.

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');

module.exports = function(passport) {


    passport.serializeUser(function(user, done) {
        done(null, user.id);
    });

    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });

    passport.use('local-signup', new LocalStrategy({

        usernameField : 'username',
        passwordField : 'password',
        passReqToCallback : true
    },

    function(req, username, password, done) {

        process.nextTick(function() {

            User.findOne({ 'local.username' : username}, function(err, user) {
                if (err)
                    return done(err);

                if(user) {
                    return done(null, false, req.flash('signupMessage', 'That Username is already taken.'));
                }

                else {

                    var newUser = new User();

                    newUser.local.username = username;
                    newUser.local.password = newUser.generateHash(password);


                    newUser.save(function(err) {
                        if(err)
                            throw err;

                        return done(null, newUser);
                    });
                }
            });
        });
    }));



    passport.use('local-login', new LocalStrategy({

        usernameField : 'username',
        passwordField : 'password',
        passReqToCallback : true
    },
    function(req, username, password,done) {

        User.findOne({ 'local.username' : username}, function(err, user) {

            if(err)
                return done(err);

            if(!user)
                return done(null, false, req.flash('loginMessage', 'No user found.'));

            if(!user.validPassword(password))
                return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));

            return done(null, user);
        });
    }));

};

And here is the post on the server side.

app.post('/signin', passport.authenticate('local-login', {
    successRedirect : '/profile',
    failureRedirect : '/login',
    failureFlash : true
}));

And here is the form in the html doc






Create Account
Forgot Password

Can anyone please help me by telling me what i have done wrong. thanks

Solved

require('./config/passport')(passport);

Change the path of the file. Without this working, passport's configurations will not be passed to the routes.

Here is a snippet of where the line should be located:

// server.js

// configuration
===============================================================
mongoose.connect(configDB.url); // connect to our database

require('./config/passport')(passport); // pass passport for configuration

I also had the same problem but when I put this line of code after the app.use(flash()) it worked:

app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
require('./config/passport')(passport);