Exemple #1
0
def _thumb(row, cls, title=None):
    """ Return a column DIV thumbnail. """
    caption = DIV(H3(row.chapter.title),
                  H4('Chapter %i' % row.chapter.number),
                  H5(row.published.strftime(date_format)),
                  H3(row.intro_hanzi),
                  H4(row.intro_en),
                  _class='caption',
                  _role='button',
                  _title=title)
    anchor = A(caption,
               _class='ddj-thumbnail',
               _href=URL('poems', 'chapter', args=[row.chapter.number]))
    thumbnail = DIV(anchor, _class='thumbnail')
    return DIV(thumbnail, _class=cls)
Exemple #2
0
def ACCORDION(panels, id='my_accordion'):
    '''
    [0]     pid
    [1]     panel link text
    [2]     panel content
    [3]     body classes (string); 'in' marks default panel
    '''
    acc = DIV(_class='panel-group', _id=id)
    for panel in panels:
        pid = panel[0]
        linktext = panel[1]
        content = panel[2]
        bclasses = '' if len(panel) <= 3 else panel[3]
        linkattrs = {
            '_class': "panel-toggle {}-toggle".format(pid),
            '_data-toggle': "collapse",
            '_data-parent': "#{}".format(id),
            '_href': "#{}".format(pid)
        }
        headattrs = {'_class': "panel-heading"}
        bodyattrs = {'_class': 'panel-body '}
        innerattrs = {
            '_class': 'panel collapse {}'.format(bclasses),
            '_id': pid
        }
        p = CAT(
            DIV(H4(A(linktext, **linkattrs), _class="panel-title"),
                **headattrs),
            DIV(DIV(content, **bodyattrs), **innerattrs),
        )

        acc.append(p)
    return acc
Exemple #3
0
def informe_mes_empleado():
    empleados = db(db.empleado.is_active is True).select(db.empleado.ALL)
    fempl = ([" "] +
             [f"{p.user_code} {p.nombre} {p.apellido}" for p in empleados])
    form = FORM(
        CENTER(
            H4('Marcadas del personal'),
            TABLE(
                TR(
                    TAG('<label class "control-label">Persona</label>'),
                    SELECT(fempl,
                           _name='fempleado',
                           _type='text',
                           _id="persona",
                           _class="form-control string")),
                TR(
                    TAG('<label class "control-label">Periodo desde</label>'),
                    INPUT(_name='fdesde',
                          _type='date',
                          _id="mesanio",
                          _class="form-control string",
                          requires=IS_NOT_EMPTY())),
                TR(
                    TAG('<label class "control-label">Periodo hasta</label>'),
                    INPUT(
                        _name='fhasta',
                        _type='date',
                        _id="mesanio",
                        _class="form-control string",
                    ))), BR(),
            INPUT(_type="submit",
                  _class="btn btn-primary btn-medium",
                  _value='Continuar')))
    if form.accepts(request, session):
        session.empleado = request.vars['fempleado']
        session.user_code = request.vars['fempleado'].split()[0]
        session.fdesde = request.vars['fdesde']
        session.fhasta = request.vars['fhasta']
        log(f"seleccionado {session.empleado}")
        log(f"desde: {session.fdesde} hasta {session.fhasta}")
        # selector = (db.empleado.user_code == user_code)
        # usuario = db(selector).select().first().as_dict()
        session.tdesde = datetime.datetime.strptime(session.fdesde, '%Y-%m-%d')
        session.thasta = datetime.datetime.strptime(session.fhasta, '%Y-%m-%d')
        lista = aplico_politica(session.user_code, session.fdesde,
                                session.fhasta)
        nombre_archivo = f'''{session.empleado}
        -{session.fdesde}-{session.fhasta}'''
        session.table = list_dict_to_table_sortable(lista, nombre_archivo)
        redirect(URL('informe'))
    else:
        log(f'acceso {request.function}')
    return dict(form=form)
