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 __call__(self): """Display a list of Todo items in the Open workflow state, grouped by Workspace and ordered by Due date. {'workspace1': {'title': 'WS1', 'url': '...', 'tasks':[<brain>, ...]}} """ pc = api.portal.get_tool('portal_catalog') me = api.user.get_current().getId() form = self.request.form if self.request.method == 'POST' and form: return update_task_status(self, return_status_message=True) tasks = pc(portal_type='todo', review_state='open', assignee=me, sort_on='due') self.grouped_tasks = {} for task in tasks: obj = task.getObject() workspace = parent_workspace(obj) if workspace.id not in self.grouped_tasks: self.grouped_tasks[workspace.id] = { 'title': workspace.title, 'url': workspace.absolute_url(), 'tasks': [task], } else: self.grouped_tasks[workspace.id]['tasks'].append(task) return self.render()
def __call__(self, title=None, description=None, tags=[]): """Render the default template and evaluate the form when editing.""" context = aq_inner(self.context) self.workspace = parent_workspace(context) self.can_edit = api.user.has_permission( 'Modify portal content', obj=context) if self.can_edit and title or description or tags: modified = False if title and safe_unicode(title) != context.title: context.title = safe_unicode(title) modified = True if description: if safe_unicode(description) != context.description: context.description = safe_unicode(description) modified = True if tags: tags = tuple([safe_unicode(tag) for tag in tags.split(',')]) if tags != context.subject: context.subject = tags modified = True if modified: context.reindexObject() notify(ObjectModifiedEvent(context)) return super(ContentView, self).__call__()
def reopen(self): """ This only applies to Todo items in Case Workspaces. Set the workflow state to "open" if the milestone of the Todo item is the same as the current, or earlier workflow state of the Case Workspace, otherwise set to "planned". Only Open items will appear in the dashboard. """ todo_state = api.content.get_state(self) workspace = parent_workspace(self) if not ICase.providedBy(workspace): if todo_state != 'open': api.content.transition(self, 'set_to_open') else: milestone = self.milestone if milestone: case_state = api.content.get_state(workspace) mm = IMetroMap(workspace).metromap_sequence.keys() # A case could be set to a state which isn't included in the # metromap e.g. on-hold, rejected. If that happens we can treat # it as a future state and set all open tasks to planned mm_states = case_state in mm and milestone in mm future = (not mm_states or mm.index(milestone) > mm.index(case_state)) current_or_past = not future if current_or_past and todo_state != 'open': api.content.transition(self, 'set_to_open') if future and todo_state != 'planned': api.content.transition(self, 'set_to_planned') elif todo_state != 'planned': api.content.transition(self, 'set_to_planned')
def reopen(self): """ This only applies to Todo items in Case Workspaces. Set the workflow state to "open" if the milestone of the Todo item is the same as the current, or earlier workflow state of the Case Workspace, otherwise set to "planned". Only Open items will appear in the dashboard. """ wft = api.portal.get_tool("portal_workflow") todo_state = wft.getInfoFor(self, "review_state") workspace = parent_workspace(self) if not ICase.providedBy(workspace): if todo_state != 'open': api.content.transition(self, 'set_to_open') else: milestone = self.milestone if milestone: case_state = wft.getInfoFor(workspace, 'review_state') mm = IMetroMap(workspace).metromap_sequence.keys() future = mm.index(milestone) > mm.index(case_state) current_or_past = not future if current_or_past and todo_state != 'open': api.content.transition(self, 'set_to_open') if future and todo_state != 'planned': api.content.transition(self, 'set_to_planned') elif todo_state != 'planned': api.content.transition(self, 'set_to_planned')
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 reopen(self): """ This only applies to Todo items in Case Workspaces. Set the workflow state to "open" if the milestone of the Todo item is the same as the current, or earlier workflow state of the Case Workspace, otherwise set to "planned". Only Open items will appear in the dashboard. """ wft = api.portal.get_tool("portal_workflow") state = wft.getInfoFor(self, "review_state") workspace = parent_workspace(self) if not ICase.providedBy(workspace): if state != "open": api.content.transition(self, "set_to_open") else: milestone = self.milestone if milestone: workspace_state = wft.getInfoFor(workspace, "review_state") mm_seq = IMetroMap(workspace).metromap_sequence.keys() if mm_seq.index(milestone) > mm_seq.index(workspace_state): if state != "planned": api.content.transition(self, "set_to_planned") elif state != "open": api.content.transition(self, "set_to_open") elif state != "planned": api.content.transition(self, "set_to_planned")
def __call__(self): """Display a list of Todo items in the Open workflow state, grouped by Workspace and ordered by Due date. {'workspace1': {'title': 'WS1', 'url': '...', 'tasks':[<brain>, ...]}} """ pc = api.portal.get_tool("portal_catalog") me = api.user.get_current().getId() form = self.request.form if self.request.method == "POST" and form: return update_task_status(self, return_status_message=True) tasks = pc(portal_type="todo", review_state=["open", "planned"], assignee=me, sort_on="due") self.grouped_tasks = {} for task in tasks: obj = task.getObject() workspace = parent_workspace(obj) if workspace.id not in self.grouped_tasks: self.grouped_tasks[workspace.id] = { "title": workspace.title, "url": workspace.absolute_url(), "tasks": [task], } else: self.grouped_tasks[workspace.id]["tasks"].append(task) return self.render()
def get_item_milestone_hr(self, item): ''' Given an item, try to get the milestone in a human readable form ''' milestone = getattr(item, 'milestone', None) if not milestone: return '' ws = parent_workspace(item) return self.get_milestone_hr(ws, milestone)
def safe_get_workspace(self): """ This will safely return a sane element, either a workspace, or app or portal object to call helper methods on """ portal = api.portal.get() return parent_workspace(self.context) or \ parent_app(self.context) or \ portal
def form_data_pat_redactor(self): ''' Return the options for pat-redactor in the format: key1: value1; key2: value2; ... ''' workspace = parent_workspace(self.context) options = '; '.join(': '.join(option) for option in self._pat_redactor_options) return options.format(workspace_url=workspace.absolute_url())
def tasks_by_workspace(self): ''' Return the tasks inside workspaces grouped by workspace ''' tasks = self.tasks tasks_by_workspace = defaultdict(list) for task in tasks: workspace = parent_workspace(task) tasks_by_workspace[workspace].append(task) return tasks_by_workspace
def __call__(self, title=None, description=None, tags=[], text=None): """Render the default template and evaluate the form when editing.""" context = aq_inner(self.context) self.workspace = parent_workspace(context) self.can_edit = api.user.has_permission('Modify portal content', obj=context) # When saving, force to POST if self.request.method == 'POST': self.update() return super(ContentView, self).__call__()
def __call__(self, title=None, description=None, tags=[], text=None): """Render the default template and evaluate the form when editing.""" context = aq_inner(self.context) self.workspace = parent_workspace(context) self.can_edit = api.user.has_permission( 'Modify portal content', obj=context ) # When saving, force to POST if self.request.method == 'POST': self.update() return super(ContentView, self).__call__()
def _update_workspace_groupings(obj, event): """ If the relevant object is inside a workspace, the workspace grouping parameters (for the sidebar) need to be updated. """ parent = parent_workspace(obj) if parent is None or not IGroupingStoragable.providedBy(parent): return storage = getAdapter(parent, IGroupingStorage) if IObjectRemovedEvent.providedBy(event) or IObjectWillBeRemovedEvent.providedBy(event): storage.remove_from_groupings(obj) else: storage.update_groupings(obj)
def _update_workspace_groupings(obj, event): """ If the relevant object is inside a workspace, the workspace grouping parameters (for the sidebar) need to be updated. """ parent = parent_workspace(obj) if parent is None or not IGroupingStoragable.providedBy(parent): return storage = getAdapter(parent, IGroupingStorage) if IObjectRemovedEvent.providedBy(event) or \ IObjectWillBeRemovedEvent.providedBy(event): storage.remove_from_groupings(obj) else: storage.update_groupings(obj)
def events(self): catalog = api.portal.get_tool("portal_catalog") workspace = parent_workspace(self.context) workspace_path = '/'.join(workspace.getPhysicalPath()) now = DateTime() # Current and future events upcoming_events = catalog.searchResults( object_provides=IEvent.__identifier__, path=workspace_path, start={'query': (now), 'range': 'min'}, ) # Events which have finished older_events = catalog.searchResults( object_provides=IEvent.__identifier__, path=workspace_path, end={'query': (now), 'range': 'max'}, ) return {"upcoming": upcoming_events, "older": older_events}
def __call__(self): workspace = parent_workspace(self.context) wft = api.portal.get_tool('portal_workflow') case_milestone = wft.getInfoFor(workspace, 'review_state') catalog = api.portal.get_tool('portal_catalog') workspace_path = '/'.join(workspace.getPhysicalPath()) open_tasks = catalog( path=workspace_path, portal_type='todo', review_state='open', ) # Only prevent the current milestone from being closed if there are # open tasks assigned to the current milestone. # This ignores open tasks assigned to earlier milestones since they # aren't represented in the metromap. for task in open_tasks: if task.getObject().milestone == case_milestone: return False return True
def update_todo_state(obj, event): """ After editing a Todo item, set the workflow state to either Open or Planned depending on the state of the Case. Also update access permissions on the Case, which might have changed due to a change in assignment. """ # Do nothing on copy if IObjectCopiedEvent.providedBy(event): return if IObjectAddedEvent.providedBy(event): # This attribute is set when copying from a template # handle_case_workflow_state_changed will take care of everything if getattr(event.newParent, '_v_skip_update_todo_state', None): return obj.set_appropriate_state() obj.reindexObject() parent = parent_workspace(obj) if ICase.providedBy(parent): parent.update_case_access()
def get_key_maker(self): ''' Return a function that will generate a key according to the selected browsing mode The key can be the parent workspace, an attribute value, the review state or whatever. As a fallback we return a function that returns None. ''' browse_mode = self.browse_mode if browse_mode in ('origin', 'assigned', 'initiated'): return parent_workspace if browse_mode == 'origin_and_milestone': return lambda task: (parent_workspace(task), task.milestone) if browse_mode == 'task_state': return api.content.get_state if browse_mode in ( 'assignee', 'initiator', 'priority', ): return lambda task: getattr(task, browse_mode, None) return lambda task: None
def __call__(self): """Display a list of Todo items in the Open workflow state, grouped by Workspace and ordered by Due date. {'workspace1': {'title': 'WS1', 'url': '...', 'tasks':[<brain>, ...]}} """ pc = api.portal.get_tool('portal_catalog') me = api.user.get_current().getId() tasks = pc(portal_type='todo', review_state='open', assignee=me, sort_on='due') self.grouped_tasks = {} for task in tasks: obj = task.getObject() workspace = parent_workspace(obj) if workspace.id not in self.grouped_tasks: self.grouped_tasks[workspace.id] = { 'title': workspace.title, 'url': workspace.absolute_url(), 'tasks': [task], } else: self.grouped_tasks[workspace.id]['tasks'].append(task) return self.render()
def workspace(self): ''' Return the parent workspace (if there is any) ''' return parent_workspace(self.context)
def parent_workspace(self): ''' Return the parent workspace ''' return parent_workspace(self.context)
def workspace(self): """Acquire the root workspace of the current context""" return parent_workspace(self.context)
def destination(self): ''' Get the parent workspace ''' return parent_workspace(self.context)
def my_workspace(self): return parent_workspace(self)
def redirect(self, url): workspace = parent_workspace(self.context) return self.request.response.redirect(workspace.absolute_url() + '#workspace-events')
def workspace(self): return parent_workspace(self.context)