diff --git a/resources/db_update_scripts/current.sql b/resources/db_update_scripts/current.sql index e70c3576f1..08656f69ac 100644 --- a/resources/db_update_scripts/current.sql +++ b/resources/db_update_scripts/current.sql @@ -1,2 +1,12 @@ alter table `general_system_settings` drop column matchAlgorithmMatchesAreForceAccepted; -alter table `general_system_settings` drop column supervisorsCanAcceptDeclinePIs; \ No newline at end of file +alter table `general_system_settings` drop column supervisorsCanAcceptDeclinePIs; + +CREATE TABLE `first_meeting` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `firstMeetingDate` datetime NOT NULL, + `description` varchar(1024) NOT NULL, + `supervisoridea_id` bigint(20) NOT NULL, + PRIMARY KEY (`id`), + KEY `FK2E9F13AC8DE85053` (`supervisoridea_id`), + CONSTRAINT `FK2E9F13AC8DE85053` FOREIGN KEY (`supervisoridea_id`) REFERENCES `supervisoridea` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=latin1; diff --git a/src/main/java/se/su/dsv/scipro/SciProApplication.java b/src/main/java/se/su/dsv/scipro/SciProApplication.java index eaa6dfc420..0c91fec54b 100644 --- a/src/main/java/se/su/dsv/scipro/SciProApplication.java +++ b/src/main/java/se/su/dsv/scipro/SciProApplication.java @@ -204,7 +204,8 @@ public class SciProApplication extends RepositoryApplication implements IThemabl mountBookmarkablePage("supervisor/project/files", SupervisorFilePage.class); mountBookmarkablePage("supervisor/interest", SupervisorInterestPage.class); mountBookmarkablePage("supervisor/projectideas", SupervisorProjectIdeaStartPage.class); - mountBookmarkablePage("supervisor/projectideas/myideas", SupervisorMyProjectIdeasPage.class); + mountBookmarkablePage("supervisor/projectideas/mystudentideas", SupervisorMyProjectIdeasPage.class); + mountBookmarkablePage("supervisor/projectideas/myideas", SupervisorMySupervisorIdeasPage.class); /* * Peer pages */ diff --git a/src/main/java/se/su/dsv/scipro/datatables/BooleanIconColumn$IconPanel.html b/src/main/java/se/su/dsv/scipro/datatables/BooleanIconColumn$IconPanel.html new file mode 100644 index 0000000000..18441b3293 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/datatables/BooleanIconColumn$IconPanel.html @@ -0,0 +1,3 @@ +<wicket:panel> + <img wicket:id="icon"/> +</wicket:panel> \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/datatables/BooleanIconColumn.java b/src/main/java/se/su/dsv/scipro/datatables/BooleanIconColumn.java new file mode 100644 index 0000000000..3db5d36cf4 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/datatables/BooleanIconColumn.java @@ -0,0 +1,49 @@ +package se.su.dsv.scipro.datatables; + +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; + +import se.su.dsv.scipro.icons.ImageObject; + +/** + * Column that displays different icons depending on a boolean value defined in abstract method booleanValue() + * + * @author emil-siv + * + */ +public abstract class BooleanIconColumn<T> extends AbstractColumn<T> { + + private static final long serialVersionUID = -9034393574179345237L; + + private final String yesIconString; + private final String noIconString; + + public BooleanIconColumn(IModel<String> displayModel, String yesIconString, String noIconString) { + super(displayModel, null); + this.yesIconString = yesIconString; + this.noIconString = noIconString; + } + + public void populateItem(Item<ICellPopulator<T>> cellItem, + String componentId, IModel<T> rowModel) { + cellItem.add(new IconPanel(componentId, rowModel)); + } + + private class IconPanel extends Panel { + private static final long serialVersionUID = 5301911716927261302L; + + public IconPanel(String id, IModel<T> rowModel) { + super(id); + + if(booleanValue(rowModel)) + add(new ImageObject("icon", ImageObject.SIXTEEN + yesIconString)); + else + add(new ImageObject("icon", ImageObject.SIXTEEN + noIconString)); + } + } + + protected abstract boolean booleanValue(IModel<T> rowModel); +} \ No newline at end of file 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/IdeaParticipation.java b/src/main/java/se/su/dsv/scipro/match/dataobject/IdeaParticipation.java index c17ad1b70f..0a0cd8a419 100644 --- a/src/main/java/se/su/dsv/scipro/match/dataobject/IdeaParticipation.java +++ b/src/main/java/se/su/dsv/scipro/match/dataobject/IdeaParticipation.java @@ -85,5 +85,8 @@ public class IdeaParticipation implements Serializable { return (getPk()!=null?getPk().hashCode() : 0); } - + @Override + public String toString() { + return getStudent().getNameAsString(); + } } 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/FirstMeetingServiceImpl.java b/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/FirstMeetingServiceImpl.java new file mode 100644 index 0000000000..7e774c92f5 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/FirstMeetingServiceImpl.java @@ -0,0 +1,42 @@ +package se.su.dsv.scipro.springdata.serviceimpls; + +import javax.annotation.Resource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.mysema.query.types.expr.BooleanExpression; + +import se.su.dsv.scipro.match.dataobject.FirstMeeting; +import se.su.dsv.scipro.match.dataobject.QFirstMeeting; +import se.su.dsv.scipro.match.dataobject.SupervisorIdea; +import se.su.dsv.scipro.springdata.repos.FirstMeetingRepo; +import se.su.dsv.scipro.springdata.services.FirstMeetingService; + + +@Service ( "firstMeetingService" ) +@Transactional ( readOnly = true ) +public class FirstMeetingServiceImpl extends AbstractQueryService<FirstMeeting, Long> implements FirstMeetingService { + + @Resource + private FirstMeetingRepo firstMeetingRepo; + + @Autowired + public FirstMeetingServiceImpl( + @Qualifier("firstMeetingRepo") + FirstMeetingRepo firstMeetingRepo) { + super(firstMeetingRepo, firstMeetingRepo); + System.out.println("FirstMeetingServiceImpl instantiating..."); + } + + @Override + public FirstMeeting getMeetingByIdea(SupervisorIdea idea) { + return firstMeetingRepo.findOne(byIdea(idea)); + } + + public BooleanExpression byIdea(SupervisorIdea idea) { + return QFirstMeeting.firstMeeting.supervisorIdea.eq(idea); + } +} 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..9d2a2b8eff 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 @@ -19,6 +19,7 @@ import se.su.dsv.scipro.data.dataobjects.Employee; 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.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.QSupervisorIdea; @@ -27,6 +28,7 @@ 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.SupervisorIdeaRepo; import se.su.dsv.scipro.springdata.services.ApplicationPeriodService; +import se.su.dsv.scipro.springdata.services.FirstMeetingService; import se.su.dsv.scipro.springdata.services.StudentService; import se.su.dsv.scipro.springdata.services.SupervisorIdeaService; import se.su.dsv.scipro.springdata.services.SupervisorService; @@ -47,6 +49,9 @@ public class SupervisorIdeaServiceImpl extends AbstractQueryService<SupervisorId private SupervisorService supervisorService; @Resource private ApplicationPeriodService applicationPeriodService; + @Resource + private FirstMeetingService firstMeetingService; + private transient Logger logger = Logger.getLogger(SupervisorIdeaService.class); private int MAX_PARTNERS = 1; @@ -190,6 +195,10 @@ public class SupervisorIdeaServiceImpl extends AbstractQueryService<SupervisorId Student s = ip.getStudent(); s.removeIdeaParticipation(ip); } + //Remove first meeting info if existing + if(reloadedIdea.getFirstMeeting()!=null) + firstMeetingService.delete(reloadedIdea.getFirstMeeting().getId()); + reloadedIdea.setFirstMeeting(null); //Erase watson boxes reloadedIdea.setWatson(new Watson()); //Remove application period association @@ -212,6 +221,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 = firstMeetingService.save(meeting); + reloadedIdea.setFirstMeeting(meeting); + } + return reloadedIdea; + } + @Override @Transactional public boolean hasTakenIdeas(User authorUser, boolean confirmed) { @@ -248,7 +272,7 @@ public class SupervisorIdeaServiceImpl extends AbstractQueryService<SupervisorId @Override public Page<SupervisorIdea> findByStatusAndParams(IdeaStatus status, FilterParams params, Pageable pageable) { - return supervisorIdeaRepo.findAll(byStatus(status).and(levelFilter(params.getLevels())), pageable); + return supervisorIdeaRepo.findAll(byStatus(status).and(predicateFromParams(params)), pageable); } @Override @@ -284,6 +308,16 @@ public class SupervisorIdeaServiceImpl extends AbstractQueryService<SupervisorId return supervisorIdeaRepo.countIdeasByAuthorAndStatus(author, status); } + @Override + public Long count(FilterParams params) { + return supervisorIdeaRepo.count(predicateFromParams(params)); + } + + @Override + public Long countByStatusAndParams(IdeaStatus status, FilterParams params) { + return supervisorIdeaRepo.count(byStatus(status).and(predicateFromParams(params))); + } + @Override public boolean authorParticipatingOnIdea(User user) { Student author = studentService.findByUser(user); diff --git a/src/main/java/se/su/dsv/scipro/springdata/services/FirstMeetingService.java b/src/main/java/se/su/dsv/scipro/springdata/services/FirstMeetingService.java new file mode 100644 index 0000000000..ccc671a8c7 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/springdata/services/FirstMeetingService.java @@ -0,0 +1,10 @@ +package se.su.dsv.scipro.springdata.services; + +import se.su.dsv.scipro.match.dataobject.FirstMeeting; +import se.su.dsv.scipro.match.dataobject.SupervisorIdea; + + +public interface FirstMeetingService extends GenericService<FirstMeeting, Long>, QueryService<FirstMeeting, Long> { + + FirstMeeting getMeetingByIdea(SupervisorIdea idea); +} 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..f91dfb3d74 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; @@ -28,6 +29,8 @@ public interface SupervisorIdeaService extends GenericService<SupervisorIdea, Lo Long countByAuthorAndStatus(Student author, IdeaStatus status); Long countByStatus(IdeaStatus status); Long countIdeas(IdeaStatus status, Employee supervisor, ProjectClass pc); + Long count(FilterParams params); + Long countByStatusAndParams(IdeaStatus status, FilterParams params); void saveSupervisorCreatedIdea(SupervisorIdea idea, Employee creator, SortedSet<Student> students); void acceptIdea(SupervisorIdea idea, User mainAuthor, SortedSet<Student> sortedSet); @@ -35,6 +38,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/pages/SupervisorMySupervisorIdeasPage.html b/src/main/java/se/su/dsv/scipro/supervisor/pages/SupervisorMySupervisorIdeasPage.html new file mode 100644 index 0000000000..77666369e8 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/supervisor/pages/SupervisorMySupervisorIdeasPage.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"> +<body> + <wicket:extend> + <div wicket:id="feedback"></div> + <div wicket:id="availabilityPanel" class="append-bottom"></div> + <div class="prepend-top" wicket:id="ideaPanel"></div> + </wicket:extend> +</body> +</html> \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/supervisor/pages/SupervisorMySupervisorIdeasPage.java b/src/main/java/se/su/dsv/scipro/supervisor/pages/SupervisorMySupervisorIdeasPage.java new file mode 100644 index 0000000000..5531be3036 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/supervisor/pages/SupervisorMySupervisorIdeasPage.java @@ -0,0 +1,25 @@ +package se.su.dsv.scipro.supervisor.pages; + + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.panel.FeedbackPanel; + +import se.su.dsv.scipro.security.auth.Authorization; +import se.su.dsv.scipro.security.auth.roles.Roles; +import se.su.dsv.scipro.supervisor.panels.SupervisorAvailabilityPanel; +import se.su.dsv.scipro.supervisor.panels.SupervisorMatchedSupervisorIdeasPanel; + +@Authorization(authorizedRoles={Roles.SYSADMIN}) +public class SupervisorMySupervisorIdeasPage extends AbstractSupervisorProjectIdeaPage { + + private FeedbackPanel feedbackPanel; + + public SupervisorMySupervisorIdeasPage(PageParameters pp) { + super(pp); + add(feedbackPanel = new FeedbackPanel("feedback")); + feedbackPanel.setOutputMarkupId(true); + add(new SupervisorAvailabilityPanel("availabilityPanel", getUser())); + add(new SupervisorMatchedSupervisorIdeasPanel("ideaPanel", getUser())); + + } +} 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/SupervisorMatchedSupervisorIdeasPanel.html b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMatchedSupervisorIdeasPanel.html new file mode 100644 index 0000000000..b26fe1a011 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMatchedSupervisorIdeasPanel.html @@ -0,0 +1,18 @@ +<!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:panel> + <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> + </form> + <div class="span-24 prepend-top" wicket:id="dataPanel"></div> + </wicket:panel> +</body> +</html> \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMatchedSupervisorIdeasPanel.java b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMatchedSupervisorIdeasPanel.java new file mode 100644 index 0000000000..1adbe29e08 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMatchedSupervisorIdeasPanel.java @@ -0,0 +1,164 @@ +package se.su.dsv.scipro.supervisor.panels; + +import java.util.Iterator; + +import org.apache.wicket.ajax.AjaxRequestTarget; +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; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.odlabs.wiquery.ui.dialog.Dialog; +import org.springframework.data.domain.PageRequest; + +import se.su.dsv.scipro.data.dataobjects.Employee; +import se.su.dsv.scipro.data.dataobjects.User; +import se.su.dsv.scipro.datatables.BooleanIconColumn; +import se.su.dsv.scipro.datatables.ClickableTitleColumn; +import se.su.dsv.scipro.datatables.GenericDataPanel; +import se.su.dsv.scipro.icons.ImageObject; +import se.su.dsv.scipro.match.dataobject.Idea.IdeaStatus; +import se.su.dsv.scipro.match.dataobject.SupervisorIdea; +import se.su.dsv.scipro.match.panel.FilterFormProjectClass; +import se.su.dsv.scipro.reusable.SafeLongToIntService; +import se.su.dsv.scipro.springdata.services.GenericService; +import se.su.dsv.scipro.springdata.services.SupervisorIdeaService; +import se.su.dsv.scipro.springdata.services.SupervisorService; + +public class SupervisorMatchedSupervisorIdeasPanel extends Panel { + + @SpringBean + private SupervisorIdeaService ideaService; + @SpringBean + private SupervisorService supervisorService; + private GenericDataPanel<SupervisorIdea> genericDataPanel; + private SupervisorIdeaService.FilterParams params; + private Dialog dialog; + + private static final long serialVersionUID = -9010467449322120267L; + + public SupervisorMatchedSupervisorIdeasPanel(String id, final User supervisor) { + super(id); + FeedbackPanel feedback = new FeedbackPanel("feedback"); + feedback.setOutputMarkupId(true); + add(feedback); + addDialog(); + addDataTable(supervisor, feedback); + add(new FilterForm("form", supervisor)); + } + + private void addDialog() { + dialog = new Dialog("dialog"); + dialog.setModal(true); + dialog.setAutoOpen(false); + dialog.setWidth(450); + dialog.setHeight(600); + dialog.add(new EmptyPanel("dialogPanel")); + add(dialog); + } + + private void addDataTable(final User supervisor, final FeedbackPanel feedback) { + add(genericDataPanel = new GenericDataPanel<SupervisorIdea>("dataPanel") { + + @Override + public int getSize() { + return SafeLongToIntService.safeLongToInt(ideaService.countByStatusAndParams(IdeaStatus.TAKEN, params)); + } + + private static final long serialVersionUID = -4539188306454725307L; + + @Override + public Iterator<SupervisorIdea> getIterator() { + return ideaService.findByStatusAndParams(IdeaStatus.TAKEN, params, new PageRequest(getTable().getCurrentPage(), getTable().getRowsPerPage(), getSort())).iterator(); + } + + @Override + public GenericService<SupervisorIdea, Long> getService() { + return ideaService; + } + + @Override + public String getSortString() { + return "dateCreated"; + } + + @Override + public IColumn[] getColumns() { + IColumn[] columns = new IColumn[5]; + columns[0] = new PropertyColumn<SupervisorIdea>(Model.of("Date"), "dateCreated", "dateCreated"); + columns[1] = new PropertyColumn<SupervisorIdea>(Model.of("Level"), "projectClass", "projectClass"); + columns[2] = new ClickableTitleColumn<SupervisorIdea>(Model.of("Title"), "title", "title") { + private static final long serialVersionUID = 4667741924987868274L; + + @Override + protected void onClick(final IModel<SupervisorIdea> ideaModel, + AjaxRequestTarget target) { + 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); + target.addComponent(getWMC()); + } + + }); + dialog.setTitle("Selected supervisor project idea"); + target.addComponent(dialog); + dialog.open(target); + } + }; + columns[3] = new PropertyColumn<SupervisorIdea>(Model.of("Author(s)"), "ideaParticipations"); + columns[4] = new BooleanIconColumn<SupervisorIdea>(Model.of("First meeting added?"), ImageObject.CHECK, ImageObject.DELETE){ + + private static final long serialVersionUID = -6759283830735306302L; + + @Override + protected boolean booleanValue(IModel<SupervisorIdea> ideaModel) { + return ideaModel.getObject().getFirstMeeting()!=null; + } + + }; + return columns; + } + }); + + } + private class FilterForm extends Form<Void> { + + private static final long serialVersionUID = 6581597176580961782L; + + public FilterForm(String id, User user) { + super(id); + params = new SupervisorIdeaService.FilterParams(); + + //FILTERING ON PROJECT CLASS: + final FilterFormProjectClass levelFilter = new FilterFormProjectClass("levelFilter", null) { + private static final long serialVersionUID = -7758850229259608443L; + + @Override + public void ajaxUpdate(AjaxRequestTarget target) { + if(!getProjectClasses().isEmpty()){ + params.setLevels(getProjectClasses()); + } + target.addComponent(genericDataPanel.getWMC()); + } + + + }; + params.setLevels(levelFilter.getProjectClasses()); + Employee supervisor = supervisorService.findByUser(user); + params.setSupervisor(supervisor); + add(levelFilter); + } + + + } +} 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..9eb5b58c6d 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 @@ -5,9 +5,7 @@ </head> <body> <wicket:panel> - <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..e8a037445c 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 @@ -8,22 +8,21 @@ import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox; 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; import org.apache.wicket.spring.injection.annot.SpringBean; -import org.odlabs.wiquery.ui.dialog.Dialog; import org.springframework.data.domain.PageRequest; import se.su.dsv.scipro.data.dataobjects.Employee; import se.su.dsv.scipro.data.dataobjects.User; import se.su.dsv.scipro.datatables.ClickableIconColumn; -import se.su.dsv.scipro.datatables.ClickableTitleColumn; import se.su.dsv.scipro.datatables.GenericDataPanel; import se.su.dsv.scipro.icons.ImageIcon; import se.su.dsv.scipro.match.dataobject.SupervisorIdea; import se.su.dsv.scipro.match.panel.FilterFormProjectClass; +import se.su.dsv.scipro.reusable.SafeLongToIntService; import se.su.dsv.scipro.springdata.services.GenericService; import se.su.dsv.scipro.springdata.services.SupervisorIdeaService; import se.su.dsv.scipro.springdata.services.SupervisorService; @@ -37,28 +36,19 @@ public class SupervisorProjectIdeaOverviewPanel extends Panel { private SupervisorService supervisorService; private GenericDataPanel<SupervisorIdea> genericDataPanel; private SupervisorIdeaService.FilterParams params; - private Dialog dialog; private static final long serialVersionUID = -9010467449322120267L; public SupervisorProjectIdeaOverviewPanel(String id, final User supervisor) { super(id); - addDialog(); - addDataTable(supervisor); + FeedbackPanel feedback = new FeedbackPanel("feedback"); + feedback.setOutputMarkupId(true); + add(feedback); + addDataTable(supervisor, feedback); add(new FilterForm("form", supervisor)); } - - private void addDialog() { - dialog = new Dialog("dialog"); - dialog.setModal(true); - dialog.setAutoOpen(false); - dialog.setWidth(500); - 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; @@ -68,6 +58,11 @@ public class SupervisorProjectIdeaOverviewPanel extends Panel { return ideaService.findAll(params, new PageRequest(getTable().getCurrentPage(), getTable().getRowsPerPage(), getSort())).iterator(); } + @Override + public int getSize(){ + return SafeLongToIntService.safeLongToInt(ideaService.count(params)); + } + @Override public GenericService<SupervisorIdea, Long> getService() { return ideaService; @@ -83,18 +78,7 @@ public class SupervisorProjectIdeaOverviewPanel extends Panel { IColumn[] columns = new IColumn[7]; columns[0] = new PropertyColumn<SupervisorIdea>(Model.of("Date"), "dateCreated", "dateCreated"); columns[1] = new PropertyColumn<SupervisorIdea>(Model.of("Level"), "projectClass", "projectClass"); - columns[2] = new ClickableTitleColumn<SupervisorIdea>(Model.of("Title"), "title", "title") { - private static final long serialVersionUID = 4667741924987868274L; - - @Override - protected void onClick(IModel<SupervisorIdea> ideaModel, - AjaxRequestTarget target) { - dialog.replace(new SupervisorIdeaDetailsPanel("dialogPanel", ideaModel)); - dialog.setTitle("Selected supervisor project idea"); - target.addComponent(dialog); - dialog.open(target); - } - }; + columns[2] = new PropertyColumn<SupervisorIdea>(Model.of("Title"), "title", "title"); columns[3] = new PropertyColumn<SupervisorIdea>(Model.of("Creator"), "creator.user.lastName", "creator"); columns[4] = new PropertyColumn<SupervisorIdea>(Model.of("Status"), "ideaStatus", "ideaStatus"); columns[5] = new ClickableIconColumn<SupervisorIdea>(Model.of("Edit"), null, ImageIcon.ICON_EDIT) { diff --git a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaTabMenuPanel.java b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaTabMenuPanel.java index 24ef41439e..c505e6fedc 100644 --- a/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaTabMenuPanel.java +++ b/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorProjectIdeaTabMenuPanel.java @@ -10,6 +10,7 @@ import se.su.dsv.scipro.components.menuhighlighting.MenuHighlightSupervisorProje import se.su.dsv.scipro.supervisor.pages.AbstractSupervisorProjectIdeaPage; import se.su.dsv.scipro.supervisor.pages.SupervisorInterestPage; import se.su.dsv.scipro.supervisor.pages.SupervisorMyProjectIdeasPage; +import se.su.dsv.scipro.supervisor.pages.SupervisorMySupervisorIdeasPage; import se.su.dsv.scipro.supervisor.pages.SupervisorProjectIdeaStartPage; public class SupervisorProjectIdeaTabMenuPanel extends AbstractMenuPanel{ @@ -24,6 +25,7 @@ public class SupervisorProjectIdeaTabMenuPanel extends AbstractMenuPanel{ protected List<MenuItem> getItemList() { List<MenuItem> items = new ArrayList<MenuItem>(); items.add(new MenuItem("Supervisor project ideas", SupervisorProjectIdeaStartPage.class, MenuHighlightSupervisorProjectIdea.class)); + items.add(new MenuItem("My matched supervisor project ideas", SupervisorMySupervisorIdeasPage.class)); items.add(new MenuItem("Unmatched student project ideas", SupervisorInterestPage.class)); items.add(new MenuItem("My matched student project ideas", SupervisorMyProjectIdeasPage.class)); return items; 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); + } + } }