/*******************************************************************************
* Copyright 2006 - 2012 Vienna University of Technology,
* Department of Software Technology and Interactive Systems, IFS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package eu.scape_project.planning.user;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.ejb.Stateful;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import eu.scape_project.planning.model.GroupInvitation;
import eu.scape_project.planning.model.User;
import eu.scape_project.planning.model.UserGroup;
import eu.scape_project.planning.utils.ConfigurationLoader;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
/**
* Class to update the group of the current user.
*/
@Stateful
@SessionScoped
public class Groups implements Serializable {
/**
* Serial version UID.
*/
private static final long serialVersionUID = 1811189638942547758L;
@Inject
private Logger log;
@Inject
private EntityManager em;
@Inject
private User user;
@Inject
private ConfigurationLoader configurationLoader;
private Configuration config;
/**
* Users marked as changed.
*/
private Set<User> changedUsers = new HashSet<User>();
/**
* Groups marked as changed.
*/
private Set<UserGroup> changedGroups = new HashSet<UserGroup>();
/**
* The current users of the group.
*/
private List<User> groupUsers = new ArrayList<User>();
/**
* Initialises the class.
*/
@PostConstruct
public void init() {
config = configurationLoader.load();
changedUsers.clear();
changedGroups.clear();
groupUsers = em.createQuery("SELECT u FROM User u WHERE u.userGroup = :group", User.class)
.setParameter("group", user.getUserGroup()).getResultList();
}
/**
* Saves changes.
*/
public void save() {
em.merge(user);
// Save changed users
for (User changedUser : changedUsers) {
em.merge(changedUser);
}
// Save/delete changed groups
for (UserGroup changedGroup : changedGroups) {
List<User> users = em.createQuery("SELECT u FROM User u WHERE u.userGroup = :changedGroup", User.class)
.setParameter("changedGroup", changedGroup).getResultList();
if (users.size() == 0) {
deleteGroup(changedGroup);
} else {
em.merge(changedGroup);
}
}
init();
log.debug("Saved group of user " + user.getUsername());
}
/**
* Discards changes.
*/
public void discard() {
User origUser = em.find(User.class, user.getId());
user.setUserGroup(origUser.getUserGroup());
init();
log.debug("Group changes discarted for user " + user.getUsername());
}
/**
* Deletes the provided group from the DB.
*
* @param group
* the group to delete
*/
private void deleteGroup(UserGroup group) {
List<GroupInvitation> invitations = em
.createQuery("SELECT i FROM GroupInvitation i WHERE i.invitedGroup = :invitedGroup", GroupInvitation.class)
.setParameter("invitedGroup", group).getResultList();
for (GroupInvitation invitation : invitations) {
invitation.setInvitedGroup(null);
em.merge(invitation);
}
List<User> users = em.createQuery("SELECT u FROM User u WHERE u.userGroup = :changedGroup", User.class)
.setParameter("changedGroup", group).getResultList();
for (User user : users) {
UserGroup newGroup = new UserGroup();
newGroup.setName(user.getUsername());
em.merge(user);
}
em.remove(em.merge(group));
}
/**
* Removes the current user from his group.
*/
public void leaveGroup() {
removeUser(user);
}
/**
* Removes the provided user from the group of the current user.
*/
public void removeUser(User user) {
UserGroup group = new UserGroup();
group.setName(user.getUsername());
groupUsers.remove(user);
switchGroup(user, group);
}
/**
* Marks a user as changed.
*
* @param user
*/
private void markChangedUser(User user) {
if (!user.equals(this.user) && !changedUsers.contains(user)) {
changedUsers.add(user);
}
}
/**
* Switches the group of the provided user to the provided group.
*
* @param user
* the user to change
* @param group
* the group to switch to
*/
private void switchGroup(User user, UserGroup group) {
markChangedUser(user);
changedGroups.add(user.getUserGroup());
user.setUserGroup(group);
log.debug("Switched user " + user.getUsername() + " to group " + group.getName());
}
/**
* Invites a user to join the group of the current user.
*
* @param inviteUser
* the user to invite
* @param serverString
* the server string
* @throws InvitationMailException
* if the invitation mail could not be send
* @throws AlreadyGroupMemberException
* if the user is already a member of the group
*/
public void inviteUser(User inviteUser, String serverString) throws InvitationMailException,
AlreadyGroupMemberException {
if (inviteUser.getUserGroup().getId() == user.getUserGroup().getId()) {
throw new AlreadyGroupMemberException();
}
GroupInvitation invitation = createInvitation(inviteUser.getEmail());
sendInvitationMail(inviteUser, invitation, serverString);
}
/**
* Invites users with the provided email address to the group of the current
* user.
*
* @param inviteMail
* the email address of the user to invite
* @param serverString
* the server string
* @return true if the users were invited, false otherwise
* @throws InvitationMailException
* if the invitation mail could not be send
* @throws AlreadyGroupMemberException
* if the user is already a member of the group
*/
public void inviteUser(String inviteMail, String serverString) throws InvitationMailException,
AlreadyGroupMemberException {
String trimmedInviteMail = inviteMail.trim();
List<User> users = em.createQuery("SELECT u From User u WHERE u.email = :email", User.class)
.setParameter("email", trimmedInviteMail).getResultList();
if (users.size() > 0) {
// Users found
for (User user : users) {
inviteUser(user, serverString);
}
} else {
// No user found
GroupInvitation invitation = createInvitation(trimmedInviteMail);
sendInvitationMail(invitation, serverString);
}
}
/**
* Creates a new invitation for the provided email address.
*
* @param inviteMail
* the email address of the user to invite
* @return an invitation
*/
private GroupInvitation createInvitation(String inviteMail) {
List<GroupInvitation> existingInvitations = em
.createQuery("SELECT i FROM GroupInvitation i WHERE i.email = :email AND i.invitedGroup = :invitedGroup",
GroupInvitation.class).setParameter("email", inviteMail)
.setParameter("invitedGroup", user.getUserGroup()).getResultList();
for (GroupInvitation existingInvitation : existingInvitations) {
em.remove(existingInvitation);
}
GroupInvitation invitation = new GroupInvitation();
invitation.setEmail(inviteMail);
invitation.setInvitationActionToken(UUID.randomUUID().toString());
invitation.setInvitedGroup(user.getUserGroup());
em.merge(invitation);
log.debug("Created GroupInvitation for mail " + inviteMail);
return invitation;
}
/**
* Sends an invitation mail to the user.
*
* @param toUser
* the recipient of the mail
* @param serverString
* the server string
* @return true if the mail was sent successfully, false otherwise
* @throws InvitationMailException
* if the invitation mail could not be send
*/
private void sendInvitationMail(GroupInvitation invitation, String serverString) throws InvitationMailException {
try {
Properties props = System.getProperties();
props.put("mail.smtp.host", config.getString("mail.smtp.host"));
Session session = Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(config.getString("mail.from")));
message.setRecipient(RecipientType.TO, new InternetAddress(invitation.getEmail()));
message.setSubject(user.getFullName() + " invited you to join the Plato group "
+ user.getUserGroup().getName());
StringBuilder builder = new StringBuilder();
builder.append("Hello, \n\n");
builder.append("The Plato user " + user.getFullName() + " has invited you to join the group "
+ user.getUserGroup().getName() + ".\n\n");
builder
.append("You do not seem to be a Plato user. If you would like to accept the invitation, please first create an account at http://"
+ serverString + "/idp/addUser.jsf.\n");
builder
.append("If you have an account, please log in and use the following link to accept the invitation: \n");
builder.append("http://" + serverString + "/plato/user/groupInvitation.jsf?uid="
+ invitation.getInvitationActionToken());
builder.append("\n\n--\n");
builder.append("Your Planningsuite team");
message.setText(builder.toString());
message.saveChanges();
Transport.send(message);
log.debug("Group invitation mail sent successfully to " + invitation.getEmail());
} catch (MessagingException e) {
log.error("Error sending group invitation mail to " + invitation.getEmail(), e);
throw new InvitationMailException(e);
}
}
/**
* Sends an invitation mail to the user.
*
* @param toUser
* the recipient of the mail
* @param serverString
* the server string
* @return true if the mail was sent successfully, false otherwise
* @throws InvitationMailException
* if the invitation mail could not be send
*/
private void sendInvitationMail(User toUser, GroupInvitation invitation, String serverString)
throws InvitationMailException {
try {
Properties props = System.getProperties();
props.put("mail.smtp.host", config.getString("mail.smtp.host"));
Session session = Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(config.getString("mail.from")));
message.setRecipient(RecipientType.TO, new InternetAddress(invitation.getEmail()));
message.setSubject(user.getFullName() + " invited you to join the Plato group "
+ user.getUserGroup().getName());
StringBuilder builder = new StringBuilder();
builder.append("Dear " + toUser.getFullName() + ", \n\n");
builder.append("The Plato user " + user.getFullName() + " has invited you to join the group "
+ user.getUserGroup().getName() + ".\n");
builder.append("Please log in and use the following link to accept the invitation: \n");
builder.append("http://" + serverString + "/plato/user/groupInvitation.jsf?uid="
+ invitation.getInvitationActionToken());
builder.append("\n\n--\n");
builder.append("Your Planningsuite team");
message.setText(builder.toString());
message.saveChanges();
Transport.send(message);
log.debug("Group invitation mail sent successfully to " + invitation.getEmail());
} catch (Exception e) {
log.error("Error sending group invitation mail to " + invitation.getEmail(), e);
throw new InvitationMailException(e);
}
}
/**
* Accept a group invitation.
*
* @param invitationActionToken
* the invitation action token
* @return true if the group was changed, false otherwise
* @throws GroupNotFoundException
* if the group could not be found
* @throws TokenNotFoundException
* if the token could not be found
* @throws AlreadyGroupMemberException
* if the user is already a member of the group
*/
public void acceptInvitation(String invitationActionToken) throws GroupNotFoundException, TokenNotFoundException,
AlreadyGroupMemberException {
try {
GroupInvitation invitation = em
.createQuery("SELECT i FROM GroupInvitation i WHERE i.invitationActionToken = :invitationActionToken",
GroupInvitation.class).setParameter("invitationActionToken", invitationActionToken)
.getSingleResult();
em.remove(invitation);
if (invitation.getInvitedGroup() == null) {
throw new GroupNotFoundException();
}
if (invitation.getInvitedGroup().getId() == user.getUserGroup().getId()) {
throw new AlreadyGroupMemberException();
}
switchGroup(user, invitation.getInvitedGroup());
save();
log.info("Invitation to group " + user.getUserGroup().getName() + " accepted by user " + user.getUsername());
} catch (NoResultException e) {
log.info("InvitationActionToken for user " + user.getUsername() + " not found.");
throw new TokenNotFoundException(e);
}
}
/**
* Declines the group invitation.
*
* @param invitationActionToken
* the invitation action token
* @throws TokenNotFoundException
* if the token could not be found
*/
public void declineInvitation(String invitationActionToken) throws TokenNotFoundException {
try {
GroupInvitation invitation = em
.createQuery("SELECT i FROM GroupInvitation i WHERE i.invitationActionToken = :invitationActionToken",
GroupInvitation.class).setParameter("invitationActionToken", invitationActionToken)
.getSingleResult();
em.remove(invitation);
log.info("Invitation to group " + user.getUserGroup().getName() + " declined by user " + user.getUsername());
} catch (NoResultException e) {
log.info("InvitationActionToken for user " + user.getUsername() + " not found.");
throw new TokenNotFoundException(e);
}
}
/**
* Returns the group name of an invitation identified by the action token.
*
* @param invitationActionToken
* the action token
* @return the name of the associated group
* @throws TokenNotFoundException
* if the token could not be found
* @throws GroupNotFoundException
* if the group does not exist anymore
*/
public String getInvitationGroupName(String invitationActionToken) throws TokenNotFoundException,
GroupNotFoundException {
try {
GroupInvitation invitation = em
.createQuery("SELECT i FROM GroupInvitation i WHERE i.invitationActionToken = :invitationActionToken",
GroupInvitation.class).setParameter("invitationActionToken", invitationActionToken)
.getSingleResult();
if (invitation.getInvitedGroup() == null) {
throw new GroupNotFoundException();
}
return invitation.getInvitedGroup().getName();
} catch (NoResultException e) {
log.info("InvitationActionToken for user " + user.getUsername() + " not found.");
throw new TokenNotFoundException(e);
}
}
/**
* Gets the users of the provided group.
*
* @param group
* the group
* @return a list of users
*/
public List<User> getGroupUsers() {
return groupUsers;
}
}