/*
This file is part of OpenMyEWB.
OpenMyEWB is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenMyEWB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMyEWB. If not, see <http://www.gnu.org/licenses/>.
OpenMyEWB is Copyright 2005-2009 Nicolas Kruchten (nicolas@kruchten.com), Francis Kung, Engineers Without Borders Canada, Michael Trauttmansdorff, Jon Fishbein, David Kadish
*/
package ca.myewb.logic;
import java.io.File;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.Restrictions;
import ca.myewb.beans.Post;
import ca.myewb.beans.User;
import ca.myewb.frame.BCrypt;
import ca.myewb.frame.Helpers;
import ca.myewb.frame.HibernateUtil;
import ca.myewb.frame.SafeHibList;
import ca.myewb.model.GroupChapterModel;
import ca.myewb.model.GroupModel;
import ca.myewb.model.PostModel;
import ca.myewb.model.RoleModel;
import ca.myewb.model.UserModel;
public abstract class UserLogic extends User
{
protected ThreadLocal<Boolean> adminCache = new ThreadLocal<Boolean>();
public UserLogic() throws Exception
{
super();
}
public static String[] companySizes = { "", "1-5 employees",
"6-20 employees", "20-100 employees", "100+ employees" };
public static String[] incomeLevels = { "", "< $30k/year",
"$30k/year - $45k/year", "$45k/year - $75k/year", "> $75k/year" };
public static String[] studentLevels = { "", "High school",
"College/Undergraduate", "Graduate", "Other" };
public static String[] gradMonths = { "January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
"November", "December" };
public String getProcompsizeString()
{
try
{
return companySizes[procompsize];
}
catch (ArrayIndexOutOfBoundsException e)
{
log.warn("procompsize out of range for user=" + username
+ " with procompsize=" + procompsize, e);
return "";
}
}
public String getProincomelevelString()
{
try
{
return incomeLevels[proincomelevel];
}
catch (ArrayIndexOutOfBoundsException e)
{
log.warn("proincomelevel out of range for user=" + username
+ " with proincomelevel=" + proincomelevel, e);
return "";
}
}
public String getStudentlevelString()
{
try
{
return studentLevels[studentlevel];
}
catch (ArrayIndexOutOfBoundsException e)
{
log.warn("studentlevel out of range for user=" + username
+ " with studentlevel=" + studentlevel, e);
return "";
}
}
public String getStudentgradmonthString()
{
try
{
return gradMonths[studentgradmonth - 1];
}
catch (ArrayIndexOutOfBoundsException e)
{
log.warn("studentgradmonth out of range for user=" + username
+ " with studentgradmonth=" + studentgradmonth, e);
return "";
}
}
public String getAddress()
{
if(address1 == null)
return null;
return address1 + "\n" + suite + "\n" + address2 + "\n"
+ city + "\n" + province + "\n" + postalcode + "\n" + country;
}
public void setAddress(String address)
{
if (address == null)
{
setAddress1(null);
setSuite(null);
setAddress2(null);
setCity(null);
setProvince(null);
setPostalcode(null);
setCountry(null);
}
else
{
String[] splitAddress = address.split("\n");
setAddress1( (splitAddress.length > 0 && splitAddress[0] != null) ? splitAddress[0] : "");
setSuite( (splitAddress.length > 1 && splitAddress[1] != null) ? splitAddress[1] : "");
setAddress2( (splitAddress.length > 2 && splitAddress[2] != null) ? splitAddress[2] : "");
setCity( (splitAddress.length > 3 && splitAddress[3] != null) ? splitAddress[3] : "");
setProvince( (splitAddress.length > 4 && splitAddress[4] != null) ? splitAddress[4] : "");
setPostalcode( (splitAddress.length > 5 && splitAddress[5] != null) ? splitAddress[5] : "");
setCountry( (splitAddress.length > 6 && splitAddress[6] != null) ? splitAddress[6] : "");
}
setAddressUpdated(new Date());
}
public String getGenderString()
{
if (gender == 0)
{
return "";
}
else if (gender == 'f')
{
return "Female";
}
else if (gender == 'm')
{
return "Male";
}
log.warn("non-0, non-m, non-f gender value!");
return new String(gender + "");
}
public String getStudentString()
{
if (student == 0)
{
return "";
}
else if (student == 'y')
{
return "Student";
}
else if (student == 'n')
{
return "Non-student";
}
log.warn("non-0, non-n, non-y student value!");
return new String(student + "");
}
public List<GroupModel> getGroups() throws HibernateException
{
return (new SafeHibList<GroupModel>(session.createQuery(
"select r.group from RoleModel as r where r.user=? AND r.end IS NULL")
.setEntity(0, this))).list();
}
public List<GroupModel> getGroups(char lvl) throws HibernateException
{
return (new SafeHibList<GroupModel>(session.createQuery(
"select r.group from RoleModel as r where r.user=? AND r.end IS NULL AND r.level=? order by r.group.id asc")
.setEntity(0, this).setCharacter(1, lvl))).list();
}
public boolean checkPassword(String password) throws Exception
{
return BCrypt.checkpw(password, passhash);
}
public void setPassword(String password) throws Exception
{
passhash = BCrypt.hashpw(password, BCrypt.gensalt());
}
private boolean checkRole(GroupLogic g, char c, boolean override)
throws HibernateException
{
if(override && isAdmin())
{
return true;
}
int countRoles = ((Long)session.createQuery(
"SELECT count(*) from RoleModel as r WHERE r.user=? AND r.group.id=? AND r.level=? AND r.end IS NULL")
.setEntity(0, this).setInteger(1, g.getId()).setCharacter(2, c).uniqueResult()).intValue();
return countRoles != 0;
}
private boolean checkRoleInAdminGroup(String shortname, char c, boolean override)
throws HibernateException
{
if(override && isAdmin())
{
return true;
}
int countRoles = ((Long)session.createQuery(
"SELECT count(*) from RoleModel as r WHERE r.user=? AND r.group.shortname=? AND r.group.admin=true AND r.level=? AND r.end IS NULL")
.setEntity(0, this).setString(1, shortname).setCharacter(2, c).uniqueResult()).intValue();
return countRoles != 0;
}
//role-checkers, string, override
public boolean isLeader(String s, boolean override)
throws HibernateException
{
return checkRoleInAdminGroup(s, 'l', override);
}
public boolean isSender(String s, boolean override)
throws HibernateException
{
return checkRoleInAdminGroup(s, 's', override);
}
public boolean isMember(String s, boolean override)
throws HibernateException
{
return checkRoleInAdminGroup(s, 'm', override);
}
public boolean isRecipient(String s, boolean override)
throws HibernateException
{
return checkRoleInAdminGroup(s, 'r', override);
}
//role-checkers, string, no override
public boolean isLeader(String s) throws HibernateException
{
return isLeader(s, true);
}
public boolean isSender(String s) throws HibernateException
{
return isSender(s, true);
}
public boolean isMember(String s) throws HibernateException
{
return isMember(s, true);
}
public boolean isRecipient(String s) throws HibernateException
{
return isRecipient(s, true);
}
//role-checkers, group, override
public boolean isLeader(GroupLogic g, boolean override)
throws HibernateException
{
return checkRole(g, 'l', override);
}
public boolean isSender(GroupLogic g, boolean override)
throws HibernateException
{
return checkRole(g, 's', override);
}
public boolean isMember(GroupLogic g, boolean override)
throws HibernateException
{
return checkRole(g, 'm', override);
}
public boolean isRecipient(GroupLogic g, boolean override)
throws HibernateException
{
return checkRole(g, 'r', override);
}
//role-checkers, group, no override
public boolean isLeader(GroupLogic g) throws HibernateException
{
return isLeader(g, true);
}
public boolean isSender(GroupLogic g) throws HibernateException
{
return isSender(g, true);
}
public boolean isMember(GroupLogic g) throws HibernateException
{
return isMember(g, true);
}
public boolean isRecipient(GroupLogic g) throws HibernateException
{
return isRecipient(g, true);
}
public boolean addGroup(GroupLogic g, char level) throws Exception
{
return addGroup(g, level, new Date());
}
public boolean addGroup(GroupLogic g, char lvl, Date start) throws Exception
{
if (!checkRole(g, lvl, false))
{
RoleModel role = new RoleModel(lvl, start);
roles.add(role);
role.setUser(this);
g.addRole(role);
session.save(role);
log.debug("Granted " + g.getName() + " (" + lvl + ") access to "
+ getUsername());
return true;
}
else
{
log.debug(getUsername() + " is already a " + lvl + " member of "
+ g.getName());
return false;
}
}
public boolean remGroup(GroupLogic g) throws Exception
{
return remGroup(g, null);
}
public boolean remGroup(GroupLogic g, Character level)
throws HibernateException, Exception
{
return remGroup(g, level, new Date());
}
public boolean remGroup(GroupLogic g, Character lvl, Date end)
throws HibernateException, Exception
{
List r;
if (lvl != null)
{
r = session.createQuery(
"FROM RoleModel r WHERE r.user=? AND r.group.id=? AND r.level=? AND r.end IS NULL")
.setEntity(0, this).setInteger(1, g.getId()).setCharacter(2, lvl.charValue()).list();
}
else
{
r = session.createQuery(
"FROM RoleModel r WHERE r.user=? AND r.group.id=? AND r.end IS NULL")
.setEntity(0, this).setInteger(1, g.getId()).list();
}
if (!r.isEmpty())
{
Iterator it = r.iterator();
while (it.hasNext())
{
RoleModel role = (RoleModel) it.next();
role.end(end);
log.debug("Removed " + g.getName() + " (" + lvl + ") access from " + getUsername());
}
return true;
}
else
{
log.debug(getUsername() + " is not a " + lvl + " member of " + g.getName());
return false;
}
}
public GroupChapterModel getChapter() throws HibernateException
{
return (GroupChapterModel) session.createQuery(
"SELECT g FROM GroupChapterModel g, RoleModel r "
+ "WHERE r.group.id=g.id AND r.user=? AND r.level='m' AND r.end IS NULL")
.setEntity(0, this).uniqueResult();
}
public boolean isAdmin() throws HibernateException
{
if(adminCache.get() == null)
{
//LOOK hardcoded admin and nmt groupid's here for performance
adminCache.set((!session.createQuery(
"FROM RoleModel r WHERE r.user=? AND (r.group.shortname='Admin' OR r.group.shortname='NMT') AND r.end IS NULL")
.setEntity(0, this).list().isEmpty()));
}
return adminCache.get();
}
public boolean isPresident()
{
return isMember("UniPresidents") || isMember("ProPresidents");
}
public void addPost(PostLogic p)
{
posts.add((PostModel) p);
p.setPoster(this);
}
public void remPost(PostLogic p)
{
posts.remove(p);
}
public boolean isLastAdmin()
{
if (!isAdmin())
{
return false;
}
int size = session
.createQuery(
"select r from RoleModel as r where r.group=? AND r.end IS NULL")
.setEntity(0, Helpers.getGroup("Admin")).list().size();
log.debug("remaining admins: " + size);
return (size == 1);
}
public boolean isLastExec()
{
if (getChapter() == null)
{
return false;
}
if (!isMember("Exec", false))
{
return false;
}
int size = session
.createQuery(
"select r from RoleModel as r where r.group=? and r.level='l' AND r.end IS NULL")
.setEntity(0, this.getChapter()).list().size();
log.debug("remaining execs: " + size);
return (size == 1);
}
public boolean canRenew()
{
if (expiry == null)
{
return false;
}
Calendar cal = Calendar.getInstance();
cal.setTime(expiry);
cal.add(Calendar.DAY_OF_YEAR, -35);
return Calendar.getInstance().after(cal);
}
public String getUniqueToken() throws NoSuchAlgorithmException
{
// this is a re-usable unique token for a given user
// we can use it as an emailable one-shot password, eg to unsub without
// logging in
// bonus: it's parsable in PHP so it's easy to pass data in/out through
// URLs
// reasoning for this hash:
// username is immutable, but is null for many users
// id is immutable, but might be visible at some point
// passhash is assumed to be hidden, but is null for many users
// email is assumed to be fairly hidden from most users
// taken together, I think it's hard to guess the correct combo for any
// given user
// even if it were, it would be a mailing list user (passhash)
String key = username + "salt" + id + "pepper" + passhash + "sugar"
+ email;
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(key.getBytes());
byte[] v = md.digest();
// Thank you
// http://forum.java.sun.com/thread.jspa?threadID=429739&messageID=1921162
String HEX_DIGITS = "0123456789abcdef";
StringBuffer sb = new StringBuffer(v.length * 2);
for (int i = 0; i < v.length; i++)
{
int b = v[i] & 0xFF;
sb.append(HEX_DIGITS.charAt(b >>> 4)).append(
HEX_DIGITS.charAt(b & 0xF));
}
key = sb.toString();
return key;
}
public Date getAccountCreationDate()
{
Criteria criteria = session.createCriteria(RoleModel.class);
criteria.add(Restrictions.eq("user", this));
criteria.add(Restrictions.eq("group", Helpers.getGroup("Org")));
criteria.add(Restrictions.isNull("end"));
Iterator it = criteria.list().iterator();
if (it.hasNext())
{
return ((RoleModel) it.next()).getStart();
}
else
{
return null;
}
}
public String getNatlRepTitle() throws HibernateException
{
// returns "" if this user isn't currently an exec
// otherwise, it returns the title field of the currently unended exec
// role
GroupModel natlRep = Helpers.getGroup("NatlRep");
List execRole = session
.createQuery(
"select r from RoleModel as r where r.user=? AND r.end IS NULL AND r.level=? and r.group=?")
.setEntity(0, this).setCharacter(1, 'm').setEntity(2,
natlRep).list();
if (execRole.isEmpty())
{
return "";
}
return ((RoleModel) execRole.get(0)).getTitle();
}
public String getExecTitle() throws HibernateException
{
// returns "" if this user isn't currently an exec
// otherwise, it returns the title field of the currently unended exec
// role
GroupChapterModel theChapter = getChapter();
if (theChapter == null)
{
return "";
}
List execRole = session
.createQuery(
"select r from RoleModel as r where r.user=? AND r.end IS NULL AND r.level=? and r.group=?")
.setEntity(0, this).setCharacter(1, 'l').setEntity(2,
theChapter).list();
if (execRole.isEmpty())
{
return "";
}
return ((RoleModel) execRole.get(0)).getTitle();
}
public String getNMTTitle() throws HibernateException
{
if (isMember("NMT", false))
{
List nmtRole = session
.createQuery(
"select r from RoleModel as r where r.user=? AND r.end IS NULL and r.group=?")
.setEntity(0, this).setEntity(1, Helpers.getGroup("NMT"))
.list();
return ((RoleModel) nmtRole.get(0)).getTitle();
}
else if (isMember("Admin", false))
{
return "Admin User";
}
else
{
return "";
}
}
public void setNatlRepTitle(String title) throws HibernateException
{
// does nothing if the user isn't currently an exec
// otherwise, it sets the title field of the currently unended exec role
List execRole = session
.createQuery(
"select r from RoleModel as r where r.user=? AND r.end IS NULL AND r.level=? and r.group=?")
.setEntity(0, this).setCharacter(1, 'm').setEntity(2,
Helpers.getGroup("NatlRep")).list();
if (execRole.isEmpty())
{
return;
}
((RoleModel) execRole.get(0)).setTitle(title);
}
public void setExecTitle(String title) throws HibernateException
{
// does nothing if the user isn't currently an exec
// otherwise, it sets the title field of the currently unended exec role
List execRole = session
.createQuery(
"select r from RoleModel as r where r.user=? AND r.end IS NULL AND r.level=? and r.group=?")
.setEntity(0, this).setCharacter(1, 'l').setEntity(2,
getChapter()).list();
if (execRole.isEmpty())
{
return;
}
((RoleModel) execRole.get(0)).setTitle(title);
}
public void setNMTTitle(String title) throws HibernateException
{
// does nothing if the user isn't currently an nmt
// otherwise, it sets the title field of the currently unended nmt role
List nmtRole = session
.createQuery(
"select r from RoleModel as r where r.user=? AND r.end IS NULL and r.group=?")
.setEntity(0, this).setEntity(1, Helpers.getGroup("NMT")).list();
if (nmtRole.isEmpty())
{
return;
}
((RoleModel) nmtRole.get(0)).setTitle(title);
}
public boolean hasPicture()
{
return (new File(Helpers.getUserFilesDir() + "/userpics/thumbs/" + id
+ ".jpg")).exists();
}
public String getFormattedEmailList()
{
StringBuffer emails = new StringBuffer();
for (Iterator<String> it = getEmails().iterator(); it.hasNext();)
{
String email = it.next();
if (!email.equals(getEmail()))
{
emails.append(email);
if (it.hasNext())
{
emails.append("\n");
}
}
}
return emails.toString();
}
public static UserModel getUserForEmail(String email)
{
List result = HibernateUtil.currentSession().createQuery(
"FROM UserModel u WHERE :email in elements(u.emails)")
.setString("email", email).list();
if (result.isEmpty())
{
return null;
}
if(result.size() > 1)
{
Logger.getLogger(UserModel.class).error("2 users with email address " + email);
}
return (UserModel) result.get(0);
}
public void flagPost(PostModel p)
{
getFlaggedPosts().add(p);
HibernateUtil.currentSession().flush();
if(p.getFlaggedByUsers().size() == Post.FlagsToFeature)
{
p.feature();
}
}
public void unflagPost(PostModel p)
{
getFlaggedPosts().remove(p);
}
public boolean hasFlagged(PostModel p)
{
return getFlaggedPosts().contains(p);
}
}