You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rave.apache.org by ps...@apache.org on 2012/05/30 19:01:48 UTC

svn commit: r1344349 - in /rave/trunk: rave-components/rave-core/src/main/java/org/apache/rave/portal/model/ rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/impl/ rave-components/rave-core/src/main/java/org/apache/rave/portal/...

Author: psharples
Date: Wed May 30 17:01:47 2012
New Revision: 1344349

URL: http://svn.apache.org/viewvc?rev=1344349&view=rev
Log:
Updates to the page sharing facility.  A user can share pages which by default are non-editable, but can also elect to give users 'editing' permissions - add, move, delete widgets etc on the page.  See RAVE-103. Also fixed the mobile view which had a bug (referred to old renderSequence in <PAGE>)

Modified:
    rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/PageUser.java
    rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/impl/JpaPageRepository.java
    rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultPagePermissionEvaluator.java
    rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionPermissionEvaluator.java
    rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionWidgetPermissionEvaluator.java
    rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java
    rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
    rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java
    rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/PageController.java
    rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/ProfileController.java
    rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java
    rave/trunk/rave-portal-resources/src/main/resources/messages.properties
    rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties
    rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/mobile_home.jsp
    rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp
    rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region.tag
    rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region_widget.tag
    rave/trunk/rave-portal-resources/src/main/webapp/script/rave.js
    rave/trunk/rave-portal-resources/src/main/webapp/script/rave_api.js
    rave/trunk/rave-portal-resources/src/main/webapp/script/rave_layout.js
    rave/trunk/rave-portal-resources/src/main/webapp/script/rave_opensocial.js

Modified: rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/PageUser.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/PageUser.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/PageUser.java (original)
+++ rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/PageUser.java Wed May 30 17:01:47 2012
@@ -69,6 +69,7 @@ public class PageUser implements BasicEn
     @JoinColumn(name = "page_id", nullable=false)
     private Page page;
     
+    @Basic(optional=false) @Column(name="editor")
     private boolean editor;
     
     @Basic(optional=false) @Column(name="render_sequence")

Modified: rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/impl/JpaPageRepository.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/impl/JpaPageRepository.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/impl/JpaPageRepository.java (original)
+++ rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/impl/JpaPageRepository.java Wed May 30 17:01:47 2012
@@ -95,6 +95,7 @@ public class JpaPageRepository extends A
         p.setOwner(user);
         PageUser pageUser = new PageUser(p.getOwner(), p, pt.getRenderSequence());
         pageUser.setPageStatus(PageInvitationStatus.OWNER);
+        pageUser.setEditor(true);
         List<PageUser> members = new ArrayList<PageUser>();
         members.add(pageUser);
         p.setMembers(members);
@@ -170,6 +171,7 @@ public class JpaPageRepository extends A
             // create new pageUser tuple
             PageUser pageUser = new PageUser(lPage.getOwner(), lPage, pt.getRenderSequence());
             pageUser.setPageStatus(PageInvitationStatus.OWNER);
+            pageUser.setEditor(true);
             List<PageUser> members = new ArrayList<PageUser>();
             members.add(pageUser);
             lPage.setMembers(members);

Modified: rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultPagePermissionEvaluator.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultPagePermissionEvaluator.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultPagePermissionEvaluator.java (original)
+++ rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultPagePermissionEvaluator.java Wed May 30 17:01:47 2012
@@ -118,11 +118,12 @@ public class DefaultPagePermissionEvalua
             case UPDATE:
                 // anyone can create, delete, or update a page that they own                  
                 hasPermission = isPageOwner(authentication, page, trustedPageContainer, trustedDomainObject)
-                || isPageMember(authentication, page, trustedPageContainer, trustedDomainObject);     
+                || isPageMember(authentication, page, trustedPageContainer, trustedDomainObject, true);
                 break;
             case READ:
                 // anyone can read a USER page they own or anyone's PERSON_PROFILE page
-                hasPermission = isReadablePage(authentication, page, trustedPageContainer, trustedDomainObject);
+                hasPermission = isReadablePage(authentication, page, trustedPageContainer, trustedDomainObject)
+                || isPageMember(authentication, page, trustedPageContainer, trustedDomainObject, false);
                 break;
             default:
                 log.warn("unknown permission: " + permission);
