Fix of several serious bugs in final seminar file handling and

addition of possibility of deletion of all documents related to a
final seminar by an admin

Change-Id: If75bee176893c36e14c12deee3d17098a83fa260
This commit is contained in:
mpeters 2011-07-29 13:25:15 +02:00
parent ac8716d4b0
commit 0da9284647
6 changed files with 214 additions and 129 deletions

@ -6,11 +6,10 @@ import org.apache.wicket.markup.html.form.upload.FileUpload;
import se.su.dsv.scipro.data.dataobjects.FinalSeminar; import se.su.dsv.scipro.data.dataobjects.FinalSeminar;
import se.su.dsv.scipro.data.dataobjects.FinalSeminarOpposition; import se.su.dsv.scipro.data.dataobjects.FinalSeminarOpposition;
import se.su.dsv.scipro.data.dataobjects.User; import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.repository.util.FileStorageException;
public interface FinalSeminarUploadController extends IClusterable { public interface FinalSeminarUploadController extends IClusterable {
void deleteSeminarFilesRecursive(FinalSeminar seminar);
void deleteOpponentFiles(FinalSeminarOpposition opp); void deleteOpponentFiles(FinalSeminarOpposition opp);
/** /**
@ -21,6 +20,15 @@ public interface FinalSeminarUploadController extends IClusterable {
*/ */
FinalSeminar deleteSeminarReport(FinalSeminar seminar) throws Exception; FinalSeminar deleteSeminarReport(FinalSeminar seminar) throws Exception;
/**
* Delete the upload report for the seminar, adminOverrideMode = true means no intentional exceptions will be thrown
* @param seminar
* @param adminOverrideMode
* @return
* @throws Exception
*/
FinalSeminar deleteSeminarReport(FinalSeminar seminar, boolean adminOverrideMode) throws Exception;
void storeSeminarDocument(FileUpload upload, User uploader, FinalSeminar seminar) throws Exception; void storeSeminarDocument(FileUpload upload, User uploader, FinalSeminar seminar) throws Exception;
void storeOpposition(FileUpload upload, User uploader, FinalSeminarOpposition opposition) throws Exception; void storeOpposition(FileUpload upload, User uploader, FinalSeminarOpposition opposition) throws Exception;

@ -78,17 +78,9 @@ public class FinalSeminarUploadControllerImpl implements FinalSeminarUploadContr
} }
private void delete(String path) { private void delete(String path) {
fileRepository.delete(path); fileRepository.delete(path);
} }
public void deleteSeminarFilesRecursive(final FinalSeminar seminar) throws FileStorageException {
if (seminar.getDocument() != null) {
//delete(getRepositorySeminarPath(seminar)); Use of deprecated path/method
delete(seminar.getDocument().getPath());
}
}
public void deleteOpponentFiles(final FinalSeminarOpposition opp) throws FileStorageException { public void deleteOpponentFiles(final FinalSeminarOpposition opp) throws FileStorageException {
if (opp.getOpponentReport() != null) { if (opp.getOpponentReport() != null) {
//delete(getRepositoryOppositionPath(opp)); Use of deprecated path/method //delete(getRepositoryOppositionPath(opp)); Use of deprecated path/method
@ -103,17 +95,30 @@ public class FinalSeminarUploadControllerImpl implements FinalSeminarUploadContr
* @return * @return
* @throws Exception * @throws Exception
*/ */
public FinalSeminar deleteSeminarReport(FinalSeminar seminar) throws Exception { public FinalSeminar deleteSeminarReport(FinalSeminar seminar) throws Exception{
return deleteSeminarReport(seminar, false);
}
/**
* Delete the upload report for the seminar, adminOverrideMode = true means no intentional exceptions will be thrown
* @param seminar
* @param adminOverrideMode
* @return
* @throws Exception
*/
public FinalSeminar deleteSeminarReport(FinalSeminar seminar, boolean adminOverrideMode) throws Exception {
seminar = finalSeminarDao.reLoad(seminar); seminar = finalSeminarDao.reLoad(seminar);
if( !adminOverrideMode ){
if (!seminar.getOppositions().isEmpty() || !seminar.getActiveParticipations().isEmpty()) { if (!seminar.getOppositions().isEmpty() || !seminar.getActiveParticipations().isEmpty()) {
throw new Exception( throw new Exception(
"Cannot delete seminar report, seminar has opponents or active participants"); "Cannot delete seminar report, seminar has opponents or active participants");
} }
}
for (CheckPlagiarismEvent cpe : checkPlagiarismEventDao.getWithFileDescription(seminar for (CheckPlagiarismEvent cpe : checkPlagiarismEventDao.getWithFileDescription(seminar
.getDocument())) { .getDocument())) {
checkPlagiarismEventDao.delete(cpe); checkPlagiarismEventDao.delete(cpe);
} }
if(seminar.getDocument() != null)
if(seminar.getDocument().getPath() != null)
fileRepository.delete(seminar.getDocument().getPath()); fileRepository.delete(seminar.getDocument().getPath());
seminar.setDocument(null); seminar.setDocument(null);
return finalSeminarDao.save(seminar); return finalSeminarDao.save(seminar);

@ -2,36 +2,28 @@
<html <html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"> xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body> <body>
<wicket:panel> <wicket:panel>
<div wicket:id="titleContainer"> <div wicket:id="feedback"></div>
<strong>Project Title: </strong> <span wicket:id="projectTitle"></span> <div wicket:id="titleContainer"><strong>Project Title: </strong>
<div> <span wicket:id="projectTitle"></span>
<strong>Room: </strong> <span wicket:id="room"></span> <div><strong>Room: </strong> <span wicket:id="room"></span></div>
</div>
</div> </div>
<div class="append-bottom"> <div class="append-bottom">
<div> <div><strong>Head supervisor:</strong></div>
<strong>Head supervisor:</strong> <span wicket:id="headSupervisor"></span></div>
</div> <div><strong>Author(s): </strong>
<span wicket:id="headSupervisor"></span>
</div>
<div>
<strong>Author(s): </strong>
<ul class="no-list-style"> <ul class="no-list-style">
<li wicket:id="authorsList"><span wicket:id="author"></span></li> <li wicket:id="authorsList"><span wicket:id="author"></span></li>
</ul> </ul>
</div> </div>
<div> <div><strong>Co-supervisor(s): </strong>
<strong>Co-supervisor(s): </strong>
<ul class="no-list-style"> <ul class="no-list-style">
<li wicket:id="coSupervisorsList"><span <li wicket:id="coSupervisorsList"><span wicket:id="coSupervisor"></span></li>
wicket:id="coSupervisor"></span></li>
</ul> </ul>
</div> </div>
<div> <div><strong>Reviewer(s): </strong>
<strong>Reviewer(s): </strong>
<ul class="no-list-style"> <ul class="no-list-style">
<li wicket:id="reviewersList"><span wicket:id="reviewer"></span> <li wicket:id="reviewersList"><span wicket:id="reviewer"></span>
</li> </li>
@ -40,40 +32,43 @@
<div wicket:id="detailsContainer"> <div wicket:id="detailsContainer">
<div> <div><strong>Opponent(s): </strong>
<strong>Opponent(s): </strong>
<ul class="no-list-style"> <ul class="no-list-style">
<li wicket:id="opponentsList"><span wicket:id="opponent"></span> <li wicket:id="opponentsList"><span wicket:id="opponent"></span>
<div wicket:id="oppositionContainer"><strong>Report:</strong> <span wicket:id="oppositionReportTitle"></span> <a href="#"
wicket:id="open"><img
src="images/icons/document-preview_16x16.png" alt="Open/Preview" />
</a> <a href="#" wicket:id="download"><img
src="images/icons/download_16x16.png" alt="Download" /> </a> <a href="#"
wicket:id="deleteOppositionReport"><img
src="images/icons/delete_16x16.png" alt="delete" /> </a>
</div>
</li> </li>
</ul> </ul>
</div> </div>
<div> <div><strong>Active participant(s): </strong>
<strong>Active participant(s): </strong>
<ul class="no-list-style"> <ul class="no-list-style">
<li wicket:id="activeParticipantsList"><span <li wicket:id="activeParticipantsList"><span
wicket:id="activeParticipant"></span></li> wicket:id="activeParticipant"></span></li>
</ul> </ul>
</div> </div>
<div> <div><strong>Presentation Language: </strong>
<strong>Presentation Language: </strong>
<div wicket:id="seminarLanguage"></div> <div wicket:id="seminarLanguage"></div>
</div> </div>
<div> <div><strong>Thesis/Report Language: </strong>
<strong>Thesis/Report Language: </strong>
<div wicket:id="thesisLanguage"></div> <div wicket:id="thesisLanguage"></div>
</div> </div>
<strong>Thesis/Report: </strong> <strong>Thesis/Report: </strong>
<div> <div><span wicket:id="seminarReportTitle"></span> <span
<span wicket:id="seminarReportTitle"></span> <span wicket:id="uploadInfoContainer"> <a href="#" wicket:id="open"><img
wicket:id="uploadInfoContainer"> <a href="#" src="images/icons/document-preview_16x16.png" alt="Open/Preview" /> </a>
wicket:id="open"><img <a href="#" wicket:id="download"><img
src="images/icons/document-preview_16x16.png" alt="Open/Preview" /> src="images/icons/download_16x16.png" alt="Download" /> </a> <a href="#"
</a> <a href="#" wicket:id="download"><img wicket:id="deleteSeminarReport"><img
src="images/icons/download_16x16.png" alt="Download" /> </a> </span> src="images/icons/delete_16x16.png" alt="delete" /> </a> </span></div>
</div> </div>
</div> </wicket:panel>
</wicket:panel>
</body> </body>
</html> </html>

@ -3,16 +3,21 @@ package se.su.dsv.scipro.opponent.panels;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.EmptyPanel; import org.apache.wicket.markup.html.panel.EmptyPanel;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model; import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.data.controllers.FinalSeminarUploadController;
import se.su.dsv.scipro.data.dao.interfaces.FinalSeminarDao; import se.su.dsv.scipro.data.dao.interfaces.FinalSeminarDao;
import se.su.dsv.scipro.data.dao.interfaces.FinalSeminarOppositionDao;
import se.su.dsv.scipro.data.dataobjects.FinalSeminar; import se.su.dsv.scipro.data.dataobjects.FinalSeminar;
import se.su.dsv.scipro.data.dataobjects.FinalSeminarActiveParticipation; import se.su.dsv.scipro.data.dataobjects.FinalSeminarActiveParticipation;
import se.su.dsv.scipro.data.dataobjects.FinalSeminarOpposition; import se.su.dsv.scipro.data.dataobjects.FinalSeminarOpposition;
@ -23,6 +28,9 @@ import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.data.enums.ProjectTeamMemberRoles; import se.su.dsv.scipro.data.enums.ProjectTeamMemberRoles;
import se.su.dsv.scipro.repository.components.FileDownloadLink; import se.su.dsv.scipro.repository.components.FileDownloadLink;
import se.su.dsv.scipro.repository.components.FileOpenLink; import se.su.dsv.scipro.repository.components.FileOpenLink;
import se.su.dsv.scipro.security.auth.MetaDataActionStrategy;
import se.su.dsv.scipro.security.auth.roles.Roles;
import se.su.dsv.scipro.util.JavascriptEventConfirmation;
public class FinalSeminarDetailsPanel extends Panel { public class FinalSeminarDetailsPanel extends Panel {
@ -30,11 +38,15 @@ public class FinalSeminarDetailsPanel extends Panel {
@SpringBean @SpringBean
private FinalSeminarDao finalSeminarDao; private FinalSeminarDao finalSeminarDao;
@SpringBean
private FinalSeminarOppositionDao finalSeminarOppositionDao;
@SpringBean
private FinalSeminarUploadController finalSeminarUploadController;
public FinalSeminarDetailsPanel(final String id, final FinalSeminar seminar2, public FinalSeminarDetailsPanel(final String id, final FinalSeminar seminar2, final boolean details) {
final boolean details) {
super(id); super(id);
this.setOutputMarkupId(true);
add(new FeedbackPanel("feedback"));
final FinalSeminar seminar = finalSeminarDao.reLoad(seminar2); final FinalSeminar seminar = finalSeminarDao.reLoad(seminar2);
final Project project = seminar.getProject(); final Project project = seminar.getProject();
WebMarkupContainer titleContainer = new WebMarkupContainer("titleContainer") { WebMarkupContainer titleContainer = new WebMarkupContainer("titleContainer") {
@ -53,8 +65,7 @@ public class FinalSeminarDetailsPanel extends Panel {
}); });
titleContainer.add(new Label("room", seminar.getRoom())); titleContainer.add(new Label("room", seminar.getRoom()));
add(titleContainer); add(titleContainer);
add(new ListView<Student>("authorsList", new ArrayList<Student>( add(new ListView<Student>("authorsList", new ArrayList<Student>(project.getProjectParticipants())) {
project.getProjectParticipants())) {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
@ -111,41 +122,76 @@ public class FinalSeminarDetailsPanel extends Panel {
}; };
detailsContainer.add(new ListView<FinalSeminarOpposition>("opponentsList", seminar detailsContainer.add(new ListView<FinalSeminarOpposition>("opponentsList", seminar.getOppositions()) {
.getOppositions()) {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
protected void populateItem(ListItem<FinalSeminarOpposition> item) { protected void populateItem(final ListItem<FinalSeminarOpposition> item) {
item.add(item.getModelObject().getOpponent().getUser() item.add(item.getModelObject().getOpponent().getUser().getDisplayComponent("opponent", true));
.getDisplayComponent("opponent", true)); WebMarkupContainer oppCon = new WebMarkupContainer("oppositionContainer"){
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible(){
return item.getModelObject().getOpponentReport() != null;
}
};
MetaDataActionStrategy.authorize(oppCon, Roles.ADMIN);
item.add(oppCon);
String reportTitle = "";
if(item.getModelObject().getOpponentReport() != null)
reportTitle = item.getModelObject().getOpponentReport().getName();
oppCon.add(new Label("oppositionReportTitle", reportTitle));
oppCon.add(new FileDownloadLink("download", item.getModelObject().getOpponentReport()));
oppCon.add(new FileOpenLink("open", item.getModelObject().getOpponentReport()));
oppCon.add(new AjaxLink<Void>("deleteOppositionReport"){
private static final long serialVersionUID = 1L;
{ //Extra safeguard should someone later decide that the surrounding container should be visible to all
MetaDataActionStrategy.authorize(this, Roles.ADMIN);
this.add(new JavascriptEventConfirmation("onclick", "Do you really want to delete this user-uploaded report?"));
}
@Override
public void onClick(AjaxRequestTarget target) {
try{
finalSeminarUploadController.deleteOpponentFiles(item.getModelObject());
FinalSeminarOpposition opp = item.getModelObject();
opp.setOpponentReport(null);
opp = finalSeminarOppositionDao.save(opp);
item.setModelObject(opp);
info("Opposition report deleted");
} catch(Exception e){
e.printStackTrace();
error("Something went wrong, see log files for stacktrace");
}
target.addComponent(FinalSeminarDetailsPanel.this);
}
});
add(item); add(item);
} }
}); });
detailsContainer.add(new ListView<FinalSeminarActiveParticipation>( detailsContainer.add(new ListView<FinalSeminarActiveParticipation>("activeParticipantsList", seminar.getActiveParticipations()) {
"activeParticipantsList", seminar.getActiveParticipations()) {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
protected void populateItem(ListItem<FinalSeminarActiveParticipation> item) { protected void populateItem(ListItem<FinalSeminarActiveParticipation> item) {
item.add(item.getModelObject().getUser() item.add(item.getModelObject().getUser().getDisplayComponent("activeParticipant", true));
.getDisplayComponent("activeParticipant", true));
add(item); add(item);
} }
}); });
detailsContainer.add(new Label("seminarLanguage", seminar.getPresentationLanguage() detailsContainer.add(new Label("seminarLanguage", seminar.getPresentationLanguage().toString()));
.toString()));
detailsContainer.add(new Label("thesisLanguage", seminar.getReportLanguage().toString())); detailsContainer.add(new Label("thesisLanguage", seminar.getReportLanguage().toString()));
detailsContainer.add(new Label("seminarReportTitle", new Model<String>() { detailsContainer.add(new Label("seminarReportTitle", new Model<String>() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
public String getObject() { public String getObject() {
return seminar.getDocument() == null ? "No thesis/report uploaded" : seminar return seminar.getDocument() == null ? "No thesis/report uploaded" : seminar.getDocument().getName();
.getDocument().getName();
} }
})); }));
@ -161,6 +207,27 @@ public class FinalSeminarDetailsPanel extends Panel {
uploadInfoContainer.add(new FileDownloadLink("download", seminar.getDocument())); uploadInfoContainer.add(new FileDownloadLink("download", seminar.getDocument()));
uploadInfoContainer.add(new FileOpenLink("open", seminar.getDocument())); uploadInfoContainer.add(new FileOpenLink("open", seminar.getDocument()));
uploadInfoContainer.add(new AjaxLink<Void>("deleteSeminarReport") {
private static final long serialVersionUID = 1L;
{
MetaDataActionStrategy.authorize(this, Roles.ADMIN);
this.add(new JavascriptEventConfirmation("onclick", "Do you really want to delete this user-uploaded report?"));
}
@Override
public void onClick(AjaxRequestTarget target) {
try {
finalSeminarUploadController.deleteSeminarReport(seminar, true);
seminar.setDocument(null); //Only to repaint the ajax call without the document icons
info("Report deleted");
} catch (Exception e) {
e.printStackTrace();
error("Deletion failed");
}
target.addComponent(FinalSeminarDetailsPanel.this);
}
});
detailsContainer.add(uploadInfoContainer); detailsContainer.add(uploadInfoContainer);
add(detailsContainer); add(detailsContainer);

@ -5,6 +5,7 @@
<wicket:panel> <wicket:panel>
<div class="span-22 prepend-top last"> <div class="span-22 prepend-top last">
<div wicket:id="feedback"></div>
<table class="rounded-table seminar-table even-rows"> <table class="rounded-table seminar-table even-rows">
<tr> <tr>
<th>Date</th> <th>Date</th>

@ -76,6 +76,10 @@ public class OpponentListViewPanel extends Panel {
super(id); super(id);
this.adminView = adminView; this.adminView = adminView;
loadListView(seminarList); loadListView(seminarList);
feedbackPanel = new FeedbackPanel("feedback");
add(feedbackPanel);
this.setOutputMarkupId(true);
editSeminarDialogContainer = new WebMarkupContainer("dialogContainer"); editSeminarDialogContainer = new WebMarkupContainer("dialogContainer");
editSeminarDialog = new Dialog("dialog"); editSeminarDialog = new Dialog("dialog");
editSeminarDialog.setModal(true); editSeminarDialog.setModal(true);
@ -191,7 +195,8 @@ public class OpponentListViewPanel extends Panel {
@Override @Override
public void onClick(AjaxRequestTarget target) { public void onClick(AjaxRequestTarget target) {
FinalSeminar seminar2 = finalSeminarDao.reLoad(seminar); FinalSeminar seminar2 = finalSeminarDao.reLoad(seminar);
seminarUploadController.deleteSeminarFilesRecursive(seminar2); try{
seminarUploadController.deleteSeminarReport(seminar2, true);
for (FinalSeminarActiveParticipation al : seminar2 for (FinalSeminarActiveParticipation al : seminar2
.getActiveParticipations()) { .getActiveParticipations()) {
finalSeminarActiveParticipationDao.delete(al); finalSeminarActiveParticipationDao.delete(al);
@ -203,8 +208,12 @@ public class OpponentListViewPanel extends Panel {
finalSeminarOppositionDao.delete(fso); finalSeminarOppositionDao.delete(fso);
} }
finalSeminarDao.delete(seminar2); finalSeminarDao.delete(seminar2);
setResponsePage(AdminFinalSeminarPage.class); info("Final seminar deleted");
} catch (Exception e){
error("Something went wrong, see logs for stacktrace");
e.printStackTrace();
}
target.addComponent(OpponentListViewPanel.this);
} }
@Override @Override