SwiftUI Firebase Phone Auth Change DisplayName - firebase

The displayName in the user parameter of the addStateDidChangeListener function in the listener function inside the SessionStore Class returns nil. But I am changing the displayName with the createProfileChangeRequest function. I have one problem. When I change the DisplayName, when I log in with the phone number for the first time, the displayName returns empty. However, when I log in with the application closed in the background, the displayName is full. What is the reason of this ? Where am I doing wrong?
Model:
struct User {
var uid: String
var displayName: String?
var phoneNumber: String?
var isAdmin: Bool
}
Session Store:
class SessionStore : ObservableObject {
var didChange = PassthroughSubject<SessionStore, Never>()
var handle: AuthStateDidChangeListenerHandle?
#Published var user: User?
#Published var uid: String = ""
#Published var errorMessage: String = ""
#Published var showAlert: Bool = false
#Published var isOpenHomePage: Bool = false
#Published var code: String = ""
func listener() {
handle = Auth.auth().addStateDidChangeListener { (auth, user) in
if let user = user {
self.user = User(uid: user.uid, displayName: user.displayName, phoneNumber: user.phoneNumber ?? "", isAdmin: false)
} else {
self.user = nil
}
}
}
func verifyPhoneNumber(phoneNumber: String) {
PhoneAuthProvider.provider().verifyPhoneNumber("+90\(phoneNumber)", uiDelegate: nil) { ID, error in
if error != nil {
self.errorMessage = error?.localizedDescription ?? ""
self.showAlert = true
print("erroroo: \(self.errorMessage)")
return
}
self.uid = ID ?? ""
}
}
func credentialProviderPhoneNumber() {
let credential = PhoneAuthProvider.provider().credential(withVerificationID: uid, verificationCode: code)
Auth.auth().signIn(with: credential) { result, error in
if error != nil {
self.errorMessage = error?.localizedDescription ?? ""
print("error mesajı: \(self.errorMessage)")
return
}
self.isOpenHomePage = true
}
}
func signOut () {
do {
try Auth.auth().signOut()
self.user = nil
} catch {
}
}
func unbind () {
if let handle = handle {
Auth.auth().removeStateDidChangeListener(handle)
}
}
func createProfileChangeRequest() {
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = "Test 123"
changeRequest?.commitChanges(completion: { error in
print("hata: \(error?.localizedDescription)")
})
}
}
SignIn View:
struct SignInView: View {
#State var phoneNumber: String = ""
#State var code: String = ""
#State var didGetCode: Bool = false
#EnvironmentObject var session: SessionStore
var body: some View {
NavigationView {
VStack {
TextField("Telefon Numarası", text: $phoneNumber)
.padding(15)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(15)
.padding(.horizontal)
.keyboardType(.numberPad)
.opacity(didGetCode ? 0.5 : 1)
.disabled(didGetCode ? true : false)
TextField("Kod", text: $code)
.padding(15)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(15)
.padding(.horizontal)
.textContentType(.oneTimeCode)
.keyboardType(.numberPad)
.opacity(didGetCode ? 1 : 0.5)
.disabled(didGetCode ? false : true)
Button(action: {
if code == "" && phoneNumber != "" {
session.verifyPhoneNumber(phoneNumber: phoneNumber)
didGetCode = true
} else {
session.code = code
session.credentialProviderPhoneNumber()
session.createProfileChangeRequest()
}
}) {
Text(didGetCode ? "Doğrula" : "Kod Al")
}
NavigationLink(
destination: HomeView(),
isActive: session.user != nil ? .constant(true) : $session.isOpenHomePage,
label: {
Text("")
})
}
.onAppear {
session.listener()
}
}
}
}
Home View:
struct HomeView: View {
#EnvironmentObject var session: SessionStore
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
Text("Hello User Id: \(session.user?.uid ?? "")")
Text("Tel No: \(session.user?.phoneNumber ?? "")")
Text("Display Name: \(session.user?.displayName ?? "")")
Button(action: {
session.signOut()
presentationMode.wrappedValue.dismiss()
}) {
Text("Çıkış Yap")
}
}
.onAppear {
session.createProfileChangeRequest() -> here
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}

