view src/nabble/view/web/catalog/ChangeParent.jtp @ 19:18cf4872fd7f

remove anonymous posting
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 29 May 2020 22:58:25 -0600
parents 7ecd1a4ef557
children
line wrap: on
line source

<%
package nabble.view.web.catalog;

import fschmidt.db.DbDatabase;
import fschmidt.util.java.HtmlUtils;
import fschmidt.util.servlet.AuthorizingServlet;
import nabble.model.Message;
import nabble.model.ModelException;
import nabble.model.Node;
import nabble.model.Person;
import nabble.model.Site;
import nabble.model.User;
import nabble.model.export.Export;
import nabble.view.lib.Jtp;
import nabble.view.lib.Permissions;
import nabble.view.lib.Shared;
import nabble.view.web.template.UrlMapperNamespace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


public class ChangeParent extends HttpServlet implements AuthorizingServlet {
	private static final Logger logger = LoggerFactory.getLogger(ChangeParent.class);

	public String getAuthorizationKey(HttpServletRequest request) throws ServletException {
		return Jtp.getReadAuthorizationKey( Jtp.getSiteNotNull(request).getNode(Jtp.getLong(request,"forum")) );
	}

	public boolean authorize(String key,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
		return Jtp.authorizeForRead(key,request,response);
	}

