app/src/main/java/com/ncnf/models/User.java
package com.ncnf.models;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.GeoPoint;
import com.ncnf.authentication.firebase.FirebaseAuthentication;
import com.ncnf.database.firebase.FirebaseDatabase;
import com.ncnf.authentication.firebase.CurrentUserModule;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import static com.ncnf.utilities.InputValidator.isInvalidString;
import static com.ncnf.utilities.StringCodes.EVENTS_COLLECTION_KEY;
import static com.ncnf.utilities.StringCodes.FULL_NAME_KEY;
import static com.ncnf.utilities.StringCodes.GROUPS_COLLECTION_KEY;
import static com.ncnf.utilities.StringCodes.NOTIFICATIONS_KEY;
import static com.ncnf.utilities.StringCodes.NOTIFICATIONS_TOKEN_KEY;
import static com.ncnf.utilities.StringCodes.OWNED_GROUPS_KEY;
import static com.ncnf.utilities.StringCodes.PARTICIPATING_GROUPS_KEY;
import static com.ncnf.utilities.StringCodes.SAVED_EVENTS_KEY;
import static com.ncnf.utilities.StringCodes.USERS_COLLECTION_KEY;
import static com.ncnf.utilities.StringCodes.UUID_KEY;
public class User {
private FirebaseDatabase db;
private final String uuid;
private String username;
private String email;
private String fullName;
private List<String> friendsIds;
private List<String> ownedGroupsIds;
private List<String> participatingGroupsIds;
private List<String> savedEventsIds;
private LocalDate birthDate;
private boolean notifications;
private GeoPoint location;
/**
* Public constructor used to create an already existing user
* @param db Database service used to store and load user's attributes, etc.
* @param uuid User's unique identifier
* @param username User's username
* @param email User's email
* @param fullName User's full name
* @param friendsIds List of ID of the User's friends
* @param ownedGroupsIds List of ID of the User's owned group
* @param participatingGroupsIds List of ID of the groups in which the User is
* @param savedEventsIds List of ID of the User's saved event
* @param notifications Boolean indicating whether the user receives notification or not
* @param birthDate User's birthdate
* @param location User's location
*/
public User(FirebaseDatabase db, String uuid, String username, String email, String fullName, List<String> friendsIds, List<String> ownedGroupsIds, List<String> participatingGroupsIds, List<String> savedEventsIds, boolean notifications, LocalDate birthDate, GeoPoint location) {
if(isInvalidString(uuid) || isInvalidString(email)){
throw new IllegalArgumentException();
}
this.db = db;
this.uuid = uuid;
this.username = username;
this.email = email;
this.fullName = fullName;
this.friendsIds = friendsIds;
this.ownedGroupsIds = ownedGroupsIds;
this.savedEventsIds = savedEventsIds;
this.birthDate = birthDate;
this.notifications = notifications;
this.participatingGroupsIds = participatingGroupsIds;
this.location = location;
}
/**
* Public constructor with all attributes set to default values
*/
public User(){
this(new FirebaseDatabase(), FirebaseAuth.getInstance().getUid(), "",FirebaseAuth.getInstance().getCurrentUser().getEmail(),"", new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), false, null, null);
}
/**
* Public constructor used to create a new user
* @param username User's username
* @param email User's email
* @param fullName User's full name
* @param friendsIds List of ID of the User's friends
* @param ownedGroupsIds List of ID of the User's owned group
* @param savedEventsIds List of ID of the User's saved event
* @param birthDate User's birthdate
* @param notifications Boolean indicating whether the user receives notification or not
* @param location User's location
*/
public User(String username, String email, String fullName, List<String> friendsIds, List<String> ownedGroupsIds, List<String> savedEventsIds, LocalDate birthDate, boolean notifications, GeoPoint location) {
this(new FirebaseDatabase(), FirebaseAuth.getInstance().getUid(), username, email, fullName, friendsIds, ownedGroupsIds, new ArrayList<>(), savedEventsIds, notifications, birthDate, location);
}
/**
* Getters for attributes
*/
public String getUuid(){
return uuid;
}
public String getUsername() {
return username;
}
public String getEmail(){
return email;
}
public String getFullName() {
return fullName;
}
public List<String> getFriendsIds() {
return Collections.unmodifiableList(friendsIds);
}
public List<String> getOwnedGroupsIds() {
return Collections.unmodifiableList(ownedGroupsIds);
}
public List<String> getParticipatingGroupsIds() {
return Collections.unmodifiableList(participatingGroupsIds);
}
public List<String> getSavedEventsIds() {
return Collections.unmodifiableList(savedEventsIds);
}
public LocalDate getBirthDate() {
return birthDate;
}
public GeoPoint getLocation() { return location; }
public boolean getNotifications() {
return notifications;
}
/**
* Getters for attributes
*/
public void setUsername(String username){
this.username = username;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public void setFriendsIds(List<String> friendsIds) {
this.friendsIds = friendsIds;
}
public void setLocation(GeoPoint location){
this.location = location;
}
public void setEmail(String email){
this.email = email;
}
public void setParticipatingGroupsIds(List<String> participatingGroupsIds) {
this.participatingGroupsIds = new ArrayList<>(participatingGroupsIds);
}
public void setOwnedGroupsIds(List<String> ownedGroupsIds) {
this.ownedGroupsIds = new ArrayList<>(ownedGroupsIds);
}
public void setSavedEventsIds(List<String> savedEventsIds) {
this.savedEventsIds = new ArrayList<>(savedEventsIds);
}
public void setDB(FirebaseDatabase db){
this.db = db;
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public void setNotifications(boolean notifications) {
this.notifications = notifications;
}
public CompletableFuture<Boolean> updateNotifications(boolean isEnabled) {
setNotifications(isEnabled);
return this.db.updateField(USERS_COLLECTION_KEY+uuid, NOTIFICATIONS_KEY, isEnabled);
}
public CompletableFuture<Boolean> updateNotificationsToken(String token) {
return this.db.updateField(USERS_COLLECTION_KEY+uuid, NOTIFICATIONS_TOKEN_KEY, token);
}
public CompletableFuture<Boolean> saveUserToDB(){
return this.db.setDocument(USERS_COLLECTION_KEY + uuid, this);
}
public CompletableFuture<User> loadUserFromDB(){
CompletableFuture<User> futureUser = this.db.getDocument(USERS_COLLECTION_KEY + uuid, User.class);
return futureUser.thenApply(response -> {
this.username = response.getUsername();
this.email = response.getEmail();
this.fullName = response.getFullName();
this.friendsIds = new ArrayList<>(response.getFriendsIds());
this.ownedGroupsIds = new ArrayList<>(response.getOwnedGroupsIds());
this.participatingGroupsIds = new ArrayList<>(response.getParticipatingGroupsIds());
this.savedEventsIds = new ArrayList<>(response.getSavedEventsIds());
this.birthDate = response.getBirthDate();
this.notifications = response.getNotifications();
this.location = response.getLocation();
return this;
}).exceptionally(exception -> {
// TODO : handle exception
return null;
});
}
public CompletableFuture<List<User>> getAllUsersLike(String username){
return this.db.withFieldContaining(USERS_COLLECTION_KEY, FULL_NAME_KEY, username, User.class); // TODO : change to username when possible
}
public CompletableFuture<Boolean> addSavedEvent(Event event){
if(this.savedEventsIds.add(event.getUuid().toString())){
return this.db.updateArrayField(USERS_COLLECTION_KEY + uuid, SAVED_EVENTS_KEY, event.getUuid().toString());
}
return CompletableFuture.completedFuture(false);
}
public CompletableFuture<Boolean> addOwnedGroup(Group group){
if(this.ownedGroupsIds.contains(group.getUuid())){
return CompletableFuture.completedFuture(true);
}
if(this.ownedGroupsIds.add(group.getUuid().toString())){
return this.db.updateArrayField(USERS_COLLECTION_KEY + uuid, OWNED_GROUPS_KEY, group.getUuid().toString())
.thenCompose(task -> addParticipatingGroup(group));
}
return CompletableFuture.completedFuture(false);
}
public CompletableFuture<Boolean> addParticipatingGroup(Group group){
if(this.participatingGroupsIds.contains(group.getUuid())){
return CompletableFuture.completedFuture(true);
}
if(this.participatingGroupsIds.add(group.getUuid().toString())){
return this.db.updateArrayField(USERS_COLLECTION_KEY + uuid, PARTICIPATING_GROUPS_KEY, group.getUuid().toString());
}
return CompletableFuture.completedFuture(false);
}
public CompletableFuture<List<Group>> getOwnedGroups(){
if(this.ownedGroupsIds.isEmpty()){
return CompletableFuture.completedFuture(new ArrayList<>());
}
return this.db.whereIn(GROUPS_COLLECTION_KEY, UUID_KEY, this.ownedGroupsIds, Group.class);
}
public CompletableFuture<List<Group>> getParticipatingGroups(){
if(this.participatingGroupsIds.isEmpty()){
return CompletableFuture.completedFuture(new ArrayList<>());
}
return this.db.whereIn(GROUPS_COLLECTION_KEY, UUID_KEY, this.ownedGroupsIds, Group.class);
}
public CompletableFuture<List<Event>> getSavedEvents(){
if(this.savedEventsIds.isEmpty()){
return CompletableFuture.completedFuture(new ArrayList<>());
}
return this.db.whereIn(EVENTS_COLLECTION_KEY, UUID_KEY, savedEventsIds, Event.class);
}
//TODO : for now it can store both type of events but won't be the case in the future
public CompletableFuture<Boolean> createGroup(Group group){
if(!group.getOwnerId().equals(this.uuid)){
return CompletableFuture.completedFuture(false);
}
return group.store(this.db)
.thenCompose(task -> this.addOwnedGroup(group))
.exceptionally(exception -> false); // TODO: handle exception
}
public CompletableFuture<Boolean> createEvent(Event event){
return event.store(this.db)
.exceptionally(exception -> false); // TODO: handle exception
}
public void signOut() {
CurrentUserModule.signOut();
}
public CompletableFuture<Boolean> changeEmail(FirebaseAuthentication auth, String email){
return auth.changeEmail(email);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(uuid, user.uuid) && Objects.equals(email, user.email);
}
@Override
public int hashCode() {
return Objects.hash(uuid);
}
}