diff --git a/src/main/java/se/su/dsv/scipro/match/dataobject/FirstMeeting.java b/src/main/java/se/su/dsv/scipro/match/dataobject/FirstMeeting.java new file mode 100644 index 0000000000..b828a81202 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/match/dataobject/FirstMeeting.java @@ -0,0 +1,76 @@ +package se.su.dsv.scipro.match.dataobject; + +import java.util.Date; + +import javax.persistence.Basic; +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.apache.wicket.IClusterable; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +@Entity +@Table(name = "first_meeting") +@Cacheable(true) +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +public class FirstMeeting implements IClusterable { + + private static final long serialVersionUID = 1659431236791209714L; + + @Id + @GeneratedValue + private Long id; + + @Basic(optional=false) + private Date firstMeetingDate; + + @Column(nullable = false, length = 1024) + private String description; + + @OneToOne(optional=false) + private SupervisorIdea supervisorIdea; + + public FirstMeeting(){ + + } + + public FirstMeeting(Date firstMeetingDate, String description, SupervisorIdea supervisorIdea) { + this.firstMeetingDate = firstMeetingDate; + this.description = description; + this.supervisorIdea = supervisorIdea; + } + + public Date getFirstMeetingDate() { + return firstMeetingDate; + } + + public void setFirstMeetingDate(Date firstMeetingDate) { + this.firstMeetingDate = firstMeetingDate; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Long getId() { + return id; + } + + public void setSupervisorIdea(SupervisorIdea supervisorIdea) { + this.supervisorIdea = supervisorIdea; + } + + public SupervisorIdea getSupervisorIdea() { + return supervisorIdea; + } +} diff --git a/src/main/java/se/su/dsv/scipro/match/dataobject/SupervisorIdea.java b/src/main/java/se/su/dsv/scipro/match/dataobject/SupervisorIdea.java index 64efed2e1d..0eac34a6b0 100644 --- a/src/main/java/se/su/dsv/scipro/match/dataobject/SupervisorIdea.java +++ b/src/main/java/se/su/dsv/scipro/match/dataobject/SupervisorIdea.java @@ -2,11 +2,11 @@ package se.su.dsv.scipro.match.dataobject; import javax.persistence.Cacheable; import javax.persistence.Column; -import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; import javax.persistence.Table; import org.hibernate.annotations.Cache; @@ -34,6 +34,9 @@ public class SupervisorIdea extends Idea { @Column(nullable = false, length = 1024) private String requirements; + @OneToOne(mappedBy="supervisorIdea", orphanRemoval = true, optional = true) + private FirstMeeting firstMeeting; + @Override public Long getId() { return id; @@ -109,4 +112,12 @@ public class SupervisorIdea extends Idea { return false; return true; } + + public void setFirstMeeting(FirstMeeting firstMeeting) { + this.firstMeeting = firstMeeting; + } + + public FirstMeeting getFirstMeeting() { + return firstMeeting; + } } diff --git a/src/main/java/se/su/dsv/scipro/springdata/repos/FirstMeetingRepo.java b/src/main/java/se/su/dsv/scipro/springdata/repos/FirstMeetingRepo.java new file mode 100644 index 0000000000..32433ee0d7 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/springdata/repos/FirstMeetingRepo.java @@ -0,0 +1,12 @@ +package se.su.dsv.scipro.springdata.repos; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QueryDslPredicateExecutor; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.match.dataobject.FirstMeeting; + +@Transactional(readOnly = true) +public interface FirstMeetingRepo extends JpaRepository<FirstMeeting, Long>, QueryDslPredicateExecutor<FirstMeeting> { + +} diff --git a/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/SupervisorIdeaServiceImpl.java b/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/SupervisorIdeaServiceImpl.java index 200cc2272b..63a264021b 100644 --- a/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/SupervisorIdeaServiceImpl.java +++ b/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/SupervisorIdeaServiceImpl.java @@ -20,11 +20,13 @@ 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.match.dataobject.Idea.IdeaStatus; +import se.su.dsv.scipro.match.dataobject.FirstMeeting; import se.su.dsv.scipro.match.dataobject.IdeaParticipation; import se.su.dsv.scipro.match.dataobject.QSupervisorIdea; import se.su.dsv.scipro.match.dataobject.SupervisorIdea; import se.su.dsv.scipro.match.dataobject.Watson; import se.su.dsv.scipro.peer.data.dao.controllers.Pair; +import se.su.dsv.scipro.springdata.repos.FirstMeetingRepo; import se.su.dsv.scipro.springdata.repos.SupervisorIdeaRepo; import se.su.dsv.scipro.springdata.services.ApplicationPeriodService; import se.su.dsv.scipro.springdata.services.StudentService; @@ -47,6 +49,9 @@ public class SupervisorIdeaServiceImpl extends AbstractQueryService<SupervisorId private SupervisorService supervisorService; @Resource private ApplicationPeriodService applicationPeriodService; + @Resource + private FirstMeetingRepo firstMeetingRepo; + private transient Logger logger = Logger.getLogger(SupervisorIdeaService.class); private int MAX_PARTNERS = 1; @@ -212,6 +217,21 @@ public class SupervisorIdeaServiceImpl extends AbstractQueryService<SupervisorId reloadedIdea.getWatson().setPracticalHow(idea.getWatson().getPracticalHow()); } + @Override + @Transactional ( readOnly = false) + public SupervisorIdea saveMeeting(SupervisorIdea idea, Date date, String desc) { + SupervisorIdea reloadedIdea = supervisorIdeaRepo.findOne(idea.getId()); + if (reloadedIdea.getFirstMeeting()!=null) { + reloadedIdea.getFirstMeeting().setFirstMeetingDate(date); + reloadedIdea.getFirstMeeting().setDescription(desc); + } else { + FirstMeeting meeting = new FirstMeeting(date, desc, reloadedIdea); + meeting = firstMeetingRepo.save(meeting); + reloadedIdea.setFirstMeeting(meeting); + } + return reloadedIdea; + } + @Override @Transactional public boolean hasTakenIdeas(User authorUser, boolean confirmed) { diff --git a/src/main/java/se/su/dsv/scipro/springdata/services/SupervisorIdeaService.java b/src/main/java/se/su/dsv/scipro/springdata/services/SupervisorIdeaService.java index e847d41b6b..cac44a75fd 100644 --- a/src/main/java/se/su/dsv/scipro/springdata/services/SupervisorIdeaService.java +++ b/src/main/java/se/su/dsv/scipro/springdata/services/SupervisorIdeaService.java @@ -2,6 +2,7 @@ package se.su.dsv.scipro.springdata.services; import java.io.Serializable; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.SortedSet; @@ -35,6 +36,7 @@ public interface SupervisorIdeaService extends GenericService<SupervisorIdea, Lo void partnerAcceptIdea(SupervisorIdea idea, User loggedInUser); void declineIdea(SupervisorIdea idea); void updateIdea(SupervisorIdea idea); + SupervisorIdea saveMeeting(SupervisorIdea idea, Date date, String desc); boolean hasTakenIdeas(User authorUser, boolean confirmed); boolean isIdeaEditable(SupervisorIdea idea, User currentUser); diff --git a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.html b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.html index d642a86f96..68481d8404 100644 --- a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.html +++ b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.html @@ -7,7 +7,27 @@ <body> <wicket:panel> <form wicket:id="form"> - <div wicket:id="ideaDetails"></div> + <div class="append-bottom" wicket:id="ideaDetails"></div> + <div class="prepend-top" wicket:id="meetingEnclosure"> + <div class="span-8 append-bottom info-box rounded-box last"> + <p> + The students won't see who is the supervisor until the + application period course start date. + </p> + + A time and date for the first meeting must be selected and + saved at least X days before application period course start date. + + </div> + <div class="span-6"> + <div class="span-8" wicket:id="feedback"></div> + <b>First meeting:</b><br /> + <input wicket:id="dateField"/><br /> + <b>Place:</b><br /> + <textarea wicket:id="descriptionField"></textarea> + <input type="button" wicket:id="saveButton" value="Save meeting details"/> + </div> + </div> </form> </wicket:panel> </body> diff --git a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.java b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.java index 4a58790ac1..a9f9ba1b77 100644 --- a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.java +++ b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorIdeaDetailsPanel.java @@ -1,19 +1,36 @@ package se.su.dsv.scipro.supervisor.panels; +import java.util.Date; + +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; +import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.extensions.yui.calendar.DatePicker; +import org.apache.wicket.markup.html.basic.EnclosureContainer; import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; import se.su.dsv.scipro.match.dataobject.SupervisorIdea; import se.su.dsv.scipro.project.panels.ProjectIdeaDetailsPanel; +import se.su.dsv.scipro.springdata.services.SupervisorIdeaService; -public class SupervisorIdeaDetailsPanel extends Panel { +public abstract class SupervisorIdeaDetailsPanel extends Panel { + + @SpringBean + private SupervisorIdeaService ideaService; public SupervisorIdeaDetailsPanel(String id, IModel<SupervisorIdea> model) { super(id, model); add(new SupervisorIdeaDetailsForm("form", model)); } + public abstract void updateTarget(AjaxRequestTarget target, SupervisorIdea idea); + private static final long serialVersionUID = 29731924490786784L; private class SupervisorIdeaDetailsForm extends Form<SupervisorIdea> { @@ -23,6 +40,56 @@ public class SupervisorIdeaDetailsPanel extends Panel { public SupervisorIdeaDetailsForm(String id, final IModel<SupervisorIdea> model) { super(id, model); add(new ProjectIdeaDetailsPanel("ideaDetails", model, true, true)); + addFirstMeetingEnclosure(model, true); + } + + private void addFirstMeetingEnclosure(final IModel<SupervisorIdea> model, boolean visibility) { + final FeedbackPanel feedback = new FeedbackPanel("feedback"); + feedback.setOutputMarkupId(true); + Date firstMeetingDate; + Model<String> descModel; + if (model.getObject().getFirstMeeting()!=null){ + firstMeetingDate = model.getObject().getFirstMeeting().getFirstMeetingDate(); + descModel = Model.of(model.getObject().getFirstMeeting().getDescription()); + } + else { + firstMeetingDate = new Date(); + descModel = new Model<String>(); + } + + final DateTextField dateField = new DateTextField("dateField", new Model<Date>(firstMeetingDate), "yyyy-MM-dd"); + DatePicker datePicker = new DatePicker(); + datePicker.setShowOnFieldClick(true); + dateField.add(datePicker); + + final TextArea<String> meetingDescriptionField = new TextArea<String>("descriptionField", descModel); + + AjaxSubmitLink saveLink = new AjaxSubmitLink("saveButton") { + private static final long serialVersionUID = -4841491128764249358L; + + @Override + protected void onSubmit(AjaxRequestTarget target, Form<?> form) { + if(meetingDescriptionField.getModelObject()==null){ + error("You need to specify a place for the meeting"); + } else { + SupervisorIdea idea = ideaService.saveMeeting(model.getObject(), dateField.getModelObject(), meetingDescriptionField.getModelObject()); + updateTarget(target, idea); + } + target.addComponent(feedback); + } + }; + + //Date field controls visibility of entire container. + dateField.setVisible(visibility); + + EnclosureContainer firstMeetingEnclosure = new EnclosureContainer("meetingEnclosure", dateField); + firstMeetingEnclosure.add(feedback); + firstMeetingEnclosure.add(dateField); + firstMeetingEnclosure.add(meetingDescriptionField); + firstMeetingEnclosure.add(saveLink); + add(firstMeetingEnclosure); + + } diff --git a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.html b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.html index ea80bcc6c5..89a52c5584 100644 --- a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.html +++ b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.html @@ -8,6 +8,7 @@ <div wicket:id="dialog"> <div wicket:id="dialogPanel"></div> </div> + <div wicket:id="feedback"></div> <form wicket:id="form"> <div class="span-5" wicket:id="levelFilter"></div> <div class="span-5"> diff --git a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.java b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.java index 9626edc6b2..5114c97c8b 100644 --- a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.java +++ b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaOverviewPanel.java @@ -9,6 +9,7 @@ import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.panel.EmptyPanel; +import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -43,8 +44,11 @@ public class SupervisorProjectIdeaOverviewPanel extends Panel { public SupervisorProjectIdeaOverviewPanel(String id, final User supervisor) { super(id); + FeedbackPanel feedback = new FeedbackPanel("feedback"); + feedback.setOutputMarkupId(true); + add(feedback); addDialog(); - addDataTable(supervisor); + addDataTable(supervisor, feedback); add(new FilterForm("form", supervisor)); } @@ -52,13 +56,13 @@ public class SupervisorProjectIdeaOverviewPanel extends Panel { dialog = new Dialog("dialog"); dialog.setModal(true); dialog.setAutoOpen(false); - dialog.setWidth(500); + dialog.setWidth(450); dialog.setHeight(600); dialog.add(new EmptyPanel("dialogPanel")); add(dialog); } - private void addDataTable(final User supervisor) { + private void addDataTable(final User supervisor, final FeedbackPanel feedback) { add(genericDataPanel = new GenericDataPanel<SupervisorIdea>("dataPanel") { private static final long serialVersionUID = -4539188306454725307L; @@ -87,9 +91,20 @@ public class SupervisorProjectIdeaOverviewPanel extends Panel { private static final long serialVersionUID = 4667741924987868274L; @Override - protected void onClick(IModel<SupervisorIdea> ideaModel, + protected void onClick(final IModel<SupervisorIdea> ideaModel, AjaxRequestTarget target) { - dialog.replace(new SupervisorIdeaDetailsPanel("dialogPanel", ideaModel)); + dialog.replace(new SupervisorIdeaDetailsPanel("dialogPanel", ideaModel){ + private static final long serialVersionUID = -1970068053928444580L; + + @Override + public void updateTarget(AjaxRequestTarget target, SupervisorIdea idea) { + dialog.close(target); + info("Meeting details saved"); + ideaModel.setObject(idea); + target.addComponent(feedback); + } + + }); dialog.setTitle("Selected supervisor project idea"); target.addComponent(dialog); dialog.open(target); diff --git a/src/test/java/se/su/dsv/scipro/springdata/TestSupervisorIdea.java b/src/test/java/se/su/dsv/scipro/springdata/TestSupervisorIdea.java index 19e9fdc558..c81b9955b4 100644 --- a/src/test/java/se/su/dsv/scipro/springdata/TestSupervisorIdea.java +++ b/src/test/java/se/su/dsv/scipro/springdata/TestSupervisorIdea.java @@ -1,10 +1,14 @@ package se.su.dsv.scipro.springdata; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -29,6 +33,7 @@ import se.su.dsv.scipro.data.dataobjects.User; import se.su.dsv.scipro.match.dao.interfaces.KeywordDao; import se.su.dsv.scipro.match.dao.interfaces.KeywordTypeDao; import se.su.dsv.scipro.match.dataobject.ApplicationPeriod; +import se.su.dsv.scipro.match.dataobject.FirstMeeting; import se.su.dsv.scipro.match.dataobject.Idea.IdeaStatus; import se.su.dsv.scipro.match.dataobject.IdeaParticipation; import se.su.dsv.scipro.match.dataobject.Keyword; @@ -70,6 +75,7 @@ public class TestSupervisorIdea { private SupervisorIdea waitingBachelorIdea, waitingMasterIdea, takenBachelorIdea, completedMasterIdea, waitingBachelor2, waitingMaster2, waitingBachelor3; private ApplicationPeriod bachelorPeriod, masterPeriod; private Keyword keyword1, keyword2; + private SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH); @Before public void startTransaction() throws Exception { @@ -410,6 +416,18 @@ public class TestSupervisorIdea { Assert.assertNotNull(idea.getApplicationPeriod()); } + @Test + @Transactional + @Rollback + public void testCreateFirstMeeting() { + Date firstMeetingDate = date("2012-08-01"); + FirstMeeting firstMeeting = new FirstMeeting(firstMeetingDate, "First meeting description", takenBachelorIdea); + takenBachelorIdea.setFirstMeeting(firstMeeting); + Assert.assertEquals(firstMeetingDate, takenBachelorIdea.getFirstMeeting().getFirstMeetingDate()); + Assert.assertEquals("First meeting description", takenBachelorIdea.getFirstMeeting().getDescription()); + Assert.assertEquals(takenBachelorIdea, takenBachelorIdea.getFirstMeeting().getSupervisorIdea()); + } + // HELPER METHODS private SupervisorIdea newIdea(ProjectClass pc, ApplicationPeriod ap, Employee supervisor, IdeaStatus ideaStatus) { SupervisorIdea idea = new SupervisorIdea(); @@ -455,4 +473,12 @@ public class TestSupervisorIdea { } return list; } + + private Date date(String dateString) { + try { + return date.parse(dateString); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } }