Index: messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties =================================================================== --- messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties (revision 98096) +++ messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties (working copy) @@ -111,7 +111,7 @@ cdfm_discussion_forums=Forums cdfm_discussion_forums_old=Discussion Forums cdfm_new_forum=New Forum -cdfm_new_topic=New Topic +cdfm_new_topic=New Topic(s) cdfm_forum_inf_note=Note: cdfm_forum_inf_no_topics= You need to add at least one topic. cdfm_forum_inf_all_topics_draft=All topics are draft. Topics saved as drafts cannot be seen by all participants. @@ -129,6 +129,14 @@ cdfm_duplicate_topic_confirm=Are you sure you wish to duplicate this topic? cdfm_duplicate_forum_confirm=Are you sure you wish to duplicate this forum? cdfm_insufficient_privileges_duplicate=You do not have privileges to duplicate this. +cdfm_create_one_topic=Create One Topic +cdfm_autocreate_topics_for_groups=Create Topics For Groups +cdfm_autocreate_topics_desc=An instance of this topic will automatically be created and configured for each group selected below. +cdfm_autocreate_topics_desc_more=Default permissions are based on this forum's permissions configuration. +cdfm_autocreate_topics_desc_roles=The {0} role(s) will automatically be set to the permission level of None. +cdfm_autocreate_topics_desc_groups=Each group will be set to {0} in their group''s topic and None in other automatically created topics. +cdfm_create_one_topic_desc=One topic will be created with the permissions settings you can configure below. +cdfm_no_group_selected=Please select at least one group to automatically create topics. cdfm_organize=Organize cdfm_statistics=Statistics & Grading cdfm_template_setting=Template Settings Index: messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java =================================================================== --- messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java (revision 98096) +++ messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java (working copy) @@ -108,6 +108,7 @@ import org.sakaiproject.tool.messageforums.ui.DiscussionTopicBean; import org.sakaiproject.tool.messageforums.ui.EmailNotificationBean; import org.sakaiproject.tool.messageforums.ui.PermissionBean; +import org.sakaiproject.tool.messageforums.ui.SiteGroupBean; import org.sakaiproject.user.api.User; import org.sakaiproject.user.cover.UserDirectoryService; import org.sakaiproject.util.FormattedText; @@ -244,6 +245,8 @@ private static final String CONFIRM_DELETE_MESSAGE="cdfm_delete_msg"; private static final String INSUFFICIENT_PRIVILEGES_TO_DELETE = "cdfm_insufficient_privileges_delete_msg"; private static final String END_DATE_BEFORE_OPEN_DATE = "endDateBeforeOpenDate"; + private static final String NO_GROUP_SELECTED ="cdfm_no_group_selected"; + private static final String AUTOCREATE_TOPICS_ROLES_DESCRIPTION = "cdfm_autocreate_topics_desc_roles"; private static final String DUPLICATE_COPY_TITLE = "cdfm_duplicate_copy_title"; private static final String FROM_PAGE = "msgForum:mainOrForumOrTopic"; @@ -342,6 +345,9 @@ private int selectedMessageCount = 0; private int functionClick = 0; + + private List siteGroups = new ArrayList(); + private Boolean createTopicsForGroups = false; private boolean dialogGradeSavedSuccessfully = false; @@ -1287,6 +1293,8 @@ return gotoMain(); } setPermissionMode(PERMISSION_MODE_TOPIC); + siteGroups.clear(); + createTopicsForGroups = false; attachments.clear(); prepareRemoveAttach.clear(); @@ -1623,6 +1631,8 @@ } attachments.clear(); prepareRemoveAttach.clear(); + siteGroups.clear(); + createTopicsForGroups = false; setFromMainOrForumOrTopic(); return TOPIC_SETTING_REVISE; @@ -1683,7 +1693,8 @@ } setFromMainOrForumOrTopic(); - + siteGroups.clear(); + createTopicsForGroups = false; return TOPIC_SETTING_REVISE; } @@ -1735,7 +1746,13 @@ forumManager.approveAllPendingMessages(selectedTopic.getTopic().getId()); } - saveTopicSettings(false); + if (createTopicsForGroups ) { + if (!saveTopicsForGroups(false)) { + return null; + } + } else { + saveTopicSettings(false); + } Long forumId = selectedForum.getForum().getId(); if (forumId == null) { @@ -1754,6 +1771,8 @@ } attachments.clear(); prepareRemoveAttach.clear(); + siteGroups.clear(); + createTopicsForGroups = false; return TOPIC_SETTING_REVISE; } @@ -1821,7 +1840,13 @@ beforeChangeHM = SynopticMsgcntrManagerCover.getUserToNewMessagesForForumMap(getSiteId(), forumId, null); } - saveTopicSettings(false); + if (createTopicsForGroups ) { + if (!saveTopicsForGroups(false)) { + return null; + } + } else { + saveTopicSettings(false); + } if(updateSynopticCounts){ if(beforeChangeHM != null){ @@ -1884,7 +1909,13 @@ setErrorMessage(getResourceBundleString(INSUFFICIENT_PRIVILEGES_NEW_TOPIC)); return gotoMain(); } - saveTopicSettings(true); + if (createTopicsForGroups ) { + if (!saveTopicsForGroups(true)) { + return null; + } + } else { + saveTopicSettings(true); + } //reset(); //return MAIN; @@ -2102,7 +2133,8 @@ } } - + siteGroups.clear(); + createTopicsForGroups = false; setTopicBeanAssign(); setFromMainOrForumOrTopic(); @@ -6607,7 +6639,7 @@ if(siteMembers!=null && siteMembers.size()>0) { - return siteMembers; + return siteMembers; } permissions=new ArrayList(); @@ -8460,5 +8492,178 @@ this.editorRows = editorRows; } + public List getSiteGroups() { + if (siteGroups == null || siteGroups.isEmpty()) { + siteGroups = new ArrayList(); + try { + Site currentSite = SiteService.getSite(ToolManager.getCurrentPlacement().getContext()); + Collection groups = currentSite.getGroups(); + groups = sortGroups(groups); + for (Iterator groupIterator = groups.iterator(); groupIterator.hasNext();) { + Group currentGroup = (Group) groupIterator.next(); + siteGroups.add(new SiteGroupBean(currentGroup, false)); + } + } catch (IdUnusedException e) { + LOG.error(e.getMessage(), e); + } + } + return siteGroups; + } + + private List getSiteRolesNames() { + ArrayList siteRolesNames = new ArrayList(); + + AuthzGroup realm; + try { + realm = AuthzGroupService.getAuthzGroup(getContextSiteId()); + + Set roles1 = realm.getRoles(); + + if (roles1 != null && roles1.size() > 0) { + List rolesList = sortRoles(roles1); + + Iterator roleIter = rolesList.iterator(); + while (roleIter.hasNext()) { + Role role = (Role) roleIter.next(); + if (role != null) { + siteRolesNames.add(role.getId()); + } + } + } + } catch (GroupNotDefinedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return siteRolesNames; + } + + public Boolean getCreateTopicsForGroups() { + return this.createTopicsForGroups; + } + + public void setCreateTopicsForGroups(Boolean createTopicsForGroups) { + this.createTopicsForGroups = createTopicsForGroups; + } + + /** + * + * @param draft + * @return error status (no groups selected) + */ + private boolean saveTopicsForGroups(boolean draft) { + LOG.debug("saveTopicsForGroup()"); + if (siteGroups == null || siteGroups.isEmpty()) { + setErrorMessage(getResourceBundleString(NO_GROUP_SELECTED)); + return false; + } + DiscussionTopicBean topicTempate = selectedTopic; + ArrayList attachmentsTemplate = attachments; + + // sakai.properties settings + ArrayList rolesNone = (ArrayList) getAutoRolesNone(); + String groupLevel = getAutoGroupsPermConfig(); + + Collections.reverse(siteGroups); + + ArrayList groupsNone = new ArrayList(); + for (Iterator groupIterator = siteGroups.iterator(); groupIterator.hasNext();) { + SiteGroupBean currentGroup = (SiteGroupBean) groupIterator.next(); + if (currentGroup.getCreateTopicForGroup()==true) { + groupsNone.add(currentGroup.getGroup().getTitle()); + } + } + + boolean groupSelected = false; + for (Iterator groupIterator = siteGroups.iterator(); groupIterator.hasNext();) { + SiteGroupBean currentGroup = (SiteGroupBean) groupIterator.next(); + if (currentGroup.getCreateTopicForGroup()==true) { + groupSelected = true; + selectedTopic = createTopic(topicTempate.getTopic().getBaseForum().getId()); + DiscussionTopic thisTopic = selectedTopic.getTopic(); + thisTopic.setTitle(topicTempate.getTopic().getTitle() + " - " + currentGroup.getGroup().getTitle()); + thisTopic.setShortDescription(topicTempate.getTopic().getShortDescription()); + thisTopic.setExtendedDescription(topicTempate.getTopic().getExtendedDescription()); + thisTopic.setLocked(topicTempate.getTopic().getLocked()); + thisTopic.setModerated(topicTempate.getTopic().getModerated()); + thisTopic.setPostFirst(topicTempate.getTopic().getPostFirst()); + thisTopic.setAvailabilityRestricted(topicTempate.getTopic().getAvailabilityRestricted()); + thisTopic.setOpenDate(topicTempate.getTopic().getOpenDate()); + thisTopic.setCloseDate(topicTempate.getTopic().getCloseDate()); + thisTopic.setAutoMarkThreadsRead(topicTempate.getTopic().getAutoMarkThreadsRead()); + thisTopic.setGradebookAssignment(topicTempate.getTopic().getGradebookAssignment()); + + // Attachments + attachments.clear(); + for (Iterator attachmentIterator = attachmentsTemplate.iterator(); attachmentIterator.hasNext();) { + DecoratedAttachment currentAttachment = (DecoratedAttachment) attachmentIterator.next(); + Attachment thisDFAttach = forumManager.createDFAttachment( + currentAttachment.getAttachment().getAttachmentId(), + currentAttachment.getAttachment().getAttachmentName()); + attachments.add(new DecoratedAttachment(thisDFAttach)); + } + + // Permissions + Iterator iter = permissions.iterator(); + while(iter.hasNext()) { + PermissionBean permBean = (PermissionBean) iter.next(); + if (rolesNone.contains(permBean.getName())) { + permBean.setSelectedLevel(PermissionLevelManager.PERMISSION_LEVEL_NAME_NONE); + } + // Permissions will be remembered across topic loops, so we must reset marked groups to none in every loop + if (groupsNone.contains(permBean.getName())) { + permBean.setSelectedLevel(PermissionLevelManager.PERMISSION_LEVEL_NAME_NONE); + } + if (permBean.getName().equals(currentGroup.getGroup().getTitle())) { + permBean.setSelectedLevel(groupLevel); + } + } + saveTopicSettings(draft); + } + } + if (!groupSelected) { + setErrorMessage(getResourceBundleString(NO_GROUP_SELECTED)); + Collections.reverse(siteGroups); + return false; + } + createTopicsForGroups = false; + return true; + } + + /** + * + * @return list of role titles appropriate to this site which should be set to None when autocreating topics + */ + private List getAutoRolesNone() { + ArrayList autoRolesNone = new ArrayList(); + ArrayList siteRolesList = (ArrayList) getSiteRolesNames(); + String[] rolesNone = ServerConfigurationService.getStrings("msgcntr.rolesnone"); + if (rolesNone != null && rolesNone.length > 0) { + for (String role : rolesNone) { + if (siteRolesList.contains(role.trim())) autoRolesNone.add(role.trim()); + } + } + return autoRolesNone; + } + + public String getAutoRolesNoneDesc() { + ArrayList autoRolesNone = (ArrayList) getAutoRolesNone(); + if (autoRolesNone.size() > 0) { + StringBuffer roles = new StringBuffer(); + Iterator iter = autoRolesNone.iterator(); + while (iter.hasNext()) { + roles.append(iter.next()); + if (iter.hasNext()) roles.append("/"); + } + return getResourceBundleString(AUTOCREATE_TOPICS_ROLES_DESCRIPTION , new Object[] {roles}) ; + } else { + return ""; + } + } + + public String getAutoGroupsPermConfig() { + String groupLevel = ServerConfigurationService.getString("msgcntr.groupsdefaultlevel", "Contributor"); + return groupLevel; + } + } Index: messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/SiteGroupBean.java =================================================================== --- messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/SiteGroupBean.java (revision 0) +++ messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/SiteGroupBean.java (revision 0) @@ -0,0 +1,54 @@ +/********************************************************************************** + * $URL: https://source.sakaiproject.org/svn/msgcntr/trunk/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/SiteGroupBean.java $ + * $Id: SiteGroupBean.java $ + *********************************************************************************** + * + * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 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.osedu.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.tool.messageforums.ui; + +import org.sakaiproject.site.api.Group; + +public class SiteGroupBean { + private Group group; + private boolean createTopicForGroup; + + public SiteGroupBean (Group group, boolean createTopicForGroup) + { + this.group = group; + this.createTopicForGroup = createTopicForGroup; + } + + public Group getGroup() + { + return this.group; + } + + public void setGroup(Group group) + { + this.group = group; + } + + public boolean getCreateTopicForGroup() + { + return this.createTopicForGroup; + } + + public void setCreateTopicForGroup(boolean createTopicForGroup) + { + this.createTopicForGroup = createTopicForGroup; + } +} Index: messageforums-app/src/webapp/css/msgcntr.css =================================================================== --- messageforums-app/src/webapp/css/msgcntr.css (revision 98096) +++ messageforums-app/src/webapp/css/msgcntr.css (working copy) @@ -388,12 +388,12 @@ padding:.3em; } -.permissionRow .ui-icon { display: inline-block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; vertical-align:bottom; } -.permissionRow .ui-icon { width: 16px; height: 16px; background-image: url(ui-lightness/images/ui-icons_222222_256x240.png); } -.permissionRow .ui-icon-triangle-1-s { background-position: -64px -16px; } -.permissionRow .ui-icon-triangle-1-e { background-position: -32px -16px; } -.permissionRow .ui-accordion-content { background: #eee; border: 1px solid #ccc; } -.permissionRow .ui-accordion-header { +.ui-accordion .permissionRow .ui-icon { display: inline-block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; vertical-align:bottom; } +.ui-accordion .permissionRow .ui-icon { width: 16px; height: 16px; background-image: url(ui-lightness/images/ui-icons_222222_256x240.png); } +.ui-accordion .permissionRow .ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-accordion .permissionRow .ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-accordion .permissionRow .ui-accordion-content { background: #eee; border: 1px solid #ccc; } +.ui-accordion .permissionRow .ui-accordion-header { background: #eee; border-radius: 4px; cursor:pointer; @@ -403,16 +403,16 @@ display:inline-block; height: 1.75em; } -.permissionRow .ui-accordion-header:hover { +.ui-accordion .permissionRow .ui-accordion-header:hover { border: 1px solid #666; } -.permissionRow .ui-accordion-header.ui-state-active { +.ui-accordion .permissionRow .ui-accordion-header.ui-state-active { border-radius: 4px 4px 0 0; position:relative; top: 1px; border-bottom:none; } -.permissionRow .ui-accordion-header.ui-state-active:hover { +.ui-accordion .permissionRow .ui-accordion-header.ui-state-active:hover { border-bottom:none; } Index: messageforums-app/src/webapp/css/tabs.css =================================================================== --- messageforums-app/src/webapp/css/tabs.css (revision 0) +++ messageforums-app/src/webapp/css/tabs.css (revision 0) @@ -0,0 +1,58 @@ +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + +.ui-state-disabled { cursor: default !important; } + +/* Component containers +----------------------------------*/ +.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_75_ffffff_1x400.png) 50% 50% repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_inset-soft_95_fef1ec_1x100.png) 50% bottom repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Corner radius */ +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } + +.ui-tabs { position: relative; padding: .2em; zoom: 1; max-width: 700px; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } Index: messageforums-app/src/webapp/jsp/dfReviseTopicSettingsAttach.jsp =================================================================== --- messageforums-app/src/webapp/jsp/dfReviseTopicSettingsAttach.jsp (revision 98096) +++ messageforums-app/src/webapp/jsp/dfReviseTopicSettingsAttach.jsp (working copy) @@ -9,6 +9,7 @@ + @@ -276,9 +277,56 @@ - - + + +
+ + + <%@include file="/jsp/discussionForum/permissions/permissions_include.jsp"%> + + + + + + + + +
+ + + + + + + + + + + + + +
+