Merge branch 'release20120123'

This commit is contained in:
Fredrik Friis 2012-01-23 12:36:09 +09:00
commit d8fb6c5dec
63 changed files with 1140 additions and 321 deletions
pom.xml
resources/db_update_scripts
src
main
java/se/su/dsv/scipro
ProjectStatus
activityplan/panels
admin
components
data/facade
io
match
project
reusable
supervisor
workerthreads
webapp/WEB-INF
test/java/se/su/dsv/scipro

@ -338,7 +338,7 @@
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.1.4</version>
<configuration>
<!-- Container configuration -->
<container>

@ -0,0 +1,35 @@
-- required database changes for the property Match#rejectedBy
ALTER TABLE matchings ADD COLUMN rejectedBy_id bigint(20);
ALTER TABLE matchings ADD CONSTRAINT `FK24A2D416D0C9D7F5` FOREIGN KEY (`rejectedBy_id`) REFERENCES `user` (`id`);
/* The results running the queries above should look exactly like the hibernate generated table below, this can be tested by
running "show create table matchings;" from the command prompt
CREATE TABLE IF NOT EXISTS `matchings` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`dateCreated` datetime NOT NULL,
`lastModified` datetime NOT NULL,
`version` int(11) NOT NULL,
`commentForAdmin` varchar(1024) DEFAULT NULL,
`commentForStudent` varchar(1024) DEFAULT NULL,
`points` int(11) NOT NULL,
`status` varchar(255) DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`createdBy_id` bigint(20) NOT NULL,
`projectIdea_id` bigint(20) NOT NULL,
`supervisor_id` bigint(20) DEFAULT NULL,
`rejectedBy_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK24A2D4169AA5FCB` (`createdBy_id`),
KEY `FK24A2D4164E31D7A1` (`projectIdea_id`),
KEY `FK24A2D416BCA56165` (`supervisor_id`),
KEY `FK24A2D416D0C9D7F5` (`rejectedBy_id`),
CONSTRAINT `FK24A2D416D0C9D7F5` FOREIGN KEY (`rejectedBy_id`) REFERENCES `user` (`id`),
CONSTRAINT `FK24A2D4164E31D7A1` FOREIGN KEY (`projectIdea_id`) REFERENCES `projectIdea` (`id`),
CONSTRAINT `FK24A2D4169AA5FCB` FOREIGN KEY (`createdBy_id`) REFERENCES `user` (`id`),
CONSTRAINT `FK24A2D416BCA56165` FOREIGN KEY (`supervisor_id`) REFERENCES `role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=latin1 |
*/
-- no database changes were required for changing the annotation of ProjectIdea#match from @ManyToOne to @OneToOne

@ -0,0 +1,21 @@
<!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>
<h5 class="peer-title">Project state<span wicket:id="stateofmindHelp" class="right"></span></h5>
<table>
<tr>
<td><img wicket:id="greenBall"></td>
<td>Project completed, state automatically set to green.</td>
</tr>
</table>
<wicket:fragment wicket:id="stateofmindExplanation" >
<p>Indicates the current perceived state of the project according to the authors.</p>
</wicket:fragment>
</wicket:panel>
</body>
</html>

@ -0,0 +1,18 @@
package se.su.dsv.scipro.ProjectStatus;
import org.apache.wicket.markup.html.panel.Panel;
import se.su.dsv.scipro.icons.HelpIconDialog;
import se.su.dsv.scipro.icons.ImageObject;
public class CompletedProjectStatus extends Panel {
private static final long serialVersionUID = 1L;
public CompletedProjectStatus(String id) {
super(id);
add(new ImageObject("greenBall", ImageObject.FORTYEIGHT + ImageObject.LIGHT_GREEN));
add(new HelpIconDialog("stateofmindHelp", "stateofmindExplanation", this, "Project state"));
}
}

@ -18,27 +18,37 @@
</span>
</form>
</div>
<div wicket:id="editDialog">
<div wicket:id="addScheduleEventPanel"></div>
<div wicket:id="eventDialog">
<div wicket:id="eventPanel"></div>
</div>
<button wicket:id="createLink">Create new</button>
<div wicket:id="addDialog">
<div wicket:id="addScheduleEventPanel"></div>
</div>
<!-- <div wicket:id="editDialog"> -->
<!-- <div wicket:id="addScheduleEventPanel"></div> -->
<!-- </div> -->
<!-- <div><a href="#" wicket:id="addFromTemplateLink">add predefined activity plan using an activity plan template&gt;&gt;</a></div> -->
<div><button wicket:id="addFromTemplateLink">add predefined activity plan using an activity plan template</button></div>
<!-- <div><a href="#" wicket:id="createLink">create new activity&gt;&gt;</a></div> -->
<div><button wicket:id="createLink">create new activity</button></div>
<!-- <div><button wicket:id="createLink">create new activity</button></div> -->
<div wicket:id="addDialog">
<div wicket:id="addScheduleEventPanel"></div>
</div>
<!-- <div wicket:id="addDialog"> -->
<!-- <div wicket:id="addScheduleEventPanel"></div> -->
<!-- </div> -->
<div wicket:id="saveAsTemplateDialog">
<div wicket:id="saveAsTemplatePanel"></div>
</div>
<!-- <div wicket:id="saveAsTemplateDialog"> -->
<!-- <div wicket:id="saveAsTemplatePanel"></div> -->
<!-- </div> -->
<!-- <div><a href="#" wicket:id="saveAsTemplateLink">save as activity plan template&gt;&gt;</a></div> -->
<div><button wicket:id="saveAsTemplateLink">save as activity plan template</button></div>
<!-- <div><button wicket:id="saveAsTemplateLink">save as activity plan template</button></div> -->
<div wicket:id=dataViewContainer>
<div>

