class EditForm(base.EditForm): schema = ILatest label = _(u'Edit latest news portlet') description = _( u'This portlet displays the latest news that must be read.' )
def __call__(self, milestone=None): context = aq_inner(self.context) self.can_edit = api.user.has_permission('Modify portal content', obj=context) modified, errors = dexterity_update(context) self.workspace = parent_workspace(context) if self.workspace.is_case: if self.can_edit and milestone is not None \ and milestone != context.milestone: context.milestone = milestone modified = True if modified: api.portal.show_message( _("Your changes have been saved."), request=self.request, type="success", ) context.reindexObject() notify(ObjectModifiedEvent(context)) if errors: api.portal.show_message(_("There was an error."), request=self.request, type="error") return super(TodoView, self).__call__()
def workspace_types(self): options = [{'value': '', 'content': _(u'All workspace types')}] translate = self.context.translate try: additional_filters = api.portal.get_registry_record( 'ploneintranet.workspace.workspace_type_filters') # Sort them by the translated values for portal_type in sorted( additional_filters, key=lambda x: translate(_(additional_filters.get(x))), ): label = additional_filters[portal_type] options.append({'value': portal_type, 'content': _(label)}) except api.exc.InvalidParameterError: # fallback if registry entry is not there options.extend([ { 'value': 'ploneintranet.workspace.workspacefolder', 'content': _(u'Generic workspaces') }, { 'value': 'ploneintranet.workspace.case', 'content': _(u'Cases') }, ]) return options
def likers(self): ''' The id of the people that like this content If it includes the current user, return Myself as the first element ''' likers = [] userid = api.user.get_current().id include_myself = False for likerid in self.likerids: if likerid == userid: include_myself = True else: liker = piapi.userprofile.get(likerid) if liker: likers.append(liker.fullname) else: likers.append(likerid) likers.sort() if include_myself: likers.insert(0, self.context.translate(_(u'Myself'))) if not likers: return return _('liked_by', default=u'Liked by: ${likers}', mapping={'likers': u', '.join(likers)})
class AddForm(add.DefaultAddForm, DexterityFormMixin): """ Custom add form for the Document content type. It's not necessary to override all the methods below, but we leave them there for now as reference. """ template = ViewPageTemplateFile('templates/edit_document.pt') def render(self): """ The "contents" attribute of the AddView gets populated with the return results of this method. """ return super(AddForm, self).render() def update(self): return super(AddForm, self).update() def extractData(self, setErrors=True): exclude_from_nav_id = ('form.widgets.IExcludeFromNavigation.exclude_' 'from_nav') if exclude_from_nav_id not in self.request: # XXX: This is a required field, but not in the form. Not yet sure # what the right approach to deal with it is. # Either we deal with it here, or add a hidden field in the # template. self.request.form[exclude_from_nav_id] = 'selected' return super(AddForm, self).extractData() @button.buttonAndHandler(_('Save'), name='save') def handleAdd(self, action): return super(EditForm, self).handleAdd(self, action) @button.buttonAndHandler(_(u'Cancel'), name='cancel') def handleCancel(self, action): return super(AddForm, self).handleCancel(self, action)
def __call__(self): """ write attributes, if any, set state, render """ form = self.request.form ws = self.workspace() if self.request.method == 'POST' and form: if self.can_manage_workspace(): modified, errors = dexterity_update(self.context) if modified and not errors: api.portal.show_message(_("Attributes changed."), request=self.request, type="success") ws.reindexObject() notify(ObjectModifiedEvent(self.context)) if errors: api.portal.show_message( _("There was a problem updating the content: %s." % errors), request=self.request, type="error", ) return self.render()
class View(BrowserView): _tabs = [ { 'view': 'search', 'title': _('All'), }, { 'view': 'search_people', 'title': _('People'), }, { 'view': 'search_images', 'title': _('Images'), }, { 'view': 'search_files', 'title': _('Files'), }, ] def get_tabs(self): ''' Return the list of tabs ''' params = {'SearchableText': self.request.get('SearchableText', '')} url_template = ''.join((self.context.absolute_url(), '/@@{view}' '?', urlencode(params), '#results')) current_view = self.request.steps[-1].lstrip('@@') for tab in self._tabs: tab = tab.copy() tab['url'] = url_template.format(**tab) if tab['view'] == current_view: tab['extra_class'] = 'current' yield tab
def __call__(self): """ """ if not self.validate_id(self.item_id): return 'No valid item-id: %s' % self.item_id self.current_user_id = api.user.get_current().getId() if not self.current_user_id: return 'No user-id' self.is_liked = self.util.is_liked( self.like_type, user_id=self.current_user_id, item_id=self.item_id, ) # toogle like only if the button is clicked if 'like_button' in self.request: self.handle_toggle() if self.is_liked: self.verb = self.context.translate(_(u'Unlike')) else: self.verb = self.context.translate(_(u'Like')) self.unique_id = uuid.uuid4().hex return self.index()
def __call__(self): self.util = getUtility(INetworkTool) self.followed_id = self.context.username self.follow_type = 'user' self.follower = plone_api.user.get_current().getUserName() self.is_followed = self.util.is_followed( self.follow_type, self.followed_id, self.follower) if 'do_toggle_follow' in self.request: self.toggle_follow() if self.is_followed: self.verb = _(u'Unfollow') else: self.verb = _(u'Follow') self.unique_id = uuid.uuid4().hex fullname = self.context.fullname self.msg_title_follow = self.context.translate(_( u'title_follow', default=u'Click to follow ${fullname}', mapping={'fullname': fullname}, )) self.msg_title_unfollow = self.context.translate(_( u'title_unfollow', default=u'You are now following ${fullname}. Click to unfollow.', mapping={'fullname': fullname}, )) return self.index()
class MessageForm(extensible.ExtensibleForm, form.Form): ignoreContext = True # don't use context to get widget data id = None label = _('Add a comment') fields = field.Fields(IMessage).select('recipient', 'text') template = ViewPageTemplateFile('send-message.pt') def updateActions(self): super(MessageForm, self).updateActions() self.actions['send'].addClass('standalone') @button.buttonAndHandler(_(u'label_sendmessage', default=u'Send Message'), name='send') def handleMessage(self, action): # Validation form data, errors = self.extractData() if errors: return sender = api.user.get_current() recipient = api.user.get(username=data['recipient']) assert sender and recipient, 'nope' locator = getUtility(IMessagingLocator) inboxes = locator.get_inboxes() inboxes.send_message(sender.id, recipient.id, data['text']) # Redirect to portal home self.request.response.redirect(self.action)
def placeholder(self): if self.thread_id or 'thread_id' in self.request.form: placeholder = _(u"leave_a_comment", default=u"Leave a comment...") else: placeholder = _(u"add_statusupdate_button", default=u"What are you doing?") return self.microblog_context.translate(placeholder)
def __call__(self): self.util = getUtility(INetworkTool) self.followed_id = self.context.username self.follow_type = 'user' self.follower = plone_api.user.get_current().getId() self.is_followed = self.util.is_followed(self.follow_type, self.followed_id, self.follower) if 'do_toggle_follow' in self.request: self.toggle_follow() if self.is_followed: self.verb = _(u'Unfollow') else: self.verb = _(u'Follow') self.unique_id = uuid.uuid4().hex fullname = self.context.fullname self.msg_title_follow = self.context.translate( _( u'title_follow', default=u'Click to follow ${fullname}', mapping={'fullname': fullname}, )) self.msg_title_unfollow = self.context.translate( _( u'title_unfollow', default= u'You are now following ${fullname}. Click to unfollow.', mapping={'fullname': fullname}, )) return self.index()
def maybe_update_tiles(self): ''' Update the custom tiles if needed ''' if not self.has_custom_dashboard(): self.show_message(_('Function not allowed'), type='error') return if self.request.form.get('restore', False): self.reset_custom_tiles() return self.show_message(_('Default dashboard restored')) requested_tiles = self.request.form.get('tiles_order') or [] available = self.available_custom_tiles() tiles = OrderedDict() for tile in requested_tiles: tile_decoded = tile.decode('utf8') if tile_decoded in available: tiles[tile_decoded] = { 'display': self.request.get('display-%s' % tile, 'span-1'), } if tiles != self.custom_tiles(): self.user.custom_tiles = tiles return self.show_message(_('Dashboard order changed')) return self.show_message( _('Dashboard order unchanged'), type='warning' )
def __call__(self, milestone=None): context = aq_inner(self.context) self.can_edit = api.user.has_permission( 'Modify portal content', obj=context) modified, errors = dexterity_update(context) self.workspace = parent_workspace(context) if self.workspace.is_case: if self.can_edit and milestone is not None \ and milestone != context.milestone: context.milestone = milestone modified = True if modified: api.portal.show_message( _("Your changes have been saved."), request=self.request, type="success", ) context.reindexObject() notify(ObjectModifiedEvent(context)) if errors: api.portal.show_message( _("There was an error."), request=self.request, type="error") return super(TodoView, self).__call__()
def _basic_save(self): ''' Performs a simple save of entered attributes. Not all sidebars need this ''' form = self.request.form ws = self.workspace() if self.request.method == 'POST' and form: if self.can_manage_workspace(): modified, errors = dexterity_update(self.context) if modified and not errors: api.portal.show_message(_("Attributes changed."), request=self.request, type="success") ws.reindexObject() notify(ObjectModifiedEvent(self.context)) if form.get('hero_image', None): self.request.response.redirect( self.context.absolute_url()) if errors: api.portal.show_message( _("There was a problem updating the content: %s." % errors), request=self.request, type="error", )
def actions(self): actions = [] if self.context.can_delete: if self.context.thread_id: title = _('Delete comment') else: title = _('Delete post') actions.append({ 'icon': 'trash', 'title': title, 'data_pat_modal': 'class: small', 'url': self.traverse + '/panel-delete-post.html', }) if self.context.can_edit: if self.context.thread_id: title = _('Edit comment') else: title = _('Edit post') actions.append({ 'icon': 'edit', 'title': title, 'url': self.traverse + '/panel-edit-post.html', 'data_pat_modal': 'panel-header-content: none', }) # edit_tags not implemented yet # edit_mentions not implemented yet return actions
def invitation_accepted(event): """ When an invitation is accepted, add the user to the team """ request = getRequest() storage = get_storage() if event.token_id not in storage: return ws_uid, username = storage[event.token_id] storage[event.token_id] acl_users = api.portal.get_tool('acl_users') acl_users.updateCredentials(request, request.response, username, None) catalog = api.portal.get_tool(name="portal_catalog") brain = catalog.unrestrictedSearchResults(UID=ws_uid)[0] with api.env.adopt_roles(["Manager"]): ws = IWorkspace(brain.getObject()) for name in ws.members: member = api.user.get(username=name) if member is not None: if member.getUserName() == username: api.portal.show_message( _('Oh boy, oh boy, you are already a member'), request, ) break else: ws.add_to_team(user=username) api.portal.show_message( _('Welcome to our family, Stranger'), request, )
def delete(self): handled = [] uids = self.request.form.get('uids', []) for uid in uids: obj = api.content.get(UID=uid) if obj: handled.append(u'"%s"' % safe_unicode(obj.Title())) api.content.delete(obj) if handled: titles = ', '.join(sorted(handled)) msg = _( u"batch_delete_success", default= u"The following items have been deleted: ${title_elems}", # noqa mapping={"title_elems": titles}) api.portal.show_message( message=msg, request=self.request, type="success", ) else: api.portal.show_message( message=_(u"No items could be deleted"), request=self.request, type="info", ) return self.redirect()
def __call__(self): """ write attributes, if any, set state, render """ form = self.request.form ws = self.workspace() if self.request.method == 'POST' and form: if self.can_manage_workspace(): modified, errors = dexterity_update(self.context) if modified and not errors: api.portal.show_message( _("Attributes changed."), request=self.request, type="success") ws.reindexObject() notify(ObjectModifiedEvent(self.context)) if errors: api.portal.show_message( _("There was a problem updating the content: %s." % errors), request=self.request, type="error", ) return self.render()
def __call__(self): """ """ if not self.validate_id(self.item_id): return 'No valid item-id: %s' % self.item_id self.current_user_id = api.user.get_current().getId() if not self.current_user_id: return 'No user-id' self.is_liked = self.util.is_liked( self.like_type, user_id=self.current_user_id, item_id=self.item_id, ) # toogle like only if the button is clicked if 'like_button' in self.request: self.handle_toggle() if self.is_liked: self.verb = self.context.translate(_(u'Unlike')) else: self.verb = self.context.translate(_(u'Like')) self.unique_id = uuid.uuid4().hex return self.index()
def create(self, container=None): """ Create content in the given container and return url. Uses dexterity_update to set the appropriate fields after creation. """ if not self.validate(): # BBB: do something clever that works with pat-inject # at the moment the @@add_something form is not a complete page # but just some markup, # so we cannot show that one here pass new = self.get_new_object(container) modified, errors = self.update(new) if not errors: api.portal.show_message( _("Item created."), request=self.request, type="success" ) new.reindexObject() notify(ObjectCreatedEvent(new)) else: api.portal.show_message( _("There was a problem: %s." % errors), request=self.request, type="error", ) return new.absolute_url()
def rename(self): handled = [] uids = self.request.form.get('uids', []) for uid in uids: obj = api.content.get(UID=uid) new_title = self.request.form.get(uid) if obj and new_title: handled.append( u'"%s" → "%s"' % (safe_unicode(obj.Title()), safe_unicode(new_title))) obj.title = new_title obj.reindexObject() if handled: titles = ', '.join(sorted(handled)) msg = _( u"batch_rename_success", default= u"The following items have been renamed: ${title_elems}", # noqa mapping={"title_elems": titles}) api.portal.show_message( message=msg, request=self.request, type="success", ) else: api.portal.show_message( message=_(u"No items could be renamed"), request=self.request, type="info", ) return self.redirect()
def __call__(self): """Cut all items currently in cart and add them to clipboard. The tricky part here is that the method that Plone uses (manage_cutObjects) was only ment to work on objects of the same parent. However, our use case allows cutting objects of different parents. Hence we need to go one level deeper and reimplement some stuff that manage_cutObjects does in our own way. """ request = self.request obj_list = [] cannot_cut = [] for obj in self.items: if obj: is_allowed = api.user.has_permission('Delete objects', obj=obj) is_locked = obj.wl_isLocked() is_movable = obj.cb_isMoveable() can_cut = is_allowed and is_movable and not is_locked if can_cut: m = Moniker(obj) obj_list.append(m.dump()) else: cannot_cut.append(u'"%s"' % safe_unicode(obj.Title())) if obj_list: # now store cutdata into a cookie # TODO: what if there's nothing in the list? ct_data = (1, obj_list) ct_data = _cb_encode(ct_data) # probably means "clipboard encode"? response = request.response path = '{0}'.format(cookie_path(request)) response.setCookie('__cp', ct_data, path=path) request['__cp'] = ct_data msg = _( u"batch_cut_success", default= u"${num_elems} Files were cut and moved to your cloud clipboard.", # noqa mapping={"num_elems": len(obj_list)}) api.portal.show_message( message=msg, request=request, type="info", ) if cannot_cut: msg = _( u"batch_cut_failure", default=u"The following items could not be cut: ${num_elems}", mapping={"num_elems": ', '.join(sorted(cannot_cut))}) api.portal.show_message( message=msg, request=request, type="info", ) return self.index()
class SidebarSettingsSecurity(BaseTile): """ A view to serve as the security settings in the sidebar """ index = ViewPageTemplateFile('templates/sidebar-settings-security.pt') join_policy_label = _(u'join_policy_label', default=u'Join policy') external_visibility_label = _(u'external_visibility_label', default=u'External visibility') participant_policy_label = _(u'participant_policy_label', default=u'Participant policy') def __init__(self, context, request): """ Set up local copies of the policies for the sidebar template """ super(SidebarSettingsSecurity, self).__init__(context, request) self.external_visibility = EXTERNAL_VISIBILITY self.join_policy = JOIN_POLICY self.participant_policy = PARTICIPANT_POLICY def __call__(self): """ Write attributes, if any, set state, render """ form = self.request.form ws = self.workspace() def update_field(field_name): index = int(form.get(field_name)) - 1 field = getattr(self, field_name) value = field.keys()[index] if value != getattr(ws, field_name): if field_name == 'external_visibility': ws.set_external_visibility(value) else: setattr(ws, field_name, value) api.portal.show_message( _(u'Workspace security policy changes saved'), self.request, 'success', ) if self.request.method == 'POST': self.form_submitted = True if not self.can_manage_workspace(): msg = _(u'You do not have permission to change the workspace ' u'policy') raise Unauthorized(msg) if form: for field in [ 'external_visibility', 'join_policy', 'participant_policy' ]: update_field(field) return self.render()
def title(self): m_context = piapi.microblog.get_microblog_context(self.context) if m_context: return m_context.Title() + ' updates' elif self.explore: return _(u'Explore') else: return _(u'My network')
def title(self): m_context = PLONEINTRANET.context(self.context) if m_context: return m_context.Title() + ' updates' elif self.explore: return _(u'Explore') else: return _(u'My network')
def title(self): m_context = piapi.microblog.get_microblog_context(self.context) if m_context: return m_context.Title() + ' updates' elif self.explore: return _(u'Explore') else: return _(u'My network')
def get_review_state_hr(self, wf, review_state): ''' Given a workflow and a review state, return a human readable title ''' if not wf: return _(review_state) state = wf.states.get(review_state) if state: return _(state.title) return _(review_state)
class AddForm(base.AddForm): schema = ILatest label = _(u'Add latest news portlet') description = _( u'This portlet displays the latest news that must be read.' ) def create(self, data): return Assignment(count=data.get('count', 5))
def roles(self): ws_policy = self.context.participant_policy title = _(u"workspace_default_role", default=u'Default role for this workspace (${role})', mapping={u'role': PARTICIPANT_POLICY[ws_policy]['title']}) yield {'id': ws_policy.title(), 'title': title} for policy_id, policy_info in PARTICIPANT_POLICY.items(): if policy_id == ws_policy: continue yield {'id': policy_id.title(), 'title': policy_info['title']} yield {'id': 'Admins', 'title': _(u'Workspace Administrator')}
def title(self): ''' The tile title. If we have an homonymous request parameter, use it Otherwise return a default based on the workspace type ''' title = self.request.form.get('title', '') if title: return _(title) workspace_type = self.workspace_type if isinstance(workspace_type, basestring): return _('tile_' + workspace_type) return _('tile_workspaces_default_tile', u'Workspaces')
def process(self, csvfile, update=False): """Process the input file, validate and create the users. """ data = tablib.Dataset() try: data.csv = csvfile except tablib.core.InvalidDimensions: return self._show_message_redirect( _("File incorrectly formatted.") ) try: self.validate(data) except custom_exc.MissingCoreFields as e: return self._show_message_redirect(_(e.message)) except custom_exc.ExtraneousFields as e: return self._show_message_redirect(_(e.message)) except tablib.core.HeadersNeeded as e: return self._show_message_redirect(_(e.message)) message_type = 'error' try: count = self.create_update_users(data, update) except custom_exc.DuplicateUser as e: message = _( u"{} on row {}".format( e.message, e.details['row']) ) except custom_exc.RequiredMissing as e: message = _( u"Missing required field {} on row {}".format( e.message, e.details['row']) ) except custom_exc.ConstraintNotSatisfied as e: message = _( u"Constraint not satisfied for {} at row {}.".format( e.details['field'], e.details['row']) ) except custom_exc.WrongType as e: message = _( u"Wrong type for {} at row {}.".format( e.details['field'], e.details['row']) ) else: message_type = 'info' verb = update and "Updated" or "Created" message = _(u"{} user(s) {}.".format(count, verb)) if message_type == 'error': transaction.abort() api.portal.show_message( message=message, request=self.request, type=message_type, ) return self._redirect()
def placeholder(self): if 'thread_id' in self.request.form: placeholder = _( u"leave_a_comment", default=u"Leave a comment..." ) else: placeholder = _( u"add_statusupdate_button", default=u"What are you doing?" ) return self.context.translate(placeholder)
class ISearchResponse(Interface): """Defines a common API for search query responses.""" spell_corrected_search = schema.TextLine( title=_(u'Spell corrected search string')) facets = schema.Dict( title=_(u'A dictionary of facets and available values')) total_results = schema.Int( title=_(u'The total number of results generated from the query')) def __iter__(): """Search responses should implement the `Iterable` protocol.
class PIDeleteConfirmationForm(DeleteConfirmationForm): ''' We need to override this because of some problems with the original delete_confirmation form See: https://github.com/plone/plone.app.content/issues/38 Caveat: we need to reimplement all the actions while overriding, because of the button.buttonAndHandler implementation ''' template = ViewPageTemplateFile('templates/delete_confirmation.pt') def view_url(self): ''' Facade to the homonymous plone_context_state method ''' context_state = getMultiAdapter( (self.context, self.request), name='plone_context_state' ) return context_state.view_url() def updateActions(self): ''' This method updates the actions to enable some dynamic behaviours In particular it understands the request parametes: - pat-modal - pat-inject If pat-modal is truish we add to the action buttons the class 'close-panel' If pat-inject is truish the pat-inject class is added to the form and a data attribute data-pat-inject is filled we the value read from the request ''' super(PIDeleteConfirmationForm, self).updateActions() if self.request.get('pat-modal'): self.actions['Delete'].klass = 'close-panel icon-ok-circle' self.actions['Cancel'].klass = 'close-panel icon-cancel-circle' else: self.actions['Delete'].klass = 'icon-ok-circle' self.actions['Cancel'].klass = 'icon-cancel-circle' @button.buttonAndHandler(_(u'I am sure, delete now'), name='Delete') def handle_delete(self, action): base_handler = super(PIDeleteConfirmationForm, self).handle_delete return base_handler(self, action) @button.buttonAndHandler( _(u'label_cancel', default=u'Cancel'), name='Cancel') def handle_cancel(self, action): return self.request.response.redirect(self.view_url())
class IWorkspaceFolder(IBaseWorkspaceFolder): ''' A workspace folder can be a division, while other objects inheriting from IBaseWorkspaceFolder cannot, e.g. cases ''' is_division = schema.Bool( title=_(u"label_workspace_is_division", u"Is this workspace representing a division?"), description=_(u"Divisions represent sections of the overall " u"organisation and appear " u"as groupings on the workspace overview."), required=False, default=False, )
class ITransferMembershipForm(form.Schema): """ the form to handle transferring membership """ workspace = schema.Choice( title=_(u"Select workspace"), source=workspaces_provider, ) move = schema.Bool( title=_(u"Move"), description=_(u"If checked, users will be removed from workspace"), required=False, )
class IWorkspaceFolder(form.Schema, IImageScaleTraversable): """ Interface for WorkspaceFolder """ calendar_visible = schema.Bool( title=_(u"label_workspace_calendar_visibility", u"Calendar visible in central calendar"), required=False, default=False, ) email = schema.TextLine( title=_(u'label_workspace_email', u'E-mail address'), required=False, default=u'', )
def execute_batch_function(self): form = self.request.form ws = self.workspace() user_ids = form.get('user_id') if isinstance(user_ids, basestring): user_ids = user_ids.split(',') batch_function = form.get('batch-function') if user_ids: if not self.can_manage_roster(): msg = _(u'You do not have permission to change the workspace ' u'policy') raise Unauthorized(msg) else: if batch_function == 'add': for user_id in user_ids: IWorkspace(ws).add_to_team(user=user_id) api.portal.show_message( _(u'Member(s) added'), self.request, 'success', ) elif batch_function == 'remove': for user_id in user_ids: IWorkspace(ws).remove_from_team(user=user_id) api.portal.show_message( _(u'Member(s) removed'), self.request, 'success', ) elif batch_function == 'role': role = self.request.get('role') if role: groups = {role} else: groups = None for user_id in user_ids: IWorkspace(ws).add_to_team(user=user_id, groups=groups) api.portal.show_message( _(u'Role updated'), self.request, 'success', ) else: api.portal.show_message( _(u'Unknown function'), self.request, 'error', )
def get_workspace_activities(brain, limit=1): """ Return the workspace activities sorted by reverse chronological order Regarding the time value: - the datetime value contains the time in international format (machine readable) - the title value contains the absolute date and time of the post """ mb = queryUtility(IMicroblogTool) items = mb.context_values(brain.getObject(), limit=limit) mtool = api.portal.get_tool('portal_membership') results = [] for item in items: user_data = mtool.getMemberInfo(item.creator) creator = user_data.get('fullname') if user_data else item.creator results.append(dict( subject=creator, verb=_(u'posted'), object=item.text, time={ 'datetime': item.date.strftime('%Y-%m-%d'), 'title': item.date.strftime('%d %B %Y, %H:%M')} )) return results
def __call__(self): """Sync a single user profile with external property providers""" alsoProvides(self.request, IDisableCSRFProtection) userprofile = self.context IUserProfileManager(userprofile).sync() api.portal.show_message(message=_("External property sync complete."), request=self.request) return self.request.response.redirect(userprofile.absolute_url())
def roles(self): ws_policy = self.context.participant_policy title = _( u"workspace_default_role", default=u'Default role for this workspace (${role})', mapping={ u'role': PARTICIPANT_POLICY[ws_policy]['title']}) yield {'id': ws_policy.title(), 'title': title} for policy_id, policy_info in PARTICIPANT_POLICY.items(): if policy_id == ws_policy: continue yield {'id': policy_id.title(), 'title': policy_info['title']} yield {'id': 'Admins', 'title': _(u'Workspace Administrator')}
def accept_invitation(event): """ Event handler for :class:`AcceptToken` event fired by invitation framework :param event: The event object :type event: :class:`AcceptToken` :return: """ request = getRequest() email = _get_storage().get(event.token_id) if email is None: api.portal.show_message(_('The token has expired.'), request) return acl_users = api.portal.get_tool('acl_users') if api.user.get(username=email) is None: api.user.create( email=email, username=email, ) acl_users.updateCredentials( request, request.response, email, None )
def update(self): """ """ context = aq_inner(self.context) modified = False errors = None messages = [] if ( self.request.get('workflow_action') and not self.request.get('form.submitted')): api.content.transition( obj=context, transition=self.request.get('workflow_action') ) # re-calculate can_edit after the workflow state change self.can_edit = api.user.has_permission( 'Modify portal content', obj=context ) modified = True messages.append( context.translate(_("The workflow state has been changed."))) if self.can_edit: mod = False if self.validate(): mod, errors = dexterity_update(context) if mod: messages.append( context.translate(_("Your changes have been saved."))) modified = modified or mod if errors: error_msg = context.translate(_("There was a problem:")) api.portal.show_message( u"{} {}".format(error_msg, errors), request=self.request, type="error", ) elif modified: api.portal.show_message( ' '.join(messages), request=self.request, type="success") context.reindexObject() notify(ObjectModifiedEvent(context))
def __call__(self): """Because self.item_id is set via publishTraverse we need an extra check""" if not getattr(self, 'item_id', False): raise KeyError( _('No item id given in sub-path. ' 'Use .../@@toggle_like/123456') ) return super(ToggleLikeStatusUpdate, self).__call__()
def validate(self, value, force=False): membrane_tool = plone_api.portal.get_tool('membrane_tool') usernames = membrane_tool._catalog.uniqueValuesFor('exact_getUserName') if value in usernames: brains = membrane_tool.searchResults(exact_getUserName=value) if brains and self.context != brains[0].getObject(): raise Invalid(_("A user with this username already exists")) return super(UsernameValidator, self).validate(value)
def __call__(self): if not self.context.join_policy == "self": msg = _(u"Workspace join policy doesn't allow self join") raise Unauthorized(msg) field = "button.join" req_method = self.request.method.lower() if req_method == "post" and field in self.request.form: user = api.user.get_current() workspace = IWorkspace(self.context) workspace.add_to_team(user=user.getId()) msg = _(u"You are a member of this workspace now") api.portal.show_message(message=_(msg), request=self.request) referer = self.request.get("HTTP_REFERER", "").strip() if not referer: referer = self.context.absolute_url() return self.request.response.redirect(referer)
def __call__(self): self.util = getUtility(INetworkTool) self.followed_id = self.context.username self.follow_type = 'user' self.follower = plone_api.user.get_current().getUserName() self.is_followed = self.util.is_followed( self.follow_type, self.followed_id, self.follower) if 'do_toggle_follow' in self.request: self.toggle_follow() if self.is_followed: self.verb = _(u'Unfollow') else: self.verb = _(u'Follow') self.unique_id = uuid.uuid4().hex return self.index()
def user_has_email(username): """ make sure, that given user has an email associated """ user = api.user.get(username=username) if not user.getProperty("email"): msg = _( "This user doesn't have an email associated " "with their account." ) raise Invalid(msg) return True
def edit(self): """ Edit content and return url. Uses dexterity_update to set the appropriate fields after creation. """ modified, errors = dexterity_update(self.context, self.request) if modified and not errors: api.portal.show_message( _("Item edited."), request=self.request, type="success") self.context.reindexObject() notify(ObjectModifiedEvent(self.context)) if errors: api.portal.show_message( _("There was a problem: %s." % errors), request=self.request, type="error", ) return self.context.absolute_url()
def __call__(self): """ Write attributes, if any, set state, render """ form = self.request.form if self.request.method == 'POST' and form: ws = self.workspace() self.set_grouping_cookie() # wft = api.portal.get_tool("portal_workflow") section = self.request.form.get('section', None) do_reindex = False # Do the workflow transitions based on what tasks the user checked # or unchecked if section == 'task': update_task_status(self) # Do the property editing. Edits only if there is something to edit # in form if self.can_manage_workspace() and form: modified, errors = dexterity_update(self.context) if modified and not errors: api.portal.show_message( _("Attributes changed."), request=self.request, type="success") do_reindex = True notify(ObjectModifiedEvent(self.context)) if errors: api.portal.show_message( _("There was a problem updating the content: %s." % errors), request=self.request, type="error", ) if do_reindex: ws.reindexObject() return self.render()
def logical_parent(self): """ Needed for the back button in the sidebar. Depending on the selected grouping, this returns the information needed to get one step back. """ grouping = self.grouping() workspace = parent_workspace(self.context) if grouping == 'folder': if self.context != workspace: parent = self.request.PARENTS[1] return dict(title=parent.Title(), url=parent.absolute_url()) else: return else: if self.request.get('groupname'): if grouping == 'date': title = _(u'All Dates') elif grouping == 'label': title = _(u'All Tags') elif grouping == 'author': title = _(u'All Authors') elif grouping == 'type': title = _(u'All Types') elif grouping == 'first_letter': title = _(u'All Letters') else: title = _(u'Back') return dict(title=title, url=workspace.absolute_url()) else: return
def execute_batch_function(self): if not self.can_manage_roster(): msg = _(u'You do not have permission to change the workspace ' u'policy') raise Unauthorized(msg) form = self.request.form user_ids = form.get('user_id') if not user_ids: return if isinstance(user_ids, basestring): user_ids = user_ids.split(',') ws = self.workspace() batch_function = form.get('batch-function') if batch_function == 'add': for user_id in user_ids: IWorkspace(ws).add_to_team(user=user_id) msg = _(u'Member(s) added') msg_type = 'success' elif batch_function == 'remove': for user_id in user_ids: IWorkspace(ws).remove_from_team(user=user_id) msg = _(u'Member(s) removed') msg_type = 'success' elif batch_function == 'role': role = self.request.get('role') groups = role and {role} or None for user_id in user_ids: IWorkspace(ws).add_to_team(user=user_id, groups=groups) msg = _(u'Role updated') msg_type = 'success' else: msg = _(u'Unknown function') msg_type = 'error' api.portal.show_message(msg, self.request, msg_type) notify(WorkspaceRosterChangedEvent(self.context))
def validate(self): ''' Override base content validation Return truish if valid ''' if self.request.get('start') <= self.request.get('end'): return True api.portal.show_message( _('Start date should be lower than end date'), request=self.request, type="error" ) return False
def invitation_accepted(event): """ When an invitation is accepted, add the user to the team """ request = getRequest() storage = get_storage() if event.token_id not in storage: return ws_uid, username = storage[event.token_id] storage[event.token_id] acl_users = api.portal.get_tool('acl_users') acl_users.updateCredentials( request, request.response, username, None ) catalog = api.portal.get_tool(name="portal_catalog") brain = catalog.unrestrictedSearchResults(UID=ws_uid)[0] with api.env.adopt_roles(["Manager"]): ws = IWorkspace(brain.getObject()) for name in ws.members: member = api.user.get(username=name) if member is not None: if member.getUserName() == username: api.portal.show_message( _('Oh boy, oh boy, you are already a member'), request, ) break else: ws.add_to_team(user=username) api.portal.show_message( _('Welcome to our family, Stranger'), request, )
def update_roster(self, REQUEST=None): """ If workspace is team managed, users can add/remove participants. Any user with the manage workspace permission can add/remove participants and admins. """ CheckAuthenticator(self.request) PostOnly(self.request) form = self.request.form entries = form.get('entries', []) self.update_users(entries) api.portal.show_message(message=_(u'Roster updated.'), request=self.request) return self.request.response.redirect( '%s/@@edit-roster' % self.context.absolute_url())
def update_field(field_name): index = int(form.get(field_name)) - 1 field = getattr(self, field_name) value = field.keys()[index] if value != getattr(ws, field_name): if field_name == 'external_visibility': ws.set_external_visibility(value) else: setattr(ws, field_name, value) api.portal.show_message( _(u'Workspace security policy changes saved'), self.request, 'success', )
def __call__(self): if self.token_id is None: raise KeyError( _("No token id given in sub-path." "Use .../@@accept-token/tokenid") ) util = getUtility(ITokenUtility) portal = api.portal.get() if util.valid(self.token_id): notify(TokenAccepted(self.token_id)) util._consume_token(self.token_id) token = util._fetch_token(self.token_id) if token.redirect_path is not None: return self.request.response.redirect('%s/%s' % ( portal.absolute_url(), token.redirect_path )) else: api.portal.show_message( _('Token no longer valid'), self.request, type='error' ) return self.request.response.redirect(portal.absolute_url())
def update(self): """ """ if ('task_action' in self.request and not self.request.get('form.submitted')): task_action = self.request.get('task_action') if task_action == 'close': api.content.transition( obj=self.context, transition='finish' ) elif task_action == 'reopen': self.context.reopen() api.portal.show_message(_( 'Changes applied'), request=self.request, type="success") super(TodoView, self).update()
def format_event_date(self, event): """ We need to show only the starting time, or in case of an all day event 'All day' in the time tag. Not the date. In case of a multi day event, we can show "2015-08-30 - 2015-08-31" """ # whole_day isn't a metadata field (yet) event_obj = event.getObject() if is_single_day(event) and event_obj.whole_day: return _(u'All day') elif is_single_day(event): return event.start.strftime('%H:%M') else: # multi day event return '{} - {}'.format( event.start.strftime('%Y-%m-%d'), event.end.strftime('%Y-%m-%d'), )