Related

SwiftUI: Publishing single view with data from multiple screens

Using SwiftUI, I am trying to create an upload onboarding flow, using multiple screens, then storing that data to firebase. Imagine someone uploading their home to airbnb. You have multiple screens in a row (toggled with a back or next button) that gives you an end result of a single, vertically scrolling screen with all of your data that you have previously input.
I have a forum in my app, and have figured out to do this with a single screen of storing data (2 text fields - body and title). But how do I do this for multiple views of data.
I am very very new to programming and have been following a tutorial while trying to mold it to my own thing, so I apologize if the terminology (View, View Model, Model) is incorrect.
Forum code below:
Api:
class Api {
// static var Post = PostApi()
static var User = UserApi()
static var Forum = ForumApi()
}
ForumApi:
class ForumApi {
func uploadForumPost(forumPostTitle: String, forumPostBody: String, imageData: Data, onSuccess: #escaping() -> Void, onError: #escaping(_ errorMessage: String) -> Void) {
guard let userId = Auth.auth().currentUser?.uid else {
return
}
let forumPostId = Ref.FIRESTORE_MY_FORUM_POSTS_DOCUMENT_USERID(userId: userId).collection("userForumPosts").document().documentID
let storageForumPostRef = Ref.STORAGE_FORUM_POST_ID(forumPostId: forumPostId)
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
StorageService.saveForumPost(userId: userId, forumPostTitle: forumPostTitle, forumPostBody: forumPostBody, forumPostId: forumPostId, imageData: imageData, metadata: metadata, storageForumPostRef: storageForumPostRef, onSuccess: onSuccess, onError: onError)
}
}
Forum Post Model:
struct ForumPost: Encodable, Decodable{
var forumPostTitle: String
var forumPostBody: String
var likes: [String: Bool]
var location: String
var ownerId: String
var postId: String
var username: String
var avatar: String
var mediaUrl: String
var date: Double
var likeCount: Int
}
Forum Post View Model:
class ForumPostViewModel: ObservableObject {
var forumPostTitle: String = ""
var forumCategory: String = ""
var forumPostBody: String = ""
var imageData: Data = Data()
var errorString = ""
#Published var showAlert: Bool = false
func shareForumPost (completed: #escaping() -> Void, onError: #escaping(_ errorMesssage: String) -> Void) {
if !forumPostTitle.isEmpty && !forumPostBody.isEmpty {
//AuthService.signupUser(username: username, email: email, password: password, imageData: imageData, onSuccess: completed, onError: onError)
Api.Forum.uploadForumPost(forumPostTitle: forumPostTitle, forumPostBody: forumPostBody, imageData: imageData, onSuccess: completed, onError: onError)
} else {
showAlert = true
errorString = "Please fill in all fields"
}
}
}
Forum Profile View Model:
class ForumProfileViewModel: ObservableObject {
#Published var userForumPosts: [ForumPost] = []
#Published var isLoading = false
var searchText: String = ""
var splitted: [[ForumPost]] = []
func loadUserForumPosts(userId: String) {
isLoading = true
Api.User.loadForumPosts(userId: userId) { (userForumPosts) in
self.isLoading = false
self.userForumPosts = userForumPosts
self.splitted = self.userForumPosts.splited(into: 1)
}
}
}
Forum Profile View:
struct ForumProfileBody: View {
var userForumPost: ForumPost
#State var shouldSheetShow: Bool = false;
var body: some View {
VStack(alignment: .leading) {
VStack {
HStack {
Text(userForumPost.forumPostTitle)
.fontWeight(.semibold)
.font(.system(size: 22))
Spacer()
Image(systemName: "ellipsis")
}
}
//More UI code
}
}
}

How to display ProgressView during an async operation in SwiftUI

