/* * Created by Itzik Braun on 12/3/2015. * Copyright (c) 2015 deluge. All rights reserved. * * Last Modification at: 3/12/15 4:35 PM */ package com.braunster.androidchatsdk.firebaseplugin.firebase.wrappers; import com.braunster.androidchatsdk.firebaseplugin.firebase.BFirebaseNetworkAdapter; import com.braunster.androidchatsdk.firebaseplugin.firebase.FirebasePaths; import com.braunster.chatsdk.Utils.Debug; import com.braunster.chatsdk.dao.BLinkedAccount; import com.braunster.chatsdk.dao.BUser; import com.braunster.chatsdk.dao.core.DaoCore; import com.braunster.chatsdk.dao.entities.BMessageEntity; import com.braunster.chatsdk.network.AbstractNetworkAdapter; import com.braunster.chatsdk.network.BDefines; import com.braunster.chatsdk.network.BFirebaseDefines; import com.braunster.chatsdk.network.TwitterManager; import com.braunster.chatsdk.object.BError; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.UserInfo; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.ServerValue; import com.google.firebase.database.ValueEventListener; import org.apache.commons.lang3.StringUtils; import org.jdeferred.Deferred; import org.jdeferred.DoneCallback; import org.jdeferred.FailCallback; import org.jdeferred.Promise; import org.jdeferred.impl.DeferredObject; import java.util.HashMap; import java.util.List; import java.util.Map; import timber.log.Timber; public class BUserWrapper extends EntityWrapper<BUser> { private static final boolean DEBUG = Debug.BUser; private static final String USER_PREFIX = "user"; public static BUserWrapper initWithAuthData(FirebaseUser authData){ return new BUserWrapper(authData); } public static BUserWrapper initWithModel(BUser user){ return new BUserWrapper(user); } public static BUserWrapper initWithSnapshot(DataSnapshot snapshot){ return new BUserWrapper(snapshot); } public static BUserWrapper initWithEntityId(String entityId){ BUser model = DaoCore.fetchOrCreateEntityWithEntityID(BUser.class, entityId); return initWithModel(model); } private BUserWrapper(FirebaseUser authData){ model = DaoCore.fetchOrCreateEntityWithEntityID(BUser.class, authData.getUid()); entityId = model.getEntityID(); updateUserFromAuthData(authData); } private BUserWrapper(BUser model) { this.model = model; entityId = model.getEntityID(); } private BUserWrapper(DataSnapshot snapshot){ model = DaoCore.fetchOrCreateEntityWithEntityID(BUser.class, snapshot.getKey()); entityId = model.getEntityID(); deserialize((Map<String, Object>) snapshot.getValue()); } /** * Note - Change was removing of online values as set online and online time. * * * * */ private void updateUserFromAuthData(FirebaseUser authData){ Timber.v("updateUserFromAuthData"); model.setAuthenticationType((Integer) getNetworkAdapter().getLoginInfo().get(BDefines.Prefs.AccountTypeKey)); model.setEntityID(authData.getUid()); String name = authData.getDisplayName(); String email = authData.getEmail(); String token = getNetworkAdapter().getLoginInfo().get(BDefines.Prefs.TokenKey).toString(); String uid = authData.getUid(); BLinkedAccount linkedAccount; switch ((Integer) (getNetworkAdapter().getLoginInfo().get(BDefines.Prefs.AccountTypeKey))) { case BDefines.ProviderInt.Facebook: // Setting the name. if (StringUtils.isNotBlank(name) && StringUtils.isBlank(model.getMetaName())) { model.setMetaName(name); } // Setting the email.// if (StringUtils.isNotBlank(email) && StringUtils.isBlank(model.getMetaEmail())) { model.setMetaEmail(email); } linkedAccount = model.getAccountWithType(BLinkedAccount.Type.FACEBOOK); if (linkedAccount == null) { linkedAccount = new BLinkedAccount(); linkedAccount.setType(BLinkedAccount.Type.FACEBOOK); linkedAccount.setBUserDaoId(model.getId()); DaoCore.createEntity(linkedAccount); } linkedAccount.setToken(token); break; case BDefines.ProviderInt.Twitter: // Setting the name if (StringUtils.isNotBlank(name) && StringUtils.isBlank(model.getMetaName())) model.setMetaName(name); // Setting the email.// if (StringUtils.isNotBlank(email) && StringUtils.isBlank(model.getMetaEmail())) { model.setMetaEmail(email); } TwitterManager.userId = uid; linkedAccount = model.getAccountWithType(BLinkedAccount.Type.TWITTER); if (linkedAccount == null) { linkedAccount = new BLinkedAccount(); linkedAccount.setType(BLinkedAccount.Type.TWITTER); linkedAccount.setBUserDaoId(model.getId()); DaoCore.createEntity(linkedAccount); } linkedAccount.setToken(token); break; case BDefines.ProviderInt.Password: // Setting the name if (StringUtils.isNotBlank(name) && StringUtils.isBlank(model.getMetaName())) model.setMetaName(name); if (StringUtils.isNotBlank(email) && StringUtils.isBlank(model.getMetaEmail())) { model.setMetaEmail(email); } break; default: break; } // Message Color. if (StringUtils.isEmpty(model.getMessageColor())) { if (StringUtils.isNotEmpty(BDefines.Defaults.MessageColor)) { model.setMessageColor(BDefines.Defaults.MessageColor); } else model.setMessageColor( BMessageEntity.colorToString(BMessageEntity.randomColor()) ); } if (StringUtils.isEmpty(model.getMetaName())) { model.setMetaName(BDefines.getDefaultUserName()); } // Save the data DaoCore.updateEntity(model); } public Promise<BUser, BError, Void> once(){ final Deferred<DataSnapshot, BError, Void> deferred = new DeferredObject<>(); final Deferred<BUser, BError, Void> promise = new DeferredObject<>(); DatabaseReference ref = ref(); if (DEBUG) Timber.v("once, EntityID: %s, Ref Path: %s", entityId, ref.toString()); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { if (DEBUG) Timber.v("once, onDataChange"); deferred.resolve(snapshot); } @Override public void onCancelled(DatabaseError firebaseError) { if (DEBUG) Timber.v("once, onCancelled"); deferred.reject(BFirebaseNetworkAdapter.getFirebaseError(firebaseError)); } }); deferred.done(new DoneCallback<DataSnapshot>() { @Override public void onDone(DataSnapshot snapshot) { deserialize((Map<String, Object>) snapshot.getValue()); promise.resolve(model); } }).fail(new FailCallback<BError>() { @Override public void onFail(BError bError) { promise.reject(bError); } }); return promise; } public void metaOff(){ getNetworkAdapter().getEventManager().userMetaOff(entityId); } public Promise metaOn(){ final Deferred<Void, Void, Void> deferred = new DeferredObject<>(); getNetworkAdapter().getEventManager().userMetaOn(entityId, deferred); return deferred; } void deserialize(Map<String, Object> value){ if (DEBUG) Timber.v("deserialize, Value is null? %s", value == null); if (value != null) { if (value.containsKey(BDefines.Keys.BOnline) && !value.get(BDefines.Keys.BOnline).equals("")) model.setOnline((Boolean) value.get(BDefines.Keys.BOnline)); if (value.containsKey(BDefines.Keys.BColor) && !value.get(BDefines.Keys.BColor).equals("")) { model.setMessageColor((String) value.get(BDefines.Keys.BColor)); } // The entity update is called in the deserializeMeta. deserializeMeta((Map<String, Object>) value.get(BFirebaseDefines.Path.BMetaPath)); } } void deserializeMeta(Map<String, Object> value){ if (DEBUG) Timber.v("deserializeMeta, Value: %s", value); if (value != null) { Map<String, Object> oldData = model.metaMap(); Map<String, Object> newData = value; if (DEBUG) Timber.v("deserializeMeta, OldDataMap: %s", oldData); // Updating the old data for (String key : newData.keySet()) { if (DEBUG) Timber.d("key: %s, Value: %s", key, newData.get(key)); if (oldData.get(key) == null || !oldData.get(key).equals(newData.get(key))) oldData.put(key, newData.get(key)); } model.setMetaMap(oldData); model = DaoCore.updateEntity(model); } } Map<String, Object> serialize(){ Map<String, Object> values = new HashMap<String, Object>(); values.put(BDefines.Keys.BColor, StringUtils.isEmpty(model.getMessageColor()) ? "" : model.getMessageColor()); values.put(BDefines.Keys.BMeta, model.metaMap()); values.put(BDefines.Keys.BLastOnline, ServerValue.TIMESTAMP); return values; } public Promise<BUser, BError, Void> push(){ if (DEBUG) Timber.v("push"); final Deferred<BUser, BError, Void> deferred = new DeferredObject<>(); ref().updateChildren(serialize(), new DatabaseReference.CompletionListener() { @Override public void onComplete(DatabaseError firebaseError, DatabaseReference firebase) { if (firebaseError == null) { deferred.resolve(model); } else deferred.reject(getFirebaseError(firebaseError)); } }); // index should be updated whenever the user is pushed updateIndex(); return deferred.promise(); } public DatabaseReference ref(){ return FirebasePaths.userRef(entityId); } private DatabaseReference imageRef(){ return ref().child(BFirebaseDefines.Path.BImage); } private DatabaseReference thumbnailRef(){ return ref().child(BFirebaseDefines.Path.BThumbnail); } private DatabaseReference metaRef(){ return ref().child(BFirebaseDefines.Path.BMetaPath); } public String pushChannel(){ String channel = USER_PREFIX + (model.getEntityID().replace(":", "_")); if (channel.contains("%3A")) channel = channel.replace("%3A", "_"); if (channel.contains("%253A")) channel = channel.replace("%253A", "_"); return channel; } public Promise<BUserWrapper, DatabaseError, Void> addThreadWithEntityId(String entityId){ final Deferred<BUserWrapper, DatabaseError, Void> deferred = new DeferredObject<>(); // Getting the user ref. DatabaseReference userThreadRef = ref(); userThreadRef = userThreadRef.child(BFirebaseDefines.Path.BThreadPath).child(entityId); userThreadRef.child(BDefines.Keys.BNull).setValue("", new DatabaseReference.CompletionListener() { @Override public void onComplete(DatabaseError firebaseError, DatabaseReference firebase) { if (firebaseError == null) { deferred.resolve(BUserWrapper.this); } else { deferred.reject(firebaseError); } } }); return deferred.promise(); } public Promise<BUserWrapper, DatabaseError, Void> removeThreadWithEntityId(String entityId){ final Deferred<BUserWrapper, DatabaseError, Void> deferred = new DeferredObject<>(); DatabaseReference userThreadRef = FirebasePaths.userRef(entityId).child(BFirebaseDefines.Path.BThreadPath).child(entityId); userThreadRef.removeValue(new DatabaseReference.CompletionListener() { @Override public void onComplete(DatabaseError firebaseError, DatabaseReference firebase) { if (firebaseError == null) { deferred.resolve(BUserWrapper.this); } else { deferred.reject(firebaseError); } } }); return deferred.promise(); } public Promise<Void, BError, Void> updateIndex(){ final Deferred<Void, BError, Void> deferred = new DeferredObject(); Map<String, String> values = new HashMap<String, String>(); String name = model.getMetaName(); String email = model.getMetaEmail(); String phoneNumber = model.metaStringForKey(BDefines.Keys.BPhone); values.put(BDefines.Keys.BName, StringUtils.isNotEmpty(name) ? AbstractNetworkAdapter.processForQuery(name) : ""); values.put(BDefines.Keys.BEmail, StringUtils.isNotEmpty(email) ? AbstractNetworkAdapter.processForQuery(email) : ""); if (BDefines.IndexUserPhoneNumber && StringUtils.isNotBlank(phoneNumber)) values.put(BDefines.Keys.BPhone, AbstractNetworkAdapter.processForQuery(phoneNumber)); DatabaseReference ref = FirebasePaths.indexRef().child(entityId); ref.setValue(values, new DatabaseReference.CompletionListener() { @Override public void onComplete(DatabaseError firebaseError, DatabaseReference firebase) { if (firebaseError==null) { deferred.resolve(null); } else{ deferred.reject(getFirebaseError(firebaseError)); } } }); return deferred.promise(); } /** * Set the user online value to false. **/ public void goOffline(){ DatabaseReference userOnlineRef = FirebasePaths.userOnlineRef(entityId); userOnlineRef.setValue(false); } /** * Set the user online value to true. * * When firebase disconnect this will be auto change to false. **/ public void goOnline(){ DatabaseReference userOnlineRef = FirebasePaths.userOnlineRef(entityId); // Set the current state of the user as online. // And add a listener so when the user log off from firebase he will be set as disconnected. userOnlineRef.setValue(true); userOnlineRef.onDisconnect().setValue(false); } }