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)
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
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)
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'))
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;')
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
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()
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")
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