Hello!
I want to display progress during my operation. I'm new to swift and swiftui. Please help...
Here is the model with one async method:
class CountriesViewModel : ObservableObject {
#Published var countries: [String] = [String]()
#Published var isFetching: Bool = false
#MainActor
func fetch() async {
countries.removeAll()
isFetching = true
countries.append("Country 1")
Thread.sleep(forTimeInterval: 1)
countries.append("Country 2")
Thread.sleep(forTimeInterval: 1)
countries.append("Country 3")
Thread.sleep(forTimeInterval: 1)
isFetching = false
}
}
and the ContentView:
struct ContentView: View {
#StateObject var countriesVM = CountriesViewModel()
var body: some View {
ZStack {
if (countriesVM.isFetching) {
ProgressView("Fetching...")
}
else {
List {
ForEach(countriesVM.countries, id: \.self) { country in
Text(country)
}
}
.task {
await countriesVM.fetch()
}
.refreshable {
Task {
await countriesVM.fetch()
}
}
}
}
}
}
The progress is not displayed. What am I doing wrong?
you could try this simple approach:
struct ContentView: View {
#StateObject var countriesVM = CountriesViewModel()
var body: some View {
ZStack {
if (countriesVM.isFetching) {
ProgressView("Fetching...")
}
else {
List {
ForEach(countriesVM.countries, id: \.self) { country in
Text(country)
}
}
.refreshable {
Task {
await countriesVM.fetch()
}
}
}
}
.task { // <-- here
await countriesVM.fetch()
}
}
class CountriesViewModel : ObservableObject {
#Published var countries: [String] = [String]()
#Published var isFetching: Bool = true // <-- here
#MainActor
func fetch() async {
countries.removeAll()
isFetching = true
countries.append("Country 1")
Thread.sleep(forTimeInterval: 1)
countries.append("Country 2")
Thread.sleep(forTimeInterval: 1)
countries.append("Country 3")
Thread.sleep(forTimeInterval: 1)
isFetching = false
}
}
}
EDIT-1: including a button to refresh the data.
struct ContentView: View {
#StateObject var countriesVM = CountriesViewModel()
var body: some View {
ZStack {
if countriesVM.isFetching {
ProgressView("Fetching...")
}
else {
VStack {
Button("refresh", action: {
Task { await countriesVM.fetch() }
}).buttonStyle(.bordered)
List {
ForEach(countriesVM.countries, id: \.self) { country in
Text(country)
}
}
.refreshable {
await countriesVM.fetch()
}
}
}
}
.task {
await countriesVM.fetch()
}
}
class CountriesViewModel : ObservableObject {
#Published var countries: [String] = [String]()
#Published var isFetching: Bool = false
#MainActor
func fetch() async {
countries.removeAll()
isFetching = true
// representative background async process
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 2) {
// eventualy, updates on the main thread for the UI to use
DispatchQueue.main.async {
self.countries.append("Country 1")
self.countries.append("Country 2")
self.countries.append("Country 3")
self.isFetching = false
}
}
}
}
}

How to check if the emaiID exists or not in the dynamodb?

am using node js for the lambda function. I need to check whether the emailID exists or not in the dynamo db...If the emailID exists it should prompt to the user that emailid already exists if not it should store the values in the dynamo db ....
EmailID is the sort key
Customername is the primary key
How can i do that ..
Below is my code:
var doc = require('aws-sdk');
var dynamodb = new doc.DynamoDB()
var tableName = "Testing";
exports.handler = (event, context, callback) => {
var EmailID = event.EmailID; // or any other var which is having emaiID
console.log(event)
var params = {
TableName: "Testing",
Key: { EmailID : "abc#gmail.com",
CustomerName : "ABC"},
AttributeUpdates: {
verified: {
Action: "PUT",
Value: true
}
}
};
// Update the user.
dynamodb.update(params, function(err, data)
{
if (err)
{
console.log(JSON.stringify(err));
context.fail(JSON.stringify(err));
return;
}
context.succeed("User successfully updated.");
});
putItem
var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
// TODO implement
var tableName = "Testing";
console.log(event.EmailID)
var parms = {
TableName : tableName,
Item : {
"EmailID" : event.EmailID,
"CustomerName" : event.CustomerName,
"PersonName" : event.PersonName,
"EmailSent" : event.EmailSent,
"Password" : event.Password
}
};
docClient.put(parms, function(err, data)
{
if (err){
callback(err)
}
else
{
callback(null,"Successfully updated data!!!")
}
})
};
To achieve this I would use the Put operation and use the "exists" parameter. Setting it to false will make sure the put operation will fail if an item already exists. When there is no match then put will insert the record.
For more details on how to use this operation in javascript please check out the documentation:
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#putItem-property
So in your put example you could add the following to your params:
var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
// TODO implement
var tableName = "Testing";
console.log(event.EmailID)
var parms = {
TableName: tableName,
Item: {
"EmailID": event.EmailID,
"CustomerName": event.CustomerName,
"PersonName": event.PersonName,
"EmailSent": event.EmailSent,
"Password": event.Password
},
ConditionExpression: "attribute_not_exists(EmailID)"
};
docClient.put(parms, function (err, data) {
if (err) {
callback(err)
}
else {
callback(null, "Successfully updated data!!!")
}
})
};