	protected void service(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException
	{
		PrintWriter out = response.getWriter();
		String forumId = request.getParameter("forum");
		Node forum = forumId == null? null : Jtp.getSiteNotNull(request).getNode(Long.valueOf(forumId));

		if (forum == null)
			return;

		User visitor = Jtp.getUser(request);
		boolean isSiteAdmin = Permissions.isInGroup( visitor, Permissions.ADMINISTRATORS_GROUP );

		boolean allowed = Jtp.canBeRemovedBy(forum,visitor);
		if (!allowed) {
			Jtp.login("Only administrators can proceed in this area.", request, response);
			return;
		}

		String errorMsg = null;
		String action = request.getParameter("action");
		String option = request.getParameter("option");
		String url = request.getParameter("url");
		if ("set".equals(action) && "POST".equals(request.getMethod())) {
			if ("provide-url".equals(option))
				errorMsg = setParent(forum, url, request, response);
			else if ("merge".equals(option))
				errorMsg = merge(forum, visitor, isSiteAdmin, response);
			else if ("delete-root".equals(option))
				errorMsg = deleteRoot(forum, visitor, response);
			else if ("create-parent".equals(option))
				errorMsg = createParent(forum, (User)visitor, request, response);
			if (errorMsg == null)
				return;
		}

		Node currentParent = forum.getParent();
		%>
		<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
		<html>
			<head>
				<% Shared.title(request, response, "Parent Options"); %>
				<script type="text/javascript">
					$(document).ready(function() {
						function handleFocus() {
							$('#url,#name,#description,#type').attr('disabled','y');
							var id = $(':radio').filter('[checked]').attr('id');
							if (id == 'choose-parent') {
								$('#url').removeAttr('disabled').focus();
							} else if (id == 'create-parent') {
								$('#name,#description,#type').removeAttr('disabled').focus();
								$('#name').focus();
							}
						};
						handleFocus();
						$(':radio').click(handleFocus);
					});
				</script>
				<style type="text/css">
					div.field-title {
						font-weight:bold;
						font-size:110%;
						padding-bottom:.1em;
						margin-top: 1.7em;
					}
					span.disabled {
						font-size:90%;
						font-weight:normal;
						margin-left:1em
					}
				</style>
			</head>
			<body>
				<% Shared.minHeader(request,response, forum); %>
				<% Shared.editHeader(forum.getSubjectHtml(), "Parent Options", out); %>
				<% Shared.errorMessage(request, response, errorMsg, null); %>
				<form id="parent-form" method="post" action="/catalog/ChangeParent.jtp" accept-charset="UTF-8">
					<input type="hidden" name="action" value="set" />
					<input type="hidden" name="forum" value="<%=forum.getId()%>" />

					<div class="second-font field-title">
						<input type="radio" id="choose-parent" name="option" value="provide-url" <%=option == null || "provide-url".equals(option)? "checked='y'" : ""%>/>
						<label for="choose-parent">Set a New Parent</label>
					</div>
					<div class="weak-color" style="margin-left:1.9em">
						Enter the permalink of the new parent:<br/>
						<input id="url" name="url" size="60" value="<%=Jtp.hideNull(url)%>"/>
					</div>

					<% boolean isDisabled = !isSiteAdmin || currentParent == null || !Jtp.canBeDeletedBy(forum,visitor); %>
					<div class="second-font field-title">
					ChangeParent.jtp	<input type="radio" <%=isDisabled?"disabled":""%> id="merge" name="option" value="merge" <%="merge".equals(option)? "checked='y'" : ""%>/>
						<label for="merge" <%=isDisabled?"class='weak-color'":""%>>Merge into <%=Jtp.parentName(forum)%></label>
						<%=isDisabled? "<span class='disabled important'>/ Not Applicable</span>":""%>
					</div>
					<div class="weak-color" style="margin-left:1.9em">
						Delete this <%=Jtp.viewName(forum).toLowerCase()%> and move its contents to the <%=Jtp.parentName(forum).toLowerCase()%>. <br/>
					</div>

					<% isDisabled = !forum.isRoot() || forum.getChildCount() != 1; %>
					<% Node child = isDisabled? null : forum.getChildren().get(0, 1).get(0); %>
					<% isDisabled = child != null && child.getKind() == Node.Kind.POST? true : isDisabled; %>
					<div class="second-font field-title">
						<input type="radio" <%=isDisabled?"disabled":""%> id="delete-root" name="option" value="delete-root" <%="delete-root".equals(option)? "checked='y'" : ""%>/>
						<label for="delete-root" <%=isDisabled?"class='weak-color'":""%>>Make Child the New Root</label>
						<%=isDisabled? "<span class='disabled important'>/ Not Applicable</span>":""%>
					</div>
					<div class="weak-color" style="margin-left:1.9em">
						Delete this <%=Jtp.viewName(forum).toLowerCase()%> and make <%=child == null? "the single child" : child.getSubjectHtml() %> the new root. <br/>
					</div>

					<% isDisabled = forum.getParent() != null; %>
					<div class="second-font field-title">
						<input type="radio" id="create-parent" name="option" value="create-parent" <%="create-parent".equals(option)? "checked='y'" : ""%> <%=isDisabled?"disabled":""%>/>
						<label <%=isDisabled?"class='weak-color'":""%> for="create-parent">Create a New Parent</label>
						<%=isDisabled? "<span class='disabled important'>/ Not Applicable</span>":""%>
					</div>
					<div class="weak-color" style="margin-left:1.9em">
						<table>
							<tr>
								<td>Name:</td>
								<td><input id="name" <%=isDisabled?"disabled":""%> name="name" size="30" value="<%=Jtp.hideNull(request.getParameter("name"))%>" /></td>
							</tr>
							<tr>
								<td>Type:</td>
								<td>
									<select id="type" name="type">
											<option value="<%=Node.Type.FORUM%>">Forum</option>
											<option value="<%=Node.Type.CATEGORY%>">Category</option>
											<option value="<%=Node.Type.BOARD%>">Board</option>
											<option value="<%=Node.Type.MIXED%>">Mixed</option>
											<option value="<%=Node.Type.GALLERY%>">Gallery</option>
											<option value="<%=Node.Type.BLOG%>">Blog</option>
											<option value="<%=Node.Type.NEWS%>">Newspaper</option>
									</select>
								</td>
							</tr>
						</table>
						<div style="margin: .5em 0">
							Description:<br/>
							<textarea id="description" <%=isDisabled?"disabled":""%> name="description" style="width:30em;height:10em"><%=Jtp.hideNull(request.getParameter("description"))%></textarea>
						</div>
					</div>

					<div style="margin-top:1.4em">
						<input type="submit" name="save" value="Save Changes" /> or <a href="<%=Jtp.path(forum)%>">Cancel</a>
					</div>
				</form>

				<% Shared.footer(request, response); %>
				<% Shared.analytics(request,response); %>
			</body>
		</html>
		<%
	}

	private static String setParent(Node app, String url, HttpServletRequest request, HttpServletResponse response)
		throws IOException, ServletException
	{
		if (url == null || url.trim().length() == 0 || !url.startsWith("http://")) {
			return "You must provide a valid link.";
		} else {
			url = Jtp.noCid(url);
			Node parent = UrlMapperNamespace.getNodeFromUrl(url);
			if (parent == null || parent.getKind()!=Node.Kind.APP || !parent.getSite().equals(app.getSite())) {
				if (Export.isValidExportServer(url)) {
					// Send to export confirmation page
					response.sendRedirect("/catalog/ExportConfirmation.jtp?node="+app.getId()+"&url="+HtmlUtils.urlEncode(url));
					return null;
				} else {
					return "The link you provided is not a valid Nabble application.";
				}
			} else if (parent.getSite().equals(app.getSite()) && parent.getAncestors().contains(app)) {
				return "Circular relationship is not allowed.";
			} else {
				DbDatabase db = app.getSite().getDb();
				db.beginTransaction();
				try {
					Node forumCopy = app.getGoodCopy();
					forumCopy.changeParent(parent);
					forumCopy.update();
					db.commitTransaction();

					forumCopy = forumCopy.getGoodCopy();
					Shared.javascriptRedirect(request, response, Jtp.url(forumCopy), null, true);
					return null;
				} catch(ModelException.NodeLoop e) {
					if (parent.equals(app))
						return "The new parent cannot be the forum itself.";
					else
						return "The new parent cannot be a descendant of the current forum (circular relationship).";
				} catch (ModelException e) {
					logger.error("",e);
					return "You cannot move this forum here because: "+e.getMessage();
				} finally {
					db.endTransaction();
				}
			}
		}
	}

	private static String merge(Node app, User visitor, boolean isSiteAdmin, HttpServletResponse response)
		throws IOException, ServletException
	{
		if (isSiteAdmin || Jtp.canBeDeletedBy(app,visitor)) {
			DbDatabase db = app.getSite().getDb();
			db.beginTransaction();
			try {
				app = app.getGoodCopy();
				Node parent = app.getParent();
				for (Node child : app.getChildren()) {
					child.changeParent(parent);
				}
				app.getGoodCopy().deleteMessageOrNode();
				db.commitTransaction();
				response.sendRedirect(Jtp.path(parent));
				return null;
			} catch (ModelException e) {
				return e.getMessage();
			} finally {
				db.endTransaction();
			}
		} else {
			return "You don't have privileges to delete and merge this sub-forum";
		}
	}

	private static String deleteRoot(Node app, User visitor, HttpServletResponse response)
		throws IOException, ServletException
	{
		if (Jtp.canBeDeletedBy(app,visitor)) {
			DbDatabase db = app.getSite().getDb();
			db.beginTransaction();
			try {
				Site site = app.getSite();
				site.deleteRootNode();
				db.commitTransaction();
				response.sendRedirect(site.getBaseUrl());
				return null;
			} catch (ModelException e) {
				return e.getMessage();
			} finally {
				db.endTransaction();
			}
		} else {
			return "You don't have privileges to make the child a new root";
		}
	}

	private static String createParent(Node app, User user, HttpServletRequest request, HttpServletResponse response)
		throws IOException, ServletException
	{
		DbDatabase db = app.getSite().getDb();
		db.beginTransaction();
		try {
			String name = request.getParameter("name");
			if (name == null || name.trim().length() == 0)
				return "Please enter a valid name";
			String description = request.getParameter("description");
			String type = request.getParameter("type");
			Node parent = user.newRootNode(Node.Kind.APP, name, description, Message.Format.TEXT, app.getSite(),type);
			Jtp.addPinnedChild(parent, app.getGoodCopy());
			db.commitTransaction();
			response.sendRedirect(Jtp.path(parent));
			return null;
		} catch (ModelException e) {
			return e.getMessage();
		} finally {
			db.endTransaction();
		}
	}
}
%>