Exemple #4
0
def admin_tabla():
    if 'tabla' in request.vars:
        tabla = request.vars['tabla']
        titulo = DIV(
            A(icon_title('fa-arrow-left', 'Volver'),
              _id='boton_r',
              _class="btn-grid",
              _href=URL('admin')), CENTER(H4('Admin ' + (str(tabla).title()))))
        log('acceso grid ' + str(tabla))
        grid = SQLFORM.smartgrid(eval('db.' + str(tabla)),
                                 maxtextlength=20,
                                 linked_tables=['child'],
                                 fields=eval(opt_tabla(tabla)['fields']))
        return dict(grid=grid, titulo=titulo)
    else:
        redirect(URL('index'))
Exemple #5
0
def chapter(poem, db, uhdb):
    """ Return a bootstrap row for a poem row. """
    if not poem:
        raise Exception('No such poem')
    qry = ((db.verse.book == 1) & (db.verse.chapter == poem.chapter))
    verse = db(qry).select().first()
    title = H3(poem.chapter.title)
    subtitle = H4('Chapter %i' % poem.chapter.number)
    published = H5(poem.published.strftime(date_format))
    stanzas = verse.en.split('\r\n\r\n')
    content = []
    for stanza in stanzas:
        content.append(P(XML(stanza.replace('\r\n', '<br />'))))
    link = P(A(I('Go to the study version'),
               _href=URL('studies', 'chapter', args=[poem.chapter.number]),
               _style='color:inherit;',
               _title='Study version'),
             _style='font-size:0.9em;padding-top:1em')
    content.append(P(link))
    column = DIV(title, subtitle, published, *content, _class=poem_class)
    return DIV(column,
               _class='row',
               _style='font-size:1.12em;white-space:nowrap;')
