Ejemplo n.º 1
0
def index():
    tax = db.product.price * 5 / 100
    tax.represent = db.product.price.represent
    pretax_price = db.product.price + tax
    pretax_price.represent = db.product.price.represent

    request_headers = request.vars.headers or 'default'
    request_columns = request.vars.columns or 'default'

    ################################ The core ######################################
    # A custom orderby selector for the solidtable.
    orderby_selector = OrderbySelector([
        db.product.id, db.product.name, ~db.product.publish_start_date,
        ~pretax_price
    ])

    rows = db().select(db.product.ALL,
                       tax,
                       pretax_price,
                       orderby=orderby_selector.orderby())

    if request_headers == 'default':
        # The "headers" is a dictionary of dictionaries for updating default values.
        # Custom fields such as "tax" can be passed to the dictionary keys.
        headers = {
            'product.name': {
                'selected': True
            },
            'product.description': {
                'label': 'Details',
                'class': 'italic',
                'width': '200px',
                'truncate': 38,
            },
            tax: {
                'label': 'Tax'
            },
            pretax_price: {
                'label': 'Pretax Price'
            }
        }
    else:
        # The "headers" can be 'labels' or 'fieldname:capitalize'
        headers = request_headers

    extracolumns = [
        {
            'label': A('Edit', _href='#'),
            'content':
            lambda row, rc: A('Edit', _href='edit/%s' % row.product.id)
        },
        {
            'label':
            A('Delete', _href='#'),
            'content':
            lambda row, rc: A('Delete', _href='delete/%s' % row.product.id)
        },
    ]

    # The structure of "columns" defines the multi-line table layout
    # A "None" indicates an empty line over which the precedent line spans
    # Custom fields such as "tax" and extracolumns can be passed to the list of lists.
    if request_columns == 'default':
        columns = [
            [db.product.name, extracolumns[0]],
            'product.id',
            ['product.status', 'product.publish_start_date'],
            [None, 'product.publish_end_date'],
            [pretax_price, 'product.description'],
            [tax, None],
            ['product.price', None],
        ]
    elif request_columns == 'columns_2':
        columns = [
            [db.product.name, extracolumns[0]],
            None,
            [pretax_price, 'product.description'],
            None,
            [tax, None],
        ]
    elif request_columns == 'columns_3':
        columns = [
            [db.product.name, extracolumns[0]],
            [None, 'product.description'],
            [None, tax],
        ]

    table = SOLIDTABLE(rows,
                       columns=columns,
                       extracolumns=extracolumns,
                       headers=headers,
                       orderby=orderby_selector,
                       renderstyle=True,
                       linkto=URL('show'),
                       selectid=lambda r: r.product.id == 7)
    ################################################################################

    return dict(table=DIV(table, STYLE('.italic {font-style: italic;}')),
                table_args=DIV(
                    A('headers=default',
                      _href=URL(vars={'headers': 'default'})),
                    ' ',
                    A('headers=labels', _href=URL(vars={'headers': 'labels'})),
                    ' ',
                    A('headers=fieldname:capitalize',
                      _href=URL(vars={'headers': 'fieldname:capitalize'})),
                    ' ',
                    A('columns=default',
                      _href=URL(vars={'columns': 'default'})),
                    ' ',
                    A('columns=columns_2',
                      _href=URL(vars={'columns': 'columns_2'})),
                    ' ',
                    A('columns=columns_3',
                      _href=URL(vars={'columns': 'columns_3'})),
                    ' ',
                ))
