1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.social.core.space.impl;
18
19 import java.io.InputStream;
20 import java.util.*;
21
22 import org.apache.commons.lang.ArrayUtils;
23 import org.apache.commons.lang.StringUtils;
24
25 import org.exoplatform.commons.api.notification.model.NotificationInfo;
26 import org.exoplatform.commons.api.notification.model.PluginKey;
27 import org.exoplatform.commons.api.notification.model.WebNotificationFilter;
28 import org.exoplatform.commons.api.notification.service.WebNotificationService;
29 import org.exoplatform.commons.utils.ListAccess;
30 import org.exoplatform.container.ExoContainer;
31 import org.exoplatform.container.ExoContainerContext;
32 import org.exoplatform.container.configuration.ConfigurationManager;
33 import org.exoplatform.portal.config.UserACL;
34 import org.exoplatform.services.log.ExoLogger;
35 import org.exoplatform.services.log.Log;
36 import org.exoplatform.services.organization.*;
37 import org.exoplatform.services.security.IdentityConstants;
38 import org.exoplatform.services.security.IdentityRegistry;
39 import org.exoplatform.services.security.MembershipEntry;
40 import org.exoplatform.social.core.application.PortletPreferenceRequiredPlugin;
41 import org.exoplatform.social.core.identity.model.Identity;
42 import org.exoplatform.social.core.identity.model.Profile;
43 import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
44 import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
45 import org.exoplatform.social.core.model.BannerAttachment;
46 import org.exoplatform.social.core.space.*;
47 import org.exoplatform.social.core.space.model.Space;
48 import org.exoplatform.social.core.space.model.Space.UpdatedField;
49 import org.exoplatform.social.core.space.spi.SpaceApplicationHandler;
50 import org.exoplatform.social.core.space.spi.SpaceLifeCycleListener;
51 import org.exoplatform.social.core.space.spi.SpaceService;
52 import org.exoplatform.social.core.space.spi.SpaceTemplateService;
53 import org.exoplatform.social.core.storage.api.IdentityStorage;
54 import org.exoplatform.social.core.storage.api.SpaceStorage;
55
56
57
58
59
60
61 public class SpaceServiceImpl implements SpaceService {
62
63 private static final Log LOG = ExoLogger.getLogger(SpaceServiceImpl.class.getName());
64
65 public static final String MEMBER = "member";
66
67 public static final String MANAGER = "manager";
68
69 private IdentityRegistry identityRegistry;
70
71 private SpaceStorage spaceStorage;
72
73 private IdentityStorage identityStorage;
74
75 private OrganizationService orgService = null;
76
77 private UserACL userACL = null;
78
79 private SpaceLifecycle spaceLifeCycle = new SpaceLifecycle();
80
81 List<String> portletPrefsRequired = null;
82
83
84 private static final int OFFSET = 0;
85
86
87 private static final int LIMIT = 200;
88
89 private WebNotificationService webNotificationService;
90
91 private SpacesAdministrationService spacesAdministrationService;
92
93 private SpaceTemplateService spaceTemplateService;
94
95 private ConfigurationManager configurationManager;
96
97
98
99
100
101
102
103 public SpaceServiceImpl(SpaceStorage spaceStorage, IdentityStorage identityStorage, UserACL userACL, ConfigurationManager configurationManager,
104 IdentityRegistry identityRegistry, WebNotificationService webNotificationService,
105 SpacesAdministrationService spacesAdministrationService, SpaceTemplateService spaceTemplateService) throws Exception {
106 this.spaceStorage = spaceStorage;
107 this.identityStorage = identityStorage;
108 this.identityRegistry = identityRegistry;
109 this.userACL = userACL;
110 this.webNotificationService = webNotificationService;
111 this.spacesAdministrationService = spacesAdministrationService;
112 this.spaceTemplateService = spaceTemplateService;
113 this.configurationManager = configurationManager;
114 }
115
116
117
118
119 public List<Space> getAllSpaces() throws SpaceException {
120 try {
121 return Arrays.asList(this.getAllSpacesWithListAccess().load(OFFSET, LIMIT));
122 } catch (Exception e) {
123 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
124 }
125 }
126
127
128
129
130 public ListAccess<Space> getAllSpacesWithListAccess() {
131 return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.ALL);
132 }
133
134
135
136
137 public Space getSpaceByDisplayName(String spaceDisplayName) {
138 return spaceStorage.getSpaceByDisplayName(spaceDisplayName);
139 }
140
141
142
143
144 public Space getSpaceByName(String spaceName) {
145 return getSpaceByPrettyName(spaceName);
146 }
147
148
149
150
151 public Space getSpaceByPrettyName(String spacePrettyName) {
152 return spaceStorage.getSpaceByPrettyName(spacePrettyName);
153 }
154
155
156
157
158 public List<Space> getSpacesByFirstCharacterOfName(String firstCharacterOfName) throws SpaceException {
159 try {
160 return Arrays.asList(this.getAllSpacesByFilter(new SpaceFilter(firstCharacterOfName.charAt(0))).load(OFFSET, LIMIT));
161 } catch (Exception e) {
162 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
163 }
164 }
165
166
167
168
169 public List<Space> getSpacesBySearchCondition(String searchCondition) throws SpaceException {
170 try {
171 return Arrays.asList(this.getAllSpacesByFilter(new SpaceFilter(searchCondition)).load(OFFSET, LIMIT));
172 } catch (Exception e) {
173 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
174 }
175 }
176
177
178
179
180 public Space getSpaceByGroupId(String groupId) {
181 return spaceStorage.getSpaceByGroupId(groupId);
182 }
183
184
185
186
187 public Space getSpaceById(String id) {
188 return spaceStorage.getSpaceById(id);
189 }
190
191
192
193
194 public Space getSpaceByUrl(String url) {
195 return spaceStorage.getSpaceByUrl(url);
196 }
197
198
199
200
201 public List<Space> getSpaces(String userId) throws SpaceException {
202 try {
203 return Arrays.asList(this.getMemberSpaces(userId).load(OFFSET, LIMIT));
204 } catch (Exception e) {
205 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
206 }
207 }
208
209
210
211
212 public List<Space> getAccessibleSpaces(String userId) throws SpaceException {
213 try {
214 return Arrays.asList(this.getAccessibleSpacesWithListAccess(userId).load(OFFSET, LIMIT));
215 } catch (Exception e) {
216 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
217 }
218 }
219
220
221
222
223 public SpaceListAccess getAccessibleSpacesWithListAccess(String userId) {
224 return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.ACCESSIBLE);
225 }
226
227
228
229
230 public List<Space> getVisibleSpaces(String userId, SpaceFilter spaceFilter) throws SpaceException {
231 try {
232 return Arrays.asList(this.getVisibleSpacesWithListAccess(userId, spaceFilter).load(OFFSET, LIMIT));
233 } catch (Exception e) {
234 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
235 }
236 }
237
238
239
240
241 public SpaceListAccess getVisibleSpacesWithListAccess(String userId, SpaceFilter spaceFilter) {
242 if (isSuperManager(userId)) {
243 if (spaceFilter == null)
244 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.ALL);
245 else
246 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
247 } else {
248 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter,SpaceListAccess.Type.VISIBLE);
249 }
250 }
251
252
253
254
255 public SpaceListAccess getUnifiedSearchSpacesWithListAccess(String userId, SpaceFilter spaceFilter) {
256 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter,SpaceListAccess.Type.UNIFIED_SEARCH);
257 }
258
259
260
261
262 public List<Space> getEditableSpaces(String userId) throws SpaceException {
263 try {
264 return Arrays.asList(this.getSettingableSpaces(userId).load(OFFSET, LIMIT));
265 } catch (Exception e) {
266 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
267 }
268 }
269
270
271
272
273 public List<Space> getInvitedSpaces(String userId) throws SpaceException {
274 try {
275 return Arrays.asList(this.getInvitedSpacesWithListAccess(userId).load(OFFSET, LIMIT));
276 } catch (Exception e) {
277 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
278 }
279 }
280
281
282
283
284 public List<Space> getPublicSpaces(String userId) throws SpaceException {
285 try {
286 return Arrays.asList(this.getPublicSpacesWithListAccess(userId).load(OFFSET, LIMIT));
287 } catch (Exception e) {
288 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
289 }
290 }
291
292
293
294
295 public SpaceListAccess getPublicSpacesWithListAccess(String userId) {
296 if (isSuperManager(userId)) {
297 return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.PUBLIC_SUPER_USER);
298 } else {
299 return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.PUBLIC);
300 }
301 }
302
303
304
305
306 public List<Space> getPendingSpaces(String userId) throws SpaceException {
307 try {
308 return Arrays.asList(this.getPendingSpacesWithListAccess(userId).load(OFFSET, LIMIT));
309 } catch (Exception e) {
310 throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
311 }
312 }
313
314
315
316
317 public SpaceListAccess getPendingSpacesWithListAccess(String userId) {
318 return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.PENDING);
319 }
320
321
322
323
324 public Space createSpace(Space space, String creator) {
325 return createSpace(space, creator, (String) null);
326 }
327
328
329
330
331 @Deprecated
332 public Space createSpace(Space space, String creator, String invitedGroupId) {
333 List<Identity> invitedIdentities = new ArrayList<Identity>();
334 if (invitedGroupId != null) {
335
336 OrganizationService org = getOrgService();
337 try {
338 ListAccess<User> groupMembersAccess = org.getUserHandler().findUsersByGroupId(invitedGroupId);
339 User [] users = groupMembersAccess.load(0, groupMembersAccess.getSize());
340 for (User user : users) {
341 String userId = user.getUserName();
342 Identity identity = identityStorage.findIdentity(OrganizationIdentityProvider.NAME, userId);
343 if (identity != null) {
344 invitedIdentities.add(identity);
345 }
346 }
347 } catch (Exception e) {
348 throw new RuntimeException("Failed to invite users from group " + invitedGroupId, e);
349 }
350 }
351 return createSpace(space, creator, invitedIdentities);
352 }
353
354
355
356
357 public Space createSpace(Space space, String creator, List<Identity> identitiesToInvite) {
358
359 if (space.getDisplayName().length() > LIMIT) {
360 throw new RuntimeException("Error while creating the space " + space.getDisplayName() + ": space name cannot exceed 200 characters");
361 }
362
363 if (!SpaceUtils.isValidSpaceName(space.getDisplayName())) {
364 throw new RuntimeException("Error while creating the space " + space.getDisplayName()+ ": space name can only contain letters, digits or space characters only");
365 }
366
367 if(!spacesAdministrationService.canCreateSpace(creator)) {
368 throw new RuntimeException("User does not have permissions to create a space.");
369 }
370
371
372 String[] managers = space.getManagers();
373 String[] members = space.getMembers();
374 managers = (String[]) ArrayUtils.add(managers,creator);
375 members = (String[]) ArrayUtils.add(members,creator);
376 space.setManagers(managers);
377 space.setMembers(members);
378
379
380 String groupId = null;
381 try {
382 groupId = SpaceUtils.createGroup(space.getDisplayName(), space.getPrettyName(), creator);
383 } catch (SpaceException e) {
384 throw new RuntimeException("Error while creating group for space " + space.getPrettyName(), e);
385 }
386
387 List<String> inviteds = new ArrayList<String>();
388 if (identitiesToInvite != null) {
389 Set<String> userIds = getUsersToInvite(identitiesToInvite);
390 userIds.remove(creator);
391 for (String userId : userIds) {
392 String[] invitedUsers = space.getInvitedUsers();
393 if (isSuperManager(userId)) {
394 members = space.getMembers();
395 if (!ArrayUtils.contains(members, userId)) {
396 members = (String[]) ArrayUtils.add(members, userId);
397 space.setMembers(members);
398 }
399 } else if (!ArrayUtils.contains(invitedUsers, userId)) {
400 invitedUsers = (String[]) ArrayUtils.add(invitedUsers, userId);
401 inviteds.add(userId);
402 space.setInvitedUsers(invitedUsers);
403 }
404 }
405 }
406
407 String prettyName = groupId.split("/")[2];
408
409 if (!prettyName.equals(space.getPrettyName())) {
410
411 space.setPrettyName(groupId.split("/")[2]);
412 }
413
414
415 space.setGroupId(groupId);
416 space.setUrl(space.getPrettyName());
417
418 try {
419 String spaceType = space.getTemplate();
420 SpaceTemplate spaceTemplate = spaceTemplateService.getSpaceTemplateByName(spaceType);
421 if (spaceTemplate == null) {
422 LOG.warn("could not find space template of type {}, will use Default template", spaceType);
423 String defaultTemplate = spaceTemplateService.getDefaultSpaceTemplate();
424 spaceTemplate = spaceTemplateService.getSpaceTemplateByName(defaultTemplate);
425 space.setTemplate(defaultTemplate);
426 }
427 String bannerPath = spaceTemplate.getBannerPath();
428 if (StringUtils.isNotBlank(bannerPath)) {
429 try {
430 InputStream bannerStream = configurationManager.getInputStream(bannerPath);
431 if (bannerStream != null) {
432 BannerAttachment bannerAttachment = new BannerAttachment(null, "banner", "png", bannerStream, null, System.currentTimeMillis());
433 space.setBannerAttachment(bannerAttachment);
434 }
435 } catch (Exception e) {
436 LOG.warn("No file found for space banner at path {}", bannerPath);
437 }
438 }
439 SpaceApplicationHandler applicationHandler = getSpaceApplicationHandler(space);
440 spaceTemplateService.initSpaceApplications(space, applicationHandler);
441 } catch (Exception e) {
442 throw new RuntimeException("Failed to init apps for space " + space.getPrettyName(), e);
443 }
444
445 saveSpace(space, true);
446 spaceLifeCycle.spaceCreated(space, creator);
447
448
449 for (String invited : inviteds) {
450 spaceLifeCycle.addInvitedUser(space, invited);
451 }
452 updateSpaceBanner(space);
453 return space;
454 }
455
456 private Set<String> getUsersToInvite(List<Identity> identities) {
457 Set<String> invitedUserIds = new HashSet<>();
458 for (Identity identity : identities) {
459 String providerId = identity.getProviderId();
460 String remoteId = identity.getRemoteId();
461
462 if (SpaceIdentityProvider.NAME.equals(providerId)) {
463 Space space = getSpaceByPrettyName(remoteId);
464 if (space != null) {
465 String[] users = space.getMembers();
466 invitedUserIds.addAll(Arrays.asList(users));
467 }
468 } else {
469 invitedUserIds.add(remoteId);
470 }
471 }
472 return invitedUserIds;
473 }
474
475
476
477
478 public void saveSpace(Space space, boolean isNew) {
479 Space oldSpace = getSpaceById(space.getId());
480 spaceStorage.saveSpace(space, isNew);
481 if (!isNew) {
482 if (!oldSpace.getVisibility().equals(space.getVisibility())) {
483 spaceLifeCycle.spaceAccessEdited(space, space.getEditor());
484 }
485
486 String oldRegistration = oldSpace.getRegistration();
487 String registration = space.getRegistration();
488 if ((oldRegistration == null && registration != null)
489 || (oldRegistration != null && !oldRegistration.equals(registration))) {
490 spaceLifeCycle.spaceRegistrationEdited(space, space.getEditor());
491 }
492 }
493 }
494
495
496
497
498 public void renameSpace(Space space, String newDisplayName) {
499 spaceStorage.renameSpace(space, newDisplayName);
500 spaceLifeCycle.spaceRenamed(space, space.getEditor());
501 }
502
503
504
505
506 public void renameSpace(String remoteId, Space space, String newDisplayName) {
507
508 if (remoteId != null &&
509 isSuperManager(remoteId) &&
510 isMember(space, remoteId) == false) {
511
512 spaceStorage.renameSpace(remoteId, space, newDisplayName);
513
514 } else {
515
516 spaceStorage.renameSpace(space, newDisplayName);
517 }
518
519
520 spaceLifeCycle.spaceRenamed(space, space.getEditor());
521 }
522
523
524
525
526 public void deleteSpace(Space space) {
527 try {
528 Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, space.getPrettyName());
529
530 if (spaceIdentity != null) {
531 identityStorage.hardDeleteIdentity(spaceIdentity);
532 }
533
534
535 SpaceUtils.removeMembershipFromGroup(space);
536
537 spaceStorage.deleteSpace(space.getId());
538
539 OrganizationService orgService = getOrgService();
540 UserACL acl = getUserACL();
541 GroupHandler groupHandler = orgService.getGroupHandler();
542 Group deletedGroup = groupHandler.findGroupById(space.getGroupId());
543 List<String> mandatories = acl.getMandatoryGroups();
544 if (deletedGroup != null) {
545 if (!isMandatory(groupHandler, deletedGroup, mandatories)) {
546 SpaceUtils.removeGroup(space);
547 }
548 } else {
549 LOG.warn("deletedGroup is null");
550 }
551
552
553 SpaceUtils.removePagesAndGroupNavigation(space);
554
555 } catch (Exception e) {
556 LOG.error("Unable delete space", e);
557 }
558 spaceLifeCycle.spaceRemoved(space, null);
559 }
560
561
562
563
564 public void deleteSpace(String spaceId) {
565 deleteSpace(getSpaceById(spaceId));
566 }
567
568
569
570
571
572
573 public void initApp(Space space) throws SpaceException {
574 LOG.warn("Does nothing, just for compatible. It will be removed at 1.3.x");
575 return;
576 }
577
578
579
580
581 public void initApps(Space space) throws SpaceException {
582 LOG.warn("Does nothing, just for compatible. It will be removed at 1.3.x");
583 return;
584 }
585
586
587
588
589 public void deInitApps(Space space) throws SpaceException {
590 LOG.warn("Does nothing, just for compatible. It will be removed at 1.3.x");
591 return;
592 }
593
594
595
596
597 public void addMember(Space space, String userId) {
598 String[] members = space.getMembers();
599 space = this.removeInvited(space, userId);
600 space = this.removePending(space, userId);
601 if (!ArrayUtils.contains(members, userId)) {
602 members = (String[]) ArrayUtils.add(members, userId);
603 space.setMembers(members);
604 this.updateSpace(space);
605 SpaceUtils.addUserToGroupWithMemberMembership(userId, space.getGroupId());
606 spaceLifeCycle.memberJoined(space, userId);
607 }
608 }
609
610
611
612
613 public void addMember(String spaceId, String userId) {
614 addMember(getSpaceById(spaceId), userId);
615 }
616
617
618
619
620 public void removeMember(Space space, String userId) {
621 Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, space.getPrettyName());
622 if (spaceIdentity != null && spaceIdentity.isDeleted()) {
623 return;
624 }
625 String[] members = space.getMembers();
626 if (ArrayUtils.contains(members, userId)) {
627 members = (String[]) ArrayUtils.removeElement(members, userId);
628 space.setMembers(members);
629 this.updateSpace(space);
630 SpaceUtils.removeUserFromGroupWithMemberMembership(userId, space.getGroupId());
631 spaceLifeCycle.memberLeft(space, userId);
632 }
633 }
634
635
636
637
638 public void removeMember(String spaceId, String userId) {
639 removeMember(getSpaceById(spaceId), userId);
640 }
641
642
643
644
645 private Space addPending(Space space, String userId) {
646 String[] pendingUsers = space.getPendingUsers();
647 if (!ArrayUtils.contains(pendingUsers, userId)) {
648 pendingUsers = (String[]) ArrayUtils.add(pendingUsers, userId);
649 space.setPendingUsers(pendingUsers);
650 }
651 return space;
652 }
653
654
655
656
657 private Space removePending(Space space, String userId) {
658 String[] pendingUsers = space.getPendingUsers();
659 if (ArrayUtils.contains(pendingUsers, userId)) {
660 pendingUsers = (String[]) ArrayUtils.removeElement(pendingUsers, userId);
661 space.setPendingUsers(pendingUsers);
662 }
663 return space;
664 }
665
666
667
668
669 private Space addInvited(Space space, String userId) {
670 String[] invitedUsers = space.getInvitedUsers();
671 if (!ArrayUtils.contains(invitedUsers, userId)) {
672 invitedUsers = (String[]) ArrayUtils.add(invitedUsers, userId);
673 space.setInvitedUsers(invitedUsers);
674 }
675 return space;
676 }
677
678
679
680
681 private Space removeInvited(Space space, String userId) {
682 String[] invitedUsers = space.getInvitedUsers();
683 if (ArrayUtils.contains(invitedUsers, userId)) {
684 invitedUsers = (String[]) ArrayUtils.removeElement(invitedUsers, userId);
685 space.setInvitedUsers(invitedUsers);
686 }
687 return space;
688 }
689
690
691
692
693 public List<String> getMembers(Space space) {
694 if (space.getMembers() != null) {
695 return Arrays.asList(space.getMembers());
696 }
697 return new ArrayList<String> ();
698 }
699
700
701
702
703 public List<String> getMembers(String spaceId) {
704 return getMembers(getSpaceById(spaceId));
705 }
706
707
708
709
710
711
712
713 public void setLeader(Space space, String userId, boolean isLeader) {
714 this.setManager(space, userId, isLeader);
715 }
716
717
718
719
720
721
722
723 public void setLeader(String spaceId, String userId, boolean isLeader) {
724 this.setManager(this.getSpaceById(spaceId), userId, isLeader);
725 }
726
727
728
729
730 public boolean isLeader(Space space, String userId) {
731 return this.isManager(space, userId);
732 }
733
734
735
736
737 public boolean isLeader(String spaceId, String userId) {
738 return this.isManager(this.getSpaceById(spaceId), userId);
739 }
740
741
742
743
744 public boolean isOnlyLeader(Space space, String userId) {
745 return this.isOnlyManager(space, userId);
746 }
747
748
749
750
751 public boolean isOnlyLeader(String spaceId, String userId) {
752 return this.isOnlyManager(this.getSpaceById(spaceId), userId);
753 }
754
755
756
757
758 public boolean isMember(Space space, String userId) {
759 return ArrayUtils.contains(space.getMembers(), userId);
760 }
761
762
763
764
765 public boolean isMember(String spaceId, String userId) {
766 return isMember(getSpaceById(spaceId), userId);
767 }
768
769
770
771
772 public boolean hasAccessPermission(Space space, String userId) {
773 if (isSuperManager(userId)
774 || (ArrayUtils.contains(space.getMembers(), userId))
775 || (ArrayUtils.contains(space.getManagers(), userId))) {
776 return true;
777 }
778 return false;
779 }
780
781
782
783
784 public boolean hasAccessPermission(String spaceId, String userId) {
785 return hasAccessPermission(getSpaceById(spaceId), userId);
786 }
787
788
789
790
791 public boolean hasEditPermission(Space space, String userId) {
792 return this.hasSettingPermission(space, userId);
793 }
794
795
796
797
798 public boolean hasEditPermission(String spaceId, String userId) {
799 return this.hasSettingPermission(this.getSpaceById(spaceId), userId);
800 }
801
802
803
804
805 public boolean isInvited(Space space, String userId) {
806 return this.isInvitedUser(space, userId);
807 }
808
809
810
811
812 public boolean isInvited(String spaceId, String userId) {
813 return this.isInvitedUser(this.getSpaceById(spaceId), userId);
814 }
815
816
817
818
819 public boolean isPending(Space space, String userId) {
820 return this.isPendingUser(space, userId);
821 }
822
823
824
825
826 public boolean isPending(String spaceId, String userId) {
827 return this.isPendingUser(this.getSpaceById(spaceId), userId);
828 }
829
830
831
832
833 public boolean isIgnored(Space space, String userId) {
834 boolean ignoredMember = spaceStorage.isSpaceIgnored(space.getId(), userId);
835 return ignoredMember;
836 }
837
838
839
840
841 public void setIgnored(String spaceId, String userId) {
842 spaceStorage.ignoreSpace(spaceId, userId);
843 }
844
845
846
847
848 public void installApplication(String spaceId, String appId) throws SpaceException {
849 installApplication(getSpaceById(spaceId), appId);
850 }
851
852
853
854
855 public void installApplication(Space space, String appId) throws SpaceException {
856
857
858
859
860
861
862
863
864 spaceLifeCycle.addApplication(space, getPortletId(appId));
865 }
866
867
868
869
870 public void activateApplication(Space space, String appId) throws SpaceException {
871
872
873
874
875 String appName = null;
876 if (SpaceUtils.isInstalledApp(space, appId)) {
877 appName = appId + System.currentTimeMillis();
878 } else {
879 appName = appId;
880 }
881 SpaceApplicationHandler appHandler = getSpaceApplicationHandler(space);
882 appHandler.activateApplication(space, appId, appName);
883
884 spaceTemplateService.setApp(space, appId, appName, true, Space.ACTIVE_STATUS);
885 saveSpace(space, false);
886
887 spaceLifeCycle.activateApplication(space, getPortletId(appId));
888 }
889
890
891
892
893 public void activateApplication(String spaceId, String appId) throws SpaceException {
894 activateApplication(getSpaceById(spaceId), appId);
895 }
896
897
898
899
900 public void deactivateApplication(Space space, String appId) throws SpaceException {
901 String appStatus = SpaceUtils.getAppStatus(space, appId);
902 if (appStatus == null) {
903 LOG.warn("appStatus is null!");
904 return;
905 }
906 if (appStatus.equals(Space.DEACTIVE_STATUS))
907 return;
908 SpaceApplicationHandler appHandler = getSpaceApplicationHandler(space);
909 appHandler.deactiveApplication(space, appId);
910 spaceTemplateService.setApp(space, appId, appId, SpaceUtils.isRemovableApp(space, appId), Space.DEACTIVE_STATUS);
911 saveSpace(space, false);
912 spaceLifeCycle.deactivateApplication(space, getPortletId(appId));
913 }
914
915
916
917
918 public void deactivateApplication(String spaceId, String appId) throws SpaceException {
919 deactivateApplication(getSpaceById(spaceId), appId);
920 }
921
922
923
924
925 public void removeApplication(Space space, String appId, String appName) throws SpaceException {
926 String appStatus = SpaceUtils.getAppStatus(space, appId);
927 if (appStatus == null)
928 return;
929 SpaceApplicationHandler appHandler = getSpaceApplicationHandler(space);
930 appHandler.removeApplication(space, appId, appName);
931 removeApp(space, appId, appName);
932 spaceLifeCycle.removeApplication(space, getPortletId(appId));
933 }
934
935
936
937
938 public void removeApplication(String spaceId, String appId, String appName) throws SpaceException {
939 removeApplication(getSpaceById(spaceId), appId, appName);
940 }
941
942
943
944
945 public void requestJoin(String spaceId, String userId) {
946 this.addPendingUser(this.getSpaceById(spaceId), userId);
947 }
948
949
950
951
952 public void requestJoin(Space space, String userId) {
953 this.addPendingUser(space, userId);
954 }
955
956
957
958
959 public void revokeRequestJoin(Space space, String userId) {
960 this.removePendingUser(space, userId);
961 }
962
963
964
965
966 public void revokeRequestJoin(String spaceId, String userId) {
967 this.removePending(this.getSpaceById(spaceId), userId);
968 }
969
970
971
972
973 public void inviteMember(Space space, String userId) {
974 this.addInvitedUser(space, userId);
975 }
976
977
978
979
980 public void inviteMember(String spaceId, String userId) {
981 this.addInvitedUser(this.getSpaceById(spaceId), userId);
982 }
983
984
985
986
987 public void revokeInvitation(Space space, String userId) {
988 this.removeInvitedUser(space, userId);
989 }
990
991
992
993
994 public void revokeInvitation(String spaceId, String userId) {
995 this.removeInvitedUser(this.getSpaceById(spaceId), userId);
996 }
997
998
999
1000
1001 public void acceptInvitation(Space space, String userId) throws SpaceException {
1002 this.addMember(space, userId);
1003 }
1004
1005
1006
1007
1008 public void acceptInvitation(String spaceId, String userId) throws SpaceException {
1009 this.addMember(this.getSpaceById(spaceId), userId);
1010 }
1011
1012
1013
1014
1015 public void denyInvitation(String spaceId, String userId) {
1016 this.removeInvitedUser(this.getSpaceById(spaceId), userId);
1017 }
1018
1019
1020
1021
1022 public void denyInvitation(Space space, String userId) {
1023 this.removeInvitedUser(space, userId);
1024 }
1025
1026
1027
1028
1029 public void validateRequest(Space space, String userId) {
1030 this.addMember(space, userId);
1031 }
1032
1033
1034
1035
1036 public void validateRequest(String spaceId, String userId) {
1037 this.addMember(this.getSpaceById(spaceId), userId);
1038 }
1039
1040
1041
1042
1043 public void declineRequest(Space space, String userId) {
1044 this.removePendingUser(space, userId);
1045 }
1046
1047
1048
1049
1050 public void declineRequest(String spaceId, String userId) {
1051 this.removePendingUser(this.getSpaceById(spaceId), userId);
1052 }
1053
1054
1055
1056
1057 public void registerSpaceLifeCycleListener(SpaceLifeCycleListener listener) {
1058 spaceLifeCycle.addListener(listener);
1059 }
1060
1061
1062
1063
1064 public void unregisterSpaceLifeCycleListener(SpaceLifeCycleListener listener) {
1065 spaceLifeCycle.removeListener(listener);
1066 }
1067
1068 public void addSpaceListener(SpaceListenerPlugin plugin) {
1069 registerSpaceLifeCycleListener(plugin);
1070 }
1071
1072
1073
1074
1075 public void setPortletsPrefsRequired(PortletPreferenceRequiredPlugin portletPrefsRequiredPlugin) {
1076 List<String> portletPrefs = portletPrefsRequiredPlugin.getPortletPrefs();
1077 if (portletPrefsRequired == null) {
1078 portletPrefsRequired = new ArrayList<String>();
1079 }
1080 portletPrefsRequired.addAll(portletPrefs);
1081 }
1082
1083
1084
1085
1086 public String [] getPortletsPrefsRequired() {
1087 return this.portletPrefsRequired.toArray(new String[this.portletPrefsRequired.size()]);
1088 }
1089
1090
1091
1092
1093
1094
1095 private OrganizationService getOrgService() {
1096 if (orgService == null) {
1097 ExoContainer container = ExoContainerContext.getCurrentContainer();
1098 orgService = (OrganizationService) container.getComponentInstanceOfType(OrganizationService.class);
1099 }
1100 return orgService;
1101 }
1102
1103
1104
1105
1106
1107
1108 private UserACL getUserACL() {
1109 return userACL;
1110 }
1111
1112
1113
1114
1115
1116
1117
1118
1119 private SpaceApplicationHandler getSpaceApplicationHandler(Space space) throws SpaceException {
1120 String spaceTemplate = space.getTemplate();
1121 SpaceApplicationHandler appHandler = spaceTemplateService.getSpaceApplicationHandlers().get(spaceTemplate);
1122 if (appHandler == null) {
1123 LOG.debug("No space application handler was defined for template with name {}. Default will be used.", spaceTemplate);
1124 String defaultTemplate = spaceTemplateService.getDefaultSpaceTemplate();
1125 appHandler = spaceTemplateService.getSpaceApplicationHandlers().get(defaultTemplate);
1126 if (appHandler == null) {
1127 throw new SpaceException(SpaceException.Code.UNKNOWN_SPACE_TYPE);
1128 }
1129 }
1130 return appHandler;
1131 }
1132
1133
1134
1135
1136
1137
1138
1139
1140 private void removeApp(Space space, String appId, String appName) throws SpaceException {
1141 String apps = space.getApp();
1142 StringBuffer remainApp = new StringBuffer();
1143 String[] listApp = apps.split(",");
1144 String[] appPart;
1145 String app;
1146 for (int idx = 0; idx < listApp.length; idx++) {
1147 app = listApp[idx];
1148 appPart = app.split(":");
1149 if (!appPart[1].equals(appName)) {
1150 if (remainApp.length() != 0)
1151 remainApp.append(",");
1152 remainApp.append(app);
1153 }
1154 }
1155
1156 space.setApp(remainApp.toString());
1157 saveSpace(space, false);
1158 }
1159
1160 private boolean isMandatory(GroupHandler groupHandler, Group group, List<String> mandatories) throws Exception {
1161 if (mandatories.contains(group.getId()))
1162 return true;
1163 Collection<Group> children = groupHandler.findGroups(group);
1164 for (Group g : children) {
1165 if (isMandatory(groupHandler, g, mandatories))
1166 return true;
1167 }
1168 return false;
1169 }
1170
1171
1172
1173
1174
1175 public SpaceStorage getStorage() {
1176 return spaceStorage;
1177 }
1178
1179
1180
1181
1182
1183
1184 public void setStorage(SpaceStorage storage) {
1185 this.spaceStorage = storage;
1186 }
1187
1188
1189
1190
1191 public void addInvitedUser(Space space, String userId) {
1192
1193 if (ArrayUtils.contains(space.getMembers(),userId)) {
1194
1195 return;
1196 }
1197
1198 if (isPending(space, userId)) {
1199 space = removePending(space, userId);
1200 addMember(space, userId);
1201 } else {
1202 space = addInvited(space, userId);
1203 }
1204 this.updateSpace(space);
1205 spaceLifeCycle.addInvitedUser(space, userId);
1206 }
1207
1208
1209
1210
1211 public void addPendingUser(Space space, String userId) {
1212 if (ArrayUtils.contains(space.getMembers(),userId)) {
1213
1214 return;
1215 }
1216
1217 if (ArrayUtils.contains(space.getPendingUsers(), userId)) {
1218 this.addMember(space, userId);
1219 space = removeInvited(space, userId);
1220 this.updateSpace(space);
1221 return;
1222 }
1223
1224 String registration = space.getRegistration();
1225 String visibility = space.getVisibility();
1226 if (visibility.equals(Space.HIDDEN) && registration.equals(Space.CLOSE)) {
1227 LOG.warn("Unable request to join hidden");
1228 return;
1229 }
1230 if (registration.equals(Space.OPEN)) {
1231 addMember(space, userId);
1232 } else if (registration.equals(Space.VALIDATION)) {
1233 space = addPending(space, userId);
1234 saveSpace(space, false);
1235 } else {
1236 LOG.warn("Unable request to join");
1237 }
1238 spaceLifeCycle.addPendingUser(space, userId);
1239 }
1240
1241
1242
1243
1244 public ListAccess<Space> getAccessibleSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1245 if (isSuperManager(userId)
1246 && (spaceFilter == null || spaceFilter.getAppId() == null)) {
1247 if(spaceFilter == null) {
1248 return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL);
1249 } else {
1250 return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
1251 }
1252 } else {
1253 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.ACCESSIBLE_FILTER);
1254 }
1255 }
1256
1257
1258
1259
1260 public ListAccess<Space> getAllSpacesByFilter(SpaceFilter spaceFilter) {
1261 return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
1262 }
1263
1264
1265
1266
1267 public ListAccess<Space> getInvitedSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1268 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.INVITED_FILTER);
1269 }
1270
1271
1272
1273
1274 public ListAccess<Space> getMemberSpaces(String userId) {
1275 return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.MEMBER);
1276 }
1277
1278
1279
1280
1281 public ListAccess<Space> getMemberSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1282 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.MEMBER_FILTER);
1283 }
1284
1285
1286
1287
1288 public ListAccess<Space> getPendingSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1289 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.PENDING_FILTER);
1290 }
1291
1292
1293
1294
1295 public ListAccess<Space> getPublicSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1296 if (isSuperManager(userId)) {
1297 return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.PUBLIC_SUPER_USER);
1298 } else {
1299 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.PUBLIC_FILTER);
1300 }
1301 }
1302
1303
1304
1305
1306 public ListAccess<Space> getSettingableSpaces(String userId) {
1307 if (isSuperManager(userId)) {
1308 return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.ALL);
1309 } else {
1310 return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.SETTING);
1311 }
1312 }
1313
1314
1315
1316
1317 public ListAccess<Space> getSettingabledSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1318 if (isSuperManager(userId)) {
1319 return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
1320 } else {
1321 return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.SETTING_FILTER);
1322 }
1323 }
1324
1325
1326
1327
1328 public boolean hasSettingPermission(Space space, String userId) {
1329 return isSuperManager(userId) || ArrayUtils.contains(space.getManagers(), userId);
1330 }
1331
1332
1333
1334
1335 public boolean isInvitedUser(Space space, String userId) {
1336 return ArrayUtils.contains(space.getInvitedUsers(), userId);
1337 }
1338
1339
1340
1341
1342 public boolean isManager(Space space, String userId) {
1343 return ArrayUtils.contains(space.getManagers(), userId);
1344 }
1345
1346
1347
1348
1349 public boolean isOnlyManager(Space space, String userId) {
1350 if (space.getManagers() != null && space.getManagers().length == 1 && ArrayUtils.contains(space.getManagers(), userId)) {
1351 return true;
1352 }
1353 return false;
1354 }
1355
1356
1357
1358
1359 public boolean isPendingUser(Space space, String userId) {
1360 return ArrayUtils.contains(space.getPendingUsers(), userId);
1361 }
1362
1363
1364
1365
1366 public void registerSpaceListenerPlugin(SpaceListenerPlugin spaceListenerPlugin) {
1367 spaceLifeCycle.addListener(spaceListenerPlugin);
1368 }
1369
1370
1371
1372
1373 public void removeInvitedUser(Space space, String userId) {
1374 if (ArrayUtils.contains(space.getInvitedUsers(), userId)) {
1375 space = this.removeInvited(space, userId);
1376 this.updateSpace(space);
1377 removeWebNotifications(space.getId(), userId);
1378 }
1379 }
1380
1381
1382
1383
1384 public void removePendingUser(Space space, String userId) {
1385 if (ArrayUtils.contains(space.getPendingUsers(), userId)) {
1386 space = this.removePending(space, userId);
1387 this.updateSpace(space);
1388 removeWebNotifications(space.getId(), userId);
1389 }
1390 }
1391
1392 private void removeWebNotifications(String spaceId, String userId) {
1393 if (webNotificationService != null) {
1394 WebNotificationFilter filter = new WebNotificationFilter(userId);
1395 filter.setParameter("spaceId", spaceId);
1396 PluginKey pluginKey = new PluginKey("SpaceInvitationPlugin");
1397 filter.setPluginKey(pluginKey);
1398 try {
1399 for (NotificationInfo notificationInfo : webNotificationService.getNotificationInfos(filter, 0, -1)) {
1400 webNotificationService.remove(notificationInfo.getId());
1401 }
1402 } catch (Exception e) {
1403 LOG.error("Cannot remove web notifications for user: " + userId + " and space id: " + spaceId, e);
1404 }
1405 } else {
1406 LOG.error("Cannot update web notfication. WebNotificationService is null");
1407 }
1408 }
1409
1410
1411
1412
1413 public void setManager(Space space, String userId, boolean isManager) {
1414 String[] managers = space.getManagers();
1415 if (isManager) {
1416 if (!ArrayUtils.contains(managers, userId)) {
1417 managers = (String[]) ArrayUtils.add(managers, userId);
1418 space.setManagers(managers);
1419 this.updateSpace(space);
1420 SpaceUtils.addUserToGroupWithManagerMembership(userId, space.getGroupId());
1421 spaceLifeCycle.grantedLead(space, userId);
1422 }
1423 } else {
1424 if (ArrayUtils.contains(managers, userId)) {
1425 managers = (String[]) ArrayUtils.removeElement(managers, userId);
1426 space.setManagers(managers);
1427 this.updateSpace(space);
1428 SpaceUtils.removeUserFromGroupWithManagerMembership(userId, space.getGroupId());
1429 Space updatedSpace = getSpaceById(space.getId());
1430 if (isMember(updatedSpace, userId)) {
1431 spaceLifeCycle.revokedLead(space, userId);
1432 }
1433 }
1434 }
1435 }
1436
1437
1438
1439
1440 public void unregisterSpaceListenerPlugin(SpaceListenerPlugin spaceListenerPlugin) {
1441 spaceLifeCycle.removeListener(spaceListenerPlugin);
1442 }
1443
1444 @Override
1445 @Deprecated
1446 public void setSpaceApplicationConfigPlugin(SpaceApplicationConfigPlugin spaceApplicationConfigPlugin) {
1447 LOG.warn("setSpaceApplicationConfigPlugin method has been deprecated, please use addSpaceTemplateConfigPlugin method from SpaceTemplateConfigPlugin class");
1448 }
1449
1450 @Override
1451 @Deprecated
1452 public SpaceApplicationConfigPlugin getSpaceApplicationConfigPlugin() {
1453 return null;
1454 }
1455
1456
1457
1458
1459 public Space updateSpace(Space existingSpace) {
1460 spaceStorage.saveSpace(existingSpace, false);
1461 if (UpdatedField.DESCRIPTION.equals(existingSpace.getField())) {
1462 spaceLifeCycle.spaceDescriptionEdited(existingSpace, existingSpace.getEditor());
1463 }
1464 return existingSpace;
1465 }
1466
1467 public Space updateSpaceAvatar(Space existingSpace) {
1468 checkSpaceEditorPermissions(existingSpace);
1469
1470 Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, existingSpace.getPrettyName());
1471 Profile profile = spaceIdentity.getProfile();
1472 if(existingSpace.getAvatarAttachment() != null) {
1473 profile.setProperty(Profile.AVATAR, existingSpace.getAvatarAttachment());
1474 } else {
1475 profile.removeProperty(Profile.AVATAR);
1476 profile.setAvatarUrl(null);
1477 profile.setAvatarLastUpdated(null);
1478 }
1479 identityStorage.updateProfile(profile);
1480 spaceLifeCycle.spaceAvatarEdited(existingSpace, existingSpace.getEditor());
1481 return existingSpace;
1482 }
1483
1484 public Space updateSpaceBanner(Space existingSpace) {
1485 checkSpaceEditorPermissions(existingSpace);
1486
1487 Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, existingSpace.getPrettyName());
1488 if (spaceIdentity != null) {
1489 Profile profile = spaceIdentity.getProfile();
1490 if (existingSpace.getBannerAttachment() != null) {
1491 profile.setProperty(Profile.BANNER, existingSpace.getBannerAttachment());
1492 } else {
1493 profile.removeProperty(Profile.BANNER);
1494 }
1495 identityStorage.updateProfile(profile);
1496 spaceLifeCycle.spaceBannerEdited(existingSpace, existingSpace.getEditor());
1497 } else {
1498 throw new IllegalStateException("Can not update space banner. Space identity " + existingSpace.getPrettyName() + " not found");
1499 }
1500 return existingSpace;
1501 }
1502
1503
1504
1505
1506 public ListAccess<Space> getInvitedSpacesWithListAccess(String userId) {
1507 return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.INVITED);
1508 }
1509
1510
1511
1512
1513 private String getPortletId(String appId) {
1514 final char SEPARATOR = '.';
1515
1516 if (appId.indexOf(SEPARATOR) != -1) {
1517 int beginIndex = appId.lastIndexOf(SEPARATOR) + 1;
1518 int endIndex = appId.length();
1519
1520 return appId.substring(beginIndex, endIndex);
1521 }
1522
1523 return appId;
1524 }
1525
1526 @Override
1527 public void updateSpaceAccessed(String remoteId, Space space) throws SpaceException {
1528 if (isMember(space, remoteId)) {
1529 spaceStorage.updateSpaceAccessed(remoteId, space);
1530 }
1531 }
1532
1533 @Override
1534 public List<Space> getLastAccessedSpace(String remoteId, String appId, int offset, int limit) throws SpaceException {
1535 SpaceFilter filter = new SpaceFilter(remoteId, appId);
1536 return spaceStorage.getLastAccessedSpace(filter, offset, limit);
1537 }
1538
1539 public List<Space> getLastSpaces(int limit) {
1540 return spaceStorage.getLastSpaces(limit);
1541 }
1542
1543 @Override
1544 public ListAccess<Space> getLastAccessedSpace(String remoteId, String appId) {
1545 return new SpaceListAccess(this.spaceStorage, remoteId, appId, SpaceListAccess.Type.LASTEST_ACCESSED);
1546 }
1547
1548 public ListAccess<Space> getVisitedSpaces(String remoteId, String appId) {
1549 return new SpaceListAccess(this.spaceStorage, remoteId, appId, SpaceListAccess.Type.VISITED);
1550 }
1551
1552
1553
1554
1555 @Override
1556 public boolean isSuperManager(String userId) {
1557 if (StringUtils.isBlank(userId) || IdentityConstants.ANONIM.equals(userId) || IdentityConstants.SYSTEM.equals(userId)) {
1558 return false;
1559 }
1560 if (userId.equals(getUserACL().getSuperUser())) {
1561 return true;
1562 }
1563 org.exoplatform.services.security.Identity identity = identityRegistry.getIdentity(userId);
1564 if (identity == null) {
1565 Collection<Membership> memberships;
1566 try {
1567 memberships = getOrgService().getMembershipHandler().findMembershipsByUser(userId);
1568 } catch (Exception e) {
1569 throw new RuntimeException("Can't get user '" + userId + "' memberships", e);
1570 }
1571 List<MembershipEntry> entries = new ArrayList<>();
1572 for (Membership membership : memberships) {
1573 entries.add(new MembershipEntry(membership.getGroupId(), membership.getMembershipType()));
1574 }
1575 identity = new org.exoplatform.services.security.Identity(userId, entries);
1576 }
1577 List<MembershipEntry> superManagersMemberships = spacesAdministrationService.getSpacesAdministratorsMemberships();
1578 if (superManagersMemberships != null && !superManagersMemberships.isEmpty()) {
1579 for (MembershipEntry superManagerMembership : superManagersMemberships) {
1580 if (identity.isMemberOf(superManagerMembership)) {
1581 return true;
1582 }
1583 }
1584 }
1585 return false;
1586 }
1587
1588 private String checkSpaceEditorPermissions(Space space) {
1589 String editor = space.getEditor();
1590
1591 if (StringUtils.isNotBlank(editor) && !hasEditPermission(space, editor)) {
1592 throw new IllegalStateException("User " + editor + " is not authorized to change space.");
1593 }
1594 return editor;
1595 }
1596 }