source: main/waeup.ikoba/branches/uli-fake-gw-provider/src/waeup/ikoba/browser/viewlets.py @ 12635

Last change on this file since 12635 was 12525, checked in by Henrik Bettermann, 10 years ago

Replace 'Portal Users' by 'Officers' because also customers are portal users.

  • Property svn:keywords set to Id
File size: 17.9 KB
Line 
1## $Id: viewlets.py 12525 2015-01-30 11:24:26Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import grok
19from urllib import urlencode
20from zope.i18n import translate
21from zope.component import getMultiAdapter, queryAdapter, getUtility
22from zope.interface import Interface
23from zope.location.interfaces import ISite
24from zope.traversing.browser import absoluteURL
25from waeup.ikoba.browser.pages import (
26    CompanyPage, DatacenterPage,
27    UsersContainerPage, UserManageFormPage)
28from waeup.ikoba.browser.interfaces import (
29    IBreadcrumbContainer, ICompany, IUsersContainer)
30from waeup.ikoba.interfaces import (
31    IIkobaUtils, IIkobaObject, IIkobaXMLExporter,
32    IIkobaXMLImporter, IDataCenter, IUserAccount)
33from waeup.ikoba.browser.layout import IkobaPage, default_primary_nav_template
34from waeup.ikoba.utils.helpers import get_user_account
35
36from waeup.ikoba.interfaces import MessageFactory as _
37
38grok.templatedir('templates')
39grok.context(IIkobaObject) # Make IIkobaObject the default context
40
41class ManageSidebar(grok.ViewletManager):
42    grok.name('left_manage')
43
44class BreadCrumbManager(grok.ViewletManager):
45    grok.name('breadcrumbs')
46
47class LanguageManager(grok.ViewletManager):
48    grok.name('languages')
49
50class ActionBar(grok.ViewletManager):
51    grok.name('actionbar')
52
53class AdministrationTasks(grok.ViewletManager):
54    grok.name('admintasks')
55
56class WidgetsSlot(grok.ViewletManager):
57    grok.name('widgets')
58
59
60#
61# Baseclasses that give some defaults for really used viewlets.
62#
63class ActionButton(grok.Viewlet):
64    """A base for action buttons.
65
66    An action button provides an icon, some text, links to a
67    target and optionally an onclick event handler.
68    If you want to set a different text, icon or target name
69    for some active button below, just override the approriate
70    attribute in the concerned viewlet.
71
72    Action buttons provide by default dynamic attributes
73
74     * ``alt``
75          An alternative text for the icon. By default the same as
76          the text.
77
78     * ``icon_url``
79          The URL of the icon.
80
81     * ``target_url``
82          The URL of the link target.
83
84     * ``onclick``
85          An onclick Javascript event handler.
86
87    """
88    grok.baseclass()
89    grok.context(IIkobaObject)
90    grok.viewletmanager(ActionBar)
91    icon = 'actionicon_modify.png' # File must exist in static/
92    target = '@@manage' # link to this viewname.
93    text = _('Edit') # Text to display on the button
94
95    # We set the template file explicitly (instead of using
96    # ``grok.template('actionbutton')``) to stick with this template
97    # also in derived classes in other packages. If we didn't, those
98    # derived ActionButton viewlets had to provide an own template,
99    # which would not be updated automatically, when the local
100    # template ``templates/actionbutton.pt`` changes.
101    #
102    # Inheriting viewlets that wish to use their own template anyway
103    # can do so by setting their local ``grok.template(<mytemplate>)``
104    # and setting ``template`` to ``None`` for the class::
105    #
106    # class DerivedActionButton(ActionButton):
107    #   ...
108    #   grok.template('overriding_template')
109    #   template = None
110    #   ...
111    #
112    template = grok.PageTemplateFile('templates/actionbutton.pt')
113
114    @property
115    def alt(self):
116        """Alternative text for icon.
117        """
118        return self.text
119
120    @property
121    def icon_url(self):
122        """Get the icon URL.
123        """
124        return '/static/img/%s' % self.icon
125
126    @property
127    def target_url(self):
128        """Get a URL to the target...
129        """
130        if self.target:
131            return self.view.url(self.view.context, self.target)
132        return
133
134    @property
135    def onclick(self):
136        """Onclick event...
137        """
138        return
139
140class PlainActionButton(ActionButton):
141    """A base for action buttons without image
142    """
143    grok.baseclass()
144    template = grok.PageTemplateFile('templates/plainactionbutton.pt')
145
146   
147class ManageActionButton(ActionButton):
148    """A base for 'edit' buttons
149    """
150    grok.baseclass()
151    grok.order(2)
152    grok.require('waeup.manageAcademics')
153    icon = 'actionicon_modify.png'
154    target = '@@manage'
155    text = _('Edit')
156
157class AddActionButton(ActionButton):
158    """A base for 'add' buttons.
159    """
160    grok.baseclass()
161    grok.order(4)
162    grok.require('waeup.manageAcademics')
163    icon = 'actionicon_add.png'
164    target = 'add'
165    text = _('Add')
166   
167class RemoveActionButton(ActionButton):
168    """A base for 'remove' buttons.
169    """
170    grok.baseclass()
171    grok.order(4)
172    grok.require('waeup.manageAcademics')
173    icon = 'actionicon_delete.png'
174    target = 'remove'
175    text = _('Remove')
176
177class SearchActionButton(ActionButton):
178    """A base for 'search' buttons.
179    """
180    grok.baseclass()
181    grok.order(5)
182    grok.require('waeup.manageAcademics')
183    icon = 'actionicon_search.png'
184    target = 'search'
185    text = _('Search')
186
187
188#
189# General viewlets (for more than one page/context)
190#
191
192class BreadCrumbs(grok.Viewlet):
193    grok.context(IIkobaObject)
194    grok.viewletmanager(BreadCrumbManager)
195    grok.order(1)
196
197    def getEntries(self):
198        result = []
199        site = grok.getSite()
200        context = self.context
201        breadcrumbs = IBreadcrumbContainer(self.view)
202        for breadcrumb in breadcrumbs:
203            if breadcrumb.target is None:
204                yield dict(
205                    title = breadcrumb.title,
206                    url = self.view.url(breadcrumb.context)
207                    )
208            elif breadcrumb.target:
209                yield dict(
210                    title = breadcrumb.title,
211                    url = self.view.url(breadcrumb.context, breadcrumb.target)
212                    )
213
214class LanguagesLink(grok.Viewlet):
215    """ The language selector itself.
216    """
217    grok.viewletmanager(LanguageManager)
218    grok.context(IIkobaObject)
219    grok.require('waeup.Public')
220    title = u'Languages'
221
222    def render(self):
223        preferred_languages = getUtility(IIkobaUtils).PREFERRED_LANGUAGES_DICT
224        html = u''
225        for key, value in sorted(
226            preferred_languages.items(), key=lambda lang: lang[1][0]):
227            args = {'lang':key, 'view_name':self.view.__name__}
228            url = self.view.url(
229                self.context) + '/@@change_language?%s' % urlencode(args)
230            html += u'| <a href="%s" title="%s">%s</a> ' % (url, value[1], key)
231        return html
232
233# Problem with circular references. Disabled for now...
234# class ExportXMLAction(grok.Viewlet):
235#    grok.viewletmanager(ActionBar)
236#     #grok.view(Index)
237#     grok.order(98)
238#     grok.require('waeup.managePortal')
239
240#class ImportXMLAction(grok.Viewlet):
241#    grok.viewletmanager(ActionBar)
242#    #grok.view(Index)
243#    grok.order(99)
244#    grok.require('waeup.managePortal')
245#
246#    def update(self):
247#        # We cannot simply replace local sites.
248#        self.can_import = not ISite.providedBy(self.context)
249
250
251class WidgetsTableRows(grok.Viewlet):
252    """The only viewlet for the WidgetsSlot viewlet manager.
253    """
254    template = grok.PageTemplateFile('templates/widgets.pt')
255    grok.viewletmanager(WidgetsSlot)
256
257
258class Login(grok.Viewlet):
259    """This viewlet allows to login in the sidebar.
260    """
261    grok.viewletmanager(ManageSidebar)
262    grok.context(IIkobaObject)
263    grok.view(Interface)
264    grok.order(2)
265    grok.require('waeup.Anonymous')
266    text = _('Login')
267    link = 'login'
268
269    def render(self):
270        if self.request.principal.id != 'zope.anybody':
271            return ''
272        url = self.view.url(grok.getSite(), self.link)
273        return u'<li"><a href="%s">%s</a></li>' % (
274                url, self.text)
275
276
277class ManageLink(grok.Viewlet):
278    """A link displayed in the upper left box.
279
280    This viewlet renders a link to the application object's settings
281    form (the 'manage' view).
282
283    In derived classes you can create different links by setting a
284    different link and text attribute. The `link` parameter is
285    understood relative to the respective application object, so that
286    ``@@manage`` will create a link to
287    ``localhost:8080/app/@@manage``.
288
289    Links defined by descendants from this viewlet are displayed on
290    every page the user is allowed to go to, if the user has also the
291    permissions set by `grok.require()`. By default only users with
292    ``waeup.managePortal`` permission will see links defined by
293    this or derivated classes.
294    """
295    grok.baseclass()
296    grok.viewletmanager(ManageSidebar)
297    grok.context(IIkobaObject)
298    grok.view(Interface)
299    grok.order(1)
300    # This link is only displayed, if the user is
301    # allowed to use it!
302    grok.require('waeup.managePortal')
303
304    link = 'relative_link'
305    text = _(u'Any link text')
306   
307    def render(self):
308        url = self.view.url(grok.getSite(), self.link)
309        text = translate(self.text, context=self.request)
310        return u'<li><a href="%s">%s</a></li>' % (
311                url, text)
312
313class ManagePortalConfiguration(ManageLink):
314    """A link to portal configuration.
315    """
316    grok.order(1)
317    grok.require('waeup.managePortalConfiguration')
318
319    link = 'configuration'
320    text = _(u'Portal Configuration')
321
322class ManageUsersLink(ManageLink):
323    """A link to users management, placed in upper left box.
324    """
325    grok.order(2)
326    grok.require('waeup.manageUsers')
327
328    link = u'users'
329    text = _(u'Officers')
330
331class ManageDataCenter(ManageLink):
332    """A link to datacenter, placed in upper left box.
333    """
334    grok.order(3)
335    grok.require('waeup.manageDataCenter')
336
337    link = u'datacenter'
338    text = _(u'Data Center')
339
340class ManageReports(ManageLink):
341    """A link to reports, placed in upper left box.
342    """
343    grok.order(4)
344    grok.require('waeup.manageReports')
345
346    link = u'reports'
347    text = _(u'Reports')
348
349class MyPreferences(ManageLink):
350    """A link to personal preferences, placed in upper left box.
351    """
352    grok.order(6)
353    grok.require('waeup.Public')
354    text = _(u'My Preferences')
355
356    def render(self):
357        account_object = get_user_account(self.request)
358        if account_object:
359            url = self.view.url(account_object)
360            text = translate(self.text, context=self.request)
361            return u'<li><a href="%s">%s</a></li>' % (
362                    url, text)
363        return ''
364
365class MyRoles(ManageLink):
366    """A link to display site and local roles.
367    """
368    grok.order(7)
369    grok.require('waeup.Public')
370    text = _(u'My Roles')
371
372    def render(self):
373        account_object = get_user_account(self.request)
374        if account_object:
375            url = self.view.url(account_object) + '/my_roles'
376            text = translate(self.text, context=self.request)
377            return u'<li><a href="%s">%s</a></li>' % (
378                    url, text)
379        return ''
380
381class ContactActionButton(ManageActionButton):
382    grok.order(4)
383    grok.context(IUserAccount)
384    grok.view(UserManageFormPage)
385    grok.require('waeup.manageUsers')
386    icon = 'actionicon_mail.png'
387    text = _('Send email')
388    target = 'contactuser'
389
390class ManageDataCenterActionButton(ManageActionButton):
391    """ 'Edit settings' button for datacenter.
392    """
393    grok.context(IDataCenter)
394    grok.view(DatacenterPage)
395    grok.require('waeup.managePortal')
396    text = _('Edit settings')
397    grok.order(1)
398
399class AddUserActionButton(AddActionButton):
400    grok.require('waeup.manageUsers')
401    grok.context(IUsersContainer)
402    grok.view(UsersContainerPage)
403    text = _('Add user')
404
405class BrowseDatacenterLogs(ActionButton):
406    grok.context(IDataCenter)
407    grok.require('waeup.manageDataCenter')
408    grok.view(DatacenterPage)
409    grok.order(2)
410    icon = 'actionicon_info.png'
411    target = '@@logs'
412    text = _('Show logs')
413
414class UploadCSVButton(ActionButton):
415    grok.context(IDataCenter)
416    grok.view(DatacenterPage)
417    grok.require('waeup.manageDataCenter')
418    grok.order(3)
419    icon = 'actionicon_up.png'
420    target = '@@upload'
421    text = _('Upload data')
422
423class BatchOpButton(ActionButton):
424    grok.context(IDataCenter)
425    grok.view(DatacenterPage)
426    grok.require('waeup.manageDataCenter')
427    grok.order(4)
428    icon = 'actionicon_gear.png'
429    target = '@@import1'
430    text = _('Process data')
431
432class ExportCSVButton(ActionButton):
433    grok.context(IDataCenter)
434    grok.view(DatacenterPage)
435    grok.require('waeup.exportData')
436    grok.order(5)
437    icon = 'actionicon_down.png'
438    target = '@@export'
439    text = _('Export data')
440
441class BrowseFinishedFiles(ActionButton):
442    grok.context(IDataCenter)
443    grok.require('waeup.manageDataCenter')
444    grok.view(DatacenterPage)
445    grok.order(6)
446    icon = 'actionicon_finished.png'
447    target = '@@processed'
448    text = _('View processed files')
449
450#
451# Primary navigation tabs (in upper left navigation bar)...
452#
453class PrimaryNavManager(grok.ViewletManager):
454    """Viewlet manager for the primary navigation tab.
455    """
456    grok.name('primary_nav')
457
458class PrimaryNavTab(grok.Viewlet):
459    """Base for primary nav tabs.
460    """
461    grok.baseclass()
462    grok.viewletmanager(PrimaryNavManager)
463    grok.order(1)
464    grok.require('waeup.Public')
465    template = default_primary_nav_template
466
467    pnav = 0 # This is a kind of id of a tab. If some page provides
468             # also a 'pnav' attribute with the same value (here: 0),
469             # then the tab will be rendered as 'active' when the page
470             # gets rendered.
471             #
472             # This way you can assign certain pages to certain
473             # primary nav tabs. Each primary tab should therefore set
474             # the 'pnav' attribute to a different value (or several
475             # tabs might be rendered as active simultanously when the
476             # page gets rendered.
477    tab_title = u'Some Text'
478   
479    @property
480    def link_target(self):
481        return self.view.application_url()
482
483    @property
484    def active(self):
485        view_pnav = getattr(self.view, 'pnav', 0)
486        if view_pnav == self.pnav:
487            return 'active'
488        return ''
489
490#class HomeTab(PrimaryNavTab):
491#    """Home-tab in primary navigation.
492#    """
493#    grok.order(1)
494#    grok.require('waeup.Public')
495
496#    pnav = 0
497#    tab_title = u'Home'
498
499
500class EnquiriesTab(PrimaryNavTab):
501    """Contact tab in primary navigation.
502
503    Display tab only for anonymous. Authenticated users can call a
504    contact form from the user navigation bar.
505    """
506    grok.order(6)
507    grok.require('waeup.Anonymous')
508    tab_title = _(u'Enquiries')
509    pnav = 2
510
511    # Also zope.manager has role Anonymous.
512    # To avoid displaying this tab, we have to check the principal id too.
513    @property
514    def link_target(self):
515        if self.request.principal.id == 'zope.anybody':
516            return self.view.application_url('enquiries')
517        return
518
519#
520# Administration tasks
521#
522class AdminTask(grok.Viewlet):
523    """The base for task entries on administration page.
524    """
525    grok.baseclass()
526    grok.order(1)
527    grok.viewletmanager(AdministrationTasks)
528    grok.require('waeup.managePortal')
529    grok.template('admintask')
530
531    link_title = 'Manage users' # How the link to the target will be titled.
532    target_viewname = 'users'   # The name of the target view.
533   
534    @property
535    def link_target(self):
536        return self.view.url(self.context[self.target_viewname])
537
538class AdminTaskPortalConfiguration(AdminTask):
539    """Entry on administration page that link to portal settings.
540    """
541    grok.order(1)
542    grok.require('waeup.managePortalConfiguration')
543
544    link_title = _('Portal Configuration')
545    def link_target(self):
546        return self.view.url(self.view.context, 'configuration')
547
548class AdminTaskUsers(AdminTask):
549    """Entry on administration page that link to user folder.
550    """
551    grok.order(2)
552    grok.require('waeup.manageUsers')
553
554    link_title = _('Officers')
555    target_viewname = 'users'
556   
557class AdminTaskDatacenter(AdminTask):
558    """Entry on administration page that link to datacenter.
559    """
560    grok.order(3)
561    grok.require('waeup.manageDataCenter')
562
563    link_title = _('Data Center')
564    target_viewname = 'datacenter'
565
566class AdminTaskReports(AdminTask):
567    """Entry on administration page that link to datacenter.
568    """
569    grok.order(3)
570    grok.require('waeup.manageReports')
571
572    link_title = _('Reports')
573    target_viewname = 'reports'
574
575# The SubobjectLister and its viewlets below are not used in Ikoba.
576
577class SubobjectLister(grok.ViewletManager):
578    """Very special viewlet manager that displays lists of subobjects.
579    """
580    grok.name('subobjectlist')
581    grok.template('subobjectlist')
582
583    def update(self):
584        # The default implementation of update() sets self.viewlets to
585        # a list of viewlets for the current context
586        # (self.context). We make use of that fact by retrieving all
587        # viewlets for all items in our context container by simply
588        # setting these items as context while we call the default
589        # update() method. So we get a list of lists of viewlets for
590        # each item in a 'row' (where a single item is a row).
591        rows = []
592        orig_context = self.context
593        for name, value in self.context.items():
594            # Retrieve all viewlets for the current item (not the context)
595            self.context = value
596            super(SubobjectLister, self).update() # sets self.viewlets
597            rows.append(self.viewlets)
598            self.context = orig_context
599        self.rows = rows
600        # Finally, set the viewlets we would retrieve normally...
601        super(SubobjectLister, self).update()
602        return
Note: See TracBrowser for help on using the repository browser.