Ejemplo n.º 2
0
    def __call__(
            self,
            query,
            fields=None,
            field_id=None,
            left=None,
            headers={},
            columns=None,
            orderby=None,  # EXTENDED for permutation
            searchable=True,  # EXTENDED ex) [table.id, table.name, ...]
            sortable=True,  # EXTENDED ex) [table.id, table.name, ...]
            paginate=(10, 25, 50, 100),  # EXTENDED
            deletable=True,
            editable=True,  # EXTENDED ex) [['id', 'name'], 'profile', ...]
            details=True,  # EXTENDED ex) [['id', 'name'], 'profile', ...]
            selectable=None,  # TODO 
            create=True,  # EXTENDED ex) [['id', 'name'], 'profile', ...]
            csv=True,
            links=None,
            upload='<default>',
            args=[],
            user_signature=True,
            maxtextlengths={},  # NOT WORK
            maxtextlength=20,
            onvalidation=None,
            oncreate=None,
            onupdate=None,
            ondelete=None,
            sorter_icons=('[^]', '[v]'),  # NOT WORK
            ui='ui',  # ONLY WORK FOR "ui"
            showbuttontext=True,
            _class="web2py_grid",
            formname='web2py_grid',
            search_widget='default',  # NOT WORK
            extracolumns=None,  # CUSTOM (same as in SQLTABLE)
            search_queries={},  # CUSTOM
            showid=True,  # CUSTOM
            onpermute=None,  # CUSTOM
            virtualtable=None,  # CUSTOM
            virtualrecord=None,  # CUSTOM
            virtualset=None,  # CUSTOM
            hmac_key=None,  # CUSTOM
            scope=None,  #CUSTOM
            scope_default=None,  #CUSTOM
            groupby=None,  #CUSTOM
    ):

        from gluon.dal import SQLALL
        from plugin_solidform import SOLIDFORM
        from plugin_solidtable import SOLIDTABLE, OrderbySelector
        from plugin_paginator import Paginator, PaginateSelector, PaginateInfo
        gridbutton = self.gridbutton
        recordbutton = self.recordbutton

        request, session, T = current.request, current.session, current.T

        def __oncreate(form):
            session.flash = T('Created')

        def __onupdate(form):
            session.flash = T('Updated')

        def __ondelete(table, tablename, ret):
            session.flash = T('Deleted')

        def __onpermute(table, tablename, ret):
            session.flash = T('Permuted')

        def redirect_patch():
            onupdate

        oncreate = oncreate or __oncreate
        onupdate = onupdate or __onupdate
        ondelete = ondelete or __ondelete
        onpermute = onpermute or __onpermute

        if ui == 'ui':
            ui = dict(
                widget='',
                header='',
                content='',
                default='',
                cornerall='',
                cornertop='',
                cornerbottom='',
                button='',
                buttontext='',
                buttonadd='ui-icon-plusthick',
                buttonback='ui-icon-arrowreturnthick-1-w',
                buttonexport='',
                buttondelete='ui-icon-close',
                buttonedit='ui-icon-pencil',
                buttontable='',
                buttonview='ui-icon-zoomin',
            )
        elif not isinstance(ui, dict):
            raise RuntimeError, 'SQLFORM.grid ui argument must be a dictionary'

        wenabled = (not user_signature or (session.auth and session.auth.user))
        deletable = wenabled and deletable
        # if search_widget=='default':
        # search_widget = SQLFORM.search_menu

        url = self.url_factory(args, user_signature, hmac_key)

        db = query._db
        dbset = db(query)
        tables = [
            db[tablename] for tablename in db._adapter.tables(dbset.query)
        ]
        if not fields:
            fields = reduce(lambda a, b: a + b,
                            [[field for field in table] for table in tables])

        new_fields = []
        for item in fields:
            if isinstance(item, SQLALL):
                new_fields += item.table
            else:
                new_fields.append(item)
        fields = new_fields

        main_table = tables[0]
        if not field_id:
            field_id = main_table._id

        table = field_id.table
        tablename = table._tablename
        referrer = session.get('_web2py_grid_referrer_' + formname, url())

        def __from_process_redirect_patch(func):
            def wrapper(form):
                func(form)
                redirect(referrer)

            return wrapper

        oncreate = __from_process_redirect_patch(oncreate)
        onupdate = __from_process_redirect_patch(onupdate)

        def check_authorization():
            if user_signature or hmac_key:
                if not URL.verify(request,
                                  user_signature=user_signature,
                                  hmac_key=hmac_key):
                    session.flash = T('not authorized')
                    redirect(referrer)

        if upload == '<default>':
            upload = lambda filename: url(args=['download', filename])
            if len(request.args) > 1 and request.args[-2] == 'download':
                check_authorization()
                stream = response.download(request, db)
                raise HTTP(200, stream, **response.headers)

        gridbuttons = [gridbutton('%(buttonback)s' % ui, T('Back'), referrer)]

        if create and len(request.args) > 1 and request.args[-2] == 'new':
            check_authorization()
            table = db[request.args[-1]]
            self.mark_not_empty(virtualtable or table)
            if orderby:
                inverted = (orderby.op == orderby.db._adapter.INVERT)
                field = orderby.first if inverted else orderby
                last = dbset.select(
                    field_id,
                    field,
                    limitby=(0, 1),
                    orderby=orderby.first if inverted else ~orderby).first()
                last_value = (last[field] or 0) if last else 0
                table[field.name].default = (-1
                                             if inverted else 1) + last_value

            create_form = SOLIDFORM(
                virtualtable or table,
                fields=create if type(create) in (list, tuple) else None,
                showid=showid,
                _class='web2py_form',
                submit_button=T('Create'),
            ).process(  # next=referrer, for web2py-bug
                onvalidation=onvalidation,
                onsuccess=oncreate,
                formname=formname)
            self.unmark_not_empty(table)
            res = DIV(create_form, _class=_class)
            res.create_form = create_form
            res.gridbuttons = gridbuttons
            return res

        elif details and len(request.args) > 2 and request.args[-3] == 'view':
            check_authorization()
            table = db[request.args[-2]]
            record = table(request.args[-1]) or redirect(URL('error'))
            form = SOLIDFORM(virtualtable or table,
                             virtualrecord or record,
                             fields=details if type(details) in (list, tuple)
                             else create if type(create) in (list,
                                                             tuple) else None,
                             upload=upload,
                             readonly=True,
                             showid=showid,
                             _class='web2py_form')
            res = DIV(form, _class=_class)
            res.record = record  # CUSTOM
            res.view_form = form  # CUSTOM
            if editable:
                gridbuttons.append(
                    gridbutton('%(buttonedit)s' % ui, T('Edit'),
                               url(args=['edit', tablename, record.id])))
            res.gridbuttons = gridbuttons
            return res

        elif editable and len(request.args) > 2 and request.args[-3] == 'edit':
            check_authorization()
            table = db[request.args[-2]]
            record = table(request.args[-1]) or redirect(URL('error'))
            self.mark_not_empty(virtualtable or table)
            edit_form = SOLIDFORM(
                virtualtable or table,
                virtualrecord or record,
                fields=editable if type(editable) in (list, tuple) else
                create if type(create) in (list, tuple) else None,
                upload=upload,
                deletable=deletable,
                showid=showid,
                delete_label=T('Check to delete:'),
                submit_button=T('Update'),
                _class='web2py_form')
            self.unmark_not_empty(table)
            edit_form.process(
                formname=formname,
                onvalidation=onvalidation,
                onsuccess=onupdate,
                # #next=referrer, for web2py-bug
            )
            res = DIV(edit_form, _class=_class)
            res.record = record  # CUSTOM
            res.edit_form = edit_form
            if details:
                gridbuttons.append(
                    gridbutton('%(buttonview)s' % ui, T('View'),
                               url(args=['view', tablename, record.id])))
            res.gridbuttons = gridbuttons
            return res

        elif deletable and len(
                request.args) > 2 and request.args[-3] == 'delete':
            check_authorization()
            table = db[request.args[-2]]
            ret = db(table.id == request.args[-1]).delete()
            if ondelete:
                ondelete(table, request.args[-1], ret)
            redirect(url())

        elif csv and len(request.args) > 0 and request.args[-1] == 'csv':
            check_authorization()
            return dict()

        elif request.vars.records and not isinstance(request.vars.records,
                                                     list):
            request.vars.records = [request.vars.records]

        elif not request.vars.records:
            request.vars.records = []

        session['_web2py_grid_referrer_' + formname] = URL(
            r=request,
            args=request.args,
            vars=request.vars,
            user_signature=user_signature,
            hmac_key=hmac_key)

        error = None
        search_form = None
        table_el_id = formname + '_maintable'

        columns = columns or [
            str(f) for f in fields if f.table == main_table and f.readable and
            (showid or f.type != 'id')
        ]

        if searchable:
            field_sep = '___'

            if searchable is True:
                _exclude_types = ('upload',
                                  'text') if showid else ('id', 'upload',
                                                          'text')
                searchable = [
                    f for f in fields if f.table == main_table
                    and f.type not in _exclude_types and f.readable
                ]

            _search_fields = []
            _from_tos = []
            for f in searchable:
                _requires = []
                if f.requires and type(f.requires) not in (list, tuple):
                    if isinstance(f.requires, IS_EMPTY_OR):
                        _requires = [f.requires.other]
                    else:
                        _requires = [f.requires]
                _requires = [
                    r for r in _requires if not isinstance(r, IS_NOT_IN_DB)
                ]
                if _requires:
                    if len(_requires) == 1:
                        _requires = _requires[0]
                    _requires = IS_EMPTY_OR(_requires)
                else:
                    _requires = None

                _type = 'string' if f.type == 'text' else 'integer' if f.type == 'id' else f.type

                if (f.type in ('double', 'decimal', 'date', 'datetime')
                        or (f.type == 'integer' and _requires
                            and isinstance(_requires.other,
                                           (IS_INT_IN_RANGE)))):
                    _from_to = [
                        Field(str(f).replace('.', field_sep) + field_sep +
                              'from',
                              type=_type,
                              requires=_requires,
                              label=f.label,
                              widget=f.widget),
                        Field(str(f).replace('.', field_sep) + field_sep +
                              'to',
                              type=_type,
                              requires=_requires,
                              label=f.label,
                              widget=f.widget)
                    ]
                    _from_tos.append(_from_to)
                    _search_fields += _from_to
                elif hasattr(f, 'table'):
                    _search_fields.append(
                        Field(str(f).replace('.', field_sep),
                              type=_type,
                              requires=_requires,
                              label=f.label,
                              widget=f.widget))
                else:
                    _search_fields.append(f)

            search_form = SQLFORM.factory(formstyle='divs',
                                          submit_button=T('Search'),
                                          _class='search_form',
                                          *_search_fields)

            for _from_to in _from_tos:
                self.inline(search_form,
                            'no_table', [f.name for f in _from_to],
                            LABEL(_from_to[0].label), SPAN(' - '))

            subquery = self.build_query_by_form(db,
                                                search_form,
                                                queries=search_queries,
                                                field_sep=field_sep,
                                                formname='search_%s' %
                                                formname)
        else:
            subquery = None

        if subquery:
            dbset = dbset(subquery)

        if scope:
            from plugin_tablescope import TableScope
            scope_el = TableScope(dbset, scope, default=scope_default)
            dbset = scope_el.scoped_dataset

        if sortable is True:
            sortable = [
                ~f if f.type in ('id', 'date', 'datetime') else f
                for f in fields
                if f.table == main_table and f.type not in ('text', 'upload')
            ]
        if not sortable:
            sortable = []
        if orderby:
            sortable.insert(0, orderby)

        orderby_selector = OrderbySelector(sortable)

        current_orderby = orderby_selector.orderby()
        permutable = (orderby and (not subquery) and sortable
                      and current_orderby is sortable[0])

        extracolumns = extracolumns or []

        if permutable:
            if len(request.args) > 2 and request.args[-3] in ('up', 'down'):
                check_authorization()
                table = db[request.args[-2]]
                record = table(request.args[-1]) or redirect(URL('error'))
                inverted = (orderby.op == orderby.db._adapter.INVERT)
                field = orderby.first if inverted else orderby

                current_value = record[field]
                if current_value is None:
                    first = dbset.select(field_id,
                                         limitby=(0, 1),
                                         orderby=orderby).first()
                    current_value = (1 if inverted else -1) + (first.id
                                                               if first else 0)

                if (request.args[-3] == ('down' if inverted else 'up')):
                    target = dbset(field < current_value).select(
                        field_id,
                        field,
                        limitby=(0, 1),
                        orderby=orderby if inverted else ~orderby).first()
                elif (request.args[-3] == ('up' if inverted else 'down')):
                    target = dbset(field > current_value).select(
                        field_id,
                        field,
                        limitby=(0, 1),
                        orderby=orderby.first
                        if inverted else orderby).first()
                else:
                    raise NotImplementedError
                if not target:
                    last = dbset.select(field_id,
                                        limitby=(0, 1),
                                        orderby=orderby.first if orderby.first
                                        else ~orderby).first()
                    target_value = (-1 if inverted else 1) + (last.id
                                                              if last else 0)
                else:
                    target_value = target[field]

                db(table.id == record[field_id]).update(
                    **{field.name: target_value})
                if target:
                    db(table.id == target[field_id]).update(
                        **{field.name: current_value})

                if onpermute:
                    onpermute(table, request.args[-2], (record, target))
                redirect(url())

            first = dbset.select(field_id, limitby=(0, 1),
                                 orderby=orderby).first()
            first_id = first.id if first else 0
            last = dbset.select(
                field_id,
                limitby=(0, 1),
                orderby=orderby.first if orderby.first else ~orderby).first()
            last_id = last.id if last else 0
            extracolumns.append({
                'label':
                DIV(T('Move'), _style='text-align:center;'),
                'width':
                '150px' if showbuttontext else '65px',
                'content':
                lambda row, rc: DIV(
                    recordbutton('ui-icon-triangle-1-n', T('Up'),
                                 url(args=['up', tablename, row[field_id]]),
                                 showbuttontext)
                    if row[field_id] != first_id else '',
                    recordbutton('ui-icon-triangle-1-s', T('Down'),
                                 url(args=['down', tablename, row[field_id]]),
                                 showbuttontext)
                    if row[field_id] != last_id else '',
                    _style='text-align:center;')
            })

        _size = 80 if showbuttontext else 25
        _size = _size * (int(bool(details)) + int(bool(editable)) +
                         int(bool(deletable)))
        if _size:

            extracolumns.append({
                'label':
                '',
                'width':
                '%spx' % (_size + 12),
                'content':
                lambda row, rc: DIV(
                    recordbutton('%(buttonview)s' % ui, T('View'),
                                 url(args=['view', tablename, row[field_id]]),
                                 showbuttontext) if details else '',
                    recordbutton('%(buttonedit)s' % ui, T('Edit'),
                                 url(args=['edit', tablename, row[field_id]]),
                                 showbuttontext) if editable else '',
                    recordbutton(
                        '%(buttondelete)s' % ui,
                        T('Delete'),
                        url(args=['delete', tablename, row[field_id]]),
                        showbuttontext,
                        _onclick="""
if(confirm("%s")){return true;} else {jQuery(this).unbind('click').fadeOut();return false;}"""
                        % T('Sure you want to delete them?'),
                    ) if deletable else '')
            })

        if paginate:
            paginate_selector = PaginateSelector(paginate if type(paginate) in
                                                 (list, tuple) else [paginate])
            current_paginate = paginate_selector.paginate
            paginator = Paginator(paginate=current_paginate)
            # TODO for groupby
            paginator.records = virtualset(
                dbset.query).count() if virtualset else dbset.count()
            paginate_info = PaginateInfo(paginator.page, paginator.paginate,
                                         paginator.records)
            limitby = paginator.limitby()
        else:
            limitby = None
            current_paginate = None

        # TODO
        # if paginator.records == 0:
        # error = 'Not Found'
        if virtualset:
            records = virtualset(dbset.query).select(left=left,
                                                     limitby=limitby,
                                                     orderby=current_orderby,
                                                     groupby=groupby,
                                                     *fields)
            records.db = virtualtable._db
        else:
            records = dbset.select(left=left,
                                   limitby=limitby,
                                   orderby=current_orderby,
                                   groupby=groupby,
                                   *fields)

        table = SOLIDTABLE(
            records,
            columns=columns,
            headers=headers,
            orderby=orderby_selector,
            truncate=maxtextlength,  #TODO replace
            extracolumns=extracolumns,
            upload=upload)
        table.attributes['_class'] = 'solidtable'
        table.attributes['_id'] = table_el_id

        inner = []
        if scope:
            inner.append(scope_el)
        if current_paginate:
            inner.append(DIV(paginate_info, _class='pagination_information'))
        inner.append(table)
        if current_paginate and paginator.records > current_paginate:
            inner.append(
                DIV(paginate_selector, paginator, _class='index_footer'))

        res = DIV(_class=_class, *inner)

        res.records = records
        res.search_form = search_form
        res.error = error
        res.gridbuttons = []
        if create:
            res.gridbuttons.append(
                gridbutton('%(buttonadd)s' % ui, T('Add'),
                           url(args=['new', tablename])))

        return res
