merged with origin/dvelop

This commit is contained in:
Fredrik Norberg 2011-07-19 12:01:45 +02:00
commit 00fa623880
12 changed files with 433 additions and 6 deletions

@ -14,9 +14,17 @@
<td><input type="checkbox" wicket:id="peerRatingsEnabled" name="peerRatingsEnabled"></td>
</tr>
<tr>
<td><label for="peerDisplayNumberOfReviewsPerformed">Display users number of reviews performed on portal page</label></td>
<td><label for="peerDisplayNumberOfReviewsPerformed">Display users number of reviews performed on portal page:</label></td>
<td><input type="checkbox" wicket:id="peerDisplayNumberOfReviewsPerformed" name="peerDisplayNumberOfReviewsPerformed"></td>
</tr>
<tr>
<td><label for="peerDisplayLatestReviews">Display the latest submitted reviews on portal page:</label></td>
<td><input type="checkbox" wicket:id="peerDisplayLatestReviews" name="peerDisplayLatestReviews"></td>
</tr>
<tr>
<td><label for="numberOfLatestReviewsDisplayed">Number of reviews to show in the "Latest reviewers" panel: </label></td>
<td><input type="text" wicket:id="numberOfLatestReviewsDisplayed" name="numberOfLatestReviewsDisplayed" /></td>
</tr>
</table>
</form>
<h5 class="peer-title">Settings for levels</h5>

