## $Id: layout.py 12634 2015-02-27 21:56:34Z henrik $
##
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
"""Basic layout components.
"""
import os
import grok
from datetime import date, datetime
from grokcore.view import PageTemplateFile
from grokcore.formlib.formlib import Action
from cgi import escape
from zope.i18n import translate
from zope.i18nmessageid import Message
from megrok.layout import Page, Layout, Form, EditForm, DisplayForm, AddForm
from z3c.flashmessage.interfaces import IMessageSource, IMessageReceiver
from zope.component import getUtility, queryUtility, ComponentLookupError
from zope.formlib.utility import setUpWidgets
from zope.interface import Interface
from zope.site.hooks import getSite
from waeup.ikoba.interfaces import IIkobaObject, IUserAccount, IIkobaUtils
from waeup.ikoba.interfaces import MessageFactory as _
from waeup.ikoba.utils.helpers import to_timezone, format_date
from waeup.ikoba.authentication import get_principal_role_manager
from waeup.ikoba.browser.interfaces import ICustomerNavigationBase
grok.templatedir('templates')
default_waeup_display_template = PageTemplateFile(
os.path.join('templates', 'default_waeup_display_form.pt'))
default_waeup_display_template.__grok_name__ = 'default_waeup_display_form'
default_waeup_edit_template = PageTemplateFile(
os.path.join('templates', 'default_waeup_edit_form.pt'))
default_waeup_edit_template.__grok_name__ = 'default_waeup_edit_form'
default_primary_nav_template = PageTemplateFile(
os.path.join('templates', 'primarynavtab.pt'))
default_primary_nav_template.__grok_name__ = 'default_primary_nav'
default_filedisplay_template = PageTemplateFile(
os.path.join('templates', 'filedisplay.pt'))
default_filedisplay_template.__grok_name__ = 'default_filedisplay'
default_fileupload_template = PageTemplateFile(
os.path.join('templates', 'fileupload.pt'))
default_fileupload_template.__grok_name__ = 'default_fileupload'
class action(grok.action):
def __call__(self, success):
action = IkobaAction(self.label, success=success, **self.options)
self.actions.append(action)
return action
class IkobaAction(Action):
def __init__(self, label, style='', tooltip='', warning='', **options):
super(IkobaAction, self).__init__(label, **options)
self.style = style
self.tooltip = tooltip
self.warning = warning
if style == '':
self.style = 'default'
def render(self):
if not self.available():
return ''
label = self.label
if isinstance(label, Message):
label = translate(self.label, context=self.form.request)
if self.warning:
warning = translate(self.warning, context=self.form.request)
self.warning = ' onclick="return window.confirm(\'%s\')"' % warning
if self.tooltip:
tooltip = translate(self.tooltip, context=self.form.request)
self.tooltip = ' data-toggle="tooltip" title="%s"' % tooltip
if self.style:
style = ' class="btn btn-%s"' % self.style
else:
style = ' class="btn btn-default"'
html = ('')
return html
class jsaction(grok.action):
msg = _('Are you sure?')
def __call__(self, success):
action = IkobaAction(self.label,
success=success, warning=self.msg,
**self.options)
self.actions.append(action)
return action
def NullValidator(*args, **kw):
"""A validator that does not validate.
This is needed especially for cancel buttons. We don't want data
to be validated that will be thrown away in the next step.
You can use it with ``grok.action`` decorator like this::
@grok.action('Cancel', validator=NullValidator)
def cancel(self, **data):
self.redirect()
"""
return dict()
class Messages(grok.View):
"""Display messages of message receivers.
"""
grok.context(Interface)
@property
def messages(self):
receiver = getUtility(IMessageReceiver)
return receiver.receive()
class UtilityView(object):
"""A view mixin with useful methods.
The ``pnav`` attribute (a number) tells, to which primary
navigation tab a page declares to belong.
"""
title = u'' # What appears in the content title...
pnav = 0 # Primary navigation index...
def application_url(self, name=None):
"""Return the URL of the nearest site.
"""
site = getSite()
#if not site:
# raise ComponentLookupError("No site found.")
return self.url(site, name)
def flash(self, message, type='success'):
"""Send a short message to the user.
"""
cssClass = 'alert alert-%s' % type
source = queryUtility(IMessageSource, name='session')
if source is None:
return None
source.send(message, cssClass)
return True
class IkobaLayout(UtilityView,Layout):
"""A megrok.layout.Layout with additional methods.
"""
grok.baseclass()
class IkobaForm(UtilityView,Form):
"""A megrok.layout.Form with additional methods.
"""
grok.baseclass()
def setUpWidgets(self,ignore_request=False):
super(IkobaForm,self).setUpWidgets(ignore_request)
# Width parameters will be overridden by Bootstrap
# so we have to set the css class
if self.widgets.get('body'):
self.widgets['body'].height = 10
class IkobaPage(UtilityView,Page):
"""A megrok.layout page with additional methods.
"""
grok.baseclass()
class IkobaDisplayFormPage(UtilityView,DisplayForm):
"""A megrok.layout.DisplayForm with additional methods.
"""
grok.baseclass()
template = default_waeup_display_template
hide_hint = True
def large_text_field(widget):
for i in ('body', 'frontpage', 'multilingual', 'condition'):
if i in widget.name:
return True
return False
class IkobaEditFormPage(UtilityView,EditForm):
"""A megrok.layout.EditForm with additional methods.
"""
grok.baseclass()
template = default_waeup_edit_template
def setUpWidgets(self,ignore_request=False):
super(IkobaEditFormPage,self).setUpWidgets(ignore_request)
for widget in self.widgets:
if not large_text_field(widget):
widget.height = 3
class IkobaAddFormPage(UtilityView,AddForm):
"""A megrok.layout.AddForm with additional methods.
"""
grok.baseclass()
template = default_waeup_edit_template
def setUpWidgets(self,ignore_request=False):
super(IkobaAddFormPage,self).setUpWidgets(ignore_request)
for widget in self.widgets:
if not large_text_field(widget):
widget.height = 3
class SiteLayout(IkobaLayout):
""" The general site layout.
"""
grok.context(IIkobaObject)
#: An instance of the default theme to use for the site layout
stafftemp = grok.PageTemplateFile('templates/staffsitelayout.pt')
customertemp = grok.PageTemplateFile('templates/customersitelayout.pt')
@property
def site(self):
return grok.getSite()
def getAppTitle(self):
return getattr(grok.getSite()['configuration'], 'name', u'Sample Company')
def getAppAcronym(self):
return getattr(grok.getSite()['configuration'], 'acronym', u'Acronym')
def isAuthenticated(self):
"""Return True if the calling user is authenticated.
"""
usertitle = self.request.principal.title
return usertitle != 'Unauthenticated User'
def getUserTitle(self):
"""Return principal title of current user.
"""
usertitle = self.request.principal.title
if usertitle == 'Unauthenticated User':
return u'Anonymous User'
return usertitle
def getUserId(self):
"""Return id of current user.
"""
userid = self.request.principal.id
return userid
def isCustomer(self):
usertype = getattr(self.request.principal, 'user_type', None)
if not usertype:
return False
return self.request.principal.user_type == 'customer'
def getCustomerName(self):
"""Return the customer name.
"""
if ICustomerNavigationBase.providedBy(self.context):
return self.context.customer.display_fullname
def formatDatetime(self,datetimeobj):
if isinstance(datetimeobj, datetime):
tz = getUtility(IIkobaUtils).tzinfo
try:
timestamp = to_timezone(
datetimeobj, tz).strftime("%Y-%m-%d %H:%M:%S")
except ValueError:
return None
return timestamp
else:
return None
def formatDate(self,dateobj):
return format_date(dateobj, self.request)
def formatTZDate(self,datetimeobj):
if isinstance(datetimeobj, datetime):
tz = getUtility(IIkobaUtils).tzinfo
date = to_timezone(
datetimeobj, tz).strftime("%d/%m/%Y")
return date
else:
return None
def render(self):
if self.isCustomer() or not self.isAuthenticated():
return self.customertemp.render(self)
return self.stafftemp.render(self)