Merge branch 'massmail' into develop

This commit is contained in:
Emil Siverhall 2012-02-21 16:12:57 +01:00
commit af1f93b959
17 changed files with 1074 additions and 37 deletions

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<wicket:extend>
<div class="span-22 last">
<div wicket:id="adminMailPanel"></div>
</div>
</wicket:extend>
</body>
</html>

@ -0,0 +1,18 @@
package se.su.dsv.scipro.admin.pages;
import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.admin.panels.AdminMailPanel;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@Authorization(authorizedRoles={Roles.SYSADMIN})
public class AdminMailPage extends AbstractAdminPage {
public AdminMailPage(PageParameters pp) {
super(pp);
add(new AdminMailPanel("adminMailPanel"));
}
}

@ -0,0 +1,65 @@
<!DOCTYPE html>
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<h5 class="peer-title">Mail from administrator</h5>
<div wicket:id="feedbackPanel"></div>
<div class="span-22">
<div class="span-10">
<div class="append-bottom">
<label for="projectClassSelection">Filter recipients by project level: </label><br />
<select id="projectClassSelection" wicket:id="projectClassSelection"></select><br />
</div>
<b>Filter recipients by project or project idea:</b>
<div class="append-bottom" wicket:id="mainChoice">
<input type="radio"/>
</div>
<div wicket:id="labelContainer">
<span wicket:id="pickerLabel"></span><span wicket:id="ideaPickerLabel"></span>
</div>
<div wicket:id="datePanel"></div>
<div wicket:id="choiceContainer">
<b>Available recipients:</b>
<wicket:enclosure child="ideaChoices">
<div class="append-bottom" wicket:id="ideaChoices">
<input type="radio"/>
</div>
</wicket:enclosure>
<wicket:enclosure child="projectChoices">
<div class="append-bottom" wicket:id="projectChoices">
<input type="radio"/>
</div>
</wicket:enclosure>
</div>
<button wicket:id="refreshRecipients">Refresh recipient list</button><br /><br />
<a wicket:id="showList">Show/Hide recipients</a><br />
<select multiple wicket:id="emailList" size="15" class="span-8">
<option>Name (e-mail)</option>
</select>
</div>
<div class="span-10">
<form wicket:id="mailForm">
<div>
<wicket:enclosure child="disabledLabel">
<div class="rounded-box">
<span wicket:id="disabledLabel"></span>
</div>
</wicket:enclosure>
Subject:<br />
<div wicket:id="subjectErrors"></div>
<input type="text" wicket:id="mailSubjectField"><br />
Message:<br />
<div wicket:id="messageErrors"></div>
<textarea wicket:id="mailBodyField"></textarea><br />
<div>
<input type="submit" value="Send e-mail" wicket:id="submitButton" />
</div>
</div>
</form>
</div>
</div>
</wicket:panel>
</body>
</html>

