Mercurial Hosting > nabble
comparison src/nabble/view/web/catalog/ChangeParent.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children | 18cf4872fd7f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:7ecd1a4ef557 |
---|---|
1 | |
2 package nabble.view.web.catalog; | |
3 | |
4 import fschmidt.db.DbDatabase; | |
5 import fschmidt.util.java.HtmlUtils; | |
6 import fschmidt.util.servlet.AuthorizingServlet; | |
7 import nabble.model.Message; | |
8 import nabble.model.ModelException; | |
9 import nabble.model.Node; | |
10 import nabble.model.Person; | |
11 import nabble.model.Site; | |
12 import nabble.model.User; | |
13 import nabble.model.export.Export; | |
14 import nabble.view.lib.Jtp; | |
15 import nabble.view.lib.Permissions; | |
16 import nabble.view.lib.Shared; | |
17 import nabble.view.web.template.UrlMapperNamespace; | |
18 import org.slf4j.Logger; | |
19 import org.slf4j.LoggerFactory; | |
20 | |
21 import javax.servlet.ServletException; | |
22 import javax.servlet.http.HttpServlet; | |
23 import javax.servlet.http.HttpServletRequest; | |
24 import javax.servlet.http.HttpServletResponse; | |
25 import java.io.IOException; | |
26 import java.io.PrintWriter; | |
27 | |
28 | |
29 public class ChangeParent extends HttpServlet implements AuthorizingServlet { | |
30 private static final Logger logger = LoggerFactory.getLogger(ChangeParent.class); | |
31 | |
32 public String getAuthorizationKey(HttpServletRequest request) throws ServletException { | |
33 return Jtp.getReadAuthorizationKey( Jtp.getSiteNotNull(request).getNode(Jtp.getLong(request,"forum")) ); | |
34 } | |
35 | |
36 public boolean authorize(String key,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { | |
37 return Jtp.authorizeForRead(key,request,response); | |
38 } | |
39 | |
40 protected void service(HttpServletRequest request, HttpServletResponse response) | |
41 throws ServletException, IOException | |
42 { | |
43 PrintWriter out = response.getWriter(); | |
44 String forumId = request.getParameter("forum"); | |
45 Node forum = forumId == null? null : Jtp.getSiteNotNull(request).getNode(Long.valueOf(forumId)); | |
46 | |
47 if (forum == null) | |
48 return; | |
49 | |
50 Person visitor = Jtp.getVisitor(request, response); | |
51 boolean isSiteAdmin = visitor instanceof User && Permissions.isInGroup((User) visitor, Permissions.ADMINISTRATORS_GROUP); | |
52 | |
53 boolean allowed = Jtp.canBeRemovedBy(forum,visitor); | |
54 if (!allowed) { | |
55 Jtp.login("Only administrators can proceed in this area.", request, response); | |
56 return; | |
57 } | |
58 | |
59 String errorMsg = null; | |
60 String action = request.getParameter("action"); | |
61 String option = request.getParameter("option"); | |
62 String url = request.getParameter("url"); | |
63 if ("set".equals(action) && "POST".equals(request.getMethod())) { | |
64 if ("provide-url".equals(option)) | |
65 errorMsg = setParent(forum, url, request, response); | |
66 else if ("merge".equals(option)) | |
67 errorMsg = merge(forum, visitor, isSiteAdmin, response); | |
68 else if ("delete-root".equals(option)) | |
69 errorMsg = deleteRoot(forum, visitor, response); | |
70 else if ("create-parent".equals(option)) | |
71 errorMsg = createParent(forum, (User)visitor, request, response); | |
72 if (errorMsg == null) | |
73 return; | |
74 } | |
75 | |
76 Node currentParent = forum.getParent(); | |
77 | |
78 out.print( "\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n<html>\r\n <head>\r\n " ); | |
79 Shared.title(request, response, "Parent Options"); | |
80 out.print( "\r\n <script type=\"text/javascript\">\r\n $(document).ready(function() {\r\n function handleFocus() {\r\n $('#url,#name,#description,#type').attr('disabled','y');\r\n var id = $(':radio').filter('[checked]').attr('id');\r\n if (id == 'choose-parent') {\r\n $('#url').removeAttr('disabled').focus();\r\n } else if (id == 'create-parent') {\r\n $('#name,#description,#type').removeAttr('disabled').focus();\r\n $('#name').focus();\r\n }\r\n };\r\n handleFocus();\r\n $(':radio').click(handleFocus);\r\n });\r\n </script>\r\n <style type=\"text/css\">\r\n div.field-title {\r\n font-weight:bold;\r\n font-size:110%;\r\n padding-bottom:.1em;\r\n margin-top: 1.7em;\r\n }\r\n span.disabled {\r\n font-size:90%;\r\n font-weight:normal;\r\n margin-left:1em\r\n }\r\n </style>\r\n </head>\r\n <body>\r\n " ); | |
81 Shared.minHeader(request,response, forum); | |
82 out.print( "\r\n " ); | |
83 Shared.editHeader(forum.getSubjectHtml(), "Parent Options", out); | |
84 out.print( "\r\n " ); | |
85 Shared.errorMessage(request, response, errorMsg, null); | |
86 out.print( "\r\n <form id=\"parent-form\" method=\"post\" action=\"/catalog/ChangeParent.jtp\" accept-charset=\"UTF-8\">\r\n <input type=\"hidden\" name=\"action\" value=\"set\" />\r\n <input type=\"hidden\" name=\"forum\" value=\"" ); | |
87 out.print( (forum.getId()) ); | |
88 out.print( "\" />\r\n\r\n <div class=\"second-font field-title\">\r\n <input type=\"radio\" id=\"choose-parent\" name=\"option\" value=\"provide-url\" " ); | |
89 out.print( (option == null || "provide-url".equals(option)? "checked='y'" : "") ); | |
90 out.print( "/>\r\n <label for=\"choose-parent\">Set a New Parent</label>\r\n </div>\r\n <div class=\"weak-color\" style=\"margin-left:1.9em\">\r\n Enter the permalink of the new parent:<br/>\r\n <input id=\"url\" name=\"url\" size=\"60\" value=\"" ); | |
91 out.print( (Jtp.hideNull(url)) ); | |
92 out.print( "\"/>\r\n </div>\r\n\r\n " ); | |
93 boolean isDisabled = !isSiteAdmin || currentParent == null || !Jtp.canBeDeletedBy(forum,visitor); | |
94 out.print( "\r\n <div class=\"second-font field-title\">\r\n <input type=\"radio\" " ); | |
95 out.print( (isDisabled?"disabled":"") ); | |
96 out.print( " id=\"merge\" name=\"option\" value=\"merge\" " ); | |
97 out.print( ("merge".equals(option)? "checked='y'" : "") ); | |
98 out.print( "/>\r\n <label for=\"merge\" " ); | |
99 out.print( (isDisabled?"class='weak-color'":"") ); | |
100 out.print( ">Merge into " ); | |
101 out.print( (Jtp.parentName(forum)) ); | |
102 out.print( "</label>\r\n " ); | |
103 out.print( (isDisabled? "<span class='disabled important'>/ Not Applicable</span>":"") ); | |
104 out.print( "\r\n </div>\r\n <div class=\"weak-color\" style=\"margin-left:1.9em\">\r\n Delete this " ); | |
105 out.print( (Jtp.viewName(forum).toLowerCase()) ); | |
106 out.print( " and move its contents to the " ); | |
107 out.print( (Jtp.parentName(forum).toLowerCase()) ); | |
108 out.print( ". <br/>\r\n </div>\r\n\r\n " ); | |
109 isDisabled = !forum.isRoot() || forum.getChildCount() != 1; | |
110 out.print( "\r\n " ); | |
111 Node child = isDisabled? null : forum.getChildren().get(0, 1).get(0); | |
112 out.print( "\r\n " ); | |
113 isDisabled = child != null && child.getKind() == Node.Kind.POST? true : isDisabled; | |
114 out.print( "\r\n <div class=\"second-font field-title\">\r\n <input type=\"radio\" " ); | |
115 out.print( (isDisabled?"disabled":"") ); | |
116 out.print( " id=\"delete-root\" name=\"option\" value=\"delete-root\" " ); | |
117 out.print( ("delete-root".equals(option)? "checked='y'" : "") ); | |
118 out.print( "/>\r\n <label for=\"delete-root\" " ); | |
119 out.print( (isDisabled?"class='weak-color'":"") ); | |
120 out.print( ">Make Child the New Root</label>\r\n " ); | |
121 out.print( (isDisabled? "<span class='disabled important'>/ Not Applicable</span>":"") ); | |
122 out.print( "\r\n </div>\r\n <div class=\"weak-color\" style=\"margin-left:1.9em\">\r\n Delete this " ); | |
123 out.print( (Jtp.viewName(forum).toLowerCase()) ); | |
124 out.print( " and make " ); | |
125 out.print( (child == null? "the single child" : child.getSubjectHtml() ) ); | |
126 out.print( " the new root. <br/>\r\n </div>\r\n\r\n " ); | |
127 isDisabled = forum.getParent() != null; | |
128 out.print( "\r\n <div class=\"second-font field-title\">\r\n <input type=\"radio\" id=\"create-parent\" name=\"option\" value=\"create-parent\" " ); | |
129 out.print( ("create-parent".equals(option)? "checked='y'" : "") ); | |
130 out.print( " " ); | |
131 out.print( (isDisabled?"disabled":"") ); | |
132 out.print( "/>\r\n <label " ); | |
133 out.print( (isDisabled?"class='weak-color'":"") ); | |
134 out.print( " for=\"create-parent\">Create a New Parent</label>\r\n " ); | |
135 out.print( (isDisabled? "<span class='disabled important'>/ Not Applicable</span>":"") ); | |
136 out.print( "\r\n </div>\r\n <div class=\"weak-color\" style=\"margin-left:1.9em\">\r\n <table>\r\n <tr>\r\n <td>Name:</td>\r\n <td><input id=\"name\" " ); | |
137 out.print( (isDisabled?"disabled":"") ); | |
138 out.print( " name=\"name\" size=\"30\" value=\"" ); | |
139 out.print( (Jtp.hideNull(request.getParameter("name"))) ); | |
140 out.print( "\" /></td>\r\n </tr>\r\n <tr>\r\n <td>Type:</td>\r\n <td>\r\n <select id=\"type\" name=\"type\">\r\n <option value=\"" ); | |
141 out.print( (Node.Type.FORUM) ); | |
142 out.print( "\">Forum</option>\r\n <option value=\"" ); | |
143 out.print( (Node.Type.CATEGORY) ); | |
144 out.print( "\">Category</option>\r\n <option value=\"" ); | |
145 out.print( (Node.Type.BOARD) ); | |
146 out.print( "\">Board</option>\r\n <option value=\"" ); | |
147 out.print( (Node.Type.MIXED) ); | |
148 out.print( "\">Mixed</option>\r\n <option value=\"" ); | |
149 out.print( (Node.Type.GALLERY) ); | |
150 out.print( "\">Gallery</option>\r\n <option value=\"" ); | |
151 out.print( (Node.Type.BLOG) ); | |
152 out.print( "\">Blog</option>\r\n <option value=\"" ); | |
153 out.print( (Node.Type.NEWS) ); | |
154 out.print( "\">Newspaper</option>\r\n </select>\r\n </td>\r\n </tr>\r\n </table>\r\n <div style=\"margin: .5em 0\">\r\n Description:<br/>\r\n <textarea id=\"description\" " ); | |
155 out.print( (isDisabled?"disabled":"") ); | |
156 out.print( " name=\"description\" style=\"width:30em;height:10em\">" ); | |
157 out.print( (Jtp.hideNull(request.getParameter("description"))) ); | |
158 out.print( "</textarea>\r\n </div>\r\n </div>\r\n\r\n <div style=\"margin-top:1.4em\">\r\n <input type=\"submit\" name=\"save\" value=\"Save Changes\" /> or <a href=\"" ); | |
159 out.print( (Jtp.path(forum)) ); | |
160 out.print( "\">Cancel</a>\r\n </div>\r\n </form>\r\n\r\n " ); | |
161 Shared.footer(request, response); | |
162 out.print( "\r\n " ); | |
163 Shared.analytics(request,response); | |
164 out.print( "\r\n </body>\r\n</html>\r\n" ); | |
165 | |
166 } | |
167 | |
168 private static String setParent(Node app, String url, HttpServletRequest request, HttpServletResponse response) | |
169 throws IOException, ServletException | |
170 { | |
171 if (url == null || url.trim().length() == 0 || !url.startsWith("http://")) { | |
172 return "You must provide a valid link."; | |
173 } else { | |
174 url = Jtp.noCid(url); | |
175 Node parent = UrlMapperNamespace.getNodeFromUrl(url); | |
176 if (parent == null || parent.getKind()!=Node.Kind.APP || !parent.getSite().equals(app.getSite())) { | |
177 if (Export.isValidExportServer(url)) { | |
178 // Send to export confirmation page | |
179 response.sendRedirect("/catalog/ExportConfirmation.jtp?node="+app.getId()+"&url="+HtmlUtils.urlEncode(url)); | |
180 return null; | |
181 } else { | |
182 return "The link you provided is not a valid Nabble application."; | |
183 } | |
184 } else if (parent.getSite().equals(app.getSite()) && parent.getAncestors().contains(app)) { | |
185 return "Circular relationship is not allowed."; | |
186 } else { | |
187 DbDatabase db = app.getSite().getDb(); | |
188 db.beginTransaction(); | |
189 try { | |
190 Node forumCopy = app.getGoodCopy(); | |
191 forumCopy.changeParent(parent); | |
192 forumCopy.update(); | |
193 db.commitTransaction(); | |
194 | |
195 forumCopy = forumCopy.getGoodCopy(); | |
196 Shared.javascriptRedirect(request, response, Jtp.url(forumCopy), null, true); | |
197 return null; | |
198 } catch(ModelException.NodeLoop e) { | |
199 if (parent.equals(app)) | |
200 return "The new parent cannot be the forum itself."; | |
201 else | |
202 return "The new parent cannot be a descendant of the current forum (circular relationship)."; | |
203 } catch (ModelException e) { | |
204 logger.error("",e); | |
205 return "You cannot move this forum here because: "+e.getMessage(); | |
206 } finally { | |
207 db.endTransaction(); | |
208 } | |
209 } | |
210 } | |
211 } | |
212 | |
213 private static String merge(Node app, Person visitor, boolean isSiteAdmin, HttpServletResponse response) | |
214 throws IOException, ServletException | |
215 { | |
216 if (isSiteAdmin || Jtp.canBeDeletedBy(app,visitor)) { | |
217 DbDatabase db = app.getSite().getDb(); | |
218 db.beginTransaction(); | |
219 try { | |
220 app = app.getGoodCopy(); | |
221 Node parent = app.getParent(); | |
222 for (Node child : app.getChildren()) { | |
223 child.changeParent(parent); | |
224 } | |
225 app.getGoodCopy().deleteMessageOrNode(); | |
226 db.commitTransaction(); | |
227 response.sendRedirect(Jtp.path(parent)); | |
228 return null; | |
229 } catch (ModelException e) { | |
230 return e.getMessage(); | |
231 } finally { | |
232 db.endTransaction(); | |
233 } | |
234 } else { | |
235 return "You don't have privileges to delete and merge this sub-forum"; | |
236 } | |
237 } | |
238 | |
239 private static String deleteRoot(Node app, Person visitor, HttpServletResponse response) | |
240 throws IOException, ServletException | |
241 { | |
242 if (Jtp.canBeDeletedBy(app,visitor)) { | |
243 DbDatabase db = app.getSite().getDb(); | |
244 db.beginTransaction(); | |
245 try { | |
246 Site site = app.getSite(); | |
247 site.deleteRootNode(); | |
248 db.commitTransaction(); | |
249 response.sendRedirect(site.getBaseUrl()); | |
250 return null; | |
251 } catch (ModelException e) { | |
252 return e.getMessage(); | |
253 } finally { | |
254 db.endTransaction(); | |
255 } | |
256 } else { | |
257 return "You don't have privileges to make the child a new root"; | |
258 } | |
259 } | |
260 | |
261 private static String createParent(Node app, User user, HttpServletRequest request, HttpServletResponse response) | |
262 throws IOException, ServletException | |
263 { | |
264 DbDatabase db = app.getSite().getDb(); | |
265 db.beginTransaction(); | |
266 try { | |
267 String name = request.getParameter("name"); | |
268 if (name == null || name.trim().length() == 0) | |
269 return "Please enter a valid name"; | |
270 String description = request.getParameter("description"); | |
271 String type = request.getParameter("type"); | |
272 Node parent = user.newRootNode(Node.Kind.APP, name, description, Message.Format.TEXT, app.getSite(),type); | |
273 Jtp.addPinnedChild(parent, app.getGoodCopy()); | |
274 db.commitTransaction(); | |
275 response.sendRedirect(Jtp.path(parent)); | |
276 return null; | |
277 } catch (ModelException e) { | |
278 return e.getMessage(); | |
279 } finally { | |
280 db.endTransaction(); | |
281 } | |
282 } | |
283 } | |
284 |