Ejemplo n.º 3
0
    def __call__(self, 
                query,
                fields=None,
                field_id=None,
                left=None,
                headers={},
                columns=None,
                orderby=None, # EXTENDED for permutation
                searchable=True, # EXTENDED ex) [table.id, table.name, ...]
                sortable=True, # EXTENDED ex) [table.id, table.name, ...]
                paginate=(10, 25, 50, 100), # EXTENDED
                
                deletable=True, # EXTENDED ex) lambda record_id: deleted
                editable=True,# EXTENDED ex) [['id', 'name'], 'profile', ...] or lambda record: edit_form
                details=True,# EXTENDED ex) [['id', 'name'], 'profile', ...] or lambda record: view_form
                selectable=None, # TODO 
                create=True, # EXTENDED ex) [['id', 'name'], 'profile', ...] or lambda: create_form
                csv=True,
                
                links=None,
                links_in_grid=True,
             
                upload = '<default>',
                args=[],
                user_signature = True,
                maxtextlengths={}, # NOT WORK
                maxtextlength=20,
                onvalidation=None,
                oncreate=None,
                onupdate=None, 
                ondelete=None,
                sorter_icons=('[^]','[v]'), # NOT WORK
                ui='ui', # ONLY WORK FOR "ui"
                showbuttontext=True,
                _class="web2py_grid",             
                formname='web2py_grid',
                search_widget='default', # NOT WORK
                extracolumns=None, # CUSTOM (same as in SQLTABLE)
                search_queries={}, # CUSTOM
                showid=True, # CUSTOM
                onpermute=None, # CUSTOM
                virtualtable=None, # CUSTOM
                virtualrecord=None, # CUSTOM
                virtualset=None, # CUSTOM
                hmac_key=None, # CUSTOM
                scope=None, #CUSTOM
                scope_default=None, #CUSTOM
                groupby=None, #CUSTOM
                ):
            
        from gluon.dal import SQLALL
        from plugin_solidform import SOLIDFORM
        from plugin_solidtable import SOLIDTABLE, OrderbySelector
        from plugin_paginator import Paginator, PaginateSelector, PaginateInfo
        gridbutton = self.settings.gridbutton
        recordbutton = self.settings.recordbutton
        
        request, session, T = current.request, current.session, current.T
        
        def __oncreate(form):
            session.flash = T('Created')
        def __onupdate(form):
            session.flash = T('Updated')
        def __ondelete(table, tablename, ret):
            session.flash = T('Deleted')
        def __onpermute(table, tablename, ret):
            session.flash = T('Permuted')
        def redirect_patch():
            onupdate
            
        oncreate = oncreate or __oncreate
        onupdate = onupdate or __onupdate
        ondelete = ondelete or __ondelete
        onpermute = onpermute or __onpermute
        
        if ui == 'ui':
            ui = dict(widget='',                      
                      header='',
                      content='',
                      default='',
                      cornerall='',
                      cornertop='',
                      cornerbottom='',
                      button='',
                      buttontext='',
                      buttonadd='ui-icon-plusthick',
                      buttonback='ui-icon-arrowreturnthick-1-w',
                      buttonexport='',
                      buttondelete='ui-icon-close',
                      buttonedit='ui-icon-pencil',
                      buttontable='',
                      buttonview='ui-icon-zoomin',
                      )
        elif not isinstance(ui,dict):
            raise RuntimeError,'SQLFORM.grid ui argument must be a dictionary'
            
        wenabled = (not user_signature or (session.auth and session.auth.user))
        deletable = wenabled and deletable
        # if search_widget=='default':
            # search_widget = SQLFORM.search_menu
            
        url = self.url_factory(args, user_signature, hmac_key)
        
        db = query._db 
        dbset = db(query)
        tables = [db[tablename] for tablename in db._adapter.tables(dbset.query)]
        if not fields:
            fields = reduce(lambda a,b:a+b,
                            [[field for field in table] for table in tables])
        
        new_fields = []
        for item in fields:
            if isinstance(item,SQLALL):
                new_fields += item.table
            else:
                new_fields.append(item)
        fields = new_fields
        
        main_table = tables[0]
        if not field_id:
            field_id = main_table._id
        
        table = field_id.table
        tablename = table._tablename
        referrer = session.get('_web2py_grid_referrer_'+formname, url())
        
        def __from_process_redirect_patch(func):
            def wrapper(form):
                func(form)
                redirect(referrer)
            return wrapper
        oncreate = __from_process_redirect_patch(oncreate)
        onupdate = __from_process_redirect_patch(onupdate)
            
        def check_authorization():
            if user_signature or hmac_key:
                if not URL.verify(request,user_signature=user_signature, hmac_key=hmac_key):
                    session.flash = T('not authorized')
                    redirect(referrer)

        if upload=='<default>':
            upload = lambda filename: url(args=['download',filename])
            if len(request.args)>1 and request.args[-2]=='download':
                check_authorization()
                stream = response.download(request,db)
                raise HTTP(200,stream,**response.headers)
        
        gridbuttons = [gridbutton('%(buttonback)s' % ui, T('Back'), referrer)]
        def _add_link_gridbuttons(record):
            if record and links:
                for link in links:
                    if isinstance(link,dict):
                         gridbuttons.append(link['body'](record))
                    elif link(record):
                         gridbuttons.append(link(record))
                     
        
        if create and len(request.args)>1 and request.args[-2]=='new':
            check_authorization()
            table = db[request.args[-1]]
            if orderby:
                inverted = (orderby.op == orderby.db._adapter.INVERT)
                field = orderby.first if inverted else orderby
                last = dbset.select(field_id, field, limitby=(0,1), orderby=orderby.first if inverted else ~orderby).first()
                last_value = (last[field] or 0) if last else 0
                table[field.name].default = (-1 if inverted else 1) + last_value
                 
            self.mark_not_empty(virtualtable or table)
            
            if type(create) == type(lambda:None):
                create_form = create()
            else:
                create_form = SOLIDFORM(virtualtable or table, 
                        fields=create if type(create) in (list, tuple) else None,
                        showid=showid,
                        _class='web2py_form',
                        submit_button=T('Create'),
                        ).process(# next=referrer, for web2py-bug
                                  onvalidation=onvalidation,
                                  onsuccess=oncreate,                          
                                  formname=formname)
            
            self.unmark_not_empty(table)
            res = DIV(create_form, _class=_class)
            res.create_form = create_form
            res.gridbuttons = gridbuttons
            return res
            
        elif details and len(request.args)>2 and request.args[-3]=='view':
            check_authorization()
            table = db[request.args[-2]]
            record = table(request.args[-1]) or redirect(URL('error'))
            
            if type(details) == type(lambda:None):
                view_form = details(record)
            else:
                view_form = SOLIDFORM(virtualtable or table, virtualrecord or record, 
                                 fields=details if type(details) in (list, tuple) else
                                            create if type(create) in (list, tuple) else None, 
                                 upload=upload,
                                 readonly=True,
                                 showid=showid,
                                 _class='web2py_form')
            res = DIV(view_form, _class=_class)
            res.record = record # CUSTOM
            res.view_form = view_form # CUSTOM
            if editable:
                gridbuttons.append(
                    gridbutton('%(buttonedit)s' % ui, T('Edit'), 
                                  url(args=['edit', tablename, record.id]))
                )
            _add_link_gridbuttons(record)
            res.gridbuttons = gridbuttons
            return res
            
        elif editable and len(request.args)>2 and request.args[-3]=='edit':
            check_authorization()
            table = db[request.args[-2]]
            record = table(request.args[-1]) or redirect(URL('error'))
            self.mark_not_empty(virtualtable or table)
            
            if type(editable) == type(lambda:None):
                edit_form = editable(record)
            else:
                edit_form = SOLIDFORM(virtualtable or table, virtualrecord or record,
                                fields=editable if type(editable) in (list, tuple) else
                                            create if type(create) in (list, tuple) else None, 
                                upload=upload,
                                deletable=deletable is True,
                                showid=showid,
                                delete_label=T('Check to delete:'),
                                submit_button=T('Update'),
                                _class='web2py_form').process(
                                    formname=formname,
                                    onvalidation=onvalidation,
                                    onsuccess=onupdate,
                                    # #next=referrer, for web2py-bug
                                    )
            
            self.unmark_not_empty(table)
                
            res = DIV(edit_form,_class=_class)
            res.record = record # CUSTOM
            res.edit_form = edit_form
            if details:
                gridbuttons.append(
                    gridbutton('%(buttonview)s' % ui, T('View'), 
                                  url(args=['view', tablename, record.id]))
                )
            _add_link_gridbuttons(record)
            res.gridbuttons = gridbuttons
            return res
            
        elif deletable and len(request.args)>2 and request.args[-3]=='delete':
            check_authorization()
            table = db[request.args[-2]]
            if type(deletable) == type(lambda:None):
                deletable(request.args[-1])
            else:
                ret = db(table.id==request.args[-1]).delete()
                if ondelete:
                    ondelete(table, request.args[-1], ret)
            redirect(url())
            
        elif csv and len(request.args)>0 and request.args[-1]=='csv':
            check_authorization()
            # TODO
            return dict()
            
        elif request.vars.records and not isinstance(request.vars.records, list):
            request.vars.records=[request.vars.records]
            
        elif not request.vars.records:
            request.vars.records=[]
           
        session['_web2py_grid_referrer_'+formname] = URL(
                r=request, args=request.args,vars=request.vars,
                user_signature=user_signature, hmac_key=hmac_key)
                
        error = None
        search_form = None
        table_el_id = formname + '_maintable'
        
        columns = columns or [str(f) for f in fields 
                                if f.table==main_table and f.readable and (showid or f.type!='id')]
        
        if searchable:
            field_sep = '___'
            
            if searchable is True:
                _exclude_types = ('upload', 'text') if showid else ('id', 'upload', 'text')
                searchable = [f for f in fields 
                                if f.table==main_table and 
                                   f.type not in _exclude_types and f.readable]
            
            _search_fields = []
            _from_tos = []
            for f in searchable:
                _requires = []
                if f.requires and type(f.requires) not in (list, tuple):
                    if isinstance(f.requires, IS_EMPTY_OR):
                        _requires = [f.requires.other]
                    else:
                        _requires = [f.requires]
                _requires = [r for r in _requires if not isinstance(r, IS_NOT_IN_DB)]
                if _requires:
                    if len(_requires) == 1:
                        _requires = _requires[0]
                    _requires = IS_EMPTY_OR(_requires)
                else:
                    _requires = None
                
                _type = 'string' if f.type=='text' else 'integer' if f.type=='id' else f.type
                
                if (f.type in ('double', 'decimal', 'date', 'datetime') or 
                        (f.type == 'integer' and _requires and 
                         isinstance(_requires.other, (IS_INT_IN_RANGE)))):
                    _from_to = [Field(str(f).replace('.', field_sep) + field_sep + 'from', 
                                      type=_type, requires=_requires, 
                                      label=f.label, widget=f.widget),
                                Field(str(f).replace('.', field_sep) + field_sep + 'to', 
                                      type=_type, requires=_requires, 
                                      label=f.label, widget=f.widget)]
                    _from_tos.append(_from_to)
                    _search_fields += _from_to
                elif hasattr(f, 'table'):
                    _search_fields.append(Field(str(f).replace('.', field_sep), 
                        type=_type, requires=_requires, label=f.label, widget=f.widget))
                else:
                    _search_fields.append(f)
            
            search_form = SQLFORM.factory(
                formstyle='divs', submit_button=T('Search'), 
                _class='search_form',
                *_search_fields)
            
            for _from_to in _from_tos:
                self.inline(search_form, 'no_table', 
                    [f.name for f in _from_to], LABEL(_from_to[0].label), SPAN(' - '))
            
            subquery = self._build_query_by_form(db, search_form, 
                            queries=search_queries,
                            field_sep=field_sep, 
                            formname='search_%s' % formname)
        else:
            subquery = None
            
        if subquery:
            dbset = dbset(subquery)
            
        if scope:
            from plugin_tablescope import TableScope
            scope_el = TableScope(dbset, scope, default=scope_default)
            dbset = scope_el.scoped_dataset
            
        if sortable is True:
            sortable = [~f if f.type in ('id', 'date', 'datetime') else f
                            for f in fields 
                                if f.table==main_table and f.type not in ('text', 'upload')]
        if not sortable:
            sortable = []
        if orderby:
            sortable.insert(0, orderby)
        
        orderby_selector = OrderbySelector(sortable)
        
        current_orderby = orderby_selector.orderby()
        permutable = (orderby and (not subquery) and sortable and current_orderby is sortable[0])
           
        extracolumns = extracolumns or []
        
        _links_in_row_buttons = []
        def _get_link_extracolumn(link):
            return {'label':link['header'], 'class':ui.get('default',''),
                    'content':lambda row, rc: link['body'](row)}
        if links and links_in_grid:
            for link in links:
                if isinstance(link, dict):
                    extracolumns.append(_get_link_extracolumn(link))
                else:
                    _links_in_row_buttons.append(link)
        
        if permutable:
            if len(request.args)>2 and request.args[-3] in ('up', 'down'):
                check_authorization()
                table = db[request.args[-2]]
                record = table(request.args[-1]) or redirect(URL('error'))
                inverted = (orderby.op == orderby.db._adapter.INVERT)
                field = orderby.first if inverted else orderby
                 
                current_value = record[field]
                if current_value is None:
                    first = dbset.select(field_id, limitby=(0,1), orderby=orderby).first()
                    current_value = (1 if inverted else -1) + (first.id if first else 0)
                    
                if (request.args[-3] == ('down' if inverted else 'up')):  
                    target = dbset(field<current_value
                        ).select(field_id, field, limitby=(0,1), orderby=orderby if inverted else ~orderby).first()
                elif (request.args[-3] == ('up' if inverted else 'down')):   
                    target = dbset(field>current_value
                        ).select(field_id, field, limitby=(0,1), orderby=orderby.first if inverted else orderby).first()
                else:
                    raise NotImplementedError
                if not target:
                    last = dbset.select(field_id, limitby=(0,1), orderby=orderby.first if orderby.first else ~orderby).first()
                    target_value = (-1 if inverted else 1) + (last.id if last else 0)
                else:
                    target_value = target[field]
                    
                db(table.id==record[field_id]).update(**{field.name:target_value})
                if target:
                    db(table.id==target[field_id]).update(**{field.name:current_value})
                
                if onpermute:
                    onpermute(table, request.args[-2], (record, target))
                redirect(url())
                
            first = dbset.select(field_id, limitby=(0,1), orderby=orderby).first()
            first_id = first.id if first else 0
            last = dbset.select(field_id, limitby=(0,1), orderby=orderby.first if orderby.first else ~orderby).first()
            last_id = last.id if last else 0
            extracolumns.append( 
                {'label':DIV(T('Move'), _style='text-align:center;'), 'width':'150px' if showbuttontext else '65px', 
                'content':lambda row, rc: 
                    DIV(recordbutton('ui-icon-triangle-1-n', T('Up'),
                                url(args=['up', tablename, row[field_id]]), showbuttontext)
                                if row[field_id] != first_id else '',
                          recordbutton('ui-icon-triangle-1-s', T('Down'),
                                url(args=['down', tablename, row[field_id]]), showbuttontext)
                                if row[field_id] != last_id else '',
                    _style='text-align:center;')}
            )
        
        if details or editable or deletable or _links_in_row_buttons:
            extracolumns.append(
                {'label':'', #'width':'%spx' % (_size + 12), 
                'content':lambda row, rc: 
                     DIV(_style='white-space:nowrap;',
                         *([link(row) or '' for link in _links_in_row_buttons] + 
                           [recordbutton('%(buttonview)s' % ui, T('View'),
                                url(args=['view', tablename, row[field_id]]), showbuttontext)
                                    if details else '',
                          recordbutton('%(buttonedit)s' % ui, T('Edit'),
                                url(args=['edit', tablename, row[field_id]]), showbuttontext)
                                    if editable else '',
                          recordbutton('%(buttondelete)s' % ui, T('Delete'),
                                url(args=['delete', tablename, row[field_id]]), showbuttontext,
                                _onclick="""
if(confirm("%s")){return true;} else {jQuery(this).unbind('click').fadeOut();return false;}""" % 
                                          T('Sure you want to delete them?'),)
                                    if deletable else '',
                          ])
                         )}
            )
            
        if paginate:
            paginate_selector = PaginateSelector(paginate if type(paginate) in (list, tuple) else [paginate])
            current_paginate = paginate_selector.paginate
            paginator = Paginator(paginate=current_paginate) 
            # TODO for groupby
            paginator.records = virtualset(dbset.query).count() if virtualset else dbset.count()
            paginate_info = PaginateInfo(paginator.page, paginator.paginate, paginator.records)
            limitby = paginator.limitby()
        else:
            limitby = None
            current_paginate = None
            
        # TODO
        # if paginator.records == 0:
            # error = 'Not Found'
        if virtualset:
            records = virtualset(dbset.query).select(left=left, limitby=limitby,
                        orderby=current_orderby, groupby=groupby, *fields)
            records.db = virtualtable._db
        else:
            records = dbset.select(left=left, limitby=limitby,
                        orderby=current_orderby, groupby=groupby, *fields)
        
        table = SOLIDTABLE(records, 
                    columns=columns,
                    headers=headers,
                    orderby=orderby_selector,
                    truncate=maxtextlength, #TODO replace
                    extracolumns=extracolumns, 
                    upload=upload)
        table.attributes['_class'] = 'solidtable'
        table.attributes['_id'] = table_el_id
        
        inner = []
        if scope:    
            inner.append(scope_el)
        if current_paginate:
            inner.append(DIV(paginate_info, _class='pagination_information'))
        inner.append(table)
        if current_paginate and paginator.records > current_paginate:
            inner.append(DIV(paginate_selector, paginator, _class='index_footer'))
        
        res = DIV(_class=_class, *inner)
          
        res.records = records
        res.search_form = search_form
        res.error = error
        res.gridbuttons = []
        if create:
            res.gridbuttons.append(
                gridbutton('%(buttonadd)s' % ui, T('Add'), url(args=['new', tablename]))
            )
            
        return res
Ejemplo n.º 4
0
def index():
    tax = db.product.price*5/100
    tax.represent = db.product.price.represent
    pretax_price = db.product.price + tax
    pretax_price.represent = db.product.price.represent
    
    request_headers = request.vars.headers or 'default'
    request_columns = request.vars.columns or 'default'
    
################################ The core ######################################
    # A custom orderby selector for the solidtable.
    orderby_selector = OrderbySelector([db.product.id, db.product.name, 
                                        ~db.product.publish_start_date, ~pretax_price])
    
    rows = db().select(db.product.ALL, tax, pretax_price,
                       orderby=orderby_selector.orderby())
             
    if request_headers == 'default':
        # The "headers" is a dictionary of dictionaries for updating default values.
        # Custom fields such as "tax" can be passed to the dictionary keys.
        headers = {'product.name':{'selected': True},
                   'product.description':{'label':'Details', 'class':'italic', 
                                          'width':'200px', 'truncate':38,},
                   tax:{'label': 'Tax'},
                   pretax_price:{'label': 'Pretax Price'}
                   }
    else:
        # The "headers" can be 'labels' or 'fieldname:capitalize'
        headers = request_headers
               
    extracolumns = [{'label':A('Edit', _href='#'),
                     'content':lambda row, rc: A('Edit',_href='edit/%s'%row.product.id)},
                    {'label':A('Delete', _href='#'),
                     'content':lambda row, rc: A('Delete',_href='delete/%s'%row.product.id)},     
                    ]
                    
    # The structure of "columns" defines the multi-line table layout
    # A "None" indicates an empty line over which the precedent line spans
    # Custom fields such as "tax" and extracolumns can be passed to the list of lists.
    if request_columns == 'default':
        columns=[[db.product.name, extracolumns[0]], 
                 'product.id', 
                 ['product.status', 'product.publish_start_date'], 
                 [None, 'product.publish_end_date'], 
                 [pretax_price, 'product.description'], 
                 [tax, None],
                 ['product.price', None],
                ]
    elif request_columns == 'columns_2':
        columns=[[db.product.name, extracolumns[0]], 
                 None,
                 [pretax_price, 'product.description'], 
                 None,
                 [tax, None],
                ]
    elif request_columns == 'columns_3':
        columns=[[db.product.name, extracolumns[0]], 
                 [None, 'product.description'], 
                 [None, tax],
                ]

    table = SOLIDTABLE(rows,  
            columns=columns, extracolumns=extracolumns,
            headers=headers, 
            orderby=orderby_selector,
            renderstyle=True, linkto=URL('show'), selectid=lambda r: r.product.id==7)
################################################################################
            
    return dict(table=DIV(table, STYLE('.italic {font-style: italic;}')),
                table_args=DIV(A('headers=default', _href=URL(vars={'headers':'default'})), ' ',
                               A('headers=labels', _href=URL(vars={'headers':'labels'})), ' ',
                               A('headers=fieldname:capitalize', _href=URL(vars={'headers':'fieldname:capitalize'})), ' ',
                               A('columns=default', _href=URL(vars={'columns':'default'})), ' ',
                               A('columns=columns_2', _href=URL(vars={'columns':'columns_2'})), ' ',
                               A('columns=columns_3', _href=URL(vars={'columns':'columns_3'})), ' ',
                               ))