Google Authentication Email Scope using Firebase

I am using the Firebase Polymer Component to get users to login using Google Oauth. I cannot though seem to find a way to get their email addresses. I cannot seem to be able to add email to scope.
There seems to be an issue in Github regarding the element with this.
https://github.com/GoogleWebComponents/firebase-element/issues/39
I used firebase-auth polymer element and added the email scope. I have also created an element called hi9-login with this in.
https://github.com/HackITtoday/hi9-login
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../firebase-element/firebase-auth.html">
<link rel="import" href="../firebase-element/firebase-document.html">
<link rel="import" href="../paper-button/paper-button.html">
<dom-module id="hi9-login">
<template>
<firebase-auth id="firebaseLogin" user="{{user}}" status-known="{{statusKnown}}" location="https://hi9site.firebaseio.com" provider="google" on-error="errorHandler" on-user-created="userSuccessHandler" on-password-changed="userSuccessHandler" on-password-reset="userSuccessHandler" on-user-removed="userSuccessHandler"></firebase-auth>
<!-- <firebase-document location="https://hi9site.firebaseio.com/data" id="firebaseDocument"></firebase-document> -->
<firebase-document location="{{userDataUrl}}" data="{{userData}}" id="firebaseUser"></firebase-document>
<firebase-document location="{{ownerDataUrl}}" data="{{ownerData}}" id="firebaseOwner"></firebase-document>
<paper-button on-tap="logout" hidden$="{{computeLogoutHidden(statusKnown, user)}}"> Logout </paper-button>
<paper-button on-tap="login" hidden$="{{computeLoginHidden(statusKnown, user)}}"> Login </paper-button>
</template>
</dom-module>
<script>
var that = {};
Polymer({
is: 'hi9-login',
properties: {
params: {
scope: "email"
},
provider: {
type: String, value: 'anonymous'
},
message: {
type: String, value: ''
},
email: {
type: String, value: ''
},
password: {
type: String, value: ''
},
user: {
type: Object, value: null,
notify: true
},
uid: {
computed:'returnVal(user.uid)'
},
owner: {
computed:'returnVal(user.owner)'
},
userDataUrl:{
computed:'getUserDataUrl(uid)'
},
ownerDataUrl:{
computed:'getOwnerDataUrl(owner, uid)'
},
statusKnown: {
type: Boolean
},
show_model: {
type: Boolean, notify: true,
computed: "computeLogoutHidden(statusKnown, user)"
},
role: {
computed: 'getRole(user,userData)',
notify: true
},
admin: {
computed: 'isAdmin(role)',
notify: true
}
},
returnVal: function(val) {
if (val !== undefined && val !== null) {
return val;
} else {
return undefined;
}
},
getOwnerDataUrl: function(owner,uid) {
return "https://hi9site.firebaseio.com/owner/" + owner + "/users/" + uid;
},
getUserDataUrl: function(uid) {
that = this;
setTimeout(function(){ that.whenReady(); }, 7000);
return "https://hi9site.firebaseio.com/users/" + uid;
},
login: function() {
var params;
try {
params = JSON.parse(this.params);
} catch (e) {
params = null;
}
if (this.provider == 'password') {
params = params || {};
params.email = this.email;
params.password = this.password;
}
this.$.firebaseLogin.login(params);
this.log("Login");
},
logout: function() {
this.log("Logout");
this.$.firebaseLogin.logout();
},
errorHandler: function(e) {
this.log("Login Status");
this.message = 'Error: ' + e.detail.message;
},
userSuccessHandler: function(e) {
this.log("Login Status");
this.message = e.type + ' success!';
},
createUserHandler: function(e) {
this.log("createUserHandler");
this.$.firebaseLogin.createUser(this.email, this.password);
},
changePasswordHandler: function(e) {
this.log("changePasswordHandler");
this.$.firebaseLogin.changePassword(this.email, this.password, this.newPassword);
},
resetPasswordHandler: function(e) {
this.log("resetPasswordHandler");
this.$.firebaseLogin.sendPasswordResetEmail(this.email);
},
computePasswordHidden: function(provider) {
this.log("Login Status");
return provider !== 'password';
},
computeCreateUserDisabled: function(email, password) {
this.log("computeCreateUserDisabled");
return !email || !password;
},
computeChangePasswordDisabled: function(email, password, newPassword) {
this.log("computeChangePasswordDisabled");
return !email || !password || !newPassword;
},
computeResetPasswordDisabled: function(email, password) {
this.log("computeResetPasswordDisabled");
return !email || !password;
},
computeRemoveUserDisabled: function(email, password) {
this.log("computeRemoveUserDisabled");
return !email || !password;
},
computeLoginHidden: function(statusKnown, user) {
this.log("computeLoginHidden");
return !statusKnown || !!user;
},
computeLogoutHidden: function(statusKnown, user) {
this.log("computeLogoutHidden");
return !statusKnown || !user;
},
computeLoginStatus: function(statusKnown, user) {
var d = new Date();
var n = d.getTime();
this.log("Login Status");
if (statusKnown && user) {
return 'Logged in';
}
if (statusKnown) {
return 'Logged out';
}
return 'Unknown (checking status...)';
},
log: function(log) {
// var d = new Date();
// var n = d.getTime();
// this.$.firebaseDocument.query.ref().push({log: log,time:n,user:this.user});
},
getRole: function(user, userData) {
if (userData !== undefined && userData !== null && user !== null) {
if (this.userSet === undefined && userData.owner === undefined) { // Stops Looping.
this.userSet = true;
if (userData.num === undefined ) {
userData.num = prompt("Hi "+user.google.displayName+"\nPlease tell me your mobile phone number?", "07");
}
if (userData.owner === undefined) {
userData.owner = prompt("What is your housing association?", "Yarlington");
}
if (userData.email === undefined) {
userData.email = prompt("and lastly you email address?", "");
}
if (userData.log === undefined) {
var d = new Date();
var n = d.getTime();
userData.log = [{first: n}]
}
userData.user = user;
this.userData = clone(userData);
this.ownerData = clone(userData);
}
// user
if (!userData.hasOwnProperty("role")) {
userData.role = "User"
}
return userData.role;
} else {
return 'no data'
}
},
isAdmin: function(role) {
return role = 'admin';
},
whenReady: function() {
var userDataTest = clone(this.$.firebaseUser.data);
delete(this.$.firebaseUser.data);
if (userDataTest === undefined || userDataTest === null){
userDataTest = {placeholder:true}
};
this.$.firebaseUser.data = userDataTest;
var ownerDataTest = clone(this.$.firebaseOwner.data);
delete(this.$.firebaseOwner.data);
if (ownerDataTest === undefined || ownerDataTest === null){
ownerDataTest = {placeholder:true}
};
if (this.ownerDataUrl) {
this.$.firebaseOwner.data = ownerDataTest;
}
}
});
function clone(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
</script>
Here also is a screenshot in JSFiddle showing it's not working
You can add a scope to the authWithOAuthRedirect API.
For example,
ref.authWithOAuthRedirect('google', errorHandler, {
scope: "email"
});
Then, in your onAuth handler you can get the "authData.google.email" property:
ref.onAuth(function(authData) {
if (authData) {
console.log("Authenticated with email: ", authData.google.email);
} else {
console.log("Client unauthenticated.")
}
});

LoginHandler with ldapjs and Meteor.methods

I try to implement a logIn in Meteor 0.9.2.1 with LDAPJS and Meteor methods. The code for the server-side is:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
LDAP = {};
LDAP.ldap = ldap;
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
LDAP.searchQuery = function(user) {
return{
filter: '(uid=username)',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
search.on('searchEntry', function(entry){
//console.log('entry: ' + JSON.stringify(entry.object));
dn.push(entry.object.uid);
dn.push(entry.object.userPassword)
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
var testBind = LDAP.ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
testBind.bind(dn[10], options.password, function (err) {
future['return'](!err);
});
client.unbind(function (err) {
assert.ifError(err);
future['return'](!err);
});
});
});
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
var loginHandler = function (username, password) {
Accounts.registerLoginHandler("ldapjs",function(loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var user = Meteor.users.findOne({ username: loginRequest.username });
if(err){
console.log(err)
}
return {
userId: uid
}
}
});
};
Meteor.methods({
setSignIn: function(username, password) {
loginHandler(username,password)
}
});
My Problem is, that when I want to log in it starts with the loginHandler. But than the console throws back that Object has no method checkAccount. I changed today a lot and I'm already totally confused.
You need to instantiate the empty object as var LDAP = {}. Rest will be solved magically :)
I finally got to work it. Referneces:
http://notjoshmiller.com/using-ldaps-in-meteor/, https://github.com/emgee3/meteor-accounts-ldap
server-side:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
var LDAP = {};
LDAP.ldap = ldap;
//provides the variables, needed for the connection
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
//is needed for the searchQuery, which delivers the Filter so that only the uid with
//the given username get searched
LDAP.searchQuery = function(username) {
return{
filter: '(uid=' + username + ')',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
//connects the client, nginx is here not necessary
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
//create the connection
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
if(err){
console.log(err)
}
//uses the class searchEntry, which is node-specific
search.on('searchEntry', function (entry) {
dn.push(entry.objectName);
LDAP.displayName = entry.object.displayName
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
//uses the end class to 'fulfill' the connection by binding
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
LDAP.client.bind(dn[0], options.password, function (err) {
future['return'](!err);
});
});
});
return future.wait();
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
Meteor.startup(function(){
Accounts.registerLoginHandler("ldapjs", function (loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var userId;
var user = Meteor.users.findOne({
username : loginRequest.username
//'profile.name': LDAP.displayName
});
if (user) {
userId = user._id;
} else {
// If no Meteor Account is found for a valid LDAP logon,
// you can either prevent logon by passing 'undefined' or
// you can automatically create the new account.
// return undefined;
userId = Meteor.users.insert({ username : loginRequest.username });
}
return {
userId: userId
}
}
return undefined;
});
});
client side:
Meteor.ldapLogin = function (username, password, callback) {
var loginRequest = {
username: username,
password: password
};
Accounts.callLoginMethod({
methodArguments: [loginRequest],
userCallback: function (err) {
if (err) {
console.log(err);
Session.set('alert', 'No valid inputs!');
} else {
Router.go('/Home');
}
}
});
};
//handles LogIn-Button, by using LDAPJS
Template.signIn.events({
"submit #box-login": function (e, t) {
e.preventDefault();
var signInForm = $(e.currentTarget),
username = trimInput(signInForm.find('#emailSignIn').val().toLowerCase()),
password = signInForm.find('#passwordSignIn').val();
if(isNotEmpty(username)&& isNotEmpty(password)) {
Meteor.ldapLogin(username, password, function (err) {
if (err) {
console.log(err)
Session.set('alert', 'Sorry, something went wrong.');
}
});
} else {
Session.set('alert','Please insert your username and password!')
}
return false;
}
});
PS: No Meteor.methods and Meteor.call is needed! It might change with every new Meteor version and package, but I guess u're aware of that ;)

Resources