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,
116 ChooseDialogPresenter workbenchChooseDialogPresenter, SimpleTranslator i18n, ComponentProvider componentProvider) {
117 super(definition, relatedFieldItem);
118 this.uiContext = uiContext;
119 this.workbenchChooseDialogPresenter = workbenchChooseDialogPresenter;
120 this.i18n = i18n;
121 this.componentProvider = componentProvider;
122 }
123
124
125
126
127 @Deprecated
128 public WorkspaceAccessFieldFactory(D definition, Item relatedFieldItem, UiContext uiContext,
129 ChooseDialogPresenter workbenchChooseDialogPresenter, SimpleTranslator i18n) {
130 this(definition, relatedFieldItem, uiContext, workbenchChooseDialogPresenter, i18n, Components.getComponentProvider());
131 }
132
133 @Override
134 protected Field<Object> createFieldComponent() {
135
136 final String aclName = "acl_" + getFieldDefinition().getWorkspace();
137
138 final VerticalLayout layout = new VerticalLayout();
139 layout.setSpacing(true);
140
141 try {
142
143 final JcrNodeAdapter roleItem = (JcrNodeAdapter) item;
144
145 final VerticalLayout aclLayout = new VerticalLayout();
146
147 final Label emptyLabel = new Label(i18n.translate("security.workspace.field.noAccess"));
148
149
150 if (!(roleItem instanceof JcrNewNodeAdapter)) {
151 Node roleNode = roleItem.getJcrItem();
152 if (roleNode.hasNode(aclName)) {
153
154 final Node aclNode = roleNode.getNode(aclName);
155
156 AccessControlList acl = new AccessControlList();
157 acl.readEntries(aclNode);
158
159 AbstractJcrNodeAdapter aclItem = new JcrNodeAdapter(aclNode);
160 roleItem.addChild(aclItem);
161
162 aclItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
163
164 final Set<AccessControlList.Entry> uniqueEntries = new HashSet<AccessControlList.Entry>();
165 for (final Node aclEntryNode : NodeUtil.getNodes(aclNode)) {
166 AccessControlList.Entry entry = acl.getEntryByNode(aclEntryNode);
167 if (uniqueEntries.contains(entry)) {
168 continue;
169 }
170
171 uniqueEntries.add(entry);
172 long permissions = entry.getPermissions();
173 long accessType = entry.getAccessType();
174 String path = entry.getPath();
175
176 JcrNodeAdapter entryItem = new JcrNodeAdapter(aclEntryNode);
177 entryItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
178 final Property<Long> permissionsProperty = getOrCreateProperty(entryItem, AccessControlList.PERMISSIONS_PROPERTY_NAME, Long.class);
179 final Property<Long> accessProperty = getOrCreateProperty(entryItem, ACCESS_TYPE_PROPERTY_NAME, Long.class);
180 final Property<String> pathProperty = getOrCreateProperty(entryItem, AccessControlList.PATH_PROPERTY_NAME, String.class);
181
182 permissionsProperty.setValue(permissions);
183 accessProperty.setValue(accessType);
184 pathProperty.setValue(path);
185
186 aclItem.addChild(entryItem);
187
188 Component ruleRow = createRuleRow(aclLayout, entryItem, emptyLabel);
189 aclLayout.addComponent(ruleRow);
190 }
191 }
192 }
193
194 if (aclLayout.getComponentCount() == 0) {
195 aclLayout.addComponent(emptyLabel);
196 }
197
198 final HorizontalLayout buttons = new HorizontalLayout();
199 final Button addButton = new Button(i18n.translate("security.workspace.field.addButton"));
200 addButton.addClickListener(new Button.ClickListener() {
201
202 @Override
203 public void buttonClick(Button.ClickEvent event) {
204 try {
205
206 AbstractJcrNodeAdapter aclItem = getOrAddAclItem(roleItem, aclName);
207 if (aclItem.getItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME) == null) {
208 aclItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
209 }
210
211 JcrNodeAdapter entryItem = addAclEntryItem(aclItem);
212 entryItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
213 entryItem.addItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, Permission.ALL));
214 entryItem.addItemProperty(ACCESS_TYPE_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN));
215 entryItem.addItemProperty(AccessControlList.PATH_PROPERTY_NAME, new DefaultProperty<String>(String.class, ""));
216
217 Component ruleRow = createRuleRow(aclLayout, entryItem, emptyLabel);
218 aclLayout.removeComponent(emptyLabel);
219 aclLayout.addComponent(ruleRow, aclLayout.getComponentCount() - 1);
220 } catch (RepositoryException e) {
221 throw new RuntimeRepositoryException(e);
222 }
223 }
224 });
225 buttons.addComponent(addButton);
226 aclLayout.addComponent(buttons);
227
228 layout.addComponent(aclLayout);
229
230 } catch (RepositoryException e) {
231 throw new RuntimeRepositoryException(e);
232 }
233
234 return new CustomField<Object>() {
235
236 @Override
237 protected Component initContent() {
238 return layout;
239 }
240
241 @Override
242 public Class<?> getType() {
243 return Object.class;
244 }
245 };
246 }
247
248 private <T> Property<T> getOrCreateProperty(JcrNodeAdapter parentItem, String propertyId, Class<T> type) {
249 Property<T> p = parentItem.getItemProperty(propertyId);
250 if (p == null) {
251 p = DefaultPropertyUtil.newDefaultProperty(type, null);
252 parentItem.addItemProperty(propertyId, p);
253 }
254 return p;
255 }
256
257 protected Component createRuleRow(final AbstractOrderedLayout parentContainer, final AbstractJcrNodeAdapter ruleItem, final Label emptyLabel) {
258
259 final HorizontalLayout ruleLayout = new HorizontalLayout();
260 ruleLayout.setSpacing(true);
261 ruleLayout.setWidth("100%");
262
263 NativeSelect accessRights = new NativeSelect();
264 accessRights.setNullSelectionAllowed(false);
265 accessRights.setImmediate(true);
266 accessRights.setInvalidAllowed(false);
267 accessRights.setNewItemsAllowed(false);
268 accessRights.addItem(Permission.ALL);
269 accessRights.setItemCaption(Permission.ALL, i18n.translate("security.workspace.field.readWrite"));
270 accessRights.addItem(Permission.READ);
271 accessRights.setItemCaption(Permission.READ, i18n.translate("security.workspace.field.readOnly"));
272 accessRights.addItem(Permission.NONE);
273 accessRights.setItemCaption(Permission.NONE, i18n.translate("security.workspace.field.denyAccess"));
274 accessRights.setPropertyDataSource(ruleItem.getItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME));
275 ruleLayout.addComponent(accessRights);
276
277 NativeSelect accessType = new NativeSelect();
278 accessType.setNullSelectionAllowed(false);
279 accessType.setImmediate(true);
280 accessType.setInvalidAllowed(false);
281 accessType.setNewItemsAllowed(false);
282 accessType.setWidth("150px");
283 accessType.addItem(AccessControlList.ACCESS_TYPE_NODE);
284 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_NODE, i18n.translate("security.workspace.field.selected"));
285 accessType.addItem(AccessControlList.ACCESS_TYPE_CHILDREN);
286 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_CHILDREN, i18n.translate("security.workspace.field.subnodes"));
287 accessType.addItem(AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN);
288 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN, i18n.translate("security.workspace.field.selectedSubnodes"));
289 Property accessTypeProperty = ruleItem.getItemProperty(ACCESS_TYPE_PROPERTY_NAME);
290 accessType.setPropertyDataSource(accessTypeProperty);
291 ruleLayout.addComponent(accessType);
292
293 final TextField path = new TextField();
294 path.setWidth("100%");
295 path.setPropertyDataSource(ruleItem.getItemProperty(AccessControlList.PATH_PROPERTY_NAME));
296 ruleLayout.addComponent(path);
297 ruleLayout.setExpandRatio(path, 1.0f);
298
299 Button chooseButton = new Button(i18n.translate("security.workspace.field.choose"));
300 chooseButton.addClickListener(new Button.ClickListener() {
301
302 @Override
303 public void buttonClick(Button.ClickEvent event) {
304 openChooseDialog(path);
305 }
306 });
307 ruleLayout.addComponent(chooseButton);
308
309 Button deleteButton = new Button();
310 deleteButton.setHtmlContentAllowed(true);
311 deleteButton.setCaption("<span class=\"" + "icon-trash" + "\"></span>");
312 deleteButton.addStyleName("inline");
313 deleteButton.setDescription(i18n.translate("security.workspace.field.delete"));
314 deleteButton.addClickListener(new Button.ClickListener() {
315
316 @Override
317 public void buttonClick(Button.ClickEvent event) {
318 parentContainer.removeComponent(ruleLayout);
319 ruleItem.getParent().removeChild(ruleItem);
320 if (parentContainer.getComponentCount() == 1) {
321 parentContainer.addComponent(emptyLabel, 0);
322 }
323 }
324 });
325 ruleLayout.addComponent(deleteButton);
326
327 return ruleLayout;
328 }
329
330 protected void openChooseDialog(final TextField textField) {
331 final ConfiguredChooseDialogDefinition def = new ConfiguredChooseDialogDefinition();
332 final ConfiguredJcrContentConnectorDefinition contentConnectorDefinition = new ConfiguredJcrContentConnectorDefinition();
333 contentConnectorDefinition.setWorkspace(getFieldDefinition().getWorkspace());
334 contentConnectorDefinition.setRootPath("/");
335 contentConnectorDefinition.setDefaultOrder(ModelConstants.JCR_NAME);
336
337 contentConnectorDefinition.setNodeTypes(resolveNodeTypes());
338 def.setContentConnector(contentConnectorDefinition);
339
340 final WorkbenchDefinition wbDef = resolveWorkbenchDefinition();
341 final WorkbenchFieldDefinition fieldDef = new WorkbenchFieldDefinition();
342 fieldDef.setWorkbench(wbDef);
343 def.setField(fieldDef);
344
345
346 ComponentProvider chooseDialogComponentProvider = ChooseDialogComponentProviderUtil.createChooseDialogComponentProvider(def, componentProvider);
347 workbenchChooseDialogPresenter = chooseDialogComponentProvider.newInstance(def.getPresenterClass(), chooseDialogComponentProvider);
348
349
350
351 ChooseDialogView chooseDialogView = workbenchChooseDialogPresenter.start(new ChooseDialogCallback() {
352 @Override
353 public void onItemChosen(String actionName, Object value) {
354 try {
355 if (value instanceof JcrItemId) {
356 JcrItemId jcrItemId = (JcrItemId) value;
357 textField.setValue(JcrItemUtil.getJcrItem(jcrItemId).getPath());
358 } else {
359 textField.setValue("/");
360 }
361 } catch (RepositoryException e) {
362 log.error("Failed to read chosen node", e);
363 }
364 }
365
366 @Override
367 public void onCancel() {
368 }
369 }, def, uiContext, textField.getValue());
370 chooseDialogView.setCaption(StringUtils.capitalize(getFieldDefinition().getWorkspace()));
371 }
372
373 protected WorkbenchDefinition resolveWorkbenchDefinition() {
374
375 if (getFieldDefinition().getWorkbench() != null) {
376 return getFieldDefinition().getWorkbench();
377 }
378
379 ConfiguredWorkbenchDefinition workbenchDefinition = new ConfiguredWorkbenchDefinition();
380 workbenchDefinition.setDialogWorkbench(true);
381 workbenchDefinition.setEditable(false);
382
383
384
385 ArrayList<ContentPresenterDefinition> contentViews = new ArrayList<ContentPresenterDefinition>();
386 TreePresenterDefinition treeView = new TreePresenterDefinition();
387 ArrayList<ColumnDefinition> columns = new ArrayList<ColumnDefinition>();
388 PropertyColumnDefinition column = new PropertyColumnDefinition();
389 column.setEditable(false);
390 column.setDisplayInChooseDialog(true);
391 column.setLabel(i18n.translate("security.workspace.field.nodeName"));
392 column.setPropertyName(ModelConstants.JCR_NAME);
393 column.setName(ModelConstants.JCR_NAME);
394 columns.add(column);
395 treeView.setColumns(columns);
396 contentViews.add(treeView);
397 workbenchDefinition.setContentViews(contentViews);
398
399 return workbenchDefinition;
400 }
401
402 private List<NodeTypeDefinition> resolveNodeTypes() {
403
404 if (getFieldDefinition().getNodeTypes() != null) {
405 return getFieldDefinition().getNodeTypes();
406 }
407
408 ArrayList<NodeTypeDefinition> nodeTypes = new ArrayList<NodeTypeDefinition>();
409 ConfiguredNodeTypeDefinition nodeType = new ConfiguredNodeTypeDefinition();
410 nodeType.setName(JcrConstants.NT_BASE);
411 nodeType.setIcon("icon-folder");
412 nodeTypes.add(nodeType);
413
414 return nodeTypes;
415 }
416
417 }