@ -0,0 +1,356 @@
package se.su.dsv.scipro.admin.panels;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.ListChoice;
import org.apache.wicket.markup.html.form.RadioChoice;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.ComponentFeedbackPanel;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.validation.validator.StringValidator;
import org.joda.time.DateTime;
import se.su.dsv.scipro.components.DatePickerPanel;
import se.su.dsv.scipro.components.ProjectClassSelector;
import se.su.dsv.scipro.components.ProjectIdeaMailChoice;
import se.su.dsv.scipro.components.ProjectMailChoice;
import se.su.dsv.scipro.data.dao.interfaces.GeneralSystemSettingsDao;
import se.su.dsv.scipro.data.dao.interfaces.MailEventDao;
import se.su.dsv.scipro.data.dataobjects.GeneralSystemSettings;
import se.su.dsv.scipro.data.dataobjects.MailEvent;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.data.facade.MailFacade;
import se.su.dsv.scipro.match.dataobject.Match;
/**
* Panel for mass mailing to predefined recipient sets.
*/
public class AdminMailPanel extends Panel {
@SpringBean
private MailEventDao mailEventDao;
@SpringBean
private GeneralSystemSettingsDao generalSystemSettingsDao;
@SpringBean
private MailFacade mailFacade;
private Set<User> userSet;
private static final Logger logger = Logger.getLogger(AdminMailPanel.class);
private final String PROJECTS = "Projects";
private final String PROJECT_IDEAS = "Project ideas";
private AjaxLink<String> showList;
private ListChoice<String> emailList;
private ProjectClassSelector projectClassSelection;
private ProjectClass projectClassModel;
private ProjectIdeaMailChoice ideaChoice;
private ProjectMailChoice projectChoice;
private RadioChoice<String> choice;
private WebMarkupContainer choiceContainer, labelContainer;
private String selectedRecipientSet;
private DatePickerPanel dpp;
private Label projectPickerLabel, ideaPickerLabel;
private static final long serialVersionUID = 1L;
public AdminMailPanel(String id) {
super(id);
setOutputMarkupId(true);
//Default value
selectedRecipientSet = ProjectMailChoice.THESIS_SUPPORT;
setUpClassSelection();
setUpDatePanel();
setUpRadioButtons();
setUpMailForm();
}
private void setUpClassSelection() {
projectClassSelection = new ProjectClassSelector("projectClassSelection");
add(projectClassSelection);
projectClassModel = projectClassSelection.getModelObject();
projectClassSelection.add(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = -1107218480527526745L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
projectClassModel = projectClassSelection.getModelObject();
updateUserSet(target);
}
});
}
private void setUpDatePanel() {
labelContainer = new WebMarkupContainer("labelContainer");
labelContainer.setOutputMarkupId(true);
projectPickerLabel = new Label("pickerLabel","Started between:");
ideaPickerLabel = new Label("ideaPickerLabel", "Submitted between:");
ideaPickerLabel.setVisible(false);
labelContainer.add(projectPickerLabel);
labelContainer.add(ideaPickerLabel);
add(labelContainer);
DateTime start = new DateTime();
start = start.minusMonths(6);
dpp = new DatePickerPanel("datePanel", start.toDate(), null);
add(dpp);
}
private void setUpMailForm() {
MailForm mailForm = new MailForm("mailForm");
add(mailForm);
add(new FeedbackPanel("feedbackPanel", new ComponentFeedbackMessageFilter(mailForm)));
}
private void setUpRadioButtons() {
List<String> options = Arrays.asList(new String[]{PROJECTS, PROJECT_IDEAS});
choice = new RadioChoice<String>("mainChoice",Model.of(PROJECTS), options);
choiceContainer = new WebMarkupContainer("choiceContainer");
choiceContainer.setOutputMarkupId(true);
ideaChoice = new ProjectIdeaMailChoice("ideaChoices");
projectChoice = new ProjectMailChoice("projectChoices");
userSet = new HashSet<User>();
userSet = getRecipients(selectedRecipientSet, projectClassModel);
ideaChoice.setVisible(false);
add(choice);
choiceContainer.add(ideaChoice);
choiceContainer.add(projectChoice);
add(choiceContainer);
addChoiceBehaviors();
emailList = new ListChoice<String>("emailList", new ListModel<String>(new ArrayList<String>())) {
private static final long serialVersionUID = -6361728706320841994L;
@Override
protected CharSequence getDefaultChoice(Object selected) {
return "";
}
};
emailList.setOutputMarkupId(true);
emailList.setOutputMarkupPlaceholderTag(true);
emailList.setVisible(false);
add(emailList);
showList = new AjaxLink<String>("showList"){
private static final long serialVersionUID = 1231753648699117745L;
@Override
public void onClick(AjaxRequestTarget target) {
showRecipients();
emailList.setVisible(!emailList.isVisible());
target.addComponent(showList);
target.addComponent(emailList);
}
};
showList.setOutputMarkupId(true);
showList.setOutputMarkupPlaceholderTag(true);
add(showList);
AjaxLink<String> refreshList = new AjaxLink<String>("refreshRecipients"){
private static final long serialVersionUID = -5312361960170366432L;
@Override
public void onClick(AjaxRequestTarget target) {
updateUserSet(target);
}
};
add(refreshList);
}
private void addChoiceBehaviors() {
AjaxFormChoiceComponentUpdatingBehavior projectChoiceBehavior = new AjaxFormChoiceComponentUpdatingBehavior() {
private static final long serialVersionUID = -143604824137895783L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
selectedRecipientSet = projectChoice.getModelObject();
updateUserSet(target);
}
};
AjaxFormChoiceComponentUpdatingBehavior ideaChoiceBehavior = new AjaxFormChoiceComponentUpdatingBehavior() {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
selectedRecipientSet = ideaChoice.getModelObject();
updateUserSet(target);
}
};
AjaxFormChoiceComponentUpdatingBehavior mainChoiceBehavior = new AjaxFormChoiceComponentUpdatingBehavior() {
private static final long serialVersionUID = -4104455092491774388L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
if(choice.getModelObject().equals(PROJECTS)) {
selectedRecipientSet = projectChoice.getModelObject();
ideaChoice.setVisible(false);
projectChoice.setVisible(true);
ideaPickerLabel.setVisible(false);
projectPickerLabel.setVisible(true);
}
else {
selectedRecipientSet = ideaChoice.getModelObject();
projectChoice.setVisible(false);
ideaChoice.setVisible(true);
ideaPickerLabel.setVisible(true);
projectPickerLabel.setVisible(false);
}
target.addComponent(choiceContainer);
target.addComponent(labelContainer);
updateUserSet(target);
}
};
ideaChoice.add(ideaChoiceBehavior);
projectChoice.add(projectChoiceBehavior);
choice.add(mainChoiceBehavior);
}
private void updateUserSet(AjaxRequestTarget target) {
userSet = getRecipients(selectedRecipientSet, projectClassModel);
showRecipients();
target.addComponent(emailList);
}
private void showRecipients(){
ArrayList<String> mailList = new ArrayList<String>();
for(User u : userSet){
if (u!=null)
mailList.add(u.toString() + " (" + u.getEmailAddress() +")");
}
Collections.sort(mailList);
emailList.setChoices(mailList);
}
private Set<User> getRecipients(String choiceInput, ProjectClass pc) {
Date startDate = dpp.getStartDate();
Date endDate = dpp.getEndDate();
Set<User> recipients = new HashSet<User>();
if(choiceInput.equals(ProjectMailChoice.THESIS_SUPPORT))
recipients = mailFacade.addThesisSupport();
else if(choiceInput.equals(ProjectMailChoice.AUTHORS_ACTIVE_PROJECT)){
recipients = mailFacade.addProjectAuthors(ProjectStatus.ACTIVE, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectIdeaMailChoice.AUTHORS_SUBMITTED)){
recipients = mailFacade.addIdeaAuthors(null, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectIdeaMailChoice.AUTHORS_CONFIRMED)){
recipients = mailFacade.addIdeaAuthors(Match.Status.CONFIRMED, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectIdeaMailChoice.AUTHORS_UNCONFIRMED)){
recipients = mailFacade.addIdeaAuthors(Match.Status.PUBLISHED, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectIdeaMailChoice.AUTHORS_REFUSED)){
recipients = mailFacade.addIdeaAuthors(Match.Status.REFUSED, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectMailChoice.ACTIVE_SUPERVISORS)){
recipients = mailFacade.addProjectSupervisors(ProjectStatus.ACTIVE, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectMailChoice.ALL_FOLLOWERS)){
recipients.addAll(mailFacade.addProjectSupervisors(ProjectStatus.ACTIVE, pc, startDate, endDate));
recipients.addAll(mailFacade.addProjectReviewers(ProjectStatus.ACTIVE, pc, startDate, endDate));
recipients.addAll(mailFacade.addProjectCoSupervisors(ProjectStatus.ACTIVE, pc, startDate, endDate));
}
else if(choiceInput.equals(ProjectIdeaMailChoice.SUPERVISOR_CONFIRMED)){
recipients = mailFacade.addIdeaSupervisors(Match.Status.CONFIRMED, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectIdeaMailChoice.SUPERVISOR_UNCONFIRMED)){
recipients = mailFacade.addIdeaSupervisors(Match.Status.PUBLISHED, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectMailChoice.ACTIVE_REVIEWERS)){
recipients = mailFacade.addProjectReviewers(ProjectStatus.ACTIVE, pc, startDate, endDate);
}
else if(choiceInput.equals(ProjectMailChoice.ACTIVE_CO_SUPERVISORS)){
recipients = mailFacade.addProjectCoSupervisors(ProjectStatus.ACTIVE, pc, startDate, endDate);
}
return recipients;
}
public class MailForm extends Form<Void> {
private TextField<String> mailSubjectField;
private TextArea<String> mailBodyField;
private String fromName;
private String fromEmail;
private static final long serialVersionUID = 1L;
public MailForm(String id) {
super(id);
GeneralSystemSettings gsettings = generalSystemSettingsDao.getGeneralSystemSettingsInstance();
fromName = gsettings.getMailFromName();
fromEmail = gsettings.getSystemFromMail();
Label disabledLabel = new Label("disabledLabel",
"Sending of e-mail through SciPro is inactivated. Please activate it under Admin -> Settings, if you want to use this feature.");
disabledLabel.setVisible(!gsettings.isMailNotifications());
add(disabledLabel);
Button submitButton = new Button("submitButton");
submitButton.setEnabled(gsettings.isMailNotifications());
submitButton.add(new SimpleAttributeModifier(
"onclick",
"if (!confirm('Are you sure you want to send this e-mail to the selected recipients?')){ return false; }"));
add(submitButton);
mailSubjectField = new TextField<String>("mailSubjectField", new Model<String>());
mailSubjectField.setRequired(true);
mailBodyField = new TextArea<String>("mailBodyField", new Model<String>());
mailBodyField.setRequired(true);
mailBodyField.add(StringValidator.minimumLength(5));
add(new ComponentFeedbackPanel("subjectErrors", mailSubjectField));
add(new ComponentFeedbackPanel("messageErrors", mailBodyField));
add(mailSubjectField);
add(mailBodyField);
}
@Override
protected void onSubmit() {
userSet = getRecipients(selectedRecipientSet, projectClassModel);
try {
if(userSet != null && !userSet.isEmpty()) {
MailEvent me = new MailEvent(mailSubjectField.getInput(), mailBodyField.getInput(), userSet, fromName, fromEmail);
me = mailEventDao.save(me);
info("E-mail sent successfully to the selected recipients");
}
else {
error("You need to specify recipients for your e-mail.");
}
} catch (Exception e) {
logger.info("Failed to send e-mail");
}
}
}
}

