package org.archive.accesscontrol.webui; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.archive.accesscontrol.model.HibernateRuleDao; import org.archive.accesscontrol.model.Rule; import org.archive.accesscontrol.model.RuleSet; import org.archive.surt.NewSurtTokenizer; import org.archive.util.ArchiveUtils; import org.archive.util.SURT; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; public class AdminController extends AbstractController { private HibernateRuleDao ruleDao; private static final DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final long NEW_RULE = -1L; static { dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT")); } protected enum ErrorStatus { SUCCESS, DUP_RULE, } @Autowired public AdminController(HibernateRuleDao ruleDao) { this.ruleDao = ruleDao; } protected ModelAndView ruleList(String surt, HttpServletRequest request, HttpServletResponse response) throws Exception { Long editingRuleId = null; if (request.getParameter("edit") != null) { if (request.getParameter("edit").equals("new")) { editingRuleId = NEW_RULE; } else { try { editingRuleId = Long.decode(request.getParameter("edit")); } catch (NumberFormatException e) { } } } return ruleList(surt, editingRuleId, request, response); } /** * Return true if the given string appears to be a SURT. * @param s * @return */ protected boolean isSurt(String s) { return s.charAt(0) == '(' || s.indexOf("://") == s.indexOf("://("); } /** * Perform a several cleanups on the given surt: * * Convert a URL to a SURT * * Add a trailing slash to SURTs of the form: http://(...) * @param surt * @return */ protected String cleanSurt(String surt) { if (!isSurt(surt)) { surt = ArchiveUtils.addImpliedHttpIfNecessary(surt); surt = SURT.fromURI(surt); } if (surt.endsWith(",)") && surt.indexOf(")") == surt.length()-1) { surt = surt + "/"; } return surt; } protected ModelAndView ruleList(String surt, Long editingRuleId, HttpServletRequest request, HttpServletResponse response) throws Exception { surt = cleanSurt(surt); int surtSegments = new NewSurtTokenizer(surt).toList().size(); Map<String, Object> model = new HashMap<String, Object>(); RuleSet rules = ruleDao.getRuleTree(surt); ArrayList<DisplayRule> ruleList = new ArrayList<DisplayRule>(); ArrayList<String> childSurts = new ArrayList<String>(); for (Rule rule: rules) { int comparison = rule.getSurt().compareTo(surt); if (comparison <= 0) { DisplayRule displayRule = new DisplayRule(rule, comparison != 0); displayRule.setEditing(rule.getId().equals(editingRuleId)); ruleList.add(displayRule); } else { try { String segment = new NewSurtTokenizer(rule.getSurt()) .toList().get(surtSegments); if (!childSurts.contains(segment)) { childSurts.add(segment); } } catch (IndexOutOfBoundsException e) { } } } String order = request.getParameter("order"); boolean reverse = order != null && order.equals("1"); if (!reverse) { Collections.sort(ruleList, Collections.reverseOrder()); } else { Collections.sort(ruleList); } if (editingRuleId != null && editingRuleId == NEW_RULE) { Rule rule = new Rule(); rule.setId(NEW_RULE); rule.setSurt(surt); DisplayRule newRule = new DisplayRule(rule, false); newRule.setEditing(true); ruleList.add(newRule); } ArrayList<String> childSurtsList = new ArrayList<String>(childSurts); Collections.sort(childSurtsList); doURLCheck(rules, ruleList, request, model); model.put("rules", ruleList); model.put("surt", surt); model.put("childSurts", childSurtsList); model.put("encodedSurt", URLEncoder.encode(surt, "utf-8")); model.put("breadcrumbs", SurtNode.nodesFromSurt(surt)); model.put("editingRuleId", request.getParameter("edit")); model.put("errorStatus", request.getParameter("errorStatus")); return new ModelAndView("list_rules", model); } protected void doURLCheck(RuleSet rules, List<DisplayRule> ruleList, HttpServletRequest request, Map<String, Object> model) { String url = request.getParameter("checkURL"); if (url == null || url.isEmpty()) { return; } String surt; if (this.isSurt(url)) { surt = url; } else { url = ArchiveUtils.addImpliedHttpIfNecessary(url); surt = SURT.fromURI(url); } surt = this.cleanSurt(surt); String dateStamp = request.getParameter("checkDate"); String group = request.getParameter("checkGroup"); model.put("checkGroup", group); model.put("checkURL", url); Date captureDate = null; if ((dateStamp != null) && !dateStamp.isEmpty()) { String paddedDateStr = dateStamp; int pad = 14 - dateStamp.length(); for (int i = 0; i < pad; i++) { paddedDateStr += '0'; } try { captureDate = ArchiveUtils.parse14DigitDate(paddedDateStr); model.put("checkDate", dateStamp); } catch (ParseException e) { captureDate = null; } } Date retrievalDate = new Date(); if (captureDate == null) { captureDate = retrievalDate; } Rule theRule = rules.getMatchingRule(surt, captureDate, retrievalDate, group); if (theRule == null) { return; } // Now, find displayRule that contains matched rule, if any, and set it to highlight for (DisplayRule displayRule : ruleList) { if (displayRule.getRule().getId().equals(theRule.getId())) { displayRule.setHighlight(true); break; } } } protected ModelAndView redirectToSurt(HttpServletRequest request, HttpServletResponse response, String surt, ErrorStatus errStatus) throws UnsupportedEncodingException { String newUrl = request.getContextPath() + "/admin?surt=" + URLEncoder.encode(surt, "UTF-8"); if (errStatus != ErrorStatus.SUCCESS) { newUrl += "&errorStatus=" + errStatus.toString(); } response.setHeader("Location", newUrl); response.setStatus(302); return null; } protected ModelAndView redirectToSurt(HttpServletRequest request, HttpServletResponse response, String surt) throws UnsupportedEncodingException { return redirectToSurt(request, response, surt, ErrorStatus.SUCCESS); } @Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { if (request.getParameter("saveRule") != null) { return saveRule(request, response); } String surt = (String) request.getAttribute("id"); if (surt == null) { surt = request.getParameter("surt"); } if (request.getParameter("cancel") != null) { return redirectToSurt(request, response, surt); } if (request.getParameter("delete") != null) { return deleteRule(request, response); } if (surt != null) { return ruleList(surt, request, response); } return new ModelAndView("index"); } private ModelAndView deleteRule(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException { Long ruleId = Long.decode(request.getParameter("edit")); ruleDao.deleteRule(ruleId); return redirectToSurt(request, response, request.getParameter("surt")); } private ModelAndView saveRule(HttpServletRequest request, HttpServletResponse response) throws Exception { String surt = request.getParameter("surt"); Rule rule; Long ruleId = Long.decode(request.getParameter("edit")); if (ruleId == NEW_RULE) { rule = new Rule(); } else { rule = ruleDao.getRule(ruleId); } rule.setSurt(surt); rule.setPolicy(request.getParameter("policy")); rule.setWho(request.getParameter("who")); rule.setCaptureStart(parseDate(request.getParameter("captureStart"))); rule.setCaptureEnd(parseDate(request.getParameter("captureEnd"))); rule.setRetrievalStart(parseDate(request.getParameter("retrievalStart"))); rule.setRetrievalEnd(parseDate(request.getParameter("retrievalEnd"))); rule.setSecondsSinceCapture(parseInteger(request.getParameter("secondsSinceCapture"))); rule.setPrivateComment(request.getParameter("privateComment")); rule.setPublicComment(request.getParameter("publicComment")); rule.setExactMatch(request.getParameter("exactMatch") != null); boolean saved = true; // If adding a new rule, make sure it doesn't match any existing rules // or we'll have duplicates (and only one of the dups will show up in the list) if (ruleId == NEW_RULE) { saved = ruleDao.saveRuleIfNotDup(rule); } else { ruleDao.saveRule(rule); } return redirectToSurt(request, response, surt, saved ? ErrorStatus.SUCCESS : ErrorStatus.DUP_RULE); } private Date parseDate(String s) { try { return dateFormatter.parse(s); } catch (ParseException e) { return null; } } private Integer parseInteger(String s) { try { return Integer.decode(s); } catch (NumberFormatException e) { return null; } } }