Exemple #6
0
def cms_post_list_layout(list_id, item_id, resource, rfields, record):
    """
        dataList item renderer for Posts on the Bulletin Board.

        @param list_id: the HTML ID of the list
        @param item_id: the HTML ID of the item
        @param resource: the S3Resource to render
        @param rfields: the S3ResourceFields to render
        @param record: the record as dict
    """

    record_id = record["cms_post.id"]
    #item_class = "thumbnail"

    T = current.T
    db = current.db
    s3db = current.s3db
    settings = current.deployment_settings
    permit = current.auth.s3_has_permission

    raw = record._row
    date = record["cms_post.date"]
    title = record["cms_post.title"]
    body = record["cms_post.body"]
    #series_id = raw["cms_post.series_id"]

    # Allow records to be truncated
    # (not yet working for HTML)
    body = DIV(
        body,
        _class="s3-truncate",
    )

    #if series_id:
    #    series = record["cms_post.series_id"]
    #    translate = settings.get_L10n_translate_cms_series()
    #    if translate:
    #        series_title = T(series)
    #    else:
    #        series_title = series
    #else:
    #    series_title = series = ""

    #status = record["cms_post.status_id"]

    author_id = raw["cms_post.created_by"]
    person = record["cms_post.created_by"]

    # @ToDo: Bulk lookup
    ltable = s3db.pr_person_user
    ptable = db.pr_person
    query = (ltable.user_id == author_id) & \
            (ltable.pe_id == ptable.pe_id)
    row = db(query).select(ptable.id, limitby=(0, 1)).first()
    if row:
        person_id = row.id
    else:
        person_id = None

    if person:
        if person_id:
            # @ToDo: deployment_setting for controller to use?
            person_url = URL(c="hrm", f="person", args=[person_id])
        else:
            person_url = "#"
        person = A(
            person,
            _href=person_url,
        )

    table = db.cms_post

    # Toolbar
    if permit("update", table, record_id=record_id):
        edit_btn = A(
            ICON("edit"),
            SPAN(
                "edit",
                _class="show-for-sr",
            ),
            _href=URL(c="cms",
                      f="post",
                      args=[record_id, "update.popup"],
                      vars={
                          "refresh": list_id,
                          "record": record_id
                      }),
            _class="s3_modal",
            #_title=T("Edit %(type)s") % dict(type=series_title),
            _title=T("Edit"),
        )
    else:
        edit_btn = ""
    if permit("delete", table, record_id=record_id):
        delete_btn = A(
            ICON("delete"),
            SPAN(
                "delete",
                _class="show-for-sr",
            ),
            _class="dl-item-delete",
            _title=T("Delete"),
        )
    else:
        delete_btn = ""

    # Bookmarks
    auth = current.auth
    user = auth.user
    if user:  #and settings.get_cms_bookmarks():
        # @ToDo: Bulk lookup (via list_fields?)
        ltable = s3db.cms_post_user
        query = (ltable.post_id == record_id) & \
                (ltable.user_id == user.id)
        exists = db(query).select(ltable.id, limitby=(0, 1)).first()
        if exists:
            bookmark = A(
                ICON("bookmark"),
                SPAN(
                    "remove bookmark",
                    _class="show-for-sr",
                ),
                _class="bookmark",
                _title=T("Remove Bookmark"),
            )
        else:
            bookmark = A(
                ICON("bookmark-empty"),
                SPAN(
                    "bookmark",
                    _class="show-for-sr",
                ),
                _class="bookmark",
                _title=T("Add Bookmark"),
            )
        bookmark["_data-c"] = "cms"
        bookmark["_data-f"] = "post"
        bookmark["_data-i"] = record_id
    else:
        bookmark = ""

    # Dropdown of available documents
    documents = raw["doc_document.file"]
    if documents:
        if not isinstance(documents, list):
            documents = (documents, )
        doc_list = UL(
            _class="dropdown-menu",
            _role="menu",
        )
        retrieve = db.doc_document.file.retrieve
        for doc in documents:
            try:
                doc_name = retrieve(doc)[0]
            except (IOError, TypeError):
                doc_name = current.messages["NONE"]
            doc_url = URL(c="default", f="download", args=[doc])
            doc_item = LI(
                A(
                    ICON("file"),
                    " ",
                    doc_name,
                    _href=doc_url,
                ),
                _role="menuitem",
            )
            doc_list.append(doc_item)
        docs = DIV(
            A(ICON("paper-clip"),
              SPAN(_class="caret"),
              _class="btn dropdown-toggle",
              _href="#",
              **{"_data-toggle": "dropdown"}),
            doc_list,
            _class="btn-group attachments dropdown pull-right",
        )
    else:
        docs = ""

    #divider = LI("|")
    #divider["_aria-hidden"] = "true"

    toolbar = UL(  #LI(share_btn,
        #   _class="item",
        #   ),
        #LI(A(ICON("flag"), # @ToDo: Use flag-alt if not flagged & flag if already flagged (like for bookmarks)
        #     SPAN("flag this",
        #          _class = "show-for-sr",
        #          ),
        #     _href="#",
        #     _title=T("Flag"),
        #     ),
        #   _class="item",
        #   ),
        LI(
            bookmark,
            _class="item",
        ),
        #LI(A(I(_class="fa fa-users",
        #       ),
        #     SPAN("make public",
        #          _class = "show-for-sr",
        #          ),
        #     _href="#",
        #     _title=T("Make Public"),
        #     ),
        #   _class="item",
        #   ),
        LI(
            edit_btn,
            _class="item",
        ),
        LI(
            delete_btn,
            _class="item",
        ),
        _class="controls",
    )

    # Tags
    #if settings.get_cms_show_tags():
    tag_list = UL(_class="left inline-list s3-tags", )
    tag_list["_data-post_id"] = record_id
    tags = raw["cms_tag.name"]
    if tags:
        if not isinstance(tags, list):
            tags = [tags]
        for tag in tags:
            tag_list.append(LI(A(
                tag,
                _href="#",
            ), ))

    # Comments
    comment_list = UL(_class="card-post-comments")
    cappend = comment_list.append

    #if settings.get_cms_comments():
    # Add existing comments (oldest 1st)
    # - should sort by default by ID which is equivalent to oldest first,
    #   however they seem to come in in a random order (even if orderby set on the component) so need to be sorted manually here
    comments = raw["cms_comment.json_dump"]
    ncomments = 0
    if comments:
        if not isinstance(comments, list):
            comments = [comments]
        comments = [json.loads(comment) for comment in comments]
        comments.sort(key=lambda c: c["created_on"])
        for comment in comments:
            author = s3_auth_user_represent(comment["created_by"])
            cdate = dateutil.parser.parse(comment["created_on"])
            ctime = cdate.time().strftime("%H:%M")
            cdate = cdate.date().strftime("%b %d, %Y")
            comment = LI(TAG["ASIDE"](P(T("Updated %(date)s @ %(time)s by %(author)s") % \
                                                dict(date = cdate,
                                                     time = ctime,
                                                     author = author,
                                                     ),
                                        _class="meta",
                                        ),
                                      DIV(comment["body"],
                                          _class="desc",
                                          ),
                                      # @ToDo: Show this if more than x chars?
                                      #TAG["FOOTER"](P(A(T("More Info"),
                                      #                  _class="more",
                                      #                  )
                                      #                ),
                                      #              _class="footer",
                                      #              ),
                                      _class="card-post-comment",
                                      ))
            cappend(comment)
            ncomments += 1

    if ncomments == 1:
        num_comments = "1 Comment"
    else:
        num_comments = T("%(num)s Comments") % dict(num=ncomments)

    if user:
        add_comment = A(
            T("Add Comment"),
            _class="add-comment",
        )
        add_comment["_data-l"] = list_id
        add_comment["_data-i"] = record_id
        add_comment = P(add_comment)
        comment_input = LI(
            TAG["ASIDE"](
                TEXTAREA(
                    _class="desc",
                    _placeholder=T("comment here"),
                ),
                TAG["FOOTER"](P(A(
                    "Submit Comment",
                    _class="submit",
                ), ), ),
                _class="card-post-comment",
            ),
            _class="comment-form hide",
        )
        cappend(comment_input)
    else:
        add_comment = ""

    item = TAG["ASIDE"](
        TAG["HEADER"](
            UL(  # post priority icon
                LI(_class="item icon", ),
                # post type title
                #LI(series_title,
                #   _class="item primary",
                #   ),
                # post status
                #LI(status,
                #   _class="item secondary border status",
                #   ),
                # post visibility
                # @ToDo: Read the visibility
                #LI(T("Public"),
                #   _class="item secondary border visibility",
                #   ),
                _class="status-bar-left"),
            toolbar,
            _class="status-bar",
        ),
        DIV(
            DIV(
                SPAN(
                    "Updated ",  # @ToDo: i18n
                    TAG["TIME"](date),
                    " by ",
                    person,
                    _class="meta-update",
                ),
                SPAN(
                    num_comments,
                    _class="meta-comments",
                ),
                _class="meta",
            ),
            H4(
                title,
                _class="title",
            ),
            DIV(
                body,
                _class="desc",
            ),
            _class="body",
        ),
        docs,
        TAG["FOOTER"](
            DIV(
                tag_list,
                _class=
                "tags clearfix",  # @ToDo: remove clearfix and style via CSS
            ),
            comment_list,
            add_comment,
            _class="footer",
        ),
        _class="card-post",
        _id=item_id,
    )

    return item
