Major merge, hopefully stuff still works...

This commit is contained in:
Robin Eklund 2011-10-27 10:30:35 +02:00
commit e2277d005b
96 changed files with 2525 additions and 788 deletions
resources/db_update_scripts
src
main
java/se/su/dsv/scipro
SciProApplication.java
activityplan
admin/pages
checklists/panels
components
data
dataproviders
json
project
repository
schedule
supervisor
workerthreads
resources/META-INF
webapp/css
test/java/se/su/dsv/scipro

@ -1 +1,2 @@
-- Required DDL changes for production deploy
ALTER TABLE schedule_template DROP COLUMN active;

@ -24,6 +24,7 @@ import org.odlabs.wiquery.ui.themes.IThemableApplication;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import se.su.dsv.scipro.activityplan.pages.ProjectActivityPlanPage;
import se.su.dsv.scipro.admin.pages.AdminFinalSeminarPage;
import se.su.dsv.scipro.admin.pages.AdminPeerListPage;
import se.su.dsv.scipro.admin.pages.AdminRolePage;
@ -221,6 +222,7 @@ public class SciProApplication extends RepositoryApplication implements IThemabl
* Project pages
*/
mountBookmarkablePage("project/conference", ProjectConferencePage.class);
mountBookmarkablePage("project/activityplan", ProjectActivityPlanPage.class);
mountBookmarkablePage("project/schedule/event", ProjectEventPage.class);
mountBookmarkablePage("project/schedule/generator", ProjectScheduleGeneratorPage.class);
mountBookmarkablePage("project/files", ProjectFilePage.class);

@ -0,0 +1,283 @@
package se.su.dsv.scipro.activityplan.facade;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.persistence.PersistenceException;
import org.apache.log4j.Logger;
import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import edu.emory.mathcs.backport.java.util.Collections;
import se.su.dsv.scipro.data.dao.interfaces.CheckListDao;
import se.su.dsv.scipro.data.dao.interfaces.FileDescriptionDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleEventDao;
import se.su.dsv.scipro.data.dao.interfaces.ScheduleTemplateDao;
import se.su.dsv.scipro.data.dataobjects.CheckList;
import se.su.dsv.scipro.data.dataobjects.FileDescription;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.dataobjects.ProjectEventTemplate;
import se.su.dsv.scipro.data.dataobjects.ProjectSchedule;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.exceptions.RenderingSafeException;
import se.su.dsv.scipro.repository.FileRepository;
import se.su.dsv.scipro.repository.SortOrder;
/**
* Service facade for project schedules and their events.
*/
@Service
public class ProjectScheduleFacade {
@Autowired
private ProjectScheduleEventDao projectScheduleEventDao;
@Autowired
private ProjectScheduleDao projectScheduleDao;
@Autowired
private ScheduleTemplateDao scheduleTemplateDao;
@Autowired
private CheckListDao checkListDao;
@Autowired
private FileRepository fileRepository;
@Autowired
private FileDescriptionDao fileDescriptionDao;
private final Logger logger = Logger.getLogger(ProjectScheduleFacade.class);
public static final String BASE_PATH = "schedule_events";
/**
* Creates a new schedule event and makes the needed object-state linking.
* If either parameter is null, a wrapped UnsupportedOperationException is thrown.
* @param ps
* @param creator
* @param date
* @return The newly created event.
*/
@Transactional
public ProjectScheduleEvent createNewProjectScheduleEvent(final ProjectSchedule ps, final User creator, String name,
String description, boolean uploadRequired, final Date date){
if (ps == null || creator == null)
throw new RenderingSafeException(new UnsupportedOperationException("Sorry, can't create schedule events without a valid schedule and creator"));
ProjectScheduleEvent pse = new ProjectScheduleEvent();
pse.setCreator(creator);
pse.setProjectSchedule(ps);
if (date == null)
pse.setDate(new Date());
else
pse.setDate(date);
pse.setName(name);
pse.setDescription(description);
pse.setUploadRequired(uploadRequired);
return projectScheduleEventDao.save(pse);
}
/**
* Saves already existing (and possibly detached) schedule event.
*/
@Transactional
public ProjectScheduleEvent saveProjectScheduleEvent(final ProjectScheduleEvent event){
if(event == null || event.getProjectSchedule() == null || event.getCreator() == null)
throw new RenderingSafeException(new UnsupportedOperationException("Sorry, object state is invalid"));
if(event.getId() == null)//Attempt to create a new one if this is a transient entity
return createNewProjectScheduleEvent(event.getProjectSchedule(),event.getCreator(),event.getName(),event.getDescription(),event.isUploadRequired(),event.getDate());
return projectScheduleEventDao.save(event);
}
/**
* Retrieves a project schedule for the given project, if none exists it will be silently created and returned.
* If the project parameter is null, a wrapped UnsupportedOperationException is thrown.
* @param p
* @return The newly created event.
*/
@Transactional
public ProjectSchedule retrieveProjectSchedule(final Project p){
if(p == null)
throw new RenderingSafeException(new UnsupportedOperationException("Sorry, can't create a schedule without a valid project"));
ProjectSchedule schedule = p.getProjectSchedule();
if(schedule == null){
schedule = new ProjectSchedule();
schedule.updateTimeStamps();
schedule.setStartDate(new Date());
schedule.setProject(p);
schedule = projectScheduleDao.save(schedule);
p.setProjectSchedule(schedule);
}
return schedule;
}
public ProjectScheduleEvent addChecklistToEvent(ProjectScheduleEvent event, CheckList checkList){
event.setCheckList(checkList);
return projectScheduleEventDao.save(event);
}
/**
* Stores uploaded file and links it to an event.
* @param file
* @param user
* @param event
* @throws IOException
*/
@Transactional
public void storeScheduleEventUpload(final FileUpload file, final User user, final ProjectScheduleEvent event)throws IOException{
String path = getAbsolutePath(event);
FileDescription fd = null;
try {
final String identifier = fileRepository.storeFile(file, path);
logger.info("Checking for: " + path+ " . " +file.getClientFileName() + " identifier: "+ identifier);
if(identifier == null || !fileRepository.existsFileByIdentifier(identifier))
throw new IOException("Something went wrong, the file is not saved correctly");
fd = fileRepository.retrieveFileDescriptionByIdentifier(identifier);
setScheduleEventUpload(fd,user,event);
} catch (IOException e) {
logger.error("Error while storing uploaded schedule event file: " + e.getMessage());
fileRepository.delete(path);
throw e;
} catch (PersistenceException e) { //If for some reason JPA freaks out, make sure the file is removed
logger.error("Error while storing schedule event resource : " + e.getMessage());
if (fd != null) {
fileDescriptionDao.delete(fd);
}
fileRepository.delete(path);
throw e;
}
}
/**
* Links a previously uploaded file to an event.
* @param file
* @param user
* @param event
*/
@Transactional
public void setScheduleEventUpload(FileDescription file, final User user, final ProjectScheduleEvent event){
event.setFileUpload(file);
file.setUserId(user.getId());
projectScheduleEventDao.save(event);
}
/**
* Attempts to delete a linked file upload from the given event, if the file is referenced from other places: only the linking is removed.
* @param event
*/
@Transactional
public void deleteSheduleEventUpload(final ProjectScheduleEvent event){
if(event != null && event.getFileUpload() != null){
final FileDescription fileDesc = fileDescriptionDao.reLoad(event.getFileUpload());//Reloading detached instance
event.setFileUpload(null);
projectScheduleEventDao.save(event);
logger.debug("Links to this resource: " + fileDescriptionDao.countFileDescriptionByIdentifier(fileDesc.getIdentifier()));
if(fileDescriptionDao.countFileDescriptionByIdentifier(fileDesc.getIdentifier()) == 0)//Not linked to other entity, safe to remove
if(! fileRepository.delete(fileDesc.getPath())){
logger.warn("Failed to remove stale file");
}
}
}
/**
* Adds all schedule events from the given template to the given schedule.
* @param schedule A null value will throw runtime exceptions
* @param template A null value will throw runtime exceptions
* @param user User owning the events. If the parameter is null, the template-owner will be used.
* @param startDate Starting date for offset calculations. If the parameter is null, the current day (at midnight) will be used.
*/
@Transactional
public void addProjectScheduleEventsFromTemplate(final ProjectSchedule schedule, ScheduleTemplate template, final User user, final Date startDate){
if(schedule == null || template == null)
throw new RenderingSafeException(new IllegalArgumentException("No null values allowed for schedule or template parameters"));
Date startDateForEvent = (startDate!=null?startDate:new DateMidnight().toDate());
template = scheduleTemplateDao.reLoad(template);//Reload lazily linked entities
int accumulatedOffset = 0;
for(final ProjectEventTemplate eventTemplate : template.getProjectEventTemplates()){
accumulatedOffset += (int)eventTemplate.getDaysOffset();
final Date dateForEvent = new DateTime(startDateForEvent).plusDays(accumulatedOffset).toDate();
final User u = (user!=null?user:eventTemplate.getTemplateCreator());
final String title = eventTemplate.getTitle()!=null?eventTemplate.getTitle():"no title";
final String desc = eventTemplate.getDescription()!=null?eventTemplate.getDescription():"";
createNewProjectScheduleEvent(schedule, u, title, desc, eventTemplate.isRequireHandIn(), dateForEvent);
}
}
/**
* Generates a new template from the given ProjectSchedule.
*/
@Transactional
public ScheduleTemplate createTemplateFromSchedule(final ProjectSchedule schedule, final User user, final ProjectClass projectClass, final String name, final String description){
if(schedule == null || user == null)
throw new RenderingSafeException(new IllegalArgumentException("No null values allowed for schedule parameter"));
final ProjectSchedule fromSchedule = projectScheduleDao.reLoad(schedule);
final ScheduleTemplate template = new ScheduleTemplate();
template.setCreator(user);
template.setProjectClass(projectClass);
template.setTemplateName(name);
template.setTemplateDescription(description);
template.setSysAdminTemplate(false);
final List<ProjectEventTemplate> templateEventList = new ArrayList<ProjectEventTemplate>(fromSchedule.getEvents().size());
final Set<ProjectScheduleEvent> eventSet = fromSchedule.getEvents();
final List<ProjectScheduleEvent> eventList = new ArrayList<ProjectScheduleEvent>(eventSet.size());
eventList.addAll(eventSet);
Collections.sort(eventList,new Comparator<ProjectScheduleEvent>(){ //Elements are unordered and needs sorting on date
@Override
public int compare(ProjectScheduleEvent o1, ProjectScheduleEvent o2) {
logger.info("Comparing " +o1.getName() +" to " +o2.getName());
return o1.getDate().compareTo(o2.getDate());
}
});
long startingOffset = new DateTime(schedule.getStartDate()).getMillis();
for(final ProjectScheduleEvent event : eventList){
ProjectEventTemplate eventTemplate = new ProjectEventTemplate();
eventTemplate.setTitle(event.getName());
final long currentEventTime = (new DateTime(event.getDate()).getMillis());
final long diff = ((new DateTime(event.getDate()).getMillis()) - (startingOffset));
startingOffset = currentEventTime;//Append mode
final long offsetFromPrevious = diff / (24l * 60l * 60l * 1000l);//Convert to days
eventTemplate.setdaysOffset((int)offsetFromPrevious);
eventTemplate.setDescription(event.getDescription());
eventTemplate.setRequireHandIn(event.isUploadRequired());
eventTemplate.setTemplateCreator(user);
eventTemplate.setScheduleTemplate(template);
templateEventList.add(eventTemplate);
}
template.setProjectEventTemplates(templateEventList);
return scheduleTemplateDao.save(template);
}
/**
* Queries for all the available templates
* @param project
* @return
*/
@Transactional(readOnly=true)
public List<ScheduleTemplate> getAvailableTemplates(final Project project){
return scheduleTemplateDao.getScheduleTemplates(null,null,null); //Return active ones for the right project class, ignore other parameters
}
/**
* Removes an event, calls deleteSheduleEventUpload on any linked files.
* @param event
*/
@Transactional
public void deleteSheduleEvent(ProjectScheduleEvent event){
deleteSheduleEventUpload(event);
if(event != null && event.getId() != null){
event = projectScheduleEventDao.reLoad(event);
projectScheduleEventDao.delete(event);
}
}
/**
* Returns a list of all available file resources linked to this project.
* @param event
* @return
*/
public List<FileDescription> getAvailableResources(final ProjectScheduleEvent event){
List<FileDescription> resources = fileRepository.searchFiles(fileRepository.getProjectRootPath(event.getProjectSchedule().getProject().getId()), true);
fileRepository.sortFileDescriptions(resources, SortOrder.CreatedDesc);
return resources;
}
private String getAbsolutePath(final ProjectScheduleEvent evt){
return (fileRepository.getProjectRootPath(evt.getProjectSchedule().getProject().getId())+BASE_PATH+"/"+evt.getId());
}
}

