View Javadoc

1   /**
2    * This file Copyright (c) 2003-2013 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.admininterface.dialogs;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.gui.control.Button;
38  import info.magnolia.cms.gui.control.Edit;
39  import info.magnolia.cms.gui.control.Hidden;
40  import info.magnolia.cms.gui.control.Select;
41  import info.magnolia.cms.gui.dialog.DialogBox;
42  import info.magnolia.cms.gui.dialog.DialogButton;
43  import info.magnolia.cms.gui.dialog.DialogFactory;
44  import info.magnolia.cms.gui.misc.CssConstants;
45  import info.magnolia.cms.i18n.Messages;
46  import info.magnolia.cms.i18n.MessagesManager;
47  import info.magnolia.cms.util.ContentUtil;
48  import info.magnolia.module.admininterface.AdminInterfaceModule;
49  import info.magnolia.module.admininterface.config.AclTypeConfiguration;
50  import info.magnolia.module.admininterface.config.PermissionConfiguration;
51  import info.magnolia.module.admininterface.config.RepositoryConfiguration;
52  import info.magnolia.module.admininterface.config.SecurityConfiguration;
53  import info.magnolia.repository.RepositoryConstants;
54  
55  import java.io.IOException;
56  import java.io.PrintWriter;
57  import java.io.Writer;
58  import java.util.Iterator;
59  
60  import javax.jcr.RepositoryException;
61  import javax.servlet.http.HttpServletRequest;
62  import javax.servlet.http.HttpServletResponse;
63  
64  import org.apache.commons.collections.map.ListOrderedMap;
65  import org.apache.commons.lang.StringUtils;
66  
67  
68  /**
69   * Builds a dialog control for ACLs.
70   * @version $Id:RolesACLPage.java 2516 2006-03-31 13:08:03Z philipp $
71   */
72  public class ACLSDialogControl extends DialogBox {
73  
74      private static final String CSS_ACL_DIV = "aclDynamicTable";
75  
76      private SecurityConfiguration securityConf = AdminInterfaceModule.getInstance().getSecurityConfiguration();
77  
78      private static String getHtmlRowInner(String dynamicTable, RepositoryConfiguration repoConf) {
79          boolean small = true;
80          Messages msgs = MessagesManager.getMessages();
81  
82          Select accessRight = new Select();
83          accessRight.setSaveInfo(false);
84          accessRight.setName("'+prefix+'AccessRight");
85          accessRight.setCssClass("mgnlDialogControlSelect");
86  
87          for (Iterator<PermissionConfiguration> iter = repoConf.getPermissions().iterator(); iter.hasNext();) {
88              PermissionConfiguration permission = iter.next();
89              accessRight.setOptions(escapeJs(permission.getI18nLabel()), Long.toString(permission.getValue()));
90          }
91  
92          accessRight.setValue("' + object.accessRight + '");
93  
94          Select accessType = new Select();
95          accessType.setSaveInfo(false);
96          accessType.setName("'+prefix+'AccessType");
97          accessType.setCssClass("mgnlDialogControlSelect");
98  
99          for (Iterator<AclTypeConfiguration> iter = repoConf.getAclTypes().iterator(); iter.hasNext();) {
100             AclTypeConfiguration patternType = iter.next();
101             accessType.setOptions(escapeJs(patternType.getI18nLabel()), String.valueOf(patternType.getType()));
102         }
103 
104         accessType.setValue("' + object.accessType + '");
105 
106         Edit path = new Edit();
107         path.setSaveInfo(false);
108         path.setName("'+prefix+'Path");
109         path.setValue("'+object.path+'");
110         path.setCssClass(CssConstants.CSSCLASS_EDIT);
111         path.setCssStyles("width", "100%");
112 
113         Button choose = null;
114         if(repoConf.isChooseButton()){
115             choose = new Button();
116             choose.setLabel(escapeJs(msgs.get("buttons.choose")));
117             choose.setOnclick("aclChoose(\\''+prefix+'\\',\\'" + repoConf.getName() + "\\');");
118             choose.setSmall(small);
119         }
120 
121         Button delete = new Button();
122         delete.setLabel(escapeJs(msgs.get("buttons.delete")));
123         delete.setOnclick(dynamicTable + ".del('+index+');");
124         delete.setSmall(small);
125 
126         StringBuilder html = new StringBuilder();
127         // set as table since ie/win does not support setting of innerHTML of a
128         // tr
129         html.append("<table cellpadding=\"0\" cellspacing=\"0\" width=\"100%\"><tr>");
130         html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(accessRight.getHtml()).append("</td>");
131         html.append("<td width=\"1\" class=\"mgnlDialogBoxInput\"></td>");
132 
133         // do we add the type selection dropdown?
134         if(!repoConf.getAclTypes().isEmpty()){
135             html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(accessType.getHtml()).append("</td>");
136             html.append("<td width=\"1\"></td>");
137         }
138         else {
139             html.append("<input type=\"hidden\" id=\"' + prefix + 'AccessType\" name=\"' + prefix + 'AccessType\" value=\"sub\"/>");
140         }
141 
142         html.append("<td width=\"100%\"class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(path.getHtml()).append("</td>");
143         html.append("<td width=\"1\"></td>");
144 
145         if (choose != null) {
146             html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(choose.getHtml()).append("</td>");
147             html.append("<td width=\"1\"></td>");
148         }
149 
150         html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(delete.getHtml()).append("</td>");
151         html.append("</tr></table>");
152 
153         return html.toString();
154     }
155 
156     @Override
157     public void drawHtml(Writer w) throws IOException {
158         PrintWriter out = (PrintWriter) w;
159         this.drawHtmlPre(out);
160         renderACLS(out);
161         this.drawHtmlPost(out);
162 
163     }
164 
165     protected void renderACLS(PrintWriter out) throws IOException {
166         Messages msgs = MessagesManager.getMessages();
167         Content role = getStorageNode();
168         HttpServletRequest request = this.getRequest();
169         HttpServletResponse response = this.getResponse();
170 
171         // select the repository
172         Select repositorySelect = getRepositorySelect();
173 
174         out.print(repositorySelect.getHtml());
175         out.print("<p><p/>");
176 
177         // process with the real existing repositories
178         for (Iterator<RepositoryConfiguration> iter = securityConf.getVisibleRepositories().iterator(); iter.hasNext();) {
179             RepositoryConfiguration repositoryConf = iter.next();
180             try {
181                 writeRepositoryTable(request, response, msgs, out, role, repositoryConf);
182             }
183             catch (RepositoryException e) {
184                 throw new RuntimeException("can't list ", e);
185             }
186         }
187 
188         // out.print("<p>&nbsp;<p>&nbsp;<p>&nbsp;<input type=\"button\" onclick=\"aclChangeRepository('website')\">");
189         out.println("<script type=\"text/javascript\">aclChangeRepository('website');</script>");
190     }
191 
192     /**
193      * @param request
194      * @param out
195      * @param role
196      * @throws RepositoryException
197      * @throws IOException
198      */
199     protected void writeRepositoryTable(HttpServletRequest request,  HttpServletResponse response, Messages msgs,
200         PrintWriter out, Content role, RepositoryConfiguration repoConf) throws RepositoryException, IOException {
201         String tableName = "acl" + repoConf.getName() + "Table";
202         String dynamicTableName = "acl" + repoConf.getName() + "DynamicTable";
203         String hiddenFieldName = "acl" + repoConf.getName() + "List";
204 
205         out.println("<div id=\"acl" + repoConf.getName() + "Div\" class=\"" + CSS_ACL_DIV + "\">"); //$NON-NLS-3$
206         out.println(new Hidden(hiddenFieldName, StringUtils.EMPTY, false).getHtml());
207 
208         // the table
209         out.println("<table id=\""
210             + tableName
211             + "\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td></td></tr></table>");
212 
213         // add button
214         out.println("<table width=\"100%\">");
215         DialogButton add = DialogFactory.getDialogButtonInstance(request, response, null, null);
216         add.setBoxType(DialogBox.BOXTYPE_1COL);
217         add.setConfig("buttonLabel", msgs.get("buttons.add"));
218         add.setConfig("onclick", dynamicTableName + ".addNew();");
219         add.drawHtml(out);
220         out.println("</table>");
221 
222         out.println("</div>");
223 
224         out.println("<script type=\"text/javascript\">");
225         // register the repository
226         out.println("aclRepositories[aclRepositories.length]= '" + repoConf.getName() + "';");
227 
228         // make renderer function
229         out.println("function acl" + repoConf.getName() + "RenderFunction(cell, prefix, index, object)");
230         out.println("{");
231 
232         // get some debug informations
233         out.println("mgnlDebug('acl" + repoConf.getName() + "RenderFunction: prefix = ' + prefix, 'acl', object)");
234         out.println("cell.innerHTML= '" + getHtmlRowInner(dynamicTableName, repoConf) + "';\n");
235         out.println("document.getElementById(prefix + 'AccessType').value = object.accessType;\n");
236         out.println("document.getElementById(prefix + 'AccessRight').value = object.accessRight;\n");
237 
238         out.println("}");
239 
240         // create the dynamicTable
241         out.println(dynamicTableName + " = new MgnlDynamicTable('"
242             + tableName
243             + "',document.getElementById('mgnlFormMain')."
244             + hiddenFieldName
245             + ", aclGetNewPermissionObject, aclGetPermissionObject, acl"
246             + repoConf.getName()
247             + "RenderFunction, null);");
248 
249         // add existing acls to table (by js, so the same mechanism as at
250         // adding rows can be used)
251         addExistingAclToTable(out, role, dynamicTableName, repoConf);
252 
253         out.println("</script>");
254     }
255 
256     /**
257      * @param out
258      * @param role
259      */
260     private void addExistingAclToTable(PrintWriter out, Content role, String dynamicTableName,
261         RepositoryConfiguration repoConf) {
262         // keeps acls per path
263         ACLS acls = new ACLS();
264 
265         Content aclsNode = ContentUtil.getContent(role, "acl_" + repoConf.getName());
266         if (aclsNode == null || aclsNode.getChildren().size() == 0) {
267             out.println(dynamicTableName + ".addNew();");
268             return;
269         }
270 
271         Iterator it = aclsNode.getChildren().iterator();
272         while (it.hasNext()) {
273             Content c = (Content) it.next();
274             String path = c.getNodeData("path").getString();
275             String accessRight = c.getNodeData("permissions").getString();
276             acls.register(path, Integer.valueOf(accessRight).intValue(), repoConf);
277         }
278 
279         for (Iterator<ACL> iter = acls.values().iterator(); iter.hasNext();) {
280             ACL acl = iter.next();
281             out.println(dynamicTableName + ".add({accessRight:"
282                 + acl.accessRight
283                 + ",accessType:'"
284                 + acl.type
285                 + "',path:'"
286                 + acl.path
287                 + "'});");
288         }
289     }
290 
291     private Select getRepositorySelect() {
292         Select repositorySelect = new Select();
293         repositorySelect.setName("aclRepository");
294         repositorySelect.setCssClass("mgnlDialogControlSelect");
295         repositorySelect.setEvent("onchange", "aclChangeRepository(this.value)");
296         repositorySelect.setSaveInfo(false);
297         repositorySelect.setValue(RepositoryConstants.WEBSITE);
298 
299         for (Iterator<RepositoryConfiguration> iter = securityConf.getVisibleRepositories().iterator(); iter.hasNext();) {
300             RepositoryConfiguration repoConf = iter.next();
301             repositorySelect.setOptions(repoConf.getI18nLabel(), repoConf.getName());
302         }
303         return repositorySelect;
304     }
305 
306     private static String escapeJs(String value) {
307         return StringUtils.replace(value, "'", "\\'");
308     }
309 
310     /**
311      * A concrete gui acl
312      * @author Philipp Bracher
313      * @version $Revision$ ($Author$)
314      */
315     protected class ACL {
316 
317         int type = 0;
318 
319         String path;
320 
321         int accessRight;
322 
323         void registerEntry(String path) {
324             if ("/*".equals(path)) {
325                 type = AclTypeConfiguration.TYPE_ALL;
326             }
327             else if (path.endsWith("/*")) {
328                 type = type | AclTypeConfiguration.TYPE_SUBS;
329             }
330             else {
331                 type = type | AclTypeConfiguration.TYPE_THIS;
332             }
333         }
334     }
335 
336     /**
337      * Used to create the gui values out of the entries in the repository
338      * @version $Revision$ ($Author$)
339      */
340     protected class ACLS extends ListOrderedMap {
341 
342         /**
343          * Register an entry
344          * @param path the not cleaned path
345          * @param accessRight the access right
346          */
347         void register(String path, int accessRight, RepositoryConfiguration repoConf) {
348             String cleanPath = repoConf.toViewPattern(path);
349 
350             String key = cleanPath + ":" + accessRight;
351             if (!this.containsKey(key)) {
352                 ACL acl = new ACL();
353                 acl.path = cleanPath;
354                 acl.accessRight = accessRight;
355                 this.put(key, acl);
356             }
357             ((ACL) this.get(key)).registerEntry(path);
358         }
359     }
360 
361 }