/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/site-manage/trunk/site-manage-tool/tool/src/java/org/sakaiproject/site/tool/MembershipAction.java $ * $Id: MembershipAction.java 131985 2013-11-26 22:37:11Z gjthomas@iu.edu $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.site.tool; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Vector; import org.sakaiproject.cheftool.Context; import org.sakaiproject.cheftool.JetspeedRunData; import org.sakaiproject.cheftool.PagedResourceActionII; import org.sakaiproject.cheftool.RunData; import org.sakaiproject.cheftool.VelocityPortlet; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.event.api.SessionState; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.InUseException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.javax.PagingPosition; import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.site.util.SiteTextEditUtil; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.userauditservice.api.UserAuditRegistration; import org.sakaiproject.userauditservice.api.UserAuditService; import org.sakaiproject.util.ResourceLoader; /** * <p> * MembershipAction is a tool which displays Sites and lets the user join and un-join joinable Sites. * </p> */ public class MembershipAction extends PagedResourceActionII { private static String STATE_VIEW_MODE = "state_view"; private static ResourceLoader rb = new ResourceLoader("membership"); private static String SORT_ASC = "sort_asc"; private static String JOINABLE_SORT_ASC = "sort_asc"; private static String STATE_CONFIRM_VIEW_MODE = "state_confirm_view"; private static String UNJOIN_SITE = "unjoin_site"; private static String SEARCH_TERM = "search"; private static final String STATE_TOP_PAGE_MESSAGE = "msg-top"; private static UserAuditRegistration userAuditRegistration = (UserAuditRegistration) ComponentManager.get("org.sakaiproject.userauditservice.api.UserAuditRegistration.membership"); private static UserAuditService userAuditService = (UserAuditService) ComponentManager.get(UserAuditService.class); private static UserDirectoryService userDirectoryService = (UserDirectoryService) ComponentManager.get(UserDirectoryService.class); /* * (non-Javadoc) * * @see org.sakaiproject.cheftool.PagedResourceActionII#sizeResources(org.sakaiproject.service.framework.session.SessionState) */ protected int sizeResources(SessionState state) { int size = 0; String search = (String) state.getAttribute(SEARCH_TERM); if ((search != null) && search.trim().equals("")) { search = null; } boolean defaultMode = state.getAttribute(STATE_VIEW_MODE) == null; if (defaultMode) { List unjoinableSites = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.ACCESS, null, null, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_ASC, null); size=unjoinableSites.size(); } else { List openSites = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.JOINABLE, // null, null, null, org.sakaiproject.service.legacy.site.SiteService.SortType.TITLE_ASC, null); null, search, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_ASC, null); size = openSites.size(); } return size; } /* * (non-Javadoc) * * @see org.sakaiproject.cheftool.PagedResourceActionII#readResourcesPage(org.sakaiproject.service.framework.session.SessionState, int, int) */ protected List readResourcesPage(SessionState state, int first, int last) { List rv = new Vector(); String search = (String) state.getAttribute(SEARCH_TERM); if ((search != null) && search.trim().equals("")) { search = null; } boolean defaultMode = state.getAttribute(STATE_VIEW_MODE) == null; PagingPosition page = new PagingPosition(first, last); // check the sort order boolean sortAsc = true; if (state.getAttribute(SORT_ASC) != null) { sortAsc =((Boolean) state.getAttribute(SORT_ASC)).booleanValue(); } else { state.setAttribute(SORT_ASC, Boolean.TRUE); } if (defaultMode) { if (sortAsc) { rv = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.ACCESS, null, search, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_ASC, page); } else { rv = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.ACCESS, null, search, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_DESC, page); } } else { if (sortAsc) { rv = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.JOINABLE, // null, null, null, org.sakaiproject.service.legacy.site.SiteService.SortType.TITLE_ASC, null); null, search, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_ASC, page); } else { rv = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.JOINABLE, // null, null, null, org.sakaiproject.service.legacy.site.SiteService.SortType.TITLE_DESC, null); null, search, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_DESC, page); } } //PagingPosition page = new PagingPosition(first, last); //page.validate(rv.size()); //rv = rv.subList(page.getFirst() - 1, page.getLast()); return rv; } /** the above : paging * */ /** * build the context */ public String buildMainPanelContext(VelocityPortlet portlet, Context context, RunData rundata, SessionState state) { // buildMenu(portlet, context, rundata, state); String template = (String) getContext(rundata).get("template"); // read the group ids to join if (state.getAttribute(SORT_ASC) == null) { state.setAttribute(SORT_ASC, Boolean.TRUE); } Boolean sortAsc = (Boolean) state.getAttribute(SORT_ASC); context.put("currentSortAsc", sortAsc); if (state.getAttribute(SEARCH_TERM) == null) { state.setAttribute(SEARCH_TERM, ""); } context.put(SEARCH_TERM, state.getAttribute(SEARCH_TERM)); boolean defaultMode = state.getAttribute(STATE_VIEW_MODE) == null; if (defaultMode) { // process all the sites the user has access to so can unjoin //List unjoinableSites = new Vector(); List unjoinableSites = prepPage(state); pagingInfoToContext(state, context); /* if (sortAsc.booleanValue()) { unjoinableSites = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.ACCESS, null, null, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_ASC, null); } else { unjoinableSites = SiteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.ACCESS, null, null, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_DESC, null); } */ context.put("unjoinableSites", unjoinableSites); context.put("tlang", rb); context.put("SiteService", SiteService.getInstance()); // if property set in sakai.properties then completely disable 'unjoin' link if (ServerConfigurationService.getBoolean("disable.membership.unjoin.selection", false)) { context.put("disableUnjoinSelection", Boolean.TRUE); } if (ServerConfigurationService.getStrings("wsetup.disable.unjoin") != null) { context.put("disableUnjoinSiteTypes", new ArrayList(Arrays.asList(ServerConfigurationService.getStrings("wsetup.disable.unjoin")))); } } else { template = buildJoinableContext(portlet, context, rundata, state); } // build confirmation screen context if (state.getAttribute(STATE_CONFIRM_VIEW_MODE) != null) { if (state.getAttribute(STATE_CONFIRM_VIEW_MODE).equals("unjoinconfirm")) { template = buildUnjoinconfirmContext(portlet, context, rundata, state); } } context.put("tlang", rb); context.put("alertMessage", state.getAttribute(STATE_MESSAGE)); context.put("membershipTextEdit", new SiteTextEditUtil()); return template; } // buildMainPanelContext /** * Navigate to confirmation screen */ public void doGoto_unjoinconfirm(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); String[] id = data.getParameters().getStrings("itemReference"); if (id==null){ state.setAttribute(STATE_CONFIRM_VIEW_MODE, "noSelectionUnjoin"); addAlert(state, rb.getString("mb.noselection.unjoin")); } else { state.setAttribute(STATE_CONFIRM_VIEW_MODE, "unjoinconfirm"); } state.setAttribute(UNJOIN_SITE, id); } /** * Build context for confirmation screen * * @param portlet * @param context * @param runData * @param state * @return */ public String buildUnjoinconfirmContext(VelocityPortlet portlet, Context context, RunData runData, SessionState state) { context.put("tlang", rb); if (state.getAttribute(UNJOIN_SITE) != null) { String[] items=(String[])state.getAttribute(UNJOIN_SITE); List unjoinSite=new Vector(); for (int i=0; i<items.length;i++){ try { unjoinSite.add(SiteService.getSite(items[i]).getTitle()); } catch (IdUnusedException e) { Log.warn("chef", this + ".buildUnjoinconfirmContext(): " + e); } } context.put("unjoinSite", unjoinSite); } String template = (String) getContext(runData).get("template"); return template + "_confirm"; } /** * process unjoin * * @param data */ public void doGoto_unjoinyes(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); state.removeAttribute(STATE_CONFIRM_VIEW_MODE); state.removeAttribute(STATE_TOP_PAGE_MESSAGE); doUnjoin(data); } /** * cancel unjoin of site * * @param data */ public void doGoto_unjoincancel(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); state.removeAttribute(STATE_CONFIRM_VIEW_MODE); } /** * Setup for the options panel. */ public String buildJoinableContext(VelocityPortlet portlet, Context context, RunData runData, SessionState state) { // the sorting sequence if (state.getAttribute(JOINABLE_SORT_ASC) == null) { state.setAttribute(JOINABLE_SORT_ASC, Boolean.TRUE); } context.put("currentSortAsc", state.getAttribute(JOINABLE_SORT_ASC)); if (state.getAttribute(SEARCH_TERM) == null) { state.setAttribute(SEARCH_TERM, ""); } context.put(SEARCH_TERM, state.getAttribute(SEARCH_TERM)); List openSites = prepPage(state); context.put("openSites", openSites); pagingInfoToContext(state, context); context.put("tlang", rb); String template = (String) getContext(runData).get("template"); return template + "_joinable"; } /** * Handle the eventSubmit_doGoto_unJoinable command to shwo the list of site which are unjoinable. */ public void doGoto_unjoinable(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); state.removeAttribute(STATE_VIEW_MODE); state.removeAttribute(STATE_PAGESIZE); state.removeAttribute(STATE_TOP_PAGE_MESSAGE); state.removeAttribute(SEARCH_TERM); } /** * Handle the eventSubmit_doGoto_unJoinable command to shwo the list of site which are joinable. */ public void doGoto_joinable(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); state.setAttribute(STATE_VIEW_MODE, "joinable"); state.removeAttribute(STATE_PAGESIZE); state.removeAttribute(STATE_TOP_PAGE_MESSAGE); state.removeAttribute(SEARCH_TERM); } /** * Handle the eventSubmit_doJoin command to have the user join one or more sites. */ public void doJoin(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); // read the group ids to join String id = data.getParameters().getString("itemReference"); if (id != null) { try { // join the site SiteService.join(id); String msg = rb.getString("mb.youhave2") + " " + SiteService.getSite(id).getTitle(); addAlert(state, msg); // add to user auditing List<String[]> userAuditList = new ArrayList<String[]>(); String currentUserEid = userDirectoryService.getCurrentUser().getEid(); String roleId = SiteService.getSite(id).getJoinerRole(); String[] userAuditString = {id,currentUserEid,roleId,userAuditService.USER_AUDIT_ACTION_ADD,userAuditRegistration.getDatabaseSourceKey(),currentUserEid}; userAuditList.add(userAuditString); if (!userAuditList.isEmpty()) { userAuditRegistration.addToUserAuditing(userAuditList); } } catch (IdUnusedException e) { Log.warn("chef", this + ".doJoin(): " + e); } catch (PermissionException e) { Log.warn("chef", this + ".doJoin(): " + e); } catch (InUseException e) { addAlert(state, rb.getString("mb.sitebeing")); } } // TODO: hard coding this frame id is fragile, portal dependent, and needs to be fixed -ggolden schedulePeerFrameRefresh("sitenav"); //scheduleTopRefresh(); } // doJoin /** * Handle the eventSubmit_doUnjoin command to have the user un-join one or more groups. */ public void doUnjoin(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); // read the form / state to figure out which attachment(s) to add. // String id = data.getParameters().getString("itemReference"); String[] id = (String[]) state.getAttribute(UNJOIN_SITE); if (id != null) { String msg = rb.getString("mb.youhave") + " "; // add to user auditing List<String[]> userAuditList = new ArrayList<String[]>(); // get the User object since we need a couple of lookups User tempUser = userDirectoryService.getCurrentUser(); String currentUserId = tempUser.getId(); String currentUserEid = tempUser.getEid(); for(int i=0; i< id.length; i++){ try { // Get the user's role before unjoining the site String roleId = SiteService.getSite(id[i]).getUserRole(currentUserId).getId(); SiteService.unjoin(id[i]); if (i>0) msg=msg+" ,"; msg = msg+SiteService.getSite(id[i]).getTitle(); String[] userAuditString = {id[i],currentUserEid,roleId,userAuditService.USER_AUDIT_ACTION_REMOVE,userAuditRegistration.getDatabaseSourceKey(),currentUserEid}; userAuditList.add(userAuditString); } catch (IdUnusedException ignore) { } catch (PermissionException e) { // This could occur if the user's role is the maintain role for the site, and we don't let the user // unjoin sites they are maintainers of Log.warn("chef", this + ".doUnjoin(): " + e); } catch (InUseException e) { Log.warn("chef", this + ".doJoin(): " + e); addAlert(state, rb.getString("mb.sitebeing")); } } addAlert(state, msg); if (!userAuditList.isEmpty()) { userAuditRegistration.addToUserAuditing(userAuditList); } } // TODO: hard coding this frame id is fragile, portal dependent, and needs to be fixed -ggolden schedulePeerFrameRefresh("sitenav"); } // doUnjoin /** * toggle the sort ascending vs decending property in main view */ public void doToggle_sort(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); if (state.getAttribute(SORT_ASC) != null) { state.setAttribute(SORT_ASC, Boolean.valueOf(!((Boolean) state.getAttribute(SORT_ASC)).booleanValue())); } } // doToggle_sort /** * toggle the sort ascending vs decending property in joinable view */ public void doToggle_joinable_sort(RunData data) { SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); if (state.getAttribute(JOINABLE_SORT_ASC) != null) { state.setAttribute(JOINABLE_SORT_ASC, Boolean.valueOf(!((Boolean) state.getAttribute(JOINABLE_SORT_ASC)).booleanValue())); } } }