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.jcr.RuntimeRepositoryException;
38 import info.magnolia.objectfactory.ComponentProvider;
39 import info.magnolia.ui.api.ModelConstants;
40 import info.magnolia.ui.api.context.UiContext;
41 import info.magnolia.ui.api.overlay.OverlayCloser;
42 import info.magnolia.ui.contentapp.choosedialog.ChooseDialogPresenter;
43 import info.magnolia.ui.contentapp.choosedialog.ChooseDialogView;
44 import info.magnolia.ui.contentapp.choosedialog.WorkbenchChooseDialogPresenter;
45 import info.magnolia.ui.contentapp.choosedialog.WorkbenchChooseDialogView;
46 import info.magnolia.ui.api.app.ItemChosenListener;
47 import info.magnolia.ui.vaadin.editorlike.DialogActionListener;
48 import info.magnolia.ui.vaadin.integration.jcr.AbstractJcrNodeAdapter;
49 import info.magnolia.ui.vaadin.integration.jcr.DefaultProperty;
50 import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
51 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
52 import info.magnolia.ui.workbench.column.definition.ColumnDefinition;
53 import info.magnolia.ui.workbench.column.definition.PropertyColumnDefinition;
54 import info.magnolia.ui.workbench.definition.ConfiguredNodeTypeDefinition;
55 import info.magnolia.ui.workbench.definition.ConfiguredWorkbenchDefinition;
56 import info.magnolia.ui.workbench.definition.ContentPresenterDefinition;
57 import info.magnolia.ui.workbench.definition.NodeTypeDefinition;
58 import info.magnolia.ui.workbench.definition.WorkbenchDefinition;
59 import info.magnolia.ui.workbench.tree.TreePresenterDefinition;
60
61 import java.util.ArrayList;
62 import java.util.List;
63
64 import javax.jcr.Node;
65 import javax.jcr.RepositoryException;
66
67 import org.apache.commons.lang.StringUtils;
68 import org.apache.jackrabbit.JcrConstants;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 import com.vaadin.data.Item;
73 import com.vaadin.data.Property;
74 import com.vaadin.ui.AbstractOrderedLayout;
75 import com.vaadin.ui.Button;
76 import com.vaadin.ui.Component;
77 import com.vaadin.ui.CustomField;
78 import com.vaadin.ui.Field;
79 import com.vaadin.ui.HorizontalLayout;
80 import com.vaadin.ui.Label;
81 import com.vaadin.ui.NativeSelect;
82 import com.vaadin.ui.TextField;
83 import com.vaadin.ui.VerticalLayout;
84
85
86
87
88
89
90
91
92
93 public class WorkspaceAccessFieldFactory<D extends WorkspaceAccessFieldDefinition> extends AbstractAccessFieldFactory<D> {
94
95 private static final Logger log = LoggerFactory.getLogger(WorkspaceAccessFieldFactory.class);
96
97 public static final String INTERMEDIARY_FORMAT_PROPERTY_NAME = "__intermediary_format";
98 public static final String ACCESS_TYPE_PROPERTY_NAME = "accessType";
99
100 private final ComponentProvider componentProvider;
101 private final UiContext uiContext;
102
103 public WorkspaceAccessFieldFactory(D definition, Item relatedFieldItem, ComponentProvider componentProvider, UiContext uiContext) {
104 super(definition, relatedFieldItem);
105 this.componentProvider = componentProvider;
106 this.uiContext = uiContext;
107 }
108
109 @Override
110 protected Field<Object> createFieldComponent() {
111
112 final String aclName = "acl_" + getFieldDefinition().getWorkspace();
113
114 final VerticalLayout layout = new VerticalLayout();
115 layout.setSpacing(true);
116
117 try {
118
119 final JcrNodeAdapter roleItem = (JcrNodeAdapter) item;
120 Node roleNode = roleItem.getJcrItem();
121
122 final VerticalLayout aclLayout = new VerticalLayout();
123
124 final Label emptyLabel = new Label("No access.");
125
126 if (roleNode.hasNode(aclName)) {
127
128 final Node aclNode = roleNode.getNode(aclName);
129
130 AccessControlList acl = new AccessControlList();
131 acl.readEntries(aclNode);
132
133 AbstractJcrNodeAdapter aclItem = new JcrNodeAdapter(aclNode);
134 roleItem.addChild(aclItem);
135
136 aclItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
137
138 for (AccessControlList.Entry entry : acl.getEntries()) {
139
140 long permissions = entry.getPermissions();
141 long accessType = entry.getAccessType();
142 String path = entry.getPath();
143
144 JcrNewNodeAdapter entryItem = addAclEntryItem(aclItem);
145 entryItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
146 entryItem.addItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, permissions));
147 entryItem.addItemProperty(ACCESS_TYPE_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, accessType));
148 entryItem.addItemProperty(AccessControlList.PATH_PROPERTY_NAME, new DefaultProperty<String>(String.class, path));
149
150 Component ruleRow = createRuleRow(aclLayout, entryItem, emptyLabel);
151 aclLayout.addComponent(ruleRow);
152 }
153 }
154
155 if (aclLayout.getComponentCount() == 0) {
156 aclLayout.addComponent(emptyLabel);
157 }
158
159 final HorizontalLayout buttons = new HorizontalLayout();
160 final Button addButton = new Button("Add new");
161 addButton.addClickListener(new Button.ClickListener() {
162
163 @Override
164 public void buttonClick(Button.ClickEvent event) {
165 try {
166
167 AbstractJcrNodeAdapter aclItem = getOrAddAclItem(roleItem, aclName);
168 if (aclItem.getItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME) == null) {
169 aclItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
170 }
171
172 JcrNewNodeAdapter entryItem = addAclEntryItem(aclItem);
173 entryItem.addItemProperty(INTERMEDIARY_FORMAT_PROPERTY_NAME, new DefaultProperty<String>(String.class, "true"));
174 entryItem.addItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, Permission.ALL));
175 entryItem.addItemProperty(ACCESS_TYPE_PROPERTY_NAME, new DefaultProperty<Long>(Long.class, AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN));
176 entryItem.addItemProperty(AccessControlList.PATH_PROPERTY_NAME, new DefaultProperty<String>(String.class, ""));
177
178 Component ruleRow = createRuleRow(aclLayout, entryItem, emptyLabel);
179 aclLayout.removeComponent(emptyLabel);
180 aclLayout.addComponent(ruleRow, aclLayout.getComponentCount() - 1);
181 } catch (RepositoryException e) {
182 throw new RuntimeRepositoryException(e);
183 }
184 }
185 });
186 buttons.addComponent(addButton);
187 aclLayout.addComponent(buttons);
188
189 layout.addComponent(aclLayout);
190
191 } catch (RepositoryException e) {
192 throw new RuntimeRepositoryException(e);
193 }
194
195 return new CustomField<Object>() {
196
197 @Override
198 protected Component initContent() {
199 return layout;
200 }
201
202 @Override
203 public Class<?> getType() {
204 return Object.class;
205 }
206 };
207 }
208
209 protected Component createRuleRow(final AbstractOrderedLayout parentContainer, final AbstractJcrNodeAdapter ruleItem, final Label emptyLabel) {
210
211 final HorizontalLayout ruleLayout = new HorizontalLayout();
212 ruleLayout.setSpacing(true);
213
214 NativeSelect accessRights = new NativeSelect();
215 accessRights.setNullSelectionAllowed(false);
216 accessRights.setImmediate(true);
217 accessRights.setInvalidAllowed(false);
218 accessRights.setNewItemsAllowed(false);
219 accessRights.addItem(Permission.ALL);
220 accessRights.setItemCaption(Permission.ALL, "Read/Write");
221 accessRights.addItem(Permission.READ);
222 accessRights.setItemCaption(Permission.READ, "Read-only");
223 accessRights.addItem(Permission.NONE);
224 accessRights.setItemCaption(Permission.NONE, "Deny access");
225 accessRights.setPropertyDataSource(ruleItem.getItemProperty(AccessControlList.PERMISSIONS_PROPERTY_NAME));
226 ruleLayout.addComponent(accessRights);
227
228 NativeSelect accessType = new NativeSelect();
229 accessType.setNullSelectionAllowed(false);
230 accessType.setImmediate(true);
231 accessType.setInvalidAllowed(false);
232 accessType.setNewItemsAllowed(false);
233 accessType.setWidth("150px");
234 accessType.addItem(AccessControlList.ACCESS_TYPE_NODE);
235 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_NODE, "Selected");
236 accessType.addItem(AccessControlList.ACCESS_TYPE_CHILDREN);
237 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_CHILDREN, "Sub nodes");
238 accessType.addItem(AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN);
239 accessType.setItemCaption(AccessControlList.ACCESS_TYPE_NODE_AND_CHILDREN, "Selected and sub nodes");
240 Property accessTypeProperty = ruleItem.getItemProperty(ACCESS_TYPE_PROPERTY_NAME);
241 accessType.setPropertyDataSource(accessTypeProperty);
242 ruleLayout.addComponent(accessType);
243
244 final TextField path = new TextField();
245 path.setWidth("125px");
246 path.setPropertyDataSource(ruleItem.getItemProperty(AccessControlList.PATH_PROPERTY_NAME));
247 ruleLayout.addComponent(path);
248
249 Button chooseButton = new Button("Choose...");
250 chooseButton.addClickListener(new Button.ClickListener() {
251
252 @Override
253 public void buttonClick(Button.ClickEvent event) {
254 openChooseDialog(path);
255 }
256 });
257 ruleLayout.addComponent(chooseButton);
258
259 Button deleteButton = new Button();
260 deleteButton.setHtmlContentAllowed(true);
261 deleteButton.setCaption("<span class=\"" + "icon-trash" + "\"></span>");
262 deleteButton.addStyleName("inline");
263 deleteButton.setDescription("Delete");
264 deleteButton.addClickListener(new Button.ClickListener() {
265
266 @Override
267 public void buttonClick(Button.ClickEvent event) {
268 parentContainer.removeComponent(ruleLayout);
269 ruleItem.getParent().removeChild(ruleItem);
270 if (parentContainer.getComponentCount() == 1) {
271 parentContainer.addComponent(emptyLabel, 0);
272 }
273 }
274 });
275 ruleLayout.addComponent(deleteButton);
276
277
278 return ruleLayout;
279 }
280
281 protected void openChooseDialog(final TextField textField) {
282
283 final ItemChosenListener listener = new ItemChosenListener() {
284
285 @Override
286 public void onItemChosen(Item item) {
287 try {
288 textField.setValue(((AbstractJcrNodeAdapter) item).getJcrItem().getPath());
289 } catch (RepositoryException e) {
290 log.error("Failed to read chosen node", e);
291 }
292 }
293
294 @Override
295 public void onChooseCanceled() {
296 }
297 };
298
299 final WorkbenchChooseDialogPresenter workbenchChooseDialogPresenter = componentProvider.newInstance(WorkbenchChooseDialogPresenter.class);
300 workbenchChooseDialogPresenter.setWorkbenchDefinition(resolveWorkbenchDefinition());
301
302 workbenchChooseDialogPresenter.addActionCallback(WorkbenchChooseDialogView.COMMIT_ACTION_NAME, new DialogActionListener() {
303 @Override
304 public void onActionExecuted(final String actionName) {
305 listener.onItemChosen(workbenchChooseDialogPresenter.getValue());
306 }
307 });
308
309 workbenchChooseDialogPresenter.addActionCallback(WorkbenchChooseDialogView.CANCEL_ACTION_NAME, new DialogActionListener() {
310 @Override
311 public void onActionExecuted(final String actionName) {
312 listener.onChooseCanceled();
313 }
314 });
315
316 ChooseDialogView chooseDialogView = workbenchChooseDialogPresenter.start();
317 chooseDialogView.setCaption(StringUtils.capitalize(getFieldDefinition().getWorkspace()));
318
319 final OverlayCloser overlayCloser = uiContext.openOverlay(chooseDialogView);
320
321 workbenchChooseDialogPresenter.setListener(new ChooseDialogPresenter.Listener() {
322
323 @Override
324 public void onClose() {
325 overlayCloser.close();
326 }
327 });
328 }
329
330 protected WorkbenchDefinition resolveWorkbenchDefinition() {
331
332 if (getFieldDefinition().getWorkbench() != null) {
333 return getFieldDefinition().getWorkbench();
334 }
335
336 ConfiguredWorkbenchDefinition workbenchDefinition = new ConfiguredWorkbenchDefinition();
337 workbenchDefinition.setWorkspace(getFieldDefinition().getWorkspace());
338 workbenchDefinition.setPath("/");
339 workbenchDefinition.setDialogWorkbench(true);
340 workbenchDefinition.setEditable(false);
341 workbenchDefinition.setDefaultOrder(ModelConstants.JCR_NAME);
342
343
344 workbenchDefinition.setNodeTypes(resolveNodeTypes());
345
346
347 ArrayList<ContentPresenterDefinition> contentViews = new ArrayList<ContentPresenterDefinition>();
348 TreePresenterDefinition treeView = new TreePresenterDefinition();
349 ArrayList<ColumnDefinition> columns = new ArrayList<ColumnDefinition>();
350 PropertyColumnDefinition column = new PropertyColumnDefinition();
351 column.setEditable(false);
352 column.setDisplayInChooseDialog(true);
353 column.setLabel("Node name");
354 column.setPropertyName(ModelConstants.JCR_NAME);
355 column.setName(ModelConstants.JCR_NAME);
356 columns.add(column);
357 treeView.setColumns(columns);
358 contentViews.add(treeView);
359 workbenchDefinition.setContentViews(contentViews);
360
361 return workbenchDefinition;
362 }
363
364 private List<NodeTypeDefinition> resolveNodeTypes() {
365
366 if (getFieldDefinition().getNodeTypes() != null) {
367 return getFieldDefinition().getNodeTypes();
368 }
369
370 ArrayList<NodeTypeDefinition> nodeTypes = new ArrayList<NodeTypeDefinition>();
371 ConfiguredNodeTypeDefinition nodeType = new ConfiguredNodeTypeDefinition();
372 nodeType.setName(JcrConstants.NT_BASE);
373 nodeType.setIcon("icon-folder");
374 nodeTypes.add(nodeType);
375
376 return nodeTypes;
377 }
378 }