View Javadoc
1   /*
2    * Copyright (C) 2003-2007 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.social.webui.space;
18  
19  import org.apache.commons.lang.StringEscapeUtils;
20  import org.apache.commons.lang.StringUtils;
21  import org.exoplatform.commons.api.settings.ExoFeatureService;
22  import org.exoplatform.commons.utils.CommonsUtils;
23  import org.exoplatform.portal.application.PortalRequestContext;
24  import org.exoplatform.portal.config.DataStorage;
25  import org.exoplatform.portal.config.UserPortalConfigService;
26  import org.exoplatform.portal.config.model.Page;
27  import org.exoplatform.portal.mop.user.UserNode;
28  import org.exoplatform.portal.webui.portal.UIPortal;
29  import org.exoplatform.portal.webui.util.Util;
30  import org.exoplatform.services.log.ExoLogger;
31  import org.exoplatform.services.log.Log;
32  import org.exoplatform.services.organization.Group;
33  import org.exoplatform.services.organization.GroupHandler;
34  import org.exoplatform.services.organization.OrganizationService;
35  import org.exoplatform.social.core.space.SpaceTemplate;
36  import org.exoplatform.social.core.space.SpaceUtils;
37  import org.exoplatform.social.core.space.model.Space;
38  import org.exoplatform.social.core.space.model.Space.UpdatedField;
39  import org.exoplatform.social.core.space.spi.SpaceService;
40  import org.exoplatform.social.core.space.spi.SpaceTemplateService;
41  import org.exoplatform.social.webui.UIAvatarUploader;
42  import org.exoplatform.social.webui.Utils;
43  import org.exoplatform.social.webui.composer.PopupContainer;
44  import org.exoplatform.web.application.ApplicationMessage;
45  import org.exoplatform.web.url.navigation.NodeURL;
46  import org.exoplatform.webui.application.WebuiRequestContext;
47  import org.exoplatform.webui.config.annotation.ComponentConfig;
48  import org.exoplatform.webui.config.annotation.EventConfig;
49  import org.exoplatform.webui.core.UIPortletApplication;
50  import org.exoplatform.webui.core.UITabPane;
51  import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
52  import org.exoplatform.webui.core.model.SelectItemOption;
53  import org.exoplatform.webui.event.Event;
54  import org.exoplatform.webui.event.Event.Phase;
55  import org.exoplatform.webui.event.EventListener;
56  import org.exoplatform.webui.form.UIForm;
57  import org.exoplatform.webui.form.UIFormSelectBox;
58  import org.exoplatform.webui.form.UIFormStringInput;
59  import org.exoplatform.webui.form.UIFormTextAreaInput;
60  import org.exoplatform.webui.form.validator.ExpressionValidator;
61  import org.exoplatform.webui.form.validator.MandatoryValidator;
62  import org.exoplatform.webui.form.validator.StringLengthValidator;
63  
64  import java.util.*;
65  
66  
67  @ComponentConfig(
68    lifecycle = UIFormLifecycle.class,
69    template = "war:/groovy/social/webui/space/UISpaceInfo.gtmpl",
70    events = {
71      @EventConfig(listeners = UISpaceInfo.SaveActionListener.class, phase = Phase.PROCESS),
72      @EventConfig(listeners = UISpaceInfo.ChangeAvatarActionListener.class)
73    }
74  )
75  public class UISpaceInfo extends UIForm {
76    
77    private static final Log LOG = ExoLogger.getLogger(UISpaceInfo.class);
78    
79    public static final String SPACE_ID = "id";
80  
81    private static final String SPACE_DISPLAY_NAME            = "displayName";
82    private static final String SPACE_DESCRIPTION             = "description";
83    private static final String SPACE_TEMPLATES_FEATURE       = "space-templates";
84    private static final String SPACE_TEMPLATE                = "template";
85    private static final String SPACE_TAG                     = "tag";
86    private SpaceService spaceService = null;
87    private SpaceTemplateService spaceTemplateService = null;
88    private ExoFeatureService featureService = null;
89    private boolean isSpaceTemplatesActive;
90    private final static String POPUP_AVATAR_UPLOADER = "UIPopupAvatarUploader";
91    
92    /** Html attribute title. */
93    private static final String HTML_ATTRIBUTE_TITLE          = "title";
94    private static final String HTML_ATTRIBUTE_PLACEHOLDER    = "placeholder";
95    
96    /**
97     * constructor
98     * 
99     * @throws Exception
100    */
101   public UISpaceInfo() throws Exception {
102     WebuiRequestContext requestContext = WebuiRequestContext.getCurrentInstance();
103     ResourceBundle resourceBundle = requestContext.getApplicationResourceBundle();
104     UIFormStringInput spaceId = new UIFormStringInput(SPACE_ID, SPACE_ID, null).setRendered(false);
105     spaceId.setHTMLAttribute(HTML_ATTRIBUTE_TITLE, resourceBundle.getString("UISpaceInfo.label.SpaceId"));
106     addUIFormInput(spaceId);
107 
108     UIFormStringInput spaceDisplayName = new UIFormStringInput(SPACE_DISPLAY_NAME, SPACE_DISPLAY_NAME, null);
109     spaceDisplayName.setHTMLAttribute(HTML_ATTRIBUTE_PLACEHOLDER, resourceBundle.getString("UISpaceSettings.label.spaceDisplayName"));
110     addUIFormInput(spaceDisplayName.
111                    addValidator(MandatoryValidator.class).
112                    addValidator(ExpressionValidator.class, "^([\\p{L}\\s\\d\'_&]+[\\s]?)+$", "UISpaceInfo.msg.name-invalid").
113                    addValidator(StringLengthValidator.class, 3, 30));
114 
115     UIFormTextAreaInput description = new UIFormTextAreaInput(SPACE_DESCRIPTION, SPACE_DESCRIPTION, null);
116     description.setHTMLAttribute(HTML_ATTRIBUTE_PLACEHOLDER, resourceBundle.getString("UISpaceSettings.label.spaceDescription"));
117     addUIFormInput(description.addValidator(StringLengthValidator.class, 0, 255));
118 
119     List<SelectItemOption<String>> templates = getSpaceTemplatesOptions();
120     addUIFormInput(new UIFormSelectBox(SPACE_TEMPLATE, SPACE_TEMPLATE, templates).setDisabled(true));
121 
122     //temporary disable tag
123     UIFormStringInput tag = new UIFormStringInput(SPACE_TAG, SPACE_TAG, null).setRendered(false);
124     tag.setHTMLAttribute(HTML_ATTRIBUTE_TITLE, resourceBundle.getString("UISpaceInfo.label.tag"));
125     addUIFormInput(tag);
126 
127     PopupContainer popupContainer = createUIComponent(PopupContainer.class, null, null);
128     addChild(popupContainer);
129   }
130 
131   @Override
132   public void processRender(WebuiRequestContext context) throws Exception {
133     UIFormSelectBox uiFormTypesSelectBox = getUIFormSelectBox(SPACE_TEMPLATE);
134     isSpaceTemplatesActive = getFeatureService().isActiveFeature(SPACE_TEMPLATES_FEATURE);
135     Space space = getSpace();
136     String templateName = space.getTemplate();
137     SpaceTemplate spaceTemplate = spaceTemplateService.getSpaceTemplateByName(templateName);
138     templateName = spaceTemplate == null ? spaceTemplateService.getDefaultSpaceTemplate() : spaceTemplate.getName();
139     uiFormTypesSelectBox.setValue(templateName);
140     uiFormTypesSelectBox.setRendered(isSpaceTemplatesActive);
141     super.processRender(context);
142   }
143 
144   private List<SelectItemOption<String>> getSpaceTemplatesOptions() {
145     List<SelectItemOption<String>> templates = new ArrayList<SelectItemOption<String>>();
146     for (SpaceTemplate spaceTemplate : getSpaceTemplateService().getSpaceTemplates()) {
147       String spaceType = spaceTemplate.getName();
148       String translation = null;
149       try {
150         ResourceBundle resourceBundle = WebuiRequestContext.getCurrentInstance().getApplicationResourceBundle();
151         String key = "space.template." + spaceType;
152         translation = resourceBundle.getString(key);
153       } catch (MissingResourceException e) {
154         translation = StringUtils.capitalize(spaceType);
155       } catch (Exception e) {
156         LOG.debug("Could not get resource bundle.");
157       }
158       SelectItemOption<String> option = new SelectItemOption<String>(translation, spaceType);
159       templates.add(option);
160     }
161     return templates;
162   }
163 
164   /**
165    * Sets the current space to ui component.
166    * 
167    * @param space
168    * @throws Exception
169    * @since 1.2.8
170    */
171   protected void setCurrentSpace(Space space) throws Exception {
172     // reset current space to component of uispacesetting.
173     UITabPane uiTabPane = this.getAncestorOfType(UITabPane.class);
174     uiTabPane.setSelectedTab(1);
175     UISpaceInfo uiSpaceInfo = uiTabPane.findFirstComponentOfType(UISpaceInfo.class);
176     uiSpaceInfo.setValue(space);
177     UISpaceMember uiSpaceMember = uiTabPane.findFirstComponentOfType(UISpaceMember.class);
178     uiSpaceMember.setValue(space.getId());
179     uiSpaceMember.setSpaceURL(space.getUrl());
180     UISpaceApplication uiSpaceApplication = uiTabPane.findFirstComponentOfType(UISpaceApplication.class);
181     uiSpaceApplication.setValue(space);
182     UISpacePermission uiSpacePermission = uiTabPane.findFirstComponentOfType(UISpacePermission.class);
183     uiSpacePermission.setValue(space);
184   }
185   
186   /**
187    * Sets space for this ui component to work with.
188    *
189    * @param space
190    * @throws Exception
191    */
192   public void setValue(Space space) throws Exception {
193     invokeGetBindingBean(space);
194     UIFormTextAreaInput description = getUIFormTextAreaInput(SPACE_DESCRIPTION);
195     description.setValue(StringEscapeUtils.unescapeHtml(description.getValue()));
196     //TODO: have to find the way to don't need the line code below.
197     getUIStringInput(SPACE_TAG).setValue(space.getTag());
198   }
199 
200   /**
201    * Gets image source url.
202    *
203    * @return image source url
204    * @throws Exception
205    */
206   protected Space getSpace() throws Exception {
207     SpaceService spaceService = getSpaceService();
208     String id = getUIStringInput(SPACE_ID).getValue();
209     Space space = spaceService.getSpaceById(id);
210     return space;
211   }
212 
213   /**
214    * Gets if space templates feature is active.
215    *
216    */
217   protected boolean isSpaceTemplatesActive() {
218     return isSpaceTemplatesActive;
219   }
220 
221   /**
222    * Triggers this action when user click on the Save button.
223    * Creating a space from existing group or creating new group for this space.
224    * Initialize some default applications in space component configuration.xml file.
225    *
226    * @author hoatle
227    */
228   public static class SaveActionListener extends EventListener<UISpaceInfo> {
229     public void execute(Event<UISpaceInfo> event) throws Exception {
230       UISpaceInfo uiSpaceInfo = event.getSource();
231       SpaceService spaceService = uiSpaceInfo.getSpaceService();
232       UIPortal uiPortal = Util.getUIPortal();
233 
234       String id = uiSpaceInfo.getUIStringInput(SPACE_ID).getValue();
235       String name = uiSpaceInfo.getUIStringInput(SPACE_DISPLAY_NAME).getValue();
236       Space space = spaceService.getSpaceById(id);
237       
238       if (space == null) {
239         //redirect to spaces
240         event.getRequestContext().sendRedirect(Utils.getURI("all-spaces"));
241         return;
242       }
243       
244       String displayName = uiSpaceInfo.getUIStringInput(SPACE_DISPLAY_NAME).getValue();
245       String spaceDescription = uiSpaceInfo.getUIFormTextAreaInput(SPACE_DESCRIPTION).getValue();
246       String oldDisplayName = space.getDisplayName();
247       String oldDescription = space.getDescription();
248       
249       UserNode selectedNode = uiPortal.getSelectedUserNode();
250       UserNode renamedNode = null;
251       
252       boolean nameChanged = (!space.getDisplayName().equals(name));
253       UIPortletApplication uiApp = uiSpaceInfo.getAncestorOfType(UIPortletApplication.class);
254       if (nameChanged) {
255 
256         String cleanedString = SpaceUtils.cleanString(name);
257         if (spaceService.getSpaceByUrl(cleanedString) != null) {
258           // reset to origin values
259           uiSpaceInfo.getUIStringInput(SPACE_DISPLAY_NAME).setValue(oldDisplayName);
260           uiSpaceInfo.getUIFormTextAreaInput(SPACE_DESCRIPTION).setValue(oldDescription);
261 
262           // 
263           uiApp.addMessage(new ApplicationMessage("UISpaceInfo.msg.current-name-exist", null, ApplicationMessage.INFO));
264           return;
265         }
266         
267         renamedNode = uiSpaceInfo.renamePageNode(name, space);
268         if (renamedNode == null) {
269           return;
270         }
271         
272       }
273       uiSpaceInfo.invokeSetBindingBean(space);
274       
275       space.setDisplayName(displayName);
276       spaceDescription = StringEscapeUtils.escapeHtml(spaceDescription);
277       space.setDescription(spaceDescription);
278       if (oldDescription != null && !oldDescription.equals(spaceDescription)) {
279         space.setField(UpdatedField.DESCRIPTION);  
280       }
281 
282       space.setEditor(Utils.getViewerRemoteId());
283       
284       if (nameChanged) {
285         space.setDisplayName(oldDisplayName);
286         String remoteId = Utils.getViewerRemoteId();
287         spaceService.renameSpace(remoteId, space, displayName);
288         
289         // rename group label
290         OrganizationService organizationService = CommonsUtils.getService(OrganizationService.class);
291         GroupHandler groupHandler = organizationService.getGroupHandler();
292         Group group = groupHandler.findGroupById(space.getGroupId());
293         group.setLabel(space.getDisplayName());
294         groupHandler.saveGroup(group, true);
295       } else {
296         spaceService.updateSpace(space);
297       }
298       
299       if (nameChanged) {
300         if (renamedNode != null) {
301           //update space navigation (change name).
302           selectedNode = renamedNode;  
303           PortalRequestContext prContext = Util.getPortalRequestContext();
304           prContext.createURL(NodeURL.TYPE).setNode(selectedNode);
305           event.getRequestContext().sendRedirect(Utils.getSpaceURL(selectedNode));
306           return;
307         }
308       } else {
309         uiApp.addMessage(new ApplicationMessage("UISpaceInfo.msg.update-success", null, ApplicationMessage.INFO));
310       }
311     }
312   }
313 
314   /**
315    * Triggers this action for editing avatar. An UIAvatarUploader popup should be displayed.
316    *
317    * @author hoatle
318    */
319   public static class ChangeAvatarActionListener extends EventListener<UISpaceInfo> {
320 
321     @Override
322     public void execute(Event<UISpaceInfo> event) throws Exception {
323       UISpaceInfo uiSpaceInfo = event.getSource();
324       PopupContainer popupContainer = uiSpaceInfo.getChild(PopupContainer.class);
325       popupContainer.activate(UIAvatarUploader.class, 500, POPUP_AVATAR_UPLOADER);
326       event.getRequestContext().addUIComponentToUpdateByAjax(popupContainer);
327     }
328   }
329 
330   /**
331    * Gets spaceService.
332    *
333    * @return spaceService
334    * @see SpaceService
335    */
336   public SpaceService getSpaceService() {
337     if (spaceService == null) {
338       spaceService = getApplicationComponent(SpaceService.class);
339     }
340     return spaceService;
341   }
342 
343   /**
344    * Gets spaceTemplateService.
345    *
346    * @return spaceTemplateService
347    * @see SpaceTemplateService
348    */
349   public SpaceTemplateService getSpaceTemplateService() {
350     if (spaceTemplateService == null) {
351       spaceTemplateService = getApplicationComponent(SpaceTemplateService.class);
352     }
353     return spaceTemplateService;
354   }
355 
356   /**
357    * Gets featureService.
358    *
359    * @return featureService
360    * @see ExoFeatureService
361    */
362   protected ExoFeatureService getFeatureService() {
363     if (featureService == null) {
364       featureService = getApplicationComponent(ExoFeatureService.class);
365     }
366     return featureService;
367   }
368 
369   /**
370    * Gets organizationService.
371    *
372    * @return organizationService
373    */
374   public OrganizationService getOrganizationService() {
375     return getApplicationComponent(OrganizationService.class);
376   }
377 
378   /**
379    * Gets dataSource.
380    *
381    * @return
382    */
383   public DataStorage getDataSource() {
384     return getApplicationComponent(DataStorage.class);
385   }
386 
387   /**
388    * Rename page node.
389    * 
390    * @param newNodeLabel
391    * @param space
392    * @return
393    * @since 1.2.8
394    */
395   private UserNode renamePageNode(String newNodeLabel, Space space) {
396     UserPortalConfigService configService = getApplicationComponent(UserPortalConfigService.class);
397 
398     DataStorage dataService = getApplicationComponent(DataStorage.class);
399 
400     try {
401 
402       UserNode renamedNode = SpaceUtils.getSpaceUserNode(space);
403       UserNode parentNode = renamedNode.getParent();
404       String newNodeName = SpaceUtils.cleanString(newNodeLabel);
405       
406       
407       if (parentNode.getChild(newNodeName) != null) {
408         newNodeName = newNodeName + "_" + System.currentTimeMillis();
409       }
410       
411       //
412       renamedNode.setLabel(newNodeLabel);
413       renamedNode.setName(newNodeName);
414 
415       Page page = dataService.getPage(renamedNode.getPageRef().format());
416       if (page != null) {
417         page.setTitle(newNodeLabel);
418         dataService.save(page);
419       }
420       
421       SpaceUtils.getUserPortal().saveNode(parentNode, null);
422 
423       space.setUrl(newNodeName);
424       SpaceUtils.changeSpaceUrlPreference(renamedNode, space, newNodeLabel);
425       SpaceUtils.changeAppPageTitle(renamedNode, newNodeLabel);
426       
427       List<UserNode> userNodes =  new ArrayList<UserNode>(renamedNode.getChildren());
428       for (UserNode childNode : userNodes) {
429         SpaceUtils.changeSpaceUrlPreference(childNode, space, newNodeLabel);
430         SpaceUtils.changeAppPageTitle(childNode, newNodeLabel);
431       }
432       return renamedNode;
433     } catch (Exception e) {
434       LOG.warn(e.getMessage() , e);
435       return null;
436     }
437   }
438 }