View Javadoc
1   /*
2    * Copyright (C) 2003-2019 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.core.service;
18  
19  import org.apache.commons.lang.StringEscapeUtils;
20  import org.apache.commons.lang.Validate;
21  import org.exoplatform.commons.utils.CommonsUtils;
22  import org.exoplatform.container.PortalContainer;
23  import org.exoplatform.portal.mop.SiteType;
24  import org.exoplatform.services.log.ExoLogger;
25  import org.exoplatform.services.log.Log;
26  import org.exoplatform.social.core.identity.model.Identity;
27  import org.exoplatform.social.core.identity.model.Profile;
28  import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
29  import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
30  import org.exoplatform.social.core.manager.IdentityManager;
31  import org.exoplatform.social.core.model.AvatarAttachment;
32  import org.exoplatform.social.core.model.BannerAttachment;
33  import org.exoplatform.social.core.space.model.Space;
34  import org.exoplatform.social.core.space.spi.SpaceService;
35  import org.exoplatform.web.application.RequestContext;
36  import org.exoplatform.web.url.navigation.NavigationResource;
37  import org.exoplatform.web.url.navigation.NodeURL;
38  
39  import java.io.UnsupportedEncodingException;
40  import java.net.URLEncoder;
41  
42  /**
43   * Builds and provides default links and links of users, spaces and activities.
44   * Links are built basing on provided information as name or Id of the target user or space.
45   * In case something is wrong when building, the default links will be returned.
46   */
47  public class LinkProvider {
48    public static final String RESOURCE_URL = "/social-resources";
49    public static final String JAVASCRIPT_RESOURCE_URL = RESOURCE_URL + "/javascript/";
50    public static final String PROFILE_DEFAULT_AVATAR_URL = "/eXoSkin/skin/images/system/UserAvtDefault.png";
51    public static final String SPACE_DEFAULT_AVATAR_URL = "/eXoSkin/skin/images/system/SpaceAvtDefault.png";
52    public static final String HAS_CONNECTION_ICON =
53            RESOURCE_URL + "/eXoSkin/skin/images/themes/default/social/skin/UIManageUsers/StatusIcon.png";
54    public static final String WAITING_CONFIRMATION_ICON =
55            RESOURCE_URL + "/eXoSkin/skin/images/themes/default/social/skin/UIManageUsers/WaittingConfirm.png";
56    public static final String SPACE_MANAGER_ICON =
57            RESOURCE_URL + "/eXoSkin/skin/images/themes/default/social/skin/UIManageSpaces/Manager.png";
58    public static final String SPACE_MEMBER_ICON =
59            RESOURCE_URL + "/eXoSkin/skin/images/themes/default/social/skin/UIManageSpaces/Member.png";
60    public static final String SPACE_WAITING_CONFIRM_ICON =
61            RESOURCE_URL + "/eXoSkin/skin/images/themes/default/social/skin/UIManageSpaces/WaitingConfirm.png";
62    public static final String STARTER_ACTIVITY_AVATAR = "/eXoSkin/skin/images/themes/default/social/skin/Activity/starterAvt.png";
63    public static final String STARTER_ACTIVITY_IMAGE = "/eXoSkin/skin/images/themes/default/social/skin/Activity/starterActImg.png";
64  
65    public static final String ROUTE_DELIMITER = "/";
66    
67    private static Log             LOG = ExoLogger.getLogger(LinkProvider.class);
68  
69    private static final  String BASE_URL_SOCIAL_REST_API = "/v1/social";
70  
71    public LinkProvider() {
72    }
73  
74    /**
75     * Gets URI to a space profile by its pretty name.
76     *
77     * @param prettyName The pretty name of space.
78     * @return The URI.
79     * @LevelAPI Platform
80     * @since 1.2.0 GA
81     */
82    public static String getSpaceUri(final String prettyName) {
83      SpaceService spaceService = CommonsUtils.getService(SpaceService.class);
84      Space space = spaceService.getSpaceByPrettyName(prettyName);
85      RequestContext ctx = RequestContext.getCurrentInstance();
86      if (ctx != null) {
87        NodeURL nodeURL = ctx.createURL(NodeURL.TYPE);
88        NavigationResource resource = new NavigationResource(SiteType.GROUP, space.getGroupId(), space.getUrl());
89        return nodeURL.setResource(resource).toString();
90      } else {
91        return null;
92      }
93    }
94  
95    /**
96     * Gets URI to a user profile by username.
97     *
98     * @param username The name of user (remoteId).
99     * @return The URI.
100    * @LevelAPI Platform
101    */
102   public static String getProfileUri(final String username) {
103     return buildProfileUri(username, null, null);
104   }
105 
106   /**
107    * Gets URI to a user profile by username and owner portal.
108    *
109    * @param username The name of user (remoteId).
110    * @param portalOwner The portal owner (for example, classic or public).
111    * @return The URI.
112    * @LevelAPI Platform
113    */
114   public static String getProfileUri(final String username, final String portalOwner) {
115     return buildProfileUri(username, null, portalOwner);
116   }
117 
118   /**
119    * Gets a link to the user profile.
120    *
121    * @param username The name of user (remoteId).
122    * @return The link.
123    * @LevelAPI Platform
124    */
125   public static String getProfileLink(final String username) {
126     return getProfileLink(username, null);
127   }
128 
129   /**
130    * Gets a link to the user profile on a portal.
131    *
132    * @param username The name of user (remoteId).
133    * @param portalOwner The portal owner (for example, classic or public).
134    * @return The link.
135    * @LevelAPI Platform
136    */
137   public static String getProfileLink(final String username, final String portalOwner) {
138     Identity identity = getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, username, true);
139     Validate.notNull(identity, "Identity must not be null.");
140 
141     //
142     String configured_domain_url = null;
143     try {
144       configured_domain_url = CommonsUtils.getCurrentDomain();
145     } catch (NullPointerException e) {
146       configured_domain_url = null;
147     }
148 
149     return new StringBuilder("<a href=\"").append((configured_domain_url != null) ? configured_domain_url : "")
150                 .append(buildProfileUri(identity.getRemoteId(), null, portalOwner)).append("\" target=\"_parent\">")
151                 .append(StringEscapeUtils.escapeHtml(identity.getProfile().getFullName())).append("</a>").toString();
152   }
153 
154   /**
155    * Gets an absolute profile URL of a user.
156    *
157    * @param userName The name of user (remoteId).
158    * @param portalName The name of current portal.
159    * @param portalOwner The portal owner (for example, classic or public).
160    * @param host The name of the provided host.
161    * @return The absolute profile URL.
162    * @LevelAPI Platform
163    */
164   public static String getAbsoluteProfileUrl(final String userName, final String portalName,
165                                              final String portalOwner, final String host) {
166     return host + buildProfileUri(userName, portalName, portalOwner);
167   }
168 
169   /**
170    * Gets the activity URI of a user.
171    * 
172    * @param remoteId Name of the user, for example root.
173    * @return The activity link.
174    * @LevelAPI Platform
175    */
176   public static String getUserActivityUri(final String remoteId) {
177     return getActivityUri(OrganizationIdentityProvider.NAME,remoteId);
178   }
179 
180   /**
181    * Gets URI to connections of a user and all people.
182    * 
183    * @param remoteId Name of the user (remoteId), for example root.
184    * @return The URI.
185    * @LevelAPI Platform
186    */
187   public static String getUserConnectionsUri(final String remoteId) {
188     return getBaseUri(null, null) + "/connections/all-people" + ROUTE_DELIMITER + remoteId;
189   }
190   
191   /**
192    * Gets URI to connections of a user.
193    * 
194    * @param remoteId The name of user (remoteId), for example root.
195    * @return The link to network of provided user who has connection with the current user. 
196    */
197   public static String getUserConnectionsYoursUri(final String remoteId) {
198     return getBaseUri(null, null) + "/connections/network" + ROUTE_DELIMITER + remoteId;
199   }
200   
201   /**
202    * Gets URI to a user profile.
203    *
204    * @param remoteId The name of user (remoteId), for example root.
205    * @return The link to profile of provided user.
206    * @LevelAPI Platform
207    */
208   public static String getUserProfileUri(final String remoteId) {
209     return getBaseUri(null, null) + "/profile" + ROUTE_DELIMITER + remoteId;
210   }
211 
212   /**
213    * Gets URI to an activity stream of space or user.
214    *
215    * @param providerId The provider information.
216    * @param remoteId Id of the target identity, for example organization:root or space:abc_def.
217    * @return The link to activity of provided user on the provided provider.
218    * @LevelAPI Platform
219    */
220   public static String getActivityUri(final String providerId, final String remoteId) {
221     final String prefix = getBaseUri(null, null) + "/";
222     if (providerId.equals(OrganizationIdentityProvider.NAME)) {
223       return String.format("%sactivities/%s",prefix,remoteId);
224     } else if (providerId.equals(SpaceIdentityProvider.NAME)) {
225       return String.format("/%s/g/:spaces:%s/%s",getPortalName(null),remoteId,remoteId);
226     } else {
227       LOG.warn("Failed to getActivityLink with providerId: " + providerId);
228     }
229     return null;
230   }
231   
232   /**
233    * @param activityId
234    * @return
235    */
236   public static String getSingleActivityUrl(String activityId) {
237     return getBaseUri(null, null) + "/activity?id=" + activityId;
238   }
239 
240   /**
241    * Gets an activity URI of the space.
242    *
243    * @param remoteId The Id of target space.
244    * @param groupId The group Id of target space.
245    * @return The URI.
246    * @LevelAPI Platform
247    * @since 1.2.8
248    */
249   public static String getActivityUriForSpace(final String remoteId, final String groupId) {
250     return String.format("/%s/g/:spaces:%s/%s", getPortalName(null), groupId, remoteId);
251   }
252   
253   /**
254    * Gets URI to the provided space's avatar.
255    *
256    * @param space The target object to get its avatar based on the attachment information.
257    * @return The URI.
258    * @LevelAPI Platform
259    * @since 1.2.0-GA
260    */
261   public static String buildAvatarImageUri(final Space space) {
262     return buildAvatarImageUri(space.getAvatarAttachment());
263   }
264 
265   /**
266    * Gets URI to an avatar from the identity name.
267    *
268    * @param identityName The name of target identity to build the URL link to the avatar.
269    * @return Link to avatar of the target provided identity name.
270    * @LevelAPI Platform
271    * @since 1.2.0-GA
272    */
273   public static String buildAvatarImageUri(final String identityName) {
274     return String.format(
275         "/rest/jcr/repository/social/production/soc:providers/soc:space/soc:%s/soc:profile/soc:avatar",
276         identityName);
277   }
278 
279   /**
280    * Escapes the JCR special characters.
281    *
282    * @param string The set of characters to be escaped.
283    * @return Null if the string value is null; or a set of corresponding characters are returned after they have been escaped.
284    * @LevelAPI Platform
285    */
286   public static String escapeJCRSpecialCharacters(String string) {
287     if (string == null) {
288       return null;
289     }
290     return string.replace("[", "%5B").replace("]", "%5D").replace(":", "%3A");
291   }
292   
293   /**
294    * Gets URL to the profile's avatar image in a portalContainer.
295    *
296    * @param profile The user profile.
297    * @param portalContainer The portal container.
298    * @return Null or the URL.
299    * @LevelAPI Provisional
300    * @deprecated use {@link Profile#getAvatarUrl()}. Will be removed by 4.0.x.
301    */
302   public static String getAvatarImageSource(final PortalContainer portalContainer, final Profile profile) {
303     final AvatarAttachment avatarAttachment = (AvatarAttachment) profile.getProperty(Profile.AVATAR);
304     if (avatarAttachment != null) {
305       return buildAvatarImageUri(avatarAttachment);
306     }
307     return null;
308   }
309   
310   /**
311    * Gets URL to the profile's avatar image.
312    *
313    * @param profile The user profile.
314    * @return Null or the URL.
315    * @LevelAPI Provisional
316    * @deprecated use {@link Profile#getAvatarUrl()}. Will be removed by 4.0.x.
317    */
318   public static String getAvatarImageSource(final Profile profile) {
319     String avatarUrl = profile.getAvatarUrl();
320     if (avatarUrl != null) {
321       return avatarUrl;
322     }
323 
324     final AvatarAttachment avatarAttachment = (AvatarAttachment) profile.getProperty(Profile.AVATAR);
325     if (avatarAttachment != null) {
326       avatarUrl = buildAvatarImageUri(avatarAttachment);
327       profile.setAvatarUrl(avatarUrl);
328       getIdentityManager().saveProfile(profile);
329       return avatarUrl;
330     }
331     return null;
332   }
333 
334   /**
335    * Builds URI to the avatar image from avatarAttachment.
336    *
337    * @param avatarAttachment The object which stores information of the avatar image.
338    * @return The URI.
339    */
340   public static String buildAvatarImageUri(final AvatarAttachment avatarAttachment) {
341     String avatarUrl = null;
342     try {
343       if (avatarAttachment != null) {
344         final String repository = CommonsUtils.getRepository().getConfiguration().getName();
345         //
346         avatarUrl = escapeJCRSpecialCharacters(new StringBuilder("/").append(CommonsUtils.getRestContextName())
347                                                                      .append("/jcr/")
348                                                                      .append(repository)
349                                                                      .append("/")
350                                                                      .append(avatarAttachment.getWorkspace())
351                                                                      .append(avatarAttachment.getDataPath())
352                                                                      .append("/?upd=")
353                                                                      .append(avatarAttachment.getLastModified())
354                                                                      .toString());
355       }
356     } catch (Exception e) {
357       LOG.warn("Failed to build avatar url from avatar attachment for: " + e.getMessage());
358     }
359     return avatarUrl;
360   }
361 
362   /**
363    * Builds a profile URI from userName and portalOwner.
364    *
365    * @param userName The name of user.
366    * @param portalName The name of portal.
367    * @param portalOwner The owner of portal (for example, classic or public).
368    *        
369    * @return The profile URI.
370    */
371   private static String buildProfileUri(final String userName, final String portalName, String portalOwner) {
372     return getBaseUri(portalName, portalOwner) + "/profile" + ROUTE_DELIMITER + userName;
373   }
374 
375   /**
376    * Builds a profile URI from userName and portalName and portalOwner.
377    *
378    * @param portalName The name of portal.
379    * @param portalOwner The owner of portal (for example, classic or public).
380    *        
381    * @return The profile URI.
382    */
383   private static String getBaseUri(final String portalName, String portalOwner) {
384     return "/" + getPortalName(portalName) + "/" + getPortalOwner(portalOwner);
385   }
386 
387   private static String getSpaceBaseUri(final String portalName, String portalOwner) {
388     return "/" + getPortalName(portalName);
389   }
390 
391   /**
392    * Gets the link of notification settings page
393    * 
394    * @param remoteId
395    * @return
396    */
397   public static String getUserNotificationSettingUri(final String remoteId) {
398     return getBaseUri(null, null) + "/notifications" + ROUTE_DELIMITER + remoteId;
399   }
400   
401   /**
402    * Gets the link of all spaces page
403    *
404    * @return
405    */
406   public static String getRedirectUri(String type) {
407     if (type.isEmpty()) {
408       return getBaseUri(null, null);
409     }
410     return getBaseUri(null, null) + "/" + type;
411   }
412 
413   public static String getRedirectSpaceUri(String type) {
414     if (type.isEmpty()) {
415       return getSpaceBaseUri(null, null);
416     }
417     return getSpaceBaseUri(null, null) + "/" + type;
418   }
419 
420   /**
421    * Gets an IdentityManager instance.
422    *
423    * @return The IdentityManager.
424    */
425   public static IdentityManager getIdentityManager() {
426     return CommonsUtils.getService(IdentityManager.class);
427   }
428   
429   /**
430    * Builds the avatar URL for a given profile
431    * @param providerId
432    * @param remoteId
433    * @return
434    */
435   public static String buildAvatarURL(String providerId, String remoteId) {
436     return buildAttachmentUrl(providerId, remoteId, AvatarAttachment.TYPE);
437   }
438 
439   /**
440    * Builds the banner URL for a given profile
441    * @param providerId
442    * @param remoteId
443    * @return
444    */
445   public static String buildBannerURL(String providerId, String remoteId) {
446     return buildAttachmentUrl(providerId, remoteId, BannerAttachment.TYPE);
447   }
448 
449   private static String buildAttachmentUrl(String providerId, String remoteId, String type) {
450     if (providerId == null || remoteId == null) {
451       return null;
452     }
453 
454     String username = remoteId;
455 
456     try {
457       username = URLEncoder.encode(username, "UTF-8");
458     } catch (UnsupportedEncodingException ex) {
459       LOG.warn("Failure to encode username for build URL", ex);
460     }
461 
462     if(providerId.equals(OrganizationIdentityProvider.NAME)) {
463       return new StringBuilder("/").append(CommonsUtils.getRestContextName()).append(BASE_URL_SOCIAL_REST_API).append("/users")
464               .append("/").append(username)
465               .append("/").append(type)
466               .toString();
467     } else if(providerId.equals(SpaceIdentityProvider.NAME)) {
468       return new StringBuilder("/").append(CommonsUtils.getRestContextName()).append(BASE_URL_SOCIAL_REST_API).append("/spaces")
469               .append("/").append(username)
470               .append("/").append(type)
471               .toString();
472     }
473     return null;
474   }
475 
476   /**
477    * Gets a portal owner. If the parameter is null or "", the method returns a default portal owner.
478    *
479    * @param portalOwner The owner of portal (for example, classic or public).
480    * @return The portal owner.
481    */
482   private static String getPortalOwner(String portalOwner) {
483     if (portalOwner == null || portalOwner.trim().length() == 0) {
484       portalOwner = CommonsUtils.getCurrentPortalOwner();
485     }
486     return portalOwner;
487   }
488 
489   /**
490    * Gets a portal name. If the parameter is null or "", the method returns a default portal name.
491    * 
492    * @param portalName The name of portal.
493    * @return The portal name.
494    */
495   private static String getPortalName(String portalName) {
496     if (portalName == null || portalName.trim().length() == 0) {
497       return PortalContainer.getCurrentPortalContainerName();
498     }
499     return portalName;
500   }
501 }