@ -0,0 +1,5 @@
Required=Field '${label}' is required
mailSubjectField.Required=You need a subject for your e-mail
mailBodyField.Required=You can't send an empty message
mailForm.mailBodyField.StringValidator.minimum=You need to write a minimum of 5 characters

@ -8,6 +8,7 @@ import org.apache.wicket.Page;
import se.su.dsv.scipro.admin.pages.AbstractAdminPage;
import se.su.dsv.scipro.admin.pages.AdminCheckListPage;
import se.su.dsv.scipro.admin.pages.AdminFinalSeminarPage;
import se.su.dsv.scipro.admin.pages.AdminMailPage;
import se.su.dsv.scipro.admin.pages.AdminPeerListPage;
import se.su.dsv.scipro.admin.pages.AdminProjectPartnerPage;
import se.su.dsv.scipro.admin.pages.AdminRolePage;
@ -46,6 +47,7 @@ public class AdminTabMenuPanel extends AbstractMenuPanel {
items.add(new MenuItem("Project partner", AdminProjectPartnerPage.class));
items.add(new MenuItem("CheckList", AdminCheckListPage.class));
items.add(new MenuItem("Match", AdminManageProjectIdeaPage.class));
items.add(new MenuItem("Mail", AdminMailPage.class));
return items;
}

