1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.security.app.dialog.field;
35
36 import info.magnolia.cms.security.Permission;
37 import info.magnolia.i18nsystem.SimpleTranslator;
38 import info.magnolia.jcr.RuntimeRepositoryException;
39 import info.magnolia.jcr.util.NodeUtil;
40 import info.magnolia.objectfactory.ComponentProvider;
41 import info.magnolia.objectfactory.Components;
42 import info.magnolia.ui.api.app.ChooseDialogCallback;
43 import info.magnolia.ui.api.context.UiContext;
44 import info.magnolia.ui.contentapp.choosedialog.ChooseDialogComponentProviderUtil;
45 import info.magnolia.ui.contentapp.field.WorkbenchFieldDefinition;
46 import info.magnolia.ui.dialog.choosedialog.ChooseDialogPresenter;
47 import info.magnolia.ui.dialog.choosedialog.ChooseDialogView;
48 import info.magnolia.ui.dialog.definition.ConfiguredChooseDialogDefinition;
49 import info.magnolia.ui.vaadin.integration.contentconnector.ConfiguredJcrContentConnectorDefinition;
50 import info.magnolia.ui.vaadin.integration.contentconnector.ConfiguredNodeTypeDefinition;
51 import info.magnolia.ui.vaadin.integration.contentconnector.NodeTypeDefinition;
52 import info.magnolia.ui.vaadin.integration.jcr.AbstractJcrNodeAdapter;
53 import info.magnolia.ui.vaadin.integration.jcr.DefaultProperty;
54 import info.magnolia.ui.vaadin.integration.jcr.DefaultPropertyUtil;
55 import info.magnolia.ui.vaadin.integration.jcr.JcrItemId;
56 import info.magnolia.ui.vaadin.integration.jcr.JcrItemUtil;
57 import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
58 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
59 import info.magnolia.ui.vaadin.integration.jcr.ModelConstants;
60 import info.magnolia.ui.workbench.column.definition.ColumnDefinition;
61 import info.magnolia.ui.workbench.column.definition.PropertyColumnDefinition;
62 import info.magnolia.ui.workbench.definition.ConfiguredWorkbenchDefinition;
63 import info.magnolia.ui.workbench.definition.ContentPresenterDefinition;
64 import info.magnolia.ui.workbench.definition.WorkbenchDefinition;
65 import info.magnolia.ui.workbench.tree.TreePresenterDefinition;
66
67 import java.util.ArrayList;
68 import java.util.HashSet;
69 import java.util.List;
70 import java.util.Set;
71
72 import javax.inject.Inject;
73 import javax.jcr.Node;
74 import javax.jcr.RepositoryException;
75
76 import org.apache.commons.lang3.StringUtils;
77 import org.apache.jackrabbit.JcrConstants;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 import com.vaadin.data.Item;
82 import com.vaadin.data.Property;
83 import com.vaadin.ui.AbstractOrderedLayout;
84 import com.vaadin.ui.Button;
85 import com.vaadin.ui.Component;
86 import com.vaadin.ui.CustomField;
87 import com.vaadin.ui.Field;
88 import com.vaadin.ui.HorizontalLayout;
89 import com.vaadin.ui.Label;
90 import com.vaadin.ui.NativeSelect;
91 import com.vaadin.ui.TextField;
92 import com.vaadin.ui.VerticalLayout;
93
94
95
96
97
98
99
100
101
102 public class WorkspaceAccessFieldFactory<D extends WorkspaceAccessFieldDefinition> extends AbstractAccessFieldFactory<D> {
103
104 private static final Logger log = LoggerFactory.getLogger(WorkspaceAccessFieldFactory.class);
105
106 public static final String INTERMEDIARY_FORMAT_PROPERTY_NAME = "__intermediary_format";
107 public static final String ACCESS_TYPE_PROPERTY_NAME = "accessType";
108
109 private final UiContext uiContext;
110 private final SimpleTranslator i18n;
111 private final ComponentProvider componentProvider;
112 private ChooseDialogPresenter workbenchChooseDialogPresenter;
113
114 @Inject
115 public WorkspaceAccessFieldFactory(D definition, Item relatedFieldItem, UiContext uiContext, ChooseDialogPresenter workbenchChooseDialogPresenter, SimpleTranslator i18n, ComponentProvider componentProvider) {
116 super(definition, relatedFieldItem);
117 this.uiContext = uiContext;
118 this.workbenchChooseDialogPresenter = workbenchChooseDialogPresenter;
119 this.i18n = i18n;
120 this.componentProvider = componentProvider;
121 }
122
123
124
125
126 @Deprecated
127 public WorkspaceAccessFieldFactory(D definition, Item relatedFieldItem, UiContext uiContext, ChooseDialogPresenter workbenchChooseDialogPresenter, SimpleTranslator i18n) {
128 this(definition, relatedFieldItem, uiContext, workbenchChooseDialogPresenter, i18n, Components.getComponentProvider());
129 }
130
131 @Override
132 protected Field<Object> createFieldComponent() {
133
134 final String aclName = "acl_" + getFieldDefinition().getWorkspace();
135
136 final VerticalLayout layout = new VerticalLayout();
137 layout.setSpacing(true);
138
139 try {
140
141 final JcrNodeAdapter roleItem = (JcrNodeAdapter) item;
142
143 final VerticalLayout aclLayout = new VerticalLayout();
144
145 final Label emptyLabel = new Label(i18n.translate("security.workspace.field.noAccess"));
146
147
148 if (!(roleItem instanceof JcrNewNodeAdapter)) {
149 Node roleNode = roleItem.getJcrItem();
150 if (roleNode.hasNode(aclName)) {
151
152 final Node aclNode = roleNode.getNode(aclName);
153
154 AccessControlList acl = new AccessControlList();
155 acl.readEntries(aclNode);
156
157 AbstractJcrNodeAdapter aclItem = new JcrNodeAdapter(aclNode);
158 roleItem.addChild(aclItem);
159
160 aclItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
161
162 final Set<AccessControlList.Entry> uniqueEntries = new HashSet<AccessControlList.Entry>();
163 for (final Node aclEntryNode : NodeUtil.getNodes(aclNode)) {
164 AccessControlList.Entry entry = acl.getEntryByNode(aclEntryNode);
165 if (uniqueEntries.contains(entry)) {
166 continue;
167 }
168
169 uniqueEntries.add(entry);
170 long permissions = entry.getPermissions();
171 long accessType = entry.getAccessType();
172 String path = entry.getPath();
173
174 JcrNodeAdapter entryItem = new JcrNodeAdapter(aclEntryNode);
175 entryItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
176 final Property<Long> permissionsProperty = DefaultPropertyUtil.newDefaultProperty(Long.class, null);
177 entryItem.addItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME, permissionsProperty);
178 final Property<Long> accessProperty = DefaultPropertyUtil.newDefaultProperty(Long.class, null);
179 entryItem.addItemProperty(ACCESS_TYPE_PROPERTY_NAME, accessProperty);
180 final Property<String> pathProperty = DefaultPropertyUtil.newDefaultProperty(String.class, null);
181 entryItem.addItemProperty(AccessControlList.PATH_PROPERTY_NAME, pathProperty);
182
183 permissionsProperty.setValue(permissions);
184 accessProperty.setValue(accessType);
185 pathProperty.setValue(path);
186
187 aclItem.addChild(entryItem);
188
189 Component ruleRow = createRuleRow(aclLayout, entryItem, emptyLabel);
190 aclLayout.addComponent(ruleRow);
191 }
192 }
193 }
194
195 if (aclLayout.getComponentCount() == 0) {
196 aclLayout.addComponent(emptyLabel);
197 }
198
199 final HorizontalLayout buttons = new HorizontalLayout();
200 final Button addButton = new Button(i18n.translate("security.workspace.field.addButton"));
201 addButton.addClickListener(new Button.ClickListener() {
202
203 @Override
204 public void buttonClick(Button.ClickEvent event) {
205 try {
206
207 AbstractJcrNodeAdapter aclItem = getOrAddAclItem(roleItem, aclName);
208 if (aclItem.getItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME) == null) {
209 aclItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
210 }
211
212 JcrNodeAdapter entryItem = addAclEntryItem(aclItem);
213 entryItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
214 entryItem.addItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, Permission.ALL));
215 entryItem.addItemProperty(ACCESS_TYPE_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN));
216 entryItem.addItemProperty(AccessControlList.PATH_PROPERTY_NAME, new DefaultProperty<String>(String.class, ""));
217
218 Component ruleRow = createRuleRow(aclLayout, entryItem, emptyLabel);
219 aclLayout.removeComponent(emptyLabel);
220 aclLayout.addComponent(ruleRow, aclLayout.getComponentCount() - 1);
221 } catch (RepositoryException e) {
222 throw new RuntimeRepositoryException(e);
223 }
224 }
225 });
226 buttons.addComponent(addButton);
227 aclLayout.addComponent(buttons);
228
229 layout.addComponent(aclLayout);
230
231 } catch (RepositoryException e) {
232 throw new RuntimeRepositoryException(e);
233 }
234
235 return new CustomField<Object>() {
236
237 @Override
238 protected Component initContent() {
239 return layout;
240 }
241
242 @Override
243 public Class<?> getType() {
244 return Object.class;
245 }
246 };
247 }
248
249 protected Component createRuleRow(final AbstractOrderedLayout parentContainer, final AbstractJcrNodeAdapter ruleItem, final Label emptyLabel) {
250
251 final HorizontalLayout ruleLayout = new HorizontalLayout();
252 ruleLayout.setSpacing(true);
253 ruleLayout.setWidth("100%");
254
255 NativeSelect accessRights = new NativeSelect();
256 accessRights.setNullSelectionAllowed(false);
257 accessRights.setImmediate(true);
258 accessRights.setInvalidAllowed(false);
259 accessRights.setNewItemsAllowed(false);
260 accessRights.addItem(Permission.ALL);
261 accessRights.setItemCaption(Permission.ALL, i18n.translate("security.workspace.field.readWrite"));
262 accessRights.addItem(Permission.READ);
263 accessRights.setItemCaption(Permission.READ, i18n.translate("security.workspace.field.readOnly"));
264 accessRights.addItem(Permission.NONE);
265 accessRights.setItemCaption(Permission.NONE, i18n.translate("security.workspace.field.denyAccess"));
266 accessRights.setPropertyDataSource(ruleItem.getItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME));
267 ruleLayout.addComponent(accessRights);
268
269 NativeSelect accessType = new NativeSelect();
270 accessType.setNullSelectionAllowed(false);
271 accessType.setImmediate(true);
272 accessType.setInvalidAllowed(false);
273 accessType.setNewItemsAllowed(false);
274 accessType.setWidth("150px");
275 accessType.addItem(AccessControlList.ACCESS_TYPE_NODE);
276 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_NODE, i18n.translate("security.workspace.field.selected"));
277 accessType.addItem(AccessControlList.ACCESS_TYPE_CHILDREN);
278 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_CHILDREN, i18n.translate("security.workspace.field.subnodes"));
279 accessType.addItem(AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN);
280 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN, i18n.translate("security.workspace.field.selectedSubnodes"));
281 Property accessTypeProperty = ruleItem.getItemProperty(ACCESS_TYPE_PROPERTY_NAME);
282 accessType.setPropertyDataSource(accessTypeProperty);
283 ruleLayout.addComponent(accessType);
284
285 final TextField path = new TextField();
286 path.setWidth("100%");
287 path.setPropertyDataSource(ruleItem.getItemProperty(AccessControlList.PATH_PROPERTY_NAME));
288 ruleLayout.addComponent(path);
289 ruleLayout.setExpandRatio(path, 1.0f);
290
291 Button chooseButton = new Button(i18n.translate("security.workspace.field.choose"));
292 chooseButton.addClickListener(new Button.ClickListener() {
293
294 @Override
295 public void buttonClick(Button.ClickEvent event) {
296 openChooseDialog(path);
297 }
298 });
299 ruleLayout.addComponent(chooseButton);
300
301 Button deleteButton = new Button();
302 deleteButton.setHtmlContentAllowed(true);
303 deleteButton.setCaption("<span class=\"" + "icon-trash" + "\"></span>");
304 deleteButton.addStyleName("inline");
305 deleteButton.setDescription(i18n.translate("security.workspace.field.delete"));
306 deleteButton.addClickListener(new Button.ClickListener() {
307
308 @Override
309 public void buttonClick(Button.ClickEvent event) {
310 parentContainer.removeComponent(ruleLayout);
311 ruleItem.getParent().removeChild(ruleItem);
312 if (parentContainer.getComponentCount() == 1) {
313 parentContainer.addComponent(emptyLabel, 0);
314 }
315 }
316 });
317 ruleLayout.addComponent(deleteButton);
318
319 return ruleLayout;
320 }
321
322 protected void openChooseDialog(final TextField textField) {
323 final ConfiguredChooseDialogDefinition def = new ConfiguredChooseDialogDefinition();
324 final ConfiguredJcrContentConnectorDefinition contentConnectorDefinition = new ConfiguredJcrContentConnectorDefinition();
325 contentConnectorDefinition.setWorkspace(getFieldDefinition().getWorkspace());
326 contentConnectorDefinition.setRootPath("/");
327 contentConnectorDefinition.setDefaultOrder(ModelConstants.JCR_NAME);
328
329 contentConnectorDefinition.setNodeTypes(resolveNodeTypes());
330 def.setContentConnector(contentConnectorDefinition);
331
332 final WorkbenchDefinition wbDef = resolveWorkbenchDefinition();
333 final WorkbenchFieldDefinition fieldDef = new WorkbenchFieldDefinition();
334 fieldDef.setWorkbench(wbDef);
335 def.setField(fieldDef);
336
337
338 ComponentProvider chooseDialogComponentProvider = ChooseDialogComponentProviderUtil.createChooseDialogComponentProvider(def, componentProvider);
339 workbenchChooseDialogPresenter = chooseDialogComponentProvider.newInstance(def.getPresenterClass(), chooseDialogComponentProvider);
340
341
342
343 ChooseDialogView chooseDialogView = workbenchChooseDialogPresenter.start(new ChooseDialogCallback() {
344 @Override
345 public void onItemChosen(String actionName, Object value) {
346 try {
347 if (value instanceof JcrItemId) {
348 JcrItemId jcrItemId = (JcrItemId) value;
349 textField.setValue(JcrItemUtil.getJcrItem(jcrItemId).getPath());
350 } else {
351 textField.setValue("/");
352 }
353 } catch (RepositoryException e) {
354 log.error("Failed to read chosen node", e);
355 }
356 }
357
358 @Override
359 public void onCancel() {
360 }
361 }, def, uiContext, textField.getValue());
362 chooseDialogView.setCaption(StringUtils.capitalize(getFieldDefinition().getWorkspace()));
363 }
364
365 protected WorkbenchDefinition resolveWorkbenchDefinition() {
366
367 if (getFieldDefinition().getWorkbench() != null) {
368 return getFieldDefinition().getWorkbench();
369 }
370
371 ConfiguredWorkbenchDefinition workbenchDefinition = new ConfiguredWorkbenchDefinition();
372 workbenchDefinition.setDialogWorkbench(true);
373 workbenchDefinition.setEditable(false);
374
375
376
377 ArrayList<ContentPresenterDefinition> contentViews = new ArrayList<ContentPresenterDefinition>();
378 TreePresenterDefinition treeView = new TreePresenterDefinition();
379 ArrayList<ColumnDefinition> columns = new ArrayList<ColumnDefinition>();
380 PropertyColumnDefinition column = new PropertyColumnDefinition();
381 column.setEditable(false);
382 column.setDisplayInChooseDialog(true);
383 column.setLabel(i18n.translate("security.workspace.field.nodeName"));
384 column.setPropertyName(ModelConstants.JCR_NAME);
385 column.setName(ModelConstants.JCR_NAME);
386 columns.add(column);
387 treeView.setColumns(columns);
388 contentViews.add(treeView);
389 workbenchDefinition.setContentViews(contentViews);
390
391 return workbenchDefinition;
392 }
393
394 private List<NodeTypeDefinition> resolveNodeTypes() {
395
396 if (getFieldDefinition().getNodeTypes() != null) {
397 return getFieldDefinition().getNodeTypes();
398 }
399
400 ArrayList<NodeTypeDefinition> nodeTypes = new ArrayList<NodeTypeDefinition>();
401 ConfiguredNodeTypeDefinition nodeType = new ConfiguredNodeTypeDefinition();
402 nodeType.setName(JcrConstants.NT_BASE);
403 nodeType.setIcon("icon-folder");
404 nodeTypes.add(nodeType);
405
406 return nodeTypes;
407 }
408
409 }