Exemple #7
0
    def pdf(self, r, **attr):
        """
            Generate the PDF

            Args:
                r: the S3Request instance
                attr: controller attributes
        """

        T = current.T

        db = current.db
        s3db = current.s3db

        # Look up the report organisation
        logo = None
        org_id, org_label = self.get_report_organisation(r)
        if org_id:
            # Look up the root organisation's logo
            otable = s3db.org_organisation
            rotable = otable.with_alias("root_organisation")
            join = rotable.on(rotable.id == otable.root_organisation)
            field = rotable.logo
            row = db(otable.id == org_id).select(
                field,
                join=join,
                limitby=(0, 1),
            ).first()
            if row and row.logo:
                if field.uploadfolder:
                    path = field.uploadfolder
                else:
                    path = os.path.join(current.request.folder, 'uploads')
                logo = os.path.join(path, row.logo)

        # Look up the report programme
        prog_id, prog_label = self.get_report_programme(r)

        # Extract the HR records
        data, pictures = self.extract(r.resource)

        # Construct the header
        title = T("Official Volunteer List")
        header = TABLE(_class="no-grid", )
        trow = TR()
        if logo:
            trow.append(
                TD(
                    IMG(_src=logo, _width="80"),
                    _rowspan=3 if prog_id else 2,
                ))
        trow.append(TD(H4(title), _colspan=3))
        header.append(trow)
        if org_id:
            header.append(TR(TD(H5(org_label), _colspan=3)))
        if prog_id:
            header.append(TR(TD(prog_label, _colspan=3)))
        header.append(TR(TD()))

        # Should we show the branch column?
        branches = set(row["_row"]["hrm_human_resource.organisation_id"]
                       for row in data.rows)
        if org_id:
            show_branch = len(branches) > 1
            org_repr = s3db.org_OrganisationRepresent(
                show_link=False,
                parent=False,
                acronym=True,
            )
        else:
            show_branch = True
            org_repr = r.table.organisation_id.represent
        org_repr.bulk(list(branches))

        # Construct the table header
        labels = TR(
            TH(T("Picture")),
            TH(T("Name")),
            TH(T("Last Name")),
            TH(T("National ID")),
            TH(T("Volunteer ID")),
            TH(T("Signature")),
        )
        if not prog_id:
            labels.insert(1, TH(T("Program")))
        if show_branch:
            labels.insert(1, TH(T("Branch")))

        # Build the table
        body = TABLE(labels, _class="repeat-header shrink-to-fit")

        # Add the data rows
        for row in data.rows:

            raw = row._row

            # Picture
            picture = pictures.get(raw["pr_person.pe_id"])
            if picture:
                picture = IMG(
                    _src=picture,
                    _width=80,
                )
            else:
                picture = ""

            # Name
            name = s3_format_fullname(
                fname=raw["pr_person.first_name"],
                mname=raw["pr_person.middle_name"],
                lname="",
                truncate=False,
            )

            # Build the row
            trow = TR(
                TD(picture),
                TD(name),
                TD(row["pr_person.last_name"]),
                TD(row["pr_national_id_identity.value"]),
                TD(row["hrm_human_resource.code"]),
                TD(),
            )
            if not prog_id:
                trow.insert(1, TD(row["hrm_programme_hours.programme_id"]))
            if show_branch:
                trow.insert(
                    1, TD(org_repr(raw["hrm_human_resource.organisation_id"])))
            body.append(trow)

        footer = DIV()

        from s3.codecs.pdf import EdenDocTemplate, S3RL_PDF

        doc = EdenDocTemplate(title=title)
        printable_width = doc.printable_width

        get_html_flowable = S3RL_PDF().get_html_flowable

        header_flowable = get_html_flowable(header, printable_width)
        body_flowable = get_html_flowable(body, printable_width)
        footer_flowable = get_html_flowable(footer, printable_width)

        # Build the PDF
        doc.build(
            header_flowable,
            body_flowable,
            footer_flowable,
        )
        filename = "siglist.pdf"

        # Return the generated PDF
        response = current.response
        response.headers["Content-Type"] = contenttype(".pdf")
        disposition = "attachment; filename=\"%s\"" % filename
        response.headers["Content-disposition"] = disposition

        return doc.output.getvalue()