@ -0,0 +1,70 @@
package se.su.dsv.scipro.components;
import java.util.Date;
import org.apache.wicket.IClusterable;
import org.joda.time.DateTime;
public class DatePickerModel implements IClusterable {
private static final long serialVersionUID = -2608932987467648773L;
private Date startDate;
private Date endDate;
/**
* Creates a DatePickerModel
* @param startDate the startDate in the DatePickerModel
* @param endDate the endDate in the DatepickerModel
*/
public DatePickerModel(Date startDate, Date endDate){
if(startDate == null){
startDate = new Date();
}
if(endDate == null){
endDate = new Date();
}
setStartDate(startDate);
setEndDate(endDate);
}
/**
* Creates A DatePickerModel with todays date in start and end.
*/
public DatePickerModel(){
this(null,null);
}
public void setStartDate(Date startDate) {
if(startDate != null){
DateTime tmp = new DateTime(startDate);
this.startDate = tmp.toDateMidnight().toDate();
}
else{
this.startDate = null;
}
}
public Date getStartDate() {
return startDate;
}
public void setEndDate(Date endDate) {
if(endDate != null){
DateTime tmp = new DateTime(endDate);
tmp = tmp.toDateMidnight().toDateTime();
tmp = tmp.minusSeconds(1);
tmp = tmp.plusDays(1);
this.endDate = tmp.toDate();
}
else{
this.endDate = null;
}
}
public Date getEndDate() {
return endDate;
}
}

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<div class="append-bottom">
<form wicket:id="dateForm">
<input wicket:id="startDate"/> <br />
and <br />
<input wicket:id="endDate"/>
</form>
</div>
</wicket:panel>
</body>
</html>

