/* * ConcourseConnect * Copyright 2009 Concursive Corporation * http://www.concursive.com * * This file is part of ConcourseConnect, an open source social business * software and community platform. * * Concursive ConcourseConnect is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, version 3 of the License. * * Under the terms of the GNU Affero General Public License you must release the * complete source code for any application that uses any part of ConcourseConnect * (system header files and libraries used by the operating system are excluded). * These terms must be included in any work that has ConcourseConnect components. * If you are developing and distributing open source applications under the * GNU Affero General Public License, then you are free to use ConcourseConnect * under the GNU Affero General Public License. * * If you are deploying a web site in which users interact with any portion of * ConcourseConnect over a network, the complete source code changes must be made * available. For example, include a link to the source archive directly from * your web site. * * For OEMs, ISVs, SIs and VARs who distribute ConcourseConnect with their * products, and do not license and distribute their source code under the GNU * Affero General Public License, Concursive provides a flexible commercial * license. * * To anyone in doubt, we recommend the commercial license. Our commercial license * is competitively priced and will eliminate any confusion about how * ConcourseConnect can be used and distributed. * * ConcourseConnect 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 Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License * along with ConcourseConnect. If not, see <http://www.gnu.org/licenses/>. * * Attribution Notice: ConcourseConnect is an Original Work of software created * by Concursive Corporation */ package com.concursive.connect.web.modules.members.dao; import com.concursive.commons.db.DatabaseUtils; import com.concursive.commons.web.mvc.beans.GenericBean; import com.concursive.connect.Constants; import com.concursive.connect.cache.utils.CacheUtils; import com.concursive.connect.web.modules.communications.utils.EmailUpdatesUtils; import com.concursive.connect.web.modules.login.dao.User; import com.concursive.connect.web.modules.login.utils.UserUtils; import com.concursive.connect.web.modules.profile.dao.Project; import com.concursive.connect.web.modules.profile.utils.ProjectUtils; import com.concursive.connect.web.utils.LookupList; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.DateFormat; /** * Represents a member of a project * * @author matt rajkowski * @version $Id$ * @created July 23, 2001 */ public class TeamMember extends GenericBean { // NOTE: Constants that control permissions within a project are driven by // the database, however some point-level solutions have been defined... // PROJECT_ADMIN = Total access to the project public final static int PROJECT_ADMIN = 10; // MANAGER = Assumed to have a lot of control similar to admin public final static int MANAGER = 14; // CHAMPION = Granted permission to create project structures public final static int CHAMPION = 17; // VIP = Acknowledged by project owners public final static int VIP = 20; // MEMBER = Status when a user self joins a project, when allowed public final static int MEMBER = 25; // PARTICIPANT = Logged in and auto-promoted by project public final static int PARTICIPANT = 30; // Permission used when user is either not logged in or not promoted by project public final static int GUEST = 100; //Constants that control invitations public final static int STATUS_ADDED = -1; public final static int STATUS_INVITING = 1; public final static int STATUS_MAILERROR = 2; public final static int STATUS_PENDING = 3; public final static int STATUS_REFUSED = 4; public final static int STATUS_JOINED_NEEDS_APPROVAL = 6; //Scheduled Email Updates public final static int EMAIL_NEVER = 0; public final static int EMAIL_OFTEN = 1; public final static int EMAIL_DAILY = 2; public final static int EMAIL_WEEKLY = 3; public final static int EMAIL_MONTHLY = 4; private Object contact = null; private User user = null; // Team Member Properties private int id = -1; private int projectId = -1; private int userId = -1; private int userLevel = -1; private java.sql.Timestamp entered = null; private int enteredBy = -1; private java.sql.Timestamp modified = null; private int modifiedBy = -1; private int roleId = -1; private int status = STATUS_ADDED; private java.sql.Timestamp lastAccessed = null; private boolean tools = false; // Other factors private boolean temporaryAdmin = false; private boolean notification = false; private String customInvitationMessage = null; private int emailUpdatesSchedule = EMAIL_NEVER; /** * Constructor for the Assignment object */ public TeamMember() { } /** * Constructor for the TeamMember object * * @param rs Description of the Parameter * @throws SQLException Description of the Exception */ public TeamMember(ResultSet rs) throws SQLException { buildRecord(rs); } /** * Constructor for the TeamMember object * * @param db Description of the Parameter * @param teamMemberId Description of the Parameter * @throws SQLException Description of the Exception */ public TeamMember(Connection db, int teamMemberId) throws SQLException { PreparedStatement pst = db.prepareStatement( "SELECT t.team_id, t.project_id, t.user_id, t.userlevel, t.entered, t.enteredby, " + "t.modified, t.modifiedby, t.status, t.last_accessed, " + "t.tools, t.notification, t.email_updates_schedule, " + "r.level " + "FROM project_team t, lookup_project_role r " + "WHERE t.userlevel = r.code " + "AND t.team_id = ?"); pst.setInt(1, teamMemberId); ResultSet rs = pst.executeQuery(); if (rs.next()) { buildRecord(rs); } else { rs.close(); pst.close(); throw new SQLException("Member record not found."); } rs.close(); pst.close(); } /** * This method is typically used to see if a user is member of a specific * project. * * @param db Description of the Parameter * @param projectId Description of the Parameter * @param userId Description of the Parameter * @throws SQLException Description of the Exception */ public TeamMember(Connection db, int projectId, int userId) throws SQLException { PreparedStatement pst = db.prepareStatement( "SELECT t.team_id, t.project_id, t.user_id, t.userlevel, t.entered, t.enteredby, " + "t.modified, t.modifiedby, t.status, t.last_accessed, " + "t.tools, t.notification, t.email_updates_schedule, " + "r.level " + "FROM project_team t, lookup_project_role r " + "WHERE t.userlevel = r.code " + "AND t.project_id = ? " + "AND t.user_id = ? "); pst.setInt(1, projectId); pst.setInt(2, userId); ResultSet rs = pst.executeQuery(); if (rs.next()) { buildRecord(rs); } else { rs.close(); pst.close(); throw new SQLException("Member record not found."); } rs.close(); pst.close(); } /** * Description of the Method * * @param rs Description of the Parameter * @throws SQLException Description of the Exception */ private void buildRecord(ResultSet rs) throws SQLException { // project_team id = rs.getInt("team_id"); projectId = rs.getInt("project_id"); userId = rs.getInt("user_id"); userLevel = DatabaseUtils.getInt(rs, "userlevel"); entered = rs.getTimestamp("entered"); enteredBy = rs.getInt("enteredby"); modified = rs.getTimestamp("modified"); modifiedBy = rs.getInt("modifiedby"); status = DatabaseUtils.getInt(rs, "status"); lastAccessed = rs.getTimestamp("last_accessed"); tools = rs.getBoolean("tools"); notification = rs.getBoolean("notification"); emailUpdatesSchedule = DatabaseUtils.getInt(rs, "email_updates_schedule"); // lookup_project_role roleId = rs.getInt("level"); } /** * Sets the contact attribute of the TeamMember object * * @param tmp The new contact value */ public void setContact(Object tmp) { this.contact = tmp; } /** * Sets the user attribute of the TeamMember object * * @param tmp The new user value */ public void setUser(User tmp) { this.user = tmp; } public int getId() { return id; } public void setId(int id) { this.id = id; } public void setId(String id) { this.id = Integer.parseInt(id); } /** * Sets the projectId attribute of the TeamMember object * * @param tmp The new projectId value */ public void setProjectId(int tmp) { this.projectId = tmp; } /** * Sets the projectId attribute of the TeamMember object * * @param tmp The new projectId value */ public void setProjectId(String tmp) { this.projectId = Integer.parseInt(tmp); } /** * Sets the userId attribute of the TeamMember object * * @param tmp The new userId value */ public void setUserId(int tmp) { this.userId = tmp; } /** * Sets the userId attribute of the TeamMember object * * @param tmp The new userId value */ public void setUserId(String tmp) { this.userId = Integer.parseInt(tmp); } /** * Sets the userLevel attribute of the TeamMember object * * @param tmp The new userLevel value */ public void setUserLevel(int tmp) { this.userLevel = tmp; } /** * Sets the userLevel attribute of the TeamMember object * * @param tmp The new userLevel value */ public void setUserLevel(String tmp) { this.userLevel = Integer.parseInt(tmp); } /** * Sets the entered attribute of the TeamMember object * * @param tmp The new entered value */ public void setEntered(java.sql.Timestamp tmp) { this.entered = tmp; } /** * Sets the entered attribute of the TeamMember object * * @param tmp The new entered value */ public void setEntered(String tmp) { this.entered = DatabaseUtils.parseTimestamp(tmp); } /** * Sets the enteredBy attribute of the TeamMember object * * @param tmp The new enteredBy value */ public void setEnteredBy(int tmp) { this.enteredBy = tmp; } /** * Sets the enteredBy attribute of the TeamMember object * * @param tmp The new enteredBy value */ public void setEnteredBy(String tmp) { this.enteredBy = Integer.parseInt(tmp); } /** * Sets the modified attribute of the TeamMember object * * @param tmp The new modified value */ public void setModified(java.sql.Timestamp tmp) { this.modified = tmp; } /** * Sets the modified attribute of the TeamMember object * * @param tmp The new modified value */ public void setModified(String tmp) { this.modified = DatabaseUtils.parseTimestamp(tmp); } /** * Sets the modifiedBy attribute of the TeamMember object * * @param tmp The new modifiedBy value */ public void setModifiedBy(int tmp) { this.modifiedBy = tmp; } /** * Sets the modifiedBy attribute of the TeamMember object * * @param tmp The new modifiedBy value */ public void setModifiedBy(String tmp) { this.modifiedBy = Integer.parseInt(tmp); } /** * Sets the roleId attribute of the TeamMember object * * @param tmp The new roleId value */ public void setRoleId(int tmp) { this.roleId = tmp; } /** * Sets the roleId attribute of the TeamMember object * * @param tmp The new roleId value */ public void setRoleId(String tmp) { this.roleId = Integer.parseInt(tmp); } /** * Sets the status attribute of the TeamMember object * * @param tmp The new status value */ public void setStatus(int tmp) { this.status = tmp; } /** * Sets the status attribute of the TeamMember object * * @param tmp The new status value */ public void setStatus(String tmp) { this.status = Integer.parseInt(tmp); } public int getEmailUpdatesSchedule() { return emailUpdatesSchedule; } public void setEmailUpdatesSchedule(int emailUpdatesSchedule) { this.emailUpdatesSchedule = emailUpdatesSchedule; } public void setEmailUpdatesSchedule(String emailUpdatesSchedule) { this.emailUpdatesSchedule = Integer.parseInt(emailUpdatesSchedule); } /** * Sets the lastAccessed attribute of the TeamMember object * * @param tmp The new lastAccessed value */ public void setLastAccessed(java.sql.Timestamp tmp) { this.lastAccessed = tmp; } public void setLastAccessed(String tmp) { this.lastAccessed = DatabaseUtils.parseTimestamp(tmp); } /** * Gets the contact attribute of the TeamMember object * * @return The contact value */ public Object getContact() { return contact; } /** * Gets the user attribute of the TeamMember object * * @return The user value */ public User getUser() { if (user == null && userId > -1) { return UserUtils.loadUser(userId); } return user; } /** * Gets the projectId attribute of the TeamMember object * * @return The projectId value */ public int getProjectId() { return projectId; } /** * Gets the userId attribute of the TeamMember object * * @return The userId value */ public int getUserId() { return userId; } /** * Gets the userLevel attribute of the TeamMember object * * @return The userLevel value */ public int getUserLevel() { return userLevel; } /** * Gets the entered attribute of the TeamMember object * * @return The entered value */ public java.sql.Timestamp getEntered() { return entered; } /** * Gets the enteredString attribute of the TeamMember object * * @return The enteredString value */ public String getEnteredString() { try { return DateFormat.getDateInstance(3).format(entered); } catch (NullPointerException e) { } return ("--"); } /** * Gets the enteredBy attribute of the TeamMember object * * @return The enteredBy value */ public int getEnteredBy() { return enteredBy; } /** * Gets the modified attribute of the TeamMember object * * @return The modified value */ public java.sql.Timestamp getModified() { return modified; } /** * Gets the modifiedString attribute of the TeamMember object * * @return The modifiedString value */ public String getModifiedString() { try { return DateFormat.getDateInstance(3).format(modified); } catch (NullPointerException e) { } return ("--"); } /** * Gets the modifiedBy attribute of the TeamMember object * * @return The modifiedBy value */ public int getModifiedBy() { return modifiedBy; } /** * Gets the roleId attribute of the TeamMember object * * @return The roleId value */ public int getRoleId() { return roleId; } /** * Gets the status attribute of the TeamMember object * * @return The status value */ public int getStatus() { return status; } /** * Gets the lastAccessed attribute of the TeamMember object * * @return The lastAccessed value */ public java.sql.Timestamp getLastAccessed() { return lastAccessed; } /** * Gets the lastAccessedString attribute of the TeamMember object * * @return The lastAccessedString value */ public String getLastAccessedString() { try { return DateFormat.getDateInstance(3).format(lastAccessed); } catch (NullPointerException e) { } return ("--"); } public boolean isTemporaryAdmin() { return temporaryAdmin; } public void setTemporaryAdmin(boolean temporaryAdmin) { this.temporaryAdmin = temporaryAdmin; } public void setTemporaryAdmin(String tmp) { this.temporaryAdmin = DatabaseUtils.parseBoolean(tmp); } public boolean getNotification() { return notification; } public void setNotification(String tmp) { this.notification = DatabaseUtils.parseBoolean(tmp); } public void setNotification(boolean notification) { this.notification = notification; } public boolean getTools() { return tools; } public void setTools(boolean tools) { this.tools = tools; } public void setTools(String tmp) { this.tools = DatabaseUtils.parseBoolean(tmp); } /** * @return the customInvitationMessage */ public String getCustomInvitationMessage() { return customInvitationMessage; } /** * @param customInvitationMessage the customInvitationMessage to set */ public void setCustomInvitationMessage(String customInvitationMessage) { this.customInvitationMessage = customInvitationMessage; } /** * Description of the Method * * @param db Description of the Parameter * @return Description of the Return Value * @throws SQLException Description of the Exception */ public boolean insert(Connection db) throws SQLException { boolean commit = false; try { commit = db.getAutoCommit(); if (commit) { db.setAutoCommit(false); } StringBuffer sql = new StringBuffer(); sql.append("INSERT INTO project_team "); sql.append("(" + (id > -1 ? "team_id, " : "") + "project_id, user_id, userlevel, tools, "); if (entered != null) { sql.append("entered, "); } if (modified != null) { sql.append("modified, "); } if (lastAccessed != null) { sql.append("last_accessed, "); } sql.append("enteredby, modifiedby, status, notification, email_updates_schedule) "); sql.append("VALUES (?, ?, ?, ?, "); if (id > -1) { sql.append("?, "); } if (entered != null) { sql.append("?, "); } if (modified != null) { sql.append("?, "); } if (lastAccessed != null) { sql.append("?, "); } sql.append("?, ?, ?, ?, ?) "); PreparedStatement pst = db.prepareStatement(sql.toString()); int i = 0; if (id > -1) { pst.setInt(++i, id); } pst.setInt(++i, projectId); pst.setInt(++i, userId); DatabaseUtils.setInt(pst, ++i, userLevel); pst.setBoolean(++i, tools); if (entered != null) { pst.setTimestamp(++i, entered); } if (modified != null) { pst.setTimestamp(++i, modified); } if (lastAccessed != null) { pst.setTimestamp(++i, lastAccessed); } pst.setInt(++i, enteredBy); pst.setInt(++i, modifiedBy); DatabaseUtils.setInt(pst, ++i, status); pst.setBoolean(++i, notification); DatabaseUtils.setInt(pst, ++i, emailUpdatesSchedule); pst.execute(); pst.close(); id = DatabaseUtils.getCurrVal(db, "project_team_team_id_seq", id); //Update the scheduled emails queue EmailUpdatesUtils.saveQueue(db, this); if (commit) { db.commit(); } } catch (SQLException e) { if (commit) { db.rollback(); } throw new SQLException(e.getMessage()); } finally { if (commit) { db.setAutoCommit(true); } } CacheUtils.invalidateValue(Constants.SYSTEM_PROJECT_CACHE, projectId); return true; } /** * Description of the Method * * @param db Description of the Parameter * @return Description of the Return Value * @throws SQLException Description of the Exception */ public int update(Connection db) throws SQLException { StringBuffer sql = new StringBuffer(); sql.append("UPDATE project_team "); sql.append("SET modified = CURRENT_TIMESTAMP, "); if (lastAccessed != null) { sql.append("last_accessed = ?, "); } sql.append("modifiedby = ?, status = ?, userlevel = ?, tools = ?, notification = ?, email_updates_schedule = ? "); sql.append("WHERE team_id = ? AND modified = ? "); PreparedStatement pst = db.prepareStatement(sql.toString()); int i = 0; if (lastAccessed != null) { pst.setTimestamp(++i, lastAccessed); } pst.setInt(++i, modifiedBy); DatabaseUtils.setInt(pst, ++i, status); DatabaseUtils.setInt(pst, ++i, userLevel); pst.setBoolean(++i, tools); pst.setBoolean(++i, notification); DatabaseUtils.setInt(pst, ++i, emailUpdatesSchedule); pst.setInt(++i, id); pst.setTimestamp(++i, modified); int resultCount = pst.executeUpdate(); pst.close(); CacheUtils.invalidateValue(Constants.SYSTEM_PROJECT_CACHE, projectId); return resultCount; } /** * Deletes a user from a team * * @param db Database connection * @return true if any records were deleted, otherwise false * @throws SQLException Any database connection or statement error */ public boolean delete(Connection db) throws SQLException { int resultCount = 0; boolean commit = false; try { commit = db.getAutoCommit(); if (commit) { db.setAutoCommit(false); } int projectId = TeamMemberList.queryProjectIdOfTeamMemberId(db, id); PreparedStatement pst = db.prepareStatement( "DELETE FROM project_team " + "WHERE team_id = ? "); pst.setInt(1, id); resultCount = pst.executeUpdate(); pst.close(); //Manage the scheduled emails queue EmailUpdatesUtils.manageQueue(db, this); if (commit) { db.commit(); } CacheUtils.invalidateValue(Constants.SYSTEM_PROJECT_CACHE, projectId); } catch (SQLException e) { if (commit) { db.rollback(); } throw new SQLException(e.getMessage()); } finally { if (commit) { db.setAutoCommit(true); } } return (resultCount > 0); } /** * Description of the Method * * @param db The database connection used * @param project The project in which the change is being made * @param userIdMakingChange The user making the change * @param userId The target user being changed * @param newUserLevel The id of the role the target user is being changed to * @return True if the change occurred * @throws SQLException Description of the Exception */ public static boolean changeRole(Connection db, Project project, int userIdMakingChange, int userId, int newUserLevel) throws SQLException { // Prepare to enforce a few rules TeamMember memberMakingChange = project.getTeam().getTeamMember(userIdMakingChange); TeamMember memberBeingChanged = project.getTeam().getTeamMember(userId); LookupList roleList = CacheUtils.getLookupList("lookup_project_role"); int newRowLevel = roleList.getLevelFromId(newUserLevel); // Leverage the user's record whether on the team or not User thisUser = UserUtils.loadUser(userIdMakingChange); // Determine if the role can be changed if ((memberMakingChange != null && memberMakingChange.getUser() != null && memberMakingChange.getUser().getAccessAdmin()) || (thisUser != null && thisUser.getAccessAdmin())) { // This is an administrator and can make the change } else { // This is not an administrator so make sure the user is on the team and has // access to make the change if (memberMakingChange == null) { return false; } // A team member cannot make themself worse or better if (memberMakingChange.getUserId() == memberBeingChanged.getUserId()) { return false; } // The team member making the change cannot change the role of another member to something better than themself if (newRowLevel < memberMakingChange.getRoleId()) { return false; } // The team member cannot make a better team member, worse if (memberBeingChanged.getRoleId() < memberMakingChange.getRoleId()) { return false; } } // Now update the team PreparedStatement pst = db.prepareStatement( "UPDATE project_team " + "SET userlevel = ? " + "WHERE project_id = ? " + "AND user_id = ? "); pst.setInt(1, newUserLevel); pst.setInt(2, project.getId()); pst.setInt(3, userId); pst.executeUpdate(); pst.close(); CacheUtils.invalidateValue(Constants.SYSTEM_PROJECT_CACHE, project.getId()); return true; } /** * Description of the Method * * @param db Description of the Parameter * @throws SQLException Description of the Exception */ public void updateStatus(Connection db) throws SQLException { PreparedStatement pst = db.prepareStatement( "UPDATE project_team " + "SET status = ?, modified = " + DatabaseUtils.getCurrentTimestamp(db) + " " + "WHERE project_id = ? " + "AND user_id = ? "); DatabaseUtils.setInt(pst, 1, status); pst.setInt(2, projectId); pst.setInt(3, userId); pst.execute(); pst.close(); CacheUtils.invalidateValue(Constants.SYSTEM_PROJECT_CACHE, projectId); } public void updateTools(Connection db) throws SQLException { PreparedStatement pst = db.prepareStatement( "UPDATE project_team " + "SET tools = ?, modified = " + DatabaseUtils.getCurrentTimestamp(db) + " " + "WHERE project_id = ? " + "AND user_id = ? "); pst.setBoolean(1, tools); pst.setInt(2, projectId); pst.setInt(3, userId); pst.execute(); pst.close(); CacheUtils.invalidateValue(Constants.SYSTEM_PROJECT_CACHE, projectId); } /** * Description of the Method * * @param db Description of the Parameter * @param projectId Description of the Parameter * @param user Description of the Parameter * @throws SQLException Description of the Exception */ public static void updateLastAccessed(Connection db, int projectId, User user) throws SQLException { PreparedStatement pst = db.prepareStatement( "UPDATE project_team " + "SET last_accessed = " + DatabaseUtils.getCurrentTimestamp(db) + " " + "WHERE project_id = ? " + "AND user_id = ? "); pst.setInt(1, projectId); pst.setInt(2, user.getId()); pst.execute(); pst.close(); user.addRecentProject(projectId); } public static boolean handleMembershipRequest(Connection db, TeamMember teamMember, boolean approval, int userId) throws SQLException { boolean success = false; if (approval) { LookupList roleList = CacheUtils.getLookupList("lookup_project_role"); teamMember.setUserLevel(roleList.getIdFromLevel(TeamMember.MEMBER)); teamMember.setStatus(TeamMember.STATUS_ADDED); teamMember.setModifiedBy(userId); success = (teamMember.update(db) == 1); } else { teamMember.setStatus(TeamMember.STATUS_REFUSED); success = teamMember.delete(db); } return success; } public Project getProject() { if (projectId > -1) { return ProjectUtils.loadProject(projectId); } else { return null; } } public Project getTeamMemberProfile() { return UserUtils.loadUser(userId).getProfileProject(); } }