@@ -187,7 +188,7 @@ public class DefaultPagePermissionEvalua
     private boolean isReadablePage(Authentication authentication, Page page, List<Page> trustedPageContainer, boolean trustedDomainObject) {
         return isPersonProfilePageOrSubPage(page) ||
                isPageOwner(authentication, page, trustedPageContainer, trustedDomainObject) ||
-               isPageMember(authentication, page, trustedPageContainer, trustedDomainObject);
+               isPageMember(authentication, page, trustedPageContainer, trustedDomainObject, false);
     }
     
     private boolean isPersonProfilePageOrSubPage(Page page) {
@@ -199,7 +200,7 @@ public class DefaultPagePermissionEvalua
     // checks to see if the Authentication object principal is a member of the supplied page object 
     // if trustedDomainObject is false, pull the entity from the database first to ensure
     // the model object is trusted and hasn't been modified
-    private boolean isPageMember(Authentication authentication, Page page, List<Page> trustedPageContainer, boolean trustedDomainObject) {
+    private boolean isPageMember(Authentication authentication, Page page, List<Page> trustedPageContainer, boolean trustedDomainObject, boolean checkEditorStatus) {
         Page trustedPage = null;
         if (trustedDomainObject) {
             trustedPage = page;
@@ -219,6 +220,10 @@ public class DefaultPagePermissionEvalua
         for (PageUser pageUser:trustedPage.getMembers()){
             if (pageUser.getUser().getUsername().equals(viewer)){
                 log.info("User "+viewer+" is a member of page "+trustedPage.getEntityId());
+                if(checkEditorStatus){
+                    log.info("checking editor:"+trustedPage.getEntityId()+"@"+viewer+"@"+pageUser.isEditor());
+                    return pageUser.isEditor();
+                }
                 return true;
             }
         }

Modified: rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionPermissionEvaluator.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionPermissionEvaluator.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionPermissionEvaluator.java (original)
+++ rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionPermissionEvaluator.java Wed May 30 17:01:47 2012
@@ -18,7 +18,10 @@
  */
 package org.apache.rave.portal.security.impl;
 
+import org.apache.rave.portal.model.Page;
+import org.apache.rave.portal.model.PageUser;
 import org.apache.rave.portal.model.Region;
+import org.apache.rave.portal.model.RegionWidget;
 import org.apache.rave.portal.model.User;
 import org.apache.rave.portal.repository.RegionRepository;
 import org.slf4j.Logger;
@@ -109,11 +112,14 @@ public class DefaultRegionPermissionEval
                 break;
             case CREATE:
             case DELETE:
-            case READ:
             case UPDATE:
                 // anyone can create, delete, read, or update a region that they own
-                hasPermission = isRegionOwner(authentication, region, trustedRegionContainer, trustedDomainObject);
+                hasPermission = isRegionOwner(authentication, region, trustedRegionContainer, trustedDomainObject)
+                || isRegionMember(authentication, region, trustedRegionContainer, trustedDomainObject, true);
                 break;
+            case READ:
+                hasPermission = isRegionOwner(authentication, region, trustedRegionContainer, trustedDomainObject)
+                || isRegionMember(authentication, region, trustedRegionContainer, trustedDomainObject, false);
             default:
                 log.warn("unknown permission: " + permission);
                 break;
@@ -171,4 +177,35 @@ public class DefaultRegionPermissionEval
             throw new IllegalArgumentException("unknown RaveSecurityContext type: " + raveSecurityContext.getType());
         }
     }
+    
+    private boolean isRegionMember(Authentication authentication, Region region, List<Region> trustedRegionContainer, boolean trustedDomainObject, boolean checkEditorStatus) {
+        Region trustedRegion = null;
+        if (trustedDomainObject) {
+            trustedRegion = region;
+        } else {
+            trustedRegion = getTrustedRegion(region.getEntityId(), trustedRegionContainer);
+        }
+        
+        Page containerPage = trustedRegion.getPage();
+        
+        
+        if (containerPage.getMembers() == null){
+            return false;
+        }
+        //
+        // Check that the viewer is a member
+        //
+        String viewer = ((User)authentication.getPrincipal()).getUsername();
+        for (PageUser pageUser:containerPage.getMembers()){
+            if (pageUser.getUser().getUsername().equals(viewer)){
+                log.info("User "+viewer+" is a member of page "+containerPage.getEntityId());
+                if(checkEditorStatus){
+                    return pageUser.isEditor();
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
\ No newline at end of file

Modified: rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionWidgetPermissionEvaluator.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionWidgetPermissionEvaluator.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionWidgetPermissionEvaluator.java (original)
+++ rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/security/impl/DefaultRegionWidgetPermissionEvaluator.java Wed May 30 17:01:47 2012
@@ -18,6 +18,8 @@
  */
 package org.apache.rave.portal.security.impl;
 
+import org.apache.rave.portal.model.Page;
+import org.apache.rave.portal.model.PageUser;
 import org.apache.rave.portal.model.RegionWidget;
 import org.apache.rave.portal.model.User;
 import org.apache.rave.portal.repository.RegionWidgetRepository;
@@ -109,11 +111,14 @@ public class DefaultRegionWidgetPermissi
                 break;
             case CREATE:
             case DELETE:
-            case READ:
             case UPDATE:
                 // anyone can create, delete, read, or update a regionWidget that they own
-                hasPermission = isRegionWidgetOwner(authentication, regionWidget, trustedRegionWidgetContainer, trustedDomainObject);
+                hasPermission = isRegionWidgetOwner(authentication, regionWidget, trustedRegionWidgetContainer, trustedDomainObject)
+                || isRegionWidgetMember(authentication, regionWidget, trustedRegionWidgetContainer, trustedDomainObject, true);
                 break;
+            case READ:
+                hasPermission = isRegionWidgetOwner(authentication, regionWidget, trustedRegionWidgetContainer, trustedDomainObject)
+                || isRegionWidgetMember(authentication, regionWidget, trustedRegionWidgetContainer, trustedDomainObject, false);
             default:
                 log.warn("unknown permission: " + permission);
                 break;
@@ -175,4 +180,35 @@ public class DefaultRegionWidgetPermissi
     private String getUsernameFromRegionWidget(RegionWidget regionWidget) {
         return regionWidget.getRegion().getPage().getOwner().getUsername();
     }
+    
+    private boolean isRegionWidgetMember(Authentication authentication, 
+            RegionWidget regionWidget, List<RegionWidget> trustedRegionWidgetContainer, boolean trustedDomainObject, boolean checkEditorStatus) {
+        RegionWidget trustedRegionWidget = null;
+        if (trustedDomainObject) {
+            trustedRegionWidget = regionWidget;
+        } else {
+            trustedRegionWidget = getTrustedRegionWidget(regionWidget.getEntityId(), trustedRegionWidgetContainer);
+        }
+        
+        Page containerPage = trustedRegionWidget.getRegion().getPage();
+        
+        
+        if (containerPage.getMembers() == null){
+            return false;
+        }
+        //
+        // Check that the viewer is a member
+        //
+        String viewer = ((User)authentication.getPrincipal()).getUsername();
+        for (PageUser pageUser:containerPage.getMembers()){
+            if (pageUser.getUser().getUsername().equals(viewer)){
+                log.info("User "+viewer+" is a member of page "+containerPage.getEntityId());
+                if(checkEditorStatus){
+                    return pageUser.isEditor();
+                }
+                return true;
+            }
+        }
+        return false;
+    }
 }

Modified: rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java (original)
+++ rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java Wed May 30 17:01:47 2012
@@ -190,8 +190,8 @@ public interface PageService {
      *                        -1 if you want this to be the first page
      * @return the updated Page object containing its new render sequence
      */
-    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'update') and " +
-                  "hasPermission(#moveAfterPageId, 'org.apache.rave.portal.model.Page', 'update')")
+    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'read') and " +
+                  "hasPermission(#moveAfterPageId, 'org.apache.rave.portal.model.Page', 'read')")
     Page movePage(long pageId, long moveAfterPageId);
     
     /**
@@ -200,7 +200,7 @@ public interface PageService {
      * @param pageId the pageId of the page to move to the default position
      * @return the updated Page object containing its new render sequence
      */
-    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'update')") 
+    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'read')") 
     Page movePageToDefault(long pageId);
 
     /**
@@ -217,8 +217,10 @@ public interface PageService {
      * @param pageId - the id of the page in question
      * @param userId - the userid to add
      * @return -  whether the user was successfully removed or not
+     * Note: this is read access because a page shared to a non page owner means they have 'read' access
+     * unless they are set as an 'editor' of the page, which means 'update' access. 
      */