Exemple #8
0
    def comment_internal(self):
        is_author = False
        if self.session.auth and self.session.auth.user:
            is_author = True if self.session.auth.user.id == self.context.article.author else False
            self.db.Comments.article_id.default = self.context.article.id
            self.db.Comments.user_id.default = self.session.auth.user.id
            self.db.Comments.commenttime.default = self.request.now
            self.db.Comments.comment_text.label = self.T("Post your comment")
            from plugin_ckeditor import CKEditor
            ckeditor = CKEditor()
            self.db.Comments.comment_text.widget = ckeditor.basicwidget
            form = SQLFORM(self.db.Comments, formstyle='divs')
            if form.process(
                    message_onsuccess=self.T('Comment included')).accepted:
                self.new_article_event(
                    'new_article_comment',
                    self.session.auth.user,
                    data={
                        'event_text':
                        form.vars.comment_text,
                        'event_link':
                        "%s/%s#comment_%s" %
                        (self.context.article.id, self.context.article.slug,
                         form.vars.id)
                    })
        else:
            form = A(
                self.T("Login to post comments"),
                _class="button",
                _href=self.CURL(
                    'default',
                    'user',
                    args='login',
                    vars=dict(_next=self.CURL('article',
                                              'show',
                                              args=[
                                                  self.context.article.id,
                                                  self.context.article.slug
                                              ]))))

        comments = self.db(
            self.db.Comments.article_id == self.context.article.id).select(
                orderby=self.db.Comments.created_on)

        if comments and is_author:
            edit_in_place = ckeditor.bulk_edit_in_place(
                ["comment_%(id)s" % comment for comment in comments],
                URL('editcomment'))
        elif comments and self.session.auth and self.session.auth.user:
            usercomments = comments.find(
                lambda row: row.user_id == self.session.auth.user.id)
            if usercomments:
                edit_in_place = ckeditor.bulk_edit_in_place(
                    ["comment_%(id)s" % comment for comment in usercomments],
                    URL('editcomment'))
            else:
                edit_in_place = ('', '')
        else:
            edit_in_place = ('', '')

        return DIV(H4(
            IMG(_src=URL('static',
                         '%s/images/icons' % self.context.theme_name,
                         args='board.24.png')), self.T("Comments")),
                   UL(
                       *[
                           LI(H5(
                               A(self.T("%s %s" %
                                        (comment.nickname or comment.user_id,
                                         self.db.pdate(comment.commenttime))),
                                 _href=self.CURL('person',
                                                 'show',
                                                 args=comment.nickname
                                                 or comment.user_id))),
                              DIV(
                                  XML(comment.comment_text), **{
                                      '_class': 'editable commentitem',
                                      '_data-object': 'comment',
                                      '_data-id': comment.id,
                                      '_id': "comment_%s" % comment.id
                                  }),
                              _class="comment_li") for comment in comments
                       ], **dict(_class="comment_ul")),
                   edit_in_place[1],
                   form,
                   _class="internal-comments article-box")