@ -0,0 +1,131 @@
package se.su.dsv.scipro.components;
import java.util.Date;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.extensions.markup.html.form.DateTextField;
import org.apache.wicket.extensions.yui.calendar.DatePicker;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.Model;
public class DatePickerPanel extends Panel{
private static final long serialVersionUID = -5607127520132313062L;
private DateTextField startDtf;
private DateTextField endDtf;
private CompoundPropertyModel<DatePickerModel> model;
private DatePickerModel dpm;
public Date getStartDate(){
return dpm.getStartDate();
}
public Date getEndDate(){
return dpm.getEndDate();
}
/**
* Creates A DatePickerPanel with todays date as start and end date.
* @param id the wicket markup id
*/
public DatePickerPanel(String id){
this(id, null, null);
}
/**
* Creates a DatePickerPanel with startDate as start date and endDate as endDate.
* @param id the wicket markup id
* @param startDate the start date to be set
* @param endDate the end date to be set
*/
public DatePickerPanel(String id, Date startDate, Date endDate) {
super(id);
dpm = new DatePickerModel(startDate, endDate);
model = new CompoundPropertyModel<DatePickerModel>(dpm);
Form<Date> dateForm = new Form<Date>("dateForm") {
private static final long serialVersionUID = -8526635121696735963L;
@Override
protected void onSubmit() {
model.getObject().setStartDate(startDtf.getModelObject());
model.getObject().setEndDate(endDtf.getModelObject());
}
};
startDtf = new DateTextField("startDate", new Model<Date>(model.getObject().getStartDate()), "yyyy-MM-dd");
endDtf = new DateTextField("endDate", new Model<Date>(model.getObject().getEndDate()), "yyyy-MM-dd");
OnChangeAjaxBehavior startDtfOnChange = new OnChangeAjaxBehavior() {
private static final long serialVersionUID = -6267372515046138786L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
setStartDate(startDtf.getModelObject());
}
};
OnChangeAjaxBehavior endDtfOnChangeAjaxBehavior = new OnChangeAjaxBehavior() {
private static final long serialVersionUID = -1131099635803805983L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
setEndDate(endDtf.getModelObject());
}
};
startDtf.add(startDtfOnChange);
endDtf.add(endDtfOnChangeAjaxBehavior);
DatePicker startDatePicker = new DatePicker();
startDatePicker.setShowOnFieldClick(true);
startDtf.add(startDatePicker);
dateForm.add(startDtf);
DatePicker endDatePicker = new DatePicker();
endDatePicker.setShowOnFieldClick(true);
endDtf.add(endDatePicker);
dateForm.add(endDtf);
add(dateForm);
}
public void startDateSetEnabled(boolean enabled){
startDtf.setEnabled(enabled);
}
public void endDateSetEnabled(boolean enabled){
endDtf.setEnabled(enabled);
}
public void setStartDate(Date startDate){
dpm.setStartDate(startDate);
model.getObject().setStartDate(dpm.getStartDate());
startDtf.setModelObject(dpm.getStartDate());
}
public void setEndDate(Date endDate){
dpm.setEndDate(endDate);
//model.getObject().setEndDate(dpm.getEndDate());
endDtf.setModelObject(dpm.getEndDate());
}
}

@ -0,0 +1,40 @@
package se.su.dsv.scipro.components;
import java.util.Arrays;
import java.util.List;
import org.apache.wicket.markup.html.form.RadioChoice;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
public class ProjectIdeaMailChoice extends RadioChoice<String> {
private static final long serialVersionUID = 2266943297142066435L;
public final static String THESIS_SUPPORT = "Thesis support";
public final static String AUTHORS_SUBMITTED = "All authors with submitted project ideas";
public final static String AUTHORS_CONFIRMED = "Authors with confirmed project ideas";
public final static String AUTHORS_UNCONFIRMED = "Authors with project ideas waiting to be confirmed";
public final static String AUTHORS_REFUSED = "Authors with refused project ideas";
public final static String SUPERVISOR_CONFIRMED = "Supervisors with confirmed project ideas";
public final static String SUPERVISOR_UNCONFIRMED = "Supervisors with project ideas waiting to be confirmed";
public ProjectIdeaMailChoice(String id) {
super(id);
initChoices();
setModel(Model.of(THESIS_SUPPORT));
}
public ProjectIdeaMailChoice(String id, IModel<String> model) {
super(id);
initChoices();
setModel(model);
}
private void initChoices() {
List<String> options = Arrays.asList(new String[]{THESIS_SUPPORT,AUTHORS_SUBMITTED,AUTHORS_CONFIRMED,AUTHORS_UNCONFIRMED,AUTHORS_REFUSED,SUPERVISOR_CONFIRMED, SUPERVISOR_UNCONFIRMED});
setChoices(options);
}
}

@ -0,0 +1,39 @@
package se.su.dsv.scipro.components;
import java.util.Arrays;
import java.util.List;
import org.apache.wicket.markup.html.form.RadioChoice;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
public class ProjectMailChoice extends RadioChoice<String> {
private static final long serialVersionUID = 2266943297142066435L;
public final static String THESIS_SUPPORT = "Thesis support";
public final static String AUTHORS_ACTIVE_PROJECT = "Authors with active projects";
public final static String ACTIVE_SUPERVISORS = "Head supervisors with active projects";
public final static String ACTIVE_CO_SUPERVISORS = "Co-supervisors with active projects";
public final static String ACTIVE_REVIEWERS = "Reviewers of active projects";
public final static String ALL_FOLLOWERS = "All supervisors and reviewers of active projects";
public ProjectMailChoice(String id) {
super(id);
initChoices();
setModel(Model.of(THESIS_SUPPORT));
}
public ProjectMailChoice(String id, IModel<String> model) {
super(id);
initChoices();
setModel(model);
}
private void initChoices() {
List<String> options = Arrays.asList(new String[]{THESIS_SUPPORT,AUTHORS_ACTIVE_PROJECT,ACTIVE_SUPERVISORS,ACTIVE_CO_SUPERVISORS,ACTIVE_REVIEWERS, ALL_FOLLOWERS});
setChoices(options);
}
}