@ -22,6 +22,7 @@ import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
import org.apache.wicket.markup.html.panel.EmptyPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
@ -52,11 +53,15 @@ public class ActivityPlanPanel extends Panel {
@SpringBean
private ProjectScheduleFacade facade;
private Dialog editEventDialog, addFromTemplateDialog, saveAsTemplateDialog;
private AddScheduleEventsFromTemplatePanel addScheduleEventsFromTemplatePanel;
private SaveAsTemplatePanel saveAsTemplatePanel;
private EditScheduleEventPanel editScheduleEventPanel;
// private Dialog editEventDialog, addFromTemplateDialog, saveAsTemplateDialog;
private Dialog addFromTemplateDialog;
private AddScheduleEventsFromTemplatePanel addScheduleEventsFromTemplatePanel;
// private SaveAsTemplatePanel saveAsTemplatePanel;
// private EditScheduleEventPanel editScheduleEventPanel;
private Dialog eventDialog;
private DataView<ProjectScheduleEvent> dataView;
private WebMarkupContainer dataViewContainer;
private ProjectScheduleEventDataProvider sdp;
@ -64,15 +69,20 @@ public class ActivityPlanPanel extends Panel {
private final User user;
private Label emptyLabel;
private AjaxLink saveAsTemplateLink;
public ActivityPlanPanel(final String id, final Project project, final User user){
super(id);
this.project = project;
this.user = user;
//Setup edit-form
formSetup();
formSetup();
//Setup pop-up dialog
dialogSetup();
dialogSetup();
newDialogSetup();
newButtonSetup();
//Setup data view
dataViewSetup();
//Setup the model and listview for adding checklists
@ -83,8 +93,58 @@ public class ActivityPlanPanel extends Panel {
addModeControls();
//Add navigator
dataViewContainer.add(new PagingNavigator("nav", dataView));
}
private void newDialogSetup(){
eventDialog = new Dialog("eventDialog");
eventDialog.setModal(true);
eventDialog.setAutoOpen(false);
eventDialog.setWidth(500);
eventDialog.setHeight(500);
eventDialog.setOutputMarkupId(true);
add(eventDialog);
eventDialog.add(new EmptyPanel("eventPanel"));
}
private void newButtonSetup(){
AjaxLink<Void> createLink = new AjaxLink("createLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
ProjectScheduleEvent dummy = new ProjectScheduleEvent();
dummy.setDate(new Date());
dummy.setName("new activity");
dummy.setCreator(getUser());
dummy.setProjectSchedule(getProjectSchedule());
EditEventPanel createNewPanel = new EditEventPanel("eventPanel", dummy, true){
@Override
public void onButtonPress(AjaxRequestTarget target) {
eventDialog.close(target);
facade.saveProjectScheduleEvent(getEvent());
target.addComponent(dataViewContainer);
emptyLabel.setVisible(sdp.size()==0);
target.addComponent(emptyLabel);
}
};
eventDialog.replace(createNewPanel);
target.addComponent(eventDialog);
target.addComponent(dataViewContainer);
eventDialog.open(target);
}
};
add(createLink);
}
protected final User getUser(){
return user;
}
@ -118,7 +178,7 @@ public class ActivityPlanPanel extends Panel {
}
};
dateFrom.addOnChangeAjaxBehavior(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
@Override
@ -128,7 +188,7 @@ public class ActivityPlanPanel extends Panel {
}
});
dateTo.addOnChangeAjaxBehavior(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
@Override
@ -137,7 +197,7 @@ public class ActivityPlanPanel extends Panel {
sdp.setDateBoundaries(dateFrom.getModelObject(), dateTo.getModelObject());
}
});
//Add radio button components to radio button control group based on available search-modes
final ProjectScheduleEventDataProvider.SEARCH_MODE[] arr = ProjectScheduleEventDataProvider.SEARCH_MODE.values();
//Java enums are stupid, why can't I just offset this with a named constant like in a "real" language ?
@ -146,35 +206,35 @@ public class ActivityPlanPanel extends Panel {
final Radio<ProjectScheduleEventDataProvider.SEARCH_MODE> radio = new Radio<ProjectScheduleEventDataProvider.SEARCH_MODE>(currentMode.toString(),new Model<ProjectScheduleEventDataProvider.SEARCH_MODE>(currentMode));
modeGroup.add(radio);
radio.add(new AjaxEventBehavior("onchange") {//Implement state change-behavior
private static final long serialVersionUID = 1L;
@Override
protected void onEvent(final AjaxRequestTarget target) {
ProjectScheduleEventDataProvider.SEARCH_MODE selectedMode = radio.getModelObject();
dateSelection.setVisible(false);
switch(selectedMode){
case PROJECT_BETWEEN:
dateSelection.setVisible(true);
sdp.setDateBoundaries(dateFrom.getModelObject(), dateTo.getModelObject());
break;
case ALL:
sdp.setDateBoundaries(null,null);
break;
case PROJECT_ALL:
sdp.setDateBoundaries(null,null);
break;
case PROJECT_PAST:
sdp.setDateBoundaries(null,new Date());
break;
case PROJECT_FUTURE:
sdp.setDateBoundaries(new Date(),null);
break;
}
modeGroup.setModelObject(currentMode);
sdp.setSearchMode(currentMode);
target.addComponent(dataViewContainer);
target.addComponent(dateSelection);
target.addComponent(modeForm);
}
private static final long serialVersionUID = 1L;
@Override
protected void onEvent(final AjaxRequestTarget target) {
ProjectScheduleEventDataProvider.SEARCH_MODE selectedMode = radio.getModelObject();
dateSelection.setVisible(false);
switch(selectedMode){
case PROJECT_BETWEEN:
dateSelection.setVisible(true);
sdp.setDateBoundaries(dateFrom.getModelObject(), dateTo.getModelObject());
break;
case ALL:
sdp.setDateBoundaries(null,null);
break;
case PROJECT_ALL:
sdp.setDateBoundaries(null,null);
break;
case PROJECT_PAST:
sdp.setDateBoundaries(null,new Date());
break;
case PROJECT_FUTURE:
sdp.setDateBoundaries(new Date(),null);
break;
}
modeGroup.setModelObject(currentMode);
sdp.setSearchMode(currentMode);
target.addComponent(dataViewContainer);
target.addComponent(dateSelection);
target.addComponent(modeForm);
}
});
}
//Add components to hierarchy
@ -183,46 +243,48 @@ public class ActivityPlanPanel extends Panel {
add(modeForm);
}
private void dialogSetup(){
//Edit dialog
editEventDialog = new Dialog("editDialog");
editEventDialog.setModal(true);
editEventDialog.setAutoOpen(false);
editEventDialog.setWidth(500);
editEventDialog.setHeight(500);
editEventDialog.add(editScheduleEventPanel);
add(editEventDialog);
//Add from template dialog
addFromTemplateDialog = new Dialog("addDialog");
addFromTemplateDialog.setModal(true);
addFromTemplateDialog.setAutoOpen(false);
addFromTemplateDialog.setWidth(300);
addFromTemplateDialog.setHeight(200);
addFromTemplateDialog.add(addScheduleEventsFromTemplatePanel);
add(addFromTemplateDialog);
//Add save as template dialog
saveAsTemplateDialog = new Dialog("saveAsTemplateDialog");
saveAsTemplateDialog.setModal(true);
saveAsTemplateDialog.setAutoOpen(false);
saveAsTemplateDialog.setWidth(400);
saveAsTemplateDialog.setHeight(300);
saveAsTemplateDialog.add(saveAsTemplatePanel);
add(saveAsTemplateDialog);
// editEventDialog = new Dialog("editDialog");
// editEventDialog.setModal(true);
// editEventDialog.setAutoOpen(false);
// editEventDialog.setWidth(500);
// editEventDialog.setHeight(500);
// editEventDialog.add(editScheduleEventPanel);
//
// add(editEventDialog);
//Add from template dialog
addFromTemplateDialog = new Dialog("addDialog");
addFromTemplateDialog.setModal(true);
addFromTemplateDialog.setAutoOpen(false);
addFromTemplateDialog.setWidth(300);
addFromTemplateDialog.setHeight(200);
addFromTemplateDialog.add(addScheduleEventsFromTemplatePanel);
add(addFromTemplateDialog);
// //Add save as template dialog
// saveAsTemplateDialog = new Dialog("saveAsTemplateDialog");
// saveAsTemplateDialog.setModal(true);
// saveAsTemplateDialog.setAutoOpen(false);
// saveAsTemplateDialog.setWidth(400);
// saveAsTemplateDialog.setHeight(300);
// saveAsTemplateDialog.add(saveAsTemplatePanel);
// add(saveAsTemplateDialog);
}
private void dataViewSetup(){
//Config provider
dataViewContainer = new WebMarkupContainer("dataViewContainer");
//Add info for the user should there be no events to display.
emptyLabel = new Label("emptyLabel", "No activities to show.");
dataViewContainer.add(emptyLabel);
emptyLabel.setOutputMarkupId(true); //Needs to be AJAX-enabled.
sdp = new ProjectScheduleEventDataProvider(getProject());
emptyLabel.setVisible(sdp.size()==0); //Rule for the empty label
sdp.setSearchMode(ProjectScheduleEventDataProvider.SEARCH_MODE.PROJECT_ALL);
//Add data view
dataView = new DataView<ProjectScheduleEvent>("projectScheduleEvents", sdp) {
@ -242,15 +304,28 @@ public class ActivityPlanPanel extends Panel {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
editScheduleEventPanel.setDataFromEvent(event);
editScheduleEventPanel.setEditable(false);
target.addComponent(editScheduleEventPanel);
editEventDialog.open(target);
EditEventPanel createNewPanel = new EditEventPanel("eventPanel", event, false){
@Override
public void onButtonPress(AjaxRequestTarget target) {
eventDialog.close(target);
}
};
eventDialog.replace(createNewPanel);
target.addComponent(eventDialog);
target.addComponent(dataViewContainer);
eventDialog.open(target);
}
};
item.add(viewEventLink);
viewEventLink.add(new Label("name",event.getName()));
checkListLink.add(new Label("linkName",event.getCheckList()!=null?event.getCheckList().getName():"n/a"));
if(event.getFileUpload() != null){
item.add(new FileViewDeletePanel("fileUpload",event.getFileUpload(),new FileViewDeletePanel.FileDeleteStrategy(){
@ -267,17 +342,17 @@ public class ActivityPlanPanel extends Panel {
item.add(new ProjectScheduleEventUploadForm(event).createDefaultWrapperPanel("fileUpload"));
else
item.add(new Label("fileUpload","n/a"));
item.add(checkListLink);
item.add(checkListLabel);
if(event.getCheckList() == null){
checkListLink.setVisible(false);
}else{
checkListLabel.setVisible(false);
}
boolean isSupervisorChecklist = false;
if (event.getCheckList()!=null && event.getCheckList().getCategories() != null){
for (ChecklistCategory cc : event.getCheckList().getCategories()){
@ -290,18 +365,34 @@ public class ActivityPlanPanel extends Panel {
checkListLabel.setVisible(true);
}
}
//add edit/delete links
item.add(new AjaxLink<Void>("editEventLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
editScheduleEventPanel.setDataFromEvent(event);
editScheduleEventPanel.setEditable(true);
target.addComponent(editScheduleEventPanel);
editEventDialog.open(target);
EditEventPanel createNewPanel = new EditEventPanel("eventPanel", event, true){
@Override
public void onButtonPress(AjaxRequestTarget target) {
eventDialog.close(target);
facade.saveProjectScheduleEvent(getEvent());
target.addComponent(dataViewContainer);
emptyLabel.setVisible(sdp.size()==0);
target.addComponent(emptyLabel);
}
};
eventDialog.replace(createNewPanel);
target.addComponent(eventDialog);
target.addComponent(dataViewContainer);
eventDialog.open(target);
}
@Override
public boolean isVisible(){
@ -316,7 +407,7 @@ public class ActivityPlanPanel extends Panel {
emptyLabel.setVisible(sdp.size()==0);
target.addComponent(emptyLabel);
target.addComponent(dataViewContainer);
target.addComponent(saveAsTemplateLink);
// target.addComponent(saveAsTemplateLink);
}
@Override
public boolean isVisible(){
@ -328,92 +419,94 @@ public class ActivityPlanPanel extends Panel {
item.add(deleteEventLink);
}
};
dataViewContainer.setOutputMarkupId(true);
dataViewContainer.add(dataView);
add(dataViewContainer);
dataView.setItemsPerPage(10);
}
private void formSetup(){
editScheduleEventPanel = new EditScheduleEventPanel("addScheduleEventPanel", (canLinkToCheckLists()?getProject().getCheckLists():null)){
private static final long serialVersionUID = 1L;
@Override
public void handleSubmit(ProjectScheduleEvent event, AjaxRequestTarget target){
facade.saveProjectScheduleEvent(event);
editEventDialog.close(target);
target.addComponent(dataViewContainer);
emptyLabel.setVisible(sdp.size()==0);
target.addComponent(emptyLabel);
}
};
editScheduleEventPanel.setOutputMarkupId(true);
//Add create link
add(new AjaxLink<Void>("createLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
ProjectScheduleEvent dummy = new ProjectScheduleEvent();
dummy.setDate(new Date());
dummy.setName("new activity");
dummy.setCreator(getUser());
dummy.setProjectSchedule(getProjectSchedule());
editScheduleEventPanel.setDataFromEvent(dummy);
editScheduleEventPanel.setEditable(true);
target.addComponent(editScheduleEventPanel);
target.addComponent(dataViewContainer);
editEventDialog.open(target);
}
});
//Add template selector
final List<ScheduleTemplate> availableTemplates = facade.getAvailableTemplates(getProject());
addScheduleEventsFromTemplatePanel = new AddScheduleEventsFromTemplatePanel("addScheduleEventPanel",availableTemplates){
private static final long serialVersionUID = 1L;
@Override
public void handleSubmit(final ScheduleTemplate template, final Date fromDate){
facade.addProjectScheduleEventsFromTemplate(getProjectSchedule(), template, getUser(), fromDate);
}
};
addScheduleEventsFromTemplatePanel.setOutputMarkupId(true);
//Add from template link
add(new AjaxLink<Void>("addFromTemplateLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
target.addComponent(addScheduleEventsFromTemplatePanel);
addFromTemplateDialog.open(target);
}
@Override
public boolean isVisible(){
return (canAddFromTemplate() && availableTemplates.size() > 0);//only show if there are templates to use
}
});
//Add save as template panel
saveAsTemplatePanel = new SaveAsTemplatePanel("saveAsTemplatePanel"){
private static final long serialVersionUID = 1L;
@Override
public void handleSubmit(final String name, final String description){
facade.createTemplateFromSchedule(getProjectSchedule(), getUser(), getProject().getProjectClass(), name, description);
}
};
saveAsTemplatePanel.setOutputMarkupId(true);
//Save as template link
saveAsTemplateLink = new AjaxLink<Void>("saveAsTemplateLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
target.addComponent(addScheduleEventsFromTemplatePanel);
saveAsTemplateDialog.open(target);
}
@Override
public boolean isVisible(){
return (canSaveAsTemplate() && getProject().getProjectSchedule() != null && sdp.size() > 0);//only show if there is a schedule with events
}
};
add(saveAsTemplateLink);
// editScheduleEventPanel = new EditScheduleEventPanel("addScheduleEventPanel", (canLinkToCheckLists()?getProject().getCheckLists():null)){
// private static final long serialVersionUID = 1L;
// @Override
// public void handleSubmit(ProjectScheduleEvent event, AjaxRequestTarget target){
// facade.saveProjectScheduleEvent(event);
// editEventDialog.close(target);
// target.addComponent(dataViewContainer);
// emptyLabel.setVisible(sdp.size()==0);
// target.addComponent(emptyLabel);
// }
//
// };
// editScheduleEventPanel.setOutputMarkupId(true);
// //Add create link
// add(new AjaxLink<Void>("createLink"){
// private static final long serialVersionUID = 1L;
// @Override
// public void onClick(AjaxRequestTarget target) {
// ProjectScheduleEvent dummy = new ProjectScheduleEvent();
// dummy.setDate(new Date());
// dummy.setName("new activity");
// dummy.setCreator(getUser());
// dummy.setProjectSchedule(getProjectSchedule());
// editScheduleEventPanel.setDataFromEvent(dummy);
// editScheduleEventPanel.setEditable(true);
// target.addComponent(editScheduleEventPanel);
// target.addComponent(dataViewContainer);
// editEventDialog.open(target);
// }
// });
//Add template selector
final List<ScheduleTemplate> availableTemplates = facade.getAvailableTemplates(getProject());
addScheduleEventsFromTemplatePanel = new AddScheduleEventsFromTemplatePanel("addScheduleEventPanel",availableTemplates){
private static final long serialVersionUID = 1L;
@Override
public void handleSubmit(final ScheduleTemplate template, final Date fromDate){
facade.addProjectScheduleEventsFromTemplate(getProjectSchedule(), template, getUser(), fromDate);
}
};
addScheduleEventsFromTemplatePanel.setOutputMarkupId(true);
//Add from template link
add(new AjaxLink<Void>("addFromTemplateLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
target.addComponent(addScheduleEventsFromTemplatePanel);
addFromTemplateDialog.open(target);
}
@Override
public boolean isVisible(){
return (canAddFromTemplate() && availableTemplates.size() > 0);//only show if there are templates to use
}
});
//Add save as template panel
// saveAsTemplatePanel = new SaveAsTemplatePanel("saveAsTemplatePanel"){
// private static final long serialVersionUID = 1L;
// @Override
// public void handleSubmit(final String name, final String description){
// facade.createTemplateFromSchedule(getProjectSchedule(), getUser(), getProject().getProjectClass(), name, description);
// }
// };
// saveAsTemplatePanel.setOutputMarkupId(true);
// //Save as template link
// saveAsTemplateLink = new AjaxLink<Void>("saveAsTemplateLink"){
// private static final long serialVersionUID = 1L;
// @Override
// public void onClick(AjaxRequestTarget target) {
// target.addComponent(addScheduleEventsFromTemplatePanel);
// saveAsTemplateDialog.open(target);
// }
// @Override
// public boolean isVisible(){
// return (canSaveAsTemplate() && getProject().getProjectSchedule() != null && sdp.size() > 0);//only show if there is a schedule with events
// }
// };
// add(saveAsTemplateLink);
}
private void addSortControls(){
//Specify wanted sort specifier fields
@ -469,15 +562,15 @@ public class ActivityPlanPanel extends Panel {
facade.setScheduleEventUpload(desc, getUser(), event);
}
}
private ProjectSchedule getProjectSchedule(){
ProjectSchedule schedule = getProject().getProjectSchedule();
if(schedule == null)
schedule = facade.retrieveProjectSchedule(getProject());
return schedule;
}
//here comes the methods to be overriden by subclasses
protected boolean canLinkToCheckLists() {
return false;
@ -488,11 +581,11 @@ public class ActivityPlanPanel extends Panel {
protected boolean canAddFromTemplate(){
return false;
}
protected BookmarkablePageLink<Void> getBookmarkablePageLink(PageParameters pp){
return new BookmarkablePageLink<Void>("checkListLink", ProjectViewCheckListPage.class, pp);
}
protected boolean willRenderDeleteLink(ProjectScheduleEvent event){
return event.getCreator().equals(getUser());
}

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<form wicket:id="editForm">
<div><strong>Title:</strong><br/><input type="text" wicket:id="nameField"/></div>
<div><strong>Description:</strong><br/><textarea wicket:id="descriptionArea"></textarea></div>
<div><strong>Date:</strong><br/><span wicket:id="date"></span></div>
<div><strong>Checklist:</strong><br/><select wicket:id="checklist"></select></div>
<div><strong>Hand-in required:</strong><br/><input type="checkbox" wicket:id="handin" /></div>
<div><button wicket:id="saveButton">Save</button></div>
</form>
</wicket:panel>
</body>
</html>

@ -0,0 +1,93 @@
package se.su.dsv.scipro.activityplan.panels;
import java.util.Date;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.components.CustomDateTimeField;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dataobjects.CheckList;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
public abstract class EditEventPanel extends Panel {
private static final long serialVersionUID = 1L;
private EditForm editForm;
public abstract void onButtonPress(AjaxRequestTarget target);
public EditEventPanel(String id, ProjectScheduleEvent event, boolean editable) {
super(id);
editForm = new EditForm("editForm", event, editable);
add(editForm);
}
public ProjectScheduleEvent getEvent(){
return editForm.getEvent();
}
private class EditForm extends Form<Void> {
private static final long serialVersionUID = 1L;
@SpringBean
private ProjectDao projectDao;
private ProjectScheduleEvent event;
public EditForm(String id, ProjectScheduleEvent event, boolean editable) {
super(id);
this.event=event;
add(new TextField("nameField", new PropertyModel<String>(event, "name")).setEnabled(editable));
add(new TextArea("descriptionArea", new PropertyModel<String>(event, "description")).setEnabled(editable));
add(new CustomDateTimeField("date", new PropertyModel<Date>(event, "date")).setEnabled(editable));
Project p = projectDao.reLoad(event.getProjectSchedule().getProject());
DropDownChoice checklistDropDown = new DropDownChoice<CheckList>("checklist", new PropertyModel<CheckList>(event, "checkList"), p.getCheckLists());
// checklistDropDown.setVisible(p.getCheckLists()!=null && p.getCheckLists().size()>0);
checklistDropDown.setEnabled(editable);
add(checklistDropDown);
// checklistDropDown = new DropDownChoice<CheckList>("checklist",new PropertyModel<CheckList>(formWrapper.getModelObject(),"checkList"),checkLists);
// checklistDropDown.setVisible(checkLists.size()>0);
// checklistDropDown.setChoiceRenderer(new ChoiceRenderer<CheckList>(){
// private static final long serialVersionUID = 1L;
// @Override
// public Object getDisplayValue(final CheckList checklist){
// if(checklist == null)
// return "No checklist";
// else
// return (checklist.getName());
// }
// });
add(new CheckBox("handin", new PropertyModel(event, "uploadRequired")).setEnabled(editable));
add(new AjaxButton("saveButton") { //button to click for performing overriden method
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
onButtonPress(target);
}
});
}
public ProjectScheduleEvent getEvent(){
return event;
}
}
}

@ -38,12 +38,12 @@ public abstract class AbstractAdminMatchPage extends AbstractAdminPage {
protected List<MenuItem> getItemList() {
final List<MenuItem> items = new ArrayList<MenuItem>();
items.add(new MenuItem("Project ideas", AdminManageProjectIdeaPage.class));
items.add(new MenuItem("Author limits", AdminMatchSettingsPerProjectClassPage.class));
//items.add(new MenuItem("Author limits", AdminMatchSettingsPerProjectClassPage.class)); not implemented, commented out
items.add(new MenuItem("Automatic match", AutomaticMatchPage.class));
items.add(new MenuItem("Manage keywords", AdminKeywordPage.class));
items.add(new MenuItem("Student exemptions", AdminExemptionPage.class));
items.add(new MenuItem("Supervisor settings", AdminManageMatchSupervisorPage.class));
items.add(new MenuItem("Application Periods", AdminManageMatchPeriodsPage.class));
items.add(new MenuItem("Application periods", AdminManageMatchPeriodsPage.class));
return items;
}

@ -6,14 +6,18 @@
<!-- Edit/add dialog -->
<div wicket:id="dialog">
<div wicket:id="dialogContent"></div>
</div>
<div class="info-box rounded-box">
Use this page to grant and remove exemptions to Bachelor level students to write their thesis alone.
Don't forget to write a comment describing the reason why the exemption was granted.
</div>
<div>
<label for="search">Search:</label> <input type="text" class="text"
id="search" wicket:id="searchField" />
<label for="search">Search on student or administrators name: </label>
<input type="text" class="text" id="search" wicket:id="searchField" />
</div>
<div class="margin">
<a href=# wicket:id="createLink"><img
wicket:id="addIcon" alt="" /> Grant exemption</a>
wicket:id="addIcon" alt="" /> Grant new exemption</a>
<div wicket:id="container">
<table class="rounded-corner">

@ -67,7 +67,7 @@ public class AdminExemptionPanel extends Panel {
dialog.add(new EmptyPanel("dialogContent"));
dialog.setWidth(500);
dialog.setHeight(360);
dialog.setHeight(380);
add(dialog);
AjaxLink<Void> createLink = new AjaxLink<Void>("createLink"){

@ -3,11 +3,15 @@
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<div><b>Unit</b></div>
<h5 class="peer-title">Manage unit keywords</h5>
<div class="info-box rounded-box">
Unit keywords are being imported from remote system. If you rename a unit and the old name is still
available on the remote system, both units will exist in Scipro after the next import.
</div>
<div wicket:id="manageUnitKeyword"></div>
<div><b>Area</b></div>
<h5 class="peer-title">Manage research area keywords</h5>
<div wicket:id="manageAreaKeyword"></div>
<div><b>Word</b></div>
<h5 class="peer-title">Manage regular keywords</h5>
<div wicket:id="manageWordKeyword"></div>
</wicket:extend>
</body>

@ -4,9 +4,14 @@
<body>
<wicket:panel>
<div class="margin">
<div class="info-box rounded-box">
This page is used for running the project ideas that are unmatched through the algorithm to produce matches. If the matches are good, they can be suggested to supervisors.
If the matches are not satisfactory, change the algorithm settings and run the algorithm again. You can run it as many times as you like before suggesting the matches to supervisors.
</div>
<form wicket:id="matchingForm">
<form wicket:id="weightsForm">
<table>
<tr><td colspan="3">Algorithm settings:</td></tr>
<tr>
<td>Keyword points: <select wicket:id="keywordPoints"></select></td>
<td>Research area points: <select wicket:id="researchAreaPoints"></select></td>

@ -12,6 +12,7 @@
<div>Export project (id): <input type="text" wicket:id="exportProjectId"/></div>
<div>Include linked projects (only applies when importing users): <input type="checkbox" wicket:id="includeLinkedProjects"/></div>
<div>Import all supervisors: <input type="checkbox" wicket:id="importSupervisors"/></div>
<div>Import attached units to supervisors: <input type="checkbox" wicket:id="importSupervisorUnits" /></div>
<div><input type="submit"/></div>
</form>
</wicket:enclosure>

@ -53,6 +53,7 @@ public class ManualImportExportPanel extends Panel {
final String userNameIn = params.getImportUserName();
final long userIdIn = params.getImportUserId();
final boolean importSupervisors = params.isImportSupervisors();
final boolean importSupervisorUnits = params.isImportSupervisorUnits();
final long projectIdIn = params.getImportProjectId();
final String projectTitleIn = params.getImportProjectTitle();
final long projectIdOut = params.getExportProjectId();
@ -87,6 +88,16 @@ public class ManualImportExportPanel extends Panel {
setMessage("Failed to import supervisors from "+getRemoteUrl()+", error: "+eie.getWrappedErrorCode());
}
}
if(importSupervisorUnits){
logger.debug("Importing attached units for supervisors");
try {
externalImporter.importSupervisorUnits();
setMessage("Successfully imported attached units to supervisors from " + getRemoteUrl());
} catch (final ExternalImportException eie) {
logger.warn("Caught error while importing units to supervisors from remote system: "+eie.getMessage());
setMessage("Failed to import units from "+getRemoteUrl()+", error: "+eie.getWrappedErrorCode());
}
}
if(projectIdIn > 0){
logger.debug("Attempting remote import of project: "+projectIdIn);
try{
@ -121,6 +132,7 @@ public class ManualImportExportPanel extends Panel {
importExportForm.add(new TextField<Long>("exportProjectId"));
importExportForm.add(new CheckBox("includeLinkedProjects"));
importExportForm.add(new CheckBox("importSupervisors"));
importExportForm.add(new CheckBox("importSupervisorUnits"));
importExportForm.setVisible(hasRemote());
}
private boolean hasRemote(){
@ -138,6 +150,7 @@ public class ManualImportExportPanel extends Panel {
private String importUserName;
private long importUserId;
private boolean importSupervisors;
private boolean importSupervisorUnits;
private long importProjectId;
private String importProjectTitle;
private long exportProjectId;
@ -172,6 +185,12 @@ public class ManualImportExportPanel extends Panel {
public void setImportSupervisors(boolean importSupervisors) {
this.importSupervisors = importSupervisors;
}
public boolean isImportSupervisorUnits() {
return importSupervisorUnits;
}
public void setImportSupervisorUnits(boolean importSupervisorUnits) {
this.importSupervisorUnits = importSupervisorUnits;
}
public long getImportUserId() {
return importUserId;
}

@ -9,7 +9,7 @@
<a href="#" wicket:id="watsonLink">Project idea details</a>
|
<a href="#" wicket:id="actionLink">Actions</a>
<div wicket:id="mainPanel"></div>
<div class="prepend-top" wicket:id="mainPanel"></div>
<!-- </div> -->
</wicket:panel>
</body>

@ -7,7 +7,7 @@
<div wicket:id="dialogContent"></div>
</div>
<a href=# wicket:id="createLink"><img
wicket:id="addIcon" alt="" />Create Keyword</a>
wicket:id="addIcon" alt="" />Create new keyword</a>
<form>
<table wicket:id="table" class="rounded-corner">
<thead>

@ -53,8 +53,8 @@ public class ManageKeywordPanel extends Panel {
dialog = new Dialog("editDialog");
dialog.setModal(true);
dialog.setAutoOpen(false);
dialog.setWidth(500);
dialog.setHeight(500);
dialog.setWidth(400);
dialog.setHeight(225);
dialog.add(new EmptyPanel("dialogContent"));
dialog.setOutputMarkupId(true);

@ -8,15 +8,15 @@
If you want to match and suggest this idea to a supervisor or reviewer manually, you can do so.
</div>
<div wicket:id="manualMatchPanel"></div>
<div>
<div class="prepend-top">
If this project idea is poorly written, it should be sent back to the authors for rewriting.
</div>
<button wicket:id="sendBackButton">Send back to author(s)</button>
<div>
<div class="prepend-top">
If this project idea has been suggested to a supervisor that has not answered for very long, it can be rematched and suggested to some other supervisor.
</div>
<button wicket:id="rematchButton">Rematch project idea</button>
<div>
<div class="prepend-top">
If this project idea will not be carried out for whatever reason, it can be canceled.
</div>
<button wicket:id="cancelButton">Cancel the project idea</button>

@ -32,8 +32,7 @@ public class ProjectIdeaActionPanel extends Panel {
@Override
public void onSubmit() {
matchModel.getObject().setStatus(Status.REFUSED);
matchDao.changeStatus(SciProSession.get().getUser(), matchModel.getObject(), null);
matchDao.changeStatus(SciProSession.get().getUser(), matchModel.getObject(), Status.REFUSED);
}
});
@ -45,8 +44,7 @@ public class ProjectIdeaActionPanel extends Panel {
@Override
public void onSubmit() {
matchModel.getObject().setStatus(Status.UNMATCHED);
matchDao.changeStatus(SciProSession.get().getUser(), matchModel.getObject(), null);
matchDao.changeStatus(SciProSession.get().getUser(), matchModel.getObject(), Status.UNMATCHED);
}
});
@ -58,8 +56,7 @@ public class ProjectIdeaActionPanel extends Panel {
@Override
public void onSubmit() {
matchModel.getObject().setStatus(Status.REJECTED);
matchDao.changeStatus(SciProSession.get().getUser(), matchModel.getObject(), null);
matchDao.changeStatus(SciProSession.get().getUser(), matchModel.getObject(), Status.REJECTED);
}
});
add(form);

@ -52,7 +52,8 @@ public class CustomDateTimeField extends FormComponentPanel<Date> {
super(id, model);
setType(Date.class);
date = new MutableDateTime();
// date = new MutableDateTime();
date = new MutableDateTime(model.getObject());
initDateField();
initHoursField();

@ -1,5 +1,6 @@
package se.su.dsv.scipro.data.facade;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
@ -16,6 +17,8 @@ import se.su.dsv.scipro.data.dataobjects.CheckListTemplate;
import se.su.dsv.scipro.data.dataobjects.ChecklistCategory;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.data.enums.StateOfMind;
@Component
public class ProjectFacade {
@ -34,6 +37,16 @@ public class ProjectFacade {
@Autowired
private CheckListTemplateDao checklistTemplateDao;
public void completedProjectStatus(Project project){
if (project!=null){
project = projectDao.reLoad(project);
if (project.getProjectStatus().equals(ProjectStatus.COMPLETED) && !project.getStateOfMind().equals(StateOfMind.FINE)){
project.setStateOfMind(StateOfMind.FINE);
project.setStateOfMindDate(new Date());
project = projectDao.save(project);
}
}
}
public void generateChecklists(Project project){
List<CheckListTemplate> templates;

@ -1,15 +1,20 @@
package se.su.dsv.scipro.data.facade;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import se.su.dsv.scipro.data.dataobjects.Employee;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.exceptions.RenderingSafeException;
import se.su.dsv.scipro.match.dao.interfaces.MatchDao;
import se.su.dsv.scipro.match.dao.interfaces.ProjectIdeaDao;
import se.su.dsv.scipro.match.dao.interfaces.ProjectIdeaDao.Params;
import se.su.dsv.scipro.match.dao.interfaces.SupervisorDao;
import se.su.dsv.scipro.match.dataobject.ApplicationPeriod;
import se.su.dsv.scipro.match.dataobject.ProjectIdea;
@Service
@ -40,5 +45,50 @@ public class ProjectIdeaFacade {
return idea;
}
/**
* @author fred
*
* Authors are not supposed to be able to submit multiple project ideas during the same period. This method takes a user and
* a list of (the current) application periods and loops through them to check if the user has already submitted or is already
* included in a project idea collected during the application periods inside the list. The method is used to hide the submit
* new project idea link for such users, as to make it impossible for them to submit new project ideas if they have already
* submitted or are already included in a project idea collected during the supplied periods. NOTE that this does not completely
* prevent a user ending up with more than one project idea, as two other users can still add the same user as partner into two
* different project ideas.
*
* @param u
* @param periodList
* @return
*/
@Transactional
public boolean projectIdeaAlreadySubmittedThisPeriod(User u, List<ApplicationPeriod> periodList){
System.out.println("Method called");
if (u == null)
throw new RenderingSafeException(new UnsupportedOperationException("Unable to recieve null user."));
if (periodList ==null)
throw new RenderingSafeException(new UnsupportedOperationException("Unable to recieve null list."));
if (periodList.size()==0)//if no period is open, the student cant submit an idea anyway
return false;
else {
System.out.println("Else block reached");
for (ApplicationPeriod ap : periodList){
System.out.println("Looping through ap");
ProjectIdeaDao.Params params = new Params();
params.setSubmittedAfter(ap.getStartDate());
params.setSubmittedBefore(ap.getEndDate());
for (ProjectIdea pi : projectIdeaDao.findProjectIdeas(params)){
System.out.println("Looping through pi");
System.out.println(pi.getTitle());
for (Student s : pi.getAuthors()){
if (s.getUser().equals(u)){
System.out.println("returning true");
return true;
}
}
}
}
return false;
}
}
}

@ -12,5 +12,6 @@ public interface ExternalImporter {
void importUsersOfRole(final Roles role,boolean includeLinkedEntities) throws ExternalImportException;
void importProject(final long externalIdentifier) throws ExternalImportException;
void importProjects(final String matchingTitle) throws ExternalImportException;
void importSupervisorUnits() throws ExternalImportException;
boolean supportsRemoteOperations();
}

@ -76,6 +76,37 @@ public abstract class AbstractDtoResponseHandler implements DtoResponseHandler {
logger.warn("Returning empty project collection wrapper for respose '"+jsonProjectCollection+"'");
return new ProjectDTOCollectionWrapper();
}
/**
* Attempts to treat input as a ProjectDTOCollectionWrapper, returns the empty wrapper if unable to extract data.
* @param jsonUserCollectionString
* @return
*/
protected final UnitDTOCollectionWrapper asUnitCollection(final String jsonUnitCollection){
//Treat as raw array
try{
final Type collectionType = new TypeToken<Collection<UnitDTO>>(){}.getType();
final Collection<UnitDTO> collection = parseTo(jsonUnitCollection,collectionType);
final UnitDTOCollectionWrapper wrapper = new UnitDTOCollectionWrapper(collection);
return wrapper;
}catch(final JsonParseException jpe){
logger.debug("Attempting to treat response '"+jsonUnitCollection+"' as a raw array failed.");
}
//If that fails, treat as regular project
{
final UnitDTO unitDTO = parseTo(jsonUnitCollection, UnitDTO.class);
if(unitDTO != null){
final UnitDTOCollectionWrapper wrapper = new UnitDTOCollectionWrapper();
wrapper.getUnits().add(unitDTO);
return wrapper;
}else{
logger.debug("Attempting to treat response '"+jsonUnitCollection+"' as a single project failed.");
}
}
logger.warn("Returning empty project collection wrapper for respose '"+jsonUnitCollection+"'");
return new UnitDTOCollectionWrapper();
}
/**
* Attempts to treat input as a UserDTO, returns null if unable to extract data.
* @param jsonUserString

@ -0,0 +1,15 @@
package se.su.dsv.scipro.io.dto;
import java.util.HashSet;
import java.util.Set;
public class SupervisorDTO {
public long id;
public String firstName, lastName, email;
public Set<UsernameDTO> usernames = new HashSet<UsernameDTO>();
public SupervisorDTO() {
}
}

@ -0,0 +1,43 @@
package se.su.dsv.scipro.io.dto;
import java.util.HashSet;
import java.util.Set;
public class UnitDTO {
public long id;
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<UnitDTO> subunits = new HashSet<UnitDTO>();
public Set<SupervisorDTO> supervisors = new HashSet<SupervisorDTO>();
public UnitDTO(){}
@Override
public int hashCode(){
final int w = 31;
int result = 17;
result = w * result + (getName()==null?0:getName().hashCode());
return result;
}
@Override
public boolean equals(Object o){
if(o==this)
return true;
if(!(o instanceof UnitDTO))
return false;
final UnitDTO other = (UnitDTO)o;
return ((getName()==null?other.getName()==null:getName().equals(other.getName())));
}
}

@ -0,0 +1,30 @@
package se.su.dsv.scipro.io.dto;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
//Collection-wrapper for UnitDTO objects
public class UnitDTOCollectionWrapper implements Iterable<UnitDTO>{
private final List<UnitDTO> units = new ArrayList<UnitDTO>();
public UnitDTOCollectionWrapper(){
}
public UnitDTOCollectionWrapper(Collection<UnitDTO> source){
this.units.addAll(source);
}
public List<UnitDTO> getUnits() {
return units;
}
public int size(){
return units.size();
}
@Override
public String toString(){
return ("listOf "+units.size()+" units :" + units.toString());
}
@Override
public Iterator<UnitDTO> iterator() {
return units.iterator();
}
}

@ -41,9 +41,15 @@ import se.su.dsv.scipro.io.dto.ProjectDTO;
import se.su.dsv.scipro.io.dto.ProjectParticipantDTO;
import se.su.dsv.scipro.io.dto.ProjectParticipantDTO.EXTERNAL_PROJECT_ROLE;
import se.su.dsv.scipro.io.dto.ProjectParticipantDTO.LOCAL_PROJECT_ROLE;
import se.su.dsv.scipro.io.dto.SupervisorDTO;
import se.su.dsv.scipro.io.dto.UnitDTO;
import se.su.dsv.scipro.io.dto.UserDTO;
import se.su.dsv.scipro.io.dto.UserRoleDTO;
import se.su.dsv.scipro.io.dto.UsernameDTO;
import se.su.dsv.scipro.match.dao.interfaces.KeywordDao;
import se.su.dsv.scipro.match.dao.interfaces.KeywordTypeDao;
import se.su.dsv.scipro.match.dao.interfaces.SupervisorDao;
import se.su.dsv.scipro.match.dataobject.Keyword;
/**
* Main service facade for all importing operations.
@ -64,10 +70,16 @@ public class ImporterFacade {
@Autowired
private ProjectFollowerDao projectFollowerDao;
@Autowired
private SupervisorDao supervisorDao;
@Autowired
private ExternalImporter externalImporter;
@Autowired
private FinalSeminarDao finalSeminarDao;
@Autowired
private KeywordDao keywordDao;
@Autowired
private KeywordTypeDao keywordTypeDao;
@Autowired
private FinalSeminarActiveParticipationDao finalSeminarActiveParticipationDao;
@Autowired
private FinalSeminarOppositionDao finalSeminarOppositionDao;
@ -390,4 +402,45 @@ public class ImporterFacade {
return ProjectStatus.INACTIVE;
}
}
@Transactional
public void addUnitToSupervisor(SupervisorDTO supervisorDTO, UnitDTO unitDTO) {
User supervisorUser = userDao.getUserByIdentifier(supervisorDTO.id);
Employee supervisor = supervisorDao.getFrom(supervisorUser);
List<Keyword> currentUnits = supervisor.getKeywords().getFiltered(keywordTypeDao.findByType(KeywordTypeDao.TYPE.UNIT));
//If supervisor is already assigned to a unit, remove to make sure only the latest unit is being added since we only allow one unit in Scipro.
//Supervisor is not going to be allowed to have more than one unit in the future, but some have two in Daisy at the moment.
if (!currentUnits.isEmpty()) {
logger.info(supervisor.getUser().getFullName() + " is already attached to a unit and this is being overwritten.");
supervisor.getKeywords().getAll().removeAll(currentUnits);
}
Keyword unitToAdd = keywordDao.getKeywordByNameAndType(unitDTO.name, keywordTypeDao.findByType(KeywordTypeDao.TYPE.UNIT));
logger.info("Adding unit: " + unitToAdd.getKeyword() + " to supervisor: " + supervisor.getUser().getFullName());
supervisor.getKeywords().getAll().add(unitToAdd);
}
@Transactional
public void addUnexistingUnitsAsKeywords(final Set<UnitDTO> subunits) {
final Set<Keyword> currentUnits = keywordDao.getKeywords(keywordTypeDao.findByType(KeywordTypeDao.TYPE.UNIT));
final Set<UnitDTO> remoteUnits = new HashSet<UnitDTO>(subunits);
for (Keyword unit : currentUnits) {
UnitDTO translatedUnit = dtoFromUnitKeyword(unit);
if (remoteUnits.contains(translatedUnit)) {
logger.debug("Unit " + translatedUnit + " already exists, skipping..");
remoteUnits.remove(translatedUnit);
}
}
//Create unit keywords of the units that not exists.
for (UnitDTO unitToAdd : remoteUnits) {
logger.info("Creating unit keyword: " + unitToAdd.name);
Keyword unit = new Keyword(unitToAdd.name, keywordTypeDao.findByType(KeywordTypeDao.TYPE.UNIT));
unit = keywordDao.save(unit);
}
}
private UnitDTO dtoFromUnitKeyword(final Keyword unit){
UnitDTO dto = new UnitDTO();
dto.setName(unit.getKeyword());
return dto;
}
}

@ -19,6 +19,9 @@ import se.su.dsv.scipro.io.ExternalImporter;
import se.su.dsv.scipro.io.dto.AbstractDtoResponseHandler;
import se.su.dsv.scipro.io.dto.ProjectDTO;
import se.su.dsv.scipro.io.dto.ProjectDTOCollectionWrapper;
import se.su.dsv.scipro.io.dto.SupervisorDTO;
import se.su.dsv.scipro.io.dto.UnitDTO;
import se.su.dsv.scipro.io.dto.UnitDTOCollectionWrapper;
import se.su.dsv.scipro.io.dto.UserDTO;
import se.su.dsv.scipro.io.dto.UserDTOCollectionWrapper;
import se.su.dsv.scipro.io.dto.UserRoleDTO;
@ -119,6 +122,55 @@ public class ExternalImporterDaisyImpl implements ExternalImporter {
importerFacade.mergeProject(project, projectDTO);
}
}
@Override
@Transactional
public void importSupervisorUnits() throws ExternalImportException {
Set<UnitDTO> unitSet = fetchRemoteUnits(new HashMap<String,String>(), HttpRequestSender.REQUEST_TYPE.GET, new UrlProcessor() {
@Override
String process(final String url){
return (url+"/orgunit/4");//This will retrieve DSV as main unit and the unit keywords to add as subunits underneath DSV.
}
});
for (UnitDTO u : unitSet) {
if (!u.subunits.isEmpty()) {
logger.info("Received " + u.subunits.size() + " subunits from remote");
importerFacade.addUnexistingUnitsAsKeywords(u.subunits);
for (UnitDTO subunitDTO : u.subunits ) {
for (SupervisorDTO supervisorDTO : subunitDTO.supervisors) {
importerFacade.addUnitToSupervisor(supervisorDTO, subunitDTO);
}
}
} else
logger.info("No subunits found");
}
}
private Set<UnitDTO> fetchRemoteUnits(final Map<String,String> parameters,final HttpRequestSender.REQUEST_TYPE requestType,
UrlProcessor urlProcessor) {
final String requestUrl = (urlProcessor==null?getRequestUrl():urlProcessor.process(getRequestUrl()));
final Set<UnitDTO> dtoCache = new HashSet<UnitDTO>();
final HttpsRequestSender senderProxy = new HttpsRequestSender(new AbstractDtoResponseHandler(){
@Override
public void handleResponse(String response) {
logger.info("Response received (from: "+requestUrl+"): " + response);
final UnitDTOCollectionWrapper unitCollection = asUnitCollection(response);//The query will always returns a collection, regardless of backing data
if(unitCollection.size() == 0){//If at this point we have nothing, we have to throw.
throw new ExternalImportException("No units found in remote");
}else{
dtoCache.addAll(unitCollection.getUnits());
}
logger.info("Received " + unitCollection.size() + " unit"+(unitCollection.size()==1?"":"s")+" from remote");
}
}, requestUrl, getRequestUser(), getRequestPassword(), parameters, requestType);
try{
process(senderProxy);
}catch(final ExternalImportException eie){
logger.warn("No units found");
}
return dtoCache;
}
@Override
public boolean supportsRemoteOperations() {
return true;

@ -36,5 +36,9 @@ public class ExternalImporterDefaultImpl implements ExternalImporter {
public boolean supportsRemoteOperations() {
return false;
}
@Override
public void importSupervisorUnits() throws ExternalImportException {
// TODO Auto-generated method stub
}
}

@ -127,9 +127,9 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
/**
* Return the best match, the old one or the new one with supervisor
* @param oldMatch
* @param supervisor
* @return
* @param oldMatchPair
* @param availability
* @return Pair
*/
private Pair getBestMatch(Pair oldMatchPair, Availability availability) {
Match oldMatch = oldMatchPair.getMatch();
@ -165,7 +165,7 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
/**
* Returns if it is possible for the supervisor to work with this project idea based on
* language and if idea has previously been rejected by supervisor
* language and if the idea has previously been rejected by the supervisor
* @param projectIdea
* @param supervisor
* @return
@ -180,11 +180,11 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
* @param supervisor
* @return
*/
private boolean isNotRejectedBySupervisor(ProjectIdea projectIdea,
Employee supervisor) {
private boolean isNotRejectedBySupervisor(ProjectIdea projectIdea, Employee supervisor) {
for (Match oldMatch : projectIdea.getMatchHistory()) {
if (supervisor.equals(oldMatch.getSupervisor())
&& oldMatch.getStatus() == Match.Status.REJECTED) {
if (oldMatch.getSupervisor() != null && oldMatch.getSupervisor().equals(supervisor) &&
oldMatch.getRejectedBy() != null && oldMatch.getRejectedBy().equals(supervisor.getUser()) &&
oldMatch.getStatus() != null && oldMatch.getStatus().equals(Match.Status.REJECTED)) {
return false;
}
}

@ -12,5 +12,7 @@ public interface KeywordDao extends LazyDeleteDao<Keyword>{
Set<Keyword> getKeywords(KeywordType type);
public List<Keyword> findAllFromType(KeywordType kt, boolean includeDeleted);
Keyword getKeywordByNameAndType(String keywordName, KeywordType type);
}

@ -5,6 +5,7 @@ import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
@ -69,4 +70,23 @@ public class KeywordDaoJPAImp extends LazyDeleteAbstractDaoJPAImp<Keyword> imple
}
});
}
@Override
public Keyword getKeywordByNameAndType(final String keywordName, final KeywordType type) {
return getJpaTemplate().execute(new JpaCallback<Keyword>() {
public Keyword doInJpa(EntityManager em) throws PersistenceException {
TypedQuery<Keyword> query = em.createQuery("SELECT x FROM "+domainClassString+" x WHERE x.type = :type AND x.keyword = :keywordName", domainClass);
query.setParameter("type", type);
query.setParameter("keywordName", keywordName);
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
});
}
}

@ -64,6 +64,10 @@ public class MatchDaoJPAImp extends AbstractDaoJPAImp<Match> implements
newMatch.setStatus(match.getStatus());
}
newMatch.setCreatedBy(changer);
if(status != null && status.equals(Match.Status.REJECTED)) {
newMatch.setRejectedBy(changer);
newMatch.setCommentForAdmin(match.getCommentForAdmin());
}
newMatch.setProjectIdea(match.getProjectIdea());
return save(newMatch);
}

@ -61,7 +61,10 @@ public class Match extends DomainObject {
@ManyToOne(optional = false)
private User createdBy;
@ManyToOne(optional = true)
private User rejectedBy;
@Column(length = 1024)
private String commentForStudent;
@ -115,6 +118,14 @@ public class Match extends DomainObject {
this.createdBy = createdBy;
}
public User getRejectedBy() {
return rejectedBy;
}
public void setRejectedBy(User rejectedBy) {
this.rejectedBy = rejectedBy;
}
public String getCommentForStudent() {
return commentForStudent;
}
@ -170,6 +181,8 @@ public class Match extends DomainObject {
.hashCode());
result =
prime * result + ((createdBy == null) ? 0 : createdBy.hashCode());
result =
prime * result + ((rejectedBy == null) ? 0 : rejectedBy.hashCode());
result = prime * result + points;
result =
prime * result
@ -203,6 +216,11 @@ public class Match extends DomainObject {
return false;
} else if (!createdBy.equals(other.createdBy))
return false;
if (rejectedBy == null) {
if (other.rejectedBy != null)
return false;
} else if (!rejectedBy.equals(other.rejectedBy))
return false;
if (points != other.points)
return false;
if (projectIdea == null) {

@ -79,7 +79,7 @@ public class ProjectIdea extends DomainObject {
@OrderBy("dateCreated DESC, id DESC")
private List<Match> matchHistory = new ArrayList<Match>();
@ManyToOne
@OneToOne(optional = true)
private Match match;
@Override

@ -6,34 +6,38 @@
<div wicket:id="dialog">
<div wicket:id="dialogContent"></div>
</div>
<h5 class="peer-title">Search among all project ideas</h5>
<form wicket:id="form">
<p>Title</p>
<input style="width:300px;" wicket:id="titleField" type="text" />
<p>Supervisor</p>
<input style="width:300px;" wicket:id="supervisorField" type="text" />
<p>Author</p>
<label for="titleField">Title:</label><br/>
<input style="width:300px;" wicket:id="titleField" type="text" /><br/>
<label for="supervisorField">Supervisor:</label><br/>
<input style="width:300px;" wicket:id="supervisorField" type="text" /><br/>
<label for="authorField">Author:</label><br/>
<input style="width:300px;" wicket:id="authorField" type="text" />
<table>
<tr>
<td wicket:id="projectClassPanel"></td>
<td colspan="2" wicket:id="matchStatusPanel"></td>
<td></td>
</tr>
</table>
<input wicket:id="filterButton" type="submit">
<div class="span-16 append-bottom last">
<div class="span-6" wicket:id="projectClassPanel"></div>
<div class="span-10 last append-bottom" wicket:id="matchStatusPanel"></div>
<input wicket:id="filterButton" type="submit" />
</div>
</form>
<div wicket:id="allContainer">
<p><b>Search among all project ideas</b></p>
<div class="span-15 last">
<table class="rounded-corner">
<thead>
<tr>
<th>Level</th>
<th class="rounded-left-top">Level</th>
<th>Title</th>
<th>Author(s)</th>
<th>Status</th>
<th>Edit</th>
<th class="rounded-right-top">Edit</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="5" class="rounded-foot">&nbsp;</td>
</tr>
</tfoot>
<tbody>
<tr wicket:id="allDataView">
<td wicket:id="level"></td>
<td wicket:id="title"></td>
@ -44,9 +48,12 @@
<tr>
<td colspan="5" wicket:id="emptyLabel"></td>
</tr>
</tbody>
</table>
</div>
<div wicket:id="nav"></div>
</div>
</wicket:panel>
</body>

@ -52,14 +52,14 @@ public class AdminManageProjectIdeaPanel extends Panel {
dialog.setModal(true);
dialog.setAutoOpen(false);
dialog.setWidth(550);
dialog.setHeight(700);
dialog.setHeight(500);
dialog.add(new EmptyPanel("dialogContent"));
add(dialog);
allContainer = new WebMarkupContainer("allContainer");
//Add info for the user should there be no events to display.
emptyLabel = new Label("emptyLabel", "No events to show.");
emptyLabel = new Label("emptyLabel", "No project ideas to show.");
allContainer.add(emptyLabel);
emptyLabel.setOutputMarkupId(true); //Needs to be AJAX-enabled.
allProvider = new ProjectIdeaDataProvider();
@ -88,7 +88,6 @@ public class AdminManageProjectIdeaPanel extends Panel {
@Override
public void onClick(AjaxRequestTarget target) {
if (target != null) {
System.out.println("opening dialog and setting title");
dialog.replace(new AdminEditProjectIdeaPanel("dialogContent", new Model<ProjectIdea>(idea)) {
private static final long serialVersionUID = 1L;});
target.addComponent(dialog);

@ -4,32 +4,44 @@
<body>
<wicket:panel>
<form wicket:id="form">
<p>Supervisor</p>
<input style="width:300px;" wicket:id="supervisorField" type="text" />
<p>Keyword</p>
<h5 class="peer-title append-bottom">Manage supervisors</h5>
<label for="supervisorField">Search using supervisor name:</label><br />
<input style="width:300px;" wicket:id="supervisorField" type="text" /><br />
<label for="keywordField">Search on keywords used by supervisor:</label><br />
<input style="width:300px;" wicket:id="keywordField" type="text" />
<table>
<tr>
<td wicket:id="unitPanel"></td>
<td colspan="2" wicket:id="researchAreaPanel"></td>
<td></td>
</tr>
</table>
<input wicket:id="filterButton" type="submit">
<div class="span-16 prepend-top append-bottom last">
<div class="span-6">
<label for="unitPanel">Filter by unit:</label><br />
<span wicket:id="unitPanel"></span>
</div>
<div class="span-10 last append-bottom">
<label for="researchAreaPanel">Filter by research area:</label>
<span wicket:id="researchAreaPanel"></span>
</div>
</div>
<div><input wicket:id="filterButton" type="submit" />
</div>
</form>
<div wicket:id="container">
<p><b>Search among all project ideas</b></p>
<div class="span-15 last">
<table class="rounded-corner">
<thead>
<tr>
<th>Supervisor</th>
<th class="rounded-left-top">Supervisor</th>
<th>Unit</th>
<th>Target bachelor</th>
<th>Target master</th>
<th>Current bachelor</th>
<th>Current master</th>
<th class="rounded-right-top">Current master</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="6" class="rounded-foot">&nbsp;</td>
</tr>
</tfoot>
<tbody>
<tr wicket:id="dataView">
<td wicket:id="supervisor"></td>
<td wicket:id="unit"></td>
@ -39,13 +51,14 @@
<td><select wicket:id="targetMaster"></select></td>
<td wicket:id="currentBachelor"></td>
<td wicket:id="currentMaster"></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan ="6" wicket:id="emptyLabel"></td>
</tr>
</tbody>
</table>
</div>
<div wicket:id="nav"></div>
</div>

@ -6,19 +6,25 @@
<div wicket:id="dialog">
<div wicket:id="dialogContent"></div>
</div>
<div wicket:id="container">
<p><b>Rejected Ideas</b></p>
<div class="prepend-top" wicket:id="container">
<h5 class="peer-title">Rejected project ideas</h5>
<table class="rounded-corner">
<thead>
<tr>
<th>Level</th>
<th class="rounded-left-top">Level</th>
<th>Title</th>
<th>Author(s)</th>
<th>Rejected by</th>
<th>Comment</th>
<th>Edit</th>
<th class="rounded-right-top">Edit</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="6" class="rounded-foot">&nbsp;</td>
</tr>
</tfoot>
<tbody>
<tr wicket:id="rejectedDataView">
<td wicket:id="level"></td>
<td wicket:id="title"></td>
@ -30,6 +36,7 @@
<tr>
<td wicket:id="emptyLabel" colspan="6"></td>
</tr>
</tbody>
</table>
<div wicket:id="nav"></div>
</div>

@ -46,13 +46,13 @@ public class AdminRejectedProjectIdeaPanel extends Panel {
dialog.setModal(true);
dialog.setAutoOpen(false);
dialog.setWidth(550);
dialog.setHeight(700);
dialog.setHeight(500);
dialog.add(new EmptyPanel("dialogContent"));
add(dialog);
container = new WebMarkupContainer("container");
//Add info for the user should there be no events to display.
emptyLabel = new Label("emptyLabel", "No events to show.");
emptyLabel = new Label("emptyLabel", "No project ideas to show.");
container.add(emptyLabel);
emptyLabel.setOutputMarkupId(true); //Needs to be AJAX-enabled.
@ -78,7 +78,7 @@ public class AdminRejectedProjectIdeaPanel extends Panel {
item.add(new Label("level", new Model<ProjectClass>(idea.getProjectClass())));
item.add(new Label("author", new Model<String>(authorString)));
item.add(new Label("title", new Model<String>(idea.getTitle())));
item.add(new Label("rejectedBy", new Model<String>(idea.getMatch().getSupervisor().getUser().getFullName())));
item.add(new Label("rejectedBy", new Model<String>(idea.getMatch().getRejectedBy() != null ? idea.getMatch().getRejectedBy().getFullName():"")));
item.add(new Label("comment", new Model<String>(idea.getMatch().getCommentForStudent())));
AjaxLink<Void> dialogLink = new AjaxLink<Void>("editDialog") {
private static final long serialVersionUID = 1L;
@ -86,7 +86,6 @@ public class AdminRejectedProjectIdeaPanel extends Panel {
@Override
public void onClick(AjaxRequestTarget target) {
if (target != null) {
System.out.println("opening dialog and setting title");
dialog.replace(new AdminEditProjectIdeaPanel("dialogContent", new Model<ProjectIdea>(idea)) {
private static final long serialVersionUID = 1L;});
target.addComponent(dialog);

@ -46,7 +46,7 @@ public class AdminSupervisorDetailsPanel extends Panel {
dialog = new Dialog("dialog");
dialog.setTitle("Details for " + supervisor.getFullName());
dialog.setWidth(800);
dialog.setWidth(885);
add(dialog);
AjaxLink<Void> dialogLink = new AjaxLink<Void>("dialogLink") {

@ -3,26 +3,37 @@
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<div wicket:id="container">
<p><b>Top waiting</b></p>
<div wicket:id="dialog">
<div wicket:id="dialogContent"></div>
</div>
<div class="prepend-top" wicket:id="container">
<h5 class="peer-title">Top waiting project ideas</h5>
<table class="rounded-corner">
<thead>
<tr>
<th>Level</th>
<th class="rounded-left-top">Level</th>
<th>Title</th>
<th>Author(s)</th>
<th>Edit</th>
<th class="rounded-right-top">Edit</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="4" class="rounded-foot">&nbsp;</td>
</tr>
</tfoot>
<tbody>
<tr wicket:id="dataView">
<td wicket:id="level"></td>
<td wicket:id="title"></td>
<td wicket:id="author"></td>
<td wicket:id="edit"></td>
<td><a href="#" wicket:id="editDialog"><img wicket:id="editIcon" /></a></td>
</tr>
<tr>
<td wicket:id="emptyLabel" colspan="4"></td>
</tr>
</tbody>
</table>
<div wicket:id="nav"></div>
</div>

@ -2,18 +2,23 @@ package se.su.dsv.scipro.match.panel;
import java.util.List;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
import org.apache.wicket.markup.html.panel.EmptyPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.model.Model;
import org.odlabs.wiquery.ui.dialog.Dialog;
import se.su.dsv.scipro.admin.panels.match.AdminEditProjectIdeaPanel;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.icons.ImageObject;
import se.su.dsv.scipro.match.dataobject.ProjectIdea;
import se.su.dsv.scipro.match.dataprovider.ProjectIdeaDataProvider;
import se.su.dsv.scipro.match.dataprovider.ProjectIdeaDataProvider.SEARCH_MODE;
@ -26,18 +31,25 @@ public class AdminWaitingProjectIdeaPanel extends Panel {
private WebMarkupContainer container;
private ProjectIdeaDataProvider provider;
private Label emptyLabel;
private Dialog dialog;
public AdminWaitingProjectIdeaPanel(String id){
super(id);
allDataViewSetup();
}
private void allDataViewSetup(){
dialog = new Dialog("dialog");
dialog.setModal(true);
dialog.setAutoOpen(false);
dialog.setWidth(550);
dialog.setHeight(500);
dialog.add(new EmptyPanel("dialogContent"));
add(dialog);
container = new WebMarkupContainer("container");
//Add info for the user should there be no events to display.
emptyLabel = new Label("emptyLabel", "No events to show.");
emptyLabel = new Label("emptyLabel", "No project ideas to show.");
container.add(emptyLabel);
emptyLabel.setOutputMarkupId(true); //Needs to be AJAX-enabled.
@ -58,9 +70,24 @@ public class AdminWaitingProjectIdeaPanel extends Panel {
}
item.add(new Label("level", new Model<ProjectClass>(idea.getProjectClass())));
item.add(new Label("author", new Model<String>(authorString + " author")));
item.add(new Label("title", new Model<String>(idea.getTitle() + " title")));
item.add(new AdminEditProjectIdeaPanel("edit", item.getModel()));
item.add(new Label("author", new Model<String>(authorString + " author")));
AjaxLink<Void> dialogLink = new AjaxLink<Void>("editDialog") {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
if (target != null) {
dialog.replace(new AdminEditProjectIdeaPanel("dialogContent", new Model<ProjectIdea>(idea)) {
private static final long serialVersionUID = 1L;});
target.addComponent(dialog);
dialog.setTitle("Edit project idea: " + idea.getTitle());
dialog.open(target);
}
}
};
dialogLink.add(new ImageObject("editIcon", ImageObject.SIXTEEN + ImageObject.EDIT));
item.add(dialogLink);
}
};

@ -8,6 +8,7 @@
<wicket:panel>
<div wicket:id="container">
<label for="checkGroup">Match status:</label>
<div wicket:id="checkGroup">
<div wicket:id="statusView">
<input type="checkbox" wicket:id="statusCheckBox"></input>

@ -8,6 +8,7 @@
<wicket:panel>
<div wicket:id="container">
<label for="checkGroup">Project level:</label>
<div wicket:id="checkGroup">
<div wicket:id="projectClasses">
<input type="checkbox" wicket:id="projectClassCheckBox"></input>

@ -3,14 +3,15 @@
<body>
<wicket:panel>
<form wicket:id="applicationPeriodForm">
<table>
<div class="prepend-top append-bottom">
<label for="checkGroup">Levels for application period:</label>
<wicket:container wicket:id="checkGroup">
<tr wicket:id="projectClasses">
<td><input type="checkbox" wicket:id="projectClassCheckbox"/></td>
<td><span wicket:id="projectClassName">...</span></td>
</tr>
<div wicket:id="projectClasses">
<input type="checkbox" wicket:id="projectClassCheckbox"/>
<span wicket:id="projectClassName">...</span>
</div>
</wicket:container>
</table>
</div>
<table>
<tr>
<td>Start date: <div wicket:id="startDate"></div></td>

@ -5,12 +5,14 @@ import org.apache.wicket.PageParameters;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.RequestUtils;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.data.DomainObjectDetachableModel;
import se.su.dsv.scipro.ProjectStatus.CompletedProjectStatus;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.data.facade.ProjectFacade;
import se.su.dsv.scipro.opponent.panels.ProjectFinalSeminarContainerPanel;
import se.su.dsv.scipro.peer.pages.ProjectPeerReviewPage;
import se.su.dsv.scipro.peer.panels.StudentPeerInfoRequestsPanel;
@ -22,12 +24,19 @@ import se.su.dsv.scipro.project.panels.UpcomingEventPanel;
public class ProjectStartPage extends ProjectPage {
public static final String MAIN_MENU_LABEL = "Author";
@SpringBean
private ProjectFacade projectFacade;
public ProjectStartPage(PageParameters pp) {
super(pp);
projectFacade.completedProjectStatus(getActiveProject());
final WebMarkupContainer leftColumn = new WebMarkupContainer("leftColumn");
add(leftColumn);
add(new FeedbackPanel("feedback"));
// DomainObjectDetachableModel<Project> projectModel = new DomainObjectDetachableModel<Project>(projectDao);
@ -43,8 +52,16 @@ public class ProjectStartPage extends ProjectPage {
}
});
add(new ProjectLatestUploadPanel("latestProjectUploads",getActiveProject(),true));
AuthorStatePanel asp = new AuthorStatePanel("asp", getActiveProject());
leftColumn.add(asp);
if (getActiveProject().getProjectStatus().equals(ProjectStatus.COMPLETED)){
CompletedProjectStatus asp = new CompletedProjectStatus("asp");
leftColumn.add(asp);
}
else {
AuthorStatePanel asp = new AuthorStatePanel("asp", getActiveProject());
leftColumn.add(asp);
}
}
public static String getAbsoluteURL() {
PageParameters pageParameters = new PageParameters();

@ -9,6 +9,7 @@
<span wicket:id="availableClassLabel"></span>
<br /><br />
<span class="prepend-top"><a href="#" wicket:id="newIdeaLink"><img wicket:id="add" /> Submit new project idea</a></span>
<span class="prepend-top" wicket:id="alreadySubmittedLabel"></span>
</wicket:enclosure>
<wicket:enclosure child="noPeriodLabel">
<b><span wicket:id="noPeriodLabel"></span></b>

@ -14,8 +14,10 @@ import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.data.dao.interfaces.ProjectClassDao;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.facade.ProjectIdeaFacade;
import se.su.dsv.scipro.icons.ImageObject;
import se.su.dsv.scipro.match.dao.interfaces.ApplicationPeriodDao;
import se.su.dsv.scipro.match.dataobject.ApplicationPeriod;
@ -30,6 +32,9 @@ public class ProjectIdeaPeriodPanel extends Panel {
private ApplicationPeriodDao applicationPeriodDao;
@SpringBean
private ProjectClassDao projectClassDao;
@SpringBean
private ProjectIdeaFacade projectIdeaFacade;
private WebMarkupContainer periodContainer;
public ProjectIdeaPeriodPanel(String id) {
@ -93,7 +98,20 @@ public class ProjectIdeaPeriodPanel extends Panel {
};
periodContainer.add(noActivePeriodLabel);
BookmarkablePageLink<Void> newIdeaLink = new BookmarkablePageLink<Void>("newIdeaLink", ProjectIdeaSubmissionPage.class);
newIdeaLink.add(new ImageObject("add", ImageObject.SIXTEEN + ImageObject.ADD));
newIdeaLink.add(new ImageObject("add", ImageObject.SIXTEEN + ImageObject.ADD));
System.out.println("Calling method");
Label alreadySubmittedLabel = new Label("alreadySubmittedLabel", "You have already submitted or are already included in a project idea collected in current project idea collection period(s)");
alreadySubmittedLabel.setVisible(false);
periodContainer.add(alreadySubmittedLabel);
if (projectIdeaFacade.projectIdeaAlreadySubmittedThisPeriod(SciProSession.get().getUser(), currentPeriods)){
newIdeaLink.setVisible(false);
alreadySubmittedLabel.setVisible(true);
}
// newIdeaLink.setVisible(!projectIdeaFacade.projectIdeaAlreadySubmittedThisPeriod(SciProSession.get().getUser(), currentPeriods));
periodContainer.add(newIdeaLink);
add(periodContainer);
}

@ -15,7 +15,7 @@
<label for="projectClassSelection">Project level: </label><br />
<select id="projectClassSelection" wicket:id="projectClassSelection"></select>
</div>
<div class="span-8 last">
<div class="span-8 last" wicket:id="partnerContainer">
<div wicket:id="partnerPanel"></div>
<a href="#" wicket:id="partnerInfoLink"><img src="images/icons/24/help2.png" alt="Partner info"/></a>
</div>

@ -27,6 +27,7 @@ import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.validation.validator.StringValidator;
import org.odlabs.wiquery.ui.dialog.Dialog;
import org.wicketstuff.objectautocomplete.ObjectAutoCompleteBuilder;
import org.wicketstuff.objectautocomplete.ObjectAutoCompleteField;
@ -85,7 +86,7 @@ public class ProjectIdeaSubmissionPanel extends Panel {
public ProjectIdeaSubmissionPanel(String id, User user, ProjectIdea idea) {
super(id);
add(new FeedbackPanel("feedback"));
add(new ProjectIdeaForm("projectIdeaForm", user, new DomainObjectDetachableModel<ProjectIdea>(projectIdeaDao, idea)));
add(new ProjectIdeaForm("projectIdeaForm", user, new Model<ProjectIdea>(idea)));
dialogSetup();
}
@ -121,6 +122,7 @@ public class ProjectIdeaSubmissionPanel extends Panel {
private Model<Long> ideaPreferred, ideaAgreed;
private Button submitButton;
private Student signedInAuthor;
private WebMarkupContainer partnerContainer;
public ProjectIdeaForm(String id, final User loggedInUser, final IModel<ProjectIdea> ideaModel) {
@ -141,7 +143,22 @@ public class ProjectIdeaSubmissionPanel extends Panel {
@Override
protected void onUpdate(AjaxRequestTarget target) {
partnerAdditionPanel.setPartnerRequired(isExemptionGranted());
partnerAdditionPanel.setPartnerRequired(!isExemptionGranted());
partnerContainer.setVisible(!isExemptionGranted());
if (projectClassModel.getObject()==null){
partnerAdditionPanel.setPartnerRequired(false);
partnerContainer.setVisible(false);
}
//there may be other higher levels later, thats why i check for bachelor, cus we know bachelor will always require partners.
if (!projectClassModel.getObject().getName().equalsIgnoreCase("bachelor")){
partnerAdditionPanel.setPartnerRequired(false);
partnerContainer.setVisible(false);
}
target.addComponent(partnerContainer);
target.addComponent(partnerAdditionPanel);
}
@ -168,9 +185,17 @@ public class ProjectIdeaSubmissionPanel extends Panel {
};
container.add(keywordPanel);
partnerContainer = new WebMarkupContainer("partnerContainer");
// partnerContainer.setOutputMarkupId(true);
partnerContainer.setOutputMarkupPlaceholderTag(true);
container.add(partnerContainer);
partnerContainer.setVisible(false);
partnerAdditionPanel = new PartnerAdditionPanel("partnerPanel", ideaModel.getObject().getAuthors());
partnerAdditionPanel.setOutputMarkupId(true);
container.add(partnerAdditionPanel);
partnerContainer.add(partnerAdditionPanel);
addWatsonBoxes();
addLanguageSelection();
@ -199,9 +224,9 @@ public class ProjectIdeaSubmissionPanel extends Panel {
validated = false;
}
} else {
if (isExemptionGranted()) {
if (isExemptionGranted() || !projectClassModel.getObject().getName().equalsIgnoreCase("bachelor")) {
idea.getAuthors().add(signedInAuthor);
//Exemption is granted, no co-author needed.
//Exemption is granted, no co-author needed OR not bachelor level, no co-author needed
} else {
error("You need to choose a project partner");
validated = false;
@ -235,12 +260,16 @@ public class ProjectIdeaSubmissionPanel extends Panel {
private void addWatsonBoxes() {
watsonWhat = new TextArea<String>("watsonWhat", new PropertyModel<String>(ideaModel, "watson.what"));
watsonWhat.setRequired(true);
watsonWhat.add(StringValidator.minimumLength(5));
watsonWhy = new TextArea<String>("watsonWhy", new PropertyModel<String>(ideaModel, "watson.why"));
watsonWhy.setRequired(true);
watsonWhy.add(StringValidator.minimumLength(5));
watsonHowTheory = new TextArea<String>("watsonHowTheory", new PropertyModel<String>(ideaModel, "watson.theoryHow"));
watsonHowTheory.setRequired(true);
watsonHowTheory.add(StringValidator.minimumLength(5));
watsonHowPrac = new TextArea<String>("watsonHowPrac", new PropertyModel<String>(ideaModel, "watson.practicalHow"));
watsonHowPrac.setRequired(true);
watsonHowPrac.add(StringValidator.minimumLength(5));
container.add(watsonWhat);
container.add(watsonWhy);
container.add(watsonHowTheory);
@ -403,7 +432,7 @@ public class ProjectIdeaSubmissionPanel extends Panel {
}
private void addInfoLinksToForm(){
container.add(partnerInfoLink);
partnerContainer.add(partnerInfoLink);
container.add(titleInfoLink);
container.add(whatInfoLink);
container.add(whyInfoLink);

@ -8,13 +8,20 @@ import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.PropertyModel;
/**
* Abstract and generic class for textfields used for filtering with AJAX.
* Generic because we dont need to have any references to any object upon
* which operations using the string the user enters is made, or to any
* wicket component that needs targeting and updating with AJAX.
* Class for getting a string and using ajax to change something.
*
* @author fred
* Example of use:
*
* x.add(new FilterStringPanel("filterStringPanel"){
* private static final long serialVersionUID = 1L;
* @Override
* public void onUpdateFilter(AjaxRequestTarget target) {
* params.setFilterString(getFilterString());
* target.addComponent(dataViewContainer);
* }
* });
*
* @author fred
*/
public abstract class FilterStringPanel extends Panel {
@ -33,8 +40,7 @@ public abstract class FilterStringPanel extends Panel {
}
/**
*For developers to implement in class that contains the correct references to params and facade objects, dataviews etc.
*e.g. they could do params.setFilter(<reference to an instance of this class>.getFilterString()) and/or AJAX stuff too.
* Override this class to do something.
*/
public abstract void onUpdateFilter(AjaxRequestTarget target);

@ -3,8 +3,12 @@ package se.su.dsv.scipro.supervisor.pages;
import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import com.mchange.v2.codegen.bean.CompleteConstructorGeneratorExtension;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.ProjectStatus.CompletedProjectStatus;
import se.su.dsv.scipro.components.menuhighlighting.MenuHighlightSupervisorMyProjects;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.peer.pages.SupervisorPeerReviewPage;
import se.su.dsv.scipro.peer.panels.StudentPeerInfoRequestsPanel;
import se.su.dsv.scipro.project.panels.ProjectDetailsPanel;
@ -23,6 +27,9 @@ public class SupervisorProjectDetailsPage extends AbstractSupervisorProjectDetai
super(pp);
add(new ProjectDetailsPanel("projectDetails", projectModel));
add(new SupervisorStateOfMindPanel("stateOfMindPanel", projectModel.getObject()));
if (projectModel.getObject()!=null && projectModel.getObject().getProjectStatus().equals(ProjectStatus.COMPLETED)){
replace(new CompletedProjectStatus("stateOfMindPanel"));
}
add(new ProjectLatestUploadPanel("latestUpload",projectModel.getObject(),true));
add(new StudentPeerInfoRequestsPanel("peerRequests", null, projectModel.getObject()){
private static final long serialVersionUID = 1L;

@ -6,11 +6,13 @@ import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.enums.StateOfMind;
import se.su.dsv.scipro.data.facade.ProjectFacade;
import se.su.dsv.scipro.icons.ImageIcon;
import se.su.dsv.scipro.supervisor.pages.SupervisorProjectDetailsPage;
/**
@ -21,6 +23,9 @@ import se.su.dsv.scipro.supervisor.pages.SupervisorProjectDetailsPage;
public abstract class AbstractSupervisorDataView extends DataView<Project>{
private static final long serialVersionUID = 1L;
@SpringBean
private ProjectFacade projectFacade;
protected AbstractSupervisorDataView(String id,IDataProvider<Project> dataProvider) {
this(id, dataProvider, Integer.MAX_VALUE);
}
@ -34,6 +39,8 @@ public abstract class AbstractSupervisorDataView extends DataView<Project>{
protected void populateItem(Item<Project> item) {
Project project = item.getModelObject();
projectFacade.completedProjectStatus(project);
if (project.getStateOfMind()==StateOfMind.FINE)
item.add(new ImageIcon("state", ImageIcon.ICON_NEW_CHECKLIST_GREEN));
else if (project.getStateOfMind()==StateOfMind.NEUTRAL)

@ -44,7 +44,7 @@ public class SupervisorAcceptDeclinePanel extends Panel {
@Override
protected void onSubmit() {
matchDao.changeStatus(SciProSession.get().getUser(), getModelObject(), Status.REJECTED);
matchDao.changeStatus(SciProSession.get().getUser(), getModelObject() , Status.REJECTED);
}
};

@ -6,18 +6,26 @@
</head>
<body>
<wicket:panel>
Author(s): <span wicket:id="authors"></span>
<b>Author(s):</b> <span wicket:id="authors"></span>
<p>
Keywords: <span wicket:id="keywords"></span>
<b>Keywords:</b> <span wicket:id="keywords"></span>
<div>
<h5>What?</h5>
<div wicket:id="what"></div>
<h5>Why?</h5>
<div wicket:id="why"></div>
<h5>Theoretically how?</h5>
<div wicket:id="theoryHow"></div>
<h5>Practically how?</h5>
<div wicket:id="practicalHow"></div>
<div class="rounded-box">
<span class="box-title">What?</span>
<span wicket:id="what"></span>
</div>
<div class="rounded-box">
<span class="box-title">Why?</span>
<span wicket:id="why"></span>
</div>
<div class="rounded-box">
<span class="box-title">Theoretically how?</span>
<span wicket:id="theoryHow"></span>
</div>
<div class="rounded-box">
<span class="box-title">Practically how?</span>
<span wicket:id="practicalHow"></span>
</div>
</div>
</wicket:panel>
</body>

@ -18,6 +18,7 @@ public class UserImportWorker extends AbstractWorker{
final Date startDate = getStartedWorkingDate();
logger.info("Starting execution for scheduled remote user import of all remote supervisors");
externalImporter.importUsersOfRole(Roles.EMPLOYEE, true);
externalImporter.importSupervisorUnits();
final Date endDate = new Date();
final long executionTimeSecs = (endDate.getTime() - startDate.getTime())/1000;
final String fmt = String.format("%%0%dd", 2);

@ -64,7 +64,7 @@
<!-- Use deployment for production, development for development -->
<context-param>
<param-name>configuration</param-name>
<!--<param-value>development</param-value> -->
<!-- <param-value>development</param-value> -->
<param-value>deployment</param-value>
</context-param>

@ -71,4 +71,16 @@ public class TestKeywordDao {
Arrays.asList(new Keyword[] { keyword1, keyword2 })), keywords);
}
@Test
@Transactional
@Rollback
public void testShouldOnlyGetKeywordByCorrectNameAndType() {
Keyword nullKey = target.getKeywordByNameAndType("Key 2", other);
Assert.assertNull(nullKey);
Keyword correctKey = target.getKeywordByNameAndType("Key 2", standard);
Assert.assertEquals(keyword2, correctKey);
}
}

@ -172,20 +172,12 @@ public class TestMatchDao {
expected.setProjectIdea(projectIdea1);
expected.setSupervisor(employee1Role);
expected.setType(Match.Type.PRE_APPROVED);
expected.setStatus(Match.Status.REJECTED);
expected.setCreatedBy(employee1);
Match rejectedMatch =
target.changeStatus(employee1, preApprovedMatch,
Match.Status.REJECTED);
projectIdea1 = projectIdeaDao.reLoad(projectIdea1);
expected = target.changeStatus(employee1, expected, Match.Status.REJECTED);
Assert.assertEquals(expected, projectIdea1.getMatch());
projectIdea1 = projectIdeaDao.reLoad(projectIdea1);
List<Match> history = target.getMatchHistory(projectIdea1);
Assert.assertEquals(Arrays.asList(new Match[] { rejectedMatch,
preApprovedMatch }), history);
Match rejectedMatch = target.changeStatus(employee1, preApprovedMatch, Match.Status.REJECTED);
Assert.assertEquals(Arrays.asList(new Match[] { rejectedMatch,preApprovedMatch }), history);
}
@Test

@ -53,6 +53,7 @@ import se.su.dsv.scipro.data.dao.interfaces.WorkerDataDao;
import se.su.dsv.scipro.data.dataobjects.GeneralSystemSettings;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.facade.ProjectFacade;
import se.su.dsv.scipro.data.facade.ProjectIdeaFacade;
import se.su.dsv.scipro.io.ExternalExporter;
import se.su.dsv.scipro.io.ExternalImporter;
@ -86,6 +87,7 @@ public abstract class BaseWicketTest {
* Add beans to be mocked-up. Note that the name of the field is identical
* to the name that will be given to the bean in the applicationContext.
*/
@Mock ProjectFacade projectFacade;
@Mock UserDao userDao;
@Mock RoleDao roleDao;
@Mock protected ProjectDao projectDao;