-    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'update')")
+    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'read')")
     Boolean removeMemberFromPage(long pageId, long userId);
 
     /**
@@ -227,6 +229,18 @@ public interface PageService {
      * @param shareStatus - a string value defined in PageStatus
      * @return
      */
-    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'update')")
+    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'read')")
     Boolean updateSharedPageStatus(long pageId, String shareStatus);
+
+    /**
+     * Update a user who has shared access to a given page, so that they can edit the page (true)
+     * or can only view it (false)
+     * @param pageId - the id of the page in question 
+     * @param userId - the userId of the user to assign the permission to
+     * @param isEditor - value to denote if the user can edit or not
+     * @return
+     */
+    @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.portal.model.Page', 'update')")
+    Boolean updatePageEditingStatus(long pageId, long userId, boolean isEditor);
+
 }
\ No newline at end of file

Modified: rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java (original)
+++ rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java Wed May 30 17:01:47 2012
@@ -357,6 +357,22 @@ public class DefaultPageService implemen
         }
     }
 
+    @Override
+    @Transactional
+    public Boolean updatePageEditingStatus(long pageId, long userId, boolean isEditor) {
+        Page page = this.getPage(pageId);
+        for(PageUser pageUser : page.getMembers()){
+            if(pageUser.getUser().equals(userService.getUserById(userId))){
+                pageUser.setEditor(isEditor);
+            }
+        }
+        if(pageRepository.save(page) != null){
+            return Boolean.TRUE;
+        }else{
+            return Boolean.FALSE;
+        }
+    }
+
     /**
      * Utility function to determine if a Page layout adjustment is needed
      * which comparing the existing and new PageLayout objects
@@ -500,6 +516,7 @@ public class DefaultPageService implemen
         page.setPageLayout(pageLayout);
         PageUser pageUser = new PageUser(page.getOwner(), page, renderSequence);
         pageUser.setPageStatus(PageInvitationStatus.OWNER);
+        pageUser.setEditor(true);
 
         List<PageUser> members = new ArrayList<PageUser>();
         members.add(pageUser);

Modified: rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java (original)
+++ rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java Wed May 30 17:01:47 2012
@@ -249,4 +249,15 @@ public class PageApi {
              }
         }.getResult();
     }
+
+    @ResponseBody
+    @RequestMapping(value = "{pageId}/editstatus", method = RequestMethod.POST)
+    public RpcResult<Boolean> updatePageEditingStatus(@PathVariable final long pageId, @RequestParam final long userId, @RequestParam final boolean isEditor) {
+        return new RpcOperation<Boolean>() {
+             @Override
+             public Boolean execute() {
+               return pageService.updatePageEditingStatus(pageId, userId, isEditor);
+             }
+        }.getResult();
+    }
 }
\ No newline at end of file

Modified: rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/PageController.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/PageController.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/PageController.java (original)
+++ rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/PageController.java Wed May 30 17:01:47 2012
@@ -84,7 +84,7 @@ public class PageController {
         List<PageLayout> pageLayouts = pageLayoutService.getAllUserSelectable();
         addAttributesToModel(model, page, currentPageUser, pages, pageLayouts);
         String view = ControllerUtils.getDeviceAppropriateView(request, ViewNames.getPageView(page.getPageLayout().getCode()), ViewNames.MOBILE_HOME);
-        ControllerUtils.addNavItemsToModel(view, model, page.getEntityId(), userService.getAuthenticatedUser());
+        ControllerUtils.addNavItemsToModel(view, model, page.getEntityId(), userService.getAuthenticatedUser(), currentPageUser.isEditor());
         return view;
     }
     
@@ -103,7 +103,7 @@ public class PageController {
             List<PageLayout> pageLayouts = pageLayoutService.getAllUserSelectable();
             addAttributesToModel(model, page, currentPageUser, pages, pageLayouts);
             String view = ControllerUtils.getDeviceAppropriateView(request, ViewNames.getPageView(page.getPageLayout().getCode()), ViewNames.MOBILE_HOME);
-            ControllerUtils.addNavItemsToModel(view, model, page.getEntityId(), thisUser);
+            ControllerUtils.addNavItemsToModel(view, model, page.getEntityId(), thisUser, currentPageUser.isEditor());
             return view;
         } catch (Exception e) {
             logger.info("unable to get page - possibly because a shared page was revoked by its owner");

Modified: rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/ProfileController.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/ProfileController.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/ProfileController.java (original)
+++ rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/ProfileController.java Wed May 30 17:01:47 2012
@@ -114,7 +114,7 @@ public class ProfileController {
 
     public static void addNavItemsToModel(String view, ModelMap model, Long referringPageId, User user) {
         long refPageId = referringPageId != null ? referringPageId : 0;
-        final NavigationMenu topMenu = ControllerUtils.getTopMenu(view, refPageId, user);
+        final NavigationMenu topMenu = ControllerUtils.getTopMenu(view, refPageId, user, false);
         model.addAttribute(topMenu.getName(), topMenu);
     }
 }

Modified: rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java
URL: http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java (original)
+++ rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java Wed May 30 17:01:47 2012
@@ -61,19 +61,25 @@ public class ControllerUtils {
     }
 
     public static void addNavItemsToModel(String view, Model model, long referringPageId, User user) {
-        final NavigationMenu topMenu = getTopMenu(view, referringPageId, user);
+        final NavigationMenu topMenu = getTopMenu(view, referringPageId, user, true);
         model.addAttribute(topMenu.getName(), topMenu);
     }
 
-    public static NavigationMenu getTopMenu(String view, long referringPageId, User user) {
+    public static void addNavItemsToModel(String view, Model model, long referringPageId, User user, boolean addStore) {
+        final NavigationMenu topMenu = getTopMenu(view, referringPageId, user, addStore);
+        model.addAttribute(topMenu.getName(), topMenu);
+    }
+    
+    public static NavigationMenu getTopMenu(String view, long referringPageId, User user, boolean addStoreLink) {
         NavigationMenu menu = new NavigationMenu("topnav");
-
-        if(view.startsWith(ViewNames.PAGE)) {
+        if(view.startsWith(ViewNames.PAGE) || view.startsWith(ViewNames.MOBILE_HOME)) {
             NavigationItem profile = new NavigationItem("page.profile.title", user.getDisplayName() != null ? user.getDisplayName() : user.getUsername(), "/app/person/" + user.getUsername() + "?referringPageId=" + referringPageId);
             menu.addNavigationItem(profile);
 
-            NavigationItem store = new NavigationItem("page.store.title", null, "/app/store?referringPageId=" + referringPageId);
-            menu.addNavigationItem(store);
+            if(addStoreLink){
+                NavigationItem store = new NavigationItem("page.store.title", null, "/app/store?referringPageId=" + referringPageId);
+                menu.addNavigationItem(store);
+            }
 
             NavigationItem admin = getAdminItem();
             menu.addNavigationItem(admin);

Modified: rave/trunk/rave-portal-resources/src/main/resources/messages.properties
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/resources/messages.properties?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/resources/messages.properties (original)
+++ rave/trunk/rave-portal-resources/src/main/resources/messages.properties Wed May 30 17:01:47 2012
@@ -55,6 +55,7 @@ page.general.deletepage=Delete Page
 page.general.editpage=Edit Page
 page.general.email=Email address:
 page.general.empty=Add widgets to this page
+page.general.non.editing.empty=There are currently no widgets on this page.
 page.general.logout=Logout
 page.general.movepage=Move Page
 page.general.movethispage=Move this page:
@@ -356,6 +357,7 @@ _rave_client.common.accept=Accept
 _rave_client.common.decline=Decline
 _rave_client.common.username=Username
 _rave_client.common.sharing=Sharing
+_rave_client.common.editing.auth=Edit Permission 
 _rave_client.form.password.invalid_match=The password does not match
 _rave_client.opensocial.render_error=Unable to render OpenSocial Gadget:
 _rave_client.page.add=Add a New Page
@@ -374,4 +376,6 @@ _rave_client.create.share.confirm=Are yo
 _rave_client.revoke.share.confirm=Are you sure you wish to remove this user?
 _rave_client.revoke.share.current.user=Your share to this page has been successfully removed
 _rave_client.revoke.share.current.user.confirm=Are you sure you wish to remove this shared page?
+_rave_client.grant.editing.user.confirm=Are you sure you wish to give editing rights to the following user?
+_rave_client.revoke.editing.user.confirm=Are you sure you wish to remove editing rights from the following user?
 _rave_client.no.results.found=No results found

Modified: rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties (original)
+++ rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties Wed May 30 17:01:47 2012
@@ -57,6 +57,7 @@ page.general.deletepage=Verwijder pagina
 page.general.editpage=Pas pagina aan
 page.general.email=E-mail adres\:
 page.general.empty=Voeg widgets aan deze pagina toe
+page.general.non.editing.empty=Er zijn momenteel geen widgets op deze pagina.
 page.general.logout=Uitloggen
 page.general.movepage=Verplaats pagina
 page.general.movethispage=Verplaats deze pagina:
@@ -367,6 +368,7 @@ _rave_client.common.accept=Accepteer
 _rave_client.common.decline=Wijs af	
 _rave_client.common.username=Gebruikersnaam	
 _rave_client.common.sharing=Delen
+_rave_client.common.editing.auth=Geef Toestemming uit
 _rave_client.form.password.invalid_match=Het wachtwoord komt niet overeen
 _rave_client.opensocial.render_error=Kan OpenSocial Gadget niet weergeven\:
 _rave_client.page.add=Voeg een nieuwe pagina toe
@@ -385,4 +387,6 @@ _rave_client.create.share.confirm=Weet j
 _rave_client.revoke.share.confirm=Weet je zeker dat je deze gebruiker wilt verwijderen?
 _rave_client.revoke.share.current.user=Deze pagina is niet langer gedeeld.
 _rave_client.revoke.share.current.user.confirm=Weet je zeker dat je deze gedeelde pagina wilt verwijderen?
+_rave_client.grant.editing.user.confirm=Bent zeker u u wenst om het uitgeven rechten op de volgende gebruiker te geven?
+_rave_client.revoke.editing.user.confirm=Bent zeker u u wenst om het uitgeven rechten uit de volgende gebruiker te verwijderen?
 _rave_client.no.results.found=Geen resultaten gevonden

Modified: rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/mobile_home.jsp
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/mobile_home.jsp?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/mobile_home.jsp (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/mobile_home.jsp Wed May 30 17:01:47 2012
@@ -21,36 +21,19 @@
 <fmt:setBundle basename="messages"/>
 <jsp:useBean id="pages" type="java.util.List<org.apache.rave.portal.model.Page>" scope="request"/>
 <%--@elvariable id="page" type="org.apache.rave.portal.model.Page"--%>
-    <header class="header-mobile">
-        <nav class="topnav">
-            <ul class="horizontal-list">
-                <li>
-                    <a href="<spring:url value="/app/store?referringPageId=${page.entityId}" />">
-                      <fmt:message key="page.store.title"/>
-                    </a>
-                </li>
-                <sec:authorize url="/app/admin/">
-                <li>
-                    <a href="<spring:url value="/app/admin/"/>">
-                        <fmt:message key="page.general.toadmininterface"/>
-                    </a>
-                </li>
-                </sec:authorize>
-                <li>
-                    <a href="<spring:url value="/j_spring_security_logout" htmlEscape="true" />">
-                      <fmt:message key="page.general.logout"/></a>
-                </li>
-            </ul>
-        </nav>
-        <h1>
-            <fmt:message key="page.home.welcome"><fmt:param>
-                <c:choose>
-                    <c:when test="${not empty page.owner.displayName}"><c:out value="${page.owner.displayName}"/></c:when>
-                    <c:otherwise><c:out value="${page.owner.username}"/></c:otherwise>
-                </c:choose>
-            </fmt:param></fmt:message>
-        </h1>
-    </header>
+<sec:authentication property="principal.username" var="principleUsername" scope="request"/>
+<sec:authentication property="principal.displayName" var="displayName" scope="request"/>
+
+<fmt:message key="page.home.welcome" var="pagetitle">
+    <fmt:param>
+        <c:choose>
+            <c:when test="${not empty displayName}"><c:out value="${displayName}"/></c:when>
+            <c:otherwise><c:out value="${principleUsername}"/></c:otherwise>
+        </c:choose>
+    </fmt:param>
+</fmt:message>
+<rave:navbar pageTitle="${pagetitle}"/>
+
     <input id="currentPageId" type="hidden" value="${page.entityId}" />
     <c:set var="hasOnlyOnePage" scope="request">
         <c:choose>
@@ -125,7 +108,7 @@
         <div><fmt:message key="page.general.movethispage"/></div>
         <form id="movePageForm">
             <select id="moveAfterPageId">
-                <c:if test="${page.renderSequence != 1}">
+                <c:if test="${pageUser.renderSequence != 1}">
                     <option value="-1"><fmt:message key="page.general.movethispage.tofirst"/></option>
                 </c:if>
                 <c:forEach var="userPage" items="${pages}">
@@ -159,6 +142,7 @@
 <portal:register-init-script location="${'AFTER_RAVE'}">
     <script>
         $(function() {
+            rave.initPageEditorStatus(<c:out value="${pageUser.editor}"/>);
             rave.setMobile(true);
             rave.initProviders();
             rave.initWidgets();

Modified: rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp Wed May 30 17:01:47 2012
@@ -44,6 +44,7 @@
         <c:otherwise>false</c:otherwise>
     </c:choose>
 </c:set>
+<c:set var="canMoveWidgetsToEditablePage" scope="request" value="false"/>
 
 <div id="pageContent" class="container-fluid">
     <nav>
@@ -113,10 +114,14 @@
                                      <a href="#"><c:out value="${userPage.name}"/></a>
                                 </c:otherwise>
                             </c:choose>
-
                         </li>
                     </c:otherwise>
                 </c:choose>
+                <c:forEach var="members" items="${userPage.members}">
+                    <c:if test="${members.user.username == principleUsername and members.editor and userPage.entityId != page.entityId}">
+                        <c:set var="canMoveWidgetsToEditablePage" scope="request" value="true"/>
+                    </c:if>
+               </c:forEach>
             </c:forEach>
             <li id="addPageButton"><a href="#"><i class="icon-plus"></i></a></li>
         </ul>
@@ -126,7 +131,14 @@
     <div class="row-fluid">
         <div id="emptyPageMessageWrapper" class="emptyPageMessageWrapper hidden">
             <div class="emptyPageMessage">
-                <a href="<spring:url value="/app/store?referringPageId=${page.entityId}" />"><fmt:message key="page.general.empty"/></a>
+                <c:choose>
+                    <c:when test="${pageUser.editor == true}">
+                        <a href="<spring:url value="/app/store?referringPageId=${page.entityId}" />"><fmt:message key="page.general.empty"/></a>
+                    </c:when>
+                    <c:otherwise>
+                        <fmt:message key="page.general.non.editing.empty"/>
+                    </c:otherwise>
+                </c:choose>
             </div>
         </div>
         <div class="regions">
@@ -223,11 +235,13 @@
                         <div class="controls">
                             <select id="moveToPageId">
                                 <c:forEach var="userPage" items="${pages}">
-                                    <c:if test="${userPage.entityId != page.entityId}">
-                                        <option value="${userPage.entityId}">
-                                            <c:out value="${userPage.name}"/>
-                                        </option>
-                                    </c:if>
+                                    <c:forEach var="members" items="${userPage.members}">
+                                        <c:if test="${members.user.username == principleUsername and members.editor and userPage.entityId != page.entityId}">
+                                            <option value="${userPage.entityId}">
+                                                <c:out value="${userPage.name}"/>
+                                            </option>
+                                        </c:if>
+                                    </c:forEach>
                                 </c:forEach>
                             </select>
                         </div>
@@ -285,6 +299,7 @@
 <portal:register-init-script location="${'AFTER_RAVE'}">
     <script>
         $(function() {
+            rave.initPageEditorStatus(<c:out value="${pageUser.editor}"/>);
             rave.initProviders();
             rave.initWidgets();
             rave.initUI();
@@ -293,6 +308,6 @@
         });
     </script>
     <c:forEach var="members" items="${page.members}">
-        <script>rave.layout.searchHandler.addExistingMember("${members.user.username}");</script>
+        <script>rave.layout.searchHandler.addExistingMember("${members.user.username}",${members.editor});</script>
     </c:forEach>
 </portal:register-init-script>

Modified: rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region.tag
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region.tag?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region.tag (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region.tag Wed May 30 17:01:47 2012
@@ -30,7 +30,7 @@ Template for rendering a Region on a pag
 <fmt:setBundle basename="messages"/>
 
 <%--@elvariable id="region" type="org.apache.rave.portal.model.Region"--%>
-<div class="region<c:if test="${region.locked}"> region-locked</c:if> <c:out value="${region.page.pageLayout.code}"/>_${regionIdx} regionNonDragging" id="region-${region.entityId}-id">
+<div class="region<c:if test="${region.locked || pageUser.editor == false}"> region-locked</c:if> <c:out value="${region.page.pageLayout.code}"/>_${regionIdx} regionNonDragging" id="region-${region.entityId}-id">
     <c:forEach var="regionWidget" items="${region.regionWidgets}">
         <rave:region_widget regionWidget="${regionWidget}"/>
     </c:forEach>

Modified: rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region_widget.tag
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region_widget.tag?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region_widget.tag (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/tags/region_widget.tag Wed May 30 17:01:47 2012
@@ -70,12 +70,12 @@ Template for rendering a RegionWidget in
                                 <fmt:message key="widget.menu.maximize"/>
                             </a>
                         </li>
-                        <li id="widget-${regionWidget.entityId}-menu-move-item" <c:if test='${hasOnlyOnePage}'>class="menu-item-disabled"</c:if>>
+                        <li id="widget-${regionWidget.entityId}-menu-move-item" <c:if test='${hasOnlyOnePage or pageUser.editor == false or canMoveWidgetsToEditablePage == false}'>class="menu-item-disabled"</c:if>>
                             <a href="#">
                                 <fmt:message key="widget.menu.movetopage"/>
                             </a>
                         </li>
-                        <li id="widget-${regionWidget.entityId}-menu-delete-item">
+                        <li id="widget-${regionWidget.entityId}-menu-delete-item" <c:if test='${pageUser.editor == false}'>class="menu-item-disabled"</c:if>>
                             <a href="#">
                                 <fmt:message key="widget.menu.delete"/>
                             </a>

Modified: rave/trunk/rave-portal-resources/src/main/webapp/script/rave.js
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/script/rave.js?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/script/rave.js (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/script/rave.js Wed May 30 17:01:47 2012
@@ -23,6 +23,9 @@ var rave = rave || (function () {
     var context = "";
     var clientMessages = {};
     var openAjaxHub;
+    // variable to store whether or not some
+    // UI actions should be propagated back to the server
+    var pageEditor = true;
 
     /**
      * Separate sub-namespace for isolating UI functions and state management
@@ -469,7 +472,7 @@ var rave = rave || (function () {
             // don't persist the collapse / restore state if we are in
             // mobile mode because we defaulted all widgets to collapsed
             // when initially rendering the mobile view
-            if (rave.isMobile()) {
+            if (rave.isMobile() || !rave.isPageEditor()) {
                 rave.doWidgetUiCollapse(functionArgs);
             } else {
                 rave.api.rest.saveWidgetCollapsedState(functionArgs);
@@ -1036,6 +1039,16 @@ var rave = rave || (function () {
         }
     }
 
+    function initPageEditorStatus(status){
+        if(status != "undefined"){
+            this.pageEditor = status;
+        }
+     }
+
+    function isPageEditor(){
+        return this.pageEditor;
+    }
+
     /**
      * Public API
      */
