package com.zulip.android.models; import com.google.gson.annotations.SerializedName; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.RuntimeExceptionDao; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.table.DatabaseTable; import com.zulip.android.ZulipApp; import com.zulip.android.util.ZLog; import org.apache.commons.lang.builder.HashCodeBuilder; import java.sql.SQLException; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @DatabaseTable(tableName = "people") public class Person { public static final String NAME_FIELD = "name"; public static final String MESSAGESPARTICIPATEDIN_FIELD = "messagesParticipatedIn"; public static final String EMAIL_FIELD = "email"; public static final String ISBOT_FIELD = "isBot"; public static final String ISACTIVE_FIELD = "isActive"; private static final String ID_FIELD = "id"; private static final String AVATARURL_FIELD = "avatarUrl"; @SerializedName("user_id") @DatabaseField(columnName = ID_FIELD, id = true) protected int id; @SerializedName("full_name") @DatabaseField(columnName = NAME_FIELD) private String name; @SerializedName("email") @DatabaseField(columnName = EMAIL_FIELD, uniqueIndex = true) private String email; @DatabaseField(columnName = AVATARURL_FIELD) private String avatarURL; @SerializedName("is_bot") @DatabaseField(columnName = ISBOT_FIELD) private boolean isBot; @DatabaseField(columnName = ISACTIVE_FIELD) private boolean isActive; @SerializedName("is_admin") private boolean isAdmin; @SerializedName("domain") private String domain; @SerializedName("short_name") private String shortName; @SerializedName("is_mirror_dummy") private boolean isMirrorDummy; /** * used to get person id in case of {@link Message.ZulipDirectMessage} */ @SerializedName("id") private int recipientId; public Person(String name, String email) { this.setName(name); this.setEmail(email); } public Person(String name, String email, String avatarURL) { this(name, email); this.setAvatarURL(avatarURL); this.isActive = false; } public Person(int id, String name, String email, String avatarURL, boolean isBot, boolean isActive) { this.setId(id); this.setName(name); this.setEmail(email); this.setAvatarURL(avatarURL); this.setActive(isActive); this.setBot(isBot); } /** * Construct an empty Person object. */ public Person() { } public static Person getByEmail(ZulipApp app, String email) { try { return getByEmail(app.getDatabaseHelper().getDao( Person.class), email); } catch (SQLException e) { ZLog.logException(e); } return null; } @SuppressWarnings("WeakerAccess") public static Person getByEmail(Dao<Person, ?> dao, String email) { try { return dao.queryBuilder().where() .eq(Person.EMAIL_FIELD, new SelectArg(email)) .queryForFirst(); } catch (SQLException e) { throw new RuntimeException(e); } } @SuppressWarnings("WeakerAccess") /** * Returns person object {@link Person} from the database if exists or newly created object using * the passed parameters. * Note: always call this method with valid Person id {@link Person#id} passed as argument. * * @param app Zulip god object {@link ZulipApp} * @param email person email {@link Person#email} * @param name person name {@link Person#name} * @param avatarURL person avatar url {@link Person#avatarURL} * @param personId person id {@link Person#id} * @param personCache person cache used ofr faster fetching of results * @return {@link Person} object */ public static Person getOrUpdate(ZulipApp app, String email, String name, String avatarURL, int personId, Map<String, Person> personCache) { Person person = null; if (personCache != null) { person = personCache.get(email); } if (person == null) { person = getByEmail(app, email); if (personCache != null) { personCache.put(email, person); } } if (person == null) { person = new Person(name, email, avatarURL); // use the person id passed to generate person skeleton object which is consistent // with server id. person.setId(personId); person.setActive(true); app.getDao(Person.class).createOrUpdate(person); } else { boolean changed = false; if (name != null && !name.equals(person.name)) { person.name = name; changed = true; } if (avatarURL != null && !avatarURL.equals(person.avatarURL)) { person.avatarURL = avatarURL; changed = true; } if (changed) { person.setActive(true); app.getDao(Person.class).update(person); } } return person; } /** * This function is called from setEmail {@link ZulipApp#setEmail(String)}. * It is used to get current user person {@link Person} object if it exists in the database * or create a new object using {@param email}. * * @param app {@link ZulipApp} * @param email Person email id {@link Person#email} * @return {@link Person} object */ public static Person get(ZulipApp app, String email) { Person foundPerson = getByEmail(app, email); if (foundPerson == null) { // fake it till you make it return new Person(null, email); } return foundPerson; } /** * This function is used to call {@link Person#getOrUpdate(ZulipApp, String, String, String, int, Map)} * with no cache. * Note: always call this method with valid Person id {@link Person#id} passed as argument. * * @param app Zulip god object {@link ZulipApp} * @param email person email {@link Person#email} * @param name person name {@link Person#name} * @param avatarURL person avatar url {@link Person#avatarURL} * @param personId person id {@link Person#id} * @return {@link Person} object */ public static Person getOrUpdate(ZulipApp app, String email, String name, String avatarURL, int personId) { return getOrUpdate(app, email, name, avatarURL, personId, null); } public static Person getById(ZulipApp app, int id) { RuntimeExceptionDao<Person, Object> dao = app.getDao(Person.class); return dao.queryForId(id); } public static List<Person> getAllPeople(ZulipApp app) throws SQLException { RuntimeExceptionDao<Person, Object> dao = app.getDao(Person.class); return dao.queryBuilder().where().eq(Person.ISBOT_FIELD, false).query(); } public static void sortByPresence(ZulipApp app, List<Person> people) { final Map<String, Presence> presenceCopy = new HashMap<>( app.presences); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person a, Person b) { Presence aPresence = presenceCopy.get(a.getEmail()); Presence bPresence = presenceCopy.get(b.getEmail()); final int inactiveTimeout = 2 * 60; if (aPresence == null && bPresence == null) { return a.getName().toLowerCase(Locale.US) .compareTo(b.getName().toLowerCase(Locale.US)); } else if (aPresence == null) { return 1; } else if (bPresence == null) { return -1; } else if (aPresence.getAge() > inactiveTimeout && bPresence.getAge() > inactiveTimeout) { return a.getName().toLowerCase(Locale.US) .compareTo(b.getName().toLowerCase(Locale.US)); } else if (aPresence.getAge() > inactiveTimeout) { return 1; } else if (bPresence.getAge() > inactiveTimeout) { return -1; } else if (aPresence.getStatus() == bPresence.getStatus()) { return a.getName().toLowerCase(Locale.US) .compareTo(b.getName().toLowerCase(Locale.US)); } else if (aPresence.getStatus() == PresenceType.ACTIVE) { return -1; } else { return 1; } } }); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } private void setName(String name) { this.name = name; } public String getEmail() { return email; } private void setEmail(String email) { if (email != null) { this.email = email.toLowerCase(Locale.US); } } public boolean getIsBot() { return isBot; } public String getAvatarURL() { return avatarURL; } private void setAvatarURL(String avatarURL) { this.avatarURL = avatarURL; } /** * Calculate the Humbug realm for the person, currently by splitting the * email address. * <p/> * In the future, realms may be distinct from your email hostname. * * @return the Person's realm. */ public String getRealm() { String[] splitEmail = this.getEmail().split("@"); return splitEmail[splitEmail.length - 1]; } public boolean equals(Object obj) { if (obj == null) { return false; } if (obj == this) { return true; } if (!(obj instanceof Person)) { return false; } Person per = (Person) obj; if (this.name == null || this.email == null) return false; return this.name.equals(per.getName()) && this.email.equals(per .getEmail()); } public int hashCode() { return new HashCodeBuilder(17, 31).append(name).append(email) .toHashCode(); } @SuppressWarnings("WeakerAccess") public void setBot(boolean isBot) { this.isBot = isBot; } public void setActive(boolean active) { isActive = active; } public int getRecipientId() { return this.recipientId; } public void setRecipientId(int id) { this.recipientId = id; } }