@ -1,8 +1,7 @@
package se.su.dsv.scipro.util;
package se.su.dsv.scipro.activityplan.facade;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import org.apache.wicket.injection.web.InjectorHolder;
@ -11,17 +10,15 @@ import org.joda.time.DateMidnight;
import org.joda.time.DateTimeConstants;
import org.joda.time.Days;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.data.dao.interfaces.EventDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectEventDao;
import se.su.dsv.scipro.data.dao.interfaces.ScheduleTemplateDao;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectEvent;
import se.su.dsv.scipro.data.dataobjects.ProjectEventTemplate;
import se.su.dsv.scipro.data.dataobjects.ProjectSchedule;
import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
@Deprecated
public class ScheduleGenerator {
@SpringBean

@ -1,6 +1,5 @@
package se.su.dsv.scipro.util;
package se.su.dsv.scipro.activityplan.facade;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@ -8,9 +7,9 @@ import java.util.List;
import org.apache.wicket.IClusterable;
import se.su.dsv.scipro.data.dataobjects.ProjectEvent;
import se.su.dsv.scipro.data.dataobjects.ProjectSchedule;
import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
@Deprecated
public class ScheduleGeneratorResult implements IClusterable {
private static final long serialVersionUID = 1L;

@ -1,9 +1,8 @@
package se.su.dsv.scipro.util;
package se.su.dsv.scipro.activityplan.facade;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.wicket.injection.web.InjectorHolder;
@ -12,7 +11,6 @@ import org.joda.time.DateMidnight;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleDao;
import se.su.dsv.scipro.data.dao.interfaces.ScheduleTemplateDao;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectEvent;
@ -20,6 +18,7 @@ import se.su.dsv.scipro.data.dataobjects.ProjectEventTemplate;
import se.su.dsv.scipro.data.dataobjects.ProjectSchedule;
import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
@Deprecated
public class TemplateGenerator { //based on ScheduleGenerator
/*@SpringBean

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<div wicket:id="activityPlan"></div>
</wicket:extend>
</body>
</html>

@ -0,0 +1,18 @@
package se.su.dsv.scipro.activityplan.pages;
import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.activityplan.panels.ActivityPlanPanel;
import se.su.dsv.scipro.project.pages.ProjectPage;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@Authorization(authorizedRoles={Roles.STUDENT})
public class ProjectActivityPlanPage extends ProjectPage {
public ProjectActivityPlanPage(final PageParameters pp){
super(pp);
add(new ActivityPlanPanel("activityPlan",getActiveProject(),getUser()));
}
}

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<div wicket:id="activityPlan"></div>
</wicket:extend>
</body>
</html>

@ -0,0 +1,23 @@
package se.su.dsv.scipro.activityplan.pages;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.activityplan.panels.SupervisorActivityPlanPanel;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
import se.su.dsv.scipro.supervisor.pages.AbstractSupervisorProjectDetailsPage;
@Authorization(authorizedRoles={Roles.EMPLOYEE})
public class SupervisorActivityPlanPage extends AbstractSupervisorProjectDetailsPage {
public SupervisorActivityPlanPage(final PageParameters pp){
super(pp);
if(projectModel.getObject() == null)
add(new Label("activityPlan","No project selected"));
else
add(new SupervisorActivityPlanPanel("activityPlan", projectModel.getObject(),SciProSession.get().getUser()));
}
}

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<div>
<form wicket:id="modeForm">
<span wicket:id="modeGroup">
<input type="radio" wicket:id="upcoming"/>Show upcoming events<br/>
<input type="radio" wicket:id="past"/>Show past events<br/>
<input type="radio" wicket:id="between"/>Show events between<br/>
<span wicket:id="dateSelection">
<span wicket:id="dateFrom">datePicker</span><br/>
&nbsp;and <br/>
<span wicket:id="dateTo">datePicker</span><br/>
</span>
<input type="radio" wicket:id="all"/>Show all events<br/>
<input type="submit" style="display:none"/>
</span>
</form>
</div>
<div wicket:id="editDialog">
<div wicket:id="addScheduleEventPanel"></div>
</div>
<div wicket:id="checklistDialog">
<div wicket:id="checkLists">
<div wicket:id="listName"></div>
<a href="#" wicket:id="addLink">add</a>
</div>
</div>
<div><a href="#" wicket:id="createLink">create new&gt;&gt;</a></div>
<div wicket:id="addDialog">
<div wicket:id="addScheduleEventPanel"></div>
</div>
<div><a href="#" wicket:id="addFromTemplateLink">add from template&gt;&gt;</a></div>
<div><a href="#" wicket:id="saveAsTemplateLink">save as template&gt;&gt;</a></div>
<div wicket:id=dataViewContainer>
<div>
<table>
<thead class="blue-header">
<tr>
<td><a href="#" wicket:id="dateSort"><span wicket:id="dateLabel">date</span></a></td>
<td><a href="#" wicket:id="nameSort"><span wicket:id="nameLabel">name</span></a></td>
<td><a href="#" wicket:id="fileUploadSort"><span wicket:id="fileUploadLabel">fileUpload</span></a></td>
<td>Checklist</td>
<td>Edit</td>
<td>Delete</td>
</tr>
</thead>
<tbody>
<tr class="schedule-row" wicket:id="projectScheduleEvents">
<td><span wicket:id="date"></span></td>
<td><span wicket:id="name"></span></td>
<td><span wicket:id="fileUpload"></span></td>
<td>
<span wicket:id="checkListLabel"></span><a href="#" wicket:id="checkListLink">Checklist</a><a href="#" wicket:id="addCheckListLink">Add checklist</a>
</td>
<td><a href="#" wicket:id="editEventLink"><img src="images/icons/edit_16x16.png" alt="Edit"/></a></td>
<td><a href="#" wicket:id="deleteEventLink"><img src="images/icons/delete_16x16.png" alt="Delete"/></a></td>
</tr>
<tr class="blue-row">
<td colspan="9"></td>
</tr>
</tbody>
</table>
</div>
<div wicket:id="nav"></div>
</div>
<wicket:child />
</wicket:panel>
</body>
</html>

@ -0,0 +1,449 @@
package se.su.dsv.scipro.activityplan.panels;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ajax.AjaxEventBehavior;
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.form.Form;
import org.apache.wicket.markup.html.form.Radio;
import org.apache.wicket.markup.html.form.RadioGroup;
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.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
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.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.odlabs.wiquery.ui.dialog.Dialog;
import se.su.dsv.scipro.activityplan.facade.ProjectScheduleFacade;
import se.su.dsv.scipro.components.AbstractUploadForm;
import se.su.dsv.scipro.components.CustomDateTimeField;
import se.su.dsv.scipro.data.dataobjects.CheckList;
import se.su.dsv.scipro.data.dataobjects.FileDescription;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.dataproviders.ProjectScheduleEventDataProvider;
import se.su.dsv.scipro.dataproviders.SortSpecifier;
import se.su.dsv.scipro.project.pages.ProjectViewCheckListPage;
import se.su.dsv.scipro.repository.panels.FileViewDeletePanel;
import se.su.dsv.scipro.util.DateFormatter;
public class ActivityPlanPanel extends Panel {
private static final long serialVersionUID = 1L;
@SpringBean
private ProjectScheduleFacade facade;
private Dialog editEventDialog, checklistDialog, addFromTemplateDialog;
private AddScheduleEventsFromTemplatePanel addScheduleEventsFromTemplatePanel;
private EditScheduleEventPanel editScheduleEventPanel;
private DataView<ProjectScheduleEvent> dataView;
private WebMarkupContainer dataViewContainer;
private ProjectScheduleEventDataProvider sdp;
private final Project project;
private final User user;
private IModel<List<CheckList>> checkListModel;
private ListView<CheckList> checkLists;
private ProjectScheduleEvent currentEvent = null;
public ActivityPlanPanel(final String id, final Project project, final User user){
super(id);
this.project = project;
this.user = user;
//Setup edit-form
formSetup();
//Setup pop-up dialog
dialogSetup();
//Setup data view
dataViewSetup();
//Setup the model and listview for adding checklists
addChecklistSetup();
//Setup the dialog window for adding checklists
addChecklistDialogSetup();
//Add sorting controllers
addSortControls();
//Add search mode controllers
addModeControls();
//Add navigator
dataViewContainer.add(new PagingNavigator("nav", dataView));
}
protected final User getUser(){
return user;
}
protected final Project getProject(){
return project;
}
private void addModeControls(){
//Create date selection fluff
final WebMarkupContainer dateSelection = new WebMarkupContainer("dateSelection");
final Calendar cal = Calendar.getInstance();
final Date currentDate = cal.getTime();
cal.add(Calendar.MONTH, 1);
final Date futureDate = cal.getTime();
final CustomDateTimeField dateFrom = new CustomDateTimeField("dateFrom",new Model<Date>(currentDate));
final CustomDateTimeField dateTo = new CustomDateTimeField("dateTo",new Model<Date>(futureDate));
dateSelection.add(dateFrom);
dateSelection.add(dateTo);
dateSelection.setVisible(false);//Default hidden
dateSelection.setOutputMarkupId(true);
//Create radio button control group
final RadioGroup<ProjectScheduleEventDataProvider.SEARCH_MODE> modeGroup = new RadioGroup<ProjectScheduleEventDataProvider.SEARCH_MODE>("modeGroup", new Model<ProjectScheduleEventDataProvider.SEARCH_MODE>());
modeGroup.setOutputMarkupId(true);
modeGroup.setModel(new Model<ProjectScheduleEventDataProvider.SEARCH_MODE>(sdp.getSearchMode()));
//Create form, should be refactored out once the CustomDatePicker supports reliable callbacks
final Form<Void> modeForm = new Form<Void>("modeForm"){
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(){
sdp.setSearchMode(modeGroup.getModelObject());
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 ?
for(int i=1;i<arr.length;++i){
final ProjectScheduleEventDataProvider.SEARCH_MODE currentMode = arr[i];
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);
}
});
}
//Add components to hierarchy
modeGroup.add(dateSelection);
modeForm.add(modeGroup);
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);
}
private void dataViewSetup(){
//Config provider
dataViewContainer = new WebMarkupContainer("dataViewContainer");
sdp = new ProjectScheduleEventDataProvider(getProject());
sdp.setSearchMode(ProjectScheduleEventDataProvider.SEARCH_MODE.PROJECT_ALL);
//Add data view
dataView = new DataView<ProjectScheduleEvent>("projectScheduleEvents", sdp) {
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(final Item<ProjectScheduleEvent> item) {
final ProjectScheduleEvent event = item.getModelObject();
Label checkListLabel = new Label("checkListLabel", "No checklist");
PageParameters pp = new PageParameters();
if(event.getCheckList() != null){
pp.put("checklist", event.getCheckList().getId());
}
BookmarkablePageLink<Void> checkListLink = getBookmarkablePageLink(pp);
AjaxLink<Void> addCheckListLink = new AjaxLink<Void>("addCheckListLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
currentEvent = event;
checklistDialog.open(target);
}
};
//new BookmarkablePageLink<Void>("checkListLink", ProjectViewCheckListPage.class, pp);
item.add(new DateFormatter(DateFormatter.FORMAT.EXTENDED).createFormattedDateLabel("date",event.getDate()));
item.add(new Label("name",event.getName()));
if(event.getFileUpload() != null){
item.add(new FileViewDeletePanel("fileUpload",event.getFileUpload(),new FileViewDeletePanel.FileDeleteStrategy(){
@Override
public void handleDelete(final FileDescription fileDesc){//Delegate removal
facade.deleteSheduleEventUpload(event);
}
@Override
public boolean renderDeleteLink(){ //Only show remove links for the owner of the schedule event
return (getUser().equals(event.getCreator()));
}
}));
}else if(event.isUploadRequired())
item.add(new ProjectScheduleEventUploadForm(event).createDefaultWrapperPanel("fileUpload"));
else
item.add(new Label("fileUpload","n/a"));
item.add(checkListLink);
item.add(addCheckListLink);
item.add(checkListLabel);
if(event.getCheckList() == null){
checkListLink.setVisible(false);
if(willRenderAddChecklistLink()){
checkListLabel.setVisible(false);
}else{
addCheckListLink.setVisible(false);
}
}else{
checkListLabel.setVisible(false);
addCheckListLink.setVisible(false);
}
//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);
target.addComponent(editScheduleEventPanel);
editEventDialog.open(target);
}
@Override
public boolean isVisible(){
return (willRenderDeleteLink(event));
}
});
item.add(new Link<Void>("deleteEventLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick() {
facade.deleteSheduleEvent(event);
}
@Override
public boolean isVisible(){
return (willRenderDeleteLink(event));
}
});
}
};
dataViewContainer.setOutputMarkupId(true);
dataViewContainer.add(dataView);
add(dataViewContainer);
dataView.setItemsPerPage(10);
}
private void formSetup(){
editScheduleEventPanel = new EditScheduleEventPanel("addScheduleEventPanel"){
private static final long serialVersionUID = 1L;
@Override
public void handleSubmit(ProjectScheduleEvent event){
facade.saveProjectScheduleEvent(event);
}
};
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 event");
dummy.setCreator(getUser());
dummy.setProjectSchedule(getProject().getProjectSchedule());
editScheduleEventPanel.setDataFromEvent(dummy);
target.addComponent(editScheduleEventPanel);
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(getProject().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 (availableTemplates.size() > 0);//only show if there are templates to use
}
});
//Save as template link
add(new AjaxLink<Void>("saveAsTemplateLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
target.addComponent(addScheduleEventsFromTemplatePanel);
facade.createTemplateFromSchedule(getProject().getProjectSchedule(), getUser(), getProject().getProjectClass(), "Generated template", "Generated template description");
}
@Override
public boolean isVisible(){
return (getProject().getProjectSchedule() != null && sdp.size() > 0);//only show if there is a schedule with events
}
});
}
private void addSortControls(){
//Specify wanted sort specifier fields
final Set<String> sortFields = new HashSet<String>();
sortFields.add("date");
sortFields.add("name");
sortFields.add("fileUpload");
//do a simple translation
final HashMap<String, String> headerMap = new HashMap<String,String>();
headerMap.put("date","Event Date");
headerMap.put("name", "Event name");
headerMap.put("fileUpload", "Event resource");
for(final SortSpecifier spec : sdp.getAvailableSortSpecifiers(sortFields)){
final String fieldBaseName = spec.getFieldName();
final Link<Void> link = new Link<Void>(fieldBaseName+"Sort"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(){
SortSpecifier current = sdp.getSortSpecifier();
if(!spec.equals(current)){
sdp.setSortSpecifier(spec);
sdp.setAscendingOrder(false);
}else{
sdp.setAscendingOrder(!sdp.isAscendingOrder());
}
}
};
link.add(new Label(fieldBaseName+"Label",headerMap.get(fieldBaseName)));
dataViewContainer.add(link);
}
}
private class ProjectScheduleEventUploadForm extends AbstractUploadForm{
private static final long serialVersionUID = 1L;
private final ProjectScheduleEvent event;
ProjectScheduleEventUploadForm(final ProjectScheduleEvent event){
super();
this.event = event;
}
@Override
protected List<FileDescription> getSelectionElements(){
List<FileDescription> availableResources = facade.getAvailableResources(event);
return availableResources;
}
@Override
protected void onNewUpload(final FileUpload fileUpload) throws IOException{
facade.storeScheduleEventUpload(fileUpload, getUser(), event);
}
@Override
protected void onNewSelection(final FileDescription desc){
facade.setScheduleEventUpload(desc, getUser(), event);
}
}
private void addChecklistSetup(){
checkListModel = new LoadableDetachableModel<List<CheckList>>() {
private static final long serialVersionUID = 1L;
@Override
protected List<CheckList> load() {
return project.getCheckLists();
}
};
checkLists = new ListView<CheckList>("checkLists", checkListModel) {
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(final ListItem<CheckList> item) {
item.add(new Label("listName", item.getModel().getObject().getName()));
item.add(new AjaxLink<Void>("addLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
facade.addChecklistToEvent(currentEvent, item.getModelObject());
target.addComponent(dataViewContainer);
checklistDialog.close(target);
}
});
}
};
}
private void addChecklistDialogSetup(){
checklistDialog = new Dialog("checklistDialog");
checklistDialog.setModal(true);
checklistDialog.setAutoOpen(false);
checklistDialog.setWidth(500);
checklistDialog.setHeight(500);
checklistDialog.add(checkLists);
add(checklistDialog);
}
//here comes the methods to be overriden by subclasses
protected BookmarkablePageLink<Void> getBookmarkablePageLink(PageParameters pp){
return new BookmarkablePageLink<Void>("checkListLink", ProjectViewCheckListPage.class, pp);
}
protected boolean willRenderDeleteLink(ProjectScheduleEvent event){
return event.getCreator().equals(getUser());
}
protected boolean willRenderAddChecklistLink(){
return false;
}
}

@ -0,0 +1,24 @@
<!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>
<form wicket:id="form">
<div class="formRow">
<strong>From template:</strong>
<select wicket:id="fromTemplate"></select>
</div>
<div class="formRow">
<strong>Start date:</strong>
<div wicket:id="startDate"></div>
</div>
<div>
<input type="submit">Save</input>
</div>
</form>
</wicket:panel>
</body>
</html>

@ -0,0 +1,38 @@
package se.su.dsv.scipro.activityplan.panels;
import java.util.Date;
import java.util.List;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import se.su.dsv.scipro.components.CustomDateTimeField;
import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
/**
* Simple UI-controller panel for adding template events to a schedule.
*/
public abstract class AddScheduleEventsFromTemplatePanel extends Panel {
private static final long serialVersionUID = 1L;
public AddScheduleEventsFromTemplatePanel(final String id, List<ScheduleTemplate> availableTemplates){
super(id);
final CustomDateTimeField fromDate = new CustomDateTimeField("startDate",new Model<Date>(new Date()));
final DropDownChoice<ScheduleTemplate> dropDown = new DropDownChoice<ScheduleTemplate>("fromTemplate",new Model<ScheduleTemplate>(null),availableTemplates);
dropDown.setRequired(true);
fromDate.setRequired(true);
Form<Void> form = new Form<Void>("form"){
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(){
handleSubmit(dropDown.getModelObject(),fromDate.getModelObject());
}
};
form.add(fromDate);
form.add(dropDown);
add(form);
}
public abstract void handleSubmit(final ScheduleTemplate template, final Date fromDate);
}

@ -0,0 +1,34 @@
<!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>
<form wicket:id="formWrapper">
<div class="formRow">
<strong>Title:</strong><br />
<input type="text" wicket:id="title" />
</div>
<div class="formRow">
<strong>Description:</strong><br />
<textarea wicket:id="description"></textarea>
</div>
<div class="formRow">
<strong>Date:</strong>
<div wicket:id="dateField"></div>
</div>
<wicket:enclosure id="requiredToggle">
<div>
<strong>Require hand in: </strong>
<input type="checkbox" wicket:id="requireHandIn" />
</div>
</wicket:enclosure>
<div>
<input type="submit">Save</input>
</div>
</form>
</wicket:panel>
</body>
</html>

@ -0,0 +1,81 @@
package se.su.dsv.scipro.activityplan.panels;
import java.util.Date;
import org.apache.wicket.markup.html.form.CheckBox;
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.Model;
import org.apache.wicket.model.PropertyModel;
import se.su.dsv.scipro.components.CustomDateTimeField;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
/**
* Abstract base class for handling editing/adding of ScheduleEvents
* Subtype implementations are just required to handle submission from an internal form.
*/
public abstract class EditScheduleEventPanel extends Panel {
private CustomDateTimeField dp;
private TextField<String> title;
private TextArea<String> description;
private CheckBox handInRequiredCheckBox;
private Form<ProjectScheduleEvent> formWrapper;
private static final long serialVersionUID = 1L;
public EditScheduleEventPanel(String id){
super(id);
this.formWrapper = new Form<ProjectScheduleEvent>("formWrapper",new Model<ProjectScheduleEvent>(new ProjectScheduleEvent())){
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(){
handleSubmit(getEvent());
}
};
dp = new CustomDateTimeField("dateField", new PropertyModel<Date>(formWrapper.getModelObject(),"date"));
title = new TextField<String>("title", new PropertyModel<String>(formWrapper.getModelObject(),"name"));
description = new TextArea<String>("description", new PropertyModel<String>(formWrapper.getModelObject(),"description"));
handInRequiredCheckBox = new CheckBox("requireHandIn", new PropertyModel<Boolean>(formWrapper.getModelObject(),"uploadRequired")){
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible(){
return (formWrapper.getModelObject().getFileUpload()==null);
}
};
dp.setRequired(true);
formWrapper.add(title);
formWrapper.add(description);
formWrapper.add(dp);
formWrapper.add(handInRequiredCheckBox);
add(formWrapper);
}
/**
* Implement in subtype, is called when the wrapped form is submitted (this is where you want to handle the saved data).
*/
public abstract void handleSubmit(ProjectScheduleEvent event);
/**
* Convenience method
* @return
*/
private ProjectScheduleEvent getEvent(){
return formWrapper.getModelObject();
}
/**
* Use to set data from a value object to keep the internal model updated.
* @param fromEvent
*/
public void setDataFromEvent(ProjectScheduleEvent fromEvent){
getEvent().setId(fromEvent.getId());
getEvent().setCreator(fromEvent.getCreator());
getEvent().setProjectSchedule(fromEvent.getProjectSchedule());
getEvent().setDate(fromEvent.getDate());
getEvent().setDescription(fromEvent.getDescription());
getEvent().setName(fromEvent.getName());
getEvent().setUploadRequired(fromEvent.isUploadRequired());
getEvent().setVersion(fromEvent.getVersion());
getEvent().setFileUpload(fromEvent.getFileUpload());
}
}

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<wicket:extend>
</wicket:extend>
</wicket:panel>
</body>
</html>

@ -0,0 +1,39 @@
package se.su.dsv.scipro.activityplan.panels;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.supervisor.pages.SupervisorViewCheckListPage;
public class SupervisorActivityPlanPanel extends ActivityPlanPanel {
private static final long serialVersionUID = 1L;
public SupervisorActivityPlanPanel(final String id, final Project project, final User user){
super(id, project, user);
}
@Override
protected BookmarkablePageLink<Void> getBookmarkablePageLink(PageParameters pp){
System.out.println("supervisorpageLink");
return new BookmarkablePageLink<Void>("checkListLink", SupervisorViewCheckListPage.class, pp);
}
@Override
protected boolean willRenderDeleteLink(ProjectScheduleEvent event){
return true;
}
@Override
protected boolean willRenderAddChecklistLink(){
return true;
}
}

@ -1,12 +0,0 @@
package se.su.dsv.scipro.admin.pages;
import org.apache.wicket.PageParameters;
public abstract class AbstractAdminScheduleTemplatesPage extends AbstractAdminPage {
public AbstractAdminScheduleTemplatesPage(final PageParameters pp){
super(pp);
}
}

@ -9,7 +9,7 @@ import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@Authorization(authorizedRoles={Roles.SYSADMIN})
public class AdminScheduleTemplatesEditorPage extends AbstractAdminScheduleTemplatesPage {
public class AdminScheduleTemplatesEditorPage extends AbstractAdminPage {
@SpringBean
private ScheduleTemplateDao scheduleTemplateDao;

@ -4,7 +4,7 @@ import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.schedule.templates.panels.ScheduleTemplatePanel;
public class AdminScheduleTemplatesPage extends AbstractAdminScheduleTemplatesPage {
public class AdminScheduleTemplatesPage extends AbstractAdminPage {
public static final String MAIN_MENU_LABEL = "Schedule Templates";

@ -2,34 +2,23 @@
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<table class="rounded-corner">
<thead>
<tr>
<th class="rounded-left-top"><a href="#" wicket:id="sortById">Id</a></th>
<th><a href="#" wicket:id="sortByModified">Modified</a></th>
<th><a href="#" wicket:id="sortByTitle">Title</a></th>
<th><a href="#" wicket:id="sortByHead">Head supervisor</a></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="projectDataView">
<td><span wicket:id="id">[id]</span></td>
<td><span wicket:id="modified"></span></td>
<td><span wicket:id="title">[title]</span></td>
<td><span wicket:id="headSupervisor">[A Person]</span></td>
<td><a href=# wicket:id="editLink">Edit</a></td>
<wicket:extend>
<table class="rounded-corner">
<tr>
<th class="rounded-left-top"><a href="#" wicket:id="idSort">Id</a></th>
<th><a href="#" wicket:id="lastModifiedSort">Modified</a></th>
<th><a href="#" wicket:id="titleSort">Title</a></th>
<th><a href="#" wicket:id="headSupervisorSort">Head supervisor</a></th>
<th class="rounded-right-top">Edit</th>
</tr>
<tr wicket:id="projectDataView">
<td><span wicket:id="id">[id]</span></td>
<td><span wicket:id="modified"></span></td>
<td><span wicket:id="title">[title]</span></td>
<td><span wicket:id="headSupervisor">[A Person]</span></td>
<td><a href=# wicket:id="editLink">Edit</a></td>
</tr>
</tbody>
</table>
<div class="span-18 last">

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<table class="rounded-corner">
<tr>
<th class="rounded-left-top"><a href="#" wicket:id="idSort">Id</a></th>
<th><a href="#" wicket:id="lastModifiedSort">Modified</a></th>
<th><a href="#" wicket:id="titleSort">Title</a></th>
<th><a href="#" wicket:id="headSupervisorSort">Head supervisor</a></th>
<th class="rounded-right-top">Edit</th>
</tr>
<tr wicket:id="projectDataView">
<td><span wicket:id="id">[id]</span></td>
<td><span wicket:id="modified"></span></td>
<td><span wicket:id="title">[title]</span></td>
<td><span wicket:id="headSupervisor">[A Person]</span></td>
<td><a href=# wicket:id="editLink">Edit</a></td>
</tr>
</tbody>
</table>
<div class="span-18 last">
<span wicket:id="navigator">[dataview navigator]</span>
</div>
<div class="span-18 last">
<a href=# wicket:id="createLink">Create new project</a>
</div>
<div class="span-18 last">
<div wicket:id="feedback"></div>
</div>
<div class="span-18 last form-border" wicket:id="formContainer">
<form wicket:id="projectCreationForm">
<div>
<strong>Exists in Daisy/Match-system</strong>
<div wicket:id="existsInOtherSystems">NO</div>
</div>
<label for="projectTitle">Project title</label>
<div>
<input type="text" id="projectTitle" wicket:id="titleField"
size="60"></input>
</div>
<div>
<label for="projectClass">Type of project</label>
</div>
<span wicket:id="projectClass"> <input type="radio"
id="projectClass" />
</span>
<div>
<label for="students">Participating students</label>
</div>
<div wicket:id="projectParticipants" id="students"></div>
<div>
<label for="headSupervisor">Head supervisor</label>
</div>
<div wicket:id="headSupervisor" id="headSupervisor"></div>
<div>
<label for="followers">Add/edit project followers</label>
</div>
<div wicket:id="followers" id="followers"></div>
<div class="span-18 last">
<input type="submit" name="Save" title="Save" value="Save" />
</div>
</form>
</div>
</wicket:extend>
</body>
</html>

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<table class="rounded-table-top">
<tr>
<th><a href="#" wicket:id="sortById">Id</a></th>
<th><a href="#" wicket:id="sortByModified">Modified</a></th>
<th><a href="#" wicket:id="sortByTitle">Title</a></th>
<th><a href="#" wicket:id="sortByHead">Head supervisor</a></th>
<th>Edit</th>
</tr>
<tr wicket:id="projectDataView">
<td><span wicket:id="id">[id]</span></td>
<td><span wicket:id="modified"></span></td>
<td><span wicket:id="title">[title]</span></td>
<td><span wicket:id="headSupervisor">[A Person]</span></td>
<td><a href=# wicket:id="editLink">Edit</a></td>
</tr>
</table>
<div class="span-18 last">
<span wicket:id="navigator">[dataview navigator]</span>
</div>
<div class="span-18 last">
<a href=# wicket:id="createLink">Create new project</a>
</div>
<div class="span-18 last">
<div wicket:id="feedback"></div>
</div>
<div class="span-18 last form-border" wicket:id="formContainer">
<form wicket:id="projectCreationForm">
<div>
<strong>Exists in Daisy/Match-system</strong>
<div wicket:id="existsInOtherSystems">NO</div>
</div>
<label for="projectTitle">Project title</label>
<div>
<input type="text" id="projectTitle" wicket:id="titleField" size="60"></input>
</div>
<div>
<label for="projectClass">Type of project</label>
</div>
<span wicket:id="projectClass">
<input type="radio" id="projectClass"/>
</span>
<div><label for="students">Participating students</label></div>
<div wicket:id="projectParticipants" id="students"></div>
<div><label for="headSupervisor">Head supervisor</label></div>
<div wicket:id="headSupervisor" id="headSupervisor"></div>
<div><label for="followers">Add/edit project followers</label></div>
<div wicket:id="followers" id="followers"></div>
<div class="span-18 last">
<input type="submit" name="Save" title="Save" value="Save"/>
</div>
</form>
</div>
</wicket:extend>
</body>
</html>

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<table class="rounded-corner">
<thead>
<tr>
<th class="rounded-left-top"><a href="#" wicket:id="sortById">Id</a></th>
<th><a href="#" wicket:id="sortByModified">Modified</a></th>
<th><a href="#" wicket:id="sortByTitle">Title</a></th>
<th><a href="#" wicket:id="sortByHead">Head supervisor</a></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="projectDataView">
<td><span wicket:id="id">[id]</span></td>
<td><span wicket:id="modified"></span></td>
<td><span wicket:id="title">[title]</span></td>
<td><span wicket:id="headSupervisor">[A Person]</span></td>
<td><a href=# wicket:id="editLink">Edit</a></td>
</tr>
</tbody>
</table>
<div class="span-18 last">
<span wicket:id="navigator">[dataview navigator]</span>
</div>
<div class="span-18 last">
<a href=# wicket:id="createLink">Create new project</a>
</div>
<div class="span-18 last">
<div wicket:id="feedback"></div>
</div>
<div class="span-18 last form-border" wicket:id="formContainer">
<form wicket:id="projectCreationForm">
<div>
<strong>Exists in Daisy/Match-system</strong>
<div wicket:id="existsInOtherSystems">NO</div>
</div>
<label for="projectTitle">Project title</label>
<div>
<input type="text" id="projectTitle" wicket:id="titleField"
size="60"></input>
</div>
<div>
<label for="projectClass">Type of project</label>
</div>
<span wicket:id="projectClass"> <input type="radio"
id="projectClass" />
</span>
<div>
<label for="students">Participating students</label>
</div>
<div wicket:id="projectParticipants" id="students"></div>
<div>
<label for="headSupervisor">Head supervisor</label>
</div>
<div wicket:id="headSupervisor" id="headSupervisor"></div>
<div>
<label for="followers">Add/edit project followers</label>
</div>
<div wicket:id="followers" id="followers"></div>
<div class="span-18 last">
<input type="submit" name="Save" title="Save" value="Save" />
</div>
</form>
</div>
</wicket:extend>
</body>
</html>

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:extend>
<table class="rounded-table-top">
<tr>
<th><a href="#" wicket:id="idSort">Id</a></th>
<th><a href="#" wicket:id="lastModifiedSort">Modified</a></th>
<th><a href="#" wicket:id="titleSort">Title</a></th>
<th><a href="#" wicket:id="headSupervisorSort">Head supervisor</a></th>
<th>Edit</th>
</tr>
<tr wicket:id="projectDataView">
<td><span wicket:id="id">[id]</span></td>
<td><span wicket:id="modified"></span></td>
<td><span wicket:id="title">[title]</span></td>
<td><span wicket:id="headSupervisor">[A Person]</span></td>
<td><a href=# wicket:id="editLink">Edit</a></td>
</tr>
</table>
<div class="span-18 last">
<span wicket:id="navigator">[dataview navigator]</span>
</div>
<div class="span-18 last">
<a href=# wicket:id="createLink">Create new project</a>
</div>
<div class="span-18 last">
<div wicket:id="feedback"></div>
</div>
<div class="span-18 last form-border" wicket:id="formContainer">
<form wicket:id="projectCreationForm">
<div>
<strong>Exists in Daisy/Match-system</strong>
<div wicket:id="existsInOtherSystems">NO</div>
</div>
<label for="projectTitle">Project title</label>
<div>
<input type="text" id="projectTitle" wicket:id="titleField" size="60"></input>
</div>
<div>
<label for="projectClass">Type of project</label>
</div>
<span wicket:id="projectClass">
<input type="radio" id="projectClass"/>
</span>
<div><label for="students">Participating students</label></div>
<div wicket:id="projectParticipants" id="students"></div>
<div><label for="headSupervisor">Head supervisor</label></div>
<div wicket:id="headSupervisor" id="headSupervisor"></div>
<div><label for="followers">Add/edit project followers</label></div>
<div wicket:id="followers" id="followers"></div>
<div class="span-18 last">
<input type="submit" name="Save" title="Save" value="Save"/>
</div>
</form>
</div>
</wicket:extend>
</body>
</html>

@ -1,8 +1,10 @@
package se.su.dsv.scipro.admin.pages;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
@ -50,6 +52,7 @@ import se.su.dsv.scipro.data.dataobjects.ProjectTeamMember;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.facade.ProjectFacade;
import se.su.dsv.scipro.dataproviders.ProjectDataProvider;
import se.su.dsv.scipro.dataproviders.SortSpecifier;
import se.su.dsv.scipro.dataproviders.SortableDataProvider;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@ -93,7 +96,7 @@ public class ProjectManagementPage extends AbstractAdminPage {
formContainer.add(form);
formContainer.setVisible(false);
final SortableDataProvider<Project> dataProvider = new ProjectDataProvider(SortableDataProvider.MODIFIED_DESC);
final SortableDataProvider<Project> dataProvider = new ProjectDataProvider(/*SortableDataProvider.MODIFIED_DESC*/);
DataView<Project> dataView = new DataView<Project>("projectDataView",dataProvider, 20) {
private static final long serialVersionUID = 1L;
@ -120,43 +123,25 @@ public class ProjectManagementPage extends AbstractAdminPage {
add(dataView);
add(new PagingNavigator("navigator", dataView));
//Sorting controllers, could be made prettier
add(new Link<Void>("sortById"){
@Override
public void onClick(){
if(dataProvider.getSortSpecifier().equals(SortableDataProvider.ID_ASC))
dataProvider.setSortSpecifier(SortableDataProvider.ID_DESC);
else
dataProvider.setSortSpecifier(SortableDataProvider.ID_ASC);
}
});
add(new Link<Void>("sortByModified"){
@Override
public void onClick(){
if(dataProvider.getSortSpecifier().equals(SortableDataProvider.MODIFIED_ASC))
dataProvider.setSortSpecifier(SortableDataProvider.MODIFIED_DESC);
else
dataProvider.setSortSpecifier(SortableDataProvider.MODIFIED_ASC);
}
});
add(new Link<Void>("sortByTitle"){
@Override
public void onClick(){
if(dataProvider.getSortSpecifier().equals(ProjectDataProvider.TITLE_ASC))
dataProvider.setSortSpecifier(ProjectDataProvider.TITLE_DESC);
else
dataProvider.setSortSpecifier(ProjectDataProvider.TITLE_ASC);
}
});
add(new Link<Void>("sortByHead"){
@Override
public void onClick(){
if(dataProvider.getSortSpecifier().equals(ProjectDataProvider.HEAD_ASC))
dataProvider.setSortSpecifier(ProjectDataProvider.HEAD_DESC);
else
dataProvider.setSortSpecifier(ProjectDataProvider.HEAD_ASC);
}
});
//Add sorting controllers
final Set<String> wantedControllers = new HashSet<String>();
wantedControllers.add("id");
wantedControllers.add("lastModified");
wantedControllers.add("title");
wantedControllers.add("headSupervisor");
for(final SortSpecifier spec : dataProvider.getAvailableSortSpecifiers(wantedControllers)){
add(new Link<Void>(spec.getFieldName()+"Sort"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(){
SortSpecifier current = dataProvider.getSortSpecifier();
if(!spec.equals(current))
dataProvider.setSortSpecifier(spec);
else
dataProvider.setAscendingOrder(!dataProvider.isAscendingOrder());
}
});
}
AjaxLink<Void> createLink = new AjaxLink<Void>("createLink"){
private static final long serialVersionUID = 1L;

@ -39,7 +39,7 @@
<table class="rounded-corner">
<thead>
<tr>
<th class="rounded-left-top">Questions</th>
<th class="rounded-left-top">Name</th>
<th>Description</th>
<th>Hand-in</th>
<th>Uploaded by</th>

@ -41,7 +41,7 @@ public abstract class AbstractUploadForm extends Form<Void> {
* Default constructor, uses a fixed id to support the panel wrapper.
*/
public AbstractUploadForm(){
super("uploadForm");
this("uploadForm");
}
/**
* Alternate constructor, allowing for altered behavior for enforcing required fields.
@ -108,7 +108,8 @@ public abstract class AbstractUploadForm extends Form<Void> {
fileUploadField = new FileUploadField("fileUpload",new PropertyModel<FileUpload>(this,"upload"));
add(fileUploadField);
add(new Label("linkResourceLabel", new Model<String>("Or choose existing resource")));
add(new Label("linkResourceLabel", new Model<String>("Link to existing resource")));
add(new Label("uploadResourceLabel", new Model<String>("Upload new")));
List<FileDescription> availableResources = getSelectionElements();
final FileListSelect fileListSelect = new FileListSelect("linkResource", availableResources);
add(fileListSelect);
@ -130,10 +131,8 @@ public abstract class AbstractUploadForm extends Form<Void> {
fileDesc = linkedResource;
onNewSelection(fileDesc);
}
}catch(final RuntimeException re){//Allow implementations to signal failure via runtimes
error(re.getMessage());
}catch(final IOException ioe){//Use explicit error handling for uploading causing IOExceptions
error("An error occured while uploading the document, please try again");
error("An error occured while uploading the resource, please try again");
}
onFinished();
}

@ -7,21 +7,22 @@
<wicket:panel>
<form wicket:id="uploadForm">
<div>
<input type="file" wicket:id="fileUpload" />
</div>
<wicket:enclosure child="linkResource">
<div>
<span wicket:id="linkResourceLabel">[Or choose existing resource]</span>
<select wicket:id="linkResource">
<option selected value="0"></option>
<wicket:enclosure child="linkResource">
<span wicket:id="linkResourceLabel"></span>:&nbsp;
<select wicket:id="linkResource" style="font-size:80%">
<option selected value="0">[Link to existing resource]</option>
<option value="somefile.txt">somefile</option>
<option value="anotherfile.txt">anotherfile</option>
</select>
</wicket:enclosure>
</div>
</wicket:enclosure>
<div>
<button type="submit" wicket:id="submitButton">
Upload report
<span wicket:id="uploadResourceLabel">[Upload new resource]</span>:&nbsp;
<input type="file" wicket:id="fileUpload" style="font-size:80%"/>
</div>
<div>
<button type="submit" wicket:id="submitButton" style="font-size:80%">
<img src="css/blueprint/plugins/buttons/icons/tick.png" alt="" style="height:10px;width:10px;"/>Save
</button>
</div>
</form>

@ -5,9 +5,7 @@ import java.util.Date;
import java.util.List;
import se.su.dsv.scipro.data.dataobjects.Event;
import se.su.dsv.scipro.data.dataobjects.GroupEvent;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectEvent;
import se.su.dsv.scipro.data.dataobjects.User;
/**
* @author Martin Peters - mpeters@dsv.su.se

@ -1,11 +1,6 @@
package se.su.dsv.scipro.data.dao.interfaces;
import java.util.List;
import se.su.dsv.scipro.data.dataobjects.Event;
import se.su.dsv.scipro.data.dataobjects.ProjectSchedule;
public interface ProjectScheduleDao extends Dao<ProjectSchedule>{
}

@ -0,0 +1,32 @@
package se.su.dsv.scipro.data.dao.interfaces;
import java.util.Date;
import java.util.List;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
import se.su.dsv.scipro.data.support.QueryParams;
public interface ProjectScheduleEventDao extends Dao<ProjectScheduleEvent>{
/**
* Shorthand, equivalent to calling findEventsByProject(Project,null,null,null)
*/
public List<ProjectScheduleEvent> findEventsByProject(final Project project);
/**
* Shorthand, equivalent to calling findEventsByProject(Project,null,null,QueryParams)
*/
public List<ProjectScheduleEvent> findEventsByProject(final Project project,final QueryParams qParams);
/**
* Shorthand, equivalent to calling findEventsByProject(Project,Date,Date,null)
*/
public List<ProjectScheduleEvent> findEventsByProject(final Project project,final Date from, final Date to);
/**
* Finds all Events attached to the given project, dates and query parameters are optional and will be silently ignored if null.
*/
public List<ProjectScheduleEvent> findEventsByProject(final Project project,final Date from, final Date to, final QueryParams qParams);
/**
* Counts all Events attached to the given project, supplying of dates are optional (any combination of dates can be used).
*/
public int countEventsByProject(final Project project,final Date from,final Date to);
}

@ -7,6 +7,5 @@ import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
import se.su.dsv.scipro.data.dataobjects.User;
public interface ScheduleTemplateDao extends Dao<ScheduleTemplate>{
public List<ScheduleTemplate> getScheduleTemplates(final User creator, final Boolean isSysAdminTemplate,
final Boolean active, final ProjectClass projectClass);
public List<ScheduleTemplate> getScheduleTemplates(final User creator, final Boolean isSysAdminTemplate, final ProjectClass projectClass);
}

@ -6,6 +6,10 @@ import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import org.hibernate.ejb.QueryHints;
import org.springframework.orm.jpa.JpaCallback;
@ -14,6 +18,8 @@ import org.springframework.transaction.annotation.Transactional;
import se.su.dsv.scipro.data.dao.interfaces.Dao;
import se.su.dsv.scipro.data.dataobjects.DomainObject;
import se.su.dsv.scipro.data.support.QueryParams;
import se.su.dsv.scipro.exceptions.RenderingSafeException;
/**
*
@ -115,6 +121,54 @@ public abstract class AbstractDaoJPAImp<T extends DomainObject> extends JpaDaoSu
}
});
}
protected final void setQueryOrdering(final CriteriaQuery<T> query,final QueryParams qParams, final CriteriaBuilder cb,final Root<T> root){
if(qParams != null && qParams.getSortFieldName() != null){
final Order o = qParams.isSortFieldOrderAscending()?cb.asc(root.get(qParams.getSortFieldName())):cb.desc(root.get(qParams.getSortFieldName()));
query.orderBy(o);
}
}
/**
* Utility method used to limit output results of a query
* @param query
* @param start
* @param count
*/
private final void setQueryLimits(final TypedQuery<T> query,final int first, final int count){
if(first > 0)
query.setFirstResult(first);
if(count >= 0)
query.setMaxResults(count);
}
/**
* Factory style utility method, creates a typed query ready for running based on input parameters.
* @param queryString Should be a complete regular query string capable of running, without ORDER BY clause, a RenderingSafeException is thrown in case of an illegal value.
* @param sortingFieldPath If using joins and multiple joined tables share identifiers, you will need to supply information on which identifier entity you want to sort on. If the query is a single table one, just supply null.
* @param qParams Standard query parameters, what field to sort on etc. A null qParams will just create a regular query, a null qParams.getSortFieldName() will not perform any sorting.
* @param em EntityManager used to create the query, supplying null is undefined.
* @return
* Example usage (from ProjectScheduleEventDaoJPAImp):
* <code>
* String queryStr = "SELECT e FROM ProjectScheduleEvent AS e JOIN e.projectSchedule AS s WHERE s.project = :project AND e.date > :from AND e.date < :to";
* final Date dateFrom = from!=null?from:new Date(0);
* final Date dateTo = to!=null?to:new Date(Long.MAX_VALUE);
* TypedQuery<ProjectScheduleEvent> query = createSortedSelectQuery(queryStr,"e",qParams,em);
* query.setParameter("project", project);
* query.setParameter("from", dateFrom);
* query.setParameter("to", dateTo);
* return query.getResultList();
* </code>
*/
protected final TypedQuery<T> createSortedSelectQuery(final String queryString,final String sortingFieldPath,final QueryParams qParams,final EntityManager em){
if(queryString == null || queryString.contains("ORDER BY"))
throw new RenderingSafeException(new IllegalStateException("Supplying null as a query string is not allowed"));
String querySQLString = queryString;
if(qParams != null && qParams.getSortFieldName() != null){ //Add sorting details if present
querySQLString += (" ORDER BY "+(sortingFieldPath!=null?sortingFieldPath+".":"")+qParams.getSortFieldName()+" "+(qParams.isSortFieldOrderAscending()?" ASC":" DESC"));
}
final TypedQuery<T> query = em.createQuery(querySQLString,getDomainClass());
if(qParams!=null) //Add query limits if present
setQueryLimits(query,qParams.getFirstResultIndex(),qParams.getResultCount());
return query;
}
}

@ -0,0 +1,67 @@
package se.su.dsv.scipro.data.dao.jpa;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleEventDao;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
import se.su.dsv.scipro.data.support.QueryParams;
@Repository("projectScheduleEventDao")
public class ProjectScheduleEventDaoJPAImp extends LazyDeleteAbstractDaoJPAImp<ProjectScheduleEvent> implements ProjectScheduleEventDao{
public ProjectScheduleEventDaoJPAImp() {
super(ProjectScheduleEvent.class);
}
@Transactional(readOnly=true)
public List<ProjectScheduleEvent> findEventsByProject(final Project project){
return findEventsByProject(project,null,null,null);
}
@Transactional(readOnly=true)
public List<ProjectScheduleEvent> findEventsByProject(final Project project, final QueryParams qParams){
return findEventsByProject(project,null,null,qParams);
}
@Transactional(readOnly=true)
public List<ProjectScheduleEvent> findEventsByProject(final Project project, final Date from, final Date to){
return findEventsByProject(project,from,to,null);
}
@Transactional(readOnly=true)
public List<ProjectScheduleEvent> findEventsByProject(final Project project, final Date from, final Date to, final QueryParams qParams){
return getJpaTemplate().execute(new JpaCallback<List<ProjectScheduleEvent>>() {
public List<ProjectScheduleEvent> doInJpa(EntityManager em) throws PersistenceException {
String queryStr = "SELECT e FROM ProjectScheduleEvent AS e JOIN e.projectSchedule AS s WHERE s.project = :project AND e.date > :from AND e.date < :to";
final Date dateFrom = from!=null?from:new Date(0);
final Date dateTo = to!=null?to:new Date(Long.MAX_VALUE);
TypedQuery<ProjectScheduleEvent> query = createSortedSelectQuery(queryStr,"e",qParams,em);
query.setParameter("project", project);
query.setParameter("from", dateFrom);
query.setParameter("to", dateTo);
return query.getResultList();
}
});
}
@Transactional(readOnly=true)
public int countEventsByProject(final Project project,final Date from,final Date to){
return getJpaTemplate().execute(new JpaCallback<Integer>() {
public Integer doInJpa(EntityManager em) throws PersistenceException {
final Date dateFrom = from!=null?from:new Date(0);
final Date dateTo = to!=null?to:new Date(Long.MAX_VALUE);
TypedQuery<Long> query = em.createQuery("SELECT COUNT(e) FROM ProjectScheduleEvent AS e JOIN e.projectSchedule AS s WHERE s.project = :project AND e.date > :from AND e.date < :to", Long.class);
query.setParameter("project", project);
query.setParameter("from", dateFrom);
query.setParameter("to", dateTo);
return (query.getSingleResult()).intValue();
}
});
}
}

@ -26,8 +26,7 @@ public class ScheduleTemplateDaoJPAImp extends AbstractDaoJPAImp<ScheduleTemplat
}
@Transactional
public List<ScheduleTemplate> getScheduleTemplates(final User creator, final Boolean isSysAdminTemplate,
final Boolean active, final ProjectClass projectClass) {
public List<ScheduleTemplate> getScheduleTemplates(final User creator, final Boolean isSysAdminTemplate, final ProjectClass projectClass) {
return getJpaTemplate().execute(new JpaCallback<List<ScheduleTemplate>>() {
public List<ScheduleTemplate> doInJpa(EntityManager em)
throws PersistenceException {
@ -39,22 +38,15 @@ public class ScheduleTemplateDaoJPAImp extends AbstractDaoJPAImp<ScheduleTemplat
if(isSysAdminTemplate != null){
conditions.add("st.isSysAdminTemplate = :isSysAdminTemplate ");
}
if(creator != null){
fromClause += ", User u ";
joinClause += "join u.roles role ";
conditions.add("role = st.creator ");
conditions.add("u = :user ");
}
if(active != null){
conditions.add("st.active = :active ");
}
if(projectClass != null){
conditions.add("st.projectClass = :projectClass ");
}
String cond = "";
for(String c : conditions){
if(conditions.indexOf(c) == 0)
@ -67,21 +59,14 @@ public class ScheduleTemplateDaoJPAImp extends AbstractDaoJPAImp<ScheduleTemplat
q += " order by st.templateName asc";
TypedQuery<ScheduleTemplate> query = em.createQuery(q, ScheduleTemplate.class);
if(isSysAdminTemplate != null){
query.setParameter("isSysAdminTemplate", isSysAdminTemplate);
}
if(creator != null){
query.setParameter("user", creator);
}
if(active != null){
query.setParameter("active", active);
}
if(projectClass != null){
query.setParameter("projectClass", projectClass);
}

@ -3,11 +3,15 @@ package se.su.dsv.scipro.data.dataobjects;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Version;
import org.apache.wicket.IClusterable;
import se.su.dsv.scipro.dataproviders.SortableField;
/**
*
* @author Martin Peters - mpeters@dsv.su.se
@ -19,11 +23,17 @@ public abstract class DomainObject implements IClusterable{
private static final long serialVersionUID = 1L;
@Basic(optional=false)
@SortableField
private Date dateCreated;
@Basic(optional=false)
@SortableField
private Date lastModified;
@Version
@Column(nullable = false)
private int version=0;
abstract public Long getId();
@PreUpdate
@ -34,21 +44,47 @@ public abstract class DomainObject implements IClusterable{
dateCreated = lastModified;
}
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Date getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
/**
* Override in subtypes only if identity/hashcode differs from primary key identity.
*/
@Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null)
return false;
if(this.getClass() != obj.getClass())
return false;
final DomainObject other = (DomainObject) obj;
final Long thisID = getId();
final Long thatID = other.getId();
return (thisID==null?thatID==null:thisID.equals(thatID));
}
/**
* Override in subtypes only if identity/hashcode differs from primary key identity.
*/
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (getId()==null?0:getId().hashCode());
return result;
}
}

@ -12,19 +12,15 @@ import se.su.dsv.scipro.data.dao.interfaces.LazyDeletable;
*/
@MappedSuperclass
public abstract class LazyDeletableDomainObject extends DomainObject implements LazyDeletable{
private static final long serialVersionUID = 1L;
@Index(name="deleted_index") //Hibernate specific, for performance
private boolean deleted = false;
/**
* @param set the object to be lazily deleted or not, does not take effect until after the object being saved.
*/
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
/**
* @return if the object is lazily deleted or not
*/

@ -34,7 +34,7 @@ import se.su.dsv.scipro.data.dataobjects.interfaces.Commentable;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.data.enums.ProjectTeamMemberRoles;
import se.su.dsv.scipro.data.enums.StateOfMind;
import se.su.dsv.scipro.data.facade.ProjectFacade;
import se.su.dsv.scipro.dataproviders.SortableField;
import se.su.dsv.scipro.icons.IconPanel;
import se.su.dsv.scipro.icons.IconizedComponent;
import se.su.dsv.scipro.icons.ImageIcon;
@ -62,6 +62,7 @@ public class Project extends DomainObject implements Comparable<Project>, Iconiz
@Column(length=255)
@Basic(optional=false)
@SortableField
private String title;
@ManyToMany(targetEntity=Student.class)
@ -74,19 +75,12 @@ public class Project extends DomainObject implements Comparable<Project>, Iconiz
private SortedSet<ProjectFollower> projectFollowers = new TreeSet<ProjectFollower>();
@ManyToOne
@SortableField
private Employee headSupervisor;
@OneToOne(mappedBy="project")
private Log log;
public Log getLog() {
return log;
}
public void setLog(Log log) {
this.log = log;
}
@Enumerated(EnumType.STRING)
private ProjectStatus projectStatus = ProjectStatus.ACTIVE;
@ -160,6 +154,14 @@ public class Project extends DomainObject implements Comparable<Project>, Iconiz
this.title = title;
}
public Log getLog() {
return log;
}
public void setLog(Log log) {
this.log = log;
}
public SortedSet<Student> getProjectParticipants() {
return projectParticipants;
}

@ -5,6 +5,7 @@ import java.util.Set;
import java.util.TreeSet;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@ -34,6 +35,9 @@ public class ProjectSchedule extends DomainObject {
@ManyToMany(mappedBy="projectSchedules")
private Set<GroupEvent> groupEvents = new TreeSet<GroupEvent>();
@OneToMany(mappedBy="projectSchedule",cascade=CascadeType.PERSIST)
private Set<ProjectScheduleEvent> events = new TreeSet<ProjectScheduleEvent>();
@OneToOne(optional=false)
private Project project;
@ -82,6 +86,14 @@ public class ProjectSchedule extends DomainObject {
public void setGroupEvents(Set<GroupEvent> groupEvents) {
this.groupEvents = groupEvents;
}
public Set<ProjectScheduleEvent> getEvents() {
return events;
}
public void setEvents(Set<ProjectScheduleEvent> events) {
this.events = events;
}
public void setStartDate(Date startDate){
this.startDate = startDate;
@ -90,34 +102,4 @@ public class ProjectSchedule extends DomainObject {
public Date getStartDate(){
return startDate;
}
@Override
public int hashCode() {
final int weight = 31;
int result = 17;
result = weight * result + ((id == null) ? 0 : (int) (id ^ (id >>> 32)));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
ProjectSchedule other = (ProjectSchedule) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}

@ -0,0 +1,118 @@
package se.su.dsv.scipro.data.dataobjects;
import java.util.Date;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import se.su.dsv.scipro.dataproviders.SortableField;
@Entity
@Table(name="project_schedule_event")
@Cacheable(true)
@Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ProjectScheduleEvent extends LazyDeletableDomainObject {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Long id;
@ManyToOne(optional=false)
@JoinColumn (name="projectSchedule_id")
@SortableField
private ProjectSchedule projectSchedule;
@ManyToOne(optional=false)
@SortableField
private User creator;
@Column(nullable=false)
@SortableField
private Date date;
@Column(length=50,nullable=false)
@SortableField
private String name;
@Column(nullable=false,length=512)
@SortableField
private String description;
@Column(nullable=false)
@SortableField
private boolean uploadRequired;
@OneToOne(optional = true, orphanRemoval = true, cascade = CascadeType.ALL)
@SortableField
private FileDescription fileUpload;
@ManyToOne
private CheckList checkList;
public ProjectScheduleEvent() {
this.uploadRequired = false;
this.name = "";
this.description = "";
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ProjectSchedule getProjectSchedule() {
return projectSchedule;
}
public void setProjectSchedule(ProjectSchedule projectSchedule) {
this.projectSchedule = projectSchedule;
}
public User getCreator() {
return creator;
}
public void setCreator(User creator) {
this.creator = creator;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isUploadRequired() {
return uploadRequired;
}
public void setUploadRequired(boolean uploadRequired) {
this.uploadRequired = uploadRequired;
}
public FileDescription getFileUpload() {
return fileUpload;
}
public void setFileUpload(FileDescription fileUpload) {
this.fileUpload = fileUpload;
}
public CheckList getCheckList() {
return checkList;
}
public void setCheckList(CheckList checkList) {
this.checkList = checkList;
}
@Override
public String toString(){
return "Event: "+getName()+"@"+getDate()+" on "+getProjectSchedule()+" by "+getCreator();
}
}

@ -13,7 +13,6 @@ import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PreRemove;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
@ -46,9 +45,6 @@ public class ScheduleTemplate extends DomainObject {
@Column(nullable=false)
private String templateName;
@Column(nullable=false)
private Boolean active = false;
@Lob
private String templateDescription;
@ -58,7 +54,6 @@ public class ScheduleTemplate extends DomainObject {
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ -67,7 +62,6 @@ public class ScheduleTemplate extends DomainObject {
Collections.sort(projectEventTemplates);
return projectEventTemplates;
}
public void setProjectEventTemplates(List<ProjectEventTemplate> projectEventTemplates) {
Collections.sort(projectEventTemplates);
this.projectEventTemplates = projectEventTemplates;
@ -76,7 +70,6 @@ public class ScheduleTemplate extends DomainObject {
public User getCreator() {
return creator;
}
public void setCreator(User creator) {
this.creator = creator;
}
@ -84,7 +77,6 @@ public class ScheduleTemplate extends DomainObject {
public ProjectClass getProjectClass() {
return projectClass;
}
public void setProjectClass(ProjectClass projectClass) {
this.projectClass = projectClass;
}
@ -92,7 +84,6 @@ public class ScheduleTemplate extends DomainObject {
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
@ -100,7 +91,6 @@ public class ScheduleTemplate extends DomainObject {
public String getTemplateDescription() {
return templateDescription;
}
public void setTemplateDescription(String templateDescription) {
this.templateDescription = templateDescription;
}
@ -108,54 +98,15 @@ public class ScheduleTemplate extends DomainObject {
public void setSysAdminTemplate(boolean isSysAdminTemplate) {
this.isSysAdminTemplate = isSysAdminTemplate;
}
public boolean isSysAdminTemplate() {
return isSysAdminTemplate;
}
public void setActive(boolean active) {
this.active = active;
}
public boolean isActive() {
return active;
}
public void addProjectEventTemplate(ProjectEventTemplate e){
e.setScheduleTemplate(this);
projectEventTemplates.add(e);
}
@Override
public int hashCode() {
final int weight = 31;
int result = 17;
result = weight * result + ((id == null) ? 0 : (int) (id ^ (id >>> 32)));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
ScheduleTemplate other = (ScheduleTemplate) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
@Override
public String toString(){
return getTemplateName();

@ -2,14 +2,12 @@ package se.su.dsv.scipro.data.facade;
import java.util.List;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import se.su.dsv.scipro.data.dao.interfaces.CheckListDao;
import se.su.dsv.scipro.data.dao.interfaces.CheckListQuestionDao;
import se.su.dsv.scipro.data.dao.interfaces.CheckListTemplateDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dataobjects.CheckList;
import se.su.dsv.scipro.data.dataobjects.CheckListQuestion;
import se.su.dsv.scipro.data.dataobjects.CheckListTemplate;
@ -28,14 +26,10 @@ public class ProjectFacade {
@Autowired
private CheckListQuestionDao checkListQuestionDao;
@Autowired
private ProjectDao projectDao;
public void generateChecklists(Project project){
List<CheckListTemplate> templates;
//project = projectDao.save(project);
if(project.getProjectClass().getCode().equals(ProjectClass.BACHELOR)){
templates = checkListTemplateDao.findTemplatesByCategory("Bachelor");
}else{

@ -0,0 +1,42 @@
package se.su.dsv.scipro.data.support;
/**
* Final value class for wrapping common SQL query parameters.
* Design is very simple, the objects are immutable and anyone accepting a QueryParams object should be prepared for handling null values in any field.
*/
public final class QueryParams {
private final String sortFieldName;
private final boolean sortFieldOrderAscending;
private final int firstResultIndex;
private final int resultCount;
public QueryParams(final String sortFieldName,final boolean isAscendingOrder, final int firstResultIndex, final int resultCount){
this.sortFieldName = sortFieldName;
this.sortFieldOrderAscending = isAscendingOrder;
this.firstResultIndex = firstResultIndex;
this.resultCount = resultCount;
}
public QueryParams(final String sortFieldName, final int firstResultIndex, final int resultCount){
this(sortFieldName,true,firstResultIndex,resultCount);
}
public QueryParams(final String sortFieldName, boolean isAscendingOrder){
this(sortFieldName,isAscendingOrder,-1,-1);
}
public QueryParams(final String sortFieldName){
this(sortFieldName,true,-1,-1);
}
public QueryParams(final int firstResultIndex, final int resultCount){
this(null,true,firstResultIndex,resultCount);
}
public String getSortFieldName() {
return sortFieldName;
}
public boolean isSortFieldOrderAscending() {
return sortFieldOrderAscending;
}
public int getFirstResultIndex() {
return firstResultIndex;
}
public int getResultCount() {
return resultCount;
}
}

@ -1,8 +1,5 @@
package se.su.dsv.scipro.dataproviders;
import java.util.ArrayList;
import java.util.List;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.data.dao.interfaces.Dao;
@ -15,11 +12,6 @@ import se.su.dsv.scipro.data.dataobjects.Project;
*/
public class ProjectDataProvider extends SortableDataProvider<Project>{
private static final long serialVersionUID = 1L;
//Custom sorting-specifiers available for project queries
public static final SortSpecifier HEAD_ASC = new SortSpecifier("headSupervisor",true);
public static final SortSpecifier HEAD_DESC = new SortSpecifier("headSupervisor",false);
public static final SortSpecifier TITLE_ASC = new SortSpecifier("title",true);
public static final SortSpecifier TITLE_DESC = new SortSpecifier("title",false);
@SpringBean
protected ProjectDao projectDao;
@Override
@ -30,15 +22,6 @@ public class ProjectDataProvider extends SortableDataProvider<Project>{
this(null);
}
public ProjectDataProvider(final SortSpecifier sortSpecifier) {
super(sortSpecifier);
}
@Override
protected List<SortSpecifier> getAvailableExtensionFields(){
List<SortSpecifier> list = new ArrayList<SortSpecifier>();
list.add(HEAD_ASC);
list.add(HEAD_DESC);
list.add(TITLE_ASC);
list.add(TITLE_DESC);
return list;
super(sortSpecifier,Project.class);
}
}

@ -0,0 +1,146 @@
package se.su.dsv.scipro.dataproviders;
import java.util.Date;
import java.util.Iterator;
import org.apache.log4j.Logger;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleEventDao;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
import se.su.dsv.scipro.data.support.QueryParams;
/**
* Custom (and well behaved) SortableDataProvider implementation with Dao-injection override mechanics and custom sorting-fields.
* @see base type for more information.
*/
public class ProjectScheduleEventDataProvider extends SortableDataProvider<ProjectScheduleEvent>{
public enum SEARCH_MODE {ALL{
public String toString() {
return "all_unbound";
}
},PROJECT_ALL{
public String toString() {
return "all";
}
},PROJECT_PAST{
public String toString() {
return "past";
}
},PROJECT_FUTURE{
public String toString() {
return "upcoming";
}
},PROJECT_BETWEEN{
public String toString() {
return "between";
}
}};
private static final long serialVersionUID = 1L;
@SpringBean
protected ProjectScheduleEventDao projectScheduleEventDao;
private SEARCH_MODE currentSearchMode = SEARCH_MODE.PROJECT_ALL;
private final Project project;
private final transient Logger logger = Logger.getLogger(ProjectScheduleEventDataProvider.class);
private Date fromDate;
private Date toDate;
@Override
protected ProjectScheduleEventDao getDao() {
return projectScheduleEventDao;
}
/**
* Create provider for Project p.
* You can supply null values for "p", in which case the provider will return all schedule events regardless of project ownership.
* By default, the current date is used for date-boundaries (see setDateBoundaries).
*/
public ProjectScheduleEventDataProvider(final Project p) {
this(null,p);
}
/**
* Create provider with the given SortSpecifier for Project p.
* You can supply null values for "p", in which case the provider will return all schedule events regardless of project ownership.
* By default, the current date is used for date-boundaries (see setDateBoundaries).
* @param sortSpecifier
* @param p
* @param u
*/
public ProjectScheduleEventDataProvider(final SortSpecifier sortSpecifier, final Project p) {
super(sortSpecifier,ProjectScheduleEvent.class);
this.project = p;
setDateBoundaries(null,null);
}
/**
* Sets search mode for iterator returns, if the provider has been created with a null project then the search mode will always be SEARCH_MODE.ALL.
* @param mode
*/
public void setSearchMode(SEARCH_MODE mode){
if(project == null)
currentSearchMode = SEARCH_MODE.ALL;
else
currentSearchMode = mode;
logger.debug("Now using search mode: "+currentSearchMode);
}
/**
* Getter for the current search mode.
* @return
*/
public SEARCH_MODE getSearchMode(){
return currentSearchMode;
}
/**
* Sets date-boundaries for the PROJECT_BETWEEN, PROJECT_PAST and PROJECT_FUTURE search mode type, not used in other modes.
* If either parameter is null, the current date will be used for that parameter.
*/
public void setDateBoundaries(final Date fromDate, final Date toDate){
this.fromDate = (fromDate!=null?fromDate:new Date());
this.toDate = (toDate!=null?toDate:new Date());
}
/**
* No backed support available for sorting yet, default facilities (with full sorting support) are used when search mode is ALL.
*/
@Override
public Iterator<ProjectScheduleEvent> iterator(int first, int count) {
Iterator<ProjectScheduleEvent> itr = null;
switch(currentSearchMode){
case ALL:
itr = super.iterator(first, count);
break;
case PROJECT_ALL:
itr = getDao().findEventsByProject(project,new QueryParams(getSafeSortSpecifier().getFieldName(),isAscendingOrder(),first,count)).iterator();
break;
case PROJECT_PAST:
itr = getDao().findEventsByProject(project,null,toDate,new QueryParams(getSafeSortSpecifier().getFieldName(),isAscendingOrder(),first,count)).iterator();
break;
case PROJECT_FUTURE:
itr = getDao().findEventsByProject(project,fromDate,null,new QueryParams(getSafeSortSpecifier().getFieldName(),isAscendingOrder(),first,count)).iterator();
break;
case PROJECT_BETWEEN:
itr = getDao().findEventsByProject(project,fromDate,toDate,new QueryParams(getSafeSortSpecifier().getFieldName(),isAscendingOrder(),first,count)).iterator();
break;
}
return itr;
}
@Override
public int size() {
int returnValue=0;
switch(currentSearchMode){
case ALL:
returnValue = getDao().countAll();
break;
case PROJECT_ALL:
returnValue = getDao().countEventsByProject(project,null,null);
break;
case PROJECT_PAST:
returnValue = getDao().countEventsByProject(project,null,toDate);
break;
case PROJECT_FUTURE:
returnValue = getDao().countEventsByProject(project,fromDate,null);
break;
case PROJECT_BETWEEN:
returnValue = getDao().countEventsByProject(project,fromDate,toDate);
break;
}
return returnValue;
}
}

@ -4,20 +4,21 @@ import java.io.Serializable;
/**
* SortingSpecifier helper value object for the SortableDataProvider mini-API.
* Intances are guaranteed to be immutable and subclassing is not allowed, see SortableDataProvider and/or ProjectDataProvider for sample usage.
* Instances are guaranteed to be immutable and subclassing is not allowed, see SortableDataProvider and/or ProjectDataProvider for sample usage.
*/
public final class SortSpecifier implements Serializable{
private static final long serialVersionUID = 1L;
private final String fieldName;
private final boolean isAscendingOrder;
public SortSpecifier(final String fieldName,final boolean isAscendingOrder){
public SortSpecifier(final String fieldName){
if(fieldName == null)
throw new IllegalStateException("The fieldName parameter is not allowed NULL values");
this.fieldName = fieldName;
this.isAscendingOrder = isAscendingOrder;
}
public String getSortString(){
return (fieldName+(isAscendingOrder?" ASC":" DESC"));
return (fieldName);
}
public String getFieldName(){
return fieldName;
}
@Override
public boolean equals(Object o){
@ -26,17 +27,16 @@ public final class SortSpecifier implements Serializable{
if(!(o instanceof SortSpecifier))
return false;
SortSpecifier rhs = (SortSpecifier)o;
return ((isAscendingOrder == rhs.isAscendingOrder) && (fieldName.equals(rhs.fieldName)));
return (fieldName.equals(rhs.fieldName));
}
@Override
public int hashCode(){
int result = 17;
result = 31 * result + (isAscendingOrder?1:0);
result = 31 * result + fieldName.hashCode();
return result;
}
@Override
public String toString(){
return fieldName+(isAscendingOrder?" ASC":" DESC");
return fieldName;
}
}

@ -1,10 +1,14 @@
package se.su.dsv.scipro.dataproviders;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.wicket.injection.web.InjectorHolder;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.model.IModel;
@ -16,11 +20,12 @@ import se.su.dsv.scipro.data.dataobjects.DomainObject;
/**
* SortableDataProvider for any DomainObject.
* Provides mechanics for sorting output from a wicket IDataProvider via all fields existing in the DomainObject public API.
* As a client of this class, you typically feed it the parameterized type and a Dao capable of fetching that type.
* As a client of this class, you typically feed it the parameterized type, a Dao capable of fetching that type and the DomainObject.class
* identifier (which is used to scan your class for "SortableField" annotations)
*
* Typical client usage:
* <code>
* SortableDataProvider<Project> sdp = new SortableDataProvider<Project>(projectDao);
* SortableDataProvider<Project> sdp = new SortableDataProvider<Project>(projectDao,Project.class);
* DataView<Project> dataView = new DataView<Project>("projectDataView",sdp, 20){....};
* </code>
* The available sorting-capable fields are accessible through iteration and as named constants.
@ -28,11 +33,12 @@ import se.su.dsv.scipro.data.dataobjects.DomainObject;
* For implementors of subtypes:
* You will probably want use to the protected constructors and override the getDao() method if you have the need to encapsulate
* dao-object ownership inside your implementation. See "ProjectDataProvider" for an example of this.
* Now for the most important part: if you add SortSpecifier fields in your implementation to provide named constants (they should be "public static final"), make sure that
* these fields are also returned by an implementation of getAvailableExtensionFields(). If you do this and follow the modifier conventions, your implementation can
* be tested for type-safety (or rather: query-field safety) by the facilities provided in "TestSortableDataProvider" with just one line of code.
* SpringBean-injection is guaranteed to happen before any overridable methods are called.
*
*
* Now for the most important part: adding sortable fields. This is actually quite simple, the only thing
* you have to do is to annotate the target DomainObject implementation with the "SortableField" annotation and the base class functionality
* will take care of the rest via annotation/reflection. You don't need to do anything in the subtypes (and you probably don't want to), but if you really want to you can override
* getAvailableExtensionFields() to provide additional sort-specifiers.
* @param <T>
*/
public class SortableDataProvider<T extends DomainObject> implements IDataProvider<T> {
@ -40,49 +46,34 @@ public class SortableDataProvider<T extends DomainObject> implements IDataProvid
private SortSpecifier inUseSpecifier;
private List<SortSpecifier> availableSpecifiers;
private Dao<T> dao;
private Class<T> domainClass;
private boolean ascending=true;
private transient Logger logger = Logger.getLogger(SortableDataProvider.class);
/**
* Named SortSpecifier constant, @see getAvailableSortSpecifiers()
*/
public static final SortSpecifier ID_ASC = new SortSpecifier("id",true);
/**
* Named SortSpecifier constant, @see getAvailableSortSpecifiers()
*/
public static final SortSpecifier ID_DESC = new SortSpecifier("id",false);
/**
* Named SortSpecifier constant, @see getAvailableSortSpecifiers()
*/
public static final SortSpecifier CREATED_ASC = new SortSpecifier("dateCreated",true);
/**
* Named SortSpecifier constant, @see getAvailableSortSpecifiers()
*/
public static final SortSpecifier CREATED_DESC = new SortSpecifier("dateCreated",false);
/**
* Named SortSpecifier constant, @see getAvailableSortSpecifiers()
*/
public static final SortSpecifier MODIFIED_ASC = new SortSpecifier("lastModified",true);
/**
* Named SortSpecifier constant, @see getAvailableSortSpecifiers()
*/
public static final SortSpecifier MODIFIED_DESC = new SortSpecifier("lastModified",false);
public static final SortSpecifier ID = new SortSpecifier("id");
/**
* Constructs a SortableDataProvider using the supplied Dao object.
* A null value for the dao-parameter is not allowed and will throw an IllegalStateException.
* A null value for the domainClass-parameter is allowed and will cause standard "DomainObject" sorters to be generated.
* @param dao
*/
public SortableDataProvider(final Dao<T> dao){
this(null,dao);
public SortableDataProvider(final Dao<T> dao, final Class<T> domainClass){
this(null,dao,domainClass);
}
/**
* Constructs a SortableDataProvider using the supplied Dao object and SortSpecifier.
* A null value for the SortSpecifier parameter is allowed and will cause standard "unsorted" results.
* A null value for the dao-parameter is not allowed and will throw an IllegalStateException.
* A null value for the domainClass-parameter is allowed and will cause standard "DomainObject" sorters to be generated.
* @param sortSpecifier
* @param dao
*/
public SortableDataProvider(final SortSpecifier sortSpecifier, final Dao<T> dao) {
public SortableDataProvider(final SortSpecifier sortSpecifier, final Dao<T> dao, final Class<T> domainClass) {
InjectorHolder.getInjector().inject(this);
this.dao = dao;
this.domainClass = domainClass;
if(getDao() == null)//Constructed like this to allow sublasses passing null values as long as they provide a valid Dao via getDao() after IOC-injection has taken place
throw new IllegalStateException("Sorry, you have to provide a non-null Dao object");
populateAvailableSpecifiers();
@ -92,13 +83,13 @@ public class SortableDataProvider<T extends DomainObject> implements IDataProvid
* Exposed to subtypes to support certain constructs (mostly when getDao is overriden in a subtype).
*/
protected SortableDataProvider() {
this(null,null);
this(null,null,null);
}
/**
* Exposed to subtypes to support certain constructs (mostly when getDao is overriden in a subtype).
*/
protected SortableDataProvider(final SortSpecifier sortSpecifier) {
this(sortSpecifier,null);
protected SortableDataProvider(final SortSpecifier sortSpecifier, Class<T> domainClass) {
this(sortSpecifier,null,domainClass);
}
/**
* Default implementation returns the Dao registered with the object at creation time, override to provide your own encapsulation mechanics.
@ -108,9 +99,15 @@ public class SortableDataProvider<T extends DomainObject> implements IDataProvid
return dao;
}
/**
* Subtype hook to provide your own custom list of SortSpecifier's, if you have new fields you should probably override this method.
* Make absolutely sure that it returns a list of all your declared SortSpecifiers.
* Called once during base class construction.
* Default implementation returns the DomainClass registered with the object at creation time, override to provide your own encapsulation mechanics.
*/
@SuppressWarnings("unchecked")
protected Class<T> getDomainClass(){
return (Class<T>) (domainClass!=null?domainClass:DomainObject.class);
}
/**
* Subtype hook to provide your own custom list of additional SortSpecifier's, if you have new fields not accessible via annotation scanning you should probably override this method.
* Called once during base class construction. Duplicate sort-keys are ignored.
* @return
*/
@SuppressWarnings("unchecked")
@ -127,6 +124,12 @@ public class SortableDataProvider<T extends DomainObject> implements IDataProvid
throw new IllegalStateException("Sorry, you are not allowed to use a non registered SortSpecifier: '"+sortSpecifier+"' as this would potentially violate runtime-safety");
this.inUseSpecifier = sortSpecifier;
}
/**
* Sets currently in-use sorting order (ascending or descending)
*/
public final void setAscendingOrder(boolean ascending){
this.ascending = ascending;
}
/**
* Returns the currently in-use SortSpecifier, or null if none is in use.
* @return
@ -134,14 +137,43 @@ public class SortableDataProvider<T extends DomainObject> implements IDataProvid
public final SortSpecifier getSortSpecifier(){
return inUseSpecifier;
}
/**
* Shorthand method for getting a valid sortspecifier, useful since getSortSpecifier is allowed to return null values.
* @return
*/
public final SortSpecifier getSafeSortSpecifier(){
return (inUseSpecifier==null?ID:inUseSpecifier);
}
/**
* Returns sort order status.
*/
public final boolean isAscendingOrder(){
return ascending;
}
/**
* Returns an aggregated (and immutable) list of all SortSpecifiers available for the implementation.
* Requires subtypes to be well behaved when specifying additional sorting fields.
* @return
*/
public final List<SortSpecifier> getAvailableSortSpecifiers(){
logger.debug("Available sort specifiers: "+availableSpecifiers);
return Collections.unmodifiableList(availableSpecifiers);
}
/**
* Returns a defensive copy-list of all SortSpecifiers available for the implementation, any SortSpecifier with a getFieldName()
* not present in the filterSet will be excluded from the returned list.
* Requires subtypes to be well behaved when specifying additional sorting fields. Behavior when passing a null Set is undefined.
* @return
*/
public final List<SortSpecifier> getAvailableSortSpecifiers(final Set<String> filterSet){
List<SortSpecifier> returnList = new ArrayList<SortSpecifier>();
for(final SortSpecifier spec : availableSpecifiers){
logger.debug("Testing: " + spec);
if(filterSet.contains(spec.getFieldName()))
returnList.add(spec);
}
return returnList;
}
/**
* Does nothing.
*/
@ -153,13 +185,13 @@ public class SortableDataProvider<T extends DomainObject> implements IDataProvid
*/
@Override
public Iterator<T> iterator(int first, int count) {
if(inUseSpecifier != null)
return getDao().findAll(first, count, inUseSpecifier.getSortString()).iterator();
if(getSortSpecifier() != null)
return getDao().findAll(first, count, getSortSpecifier().getSortString() + (isAscendingOrder()?" ASC":" DESC")).iterator();
else
return getDao().findAll(first, count).iterator();
}
/**
* Returns the size of the Dao-objects countAll.
* Returns the size of the Dao-objects countAll by default, you will want to override this whenever you override iterator.
*/
@Override
public int size() {
@ -172,14 +204,39 @@ public class SortableDataProvider<T extends DomainObject> implements IDataProvid
public IModel<T> model(T object) {
return new DomainObjectDetachableModel<T>(getDao(),object);
}
/**
* Utility method for querying annotated domain objects.
* @param c
* @return
*/
private List<SortSpecifier> getSortSpecifierListForTargetAnnotations(final Class<? extends DomainObject> c){
logger.debug("Scanning for annotations in class type: "+c.getName());
ArrayList<SortSpecifier> list = new ArrayList<SortSpecifier>();
if(c != null){
for(Field f : c.getDeclaredFields()){
logger.debug("Examining: "+f.getName());
f.getAnnotation(SortableField.class);
SortableField a = f.getAnnotation(SortableField.class);
if(a != null){
logger.debug("Annotation found for field: " + f.getName());
SortSpecifier spec = new SortSpecifier(f.getName());
logger.debug("Adding: " +spec + " to the list of available sorting specifiers");
list.add(spec);
}else{
logger.debug("Ignoring: " + f.getName());
}
}
}
logger.debug("Full returned list:" +list);
return list;
}
private void populateAvailableSpecifiers(){
availableSpecifiers = new ArrayList<SortSpecifier>();
availableSpecifiers.add(ID_ASC);
availableSpecifiers.add(ID_DESC);
availableSpecifiers.add(CREATED_ASC);
availableSpecifiers.add(CREATED_DESC);
availableSpecifiers.add(MODIFIED_ASC);
availableSpecifiers.add(MODIFIED_DESC);
availableSpecifiers.addAll(getAvailableExtensionFields());
final HashSet<SortSpecifier> specSet = new HashSet<SortSpecifier>();
specSet.add(ID);
specSet.addAll(getSortSpecifierListForTargetAnnotations(DomainObject.class));
specSet.addAll(getSortSpecifierListForTargetAnnotations(getDomainClass()));
specSet.addAll(getAvailableExtensionFields());
availableSpecifiers.addAll(specSet);
}
}

@ -0,0 +1,16 @@
package se.su.dsv.scipro.dataproviders;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Marker annotation used to specify sortable fields for Dao-objects.
* This annotation is used by the SortableDataProvider API to automatically create SortSpecifiers suitable for use with the
* parameterized DomainObject type.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SortableField {
}

@ -7,6 +7,7 @@ import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.log4j.Logger;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
@ -26,6 +27,7 @@ import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.dataobjects.Username;
import se.su.dsv.scipro.data.enums.ProjectStatus;
import se.su.dsv.scipro.data.enums.ProjectTeamMemberRoles;
import se.su.dsv.scipro.data.facade.ProjectFacade;
import se.su.dsv.scipro.jsonobjects.JsonThesis;
import se.su.dsv.scipro.jsonobjects.JsonThesisParticipant;
import se.su.dsv.scipro.jsonobjects.JsonUser;
@ -52,6 +54,8 @@ abstract class JsonResponseHandler implements IResponseHandler {
protected IUserLookupFromIdentifier userLookupFromIdentifier;
@Autowired
protected ApplicationSettings applicationSettings;
@Autowired
private ProjectFacade facade;
private Logger logger = Logger.getLogger(JsonResponseHandler.class);
@ -145,7 +149,11 @@ abstract class JsonResponseHandler implements IResponseHandler {
Date daisyStartDate = new Date(jThesis.daisyStartDate);
project.setDaisyStartDate(daisyStartDate);
}
project = projectDao.save(project);
facade.generateChecklists(project);
//Synch participants
if(options.getLookupDepth().equals(RemoteLookupOptions.LOOKUP_DEPTH.PROJECT_AND_PARTICIPANTS)){
for(JsonThesisParticipant jtp : jThesis.participants){

@ -6,7 +6,7 @@ import se.su.dsv.scipro.repository.panels.ProjectFilePanel;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@Authorization(authorizedRoles={Roles.SYSADMIN}) //TODO Hidden for initial deployment
@Authorization(authorizedRoles={Roles.STUDENT}) //TODO Hidden for initial deployment
public class ProjectFilePage extends ProjectPage {
public ProjectFilePage(PageParameters pp) {

@ -12,10 +12,8 @@ import se.su.dsv.scipro.basepages.MenuPage;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dao.interfaces.UserSettingsDao;
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.dataobjects.UserSettings;
import se.su.dsv.scipro.exceptions.RenderingSafeException;
import se.su.dsv.scipro.project.panels.ProjectTabMenuPanel;
import se.su.dsv.scipro.repository.FilePanelContainer;
@ -25,10 +23,12 @@ public abstract class ProjectPage extends MenuPage implements FilePanelContainer
protected ProjectDao projectDao;
@SpringBean
private UserSettingsDao userSettingsDao;
private User user;
private Project activeProject;
public ProjectPage(PageParameters pp) {
Project activeProject = SciProSession.get().getActiveProject();
User u = SciProSession.get().getUser();
activeProject = SciProSession.get().getActiveProject();
user = SciProSession.get().getUser();
if(activeProject == null && (this.getClass() != NoActiveProjectPage.class && this.getClass() != ProjectPartnerPage.class)){
User user = SciProSession.get().getUser();
@ -39,13 +39,12 @@ public abstract class ProjectPage extends MenuPage implements FilePanelContainer
UserSettings userSettings = userSettingsDao.getUserSettings(user);
userSettings.setActiveProject(activeProject);
userSettings = userSettingsDao.save(userSettings);
}
else {
}else{
throw new RestartResponseException(NoActiveProjectPage.class);
}
} else if(activeProject != null){
/* Make sure we're still part of the project */
if(!projectDao.isPartOf(u, activeProject)) {
if(!projectDao.isPartOf(user, activeProject)) {
SciProSession.get().setActiveProject(null);
activeProject = null;
throw new RestartResponseException(NoActiveProjectPage.class);
@ -54,7 +53,20 @@ public abstract class ProjectPage extends MenuPage implements FilePanelContainer
add(new ProjectTabMenuPanel("tabMenu", this.getClass() ));
}
/**
* Exposes current user to subclasses.
* @return
*/
protected User getUser(){
return user;
}
/**
* Exposes current project to subclasses.
* @return
*/
protected Project getActiveProject(){
return activeProject;
}
@Override
public Class<? extends WebPage> getSurroundingPageClass() {
return this.getClass();

@ -6,6 +6,7 @@ import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.schedule.panels.ScheduleGeneratorPanel;
@Deprecated
public class ProjectScheduleGeneratorPage extends ProjectSchedulePage {
public ProjectScheduleGeneratorPage(final PageParameters pp){

@ -7,7 +7,7 @@ import se.su.dsv.scipro.schedule.panels.SchedulePlannerPanel;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@Authorization(authorizedRoles={Roles.SYSADMIN}) //TODO Hidden for initial deployment
@Authorization(authorizedRoles={Roles.STUDENT}) //TODO Hidden for initial deployment
public class ProjectSchedulePlannerPage extends ProjectSchedulePage {
public ProjectSchedulePlannerPage(PageParameters pp) {

@ -2,10 +2,7 @@ package se.su.dsv.scipro.project.pages;
import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.checklists.panels.ListCheckListPanel;
import se.su.dsv.scipro.checklists.panels.ViewCheckListPanel;
import se.su.dsv.scipro.data.dataobjects.CheckList;
import se.su.dsv.scipro.data.enums.CheckListRole;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@ -15,11 +12,12 @@ import se.su.dsv.scipro.security.auth.roles.Roles;
*
*/
@Authorization(authorizedRoles={Roles.SYSADMIN})
@Authorization(authorizedRoles={Roles.STUDENT})
public class ProjectViewCheckListPage extends ProjectPage {
public ProjectViewCheckListPage(PageParameters pp) {
super(pp);
System.out.println(pp.getAsLong("checklist"));
add(new ViewCheckListPanel("viewCheckListPanel", CheckListRole.AUTHOR, pp));
}

@ -6,6 +6,7 @@ import java.util.List;
import org.apache.wicket.Page;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.activityplan.pages.ProjectActivityPlanPage;
import se.su.dsv.scipro.components.AbstractMenuPanel;
import se.su.dsv.scipro.conference.pages.ProjectConferencePage;
import se.su.dsv.scipro.data.dataobjects.Project;
@ -43,7 +44,8 @@ public class ProjectTabMenuPanel extends AbstractMenuPanel {
if(activeProject != null){
itemList.add(new MenuItem("Projects details", ProjectStartPage.class));
itemList.add(new MenuItem("Activity plan", ProjectSchedulePlannerPage.class));
itemList.add(new MenuItem("Activity plan", ProjectSchedulePlannerPage.class));
itemList.add(new MenuItem("New activity plan", ProjectActivityPlanPage.class));
itemList.add(new MenuItem("Files", ProjectFilePage.class, ProjectFilePanel.getPrefabricatedPageParameters(activeProject)));
itemList.add(new MenuItem("Opposition & Active participation", ProjectOppositionPage.class));
itemList.add(new MenuItem("Peer portal", ProjectPeerPortalPage.class));

@ -115,7 +115,7 @@ public interface FileRepository {
* @param upload
* @param absolutePath
*/
void storeFile(FileUpload upload, String absolutePath);
String storeFile(FileUpload upload, String absolutePath);
/**
* Get resource stream to read a file from a FileDescription, returns null if file does not exist
* @param fileDesc

@ -312,6 +312,7 @@ public class FileRepositoryImpl implements FileRepository {
desc.setTargetLastModified(file.getNode("jcr:content").getProperty("jcr:lastModified").getDate().getTime());
desc.setMimeType(file.getNode("jcr:content").getProperty("jcr:mimeType").getString());
desc.setSize(file.getNode("jcr:content").getProperty("jcr:data").getLength());
desc.setIdentifier(identifier);
return desc;
} catch (Exception e) {
@ -330,7 +331,7 @@ public class FileRepositoryImpl implements FileRepository {
desc.setTargetLastModified(file.getNode("jcr:content").getProperty("jcr:lastModified").getDate().getTime());
desc.setMimeType(file.getNode("jcr:content").getProperty("jcr:mimeType").getString());
desc.setSize(file.getNode("jcr:content").getProperty("jcr:data").getLength());
desc.setIdentifier(file.getIdentifier());
return desc;
}
} catch (Exception e) {
@ -339,7 +340,7 @@ public class FileRepositoryImpl implements FileRepository {
return null;
}
public void storeFile(FileUpload upload, String absolutePath){
public String storeFile(FileUpload upload, String absolutePath){
try {
if (upload != null) {
if(!absolutePath.endsWith("/"))
@ -355,11 +356,12 @@ public class FileRepositoryImpl implements FileRepository {
if(mimeType != null)
mimeString = mimeType.toString();
String unescapedFileName = upload.getClientFileName();
this.storeFile(absolutePath + unescapedFileName, mimeString, upload.getInputStream());
return this.storeFile(absolutePath + unescapedFileName, mimeString, upload.getInputStream());
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}//storeFile
public IResourceStream getFileStream(final FileDescription fileDescription){

@ -0,0 +1,18 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<wicket:remove>
<link rel="stylesheet" type="text/css" href="../../../../../../../webapp/css/scipro.css"/>
<link rel="stylesheet" type="text/css" href="../../../../../../../webapp/css/blueprint/screen.css"/>
</wicket:remove>
<body>
<wicket:panel>
<wicket:extend>
<a href="#" wicket:id="fileDelete">
<img src="images/icons/delete_16x16.png" alt="Delete"/>
</a>
</wicket:extend>
</wicket:panel>
</body>
</html>

@ -0,0 +1,58 @@
package se.su.dsv.scipro.repository.panels;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.data.dao.interfaces.FileDescriptionDao;
import se.su.dsv.scipro.data.dataobjects.FileDescription;
import se.su.dsv.scipro.repository.FileRepository;
/**
* Extension of FileViewPanel allowing for callback deletion of the file item.
*/
public final class FileViewDeletePanel extends FileViewPanel{
@SpringBean
private FileRepository fileRepository;
@SpringBean
private FileDescriptionDao fileDescriptionDao;
/**
* Simple callback/strategy interface.
*/
public interface FileDeleteStrategy{
public void handleDelete(final FileDescription fileDesc);
public boolean renderDeleteLink();
}
private final transient FileDeleteStrategy callback;
private static final long serialVersionUID = 1L;
private final Link<Void> fileDeleteLink;
/**
* Default and only constructor, if the supplied file-delete callback is null: a default implementation will be used.
* @param id
* @param fileDesc
*/
public FileViewDeletePanel(final String id, final FileDescription fileDesc, final FileDeleteStrategy callback){
super(id,fileDesc);
this.callback = (callback==null?new DefaultFileDeleteStrategy():callback);
fileDeleteLink = new Link<Void>("fileDelete"){
private static final long serialVersionUID = 1L;
@Override
public void onClick() {
FileViewDeletePanel.this.callback.handleDelete(fileDesc);
}
};
fileDeleteLink.setVisible(callback.renderDeleteLink());
add(fileDeleteLink);
}
/**
* Default implementation, removes the file.
*/
private final class DefaultFileDeleteStrategy implements FileDeleteStrategy{
public void handleDelete(final FileDescription fileDesc){
if(fileRepository.existsFileByPath(fileDesc.getPath()))
fileRepository.delete(fileDesc.getPath());
}
public boolean renderDeleteLink(){
return true;
}
}
}

@ -8,20 +8,12 @@
</wicket:remove>
<body>
<wicket:panel>
<span wicket:id="fileName">somefile.txt</span>
(<span wicket:id="fileCreatedTime">2011.01.01 13:37:01</span>)
<a href="#" wicket:id="fileOpen">
<!-- <img wicket:id="openIcon" alt="Open/Preview"/> -->
<img class="round-box-icon"
src="images/icons/24/document_view.png" alt="Open" title="Open" />
</a>
<a href="#" wicket:id="fileOpen"><span wicket:id="fileName">somefile.txt</span></a>
(<span wicket:id="fileCreatedTime">2011.01.01 13:37:01</span>)
<a href="#" wicket:id="fileDownload">
<!-- <img wicket:id="downloadIcon" alt="Download"/> -->
<img class="round-box-icon"
src="images/icons/24/document_down.png" alt="Download" title="Download" />
<img class="round-box-icon" src="images/icons/24/document_down.png" alt="Download" title="Download" />
</a>
<wicket:child/>
</wicket:panel>
</body>
</html>

@ -14,7 +14,7 @@ import se.su.dsv.scipro.util.DateFormatter;
/**
* View panel component for displaying a single repository file based on it's FileDescription.
*/
public final class FileViewPanel extends Panel{
public class FileViewPanel extends Panel{
private static final long serialVersionUID = 1L;
/**
* Default and only constructor, assert-fails if the supplied fileDesc is null.
@ -35,14 +35,14 @@ public final class FileViewPanel extends Panel{
//Control logic for component data
if(fileDesc != null){
uploadNameLabel = new Label("fileName", new PropertyModel<FileDescription>(fileDesc,"name"));
uploadTimeLabel = new DateFormatter().createFormattedDateLabel("fileCreatedTime", fileDesc.getTargetLastModified());
uploadTimeLabel = new DateFormatter(DateFormatter.FORMAT.EXTENDED).createFormattedDateLabel("fileCreatedTime", fileDesc.getTargetLastModified());
fileDownloadLink = new FileDownloadLink("fileDownload", new Model<FileDescription>(fileDesc),true);
fileOpenLink = new FileOpenLink("fileOpen", new Model<FileDescription>(fileDesc),true);
}
//Add components
add(uploadNameLabel);
add(uploadTimeLabel);
add(fileDownloadLink);
fileOpenLink.add(uploadNameLabel);
add(fileOpenLink);
}
}

@ -6,6 +6,7 @@ import org.apache.wicket.ResourceReference;
import org.apache.wicket.markup.html.image.Image;
import org.joda.time.DateTime;
@Deprecated
public class CalendarIconImage extends Image {
private static final long serialVersionUID = 1L;

@ -18,6 +18,7 @@ import se.su.dsv.scipro.data.dataobjects.GroupEvent;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.schedule.baseevent.EventForm;
@Deprecated
public abstract class GroupEventForm extends EventForm<GroupEventFormModel>{
private static final long serialVersionUID = 1L;

@ -7,10 +7,10 @@ import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.data.dataobjects.GroupEvent;
import se.su.dsv.scipro.data.dataobjects.HandInActivity;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectEvent;
import se.su.dsv.scipro.data.dataobjects.ProjectSchedule;
import se.su.dsv.scipro.schedule.baseevent.EventFormModel;
@Deprecated
public class GroupEventFormModel extends EventFormModel<GroupEvent> {
private static final long serialVersionUID = 1L;

@ -34,6 +34,8 @@ import org.odlabs.wiquery.ui.datepicker.DatePicker.ShowOnEnum;
import org.odlabs.wiquery.ui.dialog.Dialog;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.activityplan.facade.ScheduleGenerator;
import se.su.dsv.scipro.activityplan.facade.ScheduleGeneratorResult;
import se.su.dsv.scipro.components.FormFeedbackPanel;
import se.su.dsv.scipro.data.dao.interfaces.HandInActivityDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
@ -51,10 +53,9 @@ import se.su.dsv.scipro.schedule.templates.panels.ScheduleTemplateDetailsPanel;
import se.su.dsv.scipro.schedule.templates.panels.ScheduleTemplateFilterPanel;
import se.su.dsv.scipro.schedule.templates.panels.models.ScheduleTemplatesModel;
import se.su.dsv.scipro.util.DateFormatter;
import se.su.dsv.scipro.util.ScheduleGenerator;
import se.su.dsv.scipro.util.ScheduleGeneratorResult;
import se.su.dsv.scipro.util.WiQueryCoreEffectsHelper;
@Deprecated
public abstract class ScheduleGeneratorPanel extends Panel {
private static final long serialVersionUID = 1L;

@ -11,7 +11,6 @@ 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.form.DropDownChoice;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
@ -24,6 +23,7 @@ import org.odlabs.wiquery.core.effects.EffectSpeed;
import org.odlabs.wiquery.ui.dialog.Dialog;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.activityplan.facade.TemplateGenerator;
import se.su.dsv.scipro.components.monthpicker.IMonthChangedListener;
import se.su.dsv.scipro.components.monthpicker.MonthPicker;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
@ -42,10 +42,8 @@ import se.su.dsv.scipro.schedule.baseevent.panels.EventSchedulePanel;
import se.su.dsv.scipro.schedule.groupevent.panels.CreateGroupEventPanel;
import se.su.dsv.scipro.schedule.models.EventListModel;
import se.su.dsv.scipro.schedule.projectevent.panels.CreateProjectEventPanel;
import se.su.dsv.scipro.schedule.templates.pages.ScheduleTemplateDetailsPage;
import se.su.dsv.scipro.supervisor.pages.SupervisorScheduleTemplatesEditorPage;
import se.su.dsv.scipro.util.SelectOption;
import se.su.dsv.scipro.util.TemplateGenerator;
import se.su.dsv.scipro.util.WiQueryCoreEffectsHelper;

@ -17,6 +17,7 @@ import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.schedule.baseevent.EventForm;
@Deprecated
public abstract class ProjectEventForm extends EventForm<ProjectEventFormModel> {
private static final long serialVersionUID = 1L;

@ -6,11 +6,11 @@ import java.util.TreeSet;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.data.dataobjects.HandInActivity;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectEvent;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.schedule.baseevent.EventFormModel;
@Deprecated
public class ProjectEventFormModel extends EventFormModel<ProjectEvent> {
private static final long serialVersionUID = 1L;

@ -19,8 +19,8 @@
<input type="checkbox" wicket:id="requireHandIn">
</div>
<div class="formRow">
<strong>Estimated number of days:</strong><br />
<input type="text" wicket:id="estimatedTimeConsumption" name="estimatedTimeConsumption" />
<strong>Days from previous event:</strong><br />
<input type="text" wicket:id="daysOffset"/>
</div>
<div class="formRow">
<button type="submit" wicket:id="addEventTemplateButton">

@ -58,7 +58,7 @@ public class EventTemplateFormPanel extends Panel {
add(new TextField<String>("title").setRequired(true));
add(new TextArea<String>("description"));
add(new TextField<Long>("estimatedTimeConsumption"));
add(new TextField<Long>("daysOffset"));
add(new CheckBox("requireHandIn"));
AjaxButton addEventTemplateButton = new AjaxButton("addEventTemplateButton", new Model<String>(isEdit ? "Done" : "Add")){

@ -10,10 +10,6 @@
<td>Number of events:</td>
<td><span wicket:id="numEventTemplates">Number of events</span></td>
</tr>
<tr>
<td>Estimated days for template:</td>
<td><span wicket:id="totalEstimatedTime">Total days</span></td>
</tr>
<tr>
<td>Creator:</td>
<td wicket:id="templateCreator"></td>
@ -30,10 +26,6 @@
<td>System template:</td>
<td><img wicket:id="isSysAdminTemplate" /></td>
</tr>
<tr>
<td>Active:</td>
<td><img wicket:id="isActive" /></td>
</tr>
<tr>
<td>Direct link:</td>
<td><a href="#" wicket:id="directLink">link</a></td>
@ -49,7 +41,7 @@
<span wicket:id="etDescription">Event description</span>
</div>
<div>
<span>Estimated days: </span><span wicket:id="etTimeConsumption">Time consumption</span>
<span>Offset (in days): </span><span wicket:id="etTimeConsumption">Offset</span>
</div>
<div>
<span>Hand in required: </span><img wicket:id="etRequireHandIn" />

@ -42,11 +42,6 @@ public class ScheduleTemplateDetailsPanel extends Panel {
List<ProjectEventTemplate> etList = template.getProjectEventTemplates();
add(new Label("numEventTemplates", etList.size() + ""));
long totalEstimatedTime = 0;
for(ProjectEventTemplate et : etList){
totalEstimatedTime += et.getEstimatedTimeConsumption();
}
add(new Label("totalEstimatedTime", totalEstimatedTime + ""));
add(template.getCreator().getDisplayComponent("templateCreator"));
final DateFormatter df = new DateFormatter();
@ -55,9 +50,6 @@ public class ScheduleTemplateDetailsPanel extends Panel {
ImageObject isSysAdminT = new ImageObject("isSysAdminTemplate", template.isSysAdminTemplate() ? ImageObject.THIRTYTWO + ImageObject.LIGHT_GREEN : ImageObject.THIRTYTWO + ImageObject.LIGHT_RED);
add(isSysAdminT);
ImageObject isActive = new ImageObject("isActive", template.isActive() ? ImageObject.THIRTYTWO + ImageObject.LIGHT_GREEN : ImageObject.THIRTYTWO + ImageObject.LIGHT_RED);
add(isActive);
final PageParameters pp = new PageParameters();
pp.put("tid", template.getId());
@ -73,8 +65,8 @@ public class ScheduleTemplateDetailsPanel extends Panel {
item.setOutputMarkupId(true);
item.add(new Label("etTitle", et.getTitle()));
item.add(new ExpandableMultiLineLabel("etDescription", 100, et.getDescription() != null ? et.getDescription() : "", false));
item.add(new Label("etTimeConsumption", et.getEstimatedTimeConsumption() + ""));
item.add(new ImageObject("etRequireHandIn", et.isRequireHandIn() ? ImageObject.THIRTYTWO + ImageObject.LIGHT_GREEN : ImageObject.THIRTYTWO + ImageObject.LIGHT_RED));
item.add(new Label("etTimeConsumption", et.getDaysOffset() + ""));
item.add(new ImageIcon("etRequireHandIn", et.isRequireHandIn() ? ImageIcon.ICON_YES : ImageIcon.ICON_NO));
add(item);
}

@ -4,15 +4,12 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.extensions.ajax.markup.html.AjaxIndicatorAppender;
import org.apache.wicket.extensions.ajax.markup.html.autocomplete.DefaultCssAutocompleteTextField;
import org.apache.wicket.markup.html.CSSPackageResource;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
@ -58,10 +55,7 @@ public abstract class ScheduleTemplateFilterPanel extends Panel {
public ScheduleTemplateFilterPanel(String id, final ScheduleTemplatesModel templateModel, final boolean showSysAdminOptions){
super(id);
if(!showSysAdminOptions){
templateModel.setOnlyActiveTemplates(true);
}
final WebMarkupContainer sysAdminOptionsContainer = new WebMarkupContainer("sysAdminOptionsContainer"){
private static final long serialVersionUID = 1L;
@ -91,21 +85,6 @@ public abstract class ScheduleTemplateFilterPanel extends Panel {
@Override
protected void onUpdate(AjaxRequestTarget target) {
ActiveOption selected = activeDD.getModelObject().value;
switch(selected) {
case ALL:
templateModel.setOnlyActiveTemplates(null);
break;
case ACTIVE:
templateModel.setOnlyActiveTemplates(true);
break;
case INACTIVE:
templateModel.setOnlyActiveTemplates(false);
break;
default:
templateModel.setOnlyActiveTemplates(null);
}
onFilterChanged(target);
}

@ -21,13 +21,6 @@
<strong>Description:</strong><br />
<textarea wicket:id="templateDescription" name="templateDescription"></textarea>
</div>
<div class="formRow">
<strong>Active:</strong>
<input type="checkbox" wicket:id="active" name="active" />
</div>
<div class="formRow">
<strong>Days total: </strong><strong wicket:id="totalEstimatedTime">Number of days</strong>
</div>
<div class="formRow">
<button type="submit" wicket:id="saveButton">
<img alt=""/> Save
@ -58,7 +51,7 @@
<img wicket:id="editEventTemplateIcon" class="right round-box-icon"></img>
</div>
<div>
<span>Estimated days:</span><span wicket:id="eventTemplateTimeConsumption">Event template time consumption</span>
<span>Offset(days):</span><span wicket:id="eventTemplateOffset">Days from previous event</span>
</div>
</div>
<div wicket:id="editEventTemplateContainer">

@ -9,7 +9,6 @@ import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
@ -75,8 +74,6 @@ public class ScheduleTemplateFormPanel extends Panel {
private WebMarkupContainer eventTemplateListContainer;
private WebMarkupContainer feedbackContainer;
private FormFeedbackPanel<ScheduleTemplate> feedbackPanel;
private Label totalEstimatedTimeLabel;
private Long totalEstimatedTime = (long) 0;
public ScheduleTemplateForm(String id, final ScheduleTemplate template, final Class<? extends MenuPage> responsePageClass) {
super(id, new CompoundPropertyModel<ScheduleTemplate>(template));
@ -89,19 +86,6 @@ public class ScheduleTemplateFormPanel extends Panel {
add(new TextField<String>("templateName").setRequired(true));
add(new TextArea<String>("templateDescription"));
add(new CheckBox("active"));
updateEstimatedTime();
totalEstimatedTimeLabel = new Label("totalEstimatedTime", new Model<Long>(){
private static final long serialVersionUID = 1L;
public Long getObject(){
updateEstimatedTime();
return totalEstimatedTime;
}
});
totalEstimatedTimeLabel.setOutputMarkupId(true);
add(totalEstimatedTimeLabel);
eventTemplateListContainer = new WebMarkupContainer("eventTemplateListContainer");
eventTemplateListContainer.setOutputMarkupId(true);
@ -121,7 +105,6 @@ public class ScheduleTemplateFormPanel extends Panel {
private static final long serialVersionUID = 1L;
@Override
protected void onEventTemplateAdded(AjaxRequestTarget target){
target.addComponent(totalEstimatedTimeLabel);
target.addComponent(eventTemplateListContainer);
target.appendJavascript(WiQueryCoreEffectsHelper.slideUpJs(addEventTemplateContainer, EffectSpeed.SLOW));
}
@ -149,7 +132,7 @@ public class ScheduleTemplateFormPanel extends Panel {
final Label evTitle = new Label("eventTemplateTitle", new PropertyModel<String>(et, "title"));
evTitle.setOutputMarkupId(true);
item.add(evTitle);
final Label evEstTimeCons = new Label("eventTemplateTimeConsumption", new PropertyModel<Long>(et, "estimatedTimeConsumption"));
final Label evEstTimeCons = new Label("eventTemplateOffset", new PropertyModel<Long>(et, "daysOffset"));
evEstTimeCons.setOutputMarkupId(true);
item.add(evEstTimeCons);
@ -169,7 +152,6 @@ public class ScheduleTemplateFormPanel extends Panel {
eventTemplateFormContainer.replace(new EventTemplateFormPanel("editEventTemplateFormPanel", et, template, true){
private static final long serialVersionUID = 1L;
protected void onEventTemplateAdded(AjaxRequestTarget target){
target.addComponent(totalEstimatedTimeLabel);
target.addComponent(evTitle);
target.addComponent(evEstTimeCons);
target.appendJavascript(WiQueryCoreEffectsHelper.slideUpJs(eventTemplateFormContainer, EffectSpeed.SLOW));
@ -198,7 +180,6 @@ public class ScheduleTemplateFormPanel extends Panel {
evList.get(i).setNumberInOrder(i - 1);
}
evList.remove(et.getNumberInOrder());
target.addComponent(totalEstimatedTimeLabel);
target.appendJavascript(WiQueryCoreEffectsHelper.slideUpJs(item, EffectSpeed.SLOW));
}
@ -294,13 +275,5 @@ public class ScheduleTemplateFormPanel extends Panel {
cancelButton.setDefaultFormProcessing(false);
add(cancelButton);
}
private void updateEstimatedTime(){
long acc = 0;
for(ProjectEventTemplate e : getModelObject().getProjectEventTemplates()){
acc += e.getEstimatedTimeConsumption();
}
totalEstimatedTime = acc;
}
}
}

@ -2,21 +2,20 @@
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<div class="span-22 last">
<div wicket:id="filterPanel" class="span-22 last append-bottom"></div>
<div class="span-22 last append-bottom">
<a href="#" wicket:id="createNew"> <img
wicket:id="createNewIcon" /> Create new template
</a>
<div wicket:id="templateListContainer">
<table class="rounded-corner">
<wicket:panel>
<div class="span-22 last">
<div wicket:id="filterPanel" class="span-22 last append-bottom"></div>
<div class="span-22 last append-bottom">
<a href="#" wicket:id="createNew">
<img wicket:id="createNewIcon" /> Create new template
</a>
<div wicket:id="templateListContainer">
<table>
<thead>
<tr>
<th class="rounded-left-top">Template name</th>
<th>System template</th>
<th>Active</th>
<th>Creator</th>
<th>Last updated</th>
<th>Details</th>
@ -31,9 +30,8 @@
</tfoot>
<tbody>
<tr wicket:id="templateList">
<td wicket:id="templateName">TempalteName</td>
<td wicket:id="templateName">TemplateName</td>
<td><img wicket:id="isSysAdminTemplate"></img></td>
<td><img wicket:id="isActive" /></td>
<td wicket:id="templateCreator">Creator</td>
<td wicket:id="templateUpdated">Last updated</td>
<td><img wicket:id="detailsIcon" /></td>
@ -54,13 +52,11 @@
</tbody>
</table>
</div>
<div wicket:id="templateDetailsContainer">
<div wicket:id="templateDetailsPanel"></div>
</div>
</div>
</div>
</wicket:panel>
</body>
</html>

@ -71,10 +71,7 @@ public class ScheduleTemplatePanel extends Panel {
final ScheduleTemplate s = item.getModelObject();
item.add(new Label("templateName", s.getTemplateName()));
ImageObject isActive = new ImageObject("isActive", s.isActive() ? ImageObject.THIRTYTWO + ImageObject.LIGHT_GREEN : ImageObject.THIRTYTWO + ImageObject.LIGHT_RED);
item.add(isActive);
ImageObject isSysAdminT = new ImageObject("isSysAdminTemplate", s.isSysAdminTemplate() ? ImageObject.TWENTYFOUR + ImageObject.CHECK : ImageObject.TWENTYFOUR + ImageObject.DELETE2);
ImageIcon isSysAdminT = new ImageIcon("isSysAdminTemplate", s.isSysAdminTemplate() ? ImageIcon.ICON_CHECK : ImageIcon.ICON_EMPTY);
item.add(isSysAdminT);
item.add(s.getCreator().getDisplayComponent("templateCreator"));

@ -1,6 +1,5 @@
package se.su.dsv.scipro.schedule.templates.panels.models;
import java.util.ArrayList;
import java.util.List;
import org.apache.wicket.injection.web.InjectorHolder;
@ -27,7 +26,6 @@ public class ScheduleTemplatesModel extends LoadableDetachableModel<List<Schedul
private UserDao userDao;
private ProjectClass projectClass = null;
private Boolean onlyActiveTemplates = null;
private User creator = null;
private Long creatorId = null;
private Boolean onlySysAdminTemplates = null;
@ -38,7 +36,7 @@ public class ScheduleTemplatesModel extends LoadableDetachableModel<List<Schedul
@Override
protected List<ScheduleTemplate> load() {
return scheduleTemplateDao.getScheduleTemplates(creator, onlySysAdminTemplates, onlyActiveTemplates, projectClass);
return scheduleTemplateDao.getScheduleTemplates(creator, onlySysAdminTemplates, projectClass);
}
public void reloadModel(){
@ -53,15 +51,6 @@ public class ScheduleTemplatesModel extends LoadableDetachableModel<List<Schedul
return onlySysAdminTemplates;
}
public Boolean isOnlyActiveTemplates() {
return onlyActiveTemplates;
}
public void setOnlyActiveTemplates(Boolean onlyActiveTemplates) {
this.onlyActiveTemplates = onlyActiveTemplates;
reloadModel();
}
public ProjectClass getProjectClass() {
return projectClass;
}
@ -82,7 +71,6 @@ public class ScheduleTemplatesModel extends LoadableDetachableModel<List<Schedul
public void clearFilter(boolean withReload){
projectClass = null;
onlyActiveTemplates = null;
creator = null;
onlySysAdminTemplates = null;
if(withReload){

@ -1,11 +0,0 @@
package se.su.dsv.scipro.supervisor.pages;
import org.apache.wicket.PageParameters;
public abstract class AbstractSupervisorScheduleTemplatesPage extends AbstractSupervisorPage {
public AbstractSupervisorScheduleTemplatesPage(final PageParameters pp){
super(pp);
}
}

@ -5,17 +5,13 @@ import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.checklists.panels.ListCheckListPanel;
import se.su.dsv.scipro.components.MenuHighlightSupervisorMyProjects;
import se.su.dsv.scipro.data.enums.CheckListRole;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
/**
* @author Fredrik Norberg - fnorbe@dsv.su.se
*
*/
@Authorization(authorizedRoles={Roles.SYSADMIN})
public class SupervisorChecklistPage extends AbstractSupervisorProjectDetailsPage implements MenuHighlightSupervisorMyProjects {
public SupervisorChecklistPage(PageParameters pp) {
super(pp);
add(new ListCheckListPanel("listCheckListPanel", CheckListRole.SUPERVISOR, pp));

@ -2,8 +2,10 @@ package se.su.dsv.scipro.supervisor.pages;
import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.schedule.panels.ScheduleGeneratorPanel;
@Deprecated
public class SupervisorScheduleGeneratorPage extends AbstractSupervisorProjectDetailsPage {
public SupervisorScheduleGeneratorPage(final PageParameters pp){

@ -8,10 +8,8 @@ import se.su.dsv.scipro.data.dao.interfaces.ScheduleTemplateDao;
import se.su.dsv.scipro.data.dataobjects.ScheduleTemplate;
import se.su.dsv.scipro.exceptions.AccessDeniedException;
import se.su.dsv.scipro.schedule.templates.panels.ScheduleTemplateFormPanel;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
public class SupervisorScheduleTemplatesEditorPage extends AbstractSupervisorScheduleTemplatesPage {
public class SupervisorScheduleTemplatesEditorPage extends AbstractSupervisorPage {
@SpringBean
private ScheduleTemplateDao scheduleTemplateDao;

@ -6,8 +6,8 @@ import se.su.dsv.scipro.schedule.templates.panels.ScheduleTemplatePanel;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@Authorization(authorizedRoles={Roles.SYSADMIN}) //TODO Hidden for initial deployment
public class SupervisorScheduleTemplatesPage extends AbstractSupervisorScheduleTemplatesPage {
@Authorization(authorizedRoles={Roles.EMPLOYEE})
public class SupervisorScheduleTemplatesPage extends AbstractSupervisorPage {
public SupervisorScheduleTemplatesPage(final PageParameters pp){
super(pp);

@ -15,7 +15,7 @@ import se.su.dsv.scipro.security.auth.roles.Roles;
*
*/
@Authorization(authorizedRoles={Roles.SYSADMIN})
@Authorization(authorizedRoles={Roles.EMPLOYEE})
public class SupervisorViewCheckListPage extends AbstractSupervisorProjectDetailsPage {
public SupervisorViewCheckListPage(PageParameters pp) {

@ -6,6 +6,7 @@ import java.util.List;
import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.activityplan.pages.SupervisorActivityPlanPage;
import se.su.dsv.scipro.components.AbstractMenuPanel;
import se.su.dsv.scipro.conference.pages.SupervisorConferencePage;
import se.su.dsv.scipro.data.dataobjects.Project;
@ -36,6 +37,7 @@ public class SupervisorSubTabMenuPanel extends AbstractMenuPanel{
List<MenuItem> items = new ArrayList<MenuItem>();
items.add(new MenuItem("Overview", SupervisorProjectDetailsPage.class));
items.add(new MenuItem("Activity plan", SupervisorSchedulePlannerPage.class));
items.add(new MenuItem("New activity plan", SupervisorActivityPlanPage.class));
items.add(new MenuItem("Notes", SupervisorLogPage.class));
if (projectParams.getAsLong(Project.PP_PROJECT_ID)!=null){

@ -2,7 +2,6 @@ package se.su.dsv.scipro.workerthreads;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
@ -10,11 +9,9 @@ import org.springframework.stereotype.Component;
import se.su.dsv.scipro.data.dao.interfaces.GeneralSystemSettingsDao;
import se.su.dsv.scipro.data.dao.interfaces.MailEventDao;
import se.su.dsv.scipro.data.dataobjects.GeneralSystemSettings;
import se.su.dsv.scipro.data.dataobjects.MailEvent;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.util.Mail;
import se.su.dsv.scipro.util.PropsUtils;
@Component
public class MailEventWorker extends AbstractWorker {

@ -5,211 +5,77 @@
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<!-- NOTE THAT THERE ARE TWO PERSISTENCE UNITS, one default and one test used for either running or unit-tests -->
<!-- NOTE THAT THERE ARE TWO PERSISTENCE UNITS, one default and one test
used for either running or unit-tests -->
<!-- A JPA Persistence Unit -->
<persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<persistence-unit name="defaultPersistenceUnit"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- JPA entities must be registered here -->
<class>se.su.dsv.scipro.data.dataobjects.Username</class>
<class>se.su.dsv.scipro.data.dataobjects.User</class>
<class>se.su.dsv.scipro.data.dataobjects.LazyDeletableDomainObject</class>
<class>se.su.dsv.scipro.data.dataobjects.Event</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.GroupEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.DomainObject</class>
<class>se.su.dsv.scipro.data.dataobjects.Student</class>
<class>se.su.dsv.scipro.data.dataobjects.Admin</class>
<class>se.su.dsv.scipro.data.dataobjects.SysAdmin</class>
<class>se.su.dsv.scipro.data.dataobjects.Employee</class>
<class>se.su.dsv.scipro.data.dataobjects.Role</class>
<class>se.su.dsv.scipro.data.dataobjects.Project</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectSchedule</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectFollower</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectTeamMember</class>
<class>se.su.dsv.scipro.data.dataobjects.BoardMessage</class>
<class>se.su.dsv.scipro.data.dataobjects.MessageBoard</class>
<class>se.su.dsv.scipro.data.dataobjects.PrivateMessage</class>
<class>se.su.dsv.scipro.data.dataobjects.Recipient</class>
<class>se.su.dsv.scipro.data.dataobjects.StringResource</class>
<class>se.su.dsv.scipro.data.dataobjects.Ratable</class>
<class>se.su.dsv.scipro.data.dataobjects.Rating</class>
<class>se.su.dsv.scipro.data.dataobjects.Resource</class>
<class>se.su.dsv.scipro.data.dataobjects.Tag</class>
<class>se.su.dsv.scipro.data.dataobjects.Comment</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectEventTemplate</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectClass</class>
<class>se.su.dsv.scipro.data.dataobjects.ScheduleTemplate</class>
<class>se.su.dsv.scipro.data.dataobjects.FileDescription</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.Answer</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.PeerQueue</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.PeerReview</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.PeerRequest</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.Question</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.ReviewRating</class>
<class>se.su.dsv.scipro.data.dataobjects.CommentThread</class>
<class>se.su.dsv.scipro.data.dataobjects.UserSettings</class>
<class>se.su.dsv.scipro.data.dataobjects.HandInActivity</class>
<class>se.su.dsv.scipro.data.dataobjects.HandIn</class>
<class>se.su.dsv.scipro.data.dataobjects.HandInFeedback</class>
<class>se.su.dsv.scipro.data.dataobjects.Category</class>
<class>se.su.dsv.scipro.data.dataobjects.FinalSeminar</class>
<class>se.su.dsv.scipro.data.dataobjects.FinalSeminarOpposition</class>
<class>se.su.dsv.scipro.data.dataobjects.FinalSeminarActiveParticipation</class>
<class>se.su.dsv.scipro.data.dataobjects.GeneralSystemSettings</class>
<class>se.su.dsv.scipro.data.dataobjects.WorkerData</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectClassSettings</class>
<class>se.su.dsv.scipro.data.dataobjects.MailEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectPartner</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckPlagiarismEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.WebNotification</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListTemplate</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckList</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListAnswer</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListQuestion</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListUpload</class>
<class>se.su.dsv.scipro.data.dataobjects.ChecklistCategory</class>
<properties>
<!-- 2nd level cache -->
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.SingletonEhCacheProvider" />
<property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.generate_statistics" value="false" />
<!-- 2nd level cache -->
<property name="hibernate.cache.provider_class"
value="org.hibernate.cache.SingletonEhCacheProvider" />
<property name="net.sf.ehcache.configurationResourceName"
value="/ehcache.xml" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.use_second_level_cache"
value="true" />
<property name="hibernate.generate_statistics" value="false" />
<!-- DEVELOPMENT VARIABLE, REMOVE FOR PRODUCTION USE -->
<!--property name="hibernate.hbm2ddl.auto" value="update" /-->
<property name="hibernate.hbm2ddl.auto" value="update" />
<!-- production settings database -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost/scipro"></property>
<property name="hibernate.connection.username" value="scipro"></property>
<property name="hibernate.connection.password" value="pighleef"></property>
<property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"></property>
<property name="hibernate.connection.provider_class"
value="org.hibernate.connection.C3P0ConnectionProvider"></property>
<property name="hibernate.c3p0.min_size" value="3"></property>
<property name="hibernate.c3p0.max_size" value="6"></property>
<property name="hibernate.c3p0.timeout" value="1800"></property>
<property name="hibernate.c3p0.acquire_increment" value="2"></property>
<property name="hibernate.c3p0.idle_test_period" value="360"></property>
<!--
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"></property>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:test"></property>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
-->
<!-- <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"
/> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.connection.driver_class"
value="org.hsqldb.jdbcDriver"></property> <property name="hibernate.connection.url"
value="jdbc:hsqldb:mem:test"></property> <property name="hibernate.show_sql"
value="false" /> <property name="hibernate.format_sql" value="true" /> -->
</properties>
</persistence-unit>
<!-- A JPA Persistence Unit used for tests -->
<persistence-unit name="testPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- This list of persisted Entitys IS NOT updated by eclipes JPA facet,
if some tests are failing, then copy paste exact list from the above persistence unit -->
<!-- JPA entities must be registered here -->
<class>se.su.dsv.scipro.data.dataobjects.Username</class>
<class>se.su.dsv.scipro.data.dataobjects.User</class>
<class>se.su.dsv.scipro.data.dataobjects.LazyDeletableDomainObject</class>
<class>se.su.dsv.scipro.data.dataobjects.Event</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.GroupEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.DomainObject</class>
<class>se.su.dsv.scipro.data.dataobjects.Student</class>
<class>se.su.dsv.scipro.data.dataobjects.Admin</class>
<class>se.su.dsv.scipro.data.dataobjects.SysAdmin</class>
<class>se.su.dsv.scipro.data.dataobjects.Employee</class>
<class>se.su.dsv.scipro.data.dataobjects.Role</class>
<class>se.su.dsv.scipro.data.dataobjects.Project</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectSchedule</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectFollower</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectTeamMember</class>
<class>se.su.dsv.scipro.data.dataobjects.BoardMessage</class>
<class>se.su.dsv.scipro.data.dataobjects.MessageBoard</class>
<class>se.su.dsv.scipro.data.dataobjects.PrivateMessage</class>
<class>se.su.dsv.scipro.data.dataobjects.Recipient</class>
<class>se.su.dsv.scipro.data.dataobjects.StringResource</class>
<class>se.su.dsv.scipro.data.dataobjects.Ratable</class>
<class>se.su.dsv.scipro.data.dataobjects.Rating</class>
<class>se.su.dsv.scipro.data.dataobjects.Resource</class>
<class>se.su.dsv.scipro.data.dataobjects.Tag</class>
<class>se.su.dsv.scipro.data.dataobjects.Comment</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectEventTemplate</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectClass</class>
<class>se.su.dsv.scipro.data.dataobjects.ScheduleTemplate</class>
<class>se.su.dsv.scipro.data.dataobjects.FileDescription</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.Answer</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.PeerQueue</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.PeerReview</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.PeerRequest</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.Question</class>
<class>se.su.dsv.scipro.peer.data.dataobjects.ReviewRating</class>
<class>se.su.dsv.scipro.data.dataobjects.CommentThread</class>
<class>se.su.dsv.scipro.data.dataobjects.UserSettings</class>
<class>se.su.dsv.scipro.data.dataobjects.HandInActivity</class>
<class>se.su.dsv.scipro.data.dataobjects.HandIn</class>
<class>se.su.dsv.scipro.data.dataobjects.HandInFeedback</class>
<class>se.su.dsv.scipro.data.dataobjects.Category</class>
<class>se.su.dsv.scipro.data.dataobjects.FinalSeminar</class>
<class>se.su.dsv.scipro.data.dataobjects.FinalSeminarOpposition</class>
<class>se.su.dsv.scipro.data.dataobjects.FinalSeminarActiveParticipation</class>
<class>se.su.dsv.scipro.data.dataobjects.GeneralSystemSettings</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectClassSettings</class>
<class>se.su.dsv.scipro.data.dataobjects.WorkerData</class>
<class>se.su.dsv.scipro.data.dataobjects.MailEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.ProjectPartner</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckPlagiarismEvent</class>
<class>se.su.dsv.scipro.data.dataobjects.WebNotification</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListTemplate</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckList</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListAnswer</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListQuestion</class>
<class>se.su.dsv.scipro.data.dataobjects.CheckListUpload</class>
<class>se.su.dsv.scipro.data.dataobjects.ChecklistCategory</class>
<persistence-unit name="testPersistenceUnit"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<!-- 2nd level cache -->
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.SingletonEhCacheProvider" />
<property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" />
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.generate_statistics" value="false" />
<!-- 2nd level cache -->
<property name="hibernate.cache.provider_class"
value="org.hibernate.cache.SingletonEhCacheProvider" />
<property name="net.sf.ehcache.configurationResourceName"
value="/ehcache.xml" />
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.cache.use_second_level_cache"
value="false" />
<property name="hibernate.generate_statistics" value="false" />
<!-- DEVELOPMENT VARIABLE, REMOVE FOR PRODUCTION USE -->
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"></property>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:test"></property>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<!-- Local mysql test database -->
<!--
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost/scipro"></property>
<property name="hibernate.connection.username" value=""></property>
<property name="hibernate.connection.password" value=""></property>
<property name="hibernate.c3p0.idle_test_period" value="3600"></property>
-->
<!-- <property name="hibernate.hbm2ddl.auto" value="create" /> <property
name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" /> <property
name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost/scipro"></property>
<property name="hibernate.connection.username" value=""></property> <property
name="hibernate.connection.password" value=""></property> <property name="hibernate.c3p0.idle_test_period"
value="3600"></property> -->
</properties>
</persistence-unit>
</persistence>

@ -1273,3 +1273,24 @@ div.wicket-aa ul li.selected {
body {
font: 0.8em/21px arial,sans-serif;
}
thead.blue-header {
color: white;
background-color: #0A2C5F;
border: 1px solid #777A91;
padding: 0.3em 0.3em;
margin-bottom: 0.3em;
}
tr.blue-row {
background-color: #0A2C5F;
border: 1px solid #777A91;
padding: 0.3em 0.3em;
margin-bottom: 0.3em;
height: 2em;
}
tr.schedule-row {
height: 3em;
}
}

@ -19,17 +19,47 @@
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="eventDao" class="se.su.dsv.scipro.data.dao.jpa.EventDaoJPAImp">
<bean id="projectScheduleDao" class="se.su.dsv.scipro.data.dao.jpa.ProjectScheduleDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="projectScheduleDao" class="se.su.dsv.scipro.data.dao.jpa.ProjectScheduleDaoJPAImp">
<bean id="userDao" class="se.su.dsv.scipro.data.dao.jpa.UserDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="projectScheduleEventDao" class="se.su.dsv.scipro.data.dao.jpa.ProjectScheduleEventDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="scheduleTemplateDao" class="se.su.dsv.scipro.data.dao.jpa.ScheduleTemplateDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="projectDao" class="se.su.dsv.scipro.data.dao.jpa.ProjectDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
<bean id="roleDao" class="se.su.dsv.scipro.data.dao.jpa.RoleDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="projectClassDao" class="se.su.dsv.scipro.data.dao.jpa.ProjectClassDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="CheckListDao" class="se.su.dsv.scipro.data.dao.jpa.CheckListDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="FileDescriptionDao" class="se.su.dsv.scipro.data.dao.jpa.FileDescriptionDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="FileRepository" class="se.su.dsv.scipro.repository.FileRepositoryImpl">
</bean>
<bean id="projectScheduleFacade" class="se.su.dsv.scipro.activityplan.facade.ProjectScheduleFacade">
</bean>
</beans>

@ -0,0 +1,103 @@
/**
*
*/
package se.su.dsv.scipro.dao.jpa;
import java.util.Date;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import se.su.dsv.scipro.activityplan.facade.ProjectScheduleFacade;
import se.su.dsv.scipro.data.dao.interfaces.ProjectClassDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleEventDao;
import se.su.dsv.scipro.data.dao.interfaces.RoleDao;
import se.su.dsv.scipro.data.dao.interfaces.UserDao;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.data.dataobjects.ProjectSchedule;
import se.su.dsv.scipro.data.dataobjects.ProjectScheduleEvent;
import se.su.dsv.scipro.data.dataobjects.Role;
import se.su.dsv.scipro.data.dataobjects.Student;
import se.su.dsv.scipro.data.dataobjects.User;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TestActivityPlanDaoJPA {
@Autowired
private UserDao userDao;
@Autowired
private ProjectScheduleDao projectScheduleDao;
@Autowired
private ProjectScheduleEventDao projectScheduleEventDao;
@Autowired
private ProjectDao projectDao;
@Autowired
private ProjectClassDao projectClassDao;
@Autowired
private ProjectScheduleFacade projectScheduleFacade;
@Autowired
private RoleDao roleDao;
private User user;
private Project project;
private ProjectClass projectClass;
private Role role;
private ProjectSchedule projectSchedule;
@Before
public void startTransaction()
{
user = new User();
user = userDao.save(user);
role = new Student();
role.setUser(user);
role = roleDao.save(role);
projectClass = new ProjectClass(ProjectClass.BACHELOR,"Bachelor","Bachelor degree thesis project");
projectClass = projectClassDao.save(projectClass);
project = new Project();
project.setTitle("SomeProject");
project.setProjectClass(projectClass);
project.addProjectParticipant((Student)role);
project = projectDao.save(project);
projectSchedule = new ProjectSchedule();
projectSchedule.setProject(project);
projectSchedule = projectScheduleDao.save(projectSchedule);
project.setProjectSchedule(projectSchedule);
}
@Test
@Transactional
@Rollback
public void testBaseDaoAccess() {
Assert.assertEquals(userDao.countAll(),1);
Assert.assertEquals(projectDao.countAll(),1);
Assert.assertEquals(projectScheduleDao.countAll(),1);
Assert.assertEquals(roleDao.countAll(),1);
}
@Test
@Transactional
@Rollback
public void testFacade(){
ProjectScheduleEvent event = projectScheduleFacade.createNewProjectScheduleEvent(projectSchedule, user, "Some event name", "Some event description", false, new Date());
Assert.assertEquals(projectScheduleEventDao.countAll(),1);
event.setDescription("Some other description");
projectScheduleFacade.saveProjectScheduleEvent(event);
Assert.assertEquals(projectScheduleEventDao.countAll(), 1);
Assert.assertEquals(projectScheduleFacade.retrieveProjectSchedule(project),projectSchedule);
}
}

@ -1,26 +0,0 @@
package se.su.dsv.scipro.dao.jpa;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Dan Kjellman <dan-kjel@dsv.su.se>
*
*/
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration
@Ignore
public class TestProjectScheduleDaoJPA {
@Test @Transactional
@Rollback
public void testDBChange() {
//For deploy! added a date column to projectSchedule
Assert.assertEquals(true, false);
}
}

@ -52,7 +52,6 @@ public class TestScheduleTemplateDaoJPA {
private ScheduleTemplate sysAdminTemplate;
private ScheduleTemplate employeeTemplate;
private ScheduleTemplate inactiveTemplate;
private ScheduleTemplate masterTemplate;
private ProjectClass masterClass;
@ -83,28 +82,18 @@ public class TestScheduleTemplateDaoJPA {
sysAdminTemplate = new ScheduleTemplate();
sysAdminTemplate.setCreator(sysAdminUser);
sysAdminTemplate.setSysAdminTemplate(true);
sysAdminTemplate.setActive(true);
sysAdminTemplate.setTemplateName("sysAdminTemplate");
sysAdminTemplate = scheduleTemplateDao.save(sysAdminTemplate);
employeeTemplate = new ScheduleTemplate();
employeeTemplate.setCreator(supervisorUser);
employeeTemplate.setSysAdminTemplate(false);
employeeTemplate.setActive(true);
employeeTemplate.setTemplateName("employeeTemplate");
employeeTemplate = scheduleTemplateDao.save(employeeTemplate);
inactiveTemplate = new ScheduleTemplate();
inactiveTemplate.setCreator(supervisorUser);
inactiveTemplate.setSysAdminTemplate(false);
inactiveTemplate.setActive(false);
inactiveTemplate.setTemplateName("inactiveTemplate");
inactiveTemplate = scheduleTemplateDao.save(inactiveTemplate);
masterTemplate = new ScheduleTemplate();
masterTemplate.setCreator(supervisorUser);
masterTemplate.setSysAdminTemplate(false);
masterTemplate.setActive(true);
masterTemplate.setProjectClass(masterClass);
masterTemplate.setTemplateName("masterTemplate");
masterTemplate = scheduleTemplateDao.save(masterTemplate);
@ -140,7 +129,6 @@ public class TestScheduleTemplateDaoJPA {
List<ScheduleTemplate> scheduleTemplates = new ArrayList<ScheduleTemplate>();
scheduleTemplates.add(sysAdminTemplate);
scheduleTemplates.add(employeeTemplate);
scheduleTemplates.add(inactiveTemplate);
scheduleTemplates.add(masterTemplate);
Assert.assertEquals(scheduleTemplates, scheduleTemplateDao.findAll());
List<ProjectEventTemplate> eventTemplates = new ArrayList<ProjectEventTemplate>();
@ -156,7 +144,7 @@ public class TestScheduleTemplateDaoJPA {
@Test @Transactional
@Rollback
public void testCountAll() {
Assert.assertEquals(4, scheduleTemplateDao.countAll());
Assert.assertEquals(3, scheduleTemplateDao.countAll());
}
/**
@ -186,7 +174,6 @@ public class TestScheduleTemplateDaoJPA {
scheduleTemplateDao.delete(employeeTemplate);
scheduleTemplateDao.delete(sysAdminTemplate);
scheduleTemplateDao.delete(masterTemplate);
scheduleTemplateDao.delete(inactiveTemplate);
Assert.assertEquals(0, scheduleTemplateDao.countAll());
}
@ -197,7 +184,7 @@ public class TestScheduleTemplateDaoJPA {
@Rollback
public void testDeleteCascade() {
scheduleTemplateDao.delete(employeeTemplate);
Assert.assertEquals(3, scheduleTemplateDao.countAll());
Assert.assertEquals(2, scheduleTemplateDao.countAll());
Assert.assertEquals(1, projectEventTemplateDao.countAll());
}
@ -213,30 +200,12 @@ public class TestScheduleTemplateDaoJPA {
Assert.assertEquals(s2.getId(), employeeTemplate.getId());
}
@Test @Transactional
@Rollback
public void testgetActiveScheduleTemplates() {
List<ScheduleTemplate> scheduleTemplates = new ArrayList<ScheduleTemplate>();
scheduleTemplates.add(employeeTemplate);
scheduleTemplates.add(masterTemplate);
scheduleTemplates.add(sysAdminTemplate);
Assert.assertEquals(scheduleTemplates, scheduleTemplateDao.getScheduleTemplates(null, null, true, null));
}
@Test @Transactional
@Rollback
public void testgetInactiveScheduleTemplates() {
List<ScheduleTemplate> scheduleTemplates = new ArrayList<ScheduleTemplate>();
scheduleTemplates.add(inactiveTemplate);
Assert.assertEquals(scheduleTemplates, scheduleTemplateDao.getScheduleTemplates(null, null, false, null));
}
@Test @Transactional
@Rollback
public void testgetScheduleTemplatesByClass() {
List<ScheduleTemplate> scheduleTemplates = new ArrayList<ScheduleTemplate>();
scheduleTemplates.add(masterTemplate);
Assert.assertEquals(scheduleTemplates, scheduleTemplateDao.getScheduleTemplates(null, null, null, masterClass));
Assert.assertEquals(scheduleTemplates, scheduleTemplateDao.getScheduleTemplates(null, null, masterClass));
}
@Test @Transactional
@ -252,7 +221,7 @@ public class TestScheduleTemplateDaoJPA {
public void testgetSysAdminScheduleTemplates() {
List<ScheduleTemplate> scheduleTemplates = new ArrayList<ScheduleTemplate>();
scheduleTemplates.add(sysAdminTemplate);
Assert.assertEquals(scheduleTemplates, scheduleTemplateDao.getScheduleTemplates(null, true, null, null));
Assert.assertEquals(scheduleTemplates, scheduleTemplateDao.getScheduleTemplates(null, true, null));
}
}

@ -28,4 +28,7 @@
<bean id="userSettingsDao" class="se.su.dsv.scipro.data.dao.jpa.UserSettingsDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="projectScheduleEventDao" class="se.su.dsv.scipro.data.dao.jpa.ProjectScheduleEventDaoJPAImp">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>

@ -1,10 +1,6 @@
package se.su.dsv.scipro.dataproviders;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.wicket.protocol.http.HttpSessionStore;
import org.apache.wicket.session.ISessionStore;
@ -26,10 +22,10 @@ import se.su.dsv.scipro.ApplicationSettings;
import se.su.dsv.scipro.SciProApplication;
import se.su.dsv.scipro.data.dao.interfaces.ProjectClassDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectDao;
import se.su.dsv.scipro.data.dao.interfaces.ProjectScheduleEventDao;
import se.su.dsv.scipro.data.dao.interfaces.RoleDao;
import se.su.dsv.scipro.data.dao.interfaces.UserDao;
import se.su.dsv.scipro.data.dao.interfaces.UserSettingsDao;
import se.su.dsv.scipro.data.dataobjects.DomainObject;
import se.su.dsv.scipro.data.dataobjects.Project;
import se.su.dsv.scipro.data.dataobjects.ProjectClass;
import se.su.dsv.scipro.json.IUserLookupFromUsername;
@ -48,6 +44,8 @@ public class TestSortableDataProvider{
private RoleDao roleDao;
@Autowired
private UserSettingsDao userSettingsDao;
@Autowired
private ProjectScheduleEventDao projectScheduleEventDao;
private Project p1,p2,p3;
private ProjectClass pc1,pc2,pc3;
@ -63,6 +61,7 @@ public class TestSortableDataProvider{
ac.putBean("userDao",userDao);
ac.putBean("roleDao",roleDao);
ac.putBean("userSettingsDao",userSettingsDao);
ac.putBean("projectScheduleEventDao",projectScheduleEventDao);
//Mocked stuff of no importance
ac.putBean("userLookupFromUsername",Mockito.mock(IUserLookupFromUsername.class));
new WicketTester(new SciProApplication(){
@ -112,6 +111,9 @@ public class TestSortableDataProvider{
Assert.assertFalse(pc2.equals(pc3));
Assert.assertFalse(pc3.equals(pc1));
Assert.assertFalse(pc3.equals(pc2));
Assert.assertTrue(p1.equals(p1));
Assert.assertTrue(p2.equals(p2));
Assert.assertTrue(p3.equals(p3));
}
/**
* Tests base case of "I want a sortable data provider for any generic Dao<DomainObject>"
@ -120,18 +122,24 @@ public class TestSortableDataProvider{
@Transactional
@Rollback
public void testBase() {
SortableDataProvider<Project> sdp = new SortableDataProvider<Project>(projectDao);
SortableDataProvider<Project> sdp = new SortableDataProvider<Project>(projectDao,Project.class);
Assert.assertTrue(sdp.isAscendingOrder());
Assert.assertTrue(sdp.size() == 3);
sdp.setSortSpecifier(SortableDataProvider.ID);
Assert.assertTrue(sdp.isAscendingOrder());
Assert.assertTrue(sdp.size() == 3);
Assert.assertTrue(sdp.iterator(0, 1).next().equals(p1));
Assert.assertTrue(sdp.iterator(1, 1).next().equals(p2));
Assert.assertTrue(sdp.iterator(2, 1).next().equals(p3));
sdp.setSortSpecifier(SortableDataProvider.ID_DESC);
sdp.setSortSpecifier(SortableDataProvider.ID);
sdp.setAscendingOrder(false);
Assert.assertTrue(!sdp.isAscendingOrder());
Assert.assertTrue(sdp.size() == 3);
Assert.assertTrue(sdp.iterator(0, 1).next().equals(p3));
Assert.assertTrue(sdp.iterator(1, 1).next().equals(p2));
Assert.assertTrue(sdp.iterator(2, 1).next().equals(p1));
//Iterate all available
Assert.assertTrue(sdp.getAvailableSortSpecifiers().size() == 6);
Assert.assertEquals(sdp.getAvailableSortSpecifiers().size(),5);
for(final SortSpecifier spec : sdp.getAvailableSortSpecifiers()){
sdp.setSortSpecifier(spec);
Assert.assertTrue(sdp.size() == 3);
@ -144,63 +152,21 @@ public class TestSortableDataProvider{
}
Assert.assertEquals(countMatches,3);
}
Assert.assertTrue(new SortableDataProviderArgumentListValidator<Project>(sdp).validate());
}
@Test
@Transactional
@Rollback
public void testProjectExtensions(){
ProjectDataProvider pdp = new ProjectDataProvider();
Assert.assertTrue(pdp.size() == 3);
Assert.assertTrue(pdp.iterator(0, 1).next().equals(p1));
Assert.assertTrue(pdp.iterator(1, 1).next().equals(p2));
Assert.assertTrue(pdp.iterator(2, 1).next().equals(p3));
pdp.setSortSpecifier(ProjectDataProvider.TITLE_ASC);
Assert.assertTrue(pdp.size() == 3);
Assert.assertTrue(pdp.iterator(0, 1).next().equals(p2));
Assert.assertTrue(pdp.iterator(1, 1).next().equals(p1));
Assert.assertTrue(pdp.iterator(2, 1).next().equals(p3));
pdp.setSortSpecifier(ProjectDataProvider.TITLE_DESC);
Assert.assertTrue(pdp.size() == 3);
Assert.assertTrue(pdp.iterator(0, 1).next().equals(p3));
Assert.assertTrue(pdp.iterator(1, 1).next().equals(p1));
Assert.assertTrue(pdp.iterator(2, 1).next().equals(p2));
//Iterate all available, strongly recommended to do this for all new providers
Assert.assertTrue(pdp.getAvailableSortSpecifiers().size() == 10);
for(final SortSpecifier spec : pdp.getAvailableSortSpecifiers()){
pdp.setSortSpecifier(spec);
Assert.assertTrue(pdp.size() == 3);
Iterator<Project> response = pdp.iterator(0, 3);
int countMatches = 0;
while(response.hasNext()){
Project p = response.next();
if(p.equals(p1) || p.equals(p2) || p.equals(p3))
++countMatches;
}
Assert.assertEquals(countMatches,3);
Assert.assertTrue(new SortableDataProviderArgumentListValidator<Project>(pdp).validate());
}
//Ensure amount of sort specifiers available, strongly recommended to do this for all new typed providers
Assert.assertEquals(pdp.getAvailableSortSpecifiers().size(), 5);
}
/**
* Please use this private helper class to validate all custom subtypes of SortableDataProvider.
* It will validate the specification for you and confirm that the type is correctly implemented in respect
* to the number of "public static final SortSpecifier"'s declared matching those returned from getAvailableSortSpecifiers().
*/
private final class SortableDataProviderArgumentListValidator<T extends DomainObject>{
final SortableDataProvider<T> provider;
SortableDataProviderArgumentListValidator(SortableDataProvider<T> provider){
this.provider = provider;
}
boolean validate(){
final Field[] fields = provider.getClass().getFields();
List<Field> fieldList = new ArrayList<Field>();
for(Field field : fields){
final int mods = field.getModifiers();
if(field.getType().equals(SortSpecifier.class) && Modifier.isFinal(mods) && Modifier.isPublic(mods) && Modifier.isStatic(mods)){
fieldList.add(field);
}
}
return (provider.getAvailableSortSpecifiers().size() == fieldList.size());
}
@Test
@Transactional
@Rollback
public void testProjectScheduleEventExtensions(){
ProjectScheduleEventDataProvider pdp = new ProjectScheduleEventDataProvider(null);
//Ensure amount of sort specifiers available, strongly recommended to do this for all new typed providers
Assert.assertEquals(pdp.getAvailableSortSpecifiers().size(),10);
}
}