@@ -1292,6 +1305,20 @@ var rave = rave || (function () {
         /**
          * Registers a new popup definition
          */
-        registerPopup:ui.registerPopup
+        registerPopup:ui.registerPopup,
+
+        /**
+         * Set if user of a page has editing permission
+         * Used to stop sending UI events back to the server, rather
+         * than actually implementing any permission rules
+         * (which are set on the server)
+         */
+        initPageEditorStatus:initPageEditorStatus,
+
+        /**
+         * Returns a boolean indicating if the user
+         * should be treated as an page editor or not
+         */
+        isPageEditor:isPageEditor
     }
 })();

Modified: rave/trunk/rave-portal-resources/src/main/webapp/script/rave_api.js
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/script/rave_api.js?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/script/rave_api.js (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/script/rave_api.js Wed May 30 17:01:47 2012
@@ -489,7 +489,7 @@ rave.api = rave.api || (function() {
                     }
                 }).error(handleError);
         }
-        
+
         function updateSharedPageStatus(args){
             $.post(rave.getContext() + path + "page/" + args.pageId + "/sharestatus",
                 {"shareStatus": args.shareStatus},
@@ -505,6 +505,22 @@ rave.api = rave.api || (function() {
             }).error(handleError);
         }
         
+        function updatePageEditingStatus(args){
+            $.post(rave.getContext() + path + "page/" + args.pageId + "/editstatus",
+                {"userId": args.userId,
+                "isEditor": args.isEditor},
+                function(result) {
+                    if (result.error) {
+                        handleRpcError(result);
+                    }
+                    else {
+                        if (typeof args.successCallback == 'function') {
+                            args.successCallback(result);
+                        }
+                    }
+            }).error(handleError);
+        }
+        
         return {
             moveWidget : moveWidgetOnPage,
             addWidgetToPage : addWidgetToPage,
@@ -520,7 +536,8 @@ rave.api = rave.api || (function() {
             searchUsers : searchUsers,
             addMemberToPage : addMemberToPage,
             removeMemberFromPage : removeMemberFromPage,
-            updateSharedPageStatus : updateSharedPageStatus
+            updateSharedPageStatus : updateSharedPageStatus,
+            updatePageEditingStatus: updatePageEditingStatus
         };
 
     })();

Modified: rave/trunk/rave-portal-resources/src/main/webapp/script/rave_layout.js
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/script/rave_layout.js?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/script/rave_layout.js (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/script/rave_layout.js Wed May 30 17:01:47 2012
@@ -136,9 +136,12 @@ rave.layout = rave.layout || (function()
         var username;
         var userId;
         var pageId;
-        var existingSharers = new Array();
+        var existingSharers;
 
         function setDefaults(username, userId, pageId, pageStatus){
+            if(this.existingSharers == "undefined" || this.existingSharers == null){
+                this.existingSharers = {};
+            }
             this.username = username;
             this.userId = userId;
             this.pageId = pageId;
@@ -147,21 +150,35 @@ rave.layout = rave.layout || (function()
             };
         }
 
-        function addExistingMember(member){
-            existingSharers.push(member);
+        function addExistingMember(member, isEditor){
+            if(this.existingSharers == "undefined" || this.existingSharers == null){
+                this.existingSharers = {};
+            }
+            this.existingSharers[member] = isEditor;
         }
 
         function removeExistingMember(member){
-            existingSharers.splice( $.inArray(member, existingSharers), 1 );
+            delete this.existingSharers[member];
         }
 
         function isUserAlreadyAdded(username){
-            if($.inArray(username, existingSharers) == -1){
-                return false;
+            for(member in this.existingSharers){
+                if(username == member){
+                    return true;
+                }
             }
-            else{
-                return true;
+            return false;
+        }
+
+        function isUserEditor(username){
+            for(member in this.existingSharers){
+                if(username == member){
+                    if(this.existingSharers[member] == true){
+                        return true;
+                    }
+                }
             }
+            return false;
         }
 
         function removeMemberFromPage(userId, username){
@@ -176,6 +193,7 @@ rave.layout = rave.layout || (function()
                 rave.api.rpc.removeMemberFromPage({pageId: this.pageId, userId: userId,
                     successCallback: function(result) {
                         rave.layout.searchHandler.removeExistingMember(username);
+                        $('#pageEditorStatusHolder'+userId).empty();
                         $('#shareButtonHolder'+userId).empty();
                         $('#shareButtonHolder'+userId)
                             .append(
@@ -191,7 +209,7 @@ rave.layout = rave.layout || (function()
                                 // reload as page has been removed
                                 document.location.href='/';
                             }else{
-                            	alert("(" + username + ") " + rave.getClientMessage("revoke.share"));
+                                alert("(" + username + ") " + rave.getClientMessage("revoke.share"));
                             }
                     }
                 });
@@ -215,15 +233,68 @@ rave.layout = rave.layout || (function()
                                         userId+", '" + username+"');")
                                     .text(rave.getClientMessage("common.remove"))
                             )
-                            $('#shareButtonHolder'+userId).show();
+                        $('#shareButtonHolder'+userId).show();
+                        $('#pageEditorStatusHolder'+userId).empty();
+                        $('#pageEditorStatusHolder'+userId)
+                                .append(
+                                    $("<a/>")
+                                    .attr("href", "#")
+                                    .attr("id", userId)
+                                    .attr("onclick", "rave.layout.searchHandler.addEditingRightsToMember("+userId+", '"+username+"');")
+                                    .text(rave.getClientMessage("common.add"))
+                                )
                         alert("(" + username + ") " + rave.getClientMessage("create.share"));
                     }
                 });
             }
         }
-        
+
+        function removeEditingRightsFromMember(userId, username){
+            var answer = confirm(rave.getClientMessage("revoke.editing.user.confirm") + " ("+username+")");
+            if(answer){
+                $('#pageEditorStatusHolder'+userId).hide();
+                rave.api.rpc.updatePageEditingStatus({pageId: this.pageId, userId: userId, isEditor: false,
+                    successCallback: function(result) {
+                        rave.layout.searchHandler.existingSharers[username] = false;
+                        $('#pageEditorStatusHolder'+userId).empty();
+                        $('#pageEditorStatusHolder'+userId)
+                                .append(
+                                    $("<a/>")
+                                    .attr("href", "#")
+                                    .attr("id", userId)
+                                    .attr("onclick", "rave.layout.searchHandler.addEditingRightsToMember("+userId+", '"+username+"');")
+                                    .text(rave.getClientMessage("common.add"))
+                                )
+                         $('#pageEditorStatusHolder'+userId).show();
+                    }
+                });
+            }
+        }
+
+        function addEditingRightsToMember(userId, username){
+            var answer = confirm(rave.getClientMessage("grant.editing.user.confirm") + " ("+username+")");
+            if(answer){
+                $('#pageEditorStatusHolder'+userId).hide();
+                rave.api.rpc.updatePageEditingStatus({pageId: this.pageId, userId: userId, isEditor: true,
+                    successCallback: function(result) {
+                        rave.layout.searchHandler.existingSharers[username] = true;
+                        $('#pageEditorStatusHolder'+userId).empty();
+                        $('#pageEditorStatusHolder'+userId)
+                                .append(
+                                    $("<a/>")
+                                    .attr("href", "#")
+                                    .attr("id", userId)
+                                    .attr("onclick", "rave.layout.searchHandler.removeEditingRightsFromMember("+userId+", '"+username+"');")
+                                    .text(rave.getClientMessage("common.remove"))
+                                )
+                            $('#pageEditorStatusHolder'+userId).show();
+                    }
+                });
+            }
+        }
+
         function acceptShare(){
-        	$('#confirmSharePageDialog').modal('hide');
+            $('#confirmSharePageDialog').modal('hide');
             rave.api.rpc.updateSharedPageStatus({pageId: rave.layout.searchHandler.pageId, shareStatus: 'accepted',
                 successCallback: function(result) {
                     //notification here?
@@ -232,7 +303,7 @@ rave.layout = rave.layout || (function()
         }
 
         function declineShare(){
-        	$('#confirmSharePageDialog').modal('hide');
+            $('#confirmSharePageDialog').modal('hide');
             rave.api.rpc.updateSharedPageStatus({pageId: rave.layout.searchHandler.pageId, shareStatus: 'refused',
                 successCallback: function(result) {
                     document.location.href='/';
@@ -241,7 +312,7 @@ rave.layout = rave.layout || (function()
         }
 
         function confirmPageShare(){
-        	$("#confirmSharePageDialog").modal('show');
+            $("#confirmSharePageDialog").modal('show');
         }
 
         function init() {
@@ -279,7 +350,7 @@ rave.layout = rave.layout || (function()
             var $pagingDiv = $('#shareSearchListPaging');
             $pagingDiv.empty();
             if(userResults.result.pageSize < userResults.result.totalResults){
-                $pagingDiv.append('<ul id="pagingul" class="paging" style="margin-left: 0;">');
+                $pagingDiv.append('<div class="pagination"><ul id="pagingul" >');
                 if(userResults.result.currentPage > 1){
                     offset = (userResults.result.currentPage - 2) * userResults.result.pageSize;
                     $('#pagingul').append('<li><a href="#" onclick="rave.api.rpc.getUsers({offset: ' + 
@@ -288,7 +359,7 @@ rave.layout = rave.layout || (function()
                 }
                 for(var i=1;i<=userResults.result.numberOfPages;i++){
                     if(i == userResults.result.currentPage){
-                        $('#pagingul').append('<li><span class="currentPage">'+i+'</span></li>');
+                        $('#pagingul').append('<li class="active"><a href="#">'+i+'</a></li>');
                     }else{
                         offset = (i - 1) * userResults.result.pageSize;
                         $('#pagingul').append('<li><a href="#" onclick="rave.api.rpc.getUsers({offset: ' + 
@@ -302,6 +373,7 @@ rave.layout = rave.layout || (function()
                         offset + ', successCallback: function(result)' + 
                             ' {rave.layout.searchHandler.dealWithUserResults(result);}});">&gt;</a></li>');
                 }
+                $pagingDiv.append('</ul></div>')
             }
         }
 
@@ -349,6 +421,14 @@ rave.layout = rave.layout || (function()
                                             .text(rave.getClientMessage("common.sharing"))
                                         )
                                     )
+                                    .append(
+                                        $("<td/>")
+                                        .addClass("booleancell")
+                                        .append(
+                                            $("<b/>")
+                                            .text(rave.getClientMessage("common.editing.auth"))
+                                        )
+                                    )
                                 )
                         .append(
                             $("<tbody/>")
@@ -369,6 +449,10 @@ rave.layout = rave.layout || (function()
                             $("<td/>")
                             .attr("id", "shareButtonHolder" + this.entityId)
                         )
+                        .append(
+                            $("<td/>")
+                            .attr("id", "pageEditorStatusHolder" + this.entityId)
+                        )
                     )
 
                     if(this.username != rave.layout.searchHandler.username){
@@ -382,6 +466,26 @@ rave.layout = rave.layout || (function()
                                 .attr("onclick", "rave.layout.searchHandler.removeMemberFromPage("+this.entityId+", '"+this.username+"');")
                                 .text(rave.getClientMessage("common.remove"))
                             )
+                            if(rave.layout.searchHandler.isUserEditor(this.username)){
+                                $('#pageEditorStatusHolder'+this.entityId)
+                                .append(
+                                    $("<a/>")
+                                    .attr("href", "#")
+                                    .attr("id", this.entityId)
+                                    .attr("onclick", "rave.layout.searchHandler.removeEditingRightsFromMember("+this.entityId+", '"+this.username+"');")
+                                    .text(rave.getClientMessage("common.remove"))
+                                )
+                            }
+                            else{
+                                $('#pageEditorStatusHolder'+this.entityId)
+                                .append(
+                                    $("<a/>")
+                                    .attr("href", "#")
+                                    .attr("id", this.entityId)
+                                    .attr("onclick", "rave.layout.searchHandler.addEditingRightsToMember("+this.entityId+", '"+this.username+"');")
+                                    .text(rave.getClientMessage("common.add"))
+                                )
+                            }
                         }else{
                             $('#shareButtonHolder'+this.entityId)
                             .append(
@@ -390,7 +494,7 @@ rave.layout = rave.layout || (function()
                                 .attr("id", this.entityId)
                                 .attr("onclick", "rave.layout.searchHandler.addMemberToPage("+this.entityId+", '"+this.username+"');")
                                 .text(rave.getClientMessage("common.add"))
-                                )
+                            )
                         } 
                     }
                  
@@ -404,8 +508,11 @@ rave.layout = rave.layout || (function()
             addExistingMember : addExistingMember,
             removeExistingMember : removeExistingMember,
             isUserAlreadyAdded : isUserAlreadyAdded,
+            isUserEditor : isUserEditor,
             addMemberToPage : addMemberToPage,
             removeMemberFromPage : removeMemberFromPage,
+            addEditingRightsToMember: addEditingRightsToMember,
+            removeEditingRightsFromMember : removeEditingRightsFromMember,
             confirmPageShare : confirmPageShare,
             acceptShare : acceptShare,
             declineShare : declineShare

Modified: rave/trunk/rave-portal-resources/src/main/webapp/script/rave_opensocial.js
URL: http://svn.apache.org/viewvc/rave/trunk/rave-portal-resources/src/main/webapp/script/rave_opensocial.js?rev=1344349&r1=1344348&r2=1344349&view=diff
==============================================================================
--- rave/trunk/rave-portal-resources/src/main/webapp/script/rave_opensocial.js (original)
+++ rave/trunk/rave-portal-resources/src/main/webapp/script/rave_opensocial.js Wed May 30 17:01:47 2012
@@ -168,7 +168,9 @@ rave.opensocial = rave.opensocial || (fu
         };
         gadget.savePreferences = function (userPrefs) {
             this.userPrefs = userPrefs;
-            rave.api.rest.saveWidgetPreferences({regionWidgetId:this.regionWidgetId, userPrefs:userPrefs});
+            if(rave.isPageEditor()){
+                rave.api.rest.saveWidgetPreferences({regionWidgetId:this.regionWidgetId, userPrefs:userPrefs});
+            }
             // re-render the gadget in the same view if the gadget is not collapsed
             renderGadgetViewIfNotCollapsed(rave.opensocial.getCurrentView(this.regionWidgetId), this);
         };
@@ -326,7 +328,9 @@ rave.opensocial = rave.opensocial || (fu
         // update the memory prefs object
         regionWidget.userPrefs[prefName] = prefValue;
         // persist it to database
-        rave.api.rest.saveWidgetPreference({regionWidgetId:widgetId, userPref:{prefName:prefName, prefValue:prefValue}});
+        if(rave.isPageEditor()){
+            rave.api.rest.saveWidgetPreference({regionWidgetId:widgetId, userPref:{prefName:prefName, prefValue:prefValue}});
+        }
     }
 
     /**