Exemple #9
0
    def invite(self, r, **attr):
        """
            Prepare and process invitation form

            @param r: the S3Request instance
            @param attr: controller attributes
        """

        T = current.T

        db = current.db
        s3db = current.s3db

        response = current.response
        request = current.request
        session = current.session

        settings = current.deployment_settings
        auth = current.auth
        auth_settings = auth.settings
        auth_messages = auth.messages

        output = {
            "title": T("Invite Organisation"),
        }

        # Get all accounts that are linked to this org
        utable = auth_settings.table_user
        oltable = s3db.org_organisation_user
        pltable = s3db.pr_person_user

        organisation_id = r.record.id
        join = oltable.on((oltable.user_id == utable.id) & \
                          (oltable.deleted == False))
        left = pltable.on((pltable.user_id == utable.id) & \
                          (pltable.deleted == False))
        query = (oltable.organisation_id == organisation_id)
        rows = db(query).select(
            utable.id,
            utable.first_name,
            utable.last_name,
            utable.email,
            utable.registration_key,
            pltable.pe_id,
            join=join,
            left=left,
        )

        active, disabled, invited = [], [], []
        for row in rows:
            user = row[utable]
            person_link = row.pr_person_user
            if person_link.pe_id:
                if user.registration_key:
                    disabled.append(user)
                else:
                    active.append(user)
            else:
                invited.append(user)

        if active or disabled:
            response.error = T(
                "There are already user accounts registered for this organization"
            )

            from gluon import UL, LI, H4, DIV
            from s3 import s3_format_fullname

            fullname = lambda user: s3_format_fullname(
                fname=user.first_name,
                lname=user.last_name,
                truncate=False,
            )
            account_list = DIV(_class="org-account-list")
            if active:
                account_list.append(H4(T("Active Accounts")))
                accounts = UL()
                for user in active:
                    accounts.append(
                        LI("%s <%s>" % (fullname(user), user.email)))
                account_list.append(accounts)
            if disabled:
                account_list.append(H4(T("Disabled Accounts")))
                accounts = UL()
                for user in disabled:
                    accounts.append(
                        LI("%s <%s>" % (fullname(user), user.email)))
                account_list.append(accounts)

            output["item"] = account_list
            response.view = self._view(r, "display.html")
            return output

        account = invited[0] if invited else None

        # Look up existing invite-account
        email = None
        if account:
            email = account.email
        else:
            ctable = s3db.pr_contact
            query = (ctable.pe_id == r.record.pe_id) & \
                    (ctable.contact_method == "EMAIL") & \
                    (ctable.deleted == False)
            contact = db(query).select(
                ctable.value,
                orderby=ctable.priority,
                limitby=(0, 1),
            ).first()
            if contact:
                email = contact.value

        # Form Fields
        dbset = db(utable.id != account.id) if account else db
        formfields = [
            Field("email",
                  default=email,
                  requires=[
                      IS_EMAIL(error_message=auth_messages.invalid_email),
                      IS_LOWER(),
                      IS_NOT_IN_DB(
                          dbset,
                          "%s.email" % utable._tablename,
                          error_message=auth_messages.duplicate_email,
                      ),
                  ]),
        ]

        # Generate labels (and mark required fields in the process)
        labels, has_required = s3_mark_required(formfields, )
        response.s3.has_required = has_required

        # Form buttons
        SEND_INVITATION = T("Send New Invitation") if account else T(
            "Send Invitation")
        buttons = [
            INPUT(
                _type="submit",
                _value=SEND_INVITATION,
            ),
            # TODO cancel-button?
        ]

        # Construct the form
        response.form_label_separator = ""
        form = SQLFORM.factory(
            table_name="invite",
            record=None,
            hidden={"_next": request.vars._next},
            labels=labels,
            separator="",
            showid=False,
            submit_button=SEND_INVITATION,
            #delete_label = auth_messages.delete_label,
            formstyle=settings.get_ui_formstyle(),
            buttons=buttons,
            *formfields)

        # Identify form for CSS & JS Validation
        form.add_class("send_invitation")

        if form.accepts(
                request.vars,
                session,
                formname="invite",
                #onvalidation = auth_settings.register_onvalidation,
        ):

            error = self.invite_account(r.record,
                                        form.vars.email,
                                        account=account)
            if error:
                response.error = T(
                    "Could not send invitation (%(reason)s)") % {
                        "reason": error
                    }
            else:
                response.confirmation = T("Invitation sent")
        else:
            if account:
                response.warning = T(
                    "This organisation has been invited before!")

        output["form"] = form

        response.view = self._view(r, "update.html")

        return output