@ -59,17 +59,36 @@ public class AdminPeerSettingsPage extends AbstractAdminSettingsPage {
private class PeerRatingsSettingsForm extends Form<GeneralSystemSettings> {
private static final long serialVersionUID = 1L;
private TextField<Integer> numberOfLatestReviewsDisplayed;
public PeerRatingsSettingsForm(String id, IModel<GeneralSystemSettings> model) {
super(id, model);
CheckBox peerRatingsEnabled = new CheckBox("peerRatingsEnabled");
add(peerRatingsEnabled);
CheckBox peerDisplayNumberOfReviewsPerformed = new CheckBox("peerDisplayNumberOfReviewsPerformed");
add(peerDisplayNumberOfReviewsPerformed);
add(peerDisplayNumberOfReviewsPerformed);
CheckBox peerDisplayLatestReviews = new CheckBox("peerDisplayLatestReviews");
add(peerDisplayLatestReviews);
numberOfLatestReviewsDisplayed =
new TextField<Integer>("numberOfLatestReviewsDisplayed");
numberOfLatestReviewsDisplayed.setRequired(true);
add(numberOfLatestReviewsDisplayed);
// Checkbox for activating/inactiviting links to reviews in the Latest reviewers panel.
//
/*CheckBox publicReviewsActivated = new CheckBox("publicReviewsActivated");
add(publicReviewsActivated);*/
}
@Override
public void onSubmit(){
setModelObject(generalSystemSettingsDao.save(getModelObject()));
if (getModelObject().getNumberOfLatestReviewsDisplayed() == 0) {
warn("Number of reviews to show has been changed to 1. If you don't want to show any reviews, please hide the panel.");
getModelObject().setNumberOfLatestReviewsDisplayed(1);
}
setModelObject(generalSystemSettingsDao.save(getModelObject()));
}
}

@ -51,6 +51,15 @@ public class GeneralSystemSettings extends DomainObject{
@Basic(optional=false)
private boolean peerDisplayNumberOfReviewsPerformed = true;
@Basic(optional=false)
private boolean peerDisplayLatestReviews = true;
@Basic(optional=false)
private int numberOfLatestReviewsDisplayed = 3;
@Basic(optional=false)
private boolean publicReviewsActivated = true;
public GeneralSystemSettings(){
}
/**
@ -116,6 +125,24 @@ public class GeneralSystemSettings extends DomainObject{
public boolean isPeerDisplayNumberOfReviewsPerformed() {
return peerDisplayNumberOfReviewsPerformed;
}
public void setPeerDisplayLatestReviews(boolean peerDisplayLatestReviews) {
this.peerDisplayLatestReviews = peerDisplayLatestReviews;
}
public boolean isPeerDisplayLatestReviews() {
return peerDisplayLatestReviews;
}
public int getNumberOfLatestReviewsDisplayed() {
return numberOfLatestReviewsDisplayed;
}
public void setNumberOfLatestReviewsDisplayed(int numberOfLatestReviewsDisplayed) {
this.numberOfLatestReviewsDisplayed = numberOfLatestReviewsDisplayed;
}
public boolean isPublicReviewsActivated() {
return publicReviewsActivated;
}
public void setPublicReviewsActivated(boolean publicReviewsActivated) {
this.publicReviewsActivated = publicReviewsActivated;
}
}

@ -44,6 +44,10 @@ public interface PeerReviewDao extends LazyDeleteDao<PeerReview> {
public int countStudentsWithReviews(final long minimumNumberOfReviews, final Date since);
public int countStudentsWithReviews();
public int countSubmittedReviews();
public List<PeerReview> findReviewsSortedByDate(final int firstResult, final Integer limit);
/**
* Find given peer reviews for a given project and student

@ -385,4 +385,55 @@ public class PeerReviewDaoJPAImp extends LazyDeleteAbstractDaoJPAImp<PeerReview>
}
});
}
@Transactional
public List<PeerReview> findReviewsSortedByDate(final int firstResult, final Integer limit) {
return getJpaTemplate().execute(new JpaCallback<List<PeerReview>>() {
public List<PeerReview> doInJpa(EntityManager em)
throws PersistenceException {
String q = "select pr " +
"from PeerReview pr " +
"where pr.submitted = true " +
"and pr.deleted = false " +
"and pr.aborted = false " +
"order by pr.lastModified desc";
TypedQuery<PeerReview> query = em.createQuery(q, PeerReview.class);
query.setMaxResults(limit != null ? limit : 3);
query.setFirstResult(firstResult);
try {
return query.getResultList();
} catch (NoResultException e) {
return new LinkedList<PeerReview>();
}
}
});
}
@Override
public int countSubmittedReviews() {
return getJpaTemplate().execute(new JpaCallback<Integer>() {
public Integer doInJpa(EntityManager em)
throws PersistenceException {
String q = "select count(pr) " +
"from PeerReview pr " +
"where pr.submitted = true " +
"and pr.deleted = false " +
"and pr.aborted = false";
TypedQuery<Long> query = em.createQuery(q, Long.class);
try {
return query.getSingleResult().intValue();
} catch (NoResultException e) {
return 0;
}
}
}); }
}

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
<div>
<table>
<tbody wicket:id="listView">
<tr>
<td wicket:id="reviewer"></td>
</tr>
<tr>
<td><a href="#" wicket:id="reviewLink">Review date: <span wicket:id="reviewDate"></span></a></td>
</tr>
</tbody>
</table>
<i><span wicket:id="noReviewersFoundMessage"></span></i>
</div>
<div>
<a href="#" wicket:id="showMore">Show more...</a>
</div>
</wicket:panel>
</body>
</html>

@ -0,0 +1,135 @@
package se.su.dsv.scipro.peer.panels;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.peer.data.dao.interfaces.PeerReviewDao;
import se.su.dsv.scipro.peer.data.dataobjects.PeerReview;
import se.su.dsv.scipro.peer.pages.ProjectPeerReviewPage;
public class LatestReviewPanel extends Panel {
private static final long serialVersionUID = 1L;
@SpringBean
private PeerReviewDao peerReviewDao;
/**
* @param id
* @param model
* the number of users to show by default - also defines how many
* users to show when clicking showmore
*/
public LatestReviewPanel(String id, final Model<Integer> model, final boolean publicLinks) {
super(id, model);
setOutputMarkupId(true);
final int totalCount = peerReviewDao.countSubmittedReviews();
final LoadableDetachableModel<List<PeerReview>> listModel = new LoadableDetachableModel<List<PeerReview>>() {
private static final long serialVersionUID = 1L;
@Override
protected List<PeerReview> load() {
return peerReviewDao.findReviewsSortedByDate(0, model.getObject());
}
};
final ListView<PeerReview> listView = new ListView<PeerReview>("listView", listModel) {
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(ListItem<PeerReview> item) {
PeerReview pr = item.getModelObject();
item.add(pr.getReviewer().getUser().getDisplayComponent("reviewer"));
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Label dateLabel = new Label("reviewDate", df.format(pr.getLastModified()));
if(publicLinks) {
PageParameters pp = new PageParameters();
pp.put(PeerReview.PP_PEER_REVIEW_ID, pr.getId());
BookmarkablePageLink<Void> link = new BookmarkablePageLink<Void>("reviewLink", ProjectPeerReviewPage.class, pp);
link.add(dateLabel);
item.add(link);
} else {
LinkToSpanContainer ltsc = new LinkToSpanContainer("reviewLink");
ltsc.add(dateLabel);
item.add(ltsc);
}
add(item);
}
};
add(new Label("noReviewersFoundMessage", "No reviewers found") {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return listView.size() == 0;
}
});
add(listView);
add(new AjaxLink<Void>("showMore") {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
Integer i = model.getObject();
i += model.getObject();
model.setObject(i);
target.addComponent(LatestReviewPanel.this);
}
@Override
public boolean isVisible() {
return listView.size() < totalCount;
}
});
}
public LatestReviewPanel(String id) {
this(id, new Model<Integer>(3), false);
}
/*
* Change html markup from a href to span when links are disabled.
* Used when publicly viewable peer reviews is activated/inactivated.
*/
class LinkToSpanContainer extends WebMarkupContainer {
private static final long serialVersionUID = 1L;
public LinkToSpanContainer(String id) {
super(id);
}
@Override
protected final void onComponentTag(final ComponentTag tag) {
tag.setName("span");
tag.remove("href");
super.onComponentTag(tag);
}
}
}

