def inspectContentObject(self): """ Display detailed information about the current content object """ logger.debug("in inspectViewlet") context_state = getMultiAdapter((self.context, self.request), name=u'plone_context_state') template = ViewPageTemplateFile('panel_inspect_content_object.pt') # Wrap it so that Zope knows in what context it's being called # Otherwise, we get an "AttributeError: 'str' object has no attribute 'other'" error template = template.__of__(self) out = template(contentObject = self.context, parent = context_state.parent(), skinName = self.context.getCurrentSkinName(), templateName = context_state.view_template_id() ) # Dump the output to the inspector panel self.updatePanelBodyContent(out) # Highlight the element ksscore = self.getCommandSet('core') self.highlightElement(ksscore.getCssSelector('#glowormPageWrapper')) # And in the nav tree (Should this be here or in the nav tree viewlet code?) self.highlightInNavTree(ksscore.getCssSelector('#glowormPanelNavTree .inspectContentObject')) return self.render()
def inspectField(self, fieldname): """ Display detailed information about one of current content object's fields """ field = self.context.getField(fieldname) template = ViewPageTemplateFile('panel_inspect_field.pt') # Wrap it so that Zope knows in what context it's being called # Otherwise, we get an "AttributeError: 'str' object has no attribute 'other'" error template = template.__of__(self) out = template(fieldName = fieldname, type = field.type, widget = type(field.widget).__name__, accessor = field.accessor, mutator = field.mutator, readPermission = field.read_permission, writePermission = field.write_permission ) # Dump the output to the inspector panel self.updatePanelBodyContent(out) # Highlight the element ksscore = self.getCommandSet('core') self.highlightElement(ksscore.getCssSelector('.kssattr-atfieldname-%s' % fieldname)) return self.render()
def showMoveViewletForm(self, viewlethash): """ Show the form for moving a viewlet between managers. """ unhashedViewletInfo = unhashViewletInfo(viewlethash) reg = findTemplateViewRegistrationFromHash(viewlethash) viewRegistrationInfo = list(registration.templateViewRegistrationInfos([reg]))[0] managerName = unhashedViewletInfo['managerName'] managerNames = self._getAllViewletManagerNames() managerNames.sort() # Remove the viewlet's current viewlet manager and the gloworm panel from the choices. managerNames.remove(unhashedViewletInfo['managerName']) managerNames.remove('gloworm.glowormPanel') template = ViewPageTemplateFile('panel_move_viewlet.pt') # Wrap it so that Zope knows in what context it's being called # Otherwise, we get an "AttributeError: 'str' object has no attribute 'other'" error template = template.__of__(self) out = template(viewlethash=viewlethash, viewletName = unhashedViewletInfo['viewletName'], managerNames = managerNames) # Dump the output to the inspector panel self.updatePanelBodyContent(out) return self.render()
def test_cook_zope3_page_templates_using_format(self): from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile pt = ViewPageTemplateFile('using_format_zope3_page_template.pt') hack_pt(pt) # Need to pass a namespace. namespace = {'context': self.app} # Even when one of the accessed items requires a role that we do # not have, we get no Unauthorized, because this is a filesystem # template. self.app.test_folder_1_.__roles__ = ['Manager'] self.assertEqual( pt.pt_render(namespace).strip(), u"<p>class of <application at > is " u"<class 'ofs.application.application'></p>\n" u"<p>CLASS OF <APPLICATION AT > IS " u"<CLASS 'OFS.APPLICATION.APPLICATION'></p>\n" u"<p>{'foo': <Folder at /test_folder_1_>} has " u"foo=<Folder at test_folder_1_></p>\n" u"<p>{'foo': <Folder at /test_folder_1_>} has " u"foo=<Folder at test_folder_1_></p>\n" u"<p>[<Folder at /test_folder_1_>] has " u"first item <Folder at test_folder_1_></p>\n" u"<p>[<Folder at /test_folder_1_>] has " u"first item <Folder at test_folder_1_></p>" )
def default_html_handler(webdav_handle, filename, view_name, request): html_template = ViewPageTemplateFile('html_view.pt') # exist-db base url base_url = '{}/view/{}'.format(request.context.absolute_url(1), '/'.join(request.subpath[:-1])) # get HTML html = webdav_handle.open('.', 'rb').read() root = lxml.html.fromstring(html) # rewrite relative image urls for img in root.xpath('//img'): src = img.attrib['src'] if not src.startswith('http'): img.attrib['src'] = '{}/{}'.format(base_url, src) # rewrite relative image urls for link in root.xpath('//link'): src = link.attrib['href'] if not src.startswith('http'): link.attrib['href'] = '{}/{}'.format(base_url, src) html = lxml.html.tostring(root) return html_template.pt_render(dict( template='html_view', request=request, context=request.context, options=dict( base_url=base_url, html=html)))
def inspectViewlet(self, viewlethash): """ Display detailed information about a particular viewlet. """ logger.debug("in inspectViewlet") # Unhash the viewlet info unhashedViewletInfo = unhashViewletInfo(viewlethash) # Get the registration information for this viewlet reg = findTemplateViewRegistrationFromHash(viewlethash) viewName = unhashedViewletInfo['viewletName'] managerName = unhashedViewletInfo['managerName'] cls = registration.getViewClassFromRegistration(reg) className = "%s.%s" % (cls.__module__, cls.__name__) try: viewRegistrationInfo = list(registration.templateViewRegistrationInfos([reg]))[0] except IndexError: # For some reason, there's no registration with portal_view_cusomtizations, # this appears to happen when there's no template defined for the viewlet and it instead # uses a "render" method. customizationExists = False customizationAllowed = False templatePath = "" else: template = viewRegistrationInfo['zptfile'] templatePath = registration.generateIdFromRegistration(reg) container = queryUtility(IViewTemplateContainer) customizationExists = templatePath in container customizationAllowed = True # Get the names of the hidden viewlets storage = getUtility(IViewletSettingsStorage) hiddenViewlets = frozenset(storage.getHidden(managerName, self.context.getCurrentSkinName())) isVisible = viewName not in hiddenViewlets template = ViewPageTemplateFile('panel_inspect_viewlet.pt') # Wrap it so that Zope knows in what context it's being called # Otherwise, we get an "AttributeError: 'str' object has no attribute 'other'" error template = template.__of__(self) out = template(viewName = viewName, managerName = managerName, template = template, className = className, templatePath = templatePath, customizationExists = customizationExists, customizationAllowed = customizationAllowed, visible = isVisible, viewletHash = viewlethash) # Dump the output to the output panel self.updatePanelBodyContent(out) # Highlight this element ksscore = self.getCommandSet('core') self.highlightElement(ksscore.getCssSelector('.kssattr-viewlethash-%s' % viewlethash)) # And in the nav tree (Should this be here or in the nav tree viewlet code?) self.highlightInNavTree(ksscore.getCssSelector('#glowormPanelNavTree .kssattr-forviewlet-%s' % viewlethash)) return self.render()
def test_cook_zope3_page_templates_normal(self): from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile pt = ViewPageTemplateFile('normal_zope3_page_template.pt') hack_pt(pt) # Need to pass a namespace. namespace = {'context': self.app} self.assertEqual( pt.pt_render(namespace).strip(), u'<p><application at ></p>\n' u'<p><APPLICATION AT ></p>')
def test_cook_zope3_page_templates_normal(self): from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile # Note: on Plone 3.3 this is actually a ZopeTwoPageTemplateFile. pt = ViewPageTemplateFile('normal_zope3_page_template.pt') hack_pt(pt) # Need to pass a namespace. namespace = {'context': self.portal} self.assertEqual( pt.pt_render(namespace).strip(), u'<p><plonesite at plone></p>\n' u'<p><PLONESITE AT PLONE></p>')
def test_cook_zope3_page_templates_using_format(self): from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile # Note: on Plone 3.3 this is actually a ZopeTwoPageTemplateFile. pt = ViewPageTemplateFile('using_format_zope3_page_template.pt') hack_pt(pt) # Need to pass a namespace. namespace = {'context': self.portal} self.assertEqual( pt.pt_render(namespace).strip(), u"<p>class of <plonesite at plone> is " u"<class 'products.cmfplone.portal.plonesite'></p>\n" u"<p>CLASS OF <PLONESITE AT PLONE> IS " u"<CLASS 'PRODUCTS.CMFPLONE.PORTAL.PLONESITE'></p>\n" u"<p>{'foo': 42} has foo=42</p>\n" u"<p>{'foo': 42} has foo=42</p>\n" u"<p>['ni'] has first item ni</p>\n" u"<p>['ni'] has first item ni</p>" )
def ace_editor(webdav_handle, filename, view_name, request, readonly=False, template_name='ace_editor.pt'): """ Default handler for showing/editing textish content through the ACE editor """ mt, encoding = mimetypes.guess_type(filename) content = webdav_handle.open('.', 'rb').read() ace_mode = config.ACE_MODES.get(mt, 'text') template = ViewPageTemplateFile(template_name) action_url = '{}/view-editor/{}'.format(request.context.absolute_url(), '/'.join(request.subpath)) return template.pt_render(dict( template='ace_editor.pt', request=request, context=request.context, options=dict(content=content, action_url=action_url, readonly=readonly, ace_readonly=str(readonly).lower(), # JS ace_mode=ace_mode)))
def customizeViewlet(self, viewlethash): """ Display an edit form for modifiying a viewlet's template """ logger.debug("in customizeViewlet") # Unhash the viewlet info unhashedViewletInfo = unhashViewletInfo(viewlethash) # Get the viewlet's registration information from portal_view_customizations container = queryUtility(IViewTemplateContainer) reg = findTemplateViewRegistrationFromHash(viewlethash) regInfo = list(registration.templateViewRegistrationInfos([reg]))[0] # TODO We should be looking at regInfo['customized'] to determine whether or not a customization exists. # It never seems to have a value though... check on this. templateName = registration.generateIdFromRegistration(reg) # Check to see if the viewlet has already been customized. Get the template code accordingly. if templateName not in container.objectIds(): viewzpt = registration.customizeTemplate(reg) sm = getSiteManager(self.context) sm.registerAdapter(viewzpt, required= reg.required, provided = reg.provided, name=reg.name) else: viewzpt = container[templateName] templateCode = viewzpt.read() template = ViewPageTemplateFile('panel_customize_viewlet.pt') # Wrap it so that Zope knows in what context it's being called # Otherwise, we get an "AttributeError: 'str' object has no attribute 'other'" error template = template.__of__(self) out = template(templateURL = viewzpt.absolute_url(), viewletHash = viewlethash, templateCode = templateCode) # Dump the output to the output panel self.updatePanelBodyContent(out) # Force a resize update of the panel so that the form elements are sized to the dimensions of the panel. kssglo = self.getCommandSet('gloWorm') kssglo.forceGlowormPanelResize() return self.render()
def default_html_handler(get_handle, filename, view_name, request): html_template = ViewPageTemplateFile('html_view.pt') # exist-db base url base_url = '{}/@@view/{}'.format( request.context.absolute_url(1), '/'.join(request.subpath[:-1])) # get HTML html = get_handle.open(get_handle.leaf_filename, 'rb').read() html = unicode(html, 'utf8') if html.startswith(u'<?xml'): pos = html.find('?>') html = html[pos+3:] root = lxml.html.fromstring(html) # rewrite relative image urls for img in root.xpath('//img'): src = img.attrib['src'] if not src.startswith('http'): img.attrib['src'] = '{}/{}'.format(base_url, src) # rewrite relative image urls for link in root.xpath('//link'): src = link.attrib['href'] if not src.startswith('http'): link.attrib['href'] = '{}/{}'.format(base_url, src) html = lxml.html.tostring(root, encoding=unicode) return html_template.pt_render(dict( template='html_view', request=request, context=request.context, options=dict( base_url=base_url, html=html)))
class SidebarViewlet(ViewletBase): index = ViewPageTemplateFile('templates/sidebar.pt') def get_mouse_activated(self): """Pass in values to be used in JavaScript """ mouse = api.portal.get_registry_record( name='collective.sidebar.mouse', default=True, ) if mouse: return 'true' else: return 'false' def get_mouse_area(self): """Pass in values to be used in JavaScript """ mouse_area = api.portal.get_registry_record( name='collective.sidebar.mouse_area', default=30, ) return str(mouse_area) def get_sidebar_position(self): position = api.portal.get_registry_record( name='collective.sidebar.sidebar_position', default='left', ) css_class = 'sidebar-' + position return css_class def _contentCanBeAdded(self, addContext, request): """ Find out if content can be added either by local constraints on the current context or by allowed_content_types on the FTI. """ constrain = IConstrainTypes(addContext, None) if constrain is None: return _allowedTypes(request, addContext) return constrain.getLocallyAllowedTypes() def is_anonymous(self): """ Check if the user is anonymous. """ return api.user.is_anonymous() def get_portal_url(self): """ Return the portal URL. """ return api.portal.get().absolute_url() def get_static_links(self): """ Return sidebar links from portal_actions. """ links = self.context.portal_actions.listFilteredActionsFor(self.context) # noqa: 501 sidebar_links = links.get('sidebar_links', []) return sidebar_links def get_user_data(self): user = get_user() mtool = api.portal.get_tool('portal_membership') portrait = mtool.getPersonalPortrait(id=user[1]) user_info = mtool.getMemberInfo(user[1]) portal_url = self.get_portal_url() data = { 'user_info': user_info, 'portrait': portrait.absolute_url(), 'user_url': portal_url + '/@@personal-information', } return data def get_navigation_root_url(self): """ Return navigation root URL based on the language. """ navigation_root = api.portal.get_navigation_root(self.context) return navigation_root.absolute_url() def get_back(self): """ Get link to parent. """ context = self.context portal = api.portal.get() parent = context.aq_parent root_nav = api.portal.get_registry_record( name='collective.sidebar.root_nav', default=False, ) if context == portal or context.portal_type == 'LRF' or root_nav: return None try: if parent.default_page == context.id: if parent == api.portal.get_navigation_root(context): return None return parent.aq_parent.absolute_url() except AttributeError: pass return parent.absolute_url() def can_edit(self): """ Check if the user can modify content. """ permission = permissions.ModifyPortalContent if api.user.has_permission(permission, obj=self.context): return True return False def can_manage_portal(self): """ Check is user can manage the portal. """ permission = permissions.ManagePortal if api.user.has_permission(permission, obj=self.context): return True return False def check_displayed_types(self, item): """ Check settings if content type should be displayed in navigation. """ types = api.portal.get_registry_record(name='plone.displayed_types') if item.portal_type not in types: return True def check_filter_on_workflow(self, item): """ Check workflow settings if item should be displayed in navigation. """ filter = api.portal.get_registry_record( name='plone.filter_on_workflow', ) states = api.portal.get_registry_record( name='plone.workflow_states_to_show', ) if filter: state = api.content.get_state(obj=item.getObject()) if state not in states: return True def check_item(self, item): """ Check if we want to have the given item in the navigation. """ if self.check_displayed_types(item): return False if self.check_filter_on_workflow(item): return False if item.exclude_from_nav: return False try: if self.context.default_page == item.id: return False except AttributeError: pass return True def get_items(self): """ Get folder contents and return. """ context = self.context root_nav = api.portal.get_registry_record( name='collective.sidebar.root_nav', default=False, ) if root_nav: context = api.portal.get_navigation_root(context) contents = [] if IFolderish.providedBy(context): contents = context.getFolderContents() else: # Can not remember what edgecase we catch here. try: parent = context.aq_parent contents = parent.getFolderContents() except Exception: # noqa: 902 pass items = [] for item in contents: if self.check_item(item): data = { 'title': item.Title, 'title_cropped': crop(item.Title, 100), 'url': item.getURL(), } items.append(data) return items def get_folder_contents_url(self): """ Get URL to folder_contents. """ context = self.context parent = context.aq_parent context_url = context.absolute_url() + '/folder_contents' parent_url = parent.absolute_url() + '/folder_contents' try: if parent.default_page == context.id: return parent_url except AttributeError: pass if IFolderish.providedBy(context): return context_url else: return parent_url def get_workflow_state_title(self): """ Returns the workflow state title. """ state = self.get_workflow_state() tools = getMultiAdapter( (self.context, self.request), name='plone_tools', ) workflows = tools.workflow().getWorkflowsFor(self.context) if workflows: for w in workflows: if state in w.states: return w.states[state].title or state def has_workflow(self): """ Check if there is a workflow for the current context. """ state = self.get_workflow_state() return state is not None def has_workflow_state_color(self): """ Returns a CSS class for workflow state: - with-state-color - without-state-color TODO: This should be a switch in the backend # noqa: T000 to enable colored states. """ return 'with-state-color' def get_workflow_state(self): """ Return the workflow state for the current context. """ return api.content.get_state(self.context, None) def get_workflow_actions(self): """ Return menu item entries in a TAL-friendly form. """ from plone.app.contentmenu import PloneMessageFactory as _ context = self.context request = context.REQUEST try: pkg_resources.get_distribution('Products.CMFPlacefulWorkflow') from Products.CMFPlacefulWorkflow.permissions import ManageWorkflowPolicies # noqa: 501 except pkg_resources.DistributionNotFound: from Products.CMFCore.permissions import ManagePortal as ManageWorkflowPolicies # noqa: 501 results = [] locking_info = queryMultiAdapter( (context, request), name='plone_lock_info', ) if locking_info and locking_info.is_locked_for_current_user(): return [] wf_tool = api.portal.get_tool('portal_workflow') workflowActions = wf_tool.listActionInfos(object=context) for action in workflowActions: if action['category'] != 'workflow': continue cssClass = '' actionUrl = action['url'] if actionUrl == '': actionUrl = '{0}/content_status_modify?workflow_action={1}' actionUrl = actionUrl.format( context.absolute_url(), action['id'], ) cssClass = '' description = '' transition = action.get('transition', None) if transition is not None: description = transition.description if action['allowed']: results.append({ 'title': action['title'], 'description': description, 'action': addTokenToUrl(actionUrl, request), 'selected': False, 'icon': None, 'extra': { 'id': 'workflow-transition-{0}'.format(action['id']), 'separator': None, 'class': cssClass, }, 'submenu': None, }) url = context.absolute_url() try: pw = api.portal.get_tool('portal_placeful_workflow') except InvalidParameterError: pw = None if pw is not None: permission = 'ManageWorkflowPolicies' if api.user.has_permission(permission, obj=self.context): results.append({ 'title': _(u'workflow_policy', default=u'Policy...'), 'description': '', 'action': url + '/placeful_workflow_configuration', 'selected': False, 'icon': None, 'extra': { 'id': 'workflow-transition-policy', 'separator': None, 'class': '', }, 'submenu': None, }) return results @staticmethod def is_actions_enabled(): """ Should actions be shown """ return api.portal.get_registry_record( name='collective.sidebar.enable_actions', default=True, ) def cookies_enabled(self): """ Should cookie support be enabled """ return api.portal.get_registry_record( 'collective.sidebar.enable_cookies', default=False, ) def collapse_enabled(self): """ Should collapsible sections be enabled """ return api.portal.get_registry_record( 'collective.sidebar.enable_collapse', default=False, ) def get_section_state(self, section_name=''): """ Return section 'collapsed' state """ if self.cookies_enabled() and self.collapse_enabled(): sections = self.request.get('sections', '') if sections: sections = sections.split(',') if section_name in sections: return 'menu-section collapsed' return 'menu-section' def get_actions(self): """ Returns registred object_actions like cut, copy, paste, ... """ portal = api.portal.get() actions = portal.portal_actions.listFilteredActionsFor(self.context) buttons = list() if actions: buttons = actions.get('object_buttons', list()) for action in buttons: if not action.get('icon', None): action.icon = self.get_icon(action.get('id', None)) if action.get('url', None): action.url = addTokenToUrl(action.get('url'), self.request) return buttons def get_addable_items(self): """ Return menu item entries in a TAL-friendly form. """ context = self.context request = self.request factories_view = getMultiAdapter( (context, request), name='folder_factories', ) include = None addContext = factories_view.add_context() constraints = IConstrainTypes(addContext, None) if constraints is not None: include = constraints.getImmediatelyAddableTypes() results = factories_view.addable_types(include=include) results_with_icons = [] for result in results: result['icon'] = 'menu-item-icon {0}'.format(self.get_icon('plus')) results_with_icons.append(result) results = results_with_icons constraints = ISelectableConstrainTypes(addContext, None) if constraints is not None: if constraints.canSetConstrainTypes() and \ constraints.getDefaultAddableTypes(): url = '{0}/folder_constraintypes_form'.format( addContext.absolute_url(), ) results.append({ 'title': _(u'folder_add_settings', default=u'Restrictions'), 'description': _( u'title_configure_addable_content_types', default=u'Configure which content types can be ' u'added here', ), 'action': url, 'selected': False, 'icon': 'menu-item-icon {0}'.format(self.get_icon('cog')), 'id': 'settings', 'extra': { 'id': 'plone-contentmenu-settings', 'separator': None, 'class': '', }, 'submenu': None, }) # Also add a menu item to add items to the default page context_state = getMultiAdapter( (context, request), name='plone_context_state', ) if context_state.is_structural_folder() and \ context_state.is_default_page() and \ self._contentCanBeAdded(context, request): results.append({ 'title': _(u'default_page_folder', default=u'Add item to default page'), 'description': _( u'desc_default_page_folder', default=u'If the default page is also a folder, ' u'add items to it from here.', ), 'action': context.absolute_url() + '/@@folder_factories', 'selected': False, 'icon': 'menu-item-icon {0}'.format(self.get_icon('cog')), 'id': 'special', 'extra': { 'id': 'plone-contentmenu-add-to-default-page', 'separator': None, 'class': 'pat-plone-modal', }, 'submenu': None, }) return results def _get_context_state(self): return getMultiAdapter((self.context, self.request), name='plone_context_state') def get_default_view_link(self): context_state = self._get_context_state() if context_state.is_default_page(): parent = context_state.parent() return parent.absolute_url() + '/select_default_view' else: return self.context.absolute_url() + '/select_default_view' def get_default_page_link(self): context_state = self._get_context_state() if context_state.is_default_page(): parent = context_state.parent() return parent.absolute_url() + '/select_default_page' else: return self.context.absolute_url() + '/select_default_page' def get_icon(self, icon): return get_icon(icon) def get_navigation_class(self): """ Check if dynamic navigation is enabled """ root_nav = api.portal.get_registry_record( name='collective.sidebar.root_nav', default=False, ) dynamic = api.portal.get_registry_record( name='collective.sidebar.dynamic_navigation', default=False, ) if root_nav: return 'navigation-static' if dynamic: return 'navigation-dynamic' else: return 'navigation-static'
class FolderPdfBody (BrowserView): """ Override folder pdf body """ template = ViewPageTemplateFile("pt/folder.body.pt") def __init__(self, context, request): super(FolderPdfBody, self).__init__(context, request) self._macro = "content-core" self._theme = None self._maxdepth = None self._maxbreadth = None self._maxitems = None self._depth = 0 self._count = 1 def theme(self, context=None): """ PDF Theme """ if context: tool = queryUtility(IPDFTool) return tool.theme(context) if self._theme is None: tool = queryUtility(IPDFTool) self._theme = tool.theme(self.context) return self._theme def getValue(self, name, context='', default=None): """ Get value """ if context == '': context = self.context getField = getattr(context, 'getField', lambda name: None) field = getField(name) if not field: return default value = field.getAccessor(context)() return value or default @property def macro(self): """ ZPT macro to use while rendering PDF """ return self._macro @property def maxdepth(self): """ Maximum depth """ if self._maxdepth is None: self._maxdepth = self.getValue( 'pdfMaxDepth', default=self.getValue('maxdepth', self.theme(), default=0)) return self._maxdepth @property def maxbreadth(self): """ Maximum breadth """ if self._maxbreadth is None: self._maxbreadth = self.getValue( 'pdfMaxBreadth', default=self.getValue( 'maxbreadth', self.theme(), default=0)) return self._maxbreadth @property def maxitems(self): """ Maximum items """ if self._maxitems is None: self._maxitems = self.getValue( 'pdfMaxItems', default=self.getValue('maxitems', self.theme(), default=0)) return self._maxitems @property def depth(self): """ Current depth """ return self._depth @property def count(self): """ Current counter """ return self._count @property def brains(self): """ Brains """ return self.context.getFolderContents()[:self.maxbreadth] def show_limit_page(self): """ Returns the pdf limit page """ pdf = self.context.restrictedTraverse("@@pdf.limit") return pdf() @property def pdfs(self): """ Folder children """ self._depth += 1 if not self.request.get('pdf_last_brain_url'): brains = self.context.getFolderContents( contentFilter={ 'portal_type': ['Folder', 'Collection', 'Topic'] }) if brains: self.request['pdf_last_brain_url'] = brains[-1].getURL() # 31424 in case there is only one result from the content # filter then we need to reset the depth in order to # get the content of the brain if len(brains) == 1: self._depth -= 1 if self.depth > self.maxdepth: if self.context.absolute_url() == \ self.request.get('pdf_last_brain_url'): yield self.show_limit_page() return ajax_load = self.request.get('ajax_load', True) self.request.form['ajax_load'] = ajax_load for brain in self.brains: if self.count > self.maxitems: if not self.request.get('pdflimit'): self.request['pdflimit'] = "reached" yield self.show_limit_page() break doc = brain.getObject() theme = self.theme(doc) body = getattr(theme, 'body', '') if not body: continue if isinstance(body, unicode): body = body.encode('utf-8') if (self.theme(self.context).id == theme.id and self.depth == self.maxdepth): if brain.getURL() == self.request.get('pdf_last_brain_url'): if not self.request.get('pdflimit'): self.request['pdflimit'] = "reached" yield self.show_limit_page() continue try: pdf = doc.restrictedTraverse(body.split("?")[0]) self._count += 1 html = pdf( macro=self.macro, maxdepth=self.maxdepth, maxbreadth=self.maxbreadth, maxitems=self.maxitems, depth=self.depth, count=self.count ) except Exception: continue else: self._count = getattr(pdf, 'count', self._count) yield html self.request.form['ajax_load'] = ajax_load def update(self, **kwargs): """ Update counters """ self._macro = kwargs.get('macro', self._macro) self._maxdepth = kwargs.get('maxdepth', None) self._maxbreadth = kwargs.get('maxbreadth', None) self._maxitems = kwargs.get('maxitems', None) self._depth = kwargs.get('depth', self._depth) self._count = kwargs.get('count', self._count) def __call__(self, **kwargs): kwargs.update(self.request.form) self.update(**kwargs) return self.template(**kwargs)
class TempleView(BrowserView): """Default view of a Temple """ implements(ITempleView) __call__ = ViewPageTemplateFile('temple.pt') def deity_term(self, value): factory = getUtility(IVocabularyFactory, 'deity_name') vocabulary = factory(self.context) try: existing = vocabulary.getTerm(value) return existing.title.split(',')[0] except LookupError: return value def t_title(self, vocab, value): factory = getUtility(IVocabularyFactory, vocab) vocabulary = factory(self.context) try: term = vocabulary.getTerm(value) return term.title except LookupError: return None def getTemplePilgrimage(self, temple): portal_catalog = getToolByName(self.context, 'portal_catalog') reference_catalog = getToolByName(self.context, REFERENCE_CATALOG) results = [] # pil used here, but they are schedules actually. pil_uids = [ r.sourceUID for r in reference_catalog.searchResults( targetUID=temple.UID(), relationship='temples_in_pilgrimage') ] if pil_uids: pil_brains = portal_catalog.searchResults(portal_type='Schedule', UID=pil_uids, sort_on='sortable_title') for brain in pil_brains: url = brain.getURL() obj = brain.getObject() parent = obj.aq_inner.aq_parent full_title = parent.Title() + obj.Title() results.append(dict( url=url, full_title=full_title, )) return results def getTempleFestival(self, temple): portal_catalog = getToolByName(self.context, 'portal_catalog') reference_catalog = getToolByName(temple, REFERENCE_CATALOG) results = [] fsv_uids = [ r.sourceUID for r in reference_catalog.searchResults(targetUID=temple.UID(), relationship='relatesTo') ] if fsv_uids: fsv_brains = portal_catalog.searchResults(portal_type='Event', UID=fsv_uids, sort_on='start', sort_order='ascending') for brain in fsv_brains: results.append( dict( url=brain.getURL(), full_title=str(brain.start)[:4] + '年' + brain.Title, )) return results def getTempleBiXieWu(self, temple): portal_catalog = getToolByName(self.context, 'portal_catalog') reference_catalog = getToolByName(temple, REFERENCE_CATALOG) results = [] bxw_uids = [ r.sourceUID for r in reference_catalog.searchResults( targetUID=temple.UID(), relationship='temple_bixiewu') ] if bxw_uids: bxw_brains = portal_catalog.searchResults(portal_type='BiXieWu', UID=bxw_uids) for brain in bxw_brains: results.append(dict( url=brain.getURL(), title=brain.Title, )) return results
def fetchcomments(self,uid,itemindex,lasttimestamp,commentcount,lastcommentid,viewtype): query = {'UID':uid} pdt = getToolByName(self.context, 'portal_discussion', None) cat = getToolByName(self.context, 'uid_catalog') resbrains = cat.searchResults(query) if len(resbrains) == 1: zopecommands = self.getCommandSet('zope') ksscore = self.getCommandSet('core') jq = self.getCommandSet('jquery') listcommentcontainer = ksscore.getHtmlIdSelector('comcynapselistcommentscontainer' + itemindex) listcountspan = ksscore.getHtmlIdSelector('commentcountspan' + itemindex) nocommentsyet = ksscore.getCssSelector('.nocommentsyet') listtimeoutuid = ksscore.getHtmlIdSelector('comcynapsecyninfetchUID') listtimeoutindex = ksscore.getHtmlIdSelector('comcynapsecyninfetchindex') listtimeouttimestamp = ksscore.getHtmlIdSelector('comcynapselasttimestamp') listtimeoutlastcommentid = ksscore.getHtmlIdSelector('comcynapselastcommentid') listtimeoutcommentcount = ksscore.getHtmlIdSelector('comcynapsecommentcount') listcommentscount = ksscore.getHtmlIdSelector('listdiscussioncount' + itemindex) contobj = resbrains[0].getObject() isDiscussable = contobj.isDiscussable() canReply = self.canreply(contobj) if isDiscussable and canReply: passedcommentcount = 0 passedcommentcount = int(commentcount) flasttimestamp = float(lasttimestamp) datefromlasttimestamp = DateTime(flasttimestamp) newlastdate = datefromlasttimestamp.timeTime() disc_container = pdt.getDiscussionFor(contobj) newreplycount = disc_container.replyCount(contobj) allreplies = self.get_replies(pdt,contobj) if passedcommentcount <> newreplycount: alldiscussions = disc_container.objectValues() newlastcommentid = lastcommentid newlyaddedcomments = [k for k in alldiscussions if k.modified().greaterThan(datefromlasttimestamp) and k.id not in (lastcommentid)] newlyaddedcomments.sort(lambda x,y:cmp(x.modified(),y.modified())) lenofnewcomments = len(newlyaddedcomments) display_count = self.get_displaycountforlist() lastxdiscussions = [] if lenofnewcomments >= display_count: newlyaddedcomments.sort(lambda x,y:cmp(x.modified(),y.modified()),reverse=True) lastxdiscussions = newlyaddedcomments[:display_count] lastxdiscussions.sort(lambda x,y:cmp(x.modified(),y.modified())) ksscore.clearChildNodes(listcommentcontainer) else: lastxdiscussions = newlyaddedcomments if lenofnewcomments > 0 and len(alldiscussions) > display_count: alldiscussions.sort(lambda x,y:cmp(x.modified(),y.modified()),reverse=True) marker_discussion = alldiscussions[display_count-1: display_count] if len(marker_discussion) > 0: #delete nodes before this item marker_node = ksscore.getHtmlIdSelector('commenttable' + marker_discussion[0].id) ksscore.deleteNodeBefore(marker_node) complete_output = '' list_reply_ids = [] for eachcomment in lastxdiscussions: reply = disc_container.getReply(eachcomment.id) if reply <> None: parentsInThread = reply.parentsInThread() depthvalue = 0 if viewtype.lower() == 'threadedview': lenofparents = len(parentsInThread) depthvalue = lenofparents - 1 prev_reply_id = self.findpreviouscommentid(allreplies,reply) newlastdate = reply.modified().timeTime() newlastcommentid = reply.id commenttemplate = ViewPageTemplateFile('ksstemplates/commentrow.pt') commenttemplate = commenttemplate.__of__(self.context) replydict = [{'depth': depthvalue, 'object': reply,'prev_id':prev_reply_id,'view_type':viewtype, 'showoutput':False},] output = commenttemplate.render(reply_dict=replydict,allowdiscussion = isDiscussable,usercanreply = canReply) list_reply_ids.append(reply.id) complete_output += output if complete_output <> '' and len(lastxdiscussions) > 0: ksscore.insertHTMLAsLastChild(listcommentcontainer,complete_output) for erid in list_reply_ids: newcomment = ksscore.getHtmlIdSelector('commenttable' + erid) jq.serverEffect(newcomment,"fadeIn", "slow") ksscore.setAttribute(listtimeoutuid,'value',uid) ksscore.setAttribute(listtimeoutindex,'value',itemindex) ksscore.setAttribute(listtimeouttimestamp,'value',str(newlastdate)) ksscore.setAttribute(listtimeoutlastcommentid,'value',newlastcommentid) ksscore.setAttribute(listtimeoutcommentcount,'value',str(newreplycount)) ksscore.setAttribute(listtimeoutuid,'value',uid) if newreplycount > display_count: xmorecomments = newreplycount - display_count ksscore.replaceInnerHTML(listcommentscount,str(xmorecomments)) jq.serverEffect(nocommentsyet,"fadeOut", "fast") jq.serverEffect(listcountspan,"fadeIn", "slow") elif newreplycount > 0 and newreplycount <= display_count: jq.serverEffect(nocommentsyet,"fadeOut", "fast") jq.serverCall(listcommentcontainer,'truncatetextonitemexpand')
class EditView(BrowserView): template = ViewPageTemplateFile('templates/batch_edit.pt') def __call__(self): request = self.request context = self.context self.form = request.form if 'submitted' in request: try: self.validate_form_input() except ValidationError as e: self.form_error(e.message) return context.setConstrainTypesMode(constraintypes.DISABLED) portal_factory = getToolByName(context, 'portal_factory') folder = context.aq_parent batch = None if not folder.hasObject(context.getId()): batch = portal_factory.doCreate(context, context.id) else: batch = context old_qty = int(batch.Quantity or 0) new_qty = int(self.form.get('Quantity', 0)) membership = getToolByName(self.context, 'portal_membership') if membership.isAnonymousUser(): member = 'anonymous' else: member = membership.getAuthenticatedMember().getUserName() batch.getField('ChangeUserName').set(batch, member) batch.getField('ChangeDateTime').set(batch, DateTime()) if not batch.getField('DateCreated').get(batch): batch.getField('DateCreated').set(batch, DateTime()) batch.processForm() self.create_samples(batch, self.form, new_qty - old_qty, member) batch.getField('BatchId').set(batch, batch.Title()) batch.reindexObject() obj_url = batch.absolute_url_path() request.response.redirect(obj_url) return return self.template() def validate_form_input(self): subject_id = self.form.get('SubjectID') if not subject_id: raise ValidationError(['Subject ID cannot be empty!']) date_created = self.form.get('DateCreated') if not date_created: raise ValidationError(['Date Created cannot be empty!']) new_qty = int(self.form.get('Quantity', 0)) old_qty = int(self.context.Quantity or 0) if new_qty <= 0: raise ValidationError( 'Quantity of samples cannot be zero or less than zero!') if new_qty < old_qty: raise ValidationError( 'New number of samples cannot be less than the number of samples already created!' ) def get_biospecimen_storages(self): """Take a list of UIDs from the form, and resolve to a list of Storages. Accepts ManagedStorage, UnmanagedStorage, or StoragePosition UIDs. """ uc = getToolByName(self.context, 'uid_catalog') bio_storages = [] # form_uids = self.form['StorageLocation_uid'].split(',') form_uids = self.form['StorageLocation_uid'].split( ',') if self.form['StorageLocation_uid'] else [] for uid in form_uids: brain = uc(UID=uid)[0] instance = brain.getObject() if IManagedStorage.providedBy(instance) \ or len(instance.get_free_positions()) > 0: bio_storages.append(instance) return bio_storages def create_samples(self, context, form, num_samples, member=None): """Create samples from form """ sample_type = get_first_sampletype(context) uc = getToolByName(context, 'uid_catalog') project_uid = form.get('Project_uid', '') project = uc(UID=project_uid)[0].getObject() samples_gen = SampleGeneration(form, project) subject_id = form['SubjectID'] try: parent_sample_uid = form.get('ParentBiospecimen_uid') parent_sample = uc(UID=parent_sample_uid)[0].getObject() parent_sampling_date = parent_sample.getField('SamplingDate').get( parent_sample) except: parent_sampling_date = None samples = [] for i in range(num_samples): sample = samples_gen.create_sample(None, sample_type, context) sample.getField('SubjectID').set(sample, subject_id) sample.getField('SamplingDate').set(sample, parent_sampling_date) if member: sample.getField('ChangeUserName').set(sample, member) sample.getField('ChangeDateTime').set(sample, DateTime()) samples.append(sample) storages = self.get_biospecimen_storages() if storages: samples_gen.store_samples(samples, storages) for storage in storages: storage.reindexObject() return samples def get_fields_with_visibility(self, visibility, mode=None): mode = mode if mode else 'edit' schema = self.context.Schema() fields = [] for field in schema.fields(): isVisible = field.widget.isVisible v = isVisible(self.context, mode, default='invisible', field=field) if v == visibility: fields.append(field) return fields def form_error(self, msg): self.context.plone_utils.addPortalMessage(msg) self.request.response.redirect(self.context.absolute_url())
def replyToComment(self,viewtype,lasttimestamp,commentcount,lastcommentid): query = {'UID':self.request['cont_uid']} pdt = getToolByName(self.context, 'portal_discussion', None) cat = getToolByName(self.context, 'uid_catalog') resbrains = cat.searchResults(query) ksscore = self.getCommandSet('core') zopecore = self.getCommandSet('zope') jq = self.getCommandSet('jquery') if len(resbrains) == 1: contobj = resbrains[0].getObject() if contobj.isDiscussable() and self.canreply(contobj): mtool = getToolByName(self.context, 'portal_membership') username = mtool.getAuthenticatedMember().getId() dobj = pdt.getDiscussionFor(contobj) if len(self.request['commentbody'].strip(' ')) == 0 or self.request['commentbody'].lower() == self.request['comcynapsenewcommenttitle'].lower(): comcynapsecommenterrorlabel = ksscore.getHtmlIdSelector('comcynapsecommenterror'+ self.request['inreplyto']) ksscore.setStyle(comcynapsecommenterrorlabel,'display','block') else: id = dobj.createReply(title="", text=self.request['commentbody'], Creator=username) reply = dobj.getReply(id) reply.cooked_text = convertWebIntelligentPlainTextToHtml(reply.text) replyto = dobj.getReply(self.request['inreplyto']) reply.setReplyTo(replyto) if reply <> None: from ubify.cyninv2theme import triggerAddOnDiscussionItem triggerAddOnDiscussionItem(reply) #################Determine full reply to discussion to get placement peer of current comment view_type = self.request['cviewtype'] replies = [] def getRs(obj, replies, counter): rs = pdt.getDiscussionFor(obj).getReplies() if len(rs) > 0: rs.sort(lambda x, y: cmp(x.modified(), y.modified())) for r in rs: replies.append({'depth':counter, 'object':r}) getRs(r, replies, counter=counter + 1) getRs(replyto, replies, 0) if len(replies) > 1: ##There are more than 1 comments already children of the comment we just replied to, so the current comment can't have been the first reply prevrep = replies[0]['object'] else: prevrep = replyto for rep in replies: if rep['object'].id == reply.id: belowreply = prevrep else: prevrep = rep['object'] mi = mtool.getMemberInfo(); commenttemplate = ViewPageTemplateFile('ksstemplates/commentrow.pt') commenttemplate = commenttemplate.__of__(self.context) depthvalue = 0 if view_type == 'threadedview': depthvalue = int(self.request['depth']) + 1 replydict = [{'depth': depthvalue, 'object': reply,'view_type':view_type},] output = commenttemplate.render(indent=int(self.request['depth'])+2,fullname = mi['fullname'], avatarurl=self.context.portal_membership.getPersonalPortrait(username).absolute_url(),creator=username,showreply=self.canreply(self.context),showdelete=getSecurityManager().checkPermission('Manage portal',aq_inner(self.context)),commenttime=self.context.toLocalizedTime(reply.created,True),replyid=reply.id,replytitle=reply.Title(),replybody=reply.CookedBody(),replyurl=reply.absolute_url(),reply_dict=replydict) if view_type == 'threadedview': commentscontainer = ksscore.getHtmlIdSelector('commenttable' + prevrep.id) ksscore.insertHTMLAfter(commentscontainer,output) else: commentsoutercontainer = ksscore.getHtmlIdSelector('comcynapsecyninitemcommentscontainer') ksscore.insertHTMLAsLastChild(commentsoutercontainer,output) taAddNewComment = ksscore.getCssSelector('textarea.commentbodyta') ksscore.setAttribute(taAddNewComment,"value","") itemcountcommentcount = ksscore.getHtmlIdSelector('itemcountcommentcount') countofcomments = dobj.replyCount(self.context) discussionlabel = ksscore.getHtmlIdSelector('discussionlabel') ksscore.replaceInnerHTML(discussionlabel,str(countofcomments)) ksscore.replaceInnerHTML(itemcountcommentcount,str(countofcomments)) newcomment = ksscore.getHtmlIdSelector('commenttable' + reply.id) frmreply = ksscore.getHtmlIdSelector('replyform' + self.request['inreplyto']) ksscore.setStyle(frmreply,'display','none') comcynapsecommenterrorlabel = ksscore.getHtmlIdSelector('comcynapsecommenterror'+ self.request['inreplyto']) ksscore.setStyle(comcynapsecommenterrorlabel,'display','none') self.fetchnewcomments(lasttimestamp,commentcount,lastcommentid,viewtype)
def toggleCommentsView(self,viewtype): zopecommands = self.getCommandSet('zope') ksscore = self.getCommandSet('core') jq = self.getCommandSet('jquery') commentshiddencontainer = ksscore.getHtmlIdSelector('comcynapsehiddencomments') commentscontainer = ksscore.getHtmlIdSelector('comcynapsecyninitemcommentscontainer') addnewlasttimestamp = ksscore.getHtmlIdSelector('comcynapselasttimestamp') addnewlastcommentid = ksscore.getHtmlIdSelector('comcynapselastcommentid') addnewcommentcount = ksscore.getHtmlIdSelector('comcynapsecommentcount') objcommentslist = [] pdt = getToolByName(self.context, 'portal_discussion', None) if pdt <> None: disc_container = pdt.getDiscussionFor(self.context) alldiscussions = disc_container.objectValues() allreplies = self.get_replies(pdt,self.context) newreplycount = disc_container.replyCount(self.context) newlastdate = DateTime().timeTime() if viewtype == 'flatview': alldiscussions.sort(lambda x,y:cmp(x.modified(),y.modified())) objcommentslist.extend(alldiscussions) else: objcommentslist.extend(allreplies) ksscore.replaceInnerHTML(commentscontainer,'') complete_output = '' for eachcomment in objcommentslist: if hasattr(eachcomment,'id'): id = eachcomment.id elif eachcomment.has_key('id'): id = eachcomment['id'] reply = disc_container.getReply(id) if reply <> None: parentsInThread = reply.parentsInThread() depthvalue = 0 if viewtype.lower() == 'threadedview': lenofparents = len(parentsInThread) depthvalue = lenofparents - 1 prev_reply_id = self.findpreviouscommentid(allreplies,reply) newlastdate = reply.modified().timeTime() commenttemplate = ViewPageTemplateFile('ksstemplates/commentrow.pt') commenttemplate = commenttemplate.__of__(self.context) replydict = [{'depth': depthvalue, 'object': reply,'prev_id':prev_reply_id,'view_type':viewtype,'showoutput':True},] output = commenttemplate.render(reply_dict=replydict) #if there is no prev id found for new comment then insert it as last item to commentscontainer #else insert it after prev id comments table. if viewtype == 'flatview': complete_output += output else: complete_output += output if complete_output <> '' and len(objcommentslist) > 0: ksscore.replaceInnerHTML(commentscontainer,complete_output) jq.serverCall(commentscontainer,'truncatetextonitemexpand') if len(alldiscussions) > 0: strlastcommentid = str(alldiscussions[-1].id) ksscore.setKssAttribute(commentshiddencontainer,'lastcommentid',strlastcommentid) ksscore.setAttribute(addnewlastcommentid,'value',strlastcommentid) newlasttimestamp = str(newlastdate) strcommentcount = str(newreplycount) ksscore.setKssAttribute(commentshiddencontainer,'lasttimestamp',newlasttimestamp) ksscore.setKssAttribute(commentshiddencontainer,'commentcount',strcommentcount) ksscore.setAttribute(addnewlasttimestamp,'value',newlasttimestamp) ksscore.setAttribute(addnewcommentcount,'value',strcommentcount) itemcountcommentcount = ksscore.getHtmlIdSelector('itemcountcommentcount') discussionlabel = ksscore.getHtmlIdSelector('discussionlabel') ksscore.replaceInnerHTML(discussionlabel,strcommentcount) ksscore.replaceInnerHTML(itemcountcommentcount,strcommentcount) ksscore.setKssAttribute(commentshiddencontainer,'viewtype',viewtype) addnewcommentviewtype = ksscore.getHtmlIdSelector('comcynapseviewtype') ksscore.setAttribute(addnewcommentviewtype,'value',viewtype) ksscore.setStyle(commentscontainer,'display','block')
class TinyLogoViewlet(ViewletBase): index = ViewPageTemplateFile('tiny_logo.pt')
class FooterViewlet(ViewletBase): index = ViewPageTemplateFile('footer.pt') def update(self): super(FooterViewlet, self).update() self.year = date.today().year
class SampleEdit(BrowserView): """ Edit view """ implements(IViewView) template = ViewPageTemplateFile("templates/sample.pt") header_table = ViewPageTemplateFile("../templates/header_table.pt") def __init__(self, context, request): BrowserView.__init__(self, context, request) self.icon = self.portal_url + "/++resource++bika.lims.images/sample_big.png" self.allow_edit = True self.context_actions = {} def now(self): return DateTime() def getDefaultSpec(self): """ Returns 'lab' or 'client' to set the initial value of the specification radios """ mt = getToolByName(self.context, 'portal_membership') pg = getToolByName(self.context, 'portal_groups') member = mt.getAuthenticatedMember() member_groups = [pg.getGroupById(group.id).getGroupName() \ for group in pg.getGroupsByUserId(member.id)] default_spec = ('Clients' in member_groups) and 'client' or 'lab' return default_spec def __call__(self): if 'transition' in self.request.form: doActionFor(self.context, self.request.form['transition']) # Add an Analysis request creation button mtool = get_tool('portal_membership', context=self.context) if mtool.checkPermission(AddAnalysisRequest, self.context): self.context_actions[_('Add Analysis Request')] = \ {'url': "ar_add?ar_count=1", 'icon': '++resource++bika.lims.images/add.png'} ## render header table self.header_table = HeaderTableView(self.context, self.request) ## Create Sample Partitions table parts_table = None if not self.allow_edit: p = SamplePartitionsView(self.context, self.request) p.allow_edit = self.allow_edit p.show_select_column = self.allow_edit p.show_workflow_action_buttons = self.allow_edit p.show_column_toggles = False p.show_select_all_checkbox = False p.review_states[0]['transitions'] = [ { 'id': 'empty' }, ] # none parts_table = p.contents_table() self.parts = parts_table ## Create Field and Lab Analyses tables self.tables = {} if not self.allow_edit: for poc in POINTS_OF_CAPTURE: t = SampleAnalysesView(self.context, self.request, getPointOfCapture=poc, sort_on='getId') t.form_id = "sample_%s_analyses" % poc if poc == 'field': t.review_states[0]['columns'].remove('DueDate') t.show_column_toggles = False t.review_states[0]['transitions'] = [{ 'id': 'submit' }, { 'id': 'retract' }, { 'id': 'verify' }] self.tables[POINTS_OF_CAPTURE.getValue( poc)] = t.contents_table() return self.template() def tabindex(self): i = 0 while True: i += 1 yield i
class ContentViewsViewlet(ViewletBase): index = ViewPageTemplateFile('contentviews.pt') @memoize def prepareObjectTabs(self, default_tab='view', sort_first=['folderContents']): """Prepare the object tabs by determining their order and working out which tab is selected. Used in global_contentviews.pt """ context = aq_inner(self.context) context_url = context.absolute_url() context_fti = context.getTypeInfo() context_state = getMultiAdapter((context, self.request), name=u'plone_context_state') actions = context_state.actions action_list = [] if context_state.is_structural_folder(): action_list = actions('folder') action_list.extend(actions('object')) tabs = [] found_selected = False fallback_action = None try: request_url = self.request['ACTUAL_URL'] except KeyError: # not a real request, could be a test. Let's not fail. request_url = context_url request_url_path = request_url[len(context_url):] if request_url_path.startswith('/'): request_url_path = request_url_path[1:] for item in action_list: item.update({'selected': False}) action_url = item['url'].strip() starts = action_url.startswith if starts('http') or starts('javascript'): item['url'] = action_url else: item['url'] = '%s/%s' % (context_url, action_url) item['url'] = addTokenToUrl(item['url'], self.request) action_method = item['url'].split('/')[-1].split('?')[0] # Action method may be a method alias: # Attempt to resolve to a template. action_method = context_fti.queryMethodID(action_method, default=action_method) if action_method: request_action = unquote(request_url_path).split('?')[0] request_action = context_fti.queryMethodID( request_action, default=request_action) if action_method == request_action: item['selected'] = True found_selected = True current_id = item['id'] if current_id == default_tab: fallback_action = item modal = item.get('modal', None) item['cssClass'] = '' if modal: item['cssClass'] += ' pat-modal' item['url'] += '?ajax_load=1' tabs.append(item) if not found_selected and fallback_action is not None: fallback_action['selected'] = True def sortOrder(tab): try: return sort_first.index(tab['id']) except ValueError: return 255 tabs.sort(key=sortOrder) return tabs
class FolderView(BikaListingView): implements(IFolderContentsView, IViewView) template = ViewPageTemplateFile("../templates/worksheets.pt") def __init__(self, context, request): super(FolderView, self).__init__(context, request) self.catalog = 'bika_catalog' self.contentFilter = { 'portal_type': 'Worksheet', 'review_state': ['open', 'to_be_verified', 'verified', 'rejected'], 'sort_on': 'id', 'sort_order': 'reverse' } self.context_actions = { _('Add'): { 'url': 'worksheet_add', 'icon': '++resource++bika.lims.images/add.png', 'class': 'worksheet_add' } } self.show_table_only = False self.show_sort_column = False self.show_select_row = False self.show_select_all_checkbox = True self.show_select_column = True self.pagesize = 25 self.restrict_results = False request.set('disable_border', 1) self.icon = self.portal_url + "/++resource++bika.lims.images/worksheet_big.png" self.title = self.context.translate(_("Worksheets")) self.description = "" pm = getToolByName(context, "portal_membership") # this is a property of self, because self.getAnalysts returns it self.analysts = getUsers(self, ['Manager', 'LabManager', 'Analyst']) self.analysts = self.analysts.sortedByKey() bsc = getToolByName(context, 'bika_setup_catalog') templates = [ t for t in bsc(portal_type='WorksheetTemplate', inactive_state='active') ] self.templates = [(t.UID, t.Title) for t in templates] self.templates.sort(lambda x, y: cmp(x[1], y[1])) self.instruments = [ (i.UID, i.Title) for i in bsc(portal_type='Instrument', inactive_state='active') ] self.instruments.sort(lambda x, y: cmp(x[1], y[1])) self.templateinstruments = {} for t in templates: i = t.getObject().getInstrument() if i: self.templateinstruments[t.UID] = i.UID() else: self.templateinstruments[t.UID] = '' self.columns = { 'Title': { 'title': _('Worksheet'), 'index': 'sortable_title' }, 'Priority': { 'title': _('Priority'), 'index': 'Priority', 'toggle': True }, 'Analyst': { 'title': _('Analyst'), 'index': 'getAnalyst', 'toggle': True }, 'Template': { 'title': _('Template'), 'toggle': True }, 'Services': { 'title': _('Services'), 'sortable': False, 'toggle': False }, 'SampleTypes': { 'title': _('Sample Types'), 'sortable': False, 'toggle': False }, 'Instrument': { 'title': _('Instrument'), 'sortable': False, 'toggle': False }, 'QC': { 'title': _('QC'), 'sortable': False, 'toggle': False }, 'QCTotals': { 'title': _('QC Samples(Analyses)'), 'sortable': False, 'toggle': False }, 'RoutineTotals': { 'title': _('Routine Samples(Analyses)'), 'sortable': False, 'toggle': False }, 'CreationDate': { 'title': PMF('Date Created'), 'toggle': True, 'index': 'created' }, 'state_title': { 'title': _('State'), 'index': 'review_state' }, } self.review_states = [ { 'id': 'default', 'title': _('All'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': [ 'open', 'to_be_verified', ], 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [{ 'id': 'retract' }, { 'id': 'verify' }, { 'id': 'reject' }], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, # getAuthenticatedMember does not work in __init__ # so 'mine' is configured further in 'folderitems' below. { 'id': 'mine', 'title': _('Mine'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': ['open', 'to_be_verified', 'verified', 'rejected'], 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [{ 'id': 'retract' }, { 'id': 'verify' }, { 'id': 'reject' }], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, { 'id': 'open', 'title': _('Open'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': 'open', 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, { 'id': 'to_be_verified', 'title': _('To be verified'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': 'to_be_verified', 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [{ 'id': 'retract' }, { 'id': 'verify' }, { 'id': 'reject' }], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, { 'id': 'verified', 'title': _('Verified'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': 'verified', 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, ] def __call__(self): if not self.isManagementAllowed(): # The current has no prvileges to manage WS. # Remove the add button self.context_actions = {} return super(FolderView, self).__call__() def isManagementAllowed(self): mtool = getToolByName(self.context, 'portal_membership') return mtool.checkPermission(ManageWorksheets, self.context) def isEditionAllowed(self): pm = getToolByName(self.context, "portal_membership") checkPermission = self.context.portal_membership.checkPermission return checkPermission(EditWorksheet, self.context) def isItemAllowed(self, obj): # Only show "my" worksheets # this cannot be setup in contentFilter, # because AuthenticatedMember is not available in __init__ if self.selected_state == 'mine' or self.restrict_results == True: analyst = obj.getAnalyst().strip() if analyst != _c(self.member.getId()): return False return BikaListingView.isItemAllowed(self, obj) def folderitems(self): wf = getToolByName(self, 'portal_workflow') rc = getToolByName(self, REFERENCE_CATALOG) pm = getToolByName(self.context, "portal_membership") self.member = pm.getAuthenticatedMember() roles = self.member.getRoles() self.restrict_results = 'Manager' not in roles \ and 'LabManager' not in roles \ and 'LabClerk' not in roles \ and 'RegulatoryInspector' not in roles \ and self.context.bika_setup.getRestrictWorksheetUsersAccess() if self.restrict_results == True: # Remove 'Mine' button and hide 'Analyst' column del self.review_states[1] # Mine self.columns['Analyst']['toggle'] = False can_manage = pm.checkPermission(ManageWorksheets, self.context) self.selected_state = self.request.get( "%s_review_state" % self.form_id, 'default') items = BikaListingView.folderitems(self) new_items = [] analyst_choices = [] for a in self.analysts: analyst_choices.append({ 'ResultValue': a, 'ResultText': self.analysts.getValue(a) }) can_reassign = False self.allow_edit = self.isEditionAllowed() for x in range(len(items)): if not items[x].has_key('obj'): new_items.append(items[x]) continue obj = items[x]['obj'] analyst = obj.getAnalyst().strip() creator = obj.Creator().strip() items[x]['Analyst'] = analyst priority = obj.getPriority() items[x]['Priority'] = '' instrument = obj.getInstrument() items[x]['Instrument'] = instrument and instrument.Title() or '' items[x]['Title'] = obj.Title() wst = obj.getWorksheetTemplate() items[x]['Template'] = wst and wst.Title() or '' if wst: items[x]['replace']['Template'] = "<a href='%s'>%s</a>" % \ (wst.absolute_url(), wst.Title()) items[x]['getPriority'] = '' items[x]['CreationDate'] = self.ulocalized_time(obj.creation_date) nr_analyses = len(obj.getAnalyses()) if nr_analyses == '0': # give empties pretty classes. items[x]['table_row_class'] = 'state-empty-worksheet' layout = obj.getLayout() if len(layout) > 0: items[x]['replace']['Title'] = "<a href='%s/manage_results'>%s</a>" % \ (items[x]['url'], items[x]['Title']) else: items[x]['replace']['Title'] = "<a href='%s/add_analyses'>%s</a>" % \ (items[x]['url'], items[x]['Title']) # set Services ws_services = {} for slot in [s for s in layout if s['type'] == 'a']: analysis = rc.lookupObject(slot['analysis_uid']) service = analysis.getService() title = service.Title() if title not in ws_services: ws_services[title] = "<a href='%s'>%s,</a>" % \ (service.absolute_url(), title) keys = list(ws_services.keys()) keys.sort() services = [] for key in keys: services.append(ws_services[key]) if services: services[-1] = services[-1].replace(",", "") items[x]['Services'] = "" items[x]['replace']['Services'] = " ".join(services) # set Sample Types pos_parent = {} for slot in layout: # compensate for bad data caused by a stupid bug. if type(slot['position']) in (list, tuple): slot['position'] = slot['position'][0] if slot['position'] == 'new': continue if slot['position'] in pos_parent: continue pos_parent[slot['position']] = rc.lookupObject( slot['container_uid']) sampletypes = {} blanks = {} controls = {} for container in pos_parent.values(): if container.portal_type == 'AnalysisRequest': sampletypes["<a href='%s'>%s,</a>" % \ (container.getSample().getSampleType().absolute_url(), container.getSample().getSampleType().Title())] = 1 if container.portal_type == 'ReferenceSample' and container.getBlank( ): blanks["<a href='%s'>%s,</a>" % \ (container.absolute_url(), container.Title())] = 1 if container.portal_type == 'ReferenceSample' and not container.getBlank( ): controls["<a href='%s'>%s,</a>" % \ (container.absolute_url(), container.Title())] = 1 sampletypes = list(sampletypes.keys()) sampletypes.sort() blanks = list(blanks.keys()) blanks.sort() controls = list(controls.keys()) controls.sort() # remove trailing commas if sampletypes: sampletypes[-1] = sampletypes[-1].replace(",", "") if controls: controls[-1] = controls[-1].replace(",", "") else: if blanks: blanks[-1] = blanks[-1].replace(",", "") items[x]['SampleTypes'] = "" items[x]['replace']['SampleTypes'] = " ".join(sampletypes) items[x]['QC'] = "" items[x]['replace']['QC'] = " ".join(blanks + controls) items[x]['QCTotals'] = '' # Get all Worksheet QC Analyses totalQCAnalyses = [ a for a in obj.getAnalyses() if a.portal_type == 'ReferenceAnalysis' or a.portal_type == 'DuplicateAnalysis' ] totalQCSamples = [] # Get all Worksheet QC samples for analysis in totalQCAnalyses: if analysis.getSample().UID() not in totalQCSamples: totalQCSamples.append(analysis.getSample().UID()) # Total QC Samples (Total Routine Analyses) items[x]['QCTotals'] = str(len(totalQCSamples)) + '(' + str( len(totalQCAnalyses)) + ')' totalRoutineAnalyses = [ a for a in obj.getAnalyses() if a not in totalQCAnalyses ] totalRoutineSamples = [] for analysis in totalRoutineAnalyses: if analysis.getSample().UID() not in totalRoutineSamples: totalRoutineSamples.append(analysis.getSample().UID()) # Total Routine Samples (Total Routine Analyses) items[x]['RoutineTotals'] = str( len(totalRoutineSamples)) + '(' + str( len(totalRoutineAnalyses)) + ')' if items[x]['review_state'] == 'open' \ and self.allow_edit \ and self.restrict_results == False \ and can_manage == True: items[x]['allow_edit'] = [ 'Analyst', ] items[x]['required'] = [ 'Analyst', ] can_reassign = True items[x]['choices'] = {'Analyst': analyst_choices} new_items.append(items[x]) if can_reassign: for x in range(len(self.review_states)): if self.review_states[x]['id'] in ['default', 'mine', 'open']: self.review_states[x]['custom_actions'] = [ { 'id': 'reassign', 'title': _('Reassign') }, ] self.show_select_column = can_reassign self.show_workflow_action_buttons = can_reassign return new_items def getAnalysts(self): """ Present the LabManagers and Analysts as options for analyst Used in bika_listing.pt """ return self.analysts def getWorksheetTemplates(self): """ List of templates Used in bika_listing.pt """ return DisplayList(self.templates) def getInstruments(self): """ List of instruments Used in bika_listing.pt """ return DisplayList(self.instruments) def getTemplateInstruments(self): """ Distionary of instruments per template Used in bika_listing.pt """ return json.dumps(self.templateinstruments)
class ExportOrdersForm(YAMLForm): browser_template = ViewPageTemplateFile('export.pt') form_template = 'bda.plone.orders.browser:forms/orders_export.yaml' message_factory = _ action_resource = 'exportorders' def __call__(self): # check if authenticated user is vendor if not get_vendors_for(): raise Unauthorized self.prepare() controller = Controller(self.form, self.request) if not controller.next: self.rendered_form = controller.rendered return self.browser_template(self) return controller.next def vendor_vocabulary(self): return vendors_form_vocab() def vendor_mode(self): return len(vendors_form_vocab()) > 2 and 'edit' or 'skip' def customer_vocabulary(self): return customers_form_vocab() def customer_mode(self): return len(customers_form_vocab()) > 2 and 'edit' or 'skip' def from_before_to(self, widget, data): from_date = data.fetch('exportorders.from').extracted to_date = data.fetch('exportorders.to').extracted if to_date <= from_date: raise ExtractionError( _('from_date_before_to_date', default=u'From-date after to-date')) return data.extracted def export(self, widget, data): self.vendor = self.request.form.get('exportorders.vendor') self.customer = self.request.form.get('exportorders.customer') self.from_date = data.fetch('exportorders.from').extracted self.to_date = data.fetch('exportorders.to').extracted def export_val(self, record, attr_name): """Get attribute from record and cleanup. Since the record object is available, you can return aggregated values. """ val = record.attrs.get(attr_name) return cleanup_for_csv(val) def csv(self, request): # get orders soup orders_soup = get_orders_soup(self.context) # get bookings soup bookings_soup = get_bookings_soup(self.context) # fetch user vendor uids vendor_uids = get_vendor_uids_for() # base query for time range query = Ge('created', self.from_date) & Le('created', self.to_date) # filter by given vendor uid or user vendor uids vendor_uid = self.vendor if vendor_uid: vendor_uid = uuid.UUID(vendor_uid) # raise if given vendor uid not in user vendor uids if vendor_uid not in vendor_uids: raise Unauthorized query = query & Any('vendor_uids', [vendor_uid]) else: query = query & Any('vendor_uids', vendor_uids) # filter by customer if given customer = self.customer if customer: query = query & Eq('creator', customer) # prepare csv writer sio = StringIO() ex = csv.writer(sio, dialect='excel-colon', quoting=csv.QUOTE_MINIMAL) # exported column keys as first line ex.writerow(ORDER_EXPORT_ATTRS + COMPUTED_ORDER_EXPORT_ATTRS.keys() + BOOKING_EXPORT_ATTRS + COMPUTED_BOOKING_EXPORT_ATTRS.keys()) # query orders for order in orders_soup.query(query): # restrict order bookings for current vendor_uids order_data = OrderData(self.context, order=order, vendor_uids=vendor_uids) order_attrs = list() # order export attrs for attr_name in ORDER_EXPORT_ATTRS: val = self.export_val(order, attr_name) order_attrs.append(val) # computed order export attrs for attr_name in COMPUTED_ORDER_EXPORT_ATTRS: cb = COMPUTED_ORDER_EXPORT_ATTRS[attr_name] val = cb(self.context, order_data) val = cleanup_for_csv(val) order_attrs.append(val) for booking in order_data.bookings: booking_attrs = list() # booking export attrs for attr_name in BOOKING_EXPORT_ATTRS: val = self.export_val(booking, attr_name) booking_attrs.append(val) # computed booking export attrs for attr_name in COMPUTED_BOOKING_EXPORT_ATTRS: cb = COMPUTED_BOOKING_EXPORT_ATTRS[attr_name] val = cb(self.context, booking) val = cleanup_for_csv(val) booking_attrs.append(val) ex.writerow(order_attrs + booking_attrs) booking.attrs['exported'] = True bookings_soup.reindex(booking) # create and return response s_start = self.from_date.strftime('%G-%m-%d_%H-%M-%S') s_end = self.to_date.strftime('%G-%m-%d_%H-%M-%S') filename = 'orders-export-%s-%s.csv' % (s_start, s_end) self.request.response.setHeader('Content-Type', 'text/csv') self.request.response.setHeader('Content-Disposition', 'attachment; filename=%s' % filename) ret = sio.getvalue() sio.close() return ret
class RegistryExporterView(BrowserView): """this view make sane exports of the registry. Main goal is to export in a way, that the output can be reused as best practive settings """ template = ViewPageTemplateFile( os.path.join(_current_dir, 'templates', 'exportxml.pt')) def __call__(self): interface = self.request.form.get('interface', None) name = self.request.form.get('name', None) if not interface and not name: return self.template() return self.export(sinterface=interface, sname=name) def interfaces(self): prefixes = [] registry = getUtility(IRegistry) baseurl = '{0}/@@configuration_registry_export_xml?interface='.format( self.context.absolute_url()) for record in registry.records.values(): if record.interfaceName is None: continue name = record.interfaceName url = '{0}{1}'.format(baseurl, record.interfaceName) pair = (name, url) if pair not in prefixes: prefixes.append(pair) return sorted(prefixes, key=_sort_first_lower) def prefixes(self): prefixes = [] registry = getUtility(IRegistry) baseurl = '{0}/@@configuration_registry_export_xml?'.format( self.context.absolute_url()) for record in registry.records.values(): if record.interfaceName == record.__name__: continue def add_split(part): url = '{0}name={1}'.format(baseurl, part) pair = (part, url) if pair not in prefixes: prefixes.append(pair) if part.rfind('/') > part.rfind('.'): new_parts = part.rsplit('/', 1) else: new_parts = part.rsplit('.', 1) if len(new_parts) > 1: add_split(new_parts[0]) add_split(record.__name__) return sorted(prefixes, key=_sort_first_lower) def export(self, sinterface=None, sname=None): registry = getUtility(IRegistry) root = etree.Element('registry') values = {} # full prefix to valuerecord interface2values = {} interface2prefix = {} for record in registry.records.values(): if sinterface and sinterface != record.interfaceName: continue if sname and not record.__name__.startswith(sname): continue prefix, value_key = record.__name__.rsplit('.', 1) xmlvalue = etree.Element('value') if record.value is None: continue if isinstance(record.value, (list, tuple)): for element in record.value: xmlel = etree.SubElement(xmlvalue, 'element') xmlel.text = element elif isinstance(record.value, bool): xmlvalue.text = 'True' if record.value else 'False' elif isinstance(record.value, six.string_types): xmlvalue.text = record.value else: xmlvalue.text = str(record.value) if record.interfaceName: xmlvalue.attrib['key'] = value_key if record.interfaceName not in interface2values: interface2values[record.interfaceName] = [] interface2values[record.interfaceName].append(record.__name__) interface2prefix[record.interfaceName] = prefix values[record.__name__] = xmlvalue for ifname in sorted(interface2values): xmlrecord = etree.SubElement(root, 'records') xmlrecord.attrib['interface'] = ifname xmlrecord.attrib['prefix'] = interface2prefix[ifname] for value in sorted(interface2values[ifname]): xmlrecord.append(values.pop(value)) for name, xmlvalue in values.items(): xmlrecord = etree.SubElement(root, 'records') xmlrecord.attrib['prefix'] = name xmlrecord.append(xmlvalue) self.request.response.setHeader('Content-Type', 'text/xml') filename = '' if sinterface: filename += sinterface if sinterface and sname: filename += '_-_' if sname: filename += sname self.request.response.setHeader( 'Content-Disposition', 'attachment; filename={0}.xml'.format(filename)) return etree.tostring(root, pretty_print=True, xml_declaration=True, encoding='UTF-8')
class NavigationView(BrowserView): template = ViewPageTemplateFile('templates/navigation.pt') def __call__(self): return self.template() def check_displayed_types(self, item): """ Check settings if content type should be displayed in navigation. """ types = api.portal.get_registry_record(name='plone.displayed_types') if item.portal_type not in types: return True def check_filter_on_workflow(self, item): """ Check workflow settings if item should be displayed in navigation. """ filter = api.portal.get_registry_record( name='plone.filter_on_workflow', ) states = api.portal.get_registry_record( name='plone.workflow_states_to_show', ) if filter: state = api.content.get_state(obj=item.getObject()) if state not in states: return True def check_item(self, item): """ Check if we want to have the given item in the navigation. """ if self.check_displayed_types(item): return False if self.check_filter_on_workflow(item): return False if item.exclude_from_nav: return False try: if self.context.default_page == item.id: return False except AttributeError: pass return True def get_icon(self, icon): return get_icon(icon) def get_back(self): """ Get link to parent. """ context = self.context portal = api.portal.get() parent = context.aq_parent root_nav = api.portal.get_registry_record( name='collective.sidebar.root_nav', default=False, ) if context == portal or context.portal_type == 'LRF' or root_nav: return None try: if parent.default_page == context.id: if parent == api.portal.get_navigation_root(context): return None return parent.aq_parent.absolute_url() except AttributeError: pass return parent.absolute_url() def get_show(self): """ Get link to current folder. """ if self.get_back() and IFolderish.providedBy(self.context): data = { 'title': self.context.Title(), 'title_cropped': crop(self.context.Title(), 100), 'url': self.context.absolute_url(), 'type': 'link-folder', } return data def contains_items(self, item): """ Check if navigation will return items for folder """ items = item.getObject().getFolderContents() for item in items: if self.check_item(item): return True return False def get_items(self): """ Get folder contents and return. """ context = self.context root_nav = api.portal.get_registry_record( name='collective.sidebar.root_nav', default=False, ) view_types = api.portal.get_registry_record( name='plone.types_use_view_action_in_listings', ) # root level navigation is enabled in settings if root_nav: context = api.portal.get_navigation_root(context) # context is folderish, list content if IFolderish.providedBy(context): # context is an endpoint, list parents content if INavigationEndpoint.providedBy(context): context = context.aq_parent else: # context is an item, list parents content context = context.aq_parent contents = list() # Can not remember what edgecase we catch here. try: contents = context.getFolderContents() except Exception: # noqa: 902 pass items = list() for item in contents: if self.check_item(item): item_type = 'link-item' url = item.getURL() if item.portal_type in view_types: url = url + '/view' if item.is_folderish and self.contains_items(item): item_type = 'link-folder' data = { 'title': item.Title, 'title_cropped': crop(item.Title, 100), 'url': url, 'type': item_type, } items.append(data) return items
class CommentsViewlet(ViewletBase): form = CommentForm index = ViewPageTemplateFile('comments.pt') def update(self): super(CommentsViewlet, self).update() discussion_allowed = self.is_discussion_allowed() anonymous_allowed_or_can_reply = ( self.is_anonymous() and self.anonymous_discussion_allowed() or self.can_reply()) if discussion_allowed and anonymous_allowed_or_can_reply: z2.switch_on(self, request_layer=IFormLayer) self.form = self.form(aq_inner(self.context), self.request) alsoProvides(self.form, IWrappedForm) self.form.update() # view methods def can_reply(self): """Returns true if current user has the 'Reply to item' permission. """ return getSecurityManager().checkPermission('Reply to item', aq_inner(self.context)) def can_manage(self): """We keep this method for <= 1.0b9 backward compatibility. Since we do not want any API changes in beta releases. """ return self.can_review() def can_review(self): """Returns true if current user has the 'Review comments' permission. """ return getSecurityManager().checkPermission('Review comments', aq_inner(self.context)) def can_delete_own(self, comment): """Returns true if the current user can delete the comment. Only comments without replies can be deleted. """ try: return comment.restrictedTraverse( '@@delete-own-comment').can_delete() except Unauthorized: return False def could_delete_own(self, comment): """Returns true if the current user could delete the comment if it had no replies. This is used to prepare hidden form buttons for JS. """ try: return comment.restrictedTraverse( '@@delete-own-comment').could_delete() except Unauthorized: return False def can_edit(self, reply): """Returns true if current user has the 'Edit comments' permission. """ return getSecurityManager().checkPermission('Edit comments', aq_inner(reply)) def can_delete(self, reply): """Returns true if current user has the 'Delete comments' permission. """ return getSecurityManager().checkPermission('Delete comments', aq_inner(reply)) def is_discussion_allowed(self): context = aq_inner(self.context) return context.restrictedTraverse('@@conversation_view').enabled() def comment_transform_message(self): """Returns the description that shows up above the comment text, dependent on the text_transform setting and the comment moderation workflow in the discussion control panel. """ context = aq_inner(self.context) registry = queryUtility(IRegistry) settings = registry.forInterface(IDiscussionSettings, check=False) # text transform setting if settings.text_transform == "text/x-web-intelligent": message = translate(Message(COMMENT_DESCRIPTION_INTELLIGENT_TEXT), context=self.request) elif settings.text_transform == "text/x-web-markdown": message = translate(Message(COMMENT_DESCRIPTION_MARKDOWN), context=self.request) else: message = translate(Message(COMMENT_DESCRIPTION_PLAIN_TEXT), context=self.request) # comment workflow wftool = getToolByName(context, "portal_workflow", None) workflow_chain = wftool.getChainForPortalType('Discussion Item') if workflow_chain: comment_workflow = workflow_chain[0] comment_workflow = wftool[comment_workflow] # check if the current workflow implements a pending state. If this # is true comments are moderated if 'pending' in comment_workflow.states: message = message + " " + \ translate(Message(COMMENT_DESCRIPTION_MODERATION_ENABLED), context=self.request) return message def has_replies(self, workflow_actions=False): """Returns true if there are replies. """ if self.get_replies(workflow_actions) is not None: try: self.get_replies(workflow_actions).next() return True except StopIteration: # pragma: no cover pass return False def get_replies(self, workflow_actions=False): """Returns all replies to a content object. If workflow_actions is false, only published comments are returned. If workflow actions is true, comments are returned with workflow actions. """ context = aq_inner(self.context) conversation = IConversation(context, None) if conversation is None: return iter([]) wf = getToolByName(context, 'portal_workflow') # workflow_actions is only true when user # has 'Manage portal' permission def replies_with_workflow_actions(): # Generator that returns replies dict with workflow actions for r in conversation.getThreads(): comment_obj = r['comment'] # list all possible workflow actions actions = [ a for a in wf.listActionInfos(object=comment_obj) if a['category'] == 'workflow' and a['allowed'] ] r = r.copy() r['actions'] = actions yield r def published_replies(): # Generator that returns replies dict with workflow status. for r in conversation.getThreads(): comment_obj = r['comment'] workflow_status = wf.getInfoFor(comment_obj, 'review_state') if workflow_status == 'published': r = r.copy() r['workflow_status'] = workflow_status yield r # Return all direct replies if len(conversation.objectIds()): if workflow_actions: return replies_with_workflow_actions() else: return published_replies() def get_commenter_home_url(self, username=None): if username is None: return None else: return "%s/author/%s" % (self.context.portal_url(), username) def get_commenter_portrait(self, username=None): if username is None: # return the default user image if no username is given return 'defaultUser.png' else: portal_membership = getToolByName(self.context, 'portal_membership', None) return portal_membership\ .getPersonalPortrait(username)\ .absolute_url() def anonymous_discussion_allowed(self): # Check if anonymous comments are allowed in the registry registry = queryUtility(IRegistry) settings = registry.forInterface(IDiscussionSettings, check=False) return settings.anonymous_comments def edit_comment_allowed(self): # Check if editing comments is allowed in the registry registry = queryUtility(IRegistry) settings = registry.forInterface(IDiscussionSettings, check=False) return settings.edit_comment_enabled def delete_own_comment_allowed(self): # Check if delete own comments is allowed in the registry registry = queryUtility(IRegistry) settings = registry.forInterface(IDiscussionSettings, check=False) return settings.delete_own_comment_enabled def show_commenter_image(self): # Check if showing commenter image is enabled in the registry registry = queryUtility(IRegistry) settings = registry.forInterface(IDiscussionSettings, check=False) return settings.show_commenter_image def is_anonymous(self): portal_membership = getToolByName(self.context, 'portal_membership', None) return portal_membership.isAnonymousUser() def login_action(self): return '%s/login_form?came_from=%s' % \ (self.navigation_root_url, url_quote(self.request.get('URL', '')),) def format_time(self, time): # We have to transform Python datetime into Zope DateTime # before we can call toLocalizedTime. util = getToolByName(self.context, 'translation_service') zope_time = DateTime(time.isoformat()) return util.toLocalizedTime(zope_time, long_format=True)
class ClientARImportAddView(BrowserView): implements(IViewView) template = ViewPageTemplateFile('templates/arimport_add_form.pt') def __call__(self): request = self.request response = request.response form = request.form plone.protect.CheckAuthenticator(form) if form.get('submitted'): csvfile = form.get('csvfile') option = form.get('ImportOption') client_id = form.get('ClientID') valid = False if option in ('c', 'p'): arimport, msg = self._import_file(option, csvfile, client_id) else: msg = "Import Option not yet available" IStatusMessage(request).addStatusMessage(_(msg), "warn") request.response.redirect('%s/arimports' % (self.context.absolute_url())) return if arimport: msg = "AR Import complete" IStatusMessage(request).addStatusMessage(_(msg), "info") request.response.write( '<script>document.location.href="%s"</script>' % (arimport.absolute_url())) return else: IStatusMessage(request).addStatusMessage(_(msg), "error") request.response.write( '<script>document.location.href="%s/arimport_add"</script>' % (self.context.absolute_url())) return return self.template() def _import_file(self, importoption, csvfile, client_id): fullfilename = csvfile.filename fullfilename = fullfilename.split('/')[-1] filename = fullfilename.split('.')[0] log = [] r = self.portal_catalog(portal_type='Client', id=client_id) if len(r) == 0: #This is not a user input issue - client_id is added to template log.append(' Could not find Client %s' % client_id) return None, '\n'.join(log) client = r[0].getObject() updateable_states = ['sample_received', 'assigned'] reader = csv.reader(csvfile.readlines()) samples = [] sample_headers = None batch_headers = None batch_remarks = [] row_count = 0 for row in reader: row_count = row_count + 1 if not row: continue # a new batch starts if row_count == 1: if row[0] == 'Header': continue else: msg = '%s invalid batch header' % row transaction_note(msg) return None, msg elif row_count == 2: msg = None if row[1] != 'Import': msg = 'Invalid batch header - Import required in cell B2' transaction_note(msg) return None, msg entered_name = fullfilename.split('.')[0] if not row[2] or entered_name.lower() != row[2].lower(): msg = 'Filename, %s, does not match entered filename, %s' \ % (filename, row[2]) transaction_note(msg) return None, msg batch_headers = row[0:] arimport_id = tmpID() title = filename idx = 1 while title in [i.Title() for i in client.objectValues()]: title = '%s-%s' % (filename, idx) idx += 1 arimport = _createObjectByType("ARImport", client, arimport_id, title=title) arimport.unmarkCreationFlag() continue elif row_count == 3: sample_headers = row[10:] continue elif row_count in [4, 5, 6]: continue #otherwise add to list of sample samples.append(row) if not row_count: msg = 'Invalid batch header' transaction_note(msg) return None, msg pad = 8192 * ' ' request = self.request title = 'Importing file' bar = ProgressBar(self.context, self.request, title, description='') notify(InitialiseProgressBar(bar)) sample_count = len(samples) row_count = 0 for sample in samples: next_num = tmpID() row_count = row_count + 1 item_remarks = [] progress_index = float(row_count) / float(sample_count) * 100.0 progress = ProgressState(self.request, progress_index) notify(UpdateProgressEvent(progress)) #TODO REmove for production - just to look pretty #time.sleep(1) analyses = [] for i in range(10, len(sample)): if sample[i] != '1': continue analyses.append(sample_headers[(i - 10)]) if len(analyses) > 0: aritem_id = '%s_%s' % ('aritem', (str(next_num))) aritem = _createObjectByType("ARImportItem", arimport, aritem_id) aritem.edit( SampleName=sample[0], ClientRef=batch_headers[10], ClientSid=sample[1], SampleDate=sample[2], SampleType=sample[3], PickingSlip=sample[4], ContainerType=sample[5], ReportDryMatter=sample[6], Priority=sample[7], ) aritem.setRemarks(item_remarks) if importoption == 'c': aritem.setAnalyses(analyses) elif importoption == 'p': aritem.setAnalysisProfile(analyses) cc_names_report = ','.join( [i.strip() for i in batch_headers[6].split(';')]) \ if (batch_headers and len(batch_headers) > 7) else "" cc_emails_report = ','.join( [i.strip() for i in batch_headers[7].split(';')]) \ if batch_headers and len(batch_headers) > 8 else "" cc_emails_invoice = ','.join( [i.strip() for i in batch_headers[8].split(';')]) \ if batch_headers and len(batch_headers) > 9 else "" try: numOfSamples = int(batch_headers[12]) except: numOfSamples = 0 arimport.edit( ImportOption=importoption, FileName=batch_headers[2], OriginalFile=csvfile, ClientTitle=batch_headers[3], ClientID=batch_headers[4], ContactID=batch_headers[5], CCNamesReport=cc_names_report, CCEmailsReport=cc_emails_report, CCEmailsInvoice=cc_emails_invoice, OrderID=batch_headers[9], QuoteID=batch_headers[10], SamplePoint=batch_headers[11], NumberSamples=numOfSamples, Remarks=batch_remarks, Analyses=sample_headers, DateImported=DateTime(), ) arimport._renameAfterCreation() valid = arimport.validateIt() return arimport, msg
class FolderView(BikaListingView): """Listing view for Worksheets """ template = ViewPageTemplateFile("../templates/worksheets.pt") def __init__(self, context, request): super(FolderView, self).__init__(context, request) self.catalog = CATALOG_WORKSHEET_LISTING self.contentFilter = { "review_state": ["open", "to_be_verified", "verified", "rejected"], "sort_on": "created", "sort_order": "reverse" } self.title = self.context.translate(_("Worksheets")) self.description = "" self.icon = "{}/{}".format( self.portal_url, "++resource++bika.lims.images/worksheet_big.png") self.context_actions = { _("Add"): { "url": "createObject?type_name=InstrumentMaintenanceTask", "icon": "++resource++bika.lims.images/add.png" } } self.context_actions = { _("Add"): { "url": "worksheet_add", "icon": "++resource++bika.lims.images/add.png", "class": "worksheet_add" } } self.show_select_column = True self.show_select_all_checkbox = True self.filter_by_user = False self.selected_state = "" self.analyst_choices = [] self.can_reassign = False self.can_manage = False self.rc = getToolByName(self, REFERENCE_CATALOG) # this is a property of self, because self.getAnalysts returns it self.analysts = getUsers(self, ["Manager", "LabManager", "Analyst"]) self.analysts = self.analysts.sortedByValue() self.analyst_choices = [] for a in self.analysts: self.analyst_choices.append({ "ResultValue": a, "ResultText": self.analysts.getValue(a), }) self.columns = collections.OrderedDict(( ("getProgressPercentage", { "title": _("Progress") }), ("Title", { "title": _("Worksheet"), "index": "getId" }), ("Analyst", { "title": _("Analyst"), "index": "getAnalyst" }), ("getWorksheetTemplateTitle", { "title": _("Template"), "replace_url": "getWorksheetTemplateURL" }), ("getNumberOfRegularSamples", { "title": _("Samples") }), ("getNumberOfQCAnalyses", { "title": _("QC Analyses") }), ("getNumberOfRegularAnalyses", { "title": _("Routine Analyses") }), ("CreationDate", { "title": _("Created"), "index": "created" }), ("state_title", { "title": _("State"), "index": "review_state", "attr": "state_title" }), )) self.review_states = [ { "id": "default", "title": _("Active"), "contentFilter": { "review_state": [ "open", "to_be_verified", ], "sort_on": "CreationDate", "sort_order": "reverse" }, "transitions": [], "custom_transitions": [], "columns": self.columns.keys(), }, { "id": "open", "title": _("Open"), "contentFilter": { "review_state": "open", "sort_on": "CreationDate", "sort_order": "reverse" }, "transitions": [], "custom_transitions": [], "columns": self.columns.keys(), }, { "id": "to_be_verified", "title": _("To be verified"), "contentFilter": { "review_state": "to_be_verified", "sort_on": "CreationDate", "sort_order": "reverse" }, "transitions": [], "custom_transitions": [], "columns": self.columns.keys() }, { "id": "verified", "title": _("Verified"), "contentFilter": { "review_state": "verified", "sort_on": "CreationDate", "sort_order": "reverse" }, "transitions": [], "custom_transitions": [], "columns": self.columns.keys(), }, { "id": "all", "title": _("All"), "contentFilter": { "review_state": [ "open", "to_be_verified", "verified", "rejected", ], "sort_on": "CreationDate", "sort_order": "reverse" }, "transitions": [], "custom_transitions": [], "columns": self.columns.keys(), }, { # getAuthenticatedMember does not work in __init__ so "mine" is # configured further in "folderitems" below. "id": "mine", "title": _("Mine"), "contentFilter": { "review_state": ["open", "to_be_verified", "verified", "rejected"], "sort_on": "CreationDate", "sort_order": "reverse" }, "transitions": [], "custom_transitions": [], "columns": self.columns.keys(), } ] def before_render(self): """Before render hook of the listing base view """ super(FolderView, self).before_render() # disable the editable border of the Add-, Display- and Workflow menu self.request.set("disable_border", 1) # the current selected WF state self.selected_state = self.get_selected_state() self.allow_edit = self.is_edit_allowed() self.can_manage = self.is_manage_allowed() # Check if analysts can be assigned if self.is_analyst_assignment_allowed(): self.can_reassign = True self.allow_analyst_reassignment() if not self.can_manage: # The current has no prvileges to manage WS. # Remove the add button self.context_actions = {} if self.context.bika_setup.getRestrictWorksheetUsersAccess(): # Display only the worksheets assigned to the current user unless # the user belongs to a privileged role allowed = ["Manager", "LabManager", "RegulatoryInspector"] diff = filter(lambda role: role in allowed, self.member.getRoles()) self.filter_by_user = len(diff) == 0 if self.filter_by_user: # Remove 'Mine' button and hide 'Analyst' column del self.review_states[1] # Mine self.columns["Analyst"]["toggle"] = False self.contentFilter["getAnalyst"] = self.member.id for rvw in self.review_states: rvw["contentFilter"]["getAnalyst"] = self.member.id def is_analyst_assignment_allowed(self): """Check if the analyst can be assigned """ if not self.allow_edit: return False if not self.can_manage: return False if self.filter_by_user: return False return True def allow_analyst_reassignment(self): """Allow the Analyst reassignment """ reassing_analyst_transition = { "id": "reassign", "title": _("Reassign") } for rs in self.review_states: if rs["id"] not in ["default", "mine", "open", "all"]: continue rs["custom_transitions"].append(reassing_analyst_transition) self.show_select_column = True self.show_workflow_action_buttons = True def is_manage_allowed(self): """Check if the User is allowed to manage """ checkPermission = self.context.portal_membership.checkPermission return checkPermission(ManageWorksheets, self.context) def is_edit_allowed(self): """Check if edit is allowed """ checkPermission = self.context.portal_membership.checkPermission return checkPermission(EditWorksheet, self.context) def get_selected_state(self): """Returns the current selected state """ form_key = "{}_review_state".format(self.form_id) return self.request.get(form_key, "default") def folderitem(self, obj, item, index): """Service triggered each time an item is iterated in folderitems. The use of this service prevents the extra-loops in child objects. :obj: the instance of the class to be foldered :item: dict containing the properties of the object to be used by the template :index: current index of the item """ title = api.get_title(obj) url = api.get_url(obj) item["CreationDate"] = self.ulocalized_time(obj.created) title_link = "{}/{}".format(url, "add_analyses") if len(obj.getAnalysesUIDs) > 0: title_link = "{}/{}".format(url, "manage_results") item["Title"] = title item["replace"]["Title"] = get_link(title_link, value=title) # Total QC Analyses item["getNumberOfQCAnalyses"] = str(obj.getNumberOfQCAnalyses) # Total Routine Analyses item["getNumberOfRegularAnalyses"] = str( obj.getNumberOfRegularAnalyses) # Total Number of Samples item["getNumberOfRegularSamples"] = str(obj.getNumberOfRegularSamples) # Progress progress = obj.getProgressPercentage progress_bar_html = get_progress_bar_html(progress) item["replace"]["getProgressPercentage"] = progress_bar_html review_state = item["review_state"] if self.can_reassign and review_state == "open": item["Analyst"] = obj.getAnalyst item["allow_edit"] = ["Analyst"] item["required"] = ["Analyst"] item["choices"] = {"Analyst": self.analyst_choices} else: fullname = user_fullname(self.context, obj.getAnalyst) item["Analyst"] = fullname return item def getAnalysts(self): """Returns all analysts """ return self.analysts def getWorksheetTemplates(self): """Returns a DisplayList with all active worksheet templates :return: DisplayList of worksheet templates (uid, title) :rtype: DisplayList """ brains = self._get_worksheet_templates_brains() return get_display_list(brains) def getInstruments(self): """Returns a DisplayList with all active Instruments :return: DisplayList of worksheet templates (uid, title) :rtype: DisplayList """ brains = self._get_instruments_brains() return get_display_list(brains) def getTemplateInstruments(self): """Returns worksheet templates as JSON """ items = dict() templates = self._get_worksheet_templates_brains() for template in templates: template_obj = api.get_object(template) uid_template = api.get_uid(template_obj) instrument = template_obj.getInstrument() uid_instrument = "" if instrument: uid_instrument = api.get_uid(instrument) items[uid_template] = uid_instrument return json.dumps(items) def _get_worksheet_templates_brains(self): """Returns all active worksheet templates :returns: list of worksheet template brains """ query = { "portal_type": "WorksheetTemplate", "is_active": True, } return api.search(query, "bika_setup_catalog") def _get_instruments_brains(self): """Returns all active Instruments :returns: list of brains """ query = {"portal_type": "Instrument", "is_active": True} return api.search(query, "bika_setup_catalog")
def fetchnewcomments(self,lasttimestamp,commentcount,lastcommentid,viewtype): passedcommentcount = 0 passedcommentcount = int(commentcount) flasttimestamp = float(lasttimestamp) datefromlasttimestamp = DateTime(flasttimestamp) newlastdate = datefromlasttimestamp.timeTime() zopecommands = self.getCommandSet('zope') ksscore = self.getCommandSet('core') jq = self.getCommandSet('jquery') pdt = getToolByName(self.context, 'portal_discussion', None) if pdt <> None: allreplies = self.get_replies(pdt,self.context) disc_container = pdt.getDiscussionFor(self.context) replies = disc_container.getReplies() newreplycount = disc_container.replyCount(self.context) commentshiddencontainer = ksscore.getHtmlIdSelector('comcynapsehiddencomments') commentscontainer = ksscore.getHtmlIdSelector('comcynapsecyninitemcommentscontainer') addnewlasttimestamp = ksscore.getHtmlIdSelector('comcynapselasttimestamp') addnewlastcommentid = ksscore.getHtmlIdSelector('comcynapselastcommentid') addnewcommentcount = ksscore.getHtmlIdSelector('comcynapsecommentcount') if passedcommentcount <> newreplycount: #if comment count mismatch then only modify the stuff alldiscussions = disc_container.objectValues() newlyaddedcomments = [k for k in alldiscussions if k.modified().greaterThan(datefromlasttimestamp) and k.id not in (lastcommentid)] newlyaddedcomments.sort(lambda x,y:cmp(x.modified(),y.modified())) for eachcomment in newlyaddedcomments: reply = disc_container.getReply(eachcomment.id) if reply <> None: parentsInThread = reply.parentsInThread() depthvalue = 0 if viewtype.lower() == 'threadedview': lenofparents = len(parentsInThread) depthvalue = lenofparents - 1 prev_reply_id = self.findpreviouscommentid(allreplies,reply) newlastdate = reply.modified().timeTime() commenttemplate = ViewPageTemplateFile('ksstemplates/commentrow.pt') commenttemplate = commenttemplate.__of__(self.context) replydict = [{'depth': depthvalue, 'object': reply,'prev_id':prev_reply_id,'view_type':viewtype},] output = commenttemplate.render(reply_dict=replydict) #delete the node if already exists old_comment = ksscore.getHtmlIdSelector('commenttable' + reply.id) ksscore.deleteNode(old_comment) #if there is no prev id found for new comment then insert it as last item to commentscontainer #else insert it after prev id comments table. if viewtype == 'flatview': ksscore.insertHTMLAsLastChild(commentscontainer,output) else: if prev_reply_id == '': ksscore.insertHTMLAsLastChild(commentscontainer,output) else: prevcommentcontainer = ksscore.getHtmlIdSelector('commenttable' + prev_reply_id) ksscore.insertHTMLAfter(prevcommentcontainer,output) newcomment = ksscore.getHtmlIdSelector('commenttable' + reply.id) if len(newlyaddedcomments) > 0: strlastcommentid = str(newlyaddedcomments[-1].id) ksscore.setKssAttribute(commentshiddencontainer,'lastcommentid',strlastcommentid) ksscore.setAttribute(addnewlastcommentid,'value',strlastcommentid) jq.serverCall(commentscontainer,'truncatetextonitemexpand') newlasttimestamp = str(newlastdate) strcommentcount = str(newreplycount) ksscore.setKssAttribute(commentshiddencontainer,'lasttimestamp',newlasttimestamp) ksscore.setKssAttribute(commentshiddencontainer,'commentcount',strcommentcount) ksscore.setAttribute(addnewlasttimestamp,'value',newlasttimestamp) ksscore.setAttribute(addnewcommentcount,'value',strcommentcount) itemcountcommentcount = ksscore.getHtmlIdSelector('itemcountcommentcount') discussionlabel = ksscore.getHtmlIdSelector('discussionlabel') ksscore.replaceInnerHTML(discussionlabel,strcommentcount) ksscore.replaceInnerHTML(itemcountcommentcount,strcommentcount)
class A18CategoryDisplay(ItemDisplayForm): title = "Measure Progress display" extra_data_template = ViewPageTemplateFile('pt/extra-data-pivot.pt') mapper_class = sql2018.ART18Category1bNotWFD css_class = 'left-side-form' reported_date_info = { 'mapper_class': sql2018.ReportedInformation, 'col_import_id': 'Id', 'col_import_time': 'ReportingDate' } def get_reported_date(self): return self.get_reported_date_2018() def get_import_id(self): import_id = self.item.IdReportedInformation return import_id @db.use_db_session('2018') def get_current_country(self): report_id = self.item.IdReportedInformation _, res = db.get_related_record(sql2018.ReportedInformation, 'Id', report_id) country = self.print_value(res.CountryCode) return country @db.use_db_session('2018') def download_results(self): mc_countries = sql2018.ReportedInformation mc_measure = sql2018.ART18Category1bNotWFDMeasure countries = self.get_form_data_by_key(self, 'member_states') ges_comps = self.get_form_data_by_key(self, 'ges_component') conditions = [] if countries: conditions.append(mc_countries.CountryCode.in_(countries)) count, report_ids = db.get_all_records(mc_countries, *conditions) report_ids = [x.Id for x in report_ids] conditions = [self.mapper_class.IdReportedInformation.in_(report_ids)] if ges_comps: conditions.append(self.mapper_class.Descriptor.in_(ges_comps)) count, category = db.get_all_records(self.mapper_class, *conditions) id_category = [x.Id for x in category] count, category_measure = db.get_all_records( mc_measure, mc_measure.IdCategory1bNotWFD.in_(id_category)) xlsdata = [ ('ART18Category1bNotWFD', category), # worksheet title, row data ('ART18Category1bNotWFDMeasure', category_measure), ] return data_to_xls(xlsdata) @db.use_db_session('2018') def get_db_results(self): page = self.get_page() mc_countries = sql2018.ReportedInformation countries = self.get_form_data_by_key(self, 'member_states') ges_comps = self.get_form_data_by_key(self, 'ges_component') conditions = [] if countries: conditions.append(mc_countries.CountryCode.in_(countries)) count, report_ids = db.get_all_records(mc_countries, *conditions) report_ids = [x.Id for x in report_ids] conditions = [self.mapper_class.IdReportedInformation.in_(report_ids)] if ges_comps: conditions.append(self.mapper_class.Descriptor.in_(ges_comps)) item = db.get_item_by_conditions(self.mapper_class, 'Id', *conditions, page=page) return item @db.use_db_session('2018') def get_extra_data(self): if not self.item: return {} mc = sql2018.ART18Category1bNotWFDMeasure excluded_columns = ('Id', 'IdCategory1bNotWFD') res = [] id_category = self.item.Id count, data = db.get_all_records(mc, mc.IdCategory1bNotWFD == id_category) data = db_objects_to_dict(data, excluded_columns) res.append(('Category1bNotWFDMeasure', {'': data})) return res
def getDiscussionView(self,uid,itemindex,state,openeditemindex): ksscore = self.getCommandSet('core') zopecore = self.getCommandSet('zope') jq = self.getCommandSet('jquery') clickednode = ksscore.getHtmlIdSelector('listitemdiscusslinktop' + itemindex) listcommentcontainer = ksscore.getHtmlIdSelector('listitemdiscussrow' + itemindex) listtimeoutuid = ksscore.getHtmlIdSelector('comcynapsecyninfetchUID') listtimeoutindex = ksscore.getHtmlIdSelector('comcynapsecyninfetchindex') listtimeouttimestamp = ksscore.getHtmlIdSelector('comcynapselasttimestamp') listtimeoutlastcommentid = ksscore.getHtmlIdSelector('comcynapselastcommentid') listtimeoutcommentcount = ksscore.getHtmlIdSelector('comcynapsecommentcount') listitemdetailright = ksscore.getHtmlIdSelector('listitemdetail' + itemindex) if openeditemindex != itemindex: openednode = ksscore.getHtmlIdSelector('listitemdiscusslinktop' + openeditemindex) listopenedcommentcontainer = ksscore.getHtmlIdSelector('listitemdiscussrow' + openeditemindex) ksscore.setKssAttribute(openednode,'state','closed') ksscore.replaceInnerHTML(listopenedcommentcontainer,'') if state.lower() != 'closed': ksscore.setKssAttribute(clickednode,'state','closed') ksscore.replaceInnerHTML(listcommentcontainer,'') return query = {'UID':uid} pdt = getToolByName(self.context,'portal_discussion') cat = getToolByName(self.context, 'uid_catalog') resbrains = cat.searchResults(query) if len(resbrains) == 1: contobj = resbrains[0].getObject() isDiscussable = contobj.isDiscussable() canReply = self.canreply(contobj) if isDiscussable and canReply: dobj = pdt.getDiscussionFor(contobj) alldiscussions = dobj.objectValues() alldiscussions.sort(lambda x,y:cmp(x.modified(),y.modified()),reverse=True) maxdispcomments = self.get_displaycountforlist() lastxdiscussions = alldiscussions[:maxdispcomments] commentscount = dobj.replyCount(contobj) if commentscount > maxdispcomments: showxmorelink = True xmorecomments = commentscount - maxdispcomments elif commentscount > 0 and commentscount <= maxdispcomments: showxmorelink = False xmorecomments = 0 else: showxmorelink = True commentscount = 0 xmorecomments = 0 lasttimestamp = DateTime().timeTime() lastcommentid = '0' if len(alldiscussions) > 0: lasttimestamp = alldiscussions[0].modified().timeTime() lastcommentid = alldiscussions[0].id commenttemplate = ViewPageTemplateFile('ksstemplates/listcomment.pt') commenttemplate = commenttemplate.__of__(self.context) replydict = [] lastxdiscussions.sort(lambda x,y:cmp(x.modified(),y.modified())) for eachdisc in lastxdiscussions: reply = dobj.getReply(eachdisc.id) if reply <> None: replydict.append({'depth': 0,'object':reply,'view_type':'listview','showoutput':True}) output = commenttemplate.render(contobj=contobj, showxmorelink = showxmorelink, xmorecomments = xmorecomments, itemindex=itemindex,uid=uid,reply_dict=replydict,title=contobj.Title(),commentcount=commentscount,lasttimestamp = lasttimestamp,lastcommentid = lastcommentid,allowdiscussion = isDiscussable,usercanreply = canReply) detailtemplate = ViewPageTemplateFile('ksstemplates/listitemdetails.pt') detailtemplate = detailtemplate.__of__(self.context) item = resbrains[0] fullpath = item.getPath() splitpath = fullpath.split('/')[:-1] prettypath = '/' + '/'.join(splitpath) URLsuffix = getListingTemplateForContextParent(item) pathlink = self.context.portal_url() + prettypath + '/' + URLsuffix pathtitle = prettypath detail = detailtemplate.render(item_type=contobj.portal_type,portal_url=self.context.portal_url(),item_type_title=contobj.Type(),item=item,pathlink=pathlink,pathtitle=pathtitle,contobj=contobj) ksscore.replaceInnerHTML(listitemdetailright,force_unicode(detail,'utf')) ksscore.replaceInnerHTML(listcommentcontainer,output) ksscore.setKssAttribute(clickednode,'state','opened') ksscore.setAttribute(listtimeoutuid,'value',uid) ksscore.setAttribute(listtimeoutindex,'value',itemindex) ksscore.setAttribute(listtimeouttimestamp,'value',str(lasttimestamp)) ksscore.setAttribute(listtimeoutlastcommentid,'value',lastcommentid) ksscore.setAttribute(listtimeoutcommentcount,'value',str(commentscount)) jq.serverCall(clickednode,'truncatetextonitemexpand') jq.serverCall(clickednode,'marklistedtags') jq.serverCall(listcommentcontainer,'activateinputlabel')
class GenerateExcerpt(AutoExtensibleForm, EditForm): has_model_breadcrumbs = True ignoreContext = True allow_prefill_from_GET_request = True # XXX schema = IGenerateExcerpt template = ViewPageTemplateFile('templates/excerpt.pt') def __init__(self, context, request): super(GenerateExcerpt, self).__init__(context, request) self.model = self.context.model self._excerpt_data = None def update(self): self.inject_initial_data() super(GenerateExcerpt, self).update() def inject_initial_data(self): if self.request.method != 'GET': return initial_filename = self.model.get_excerpt_title() self.request['form.widgets.title'] = initial_filename dossier = self.model.get_dossier() self.request['form.widgets.dossier'] = [ '/'.join(dossier.getPhysicalPath()) ] def get_agenda_items(self): for agenda_item in self.model.agenda_items: if not agenda_item.is_paragraph: yield agenda_item @button.buttonAndHandler(_('Save', default=u'Save'), name='save') def handleApply(self, action): data, errors = self.extractData() if errors: return agenda_items_to_include = [] for agenda_item in self.get_agenda_items(): if agenda_item.name in self.request: agenda_items_to_include.append(agenda_item) if not agenda_items_to_include: raise (ActionExecutionError( Invalid(_(u"Please select at least one agenda item.")))) operations = ManualExcerptOperations( agenda_items_to_include, data['title'], include_initial_position=data['include_initial_position'], include_legal_basis=data['include_legal_basis'], include_considerations=data['include_considerations'], include_proposed_action=data['include_proposed_action'], include_discussion=data['include_discussion'], include_decision=data['include_decision'], include_publish_in=data['include_publish_in'], include_disclose_to=data['include_disclose_to'], include_copy_for_attention=data['include_copy_for_attention']) command = CreateGeneratedDocumentCommand(data['dossier'], self.model, operations) command.execute() command.show_message() return self.redirect_to_meeting() @button.buttonAndHandler(_('label_cancel', default=u'Cancel'), name='cancel') def handleCancel(self, action): return self.redirect_to_meeting() def redirect_to_meeting(self): return self.request.RESPONSE.redirect(self.model.get_url())
class BannerViewlet(ViewletBase): """ A viewlet which renders the banner """ banner_template = ViewPageTemplateFile('banner.pt') slider_template = ViewPageTemplateFile('slider.pt') def render(self): if '@@edit' in self.request.steps: return '' return self.index() def index(self): context = aq_inner(self.context) if ISlider.providedBy(context): if context.slider_relation and len(context.slider_relation) > 1: return self.slider_template() return self.banner_template() def find_banner(self): types = api.portal.get_registry_record( 'collective.behavior.banner.browser.controlpanel.IBannerSettingsSchema.types' ) # noqa: E501 context = aq_inner(self.context) # first handle the obj itself if IBanner.providedBy(context): if context.banner_hide: return False banner = self.banner(context) if banner: return banner if context.banner_stop_inheriting: return False # if all the fields are empty and inheriting is not stopped if context.portal_type not in types: return False context = context.__parent__ # we walk up the path for item in context.aq_chain: if IBanner.providedBy(item): # we have a banner. check. if item.banner_stop_inheriting: return False banner = self.banner(item) if banner: return banner if INavigationRoot.providedBy(item): return False if item.portal_type not in types: return False return False def banner(self, obj): """ return banner of this object """ banner = {} if getattr(obj, 'banner_image', False): banner['banner_image'] = '{0}/@@images/banner_image'.format( obj.absolute_url()) if obj.banner_title: banner['banner_title'] = obj.banner_title if obj.banner_description: crop = Plone(self.context, self.request).cropText banner['banner_description'] = crop(obj.banner_description, 400) if obj.banner_text: banner['banner_text'] = obj.banner_text.output if obj.banner_link: to_obj = obj.banner_link.to_object if to_obj: banner['banner_link'] = to_obj.absolute_url() banner['banner_linktext'] = to_obj.Title() if obj.banner_linktext: banner['banner_linktext'] = obj.banner_linktext if obj.banner_fontcolor: banner['banner_fontcolor'] = obj.banner_fontcolor if obj.banner_url: banner['banner_url'] = obj.banner_url banner['banner_obj'] = obj return banner def random_banner(self): context = aq_inner(self.context) banners = [] raw_banners = context.slider_relation for banner in raw_banners: banner = banner.to_object banners.append(self.banner(banner)) self.scroll = len(banners) > 1 return banners def getVideoEmbedMarkup(self, url): """ Build an iframe from a YouTube or Vimeo share url """ # https://www.youtube.com/watch?v=Q6qYdJuWB6w YOUTUBE_TEMPLATE = ''' <iframe width="660" height="495" src="//www.youtube-nocookie.com/embed/{1}?showinfo=0" frameborder="0" allowfullscreen> </iframe> ''' # https://vimeo.com/75721023 VIMEO_TEMPLATE = ''' <iframe src="//player.vimeo.com/video/{0}?title=0&byline=0&portrait=0" width="660" height="371" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen> </iframe> ''' try: parsed = urlparse(url) except AttributeError: return '' path = parsed.path.replace('/', '') videoId = parsed.query.replace('v=', '') if 'youtube' in parsed.netloc: template = YOUTUBE_TEMPLATE elif 'vimeo' in parsed.netloc: template = VIMEO_TEMPLATE else: return '' # It so happens that path is needed by the Vimeo format, # while videoId is needed by the Youtube format, so only one # of the variables will have a useful value, depending on the player. # Each template will use the argument it cares about and ignore the # other. return template.format(path, videoId)
class PasswordAccountPanel(prefs.PasswordAccountPanel): template = ViewPageTemplateFile('pt/password-account-panel.pt')
class DashboardView(BrowserView): template = ViewPageTemplateFile("templates/dashboard.pt") def __call__(self): tofrontpage = True mtool = getToolByName(self.context, 'portal_membership') if not mtool.isAnonymousUser( ) and self.context.bika_setup.getDashboardByDefault(): # If authenticated user with labman role, # display the Main Dashboard view pm = getToolByName(self.context, "portal_membership") member = pm.getAuthenticatedMember() roles = member.getRoles() tofrontpage = 'Manager' not in roles and 'LabManager' not in roles if tofrontpage == True: self.request.response.redirect(self.portal_url + "/bika-frontpage") else: self._init_date_range() return self.template() def _init_date_range(self): """ Sets the date range from which the data must be retrieved. Sets the values to the class parameters 'date_from', 'date_to', 'date_range', 'base_date_range' and self.periodicity Calculates the date range according to the value of the request's 'p' parameter: - 'd' (daily) - 'w' (weekly) - 'm' (monthly) - 'q' (quarterly) - 'b' (biannual) - 'y' (yearly) """ # By default, weekly self.periodicity = self.request.get('p', 'w') if (self.periodicity == 'd'): # Daily self.date_from = DateTime() self.date_to = DateTime() + 1 # For time-evolution data, load last 30 days self.min_date = self.date_from - 30 elif (self.periodicity == 'm'): # Monthly today = datetime.date.today() self.date_from = DateTime(today.year, today.month, 1) self.date_to = DateTime(today.year, today.month, monthrange(today.year, today.month)[1], 23, 59, 59) # For time-evolution data, load last two years min_year = today.year - 1 if today.month == 12 else today.year - 2 min_month = 1 if today.month == 12 else today.month self.min_date = DateTime(min_year, min_month, 1) elif (self.periodicity == 'q'): # Quarterly today = datetime.date.today() m = (((today.month - 1) / 3) * 3) + 1 self.date_from = DateTime(today.year, m, 1) self.date_to = DateTime(today.year, m + 2, monthrange(today.year, m + 2)[1], 23, 59, 59) # For time-evolution data, load last four years min_year = today.year - 4 if today.month == 12 else today.year - 5 self.min_date = DateTime(min_year, m, 1) elif (self.periodicity == 'b'): # Biannual today = datetime.date.today() m = (((today.month - 1) / 6) * 6) + 1 self.date_from = DateTime(today.year, m, 1) self.date_to = DateTime(today.year, m + 5, monthrange(today.year, m + 5)[1], 23, 59, 59) # For time-evolution data, load last ten years min_year = today.year - 10 if today.month == 12 else today.year - 11 self.min_date = DateTime(min_year, m, 1) elif (self.periodicity == 'y'): # Yearly today = datetime.date.today() self.date_from = DateTime(today.year, 1, 1) self.date_to = DateTime(today.year, 12, 31, 23, 59, 59) # For time-evolution data, load last 15 years min_year = today.year - 15 if today.month == 12 else today.year - 16 self.min_date = DateTime(min_year, 1, 1) else: # weekly today = datetime.date.today() year, weeknum, dow = today.isocalendar() self.date_from = DateTime() - dow self.date_to = self.date_from + 7 # For time-evolution data, load last six months min_year = today.year if today.month > 6 else today.year - 1 min_month = today.month - 6 if today.month > 6 else (today.month - 6) + 12 self.min_date = DateTime(min_year, min_month, 1) self.date_range = { 'query': (self.date_from, self.date_to), 'range': 'min:max' } self.base_date_range = { 'query': (DateTime('1990-01-01 00:00:00'), self.date_from - 1), 'range': 'min:max' } self.min_date_range = { 'query': (self.min_date, self.date_to), 'range': 'min:max' } def get_sections(self): """ Returns an array with the sections to be displayed. Every section is a dictionary with the following structure: {'id': <section_identifier>, 'title': <section_title>, 'panels': <array of panels>} """ sections = [ self.get_analyses_section(), self.get_analysisrequests_section(), self.get_worksheets_section() ] return sections def get_analysisrequests_section(self): """ Returns the section dictionary related with Analysis Requests, that contains some informative panels (like ARs to be verified, ARs to be published, etc.) """ out = [] sampenabled = self.context.bika_setup.getSamplingWorkflowEnabled() # Analysis Requests active_rs = [ 'to_be_sampled', 'to_be_preserved', 'scheduled_sampling', 'sample_due', 'sample_received', 'assigned', 'to_be_verified', 'attachment_due', 'verified' ] bc = getToolByName(self.context, "bika_catalog") numars = len( bc(portal_type="AnalysisRequest", created=self.date_range, cancellation_state=[ 'active', ])) numars += len( bc(portal_type="AnalysisRequest", review_state=active_rs, cancellation_state=[ 'active', ], created=self.base_date_range)) if (sampenabled): # Analysis Requests awaiting to be sampled or scheduled review_state = [ 'to_be_sampled', ] ars = len( bc(portal_type="AnalysisRequest", review_state=review_state, cancellation_state=[ 'active', ])) ratio = (float(ars) / float(numars)) * 100 if ars > 0 and numars > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("To be sampled") out.append({ 'type': 'simple-panel', 'name': _('Analysis Requests to be sampled'), 'class': 'informative', 'description': msg, 'number': ars, 'total': numars, 'legend': _('of') + " " + str(numars) + ' (' + ratio + '%)', 'link': self.portal_url + '/samples?samples_review_state=to_be_sampled' }) # Analysis Requests awaiting to be preserved review_state = [ 'to_be_preserved', ] ars = len( bc(portal_type="AnalysisRequest", review_state=review_state, cancellation_state=[ 'active', ])) ratio = (float(ars) / float(numars)) * 100 if ars > 0 and numars > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("To be preserved") out.append({ 'type': 'simple-panel', 'name': _('Analysis Requests to be preserved'), 'class': 'informative', 'description': msg, 'number': ars, 'total': numars, 'legend': _('of') + " " + str(numars) + ' (' + ratio + '%)', 'link': self.portal_url + '/analysisrequests?analysisrequests_review_state=to_be_preserved' }) # Analysis Requests awaiting to be sampled review_state = [ 'scheduled_sampling', ] ars = len( bc(portal_type="AnalysisRequest", review_state=review_state, cancellation_state=[ 'active', ])) ratio = (float(ars) / float(numars)) * 100 if ars > 0 and numars > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("Scheduled sampling") out.append({ 'type': 'simple-panel', 'name': _('Analysis Requests with scheduled sampling'), 'class': 'informative', 'description': msg, 'number': ars, 'total': numars, 'legend': _('of') + " " + str(numars) + ' (' + ratio + '%)', 'link': self.portal_url + '/samples?samples_review_state=to_be_sampled' }) # Analysis Requests awaiting for reception review_state = [ 'sample_due', ] ars = len( bc(portal_type="AnalysisRequest", review_state=review_state, cancellation_state=[ 'active', ])) ratio = (float(ars) / float(numars)) * 100 if ars > 0 and numars > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("Reception pending") out.append({ 'type': 'simple-panel', 'name': _('Analysis Requests to be received'), 'class': 'informative', 'description': msg, 'number': ars, 'total': numars, 'legend': _('of') + " " + str(numars) + ' (' + ratio + '%)', 'link': self.portal_url + '/analysisrequests?analysisrequests_review_state=sample_due' }) # Analysis Requests under way review_state = ['attachment_due', 'sample_received', 'assigned'] ars = len( bc(portal_type="AnalysisRequest", review_state=review_state, cancellation_state=[ 'active', ])) ratio = (float(ars) / float(numars)) * 100 if ars > 0 and numars > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("Results pending") out.append({ 'type': 'simple-panel', 'name': _('Analysis Requests with results pending'), 'class': 'informative', 'description': msg, 'number': ars, 'total': numars, 'legend': _('of') + " " + str(numars) + ' (' + ratio + '%)', 'link': self.portal_url + '/analysisrequests?analysisrequests_review_state=sample_received' }) # Analysis Requests to be verified review_state = [ 'to_be_verified', ] ars = len( bc(portal_type="AnalysisRequest", review_state=review_state, cancellation_state=[ 'active', ])) ratio = (float(ars) / float(numars)) * 100 if ars > 0 and numars > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("To be verified") out.append({ 'type': 'simple-panel', 'name': _('Analysis Requests to be verified'), 'class': 'informative', 'description': msg, 'number': ars, 'total': numars, 'legend': _('of') + " " + str(numars) + ' (' + ratio + '%)', 'link': self.portal_url + '/analysisrequests?analysisrequests_review_state=to_be_verified' }) # Analysis Requests to be published review_state = [ 'verified', ] ars = len( bc(portal_type="AnalysisRequest", review_state=review_state, cancellation_state=[ 'active', ])) ratio = (float(ars) / float(numars)) * 100 if ars > 0 and numars > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("To be published") out.append({ 'type': 'simple-panel', 'name': _('Analysis Requests to be published'), 'class': 'informative', 'description': msg, 'number': ars, 'total': numars, 'legend': _('of') + " " + str(numars) + ' (' + ratio + '%)', 'link': self.portal_url + '/analysisrequests?analysisrequests_review_state=verified' }) # Chart with the evolution of ARs over a period, grouped by # periodicity workflow = getToolByName(self.context, 'portal_workflow') allars = bc(portal_type="AnalysisRequest", sort_on="created", created=self.min_date_range) outevo = [] for ar in allars: ar = ar.getObject() state = 'other_status' try: state = workflow.getInfoFor(ar, 'cancellation_state') if (state == 'active'): state = workflow.getInfoFor(ar, 'review_state') else: state = 'inactive' except: pass created = self._getDateStr(self.periodicity, ar.created()) state = 'sample_due' if state in [ 'to_be_sampled', 'to_be_preserved' ] else state state = 'sample_received' if state in [ 'assigned', 'attachment_due' ] else state if (len(outevo) > 0 and outevo[-1]['date'] == created): key = state if _(state) in outevo[-1] else 'other_status' outevo[-1][_(key)] += 1 else: currow = { 'date': created, _('sample_due'): 0, _('sample_received'): 0, _('to_be_verified'): 0, _('verified'): 0, _('published'): 0, _('inactive'): 0, _('other_status'): 0, } key = state if _(state) in currow else 'other_status' currow[_(key)] += 1 outevo.append(currow) out.append({ 'type': 'bar-chart-panel', 'name': _('Evolution of Analysis Requests'), 'class': 'informative', 'description': _('Evolution of Analysis Requests'), 'data': json.dumps(outevo) }) return { 'id': 'analysisrequests', 'title': _('Analysis Requests'), 'panels': out } def get_worksheets_section(self): """ Returns the section dictionary related with Worksheets, that contains some informative panels (like WS to be verified, WS with results pending, etc.) """ out = [] bc = getToolByName(self.context, "bika_catalog") active_ws = ['open', 'to_be_verified', 'attachment_due'] numws = len(bc(portal_type="Worksheet", created=self.date_range)) numws += len( bc(portal_type="Worksheet", review_state=active_ws, created=self.base_date_range)) # Open worksheets review_state = ['open', 'attachment_due'] ws = len(bc(portal_type="Worksheet", review_state=review_state)) ratio = (float(ws) / float(numws)) * 100 if ws > 0 and numws > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("Results pending") out.append({ 'type': 'simple-panel', 'name': _('Results pending'), 'class': 'informative', 'description': msg, 'number': ws, 'total': numws, 'legend': _('of') + " " + str(numws) + ' (' + ratio + '%)', 'link': self.portal_url + '/worksheets?list_review_state=open' }) # Worksheets to be verified review_state = [ 'to_be_verified', ] ws = len(bc(portal_type="Worksheet", review_state=review_state)) ratio = (float(ws) / float(numws)) * 100 if ws > 0 and numws > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("To be verified") out.append({ 'type': 'simple-panel', 'name': _('To be verified'), 'class': 'informative', 'description': msg, 'number': ws, 'total': numws, 'legend': _('of') + " " + str(numws) + ' (' + ratio + '%)', 'link': self.portal_url + '/worksheets?list_review_state=to_be_verified' }) # Chart with the evolution of WSs over a period, grouped by # periodicity workflow = getToolByName(self.context, 'portal_workflow') allws = bc(portal_type="Worksheet", sort_on="created", created=self.min_date_range) outevo = [] for ws in allws: ws = ws.getObject() state = 'other_status' try: state = workflow.getInfoFor(ws, 'cancellation_state') if (state == 'active'): state = workflow.getInfoFor(ws, 'review_state') else: state = 'inactive' except: pass created = self._getDateStr(self.periodicity, ws.created()) if (len(outevo) > 0 and outevo[-1]['date'] == created): key = state if _(state) in outevo[-1] else 'other_status' outevo[-1][_(key)] += 1 else: currow = { 'date': created, _('open'): 0, _('to_be_verified'): 0, _('attachment_due'): 0, _('verified'): 0, _('inactive'): 0, _('other_status'): 0, } key = state if _(state) in currow else 'other_status' currow[_(key)] += 1 outevo.append(currow) out.append({ 'type': 'bar-chart-panel', 'name': _('Evolution of Worksheets'), 'class': 'informative', 'description': _('Evolution of Worksheets'), 'data': json.dumps(outevo) }) return {'id': 'worksheets', 'title': _('Worksheets'), 'panels': out} def get_analyses_section(self): """ Returns the section dictionary related with Analyses, that contains some informative panels (analyses pending analyses assigned, etc.) sample_registered, not_requested, published, retracted, sample_due, sample_received, sample_prep, sampled, to_be_preserved, to_be_sampled, , to_be_verified, rejected, verified, to_be_verified, assigned """ out = [] active_rs = [ 'sample_received', 'assigned', 'attachment_due', 'to_be_verified', 'verified' ] bac = getToolByName(self.context, "bika_analysis_catalog") numans = len( bac(portal_type="Analysis", created=self.date_range, cancellation_state=['active'])) numans += len( bac(portal_type="Analysis", review_state=active_rs, cancellation_state=['active'], created=self.base_date_range)) # Analyses pending review_state = [ 'sample_received', 'assigned', 'attachment_due', 'to_be_verified' ] ans = len(bac(portal_type="Analysis", review_state=review_state)) ratio = (float(ans) / float(numans)) * 100 if ans > 0 and numans > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("Analyses pending") out.append({ 'type': 'simple-panel', 'name': _('Analyses pending'), 'class': 'informative', 'description': msg, 'number': ans, 'total': numans, 'legend': _('of') + " " + str(numans) + ' (' + ratio + '%)', 'link': self.portal_url + '/aggregatedanalyses' }) # Analyses to be verified review_state = [ 'to_be_verified', ] ans = len(bac(portal_type="Analysis", review_state=review_state)) ratio = (float(ans) / float(numans)) * 100 if ans > 0 and numans > 0 else 0 ratio = str("%%.%sf" % 1) % ratio msg = _("To be verified") out.append({ 'type': 'simple-panel', 'name': _('To be verified'), 'class': 'informative', 'description': msg, 'number': ans, 'total': numans, 'legend': _('of') + " " + str(numans) + ' (' + ratio + '%)', 'link': self.portal_url + '/worksheets?list_review_state=to_be_verified' }) # Chart with the evolution of WSs over a period, grouped by # periodicity workflow = getToolByName(self.context, 'portal_workflow') allans = bac(portal_type="Analysis", sort_on="created", created=self.min_date_range) outevo = [] for an in allans: an = an.getObject() state = 'other_status' try: state = workflow.getInfoFor(an, 'cancellation_state') if (state == 'active'): state = workflow.getInfoFor(an, 'review_state') else: state = 'inactive' except: pass created = self._getDateStr(self.periodicity, an.created()) if (len(outevo) > 0 and outevo[-1]['date'] == created): key = state if _(state) in outevo[-1] else 'other_status' outevo[-1][_(key)] += 1 else: currow = { 'date': created, _('assigned'): 0, _('to_be_verified'): 0, _('attachment_due'): 0, _('verified'): 0, _('inactive'): 0, _('other_status'): 0, } key = state if _(state) in currow else 'other_status' currow[_(key)] += 1 outevo.append(currow) out.append({ 'type': 'bar-chart-panel', 'name': _('Evolution of Analyses'), 'class': 'informative', 'description': _('Evolution of Analyses'), 'data': json.dumps(outevo) }) return {'id': 'analyses', 'title': _('Analyses'), 'panels': out} def _getDateStr(self, period, created): if period == 'y': created = created.year() elif period == 'b': m = (((created.month() - 1) / 6) * 6) + 1 created = '%s-%s' % (str(created.year())[2:], str(m).zfill(2)) elif period == 'q': m = (((created.month() - 1) / 3) * 3) + 1 created = '%s-%s' % (str(created.year())[2:], str(m).zfill(2)) elif period == 'm': created = '%s-%s' % (str(created.year())[2:], str( created.month()).zfill(2)) elif period == 'w': d = (((created.day() - 1) / 7) * 7) + 1 year, weeknum, dow = created.asdatetime().isocalendar() created = created - dow created = '%s-%s-%s' % (str( created.year())[2:], str( created.month()).zfill(2), str(created.day()).zfill(2)) else: created = '%s-%s-%s' % (str( created.year())[2:], str( created.month()).zfill(2), str(created.day()).zfill(2)) return created
def inspectViewletManager(self, managerName): """ Display information about a particular viewlet manager """ logger.debug("in inspectViewletManager") # Get the viewletmanager object managerName = managerName.replace('-', '.') viewletManager = queryMultiAdapter((self.context, self.request, self), IViewletManager, managerName) # Gather information for the viewlet hashes managerInterface = list(providedBy(viewletManager).flattened())[0] # Look up the viewlets attached to this viewlet manager. # We do it this way because calling viewletManager.viewlets won't see the hidden viewlets... viewlets = getAdapters((self.context, self.request, viewletManager.__parent__, viewletManager),IViewlet) # Get the names of the hidden viewlets storage = getUtility(IViewletSettingsStorage) hidden = frozenset(storage.getHidden(managerName, self.context.getCurrentSkinName())) # Generate the output sortedViewlets = viewletManager.sort(viewlets) containedViewlets = [] for viewletTuple in sortedViewlets: containedViewlet = {} viewletname = viewletTuple[0] # generate viewlet hashes... # TODO factor this up. # Get the "provided" interfaces for this viewlet manager. # TODO: Do this lookup properly. regs = [regs for regs in getGlobalSiteManager().registeredAdapters() if regs.name == viewletname and regs.required[-1].isOrExtends(managerInterface)] if regs: reg = regs[0] provided = ','.join([a.__identifier__ for a in reg.required]) # logger.debug("%s - provided: %s" % (viewletName, provided)) hashedInfo = binascii.b2a_hex("%s\n%s\n%s" % (viewletname, managerName, provided)) else: hashedInfo = "" logger.debug("Unable to create hash for %s" % viewletname) # Give the viewlet a class name depending on the visibility classname = viewletname in hidden and 'hiddenViewlet' or 'visibleViewlet' logger.debug(classname) containedViewlet['className'] = classname containedViewlet['hashedInfo'] = hashedInfo containedViewlet['name'] = viewletname containedViewlets.append(containedViewlet) # Determine whether the contained viewlets can be sorted. skinname = self.context.getCurrentSkinName() canOrder = bool(storage.getOrder(managerName, skinname)) template = ViewPageTemplateFile('panel_inspect_viewlet_manager.pt') # Wrap it so that Zope knows in what context it's being called # Otherwise, we get an "AttributeError: 'str' object has no attribute 'other'" error template = template.__of__(self) out = template(managerName = managerName, containedViewlets = containedViewlets, canOrder = canOrder ) # Dump the output to the output panel self.updatePanelBodyContent(out) # Highlight the element ksscore = self.getCommandSet('core') self.highlightElement(ksscore.getCssSelector('.kssattr-viewletmanagername-%s' % managerName.replace('.', '-'))) # And in the nav tree (Should this be here or in the nav tree viewlet code?) self.highlightInNavTree(ksscore.getCssSelector('#glowormPanelNavTree .kssattr-forviewletmanager-%s' % managerName.replace('.', '-'))) return self.render()
# -*- coding: utf-8 -*- from plone.z3cform.layout import wrap_form from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile from rer.newsletterplugin.flask import _ from rer.newsletter.browser.message.sendmessageview import SendMessageView class SendMessageViewCustom(SendMessageView): @property def success_message(self): return _( u'message_send', default=u'Message correctly enqueued to be sent to ${subscribers} ' u'subscribers. Please check Channel history to know when ' u'the task ends or wait the confirm email.', mapping=dict(subscribers=self.active_subscriptions), ) message_sending_view = wrap_form( SendMessageViewCustom, index=ViewPageTemplateFile('templates/sendmessageview.pt'), )
class Download(Pdf): """ Download PDF """ template = ViewPageTemplateFile('../zpt/download.pt') _message = '' _email = '' def make_pdf(self, dry_run=False, **kwargs): """ Compute pdf """ data = super(Download, self).make_pdf(dry_run=dry_run, **kwargs) # Async if dry_run: return data # Sync events if not data: event.notify(PDFExportFail(self.context)) event.notify(PDFExportSuccess(self.context)) return data @property def message(self): """ Message """ return self._message @property def email(self): """ User email """ return self._email def _redirect(self, msg=''): """ Redirect """ self.request.set('disable_border', 1) self.request.set('disable_plone.leftcolumn', 1) self.request.set('disable_plone.rightcolumn', 1) self._message = msg return self.template() def link(self): """ Download link """ storage = IStorage(self.context).of('pdf') return storage.absolute_url() def period(self): """ Wait period """ ptype = getattr(self.context, 'portal_type', '') if ptype.lower() in ('collection', 'topic', 'folder', 'atfolder'): return _(u"minutes") return _(u"seconds") def finish(self, email=''): """ Finish download """ self._email = email return self._redirect( _( u"The PDF is being generated. " u"An email will be sent to you when the PDF is ready. " u"If you don't have access to your email address " u"check <a href='${link}'>this link</a> in a few ${period}.", mapping={ "link": self.link(), "period": self.period() })) def download(self, email='', **kwargs): """ Download """ # PDF already generated storage = IStorage(self.context).of('pdf') filepath = storage.filepath() fileurl = storage.absolute_url() url = self.context.absolute_url() title = self.context.title_or_id() portal = getSite() from_name = portal.getProperty('email_from_name') from_email = portal.getProperty('email_from_address') if async .file_exists(filepath): wrapper = async .ContextWrapper(self.context)( fileurl=fileurl, filepath=filepath, email=email, url=url, from_name=from_name, from_email=from_email, title=title) event.notify(AsyncPDFExportSuccess(wrapper)) return self.finish(email=email) # Cheat condition @@plone_context_state/is_view_template self.request['ACTUAL_URL'] = self.context.absolute_url() # Async generate PDF converter = self.make_pdf(dry_run=True) worker = queryUtility(IAsyncService) worker.queueJob(async .make_async_pdf, self.context, converter, email=email, filepath=filepath, fileurl=fileurl, url=url, from_name=from_name, from_email=from_email, title=title) return self.finish(email=email)
def inspectElement(self, insideInspectableArea=False, talcontent=None, talattributes=None, talcondition=None, metaldefmacro=None, metalusemacro=None, fieldname=None, portlethash=None, viewlethash=None, sourceAnnotation=None): """ Get details about a particular html element. """ # Make sure we're not clicking inside the inspector div since KSS doesn't seem to provide a # way to block processing of other rules. if insideInspectableArea: logger.debug("in inspectElement") parsedTalAttributes = [] if talattributes: # logger.debug("talattributes: %s" % talattributes) # If there's only one item in the list being returned by the KSS method, # it's passing it as a string instead of a list/array. Not sure why. # Sniff the type and make it a list if needed. if isinstance(talattributes, str): talattributes = [talattributes] for attr in talattributes: # logger.debug("attr: %s" % attr) attribute = {} attribute['name'], attribute['expression'], attribute['result'] = attr.split(',') parsedTalAttributes.append(attribute) unhashedPortletInfo = {} if portlethash: unhashedPortletInfo = unhashPortletInfo(portlethash) unhashedViewletInfo = {} if viewlethash: unhashedViewletInfo = unhashViewletInfo(viewlethash) if sourceAnnotation: sourceAnnotation = sourceAnnotation.strip(' =\n') template = ViewPageTemplateFile('panel_inspect_element.pt') # Wrap it so that Zope knows in what context it's being called # Otherwise, we get an "AttributeError: 'str' object has no attribute 'other'" error template = template.__of__(self) out = template(metalUseMacro = metalusemacro, metalDefMacro = metaldefmacro, fieldName = fieldname, talContent = talcontent, talAttributes = parsedTalAttributes, talCondition = talcondition, portletInfo = unhashedPortletInfo, viewletInfo = unhashedViewletInfo, sourceAnnotation = sourceAnnotation ) # Dump the output to the inspector panel self.updatePanelBodyContent(out) # Highlight this element ksscore = self.getCommandSet('core') self.highlightElement(ksscore.getSameNodeSelector()) # And in the nav tree (Should this be here or in the nav tree viewlet code?) if viewlethash: self.highlightInNavTree(ksscore.getCssSelector('#glowormPanelNavTree .kssattr-forviewlet-%s' % viewlethash)) return self.render()
class A18MeasureProgressDisplay(ItemDisplayForm): title = "Measure Progress display" extra_data_template = ViewPageTemplateFile('pt/extra-data-pivot.pt') mapper_class = sql2018.ART18MeasureProgres css_class = 'left-side-form' blacklist_labels = ('MeasureCode', ) reported_date_info = { 'mapper_class': sql2018.ReportedInformation, 'col_import_id': 'Id', 'col_import_time': 'ReportingDate' } def get_reported_date(self): return self.get_reported_date_2018() def get_import_id(self): import_id = self.item.IdReportedInformation return import_id @db.use_db_session('2018') def get_current_country(self): report_id = self.item.IdReportedInformation _, res = db.get_related_record(sql2018.ReportedInformation, 'Id', report_id) country = self.print_value(res.CountryCode) return country @db.use_db_session('2018') def download_results(self): mc_descr = sql2018.ART18MeasureProgressDescriptor mc_countries = sql2018.ReportedInformation countries = self.get_form_data_by_key(self, 'member_states') ges_comps = self.get_form_data_by_key(self, 'ges_component') conditions = [] if countries: conditions.append(mc_countries.CountryCode.in_(countries)) count, report_ids = db.get_all_records(mc_countries, *conditions) report_ids = [x.Id for x in report_ids] conditions = [] if ges_comps: conditions.append(mc_descr.DescriptorCode.in_(ges_comps)) count, measure_progress_ids = db.get_all_records(mc_descr, *conditions) measure_progress_ids = [ x.IdMeasureProgress for x in measure_progress_ids ] count, measure_prog = db.get_all_records( self.mapper_class, self.mapper_class.IdReportedInformation.in_(report_ids), self.mapper_class.Id.in_(measure_progress_ids), ) id_measure = [x.Id for x in measure_prog] count, measure_prog_descr = db.get_all_records( mc_descr, mc_descr.IdMeasureProgress.in_(id_measure)) xlsdata = [ ('ART18MeasureProgres', measure_prog), # worksheet title, row data ('ART18MeasureProgressDescriptor', measure_prog_descr), ] return data_to_xls(xlsdata) @db.use_db_session('2018') def get_db_results(self): page = self.get_page() mc_descr = sql2018.ART18MeasureProgressDescriptor mc_countries = sql2018.ReportedInformation countries = self.get_form_data_by_key(self, 'member_states') ges_comps = self.get_form_data_by_key(self, 'ges_component') conditions = [] if countries: conditions.append(mc_countries.CountryCode.in_(countries)) count, report_ids = db.get_all_records(mc_countries, *conditions) report_ids = [x.Id for x in report_ids] conditions = [] if ges_comps: conditions.append(mc_descr.DescriptorCode.in_(ges_comps)) count, measure_progress_ids = db.get_all_records(mc_descr, *conditions) measure_progress_ids = [ x.IdMeasureProgress for x in measure_progress_ids ] item = db.get_item_by_conditions( self.mapper_class, 'Id', self.mapper_class.IdReportedInformation.in_(report_ids), self.mapper_class.Id.in_(measure_progress_ids), page=page) return item @db.use_db_session('2018') def get_extra_data(self): if not self.item: return {} mc = sql2018.ART18MeasureProgressDescriptor excluded_columns = ('IdMeasureProgress', ) res = [] id_measure = self.item.Id count, data = db.get_all_records(mc, mc.IdMeasureProgress == id_measure) data = db_objects_to_dict(data, excluded_columns) res.append(('Descriptor', {'': data})) return res
class DashboardPortletManagerRenderer(ColumnPortletManagerRenderer): """Render a column of the dashboard """ adapts(Interface, IDefaultBrowserLayer, IBrowserView, IDashboard) template = ViewPageTemplateFile('browser/templates/dashboard-column.pt')
class SliderNavigation(navigation.SliderNavigation): template = ViewPageTemplateFile('slider.pt')
class LogoViewlet(LogoBaseViewlet): index = ViewPageTemplateFile('logo_viewlet.pt')
class Listing(BrowserView): index = ViewPageTemplateFile( pkg_resources.resource_filename('collective.eeafaceted.z3ctable', 'browser/faceted-table-items.pt'))
class AddRequestFormView(FormWrapper): form = AddRequestForm index = ViewPageTemplateFile("templates/add_request_form_view.pt")
class AnalysisRequestsView(BikaListingView): """Listing View for all Analysis Requests in the System """ template = ViewPageTemplateFile("templates/analysisrequests.pt") def __init__(self, context, request): super(AnalysisRequestsView, self).__init__(context, request) # hide the right column request.set("disable_plone.rightcolumn", 1) # hide the editable border if self.context.portal_type == "AnalysisRequestsFolder": self.request.set("disable_border", 1) # catalog used for the query self.catalog = CATALOG_ANALYSIS_REQUEST_LISTING # https://docs.plone.org/develop/plone/searching_and_indexing/query.html#searching-for-content-within-a-folder self.contentFilter = { "sort_on": "created", "sort_order": "descending", "cancellation_state": "active", } # Filter by Department if self.context.bika_setup.getAllowDepartmentFiltering(): deps = self.request.get('filter_by_department_info', '') dep_uids = deps.split(",") dep_query = {"query": dep_uids, "operator": "or"} self.contentFilter['getDepartmentUIDs'] = dep_query self.context_actions = {} if self.view_url.find("analysisrequests") == -1: self.view_url = self.view_url + "/analysisrequests" self.allow_edit = True self.show_sort_column = False self.show_select_row = False self.show_select_column = True self.form_id = "analysisrequests" ar_image_path = "/++resource++bika.lims.images/analysisrequest_big.png" self.icon = "{}{}".format(self.portal_url, ar_image_path) self.title = self.context.translate(_("Analysis Requests")) self.description = "" SamplingWorkflowEnabled = \ self.context.bika_setup.getSamplingWorkflowEnabled() # Check if the filter bar functionality is activated or not self.filter_bar_enabled =\ self.context.bika_setup.\ getDisplayAdvancedFilterBarForAnalysisRequests() self.columns = collections.OrderedDict(( ("Priority", { "title": "", "index": "getPrioritySortkey", "sortable": True, }), ("Progress", { "title": "Progress", "sortable": False, "toggle": True }), ("getId", { "title": _("Request ID"), "attr": "getId", "replace_url": "getURL", "index": "getId" }), ("getClientOrderNumber", { "title": _("Client Order"), "sortable": True, "toggle": False }), ("Creator", { "title": _("Creator"), "index": "getCreatorFullName", "sortable": True, "toggle": True }), ("Created", { "title": _("Date Registered"), "index": "created", "toggle": False }), ("SamplingDate", { "title": _("Expected Sampling Date"), "index": "getSamplingDate", "toggle": SamplingWorkflowEnabled }), ("getDateSampled", { "title": _("Date Sampled"), "toggle": True, "input_class": "datetimepicker_nofuture", "input_width": "10" }), ("getDatePreserved", { "title": _("Date Preserved"), "toggle": False, "input_class": "datetimepicker_nofuture", "input_width": "10", "sortable": False }), # no datesort without index ("getDateReceived", { "title": _("Date Received"), "toggle": False }), ("getDueDate", { "title": _("Due Date"), "toggle": False }), ("getDateVerified", { "title": _("Date Verified"), "input_width": "10", "toggle": False }), ("getDatePublished", { "title": _("Date Published"), "toggle": False }), ("getSample", { "title": _("Sample"), "attr": "getSampleID", "index": "getSampleID", "replace_url": "getSampleURL", "toggle": False }), ("BatchID", { "title": _("Batch ID"), "index": "getBatchID", "sortable": True, "toggle": False }), ("Client", { "title": _("Client"), "index": "getClientTitle", "attr": "getClientTitle", "replace_url": "getClientURL", "toggle": True }), ("Province", { "title": _("Province"), "sortable": True, "index": "getProvince", "attr": "getProvince", "toggle": False }), ("District", { "title": _("District"), "sortable": True, "index": "getDistrict", "attr": "getDistrict", "toggle": False }), ("getClientReference", { "title": _("Client Ref"), "sortable": True, "index": "getClientReference", "toggle": False }), ("getClientSampleID", { "title": _("Client SID"), "toggle": False }), ("ClientContact", { "title": _("Contact"), "sortable": True, "index": "getContactFullName", "toggle": False }), ("getSampleTypeTitle", { "title": _("Sample Type"), "sortable": True, "toggle": True }), ("getSamplePointTitle", { "title": _("Sample Point"), "sortable": True, "index": "getSamplePointTitle", "toggle": False }), ("getStorageLocation", { "title": _("Storage Location"), "sortable": True, "index": "getStorageLocationTitle", "toggle": False }), ("SamplingDeviation", { "title": _("Sampling Deviation"), "sortable": True, "index": "getSamplingDeviationTitle", "toggle": False }), ("getSampler", { "title": _("Sampler"), "toggle": SamplingWorkflowEnabled }), ("getPreserver", { "title": _("Preserver"), "sortable": False, "toggle": False }), ("getProfilesTitle", { "title": _("Profile"), "sortable": True, "index": "getProfilesTitle", "toggle": False }), ("getAnalysesNum", { "title": _("Number of Analyses"), "sortable": True, "index": "getAnalysesNum", "toggle": False }), ("getTemplateTitle", { "title": _("Template"), "sortable": True, "index": "getTemplateTitle", "toggle": False }), ("Printed", { "title": _("Printed"), "sortable": False, "index": "getPrinted", "toggle": False }), ("state_title", { "title": _("State"), "sortable": True, "index": "review_state" }), )) # custom print transition print_stickers = { "id": "print_stickers", "title": _("Print stickers"), "url": "workflow_action?action=print_stickers" } self.review_states = [ { "id": "default", "title": _("Active"), "contentFilter": { "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "sample" }, { "id": "preserve" }, { "id": "receive" }, { "id": "retract" }, { "id": "verify" }, { "id": "prepublish" }, { "id": "publish" }, { "id": "republish" }, { "id": "cancel" }, { "id": "reinstate" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "to_be_sampled", "title": _("To Be Sampled"), "contentFilter": { "review_state": ("to_be_sampled", ), "sort_on": "created", "sort_order": "descending" }, "transitions": [ { "id": "sample" }, { "id": "submit" }, { "id": "cancel" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys() }, { "id": "to_be_preserved", "title": _("To Be Preserved"), "contentFilter": { "review_state": ("to_be_preserved", ), "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "preserve" }, { "id": "cancel" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "scheduled_sampling", "title": _("Scheduled sampling"), "contentFilter": { "review_state": ("scheduled_sampling", ), "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "sample" }, { "id": "cancel" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "sample_due", "title": _("Due"), "contentFilter": { "review_state": ("to_be_sampled", "to_be_preserved", "sample_due"), "sort_on": "created", "sort_order": "descending" }, "transitions": [ { "id": "sample" }, { "id": "preserve" }, { "id": "receive" }, { "id": "cancel" }, { "id": "reinstate" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "sample_received", "title": _("Received"), "contentFilter": { "review_state": "sample_received", "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "prepublish" }, { "id": "cancel" }, { "id": "reinstate" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "to_be_verified", "title": _("To be verified"), "contentFilter": { "review_state": "to_be_verified", "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "retract" }, { "id": "verify" }, { "id": "prepublish" }, { "id": "cancel" }, { "id": "reinstate" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "verified", "title": _("Verified"), "contentFilter": { "review_state": "verified", "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "publish" }, { "id": "cancel" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "published", "title": _("Published"), "contentFilter": { "review_state": ("published"), "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "republish" }, ], "custom_transitions": [], "columns": self.columns.keys(), }, { "id": "unpublished", "title": _("Unpublished"), "contentFilter": { "cancellation_state": "active", "review_state": ( "sample_registered", "to_be_sampled", "to_be_preserved", "sample_due", "sample_received", "to_be_verified", "attachment_due", "verified", ), "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "sample" }, { "id": "preserve" }, { "id": "receive" }, { "id": "retract" }, { "id": "verify" }, { "id": "prepublish" }, { "id": "publish" }, { "id": "republish" }, { "id": "cancel" }, { "id": "reinstate" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "cancelled", "title": _("Cancelled"), "contentFilter": { "cancellation_state": "cancelled", "review_state": ( "sample_registered", "to_be_sampled", "to_be_preserved", "sample_due", "sample_received", "to_be_verified", "attachment_due", "verified", "published", ), "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "reinstate" }, ], "custom_transitions": [], "columns": self.columns.keys(), }, { "id": "invalid", "title": _("Invalid"), "contentFilter": { "review_state": "invalid", "sort_on": "created", "sort_order": "descending", }, "transitions": [], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "rejected", "title": _("Rejected"), "contentFilter": { "review_state": "rejected", "sort_on": "created", "sort_order": "descending", }, "transitions": [], "custom_transitions": [ { "id": "print_stickers", "title": _("Print stickers"), "url": "workflow_action?action=print_stickers" }, ], "columns": self.columns.keys(), }, { "id": "assigned", "title": get_image("assigned.png", title=t(_("Assigned"))), "contentFilter": { "assigned_state": "assigned", "cancellation_state": "active", "review_state": ( "sample_received", "attachment_due", ), "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "receive" }, { "id": "retract" }, { "id": "prepublish" }, { "id": "cancel" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "unassigned", "title": get_image("unassigned.png", title=t(_("Unsassigned"))), "contentFilter": { "assigned_state": "unassigned", "cancellation_state": "active", "review_state": ( "sample_received", "attachment_due", ), "sort_on": "created", "sort_order": "descending", }, "transitions": [ { "id": "receive" }, { "id": "retract" }, { "id": "prepublish" }, { "id": "cancel" }, ], "custom_transitions": [print_stickers], "columns": self.columns.keys(), }, { "id": "late", "title": get_image("late.png", title=t(_("Late"))), "contentFilter": { "cancellation_state": "active", # Query only for unpublished ARs that are late "review_state": ( "sample_received", "attachment_due", "to_be_verified", "verified", ), "getDueDate": { "query": DateTime(), "range": "max", }, "sort_on": "created", "sort_order": "descending", }, "custom_transitions": [print_stickers], "columns": self.columns.keys(), } ] def update(self): """Called before the listing renders """ super(AnalysisRequestsView, self).update() self.workflow = api.get_tool("portal_workflow") self.member = self.mtool.getAuthenticatedMember() self.roles = self.member.getRoles() setup = api.get_bika_setup() # remove `to_be_sampled` filter if not setup.getSamplingWorkflowEnabled(): self.review_states = filter( lambda x: x.get("id") != "to_be_sampled", self.review_states) # remove `scheduled_sampling` filter if not setup.getScheduleSamplingEnabled(): self.review_states = filter( lambda x: x.get("id") != "scheduled_sampling", self.review_states) # remove `to_be_preserved` filter if not setup.getSamplePreservationEnabled(): self.review_states = filter( lambda x: x.get("id") != "to_be_preserved", self.review_states) # remove `rejected` filter if not setup.getRejectionReasons(): self.review_states = filter(lambda x: x.get("id") != "rejected", self.review_states) self.hideclientlink = "RegulatoryInspector" in self.roles \ and "Manager" not in self.roles \ and "LabManager" not in self.roles \ and "LabClerk" not in self.roles if self.context.portal_type == "AnalysisRequestsFolder" and \ (self.mtool.checkPermission(AddAnalysisRequest, self.context)): self.context_actions[_("Add")] = \ {"url": "ar_add?ar_count=1", 'permission': 'Add portal content', "icon": "++resource++bika.lims.images/add.png"} self.editresults = -1 self.clients = {} # self.user_is_preserver = "Preserver" in self.roles # Printing workflow enabled? # If not, remove the Column self.printwfenabled = \ self.context.bika_setup.getPrintingWorkflowEnabled() printed_colname = "Printed" if not self.printwfenabled and printed_colname in self.columns: # Remove "Printed" columns del self.columns[printed_colname] tmprvs = [] for rs in self.review_states: tmprs = rs tmprs["columns"] = [ c for c in rs.get("columns", []) if c != printed_colname ] tmprvs.append(tmprs) self.review_states = tmprvs elif self.printwfenabled: # Print button to choose multiple ARs and print them. review_states = [] for review_state in self.review_states: review_state.get("custom_transitions", []).extend([ { "id": "print", "title": _("Print"), "url": "workflow_action?action=print" }, ]) review_states.append(review_state) self.review_states = review_states # Only "BIKA: ManageAnalysisRequests" may see the copy to new button. # elsewhere it is hacked in where required. if self.copy_to_new_allowed: review_states = [] for review_state in self.review_states: review_state.get("custom_transitions", []).extend([ { "id": "copy_to_new", "title": _("Copy to new"), "url": "workflow_action?action=copy_to_new" }, ]) review_states.append(review_state) self.review_states = review_states # Hide Preservation/Sampling workflow actions if the edit columns # are not displayed. toggle_cols = self.get_toggle_cols() new_states = [] for i, state in enumerate(self.review_states): if state["id"] == self.review_state: if "getSampler" not in toggle_cols \ or "getDateSampled" not in toggle_cols: if "hide_transitions" in state: state["hide_transitions"].append("sample") else: state["hide_transitions"] = [ "sample", ] if "getPreserver" not in toggle_cols \ or "getDatePreserved" not in toggle_cols: if "hide_transitions" in state: state["hide_transitions"].append("preserve") else: state["hide_transitions"] = [ "preserve", ] new_states.append(state) self.review_states = new_states def before_render(self): """Before template render hook """ # If the current user is a client contact, display those analysis # requests that belong to same client only super(AnalysisRequestsView, self).before_render() client = api.get_current_client() if client: self.contentFilter['path'] = { "query": "/".join(client.getPhysicalPath()), "level": 0 } # No need to display the Client column self.remove_column('Client') def isItemAllowed(self, obj): """ If Adnvanced Filter bar is enabled, this method checks if the item matches advanced filter bar criteria """ return not self.filter_bar_enabled or self.filter_bar_check_item(obj) def folderitems(self, full_objects=False, classic=False): # We need to get the portal catalog here in roder to save process # while iterating over folderitems self.portal_catalog = api.get_tool("portal_catalog") return BikaListingView.folderitems(self, full_objects, classic) def folderitem(self, obj, item, index): # Additional info from AnalysisRequest to be added in the item # generated by default by bikalisting. # Call the folderitem method from the base class item = BikaListingView.folderitem(self, obj, item, index) if not item: return None # This variable will contain the full analysis request if there is # need to work with the full object instead of the brain full_object = None item["Creator"] = self.user_fullname(obj.Creator) # If we redirect from the folderitems view we should check if the # user has permissions to medify the element or not. priority_sort_key = obj.getPrioritySortkey if not priority_sort_key: # Default priority is Medium = 3. # The format of PrioritySortKey is <priority>.<created> priority_sort_key = "3.%s" % obj.created.ISO8601() priority = priority_sort_key.split(".")[0] priority_text = PRIORITIES.getValue(priority) priority_div = """<div class="priority-ico priority-%s"> <span class="notext">%s</span><div> """ item["replace"]["Priority"] = priority_div % (priority, priority_text) item["replace"]["getProfilesTitle"] = obj.getProfilesTitleStr analysesnum = obj.getAnalysesNum if analysesnum: num_verified = str(analysesnum[0]) num_total = str(analysesnum[1]) item["getAnalysesNum"] = "{0}/{1}".format(num_verified, num_total) else: item["getAnalysesNum"] = "" # Progress num_verified = 0 num_submitted = 0 num_total = 0 if analysesnum and len(analysesnum) > 1: num_verified = analysesnum[0] num_total = analysesnum[1] num_submitted = num_total - num_verified if len(analysesnum) > 2: num_wo_results = analysesnum[2] num_submitted = num_total - num_verified - num_wo_results num_steps_total = num_total * 2 num_steps = (num_verified * 2) + (num_submitted) progress_perc = 0 if num_steps > 0 and num_steps_total > 0: progress_perc = (num_steps * 100) / num_steps_total progress = '<div class="progress-bar-container">' + \ '<div class="progress-bar" style="width:{0}%"></div>' + \ '<div class="progress-perc">{0}%</div></div>' item["replace"]["Progress"] = progress.format(progress_perc) item["BatchID"] = obj.getBatchID if obj.getBatchID: item['replace']['BatchID'] = "<a href='%s'>%s</a>" % \ (obj.getBatchURL, obj.getBatchID) # TODO: SubGroup ??? # val = obj.Schema().getField('SubGroup').get(obj) # item['SubGroup'] = val.Title() if val else '' date = obj.getSamplingDate item["SamplingDate"] = \ self.ulocalized_time(date, long_format=1) if date else "" date = obj.getDateReceived item["getDateReceived"] = \ self.ulocalized_time(date, long_format=1) if date else "" date = obj.getDueDate item["getDueDate"] = \ self.ulocalized_time(date, long_format=1) if date else "" date = obj.getDatePublished item["getDatePublished"] = \ self.ulocalized_time(date, long_format=1) if date else "" date = obj.getDateVerified item["getDateVerified"] = \ self.ulocalized_time(date, long_format=1) if date else "" if self.printwfenabled: item["Printed"] = "" printed = obj.getPrinted if hasattr(obj, "getPrinted") else "0" print_icon = "" if printed == "0": print_icon = get_image("delete.png", title=t(_("Not printed yet"))) elif printed == "1": print_icon = get_image("ok.png", title=t(_("Printed"))) elif printed == "2": print_icon = get_image("exclamation.png", title=t( _("Republished after last print"))) item["after"]["Printed"] = print_icon item["SamplingDeviation"] = obj.getSamplingDeviationTitle item["getStorageLocation"] = obj.getStorageLocationTitle after_icons = "" # Getting a dictionary with each workflow id and current state in it states_dict = obj.getObjectWorkflowStates if obj.assigned_state == 'assigned': after_icons += get_image("worksheet.png", title=t(_("All analyses assigned"))) if states_dict.get('review_state', '') == 'invalid': after_icons += get_image("delete.png", title=t(_("Results have been withdrawn"))) due_date = obj.getDueDate if due_date and due_date < (obj.getDatePublished or DateTime()): due_date_str = self.ulocalized_time(due_date) img_title = "{}: {}".format(t(_("Late Analyses")), due_date_str) after_icons += get_image("late.png", title=img_title) if obj.getSamplingDate and obj.getSamplingDate > DateTime(): after_icons += get_image("calendar.png", title=t(_("Future dated sample"))) if obj.getInvoiceExclude: after_icons += get_image("invoice_exclude.png", title=t(_("Exclude from invoice"))) if obj.getHazardous: after_icons += get_image("hazardous.png", title=t(_("Hazardous"))) if after_icons: item['after']['getId'] = after_icons item['Created'] = self.ulocalized_time(obj.created, long_format=1) if obj.getContactUID: item['ClientContact'] = obj.getContactFullName item['replace']['ClientContact'] = "<a href='%s'>%s</a>" % \ (obj.getContactURL, obj.getContactFullName) else: item["ClientContact"] = "" # TODO-performance: If SamplingWorkflowEnabled, we have to get the # full object to check the user permissions, so far this is # a performance hit. if obj.getSamplingWorkflowEnabled: # We don't do anything with Sampling Date. # User can modify Sampling date # inside AR view. In this listing view, # we only let the user to edit Date Sampled # and Sampler if he wants to make 'sample' transaction. if not obj.getDateSampled: datesampled = self.ulocalized_time(DateTime(), long_format=True) item["class"]["getDateSampled"] = "provisional" else: datesampled = self.ulocalized_time(obj.getDateSampled, long_format=True) sampler = obj.getSampler if sampler: item["replace"]["getSampler"] = obj.getSamplerFullName if "Sampler" in self.roles and not sampler: sampler = self.member.id item["class"]["getSampler"] = "provisional" # sampling workflow - inline edits for Sampler and Date Sampled if states_dict.get('review_state', '') == 'to_be_sampled': # We need to get the full object in order to check # the permissions full_object = obj.getObject() checkPermission =\ self.context.portal_membership.checkPermission if checkPermission(SampleSample, full_object): item["required"] = ["getSampler", "getDateSampled"] item["allow_edit"] = ["getSampler", "getDateSampled"] # TODO-performance: hit performance while getting the # sample object... # TODO Can LabManagers be a Sampler?! samplers = getUsers(full_object.getSample(), [ "Sampler", ]) username = self.member.getUserName() users = [({ "ResultValue": u, "ResultText": samplers.getValue(u) }) for u in samplers] item['choices'] = {'getSampler': users} Sampler = sampler and sampler or \ (username in samplers.keys() and username) or '' sampler = Sampler else: datesampled = self.ulocalized_time(obj.getDateSampled, long_format=True) sampler = obj.getSamplerFullName if obj.getSampler else '' else: datesampled = self.ulocalized_time(obj.getDateSampled, long_format=True) sampler = "" item["getDateSampled"] = datesampled item["getSampler"] = sampler # These don't exist on ARs # XXX This should be a list of preservers... item["getPreserver"] = "" item["getDatePreserved"] = "" # TODO-performance: If inline preservation wants to be used, we # have to get the full object to check the user permissions, so # far this is a performance hit. # inline edits for Preserver and Date Preserved # if checkPermission(PreserveSample, obj): # item['required'] = ['getPreserver', 'getDatePreserved'] # item['allow_edit'] = ['getPreserver', 'getDatePreserved'] # preservers = getUsers(obj, ['Preserver', # 'LabManager', 'Manager']) # username = self.member.getUserName() # users = [({'ResultValue': u, # 'ResultText': preservers.getValue(u)}) # for u in preservers] # item['choices'] = {'getPreserver': users} # preserver = username in preservers.keys() and username or '' # item['getPreserver'] = preserver # item['getDatePreserved'] = self.ulocalized_time( # DateTime(), # long_format=1) # item['class']['getPreserver'] = 'provisional' # item['class']['getDatePreserved'] = 'provisional' # Submitting user may not verify results # Thee conditions to improve performance, some functions to check # the condition need to get the full analysis request. if states_dict.get("review_state", "") == "to_be_verified": allowed = user.has_permission(VerifyPermission, username=self.member.getUserName()) # TODO-performance: isUserAllowedToVerify getts all analysis # objects inside the analysis request. if allowed: # Gettin the full object if not get before full_object = full_object if full_object else obj.getObject() if not full_object.isUserAllowedToVerify(self.member): item["after"]["state_title"] = get_image( "submitted-by-current-user.png", title=t(_("Cannot verify: Submitted by current user"))) return item @property def copy_to_new_allowed(self): mtool = api.get_tool("portal_membership") if mtool.checkPermission(ManageAnalysisRequests, self.context) \ or mtool.checkPermission(ModifyPortalContent, self.context): return True return False def getFilterBar(self): """ This function creates an instance of BikaListingFilterBar if the class has not created one yet. :returns: a BikaListingFilterBar instance """ self._advfilterbar = self._advfilterbar if self._advfilterbar else \ AnalysisRequestsBikaListingFilterBar( context=self.context, request=self.request) return self._advfilterbar def getDefaultAddCount(self): return self.context.bika_setup.getDefaultNumberOfARsToAdd()
def _write_body(self): response = self.request.response body = ViewPageTemplateFile('templates/event_vcal.pt')(self) response.setHeader('Content-Type', 'text/vCal') response.setHeader('Content-Disposition', 'filename=cmf.vcs') response.write(body.encode("UTF-8"))
class TilesPageView(BrowserView): index = ViewPageTemplateFile("templates/tiles_page_view.pt") def __call__(self, **kwargs): return self.index()