@ -65,24 +65,13 @@ public interface ProjectDao extends Dao<Project>{
private Date dateCreated;
private Date createdAfter;
private Date createdBefore;
private Date startedAfter;
public void setCreatedAfter(Date createdAfter) {
this.createdAfter = createdAfter;
}
public Date getCreatedAfter() {
return createdAfter;
}
public void setcreatedBefore(Date createdBefore) {
this.createdBefore = createdBefore;
}
public Date getCreatedBefore() {
return createdBefore;
}
private Date startedBefore;
private Date createdAfter;
private Date createdBefore;
private Collection<ProjectClass> projectClasses;
@ -97,7 +86,39 @@ public interface ProjectDao extends Dao<Project>{
// TODO: private Collection<DSVUnit> units;
// TODO: private Collection<DSVField> fields;
public Date getCreatedBefore() {
return createdBefore;
}
public Date getCreatedAfter() {
return createdAfter;
}
public void setCreatedBefore(Date createdBefore) {
this.createdBefore = createdBefore;
}
public void setCreatedAfter(Date createdAfter) {
this.createdAfter = createdAfter;
}
public Date getStartedBefore() {
return startedBefore;
}
public void setStartedBefore(Date startedBefore) {
this.startedBefore = startedBefore;
}
public Date getStartedAfter() {
return startedAfter;
}
public void setStartedAfter(Date startedAfter) {
this.startedAfter = startedAfter;
}
public Date getDateCreated() {
return dateCreated;
}

@ -19,6 +19,7 @@ import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dataobjects.Log;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.data.enums.ProjectTeamMemberRoles;
@ -502,7 +503,7 @@ public class ProjectDaoJPAImp extends AbstractDaoJPAImp<Project> implements Proj
@Transactional( readOnly=true )
public List<Project> findProjects(ProjectDao.Params params){
public List<Project> findProjects(ProjectDao.Params params){
return getJpaTemplate().execute(
createQuerySet(params).fetchCallback());
}
@ -520,8 +521,12 @@ public class ProjectDaoJPAImp extends AbstractDaoJPAImp<Project> implements Proj
.filterString(params.getFilterString())
.projectClasses(params.getProjectClasses())
.projectStatuses(params.getProjectStatuses())
.authors(params.getAuthors())
.createdAfter(params.getCreatedAfter())
.createdBefore(params.getCreatedBefore())
.startedAfter(params.getStartedAfter())
.startedBefore(params.getStartedBefore())
// .creator(params.getCreator())
.sortField(params.getSortField(), params.getDirection())
.limit(params.getLimit())
.offset(params.getOffset());
@ -532,7 +537,43 @@ public class ProjectDaoJPAImp extends AbstractDaoJPAImp<Project> implements Proj
super(Project.class);
}
public QuerySet filterString(String filterString) {
public QuerySet createdBefore(Date createdBefore) {
if (createdBefore != null) {
getQuery().combine(
new Query().where("_.dateCreated <= :endDate")
.parameter("endDate", createdBefore));
}
return this;
}
public QuerySet createdAfter(Date createdAfter) {
if (createdAfter != null) {
getQuery().combine(
new Query().where("_.dateCreated >= :startDate")
.parameter("startDate", createdAfter));
}
return this;
}
public QuerySet startedAfter(Date startDate) {
if (startDate != null) {
getQuery().combine(
new Query().where("_.daisyStartDate >= :startDate")
.parameter("startDate", startDate));
}
return this;
}
public QuerySet startedBefore(Date endDate) {
if (endDate != null) {
getQuery().combine(
new Query().where("_.daisyStartDate <= :endDate")
.parameter("endDate", endDate));
}
return this;
}
public QuerySet filterString(String filterString) {
if (filterString != null) {
getQuery().combine(
new Query()
@ -551,6 +592,7 @@ public class ProjectDaoJPAImp extends AbstractDaoJPAImp<Project> implements Proj
return this;
}
public QuerySet projectStatuses(Collection<ProjectStatus> projectStatuses) {
if (projectStatuses != null && !projectStatuses.isEmpty()) {
getQuery().combine(
@ -560,23 +602,28 @@ public class ProjectDaoJPAImp extends AbstractDaoJPAImp<Project> implements Proj
return this;
}
public QuerySet createdBefore(Date createdBefore) {
if (createdBefore != null) {
getQuery().combine(
new Query().where("_.dateCreated <= :endDate")
.parameter("endDate", createdBefore));
}
return this;
}
public QuerySet createdAfter(Date createdAfter) {
if (createdAfter != null) {
getQuery().combine(
new Query().where("_.dateCreated >= :startDate")
.parameter("startDate", createdAfter));
}
return this;
public QuerySet authors(Collection<Student> authors) {
if (authors != null && !authors.isEmpty()) {
getQuery().combine(
new Query()
.join("_.projectParticipants a")
.where("a IN (:authors)")
.parameter("authors", authors)
.distinct());
}
return this;
}
// public QuerySet creator(User user) {
// if (user != null) {
// getQuery().combine(
// new Query()
// .where("_.creator = :user")
// .parameter("user", user));
// }
// return this;
// }
@Override
public Query initQuery() {

@ -0,0 +1,177 @@
package se.su.dsv.scipro.data.facade;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dao.interfaces.UserDao;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.dataobjects.ProjectFollower;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.match.dao.interfaces.ProjectIdeaDao;
import se.su.dsv.scipro.match.dataobject.Match.Status;
import se.su.dsv.scipro.match.dataobject.ProjectIdea;
@Service
public class MailFacade {
@Autowired
private ProjectDao projectDao;
@Autowired
private ProjectIdeaDao projectIdeaDao;
@Autowired
private UserDao userDao;
private ProjectDao.Params projectParams;
private ProjectIdeaDao.Params projectIdeaParams;
private Set<User> recipients;
public Set<User> addProjectAuthors(ProjectStatus ps, ProjectClass pc, Date startDate, Date endDate) {
setProjectParams(ps, pc, startDate, endDate);
return authorsFromProjects();
}
public Set<User> addProjectSupervisors(ProjectStatus ps, ProjectClass pc, Date startDate, Date endDate) {
setProjectParams(ps, pc, startDate, endDate);
return supervisorsFromProjects();
}
public Set<User> addProjectCoSupervisors(ProjectStatus ps, ProjectClass pc, Date startDate, Date endDate) {
setProjectParams(ps, pc, startDate, endDate);
return coSupervisorsFromProjects();
}
public Set<User> addProjectReviewers(ProjectStatus ps, ProjectClass pc, Date startDate, Date endDate) {
setProjectParams(ps, pc, startDate, endDate);
return reviewersFromProjects();
}
public Set<User> addIdeaAuthors(Status status, ProjectClass pc, Date startDate, Date endDate) {
setProjectIdeaParams(status, pc, startDate, endDate);
return authorsFromProjectIdeas();
}
public Set<User> addIdeaSupervisors(Status status, ProjectClass pc, Date startDate, Date endDate) {
setProjectIdeaParams(status, pc, startDate, endDate);
return supervisorsFromProjectIdeas();
}
private void setProjectIdeaParams(Status matchStatus, ProjectClass projectClass, Date startDate, Date endDate) {
projectIdeaParams = new ProjectIdeaDao.Params();
if(matchStatus != null)
projectIdeaParams.setStatuses(Arrays.asList(new Status[]{matchStatus}));
if(projectClass != null)
projectIdeaParams.setProjectClasses(Arrays.asList(new ProjectClass[]{projectClass}));
if(startDate != null)
projectIdeaParams.setSubmittedAfter(startDate);
if(endDate != null)
projectIdeaParams.setSubmittedBefore(endDate);
}
private void setProjectParams(ProjectStatus status, ProjectClass projectClass, Date startDate, Date endDate) {
projectParams = new ProjectDao.Params();
if (status != null)
projectParams.setProjectStatuses(Arrays.asList(new ProjectStatus[]{status}));
if (projectClass != null)
projectParams.setProjectClasses(Arrays.asList(new ProjectClass[]{projectClass}));
if(startDate != null)
projectParams.setStartedAfter(startDate);
if(endDate != null)
projectParams.setStartedBefore(endDate);
}
private Set<User> authorsFromProjectIdeas() {
List<ProjectIdea> listOfIdeas = projectIdeaDao.findProjectIdeas(projectIdeaParams);
recipients = new HashSet<User>();
for (ProjectIdea idea : listOfIdeas) {
for (Student s : idea.getAuthors())
recipients.add(s.getUser());
}
recipients.addAll(addThesisSupport());
return recipients;
}
private Set<User> supervisorsFromProjectIdeas() {
List<ProjectIdea> listOfIdeas = projectIdeaDao.findProjectIdeas(projectIdeaParams);
recipients = new HashSet<User>();
for (ProjectIdea idea : listOfIdeas) {
if (idea.getMatch().getSupervisor() != null)
recipients.add(idea.getMatch().getSupervisor().getUser());
}
recipients.addAll(addThesisSupport());
return recipients;
}
private Set<User> authorsFromProjects() {
List<Project> listOfProjects = projectDao.findProjects(projectParams);
recipients = new HashSet<User>();
for (Project p : listOfProjects) {
for (Student s : p.getProjectParticipants())
recipients.add(s.getUser());
}
recipients.addAll(addThesisSupport());
return recipients;
}
private Set<User> supervisorsFromProjects() {
List<Project> listOfProjects = projectDao.findProjects(projectParams);
recipients = new HashSet<User>();
for (Project p : listOfProjects) {
if(p.getHeadSupervisor() != null)
recipients.add(p.getHeadSupervisor().getUser());
}
recipients.addAll(addThesisSupport());
return recipients;
}
private Set<User> coSupervisorsFromProjects() {
List<Project> listOfProjects = projectDao.findProjects(projectParams);
recipients = new HashSet<User>();
for (Project p : listOfProjects){
if(!p.getProjectCoSupervisors().isEmpty()){
for(ProjectFollower pf : p.getProjectReviewers())
recipients.add(pf.getFollower().getUser());
}
}
recipients.addAll(addThesisSupport());
return recipients;
}
private Set<User> reviewersFromProjects() {
List<Project> listOProjects = projectDao.findProjects(projectParams);
recipients = new HashSet<User>();
for (Project p : listOProjects) {
if(!p.getProjectReviewers().isEmpty()) {
for(ProjectFollower pf : p.getProjectReviewers())
recipients.add(pf.getFollower().getUser());
}
}
recipients.addAll(addThesisSupport());
return recipients;
}
/**
* Method for always adding thesissupport@dsv.su.se to recipients, for backup of sent mail.
*
* @return
* Set of users with thesis support added. Set is used if more than one address would like to be added.
*/
public Set<User> addThesisSupport() {
Set<User> thesisSupportSet = new HashSet<User>();
User thesisSupport = userDao.getUserByEmail("thesissupport@dsv.su.se");
if (thesisSupport!=null)
thesisSupportSet.add(thesisSupport);
return thesisSupportSet;
}
}

@ -164,7 +164,7 @@ public class ProjectManagementPanel extends Panel {
@Override
public void onUpdateFilter(AjaxRequestTarget target) {
params.setCreatedAfter(getFromDate());
params.setcreatedBefore(getToDate());
params.setCreatedBefore(getToDate());
ajaxRefresh(target);
}

@ -49,7 +49,7 @@ public class Mail {
for (int i = 0; i < recipients.length; i++) {
addressTo[i] = new InternetAddress(recipients[i]);
}
msg.setRecipients(Message.RecipientType.TO, addressTo);
msg.setRecipients(Message.RecipientType.BCC, addressTo);
// Setting the Subject and Content Type
msg.setSubject(subject, "ISO-8859-1");

@ -1,9 +1,13 @@
package se.su.dsv.scipro.dao.jpa;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import junit.framework.Assert;
@ -17,6 +21,8 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import edu.emory.mathcs.backport.java.util.Arrays;
import se.su.dsv.scipro.data.dao.interfaces.ProjectClassDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectFollowerDao;
@ -31,6 +37,7 @@ import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.data.enums.ProjectTeamMemberRoles;
import se.su.dsv.scipro.match.dataobject.ProjectIdea;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@ -71,6 +78,13 @@ public class TestProjectDaoJPA {
private User unrelatedUser;
SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
private Date date10Jan2012;
private Date date1Jan2012;
private Date date1Dec2011;
private Date date15Dec2011;
@Before
public void startTransaction(){
@ -473,4 +487,27 @@ public class TestProjectDaoJPA {
Assert.assertFalse(members.hasNext());
}
@Test
@Rollback
@Transactional
public void testShouldFindProjectsBasedOnStartDate() {
try {
date10Jan2012 = date.parse("2012-01-10");
date1Jan2012 = date.parse("2012-01-01");
date15Dec2011 = date.parse("2011-12-15");
date1Dec2011 = date.parse("2011-12-01");
} catch (ParseException e) {
e.printStackTrace();
}
ProjectDao.Params params = new ProjectDao.Params();
params.setStartedAfter(date15Dec2011);
params.setStartedBefore(date10Jan2012);
activeProject.setDaisyStartDate(date1Jan2012);
completedProject.setDaisyStartDate(date1Dec2011);
List<Project> projects = projectDao.findProjects(params);
Assert.assertEquals(Arrays.asList(new Project[] { activeProject }), projects);
}
}