@ -72,6 +72,12 @@
</div>
<!-- End left column -->
<div class="span-6 last">
<wicket:enclosure>
<div class="rounded-box">
<span class="box-title">Latest reviewers</span>
<div wicket:id="latestReviewPanel" class="append-bottom"></div>
</div>
</wicket:enclosure>
<wicket:enclosure>
<div class="rounded-box">
<span class="box-title">Most frequent reviewers</span>
@ -86,7 +92,6 @@
<div>
<i><span class="small right">Last 12 months</span></i>
</div>
</div>
</div>
</wicket:panel>

@ -216,7 +216,10 @@ public class PeerPortalPanel extends Panel {
GeneralSystemSettings gsettings = generalSystemSettingsDao.getGeneralSystemSettingsInstance();
final String mostFrequentPanel = "mostFrequentPanel";
final String latestReviewPanel ="latestReviewPanel";
final String bestRatedContainer = "bestRatedContainer";
int displayedReviews = gsettings.getNumberOfLatestReviewsDisplayed();
if(gsettings.isPeerDisplayNumberOfReviewsPerformed()){
add(new MostFrequentReviewersPanel(mostFrequentPanel));
@ -228,6 +231,18 @@ public class PeerPortalPanel extends Panel {
} else {
add(new InvisiblePanel(bestRatedContainer));
}
if(gsettings.isPeerDisplayLatestReviews()) {
// Checkbox on the AdminPeerSettingsPage is not visible since it's
// not decided what kind of info that should be public for students.
if (gsettings.isPublicReviewsActivated()) {
add(new LatestReviewPanel(latestReviewPanel, new Model<Integer>(displayedReviews), true));
} else {
add(new LatestReviewPanel(latestReviewPanel, new Model<Integer>(displayedReviews), false));
}
} else {
add(new InvisiblePanel(latestReviewPanel));
}
}
}

@ -0,0 +1,106 @@
package se.su.dsv.scipro.util.xml;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import edu.emory.mathcs.backport.java.util.Collections;
/**
* Utility class for providing configurable namespace contexts, satisfies specification defined in the NamespaceContext interface.
* The default namespace-prefixes (DEFAULT_NS_PREFIX, XML_NS_PREFIX and XMLNS_ATTRIBUTE) are automatically mapped to defaults and are not configurable from clients.
* Typical usage:
* <code>
* MutableNamespaceContext mnc = new MutableNamespaceContext();
* mnc.setMapping("somePrefix", "someNamespaceURI");
* XPath xp = .....
* xp.setNamespaceContext(mnc);
* </code>
*
*/
public final class MutableNamespaceContext implements NamespaceContext {
private final Map<String,String> nsMap = new HashMap<String,String>();
/**
* Default constructor.
*/
public MutableNamespaceContext(){
setupDefaults();
}
/**
* Attempts to resolve the given prefix into a namespaceURI.
* @return The namespace URI or XMLConstants.NULL_NS_URI if no mapping is found.
* @throws IllegalStateException if the given prefix is null.
*/
@Override
public String getNamespaceURI(String prefix){
if(prefix == null)
throw new IllegalStateException("A null prefix not allowed");
if(!nsMap.containsKey(prefix))
return XMLConstants.NULL_NS_URI;
else
return nsMap.get(prefix);
}
/**
* Resolves all registered prefixes for the given URI.
* @param uri
* @return An iterator of all registered prefixes for the given URI, the empty iterator if none are found.
*/
@SuppressWarnings("unchecked")
@Override
public Iterator<String> getPrefixes(String URI) {
if(URI == null)
throw new IllegalStateException("A null URI not allowed");
List<String> list = new ArrayList<String>();
for(Map.Entry<String, String> entry : nsMap.entrySet()){
if(entry.getValue().equals(URI))
list.add(entry.getKey());
}
return Collections.unmodifiableList(list).iterator();
}
/**
* Resolves one prefix for the given URI.
* @param uri
* @return The registered prefix
*/
@Override
public String getPrefix(String URI) {
if(URI == null)
throw new IllegalStateException("A null URI not allowed");
final Iterator<String> itr = getPrefixes(URI);
if(itr.hasNext())
return itr.next();
else
return null;
}
/**
* Sets a prefix to URI mapping.
* Overwrites existing mappings if existing, does not allow setting any of the default name space prefix mappings or mapping alternative prefixes for the default name space URI's.
* @param prefix
* @param URI
* @throws IllegalStateException if either argument is null.
*/
public void setMapping(final String prefix, final String URI){
if(prefix==null || URI==null)
throw new IllegalStateException("Null prefix or URI not allowed");
if(!prefix.equals(XMLConstants.DEFAULT_NS_PREFIX) && !prefix.equals(XMLConstants.XML_NS_PREFIX) && !prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)
&& !URI.equals(XMLConstants.XML_NS_URI) && !URI.equals(XMLConstants.XML_NS_URI) && !URI.equals(XMLConstants.NULL_NS_URI))
nsMap.put(prefix, URI);
}
/**
* Clear user defined mappings.
*/
public void clearMappings(){
nsMap.clear();
setupDefaults();
}
private void setupDefaults(){
nsMap.put(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
nsMap.put(XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.XMLNS_ATTRIBUTE_NS_URI);
nsMap.put(XMLConstants.DEFAULT_NS_PREFIX, XMLConstants.NULL_NS_URI);
}
}

