/*
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.controllers.actions;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import ca.myewb.beans.GroupChapter;
import ca.myewb.frame.Controller;
import ca.myewb.frame.Helpers;
import ca.myewb.frame.Message;
import ca.myewb.frame.Permissions;
import ca.myewb.frame.RedirectionException;
import ca.myewb.frame.forms.ListMembershipForm;
import ca.myewb.model.EmailModel;
import ca.myewb.model.GroupChapterModel;
import ca.myewb.model.GroupModel;
import ca.myewb.model.UserModel;
public class ModifyListMembership extends Controller
{
/*
* WARNING!!!
* this code is very complex and should be handled with care!
*/
public void handle(Context ctx) throws Exception
{
//assume URLparam is listid
GroupModel grp = null;
String listIDString = urlParams.getParam();
if ((listIDString == null) || (listIDString.equals("")))
{
listIDString = requestParams.get("List");
if ((listIDString == null) || (listIDString.equals("")))
{
log.warn("hit ModListMembership with no list param!!!");
if (getInterpageVar("isJoinListForm") != null)
{
throw getSecurityException("No list was specified!", path + "/mailing/ListMember");
}
else
{
throw getSecurityException("No list was specified!", Helpers.getDefaultURL());
}
}
try
{
grp = (GroupModel)getAndCheck(GroupModel.class, new Integer(listIDString));
}
catch (Exception e)
{
throw getSecurityException("There was a problem with the URL you requested.", Helpers.getDefaultURL());
}
}
else
{
grp = (GroupModel)getAndCheckFromUrl(GroupModel.class);
}
Boolean isLeaderForm = (Boolean)getInterpageVar("isLeaderForm");
Boolean isNormalListForm = (Boolean)getInterpageVar("isNormalListForm");
if (isLeaderForm == null)
{
isLeaderForm = false;
}
if (isNormalListForm == null)
{
isNormalListForm = false;
}
log.debug("leaderform: " + isLeaderForm + "; normalform: " + isNormalListForm);
ListMembershipForm form = new ListMembershipForm(path
+ "/actions/ModifyListMembership/"
+ grp.getId(),
requestParams,
isLeaderForm,
isNormalListForm);
Message m = form.validate();
if (m != null)
{
// Display error and prompt user to fix
if (isLeaderForm)
{
throw getValidationException(form, m, path + "/mailing/ListMgmt/" + grp.getId());
}
else
{
throw getValidationException(form, m, path + "/mailing/ListInfo/" + grp.getId());
}
}
String[] emails = form.getParameter("Emails").split("\n");
filterRequest(form, emails, grp); //this call enforces security/request sanity
String actionType = form.getParameter("ActionType");
boolean grpIsChapter = grp.isChapter();
boolean grpIsExec = grp.isExecList();
boolean alternateRedirect = false;
HashSet<String> emailsNoDupes = new HashSet<String>();
for(String email: emails)
{
email = email.trim();
if (!email.equals("")) //if it does, that's the guest user....
{
emailsNoDupes.add(email.toLowerCase());
}
}
List<String> errors = new Vector<String>();
TreeSet<String> toMail = new TreeSet<String>();
for (String email: emailsNoDupes)
{
UserModel targetUser = UserModel.getUserForEmail(email);
if (targetUser == null
&& (actionType.equals("add")
|| actionType.equals("upsender")
|| actionType.equals("upleader")))
{
//we need to create a user
targetUser = UserModel.newMailingListSignUp( email);
// send the welcome email
Template template = Velocity.getTemplate("emails/joinlist.vm");
VelocityContext mailctx = new VelocityContext();
mailctx.put("email", email);
mailctx.put("totalshortname", grp.getTotalShortname());
mailctx.put("helpers", new Helpers());
if (currentUser.getUsername().equals("guest"))
{
mailctx.put("actor", "you");
}
else
{
mailctx.put("actor",
currentUser.getFirstname() + " "
+ currentUser.getLastname());
}
StringWriter writer = new StringWriter();
template.merge(mailctx, writer);
EmailModel.sendEmail(email, writer.toString());
}
else if(targetUser == null)
{
//this is a removal, and the user doesn't even exist
errors.add(email + " wasn't on the list");
}
if (targetUser != null)
{
//can't downgrade leaders of chapter or exec groups implicitly by unsubbing them
if (actionType.equals("remove"))
{
if (!((grpIsChapter || grpIsExec) && targetUser.isLeader(grp, false)))
{
if (grpIsChapter)
{
//this code is only reachable if user is a leader
//assuming a chapter leader or admin is unsubbing members from the chapter list
GroupChapterModel chapter = targetUser.getChapter();
if ((chapter != null) && chapter.equals(grp))
{
//this group is the targetUser's own chapter: leave chapter
targetUser.leaveChapter(chapter);
}
else
{
//this user is merely on another chapter's list: unsubscribe it
targetUser.unsubscribe(grp);
}
}
else
{
//generic list, just do what you're told
targetUser.unsubscribe(grp);
if (!grp.getPublic())
{
alternateRedirect = true;
}
}
}
else
{
errors.add(email
+ " is a leader of this special list and wasn't removed");
}
}
else if (actionType.equals("downsender"))
{
//can't downgrade leaders of chapter or exec groups implicitly by unsendering them
if (!((grpIsChapter || grpIsExec)
&& targetUser.isLeader(grp, false)))
{
targetUser.downgradeFromListSender(grp);
}
else
{
errors.add(email
+ " is a leader of this special list and wasn't downgraded");
}
}
else if (actionType.equals("downleader"))
{
targetUser.downgradeFromListLeader(grp);
}
else
{
boolean addToMail = false;
//do we need to add them as a chapter member?
if(!targetUser.isMember("Chapter")) //admins skip this block too
{
if (grp.isChapter())
{
//yup, this IS a chapter (they don't get re-added as recipients)
addToMail = targetUser.joinChapter((GroupChapterModel)grp);
}
else if (grp.isExecList())
{
//yup, this is an exec list (wierd, but acceptable)
addToMail = targetUser.joinChapter(grp.chapterIfExec());
}
else if (grp.getParent() != null)
{
//this is a chapter sub-list and the user has no chapter, so join it
addToMail = targetUser.joinChapter(grp.getParent());
}
}
if(actionType.equals("add"))
{
addToMail = targetUser.subscribe(grp) || addToMail;
}
else if (actionType.equals("upsender"))
{
addToMail = targetUser.upgradeToListSender(grp) || addToMail;
}
else if (actionType.equals("upleader"))
{
addToMail = targetUser.upgradeToListLeader(grp) || addToMail;
}
else
{
throw getSecurityException("Sorry, there was a minor server error.",
"call to ModListMembership with invalid actionType! actionType="
+ actionType + " user=" + currentUser.getUsername(),
getLeadPage());
}
if(addToMail)
{
toMail.add(targetUser.getEmail());
}
}
}
}
if(!toMail.isEmpty() && grp.getWelcomeMessage() != null)
{
Vector<String> mailingList = new Vector<String>();
mailingList.addAll(toMail);
EmailModel.sendEmail( (grp.isChapter() ? ((GroupChapter)grp).getEmail() : Helpers.getSystemEmail()),
mailingList, grp.getFullWelcomeEmail());
}
// Leave a message in the session
if (errors.isEmpty())
{
setSessionMessage(("Done"));
}
else
{
String message = "Done, with exceptions: " +
"<div align=\"center\"><ul style=\"color: black; padding: 0; margin: 0; margin-top:8px;\">";
for (String error : errors)
{
message += ("<li style=\"margin-bottom: 5px;\">" + error + "</li>");
}
message += "</ul></div>";
httpSession.setAttribute("message", new Message(message));
}
// Redirect to somewhere
if (form.getParameter("Redirect", false) != null && !form.getParameter("Redirect", false).equals(""))
{
throw new RedirectionException(path + form.getParameter("Redirect", false));
}
else if (alternateRedirect)
{
throw new RedirectionException(path + "/mailing/Mailing");
}
else if (isLeaderForm)
{
throw new RedirectionException(path + "/mailing/ListMgmt/"
+ grp.getId());
}
else
{
throw new RedirectionException(path + "/mailing/ListInfo/"
+ grp.getId());
}
}
private void filterRequest(ListMembershipForm form, String[] emails,
GroupModel grp) throws Exception
{
String actionType = form.getParameter("ActionType");
if(!grp.getVisible())
{
throw getSecurityException("Sorry, there was a minor server error.",
"list is admin",
Helpers.getDefaultURL());
}
if (currentUser.getUsername().equals("guest"))
{
if ((!actionType.equals("add")) || (emails.length > 1))
{
//user is trying non-guest action!
throw getSecurityException("Sorry, there was a minor server error.",
"non-guest action!",
Helpers.getDefaultURL());
}
if (grp.getAdmin() && (!grp.equals(Helpers.getGroup("Org"))))
{
throw getSecurityException("Sorry, there was a minor server error.",
"list is admin",
Helpers.getDefaultURL());
}
}
else if (grp.getAdmin())
{
throw getSecurityException("Sorry, there was a minor server error.",
"list is admin", Helpers.getDefaultURL());
}
if (!grp.getPublic())
{
if (!(Permissions.canControlGroup(currentUser, grp)
|| currentUser.isLeader(grp) || currentUser.isMember(grp)
|| currentUser.isRecipient(grp) || currentUser.isSender(grp)))
{
//list is private and user is not a member
throw getSecurityException("Sorry, there was a minor server error.",
"list is private, cannot alter",
Helpers.getDefaultURL());
}
}
if (Permissions.canControlGroup(currentUser, grp))
{
if (grp.isExecList() || grp.isChapter())
{
if (actionType.equals("upleader")
|| actionType.equals("downleader"))
{
throw getSecurityException("Sorry, there was a minor server error.",
"trying to add/remove leader status from chapter or exec",
Helpers.getDefaultURL());
}
}
}
else //currentUser is not leader or admin
{
if (actionType.equals("remove"))
{
if (grp.isChapter() && currentUser.isMember(grp, false))
{
//user is trying to remove self from chapter
//redirect to LeaveChapter with a message
setSessionErrorMessage(("To leave a chapter list, you must leave the chapter..."));
throw new RedirectionException(path
+ "/actions/LeaveChapter");
}
}
else if ((!actionType.equals("add")) || (emails.length > 1))
{
//user is trying leader action!
throw getSecurityException("Sorry, there was a minor server error.",
"user is trying leader action",
Helpers.getDefaultURL());
}
}
//if we get here, the request is ok and should proceed
log.debug("modlist request passed filter");
}
public Set<String> invisibleGroups()
{
Set<String> s = new HashSet<String>();
s.add("Org");
//this page is visible to everyone, because even the guest user needs access
return s;
}
public List<String> getNeededInterpageVars()
{
Vector<String> vars = new Vector<String>();
vars.add("isLeaderForm");
vars.add("isNormalListForm");
vars.add("isJoinListForm"); //came from ListMember
//vars.addAll(GenericConfirm.getRequiredInterpageVars());
//these are so that the previous page can tell the action what type of form to return on failure
return vars;
}
}