Login and Signup using couchbaseLite + Ionic (Mobile app)


#1

Hi,
I am trying to implement Login and Sign up functionality with username and password using couchbaseLite + ionic. Can you please Guide me on this topic.


#2

I’m also interested in this option, since at the moment I only managed to login with Ionic/Couchbase using Facebook.


#3

can you share the code of login with Ionic/Couchbase using Facebook.


#4

This is the config code, then you can use Facebook Connect Plugin (https://github.com/Wizcorp/phonegap-facebook-plugin) for the connection with FB.
At the startup of the application you have the create DB function with config.startDB(), then when you execute config.login() it will start the login/replication process.

angular.module("Config", [])
.factory("$config", ["$q", "$http", "$rootScope", "$state", "FBService","$ionicLoading","$cordovaToast",function($q, $http, $rootScope, $state,FBService,$ionicLoading,$cordovaToast) {

/*
 * Construct a new Login object
 *
 * @return   promise
 */
 
 var config = function() {
    this.debug = true
    this.stringify = false
	 
    this.databaseName = "...";
    this.designDocName = "...";
    this.REMOTE_SERVER = "http://...";
    this.REMOTE_DB = "...";
    this.REMOTE_URL = this.REMOTE_SERVER+"/"+this.REMOTE_DB;
	  this.user = null
	  
		this.checkConnection = function() {
			var _this = this
			var networkState = navigator.connection.type;
			networkState = networkState.toLowerCase()
			/*
		    var states = {};
		    states[Connection.UNKNOWN]  = 'Unknown connection';
		    states[Connection.ETHERNET] = 'Ethernet connection';
		    states[Connection.WIFI]     = 'WiFi connection';
		    states[Connection.CELL_2G]  = 'Cell 2G connection';
		    states[Connection.CELL_3G]  = 'Cell 3G connection';
		    states[Connection.CELL_4G]  = 'Cell 4G connection';
		    states[Connection.CELL]     = 'Cell generic connection';
		    states[Connection.NONE]     = 'No network connection';*/				 
		    if (networkState.indexOf("unknown") != -1 || networkState.indexOf("none") != -1) {
				 $rootScope.isOnline=false
				 $rootScope.$broadcast("offline");
		    	return false
		    } else {
				 $rootScope.isOnline=true
				 $rootScope.$broadcast("online");
		    	return true
		    }
		}
		
	  this.diveplanViews = 
	  {
			...
	  }
};

config.prototype = {

    /*
     * @param
     * @return   promise
     */
	 startDB: function(fbLogin) {
		 var _this = this
      // check if database is existing
		 divePlanDatabase.getDesignDocument(_this.designDocName).then(function(ok) {
         //database exists
			 log("database existing",divePlanDatabase)
			 divePlanDatabase.listen();
			 //update design document if changeda
			 divePlanDatabase.updateDesignDocument(_this.designDocName, _this.diveplanViews)
			 
			 divePlanDatabase.getLocalDocument("user").then(function(user) {
				 _this.user = user
				 if (user.guest) {
				 	_this.guestLogin()
				 } else {
				 	_this.login()
				 }
         },function(err) {
			  if (fbLogin) {
			  	   _this.login()
			  } else {
			  		$state.go('login')
			  }
         })
      }, function(error) {
         // no database exisiting
         divePlanDatabase.createDatabase().then(function(result) {
             divePlanDatabase.createDesignDocument(_this.designDocName, _this.diveplanViews);
				  log("database created",divePlanDatabase)
             divePlanDatabase.listen();
				  $ionicLoading.hide()
				  if (fbLogin) {
				  	   _this.login()
				  } else {
				  		$state.go('login')
				  }
         }, function(error) {
             // There was an error creating the database
         });
      });
	 },
	 guestLogin: function() {
		 var _this = this
		 if (_this.user) {
			 //existing guest logi
			 guestReplicate()
		 } else {
			 //new guest login
			 _this.user = {
				 guest: true
			 }
	       divePlanDatabase.createLocalDocument("user",_this.user).then(function(result) {
	 			 log("guest_user",result)
				 guestReplicate()
	       }, function(error) {
	           // Document creation 
	 			 log("guest_user error",error)
	       });
		 }
		 
		 function guestReplicate() {
			_this.replicateDatabase().then(function(ok){
				log("replicateDatabase guest",ok)
				$ionicLoading.hide()
				$state.go('app.sites')
			}, function(err){
				log("replicateDatabase guest err",err)
			})
		 }
       
	 },
	 login: function() {
		 var _this = this
       facebookConnectPlugin.getLoginStatus(function(success){
 	       if(success.status === 'connected'){
				 var user_data =  FBService.getUser()
				  //update access token
				 user_data.authResponse.accessToken = success.authResponse.accessToken
				 FBService.setUser(user_data)
				
 	          // the user is logged in and has authenticated your app, and response.authResponse supplies
 	          // the user's ID, a valid access token, a signed request, and the time the access token
 	          // and signed request each expire
 	          //log('getLoginStatus success',success.status);
	 		 	/*
	 		 	Get user email address from Facebook, and access code to verify on Sync Gateway
	 		 	*/
	 			//check and ask user email
				 if (!user_data.profileInfo.email) {
	 				_this.requestEmail("Please insert your email address for registration.")
	 			} else {
	 				_this.userEmailOK()
	 			}
 	       } else {
 	          //if (success.status === 'not_authorized') the user is logged in to Facebook, but has not authenticated your app
 	          //else The person is not logged into Facebook, so we're not sure if they are logged into this app or not.
 	          log('getLoginStatus login',success.status);
 	          $ionicLoading.show({
 	            template: 'Logging in...'
 	          });
			 
 	          //ask the permissions you need. You can learn more about FB permissions here: https://developers.facebook.com/docs/facebook-login/permissions/v2.4
 				 FBService.fbStartLogin()		        
 			 }
       });
	 },
	 userEmailOK: function() {
		 var _this = this
		 var user_data = FBService.getUser()
	 	_this.user = user_data.profileInfo
	 	_this.user.access_token = user_data.authResponse.accessToken;
	 	_this.user.user_id= _this.user.email
		_this.checkUser().then(function(res){
			//replicated DB
			_this.replicateDatabase().then(function(ok){
				log("replicateDatabase",ok)
				$ionicLoading.hide()
				$state.go('app.sites')
			}, function(err){
				log("replicateDatabase err",err)
			})
		}, function(err){
			log("checkUser err",err)
		})
	 },
	 fbLogin: function() {
		 //reset database and login with facebook after user guest
		 var _this = this
      divePlanDatabase.deleteDatabase().then(function(result) {
          _this.user = null
			 FBService.setUser(null)
			  _this.startDB(true)
      }, function(error) {
          // There was an error deleting the database
      });
	 },
	 logout: function() {
		 var _this = this
      // check if database is existing
      facebookConnectPlugin.logout(function(){
        //success
         divePlanDatabase.deleteDatabase().then(function(result) {
				 log("delete db",result)
             _this.user = null
				 FBService.setUser(null)
				  _this.startDB()
         }, function(error) {
             // There was an error deleting the database
         });
      },
      function(fail){
        $ionicLoading.hide();
      });
	 },
	 requestEmail: function(message) {
		var emailCheck=/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
		var email = prompt(message, "");
		if (emailCheck.test(email)) {
			var user_data =  FBService.getUser()
			 user_data.profileInfo.email = email
			 FBService.setUser(user_data)
			 this.userEmailOK()
		} else {
			this.requestEmail("Not a valid email address! Please enter a valid email address.")
		}
	 },
	 checkUser: function() {
		 var deferred = $q.defer();
		 var _this = this
	 	//check if user is already registered in the database
	   divePlanDatabase.getLocalDocument("user").then(function(local_user) {
	    	log("local_user",local_user)
			//register token
			_this.registerFacebookToken().then(function(ok) {
				log("fbtoken res",ok)
 				deferred.resolve(local_user);
			}, function(error) {
				// There was an error replicating to the local device
				log("registerFacebookToken error",error)
				deferred.reject(error);
			});
	   }, function(err){
	    	log("local_user non existing",err)
	 		//create user
	       divePlanDatabase.createLocalDocument("user",_this.user).then(function(result) {
	 			 log("local_user",result,_this.user)
	           // Document created successfully
				 //create user profile
 				_this.registerFacebookToken().then(function(ok) {
 					log("fbtoken res",ok)
	 				_this.createMyProfile().then(function(profile) {
	 					log("profile created",profile)
	 					deferred.resolve(profile);
	 				}, function(error) {
	 					// There was an error replicating to the local device
	 					log("createMyProfile error",error)
	 					deferred.reject(error);
	 				});
 				}, function(error) {
 					// There was an error replicating to the local device
 					log("registerFacebookToken error",error)
 					deferred.reject(error);
 				});
				
	       }, function(error) {
	           // Document creation 
	 			 log("local_user error",error)
				 deferred.reject(error);
	       });
	   });
		return deferred.promise;
	 },
	 createMyProfile : function() {
			var _this = this
			//log("createMyProfile user "+JSON.stringify(config.user))
			var profileData = angular.copy(_this.user)
			profileData.type = "profile"
			profileData.user_id = profileData.email
			delete profileData.email
			//log("createMyProfile", profileData)
		   return divePlanDatabase.updateDocument("p:"+profileData.user_id, profileData)
	 },
	 registerFacebookToken : function() {
			var _this = this
			_this.registerData = {
				remote_url : _this.REMOTE_URL,
				email : _this.user.email,
				access_token : _this.user.access_token
			}
			log("registerFacebookToken",_this.registerData)
			return divePlanDatabase.updateFBToken(_this.registerData)
	 },
	 replicateDatabase: function() {
		 var deferred = $q.defer();
		 var _this = this
		//replicate local to remote
	    var auth = false
		 if (_this.user && _this.user.email) {
		 	auth = {facebook : {email : _this.user.email}}
		 }
		divePlanDatabase.replicate(_this.databaseName, _this.REMOTE_URL , true, auth).then(function(result1) {
			log("replicate local to remote",_this.databaseName,result1)
			//replicate remote to local
			divePlanDatabase.replicate(_this.REMOTE_URL, _this.databaseName, true, auth).then(function(result2) {
				log("replicate remote to local",result2)
				if (_this.checkConnection())
				 	_this.showToast("Downloading data from main database...", "short", "bottom")
				
				deferred.resolve(result2);
			}, function(error) {
				// There was an error replicating to the local device
				log("replicate error",error)
				deferred.reject(error);
			});
		}, function(error) {
			// There was an error replicating to the Sync Gateway
			log("replicate error",error)
			deferred.reject(error);
		});
		return deferred.promise;
	 },
	 showToast: function(message, duration, location) {
	       $cordovaToast.show(message, duration, location).then(function(success) {
	           //console.log("The toast was shown");
	       }, function (error) {
	           log("The toast was not shown due to " + error);
	       });
	   }
};
return config;

}]);`


#5

Thank Lucapale, for sharing your code.


#6

Hi Lucapale,

I want to create a view after syncing with database.
I called this below function to create view…

$scope.createview= function() {
var todoViews = {
lists: {
map: function(doc) {
console.log(doc);
if(doc.type== “list”) {
emit(doc._id, {type:doc.type,Name: doc.Name, Email: doc.Email, Company: doc.Company, Phone: doc.Phone, experiance: doc.experiance,
Drone: doc.Drone,Pilot:doc.Pilot,Equipment:doc.Equipment,Location:doc.Location,rev: doc._rev})
}
}.toString()
}
};
todoDatabase.createDesignDocument("_design/todo", todoViews);
todoDatabase.listen();

};

And After this i am calling below mentioned function to get value from view that i am creating but it giving an empty result

$scope.getvalue = function(){
todoDatabase.queryView("_design/todo", “lists”).then(function(result) {
if(result.rows !== undefined && result.rows !== null){
alert(“Result is ::”+result);
}else{
alert(“result in local database is undefined or null”);
}
}, function(error) {
// alert("ERROR QUERYING VIEW -> " + error);
});

}

Can you guide me on this?


#7

Hi. I can give you my code that you can apply to your case.
I have created a factory to access Couchbase:

.factory('CouchBase', ['$window',function($window) {
var couchbase = {}
//load sites list
couchbase.refreshSitesView = function() {
	var options = {
		descending : false
	}
  return divePlanDatabase.queryView("sites",options)
}
return couchbase;
}

in the config I have defined the views and the divePlanDatabase general variable:

this.diveplanViews = 
	  {
			sites : {
				map : function(doc, meta) 
				{
					if (doc.type == "site" && doc.name && doc.geography && doc.geography.country) {
						emit([doc.geography.country,doc.name],{
									name : doc.name,
									lat : doc.geography.latitude,
									lng : doc.geography.longitude
							})
					}
				}.toString()
			}

And finally in the view controller you can call a function that can be refreshed everytime the database receives some update:

function refreshSites() {
	CouchBase.refreshSitesView().then(function(sitesList) {			
		$scope.sites = sitesList.rows;
	}
}
refreshSites()

//refresh on database change
$rootScope.$on("couchbase:change:site", function(event) {
	refreshSites()
});
$rootScope.$on("couchbase:deleted", function(event) {
	refreshSites()
});

This is done using ngCouchbaseLite with a little tweak that sends a:

$rootScope.$broadcast("couchbase:change:" + doc.type);

from within the “listen” function.