@ -81,7 +81,7 @@
<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 -->

@ -6,10 +6,14 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
@ -23,6 +27,8 @@ import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import se.su.dsv.scipro.util.xml.MutableNamespaceContext;
/**
* Assert that deploy configuration is upheld before build can be completed.
* @author Martin Peters - mpeters@dsv.su.se
@ -34,6 +40,7 @@ public class TestDeployConfiguration {
private static String repositoryContext = "META-INF"+File.separator+"repositoryContext.xml";
private static String baseRepository = "META-INF"+File.separator+"base-repository.xml";
private static String webXmlPath = "src"+File.separator+"main"+File.separator+"webapp"+File.separator+"WEB-INF"+File.separator+"web.xml";
private static final String applicationContextPath = "applicationContext.xml";
@Test
public void testWicketDeploymentConfiguration() throws XPathExpressionException, IOException, SAXException, ParserConfigurationException {
@ -98,6 +105,27 @@ public class TestDeployConfiguration {
}
@Test
public void testExternalAuthCfg() throws XPathExpressionException, IOException{
InputSource applicationContextXml = getInputSource(applicationContextPath);
XPath xPath = getApplicationContextXPath();
Assert.assertEquals("true", xPath.evaluate("/beanNS:beans/beanNS:bean[@id='applicationSettings']/beanNS:property[@name='acceptExternalAuthentication']/@value", applicationContextXml));
}
@Test
public void testRemoteUserLookupCfg() throws XPathExpressionException, IOException{
InputSource applicationContextXml = getInputSource(applicationContextPath);
XPath xPath = getApplicationContextXPath();
Assert.assertEquals("true", xPath.evaluate("/beanNS:beans/beanNS:bean[@id='applicationSettings']/beanNS:property[@name='enableRemoteUserLookup']/@value", applicationContextXml));
}
@Test
public void testRemoteUserRemoteUserLookupUrlCfg() throws XPathExpressionException, IOException{
InputSource applicationContextXml = getInputSource(applicationContextPath);
XPath xPath = getApplicationContextXPath();
Assert.assertEquals("https://thesis.dsv.su.se/match/json", xPath.evaluate("/beanNS:beans/beanNS:bean[@id='applicationSettings']/beanNS:property[@name='remoteLookupUrl']/@value", applicationContextXml));
}
private InputSource getInputSource(String filePath) throws IOException{
String theString = readResourceAsString(filePath);
InputStream is = new ByteArrayInputStream(theString.getBytes());
@ -114,5 +142,11 @@ public class TestDeployConfiguration {
IOUtils.copy(in, writer, charset);
return writer.toString();
}
private XPath getApplicationContextXPath(){
XPath xPath = XPathFactory.newInstance().newXPath();
MutableNamespaceContext mnc = new MutableNamespaceContext();
mnc.setMapping("beanNS","http://www.springframework.org/schema/beans");
xPath.setNamespaceContext(mnc);
return xPath;
}
}