Mercurial Hosting > nabble
diff src/nabble/view/lib/Jtp.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children | 18cf4872fd7f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nabble/view/lib/Jtp.java Thu Mar 21 19:15:52 2019 -0600 @@ -0,0 +1,966 @@ +package nabble.view.lib; + +import fschmidt.util.java.HtmlUtils; +import fschmidt.util.servlet.ServletUtils; +import nabble.model.DailyNumber; +import nabble.model.Init; +import nabble.model.ModelHome; +import nabble.model.Node; +import nabble.model.NodeIterator; +import nabble.model.NodeSearcher; +import nabble.model.Person; +import nabble.model.Site; +import nabble.model.User; +import nabble.naml.compiler.Template; +import nabble.naml.compiler.TemplatePrintWriter; +import nabble.naml.namespaces.BasicNamespace; +import nabble.view.web.forum.Permalink; +import nabble.view.web.template.NabbleNamespace; +import nabble.view.web.template.NodeNamespace; +import nabble.view.web.template.UserNamespace; +import org.apache.commons.fileupload.DiskFileUpload; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public final class Jtp { + + private static final Logger logger = LoggerFactory.getLogger(Jtp.class); + + private static final String ANONYMOUS_COOKIE_ID = "anonymousId"; + private static final String ANONYMOUS_COOKIE_NAME = "anonymousName"; + + private Jtp() {} // never + + public static Person getVisitor(HttpServletRequest request, HttpServletResponse response) + throws ServletException + { + Person visitor = getUser(request,response); + if( visitor != null ) + return visitor; + return getOrCreateAnonymous(request,response); + } + + private static Person getAnonymous(HttpServletRequest request) { + String anonymousId = ServletUtils.getCookieValue(request, ANONYMOUS_COOKIE_ID); + if (anonymousId == null) + return null; + String anonymousName = ServletUtils.getCookieValue(request, ANONYMOUS_COOKIE_NAME); + return getSite(request).getAnonymous(anonymousId, anonymousName == null? null : HtmlUtils.urlDecode(anonymousName)); + } + + private static Person getOrCreateAnonymous(HttpServletRequest request, HttpServletResponse response) + throws ServletException + { + Person anonymous = getAnonymous(request); + if (anonymous == null) { + Site site = getSiteNotNull(request); + String cookie = site.newAnonymousCookie(); + anonymous = site.getAnonymous(cookie,null); + ServletUtils.setCookie(request, response, ANONYMOUS_COOKIE_ID, cookie, true, null); + } + return anonymous; + } + + public static User getUser(HttpServletRequest request, HttpServletResponse response) + throws ServletException + { + return getUser(request); + } + + public static User getUser(HttpServletRequest request) + throws ServletException + { + User user = null; + String userId = ServletUtils.getCookieValue(request,"userId"); + if (userId != null && userId.length() > 0) { + user = getSiteNotNull(request).getUser(Long.valueOf(userId)); + } + if( user==null ) + return null; + if( ServletUtils.getCookieValue(request,"username")==null) + return null; + String pwd = ServletUtils.getCookieValue(request,"password"); + if ( pwd==null ) + return null; + String passcookie = HtmlUtils.urlDecode(pwd); + if( ! (user.isRegistered() && user.checkPasscookie(passcookie)) ) + return null; + trackUser(request, user); + return user; + } + + public static void doLogin(HttpServletRequest request, HttpServletResponse response, User user, boolean save) + throws IOException + { + if( !user.isRegistered() ) + throw new RuntimeException("user must be registered to login"); + + ServletUtils.setCookie(request,response,"userId", String.valueOf(user.getId()), save, null); + ServletUtils.setCookie(request,response,"password", HtmlUtils.urlEncode(user.getPasscookie()), save, null); + ServletUtils.setCookie(request,response,"username", HtmlUtils.urlEncode(user.getName()), save, null); + dontCache(response); + + DailyNumber.logins.inc(); + trackUser(request, user); + + // fix anonymous nodes from this user + String anonymousId = ServletUtils.getCookieValue(request, ANONYMOUS_COOKIE_ID); + if (anonymousId != null) { + user.moveToRegisteredAccount(anonymousId); + ServletUtils.removeCookie(request, response, ANONYMOUS_COOKIE_ID, null); + ServletUtils.removeCookie(request, response, ANONYMOUS_COOKIE_NAME, null); + } + } + + private static Set trackUsers = Init.get("trackUsers", Collections.EMPTY_SET); + + private static void trackUser(HttpServletRequest request, User user) { + long siteId = user.getSite().getId(); + String siteAndUser = siteId + "|" + user.getId(); + if (trackUsers.contains(siteAndUser)) + logger.error("Track User [site=" + siteId + " | user = " + user.getId() + "] = " + getClientIpAddr(request)); + } + + public static String getClientIpAddr(HttpServletRequest request) { + return JtpContextServlet.getClientIpAddr(request); + } + + public static void logout(HttpServletRequest request,HttpServletResponse response) { + request.getSession().removeAttribute("nextUrl"); + ServletUtils.removeCookie(request,response,"userId", null); + ServletUtils.removeCookie(request,response,"password", null); + ServletUtils.removeCookie(request,response,"username", null); + } + + public static void login(String msg, HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + String nextUrl = getCurrentPath(request); +//if(nextUrl.endsWith("NamlServlet.jtp")) logger.error("nextUrl = "+nextUrl); + response.sendRedirect(loginPath(getSiteNotNull(request),msg,nextUrl)); + } + + public static String getCurrentPath(HttpServletRequest request) { + String s = request.getServletPath(); + String q = request.getQueryString(); + if( q != null ) + s += "?" + q; + return s; + } + + public static String loginPath(Site site,String message,String nextUrl) { + Map<String,Object> args = new HashMap<String,Object>(); + if( message != null ) + args.put("message",message); + if( nextUrl != null ) + args.put("nextUrl",nextUrl); + Template template = site.getTemplate( "login_path", + BasicNamespace.class, NabbleNamespace.class + ); + StringWriter sw = new StringWriter(); + template.run( new TemplatePrintWriter(sw), args, + new BasicNamespace(template), new NabbleNamespace(site) + ); + return sw.toString(); + } + + + public static String hideNull(Object obj) { + return obj==null ? "" : obj.toString(); + } + + public static String userUrl(Person user) { + String base = user.getSite().getBaseUrl(); + return base + "/template/NamlServlet.jtp?macro=user_nodes&user=" + user.getIdString(); + } + + public static String userLink(Person user) { + return "<a href=\"" + userUrl(user) + "\" rel=\"nofollow\" target=\"_top\">" + +user.getNameHtml()+"</a>"; + } + + public static String userLinkJs(HttpServletRequest request,User user) { + StringBuilder buf = new StringBuilder(); + buf.append("<script>document.write('<a href=\\\""); + buf.append(request.getContextPath()); + buf.append("' +'/user/UserNodes' + '.jtp?'+'user="); + buf.append(user.getId()); + buf.append("\\\" rel=\\\"nofollow\\\" "); + buf.append("' + Nabble.embeddedTarget('_top') + '"); + buf.append(">');</script>"); + buf.append(user.getNameHtml()); + buf.append("<script>document.write('</a>');</script>"); + return buf.toString(); + } + + + public static String subjectEncode(String s) { + return ViewUtils.subjectEncode(s); + } + + public static String link(Node node) { + if (node == null) + return ""; + return "<a href=\"" + url(node) + "\">" + node.getSubjectHtml() + "</a>"; + } + + public static String url(Node node) { + return node.getSite().getBaseUrl() + path(node); + } + + public static String path(Node node) { + switch( node.getKind() ) { + case POST: + return Permalink.path(null,node); + case APP: + Site site = node.getSite(); + Template template = site.getTemplate( "app_path", + BasicNamespace.class, NabbleNamespace.class, NodeNamespace.class + ); + StringWriter sw = new StringWriter(); + template.run( new TemplatePrintWriter(sw), Collections.<String,Object>emptyMap(), + new BasicNamespace(template), new NabbleNamespace(site), new NodeNamespace(node) + ); + return sw.toString(); + } + throw new RuntimeException("never"); + } + + public static String topicViewPath(Node node, long selectedId, TopicView topicView) { + Site site = node.getSite(); + Template template = site.getTemplate( "topic_path", + BasicNamespace.class, NabbleNamespace.class, NodeNamespace.class + ); + StringWriter sw = new StringWriter(); + Map<String,Object> args = new HashMap<String,Object>(); + args.put( "view", topicView == TopicView.CLASSIC? "classic" : topicView == TopicView.THREADED? "threaded" : "list"); + args.put( "selected_id", selectedId); + template.run( new TemplatePrintWriter(sw), args, + new BasicNamespace(template), new NabbleNamespace(site), new NodeNamespace(node) + ); + return sw.toString(); + } + + public static String link(User user) { + return "<a href=\"" + url(user) + "\">" + user.getNameHtml() + "</a>"; + } + + public static String url(User user) { + return user.getSite().getBaseUrl() + path(user); + } + + public static String path(User user) { + Site site = user.getSite(); + Template template = site.getTemplate( "path", + BasicNamespace.class, NabbleNamespace.class, UserNamespace.class + ); + StringWriter sw = new StringWriter(); + template.run( new TemplatePrintWriter(sw), Collections.<String,Object>emptyMap(), + new BasicNamespace(template), new NabbleNamespace(site), new UserNamespace(user) + ); + return sw.toString(); + } + + public static void javascriptRedirect(HttpServletRequest request,HttpServletResponse response,Node node) + throws IOException, ServletException + { + Shared.javascriptRedirect(request,response,url(node)); + } + + public static String getStartFragment(String text,int minSize,int maxSize) { + if( text.length() <= maxSize ) + return text; + int i = maxSize; + while( !Character.isWhitespace(text.charAt(i)) ) { + i--; + if( i <= minSize ) + return text.substring(0,maxSize); + } + while( Character.isWhitespace(text.charAt(i)) ) { + if( i < minSize ) + return text.substring(0,maxSize); + i--; + } + return text.substring(0,i+1); + } + + public static String truncate(String text,int len,String dotdotdot) { + return text.length() <= len ? text : text.substring(0,len) + dotdotdot; + } + + public static String breakUp(final String text) { + return HtmlUtils.breakUp(text,30,true); + } + + private static final String PUNCTUATION = "[\\!\"\\&\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\]\\^\\_\\`\\{\\|\\}\\~]"; + + private static void metaKeywords(final String text,Set<String> words) { + StringTokenizer str = new StringTokenizer(text.toLowerCase().replaceAll(PUNCTUATION," ")); + while( str.hasMoreTokens() ) { + String s = str.nextToken(); + if( "re".equals(s) ) + continue; + words.add(s); + } + } + + private static final Set<String> invalidKeywords = new TreeSet<String>(); + static { + String[] words = { + "hi", "a", "an", "in", "i", "hello", "please", + "to", "on", "by", "t", "m", "but", "the", "of", + "it", "so", "at", "am", "dear", "me", "and", "are", + "wonder", "from", "be", "been", "is", + "was", "if", "this", "that", "there" + }; + for (String word : words) { + invalidKeywords.add(word); + } + } + + private static String metaKeywords(Set<String> words) { + StringBuilder buf = new StringBuilder(); + for( String s : words ) { + if (invalidKeywords.contains(s.toLowerCase())) + continue; + if (buf.length() > 0) buf.append(", "); + buf.append(s); + } + return buf.toString(); + } + + public static String metaKeywords(Node node) { + return metaKeywords(node, true); + } + + public static String metaKeywords(Node node, boolean includeMessage) { + Set<String> words = new LinkedHashSet<String>(); + for( Node n = node; n!=null; n = n.getParent() ) { + metaKeywords(n.getSubjectHtml(),words); + if (includeMessage) { + metaKeywords(getFragment(n.getMessage().getText(), 200), words); + includeMessage = false; + } + } + if( node.getKind() == Node.Kind.APP ) { + String type = node.getType(); + if (type.equals(Node.Type.GALLERY)) { + words.add("photo"); + words.add("pictures"); + words.add("gallery"); + words.add("images"); + } else if (type.equals(Node.Type.BLOG)) { + words.add("blog"); + } else if (type.equals(Node.Type.NEWS)) { + words.add("news"); + words.add("newspaper"); + words.add("magazine"); + } else { + words.add("forum"); + words.add("board"); + words.add("community"); + } + if (node.getAssociatedMailingList() != null) + words.add("mailing list archive"); + } + return metaKeywords(words); + } + + public static String metaDescription(Node node) { + StringBuilder buf = new StringBuilder(); + String name = node.getSubjectHtml(); + buf.append(name); + if( node.getKind() == Node.Kind.APP ) { + String viewName = viewName(node).toLowerCase(); + if (! (name.toLowerCase().indexOf(viewName) >= 0)) { + buf.append(' ').append(viewName); + } + if (node.getAssociatedMailingList()!=null) + buf.append(" and mailing list archive"); + buf.append("."); + } + appendSnippet(node.getMessage().getText(), buf); + return buf.toString(); + } + + private static void appendSnippet(String text, StringBuilder buf) { + if (buf.length() >= 200 || text.length() == 0) return; + String fragment = getFragment(text, 200 - buf.length()); + if (buf.charAt(buf.length() - 1) != '.') buf.append('.'); + buf.append(' '); + buf.append(ModelHome.hideAllEmails(HtmlUtils.htmlEncode(fragment).replaceAll("\\s+"," "))); + if (fragment.length() < text.length()) buf.append("..."); + } + + private static String getFragment(String text, int size) { + if (text.length() <= size) return text; + int end = text.lastIndexOf(' ', size); + if (end < 0) end = size; + return text.substring(0, end); + } + + + public static String formatDateOnly(String label, Date date) { + return "<script>document.write('" + label + "' + Nabble.formatDateOnly(new Date("+date.getTime()+")));</script>"; + } + + public static String formatDateOnly(Date date) { + return "<script>document.write(Nabble.formatDateOnly(new Date("+date.getTime()+")));</script>"; + } + + public static String formatDateLong(String label, Date date) { + return "<script>document.write('" + label + "' + Nabble.formatDateLong(new Date("+date.getTime()+")));</script>"; + } + + public static String formatDateLong(Date date) { + return "<script>document.write(Nabble.formatDateLong(new Date("+date.getTime()+")));</script>"; + } + + public static String formatDateShort(Date date) { + return "<script>document.write(Nabble.formatDateShort(new Date("+date.getTime()+")));</script>"; + } + + + private static final String jsWriteStart = "<script>document.write("; + private static final String jsWriteEnd = ");</script>"; + + public static String javascriptQuote(String s) { + StringBuilder buf = new StringBuilder(); + buf.append( "'" ); + int i = 0; + while(true) { + int i2 = s.indexOf(jsWriteStart,i); + if( i2 == -1 ) + break; + int i3 = s.indexOf(jsWriteEnd,i2); + if( i3 == -1 ) + throw new RuntimeException(); + buf.append( HtmlUtils.javascriptStringEncode(s.substring(i,i2)) ); + buf.append( "'+(" ); + buf.append( s.substring(i2+jsWriteStart.length(),i3) ); + buf.append( ")+'" ); + i = i3 + jsWriteEnd.length(); + } + buf.append( HtmlUtils.javascriptStringEncode(s.substring(i)) ); + buf.append( "'" ); + return buf.toString(); + } + + public static int getYear(Date date) { + return date.getYear() + 1900; + } + + public static int thisYear() { + return getYear(new Date()); + } + + public static String capitalize(String s) { + return s.substring(0,1).toUpperCase() + s.substring(1); + } + + public static void dontCache(HttpServletResponse response) { + response.setHeader("Cache-Control","no-cache, max-age=0"); + } + + + public static Map<String,FileItem> getFileItems(HttpServletRequest request) + throws FileUploadException + { + DiskFileUpload fu = new DiskFileUpload(); + Map<String,FileItem> map = new HashMap<String,FileItem>(); + @SuppressWarnings("unchecked") + List<FileItem> fileItems = fu.parseRequest(request); + for( FileItem fi : fileItems ) { + map.put(fi.getFieldName(),fi); + } + return map; + } + + public static String helpIndexUrl(HttpServletRequest request,HttpServletResponse response) + throws IOException + { + StringBuilder url = new StringBuilder(); + url.append( request.getContextPath() ); + url.append( "/help/Index.jtp" ); + return url.toString(); + } + + public static long getLong(HttpServletRequest request,String param) + throws ServletException + { + return parseLong( request, request.getParameter(param) ); + } + + public static long parseLong(HttpServletRequest request,String s) + throws ServletException + { + try { + return Long.parseLong(s); + } catch(NumberFormatException e) { + if (invalidReferer(request) || s.contains(" Result: ")) { + logger.warn("Bad URL", e); + throw new MinorServletException(e); + } else + throw e; + } + } + + public static int getInt(HttpServletRequest request,String param) + throws ServletException + { + return parseInt( request, request.getParameter(param) ); + } + + public static int parseInt(HttpServletRequest request,String s) + throws ServletException + { + try { + return Integer.parseInt(s); + } catch(NumberFormatException e) { + if (invalidReferer(request)) + throw new ServletException(e); + else + throw e; + } + } + + /* + The User-Agent should not be considered. If a browser doesn't send the referer, then we have no way + to know if the referer is valid or not. So we should assume it isn't to avoid having cases + where it really isn't valid go into error.log . If the referer really was valid, then the same problem + should show up again in a good browser. We shouldn't worry so much about taking care of broken browsers. + -fschmidt + */ + public static boolean invalidReferer(HttpServletRequest request) { + String referer = request.getHeader("referer"); + if( referer == null + || !referer.startsWith("http://" + request.getHeader("host")) + ) + return true; + if( request.getMethod().equals("GET") ) { + StringBuffer url = request.getRequestURL(); + String query = request.getQueryString(); + if( query != null ) + url.append( '?' ).append( query ); + if( url.toString().equals(referer) ) + return true; + } + return false; + } + + public static ServletException servletException(HttpServletRequest request,String msg) { + if( invalidReferer(request) ) + return new ServletException(msg); + throw new RuntimeException(msg); + } + + public static String getString(HttpServletRequest request, String param) + throws ServletException + { + String value = request.getParameter(param); + if (value == null && invalidReferer(request)) { + throw new ServletException("Parameter is null: " + param + " [referer is null]"); + } + return value; + } + + // should be removed + public static String getReadAuthorizationKey(Node node) { + if( node==null ) + return null; + node = Permissions.getPrivateNode(node); + return node!=null ? Long.toString(node.getId()) : null; + } + + // should be removed + public static boolean authorizeForRead(String key,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { + Node node = getSiteNotNull(request).getNode( Long.parseLong(key) ); + User user = getUser(request,response); + if( user==null ) { + login("You must login to view " + node.getSubject(), request, response); + return false; + } + + if( !Jtp.canBeViewedBy(node,user) ) { + response.sendRedirect(getUnauthorizedPath(node)); + return false; + } + return true; + } + + private static String getUnauthorizedPath(Node node) { + Template template = node.getSite().getTemplate( "unauthorized_path", + BasicNamespace.class, NabbleNamespace.class, NodeNamespace.class + ); + StringWriter sw = new StringWriter(); + template.run( new TemplatePrintWriter(sw), Collections.<String, Object>emptyMap(), + new BasicNamespace(template), new NabbleNamespace(node.getSite()), new NodeNamespace(Permissions.getPrivateNode(node)) + ); + return sw.toString(); + } + + private static final long startTime = System.currentTimeMillis()/1000*1000; + + public static boolean cacheMe(HttpServletRequest request,HttpServletResponse response) + throws ServletException, IOException + { + if( startTime <= request.getDateHeader("If-Modified-Since") ) { + response.sendError(HttpServletResponse.SC_NOT_MODIFIED); + return true; + } + response.setDateHeader("Last-Modified",startTime); + return false; + } + + + public static void addBreadCrumbEvents(Collection<String> events,Node node) { + if( node==null ) return; + for( Node f = node.getApp(); f != null; f = f.getParent() ) { + events.add( Cache.nodeChangeEvent(f) ); + } + } + + + public static List<Node> getPinnedChildren(Node parent) { + List<Node> pinned = new ArrayList<Node>(); + NodeIterator<? extends Node> iter = parent.getChildren(); + try { + while( iter.hasNext() ) { + Node node = iter.next(); + if( !node.isPinned() ) + break; + pinned.add(node); + } + } finally { + iter.close(); + } + return pinned; + } + + public static void addPinnedChild(Node parent, Node child) { + List<Node> pinned = getPinnedChildren(parent); + if (child.getKind() == Node.Kind.APP) { + // Insert after the last pinned forum (before pinned threads) + boolean added = false; + for (int i = 0; i < pinned.size(); i++) { + Node node = pinned.get(i); + if (node.getKind() == Node.Kind.POST) { + pinned.add(i, child); + added = true; + break; + } + } + if (!added) + pinned.add(child); + } + else { + pinned.add(child); + } + parent.pin(pinned.toArray(new Node[0])); + } + + public static void unpinChild(Node parent, Node child) { + List<Node> pinned = getPinnedChildren(parent); + pinned.remove(child); + parent.pin(pinned.toArray(new Node[0])); + } + + + public static String snippet(Node node,int len) { + String text = node.getMessage().getTextWithoutQuotes(); + return HtmlUtils.htmlEncode(ModelHome.hideAllEmails(NodeSearcher.getStartingFragment(text, len, "..."))); + } + + + public static String noCid(String url) { + return url.replaceAll("(;|&)cid=(\\d|\\-)+", ""); + } + + // should go away -fschmidt + public static String viewName(Node node) { + Node forum = node.getApp(); + if (forum == null) + return "Forum"; + String type = forum.getType(); + if (type.equals(Node.Type.GALLERY)) + return "Gallery"; + else if (type.equals(Node.Type.NEWS)) + return "Newspaper"; + else if (type.equals(Node.Type.BLOG)) + return "Blog"; + else + return "Forum"; + } + + // should go away -fschmidt + public static String childName(Node node, boolean plural) { + Node forum = node.getApp(); + if (forum == null) + return plural? "Sub-Forums" : "Sub-Forum"; + String type = forum.getType(); + if (type.equals(Node.Type.GALLERY) || + type.equals(Node.Type.NEWS) || + type.equals(Node.Type.BLOG) || + type.equals(Node.Type.BOARD)) + return plural? "Subcategories" : "Subcategory"; + else + return plural? "Sub-Forums" : "Sub-Forum"; + } + + public static String parentName(Node node) { + if (node.getParent() == null) + return "Current Parent"; + return "Parent " + viewName(node.getParent()); + } + + // what do you plan for this? -fschmidt + public static String getSmallLogo(String type) { + if (type.equals(Node.Type.GALLERY)) + return "<img src=\"/images/homepage/gallery_sm.png\" width=20 height=15 alt=\"Free photo gallery\">"; + else if (type.equals(Node.Type.BLOG)) + return "<img src=\"/images/homepage/blog_sm.png\" width=20 height=17 alt=\"Free blog\">"; + else if (type.equals(Node.Type.NEWS)) + return "<img src=\"/images/homepage/news_sm.png\" width=20 height=15 alt=\"Free newspaper\">"; + else + return ""; + } + + static String getCanonicalUrl(HttpServletRequest request) { + String current = ServletUtils.getCurrentURL(request); + if (current.startsWith(Lazy.homeContextUrl)) + return null; + String host = request.getHeader("host"); + return current.replace("http://"+host, Lazy.homeContextUrl); + } + + private static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9]+$"); + public static boolean isInteger(String s) { + return s != null && NUMBER_PATTERN.matcher(s).find(); + } + + /** + * Maximum number of rows an app page can have. + * This limit must exist because there are physical restrictions: + * - the $Js URL can't support too many nodes at the same time. + * - div tags have a limit of 32,768 pixels of height. + */ + public static int getMaxRowsPerPage(String type) { + int n = 100; + if (type.equals(Node.Type.BLOG)) + n = 20; + return n; + } + + /** Default number of rows an app page has. */ + public static int getDefaultRowsPerPage(String type) { + int n = 35; + if (type.equals(Node.Type.BLOG)) + n = 10; + else if (type.equals(Node.Type.GALLERY)) + n = 12; + else if (type.equals(Node.Type.GALLERY)) + n = 25; + return n; + } + + public static int getDefaultMixedLength() { return 6;} + public static int getMaxMixedLength() { return 20;} + + private static final String defaultHost = (String)Init.get("defaultHost"); + static { + if( defaultHost==null ) { + logger.error("no defaultHost"); + System.exit(-1); + } + } + + public static String getDefaultHost() { + return defaultHost; + } + + public static String getBaseUrl(HttpServletRequest request) { + String host = request.getHeader("host"); + String scheme = request.getHeader("X-Forwarded-Proto"); + if( scheme == null ) + scheme = request.getScheme(); + return scheme + "://" + host; + } + + // fix jetty bug + public static void sendRedirect(HttpServletRequest request,HttpServletResponse response,String url) + throws IOException + { + if( url.startsWith("/") ) + url = Jtp.getBaseUrl(request) + url; + response.sendRedirect(url); + } + + private static class Lazy { + static final Pattern ROOT_URL_PATTERN; + static final String defaultContextUrl; + static final String homeContextUrl; + static { + defaultContextUrl = "http://" + defaultHost; + homeContextUrl = Init.get("homeContextUrl",defaultContextUrl); + ROOT_URL_PATTERN = Pattern.compile( ".*\\.(\\d+)\\."+Pattern.quote(defaultHost) ); + } + } + + public static String homePage() { + return nabble.view.web.Index.url(); + } + + public static String supportUrl() { + return "http://support.nabble.com/"; + } + + public static String supportLink() { + String supportUrl = supportUrl(); + return supportUrl==null ? null : "<a href='"+supportUrl+"' target='_top'>Nabble Support</a>"; + } + + public static String defaultContextUrl() { + return Lazy.defaultContextUrl; + } + + public static String homeContextUrl() { + return Lazy.homeContextUrl; + } + + // doesn't return null + public static Site getSiteNotNull(HttpServletRequest request) + throws ServletException + { + Site site = getSite(request); + if( site == null ) + throw servletException(request,"site not found"); + return site; + } + + private static final Object noSite = new Object(); + + public static Site getSite(HttpServletRequest request) { + Object obj = request.getAttribute("site"); + if( obj == null ) { + Long siteId = getSiteIdFromDomain( ServletUtils.getHost(request) ); + if( siteId != null ) + obj = ModelHome.getSite(siteId); + if( obj == null ) + obj = noSite; + request.setAttribute("root",obj); + } + return obj==noSite ? null : (Site)obj; + } + + public static Site getSiteFromUrl(String url) { + String domain = extractDomain(url); + if( domain == null ) + return null; + Long siteId = getSiteIdFromDomain(domain); + if( siteId == null ) + return null; + return ModelHome.getSite(siteId); + } + + public static Long getSiteIdFromDomain(String domain) { + if( domain.equals(defaultHost) ) + return null; + Matcher m = Lazy.ROOT_URL_PATTERN.matcher(domain); + if( m.matches() ) { + return Long.parseLong(m.group(1)); + } else { + return ModelHome.getSiteIdFromDomain(domain); + } + } + + public static String getDefaultBaseUrl(Site site) { + return ViewUtils.getDefaultBaseUrl( site.getId(), site.getRootNode().getSubject(), defaultHost ); + } + + public static String extractDomain(String url) { + int posDoubleSlash = url.indexOf("//"); + int posDomainEnd = url.indexOf('/', posDoubleSlash+2); + // if the last slash was not found, we can assume the domain ends at the end of the string. + posDomainEnd = posDomainEnd == -1? url.length() : posDomainEnd; + return posDoubleSlash > 0 && posDoubleSlash < 8 && posDomainEnd > posDoubleSlash? url.substring(posDoubleSlash+2, posDomainEnd) : null; + } + + // permissions hacks + + private static boolean can(Person person,String macro,Node node) { + Template template = node.getSite().getTemplate( macro, + BasicNamespace.class, NabbleNamespace.class, UserNamespace.class + ); + StringWriter sw = new StringWriter(); + Map<String,Object> args = new HashMap<String,Object>(); + args.put( "node_attr", new NodeNamespace(node) ); + template.run( new TemplatePrintWriter(sw), args, + new BasicNamespace(template), new NabbleNamespace(node.getSite()), new UserNamespace(person) + ); + return sw.toString().equals("true"); + } + + public static boolean canBeEditedBy(Node node,Person person) { + return can(person,"can_edit",node); + } + + public static boolean canBeRemovedBy(Node node,Person person) { + return can(person,"can_move",node); + } + + public static boolean canBeDeletedBy(Node node,Person person) { + return can(person,"can_delete",node); + } + + public static boolean canBeViewedBy(Node node,Person person) { + return can(person,"can_view",node); + } + + public static boolean canMove(Node node,Person person) { + return can(person,"can_move",node); + } + + public static boolean canAssign(Node node,Person person) { + return can(person,"can_be_assigned_to",node); + } + + public static boolean canChangePostDateOf(Node node,Person person) { + return can(person,"can_change_post_date_of",node); + } + + public static boolean isSiteAdmin(Site site,Person person) { + return person instanceof User && site.getRootNode().getOwner().equals(person); // for now + } + + public static final String CACHED = "cached"; + + public static boolean isCached(HttpServletRequest request,HttpServletResponse response) { + return response.containsHeader("Etag") || request.getAttribute(CACHED) != null; + } + + public static String termsUrl(boolean back) { + return homeContextUrl() + "/Terms.jtp"; + } +}