def custom_prep(r): # Call standard prep if callable(standard_prep): result = standard_prep(r) if not result: return False if r.interactive or r.representation == "aadata": # Configure fields field = r.table.duration field.readable = field.writable = True if r.interactive: from s3.s3filter import S3TextFilter, S3OptionsFilter, S3LocationFilter, S3DateFilter filter_widgets = [ S3TextFilter(["name", "code", "description", "organisation.name", "organisation.acronym", ], label=T("Name"), _class="filter-search", ), S3OptionsFilter("status_id", label=T("Status"), represent="%(name)s", cols=3, ), S3OptionsFilter("theme_project.theme_id", label=T("Theme"), represent="%(name)s", widget="multiselect", #hidden=True, ), S3LocationFilter("location.location_id", label=T("Location"), levels=["L1", "L2"], widget="multiselect", #hidden=True, ), # @ToDo: Widget to handle Start & End in 1! S3DateFilter("start_date", label=T("Start Date"), hide_time=True, #hidden=True, ), S3DateFilter("end_date", label=T("End Date"), hide_time=True, #hidden=True, ), ] current.s3db.configure("project_project", filter_widgets = filter_widgets, ) return True
def _newsfeed(): """ Custom Page - Filterable DataList of CMS Posts & a DataList of Events """ #if not current.auth.is_logged_in(): # current.auth.permission.fail() T = current.T s3db = current.s3db request = current.request response = current.response s3 = response.s3 # Ensure that filtered views translate into options which update the Widget if "~.series_id$name" in request.get_vars: series_name = request.vars["~.series_id$name"] table = s3db.cms_series series = current.db(table.name == series_name).select( table.id, limitby=(0, 1)).first() if series: series_id = str(series.id) request.get_vars.pop("~.series_id$name") request.get_vars["~.series_id__belongs"] = series_id current.deployment_settings.ui.customize_cms_post() list_layout = s3.render_posts filter_widgets = [ S3TextFilter( ["body"], label="", _class="filter-search", #_placeholder=T("Search").upper(), ), S3OptionsFilter( "series_id", label=T("Filter by Type"), represent="%(name)s", widget="multiselect", hidden=True, ), S3LocationFilter( "location_id", label=T("Filter by Location"), levels=["L1", "L2", "L3"], widget="multiselect", hidden=True, ), S3OptionsFilter( "created_by$organisation_id", label=T("Filter by Organization"), # Can't use this for integers, use field.represent instead #represent="%(name)s", widget="multiselect", hidden=True, ), S3DateFilter( "created_on", label=T("Filter by Date"), hide_time=True, hidden=True, ), ] s3db.configure( "cms_post", # We use a custom Advanced widget filter_advanced=False, filter_formstyle=filter_formstyle, filter_submit=(T("SEARCH"), "btn btn-primary"), filter_widgets=filter_widgets, list_layout=list_layout, # Create form comes via AJAX in a Modal insertable=False, notify_fields=[ (T("Type"), "series_id"), (T("Date"), "date"), (T("Location"), "location_id"), (T("Description"), "body"), ], notify_template="notify_post", ) s3.dl_pagelength = 6 # 5 forces an AJAX call old_args = request.args if "datalist_dl_post" in old_args: # DataList pagination or Ajax-deletion request request.args = ["datalist_f"] ajax = "list" elif "datalist_dl_filter" in old_args: # FilterForm options update request request.args = ["filter"] ajax = "filter" elif "validate.json" in old_args: # Inline component validation request request.args = [] ajax = True elif current.auth.permission.format == "msg": # Subscription lookup request request.args = [] ajax = True else: # Default request.args = ["datalist_f"] ajax = None def prep(r): if ajax == "list": r.representation = "dl" elif ajax == "filter": r.representation = "json" return True s3.prep = prep output = current.rest_controller("cms", "post", list_ajaxurl=URL(f="index", args="datalist_dl_post"), filter_ajax_url=URL( f="index", args="datalist_dl_filter", vars={})) request.args = old_args if ajax == "list": # Don't override view if this is an Ajax-deletion request if not "delete" in request.get_vars: response.view = "plain.html" elif not ajax: # Set Title & View after REST Controller, in order to override output["title"] = T("News Feed") view = path.join(request.folder, "private", "templates", THEME, "views", "newsfeed.html") try: # Pass view as file not str to work in compiled mode response.view = open(view, "rb") except IOError: from gluon.http import HTTP raise HTTP(404, "Unable to open Custom View: %s" % view) scripts = [] sappend = scripts.append # Style the Search TextFilter widget sappend( '''$('#post-cms_post_body-text-filter__row').addClass('input-append').append('<span class="add-on"><i class="icon-search"></i></span>')''' ) # Button to toggle Advanced Form sappend( '''$('#list-filter').append('<a class="accordion-toggle"><i class="icon-reorder"></i> %s</a>')''' % T("Advanced Search")) # Toggle doesn't work directly when removing 'hide' & requires a 2nd click to open without this sappend( '''$('.accordion-toggle').click(function(){var a=$('.advanced');if(a.hasClass('hide')){a.removeClass('hide').show()}else{a.toggle()}})''' ) s3.jquery_ready.append('''\n'''.join(scripts)) # Latest 5 Disasters # resource = s3db.resource("event_event") # layout = render_events # list_id = "event_datalist" # limit = 5 # orderby = "start_date desc" # list_fields = ["name", # "event_type_id$name", # "start_date", # "closed", # ] # output["disasters"] = latest_records(resource, layout, list_id, limit, list_fields, orderby) return output
def _updates(): """ Custom Page - Filterable DataList of CMS Posts & a DataList of Events """ #if not current.auth.is_logged_in(): # current.auth.permission.fail() T = current.T s3db = current.s3db request = current.request response = current.response s3 = response.s3 current.deployment_settings.ui.customize_cms_post() list_layout = s3.render_posts filter_widgets = [ S3TextFilter( ["body"], label="", _class="filter-search", #_placeholder=T("Search").upper(), ), S3OptionsFilter( "series_id", label=T("Filter by Type"), represent="%(name)s", widget="multiselect", cols=3, hidden=True, ), S3LocationFilter( "location_id", label=T("Filter by Location"), levels=["L1", "L2", "L3"], widget="multiselect", cols=3, hidden=True, ), S3OptionsFilter( "created_by$organisation_id", label=T("Filter by Organization"), represent="%(name)s", widget="multiselect", cols=3, hidden=True, ), S3DateFilter( "created_on", label=T("Filter by Date"), hide_time=True, hidden=True, ), ] s3db.configure( "cms_post", # We use a custom Advanced widget filter_advanced=False, filter_formstyle=filter_formstyle, filter_submit=(T("SEARCH"), "btn btn-primary"), filter_widgets=filter_widgets, list_layout=list_layout, # Create form comes via AJAX in a Modal insertable=False, ) s3.dl_pagelength = 6 # 5 forces an AJAX call if "datalist_dl_post" in request.args: # DataList pagination or Ajax-deletion request request.args = ["datalist_f"] ajax = "list" elif "datalist_dl_filter" in request.args: # FilterForm options update request request.args = ["filter"] ajax = "filter" elif "validate.json" in request.args: ajax = True else: # Default request.args = ["datalist_f"] ajax = None def prep(r): if ajax == "list": r.representation = "dl" elif ajax == "filter": r.representation = "json" return True s3.prep = prep output = current.rest_controller("cms", "post", list_ajaxurl=URL(f="index", args="datalist_dl_post"), filter_ajax_url=URL( f="index", args="datalist_dl_filter", vars={})) if ajax == "list": # Don't override view if this is an Ajax-deletion request if not "delete" in request.get_vars: response.view = "plain.html" elif not ajax: # Set Title & View after REST Controller, in order to override output["title"] = T("News Feed") view = path.join(request.folder, "private", "templates", THEME, "views", "updates.html") try: # Pass view as file not str to work in compiled mode response.view = open(view, "rb") except IOError: from gluon.http import HTTP raise HTTP("404", "Unable to open Custom View: %s" % view) scripts = [] sappend = scripts.append # Style the Search TextFilter widget sappend( '''$('#post-cms_post_body-text-filter__row').addClass('input-append').append('<span class="add-on"><i class="icon-search"></i></span>')''' ) # Button to toggle Advanced Form sappend( '''$('#list-filter').append('<a class="accordion-toggle"><i class="icon-reorder"></i> %s</a>')''' % T("Advanced Search")) sappend( '''$('.accordion-toggle').click(function(){$('.advanced').toggle()})''' ) s3.jquery_ready.append('''\n'''.join(scripts)) # Latest 5 Disasters resource = s3db.resource("event_event") list_fields = [ "name", "event_type_id$name", "zero_hour", "closed", ] orderby = resource.get_config("list_orderby", ~resource.table.created_on) datalist, numrows, ids = resource.datalist(fields=list_fields, start=None, limit=5, listid="event_datalist", orderby=orderby, layout=render_events) # Render the list data = datalist.html() if numrows == 0: # Empty table or just no match? table = resource.table if "deleted" in table: available_records = current.db(table.deleted != True) else: available_records = current.db(table._id > 0) if available_records.select(table._id, limitby=(0, 1)).first(): msg = DIV(S3CRUD.crud_string(resource.tablename, "msg_no_match"), _class="empty") else: msg = DIV(S3CRUD.crud_string(resource.tablename, "msg_list_empty"), _class="empty") data.insert(1, msg) output["disasters"] = data return output
def newsfeed(): """ RESTful CRUD controller for display of posts as a filterable dataList """ # Load Model table = s3db.cms_post title_list = T("Latest Information") # Hide Posts linked to Modules & Expired Posts FS = s3base.S3FieldSelector s3.filter = (FS("post_module.module") == None) & (FS("expired") != True) # Ensure that filtered views translate into options which update the Widget get_vars = request.get_vars if "~.series_id$name" in get_vars: series_name = get_vars["~.series_id$name"] # Disabled as can change filters dynamically # @ToDo: Better Mechanism: Another field in cms_series? #if series_name == "Request": # title_list = T("Latest Requests") #elif series_name == "Offer": # title_list = T("Latest Offers") stable = s3db.cms_series series = db(stable.name == series_name).select(stable.id, limitby=(0, 1)).first() if series: series_id = str(series.id) get_vars.pop("~.series_id$name") get_vars["~.series_id__belongs"] = series_id s3.crud_strings["cms_post"].title_list = title_list # Which levels of Hierarchy are we using? hierarchy = gis.get_location_hierarchy() levels = hierarchy.keys() if len(settings.get_gis_countries()) == 1: levels.remove("L0") # @ToDo: deployment_setting #org_field = "created_by$organisation_id" org_field = "post_organisation.organisation_id" # @ToDo: deployment_setting #contact_field = "created_by" #table.created_by.represent = s3_auth_user_represent_name contact_field = "person_id" from s3.s3filter import S3TextFilter, S3OptionsFilter, S3LocationFilter, S3DateFilter filter_widgets = [ S3TextFilter( ["body"], label=T("Search"), _class="filter-search", #_placeholder=T("Search").upper(), ), S3LocationFilter( "location_id", label=T("Filter by Location"), levels=levels, widget="multiselect", hidden=True, ), S3OptionsFilter( org_field, label=T("Filter by Organization"), # Can't use this for created_by as integer, use field.represent instead #represent="%(name)s", widget="multiselect", hidden=True, ), S3DateFilter( "date", label=T("Filter by Date"), hide_time=True, hidden=True, ), ] if settings.get_cms_show_tags(): filter_widgets.insert( 1, S3OptionsFilter( "tag_post.tag_id", label=T("Filter by Tag"), represent="%(name)s", widget="multiselect", hidden=True, )) if settings.get_cms_bookmarks() and auth.user: filter_widgets.insert( 1, S3OptionsFilter( "bookmark.user_id", label=T("Filter by Bookmark"), # Can't just use "" as this is then omitted from rendering options={ "*": T("All"), auth.user.id: T("My Bookmarks"), }, hidden=True, multiple=False, )) len_series = db(s3db.cms_series.deleted == False).count() if len_series > 3: # Multiselect widget filter_widgets.insert( 1, S3OptionsFilter( "series_id", label=T("Filter by Type"), # We want translations #represent="%(name)s", widget="multiselect", hidden=True, )) elif len_series > 1: # Checkboxes filter_widgets.insert( 1, S3OptionsFilter( "series_id", label=T("Filter by Type"), # We want translations #represent="%(name)s", cols=2, hidden=True, )) else: # No Widget pass s3db.configure( "cms_post", # We could use a custom Advanced widget #filter_advanced = False, filter_formstyle=filter_formstyle, # No Submit button (done automatically) #filter_submit = (T("SEARCH"), "btn btn-primary"), filter_widgets=filter_widgets, list_layout=s3db.cms_render_posts, # Create form comes via AJAX in a Modal #insertable = False, notify_fields=[ (T("Type"), "series_id"), (T("Date"), "date"), (T("Location"), "location_id"), (T("Organization"), org_field), (T("Contact"), contact_field), (T("Description"), "body"), ], notify_template="notify_post", ) s3.dl_pagelength = 6 # 5 forces an AJAX call def prep(r): if r.interactive or r.representation == "aadata": s3db.cms_customize_post_fields() if r.interactive: field = table.series_id field.label = T("Type") if r.method == "read": # Restore the label for the Location table.location_id.label = T("Location") elif r.method == "create": pass # @ToDo: deployment_setting #ADMIN = session.s3.system_roles.ADMIN #if (not auth.s3_has_role(ADMIN)): # represent = S3Represent(lookup="cms_series", # translate=settings.get_L10n_translate_cms_series()) # field.requires = IS_ONE_OF(db, # "cms_series.id", # represent, # not_filterby="name", # not_filter_opts = ["Alert"], # ) refresh = get_vars.get("refresh", None) if refresh == "datalist": # We must be coming from the News Feed page so can change the type on-the-fly field.readable = field.writable = True #field.requires = field.requires.other #field = table.name #field.readable = field.writable = False #field = table.title #field.readable = field.writable = False field = table.avatar field.default = True #field.readable = field.writable = False field = table.replies field.default = False #field.readable = field.writable = False field = table.body field.label = T("Description") # Plain text not Rich from s3.s3widgets import s3_comments_widget field.widget = s3_comments_widget #table.comments.readable = table.comments.writable = False #if request.controller == "default": # # Don't override card layout for News Feed/Homepage # return True from s3.s3forms import S3SQLCustomForm, S3SQLInlineComponent # Filter from a Profile page? # If so, then default the fields we know location_id = get_vars.get("~.(location)", None) if location_id: table.location_id.default = location_id event_id = get_vars.get("~.(event)", None) if event_id: crud_form = S3SQLCustomForm( "date", "series_id", "body", "location_id", S3SQLInlineComponent( "document", name="file", label=T("Files"), fields=[ "file", #"comments", ], ), ) def create_onaccept(form): table = current.s3db.event_event_post table.insert(event_id=event_id, post_id=form.vars.id) s3db.configure( "cms_post", create_onaccept=create_onaccept, ) else: crud_form = S3SQLCustomForm( "date", "series_id", "body", "location_id", # @ToDo: deployment_setting for Events #S3SQLInlineComponent( # "event_post", # #label = T("Disaster(s)"), # label = T("Disaster"), # multiple = False, # fields = ["event_id"], # orderby = "event_id$name", #), # @ToDo: deployment_setting S3SQLInlineComponent( "post_organisation", label=T("Organization"), fields=["organisation_id"], # @ToDo: deployment_setting multiple=False, ), # @ToDo: deployment_setting "person_id", S3SQLInlineComponent( "document", name="file", label=T("Files"), fields=[ "file", #"comments", ], ), ) # Return to List view after create/update/delete # We now do all this in Popups #url_next = URL(c="default", f="index", args="newsfeed") s3db.configure( "cms_post", #create_next = url_next, #delete_next = url_next, #update_next = url_next, crud_form=crud_form, # Don't include a Create form in 'More' popups listadd=False, list_layout=s3db.cms_render_posts, ) elif r.representation == "xls": table.created_by.represent = s3base.s3_auth_user_represent_name #table.created_on.represent = datetime_represent utable = auth.settings.table_user utable.organisation_id.represent = s3db.org_organisation_represent list_fields = [ (T("Date"), "date"), #(T("Disaster"), "event_post.event_id"), (T("Type"), "series_id"), (T("Details"), "body"), ] for level in levels: list_fields.append( (hierarchy[level], "location_id$%s" % level)) list_fields = + [ (T("Contact"), contact_field), (T("Organization"), org_field), ] s3db.configure( "cms_post", list_fields=list_fields, ) elif r.representation == "plain" and \ r.method != "search": # Map Popups table.location_id.represent = s3db.gis_LocationRepresent(sep=" | ") table.created_by.represent = s3base.s3_auth_user_represent_name # Used by default popups series = table.series_id.represent(r.record.series_id) s3.crud_strings[ "cms_post"].title_display = "%(series)s Details" % dict( series=series) s3db.configure( "cms_post", popup_url="", ) table.avatar.readable = False table.body.label = "" table.expired.readable = False table.replies.readable = False table.created_by.readable = True table.created_by.label = T("Author") # Used by cms_post_popup #table.created_on.represent = datetime_represent elif r.representation == "geojson": r.table.age = Field.Lazy(cms_post_age) return True s3.prep = prep def postp(r, output): if r.interactive: if r.method == "datalist" and r.representation != "dl": # Hide side menu current.menu.options = None response.view = s3base.S3CRUD._view(r, "cms/newsfeed.html") return output s3.postp = postp output = s3_rest_controller( "cms", "post", hide_filter=False, ) return output
def newsfeed(): """ RESTful CRUD controller for display of posts as a filterable dataList (use with /datalist method) """ # Load Model table = s3db.cms_post stable = db.cms_series # Hide Posts linked to Modules and Maps & Expired Posts s3.filter = (FS("post_module.module") == None) & \ (FS("post_layer.layer_id") == None) & \ (FS("expired") != True) title_list = T("Latest Information") # Ensure that filtered views translate into options which update the Widget if "~.series_id$name" in get_vars: series_name = get_vars["~.series_id$name"] # Disabled as can change filters dynamically # @ToDo: Better Mechanism: Another field in cms_series? #if series_name == "Request": # title_list = T("Latest Requests") #elif series_name == "Offer": # title_list = T("Latest Offers") series = db(stable.name == series_name).select(stable.id, cache=s3db.cache, limitby=(0, 1)).first() if series: series_id = str(series.id) get_vars.pop("~.series_id$name") get_vars["~.series_id__belongs"] = series_id s3.crud_strings["cms_post"].title_list = title_list contact_field = settings.get_cms_person() org_field = settings.get_cms_organisation() org_group_field = settings.get_cms_organisation_group() show_events = settings.get_cms_show_events() hidden = not settings.get_cms_filter_open() from s3.s3filter import S3TextFilter, S3OptionsFilter, S3LocationFilter, S3DateFilter filter_widgets = [ S3TextFilter( ["body"], label=T("Search"), _class="filter-search", #_placeholder = T("Search").upper(), ), S3LocationFilter( "location_id", label=T("Filter by Location"), hidden=hidden, ), ] fappend = filter_widgets.append finsert = filter_widgets.insert if show_events: fappend( S3OptionsFilter( "event_post.event_id", label=T("Filter by Disaster"), hidden=hidden, )) if org_field: fappend( S3OptionsFilter( org_field, label=T("Filter by Organization"), # Can't use this for created_by as integer, use field.represent instead #represent = "%(name)s", hidden=hidden, )) if org_group_field: group_label = settings.get_org_groups() if group_label: fappend( S3OptionsFilter( org_group_field, label=T("Filter by %(type)s") % dict(type=T(group_label)), # Can't use this for created_by as integer, use field.represent instead #represent = "%(name)s", hidden=hidden, )) fappend( S3DateFilter( "date", label=T("Filter by Date"), hide_time=True, hidden=hidden, )) if settings.get_cms_show_tags(): finsert( 1, S3OptionsFilter( "tag_post.tag_id", label=T("Filter by Tag"), represent="%(name)s", hidden=hidden, )) if settings.get_cms_bookmarks() and auth.user: finsert( 1, S3OptionsFilter( "bookmark.user_id", label=T("Filter by Bookmark"), # Can't just use "" as this is then omitted from rendering options={ "*": T("All"), auth.user.id: T("My Bookmarks"), }, cols=2, multiple=False, hidden=hidden, )) notify_fields = [ (T("Date"), "date"), (T("Location"), "location_id"), ] len_series = db(stable.deleted == False).count() if len_series > 3: notify_fields.insert(0, (T("Type"), "series_id")) # Multiselect widget finsert( 1, S3OptionsFilter( "series_id", label=T("Filter by Type"), # We want translations #represent = "%(name)s", hidden=hidden, )) elif len_series > 1: notify_fields.insert(0, (T("Type"), "series_id")) # Checkboxes finsert( 1, S3OptionsFilter( "series_id", label=T("Filter by Type"), # We want translations #represent = "%(name)s", cols=2, hidden=hidden, )) else: # No Widget or notify_field pass nappend = notify_fields.append if org_field: nappend((T("Organization"), org_field)) if org_group_field: if isinstance(group_label, bool): group_label = T("Organisation Group") nappend((T(group_label), org_group_field)) if contact_field: nappend((T("Contact"), contact_field)) nappend((T("Description"), "body")) # @todo: allow configuration (?) filter_formstyle = settings.get_ui_formstyle() s3db.configure( "cms_post", # We could use a custom Advanced widget #filter_advanced = False, filter_formstyle=filter_formstyle, # No Submit button (done automatically) #filter_submit = (T("SEARCH"), "btn btn-primary"), filter_widgets=filter_widgets, # Default anyway now: #list_layout = s3db.cms_post_list_layout, # Create form comes via AJAX in a Modal #insertable = False, notify_fields=notify_fields, notify_template="notify_post", ) s3.dl_pagelength = 6 # 5 forces an AJAX call def prep(r): if r.interactive or r.representation == "aadata": s3db.cms_configure_newsfeed_post_fields() if r.interactive: if len_series > 1: refresh = get_vars.get("refresh", None) if refresh == "datalist": # We must be coming from the News Feed page so can change the type on-the-fly field = table.series_id field.label = T("Type") field.readable = field.writable = True else: field = table.series_id row = db(stable.deleted == False).select(stable.id, limitby=(0, 1)).first() try: field.default = row.id except: # Prepop not done: expose field to show error field.label = T("Type") field.readable = field.writable = True else: field.readable = field.writable = False if r.method == "read": # Restore the label for the Location table.location_id.label = T("Location") elif r.method == "create": pass # @ToDo: deployment_setting #if not auth.s3_has_role("ADMIN"): # represent = S3Represent(lookup="cms_series", # translate=settings.get_L10n_translate_cms_series()) # field.requires = IS_ONE_OF(db, # "cms_series.id", # represent, # not_filterby="name", # not_filter_opts = ("Alert",), # ) #field = table.name #field.readable = field.writable = False #field = table.title #field.readable = field.writable = False field = table.avatar field.default = True #field.readable = field.writable = False field = table.replies field.default = False #field.readable = field.writable = False field = table.body field.label = T("Description") # Plain text not Rich from s3.s3widgets import s3_comments_widget field.widget = s3_comments_widget #table.comments.readable = table.comments.writable = False #if request.controller == "default": # # Don't override card layout for News Feed/Homepage # return True from s3.s3forms import S3SQLCustomForm, S3SQLInlineComponent # Filter from a Profile page? # If so, then default the fields we know location_id = get_vars.get("~.(location)", None) if location_id: table.location_id.default = location_id event_id = get_vars.get("~.(event)", None) if event_id: def create_onaccept(form): table = current.s3db.event_post table.insert(event_id=event_id, post_id=form.vars.id) s3db.configure( "cms_post", create_onaccept=create_onaccept, ) crud_fields = [ "date", "series_id", ] cappend = crud_fields.append if settings.get_cms_show_titles(): cappend("title") crud_fields.extend(( "body", "location_id", )) if not event_id and show_events: cappend( S3SQLInlineComponent( "event_post", # @ToDo: deployment_setting (use same one used to activate?) #label = T("Disaster(s)"), label=T("Disaster"), multiple=False, fields=[("", "event_id")], orderby="event_id$name", )) if org_field == "post_organisation.organisation_id": cappend( S3SQLInlineComponent( "post_organisation", label=T("Organization"), fields=[("", "organisation_id")], # @ToDo: deployment_setting multiple=False, )) if org_group_field == "post_organisation_group.group_id": cappend( S3SQLInlineComponent( "post_organisation_group", label=T(group_label), fields=[("", "group_id")], # @ToDo: deployment_setting multiple=False, )) if contact_field == "person_id": cappend("person_id") if settings.get_cms_show_attachments(): cappend( S3SQLInlineComponent( "document", name="file", label=T("Files"), fields=[ ("", "file"), #"comments", ], )) if settings.get_cms_show_links(): cappend( S3SQLInlineComponent( "document", name="url", label=T("Links"), fields=[ ("", "url"), #"comments", ], )) crud_form = S3SQLCustomForm(*crud_fields) # Return to List view after create/update/delete # We now do all this in Popups #url_next = URL(c="default", f="index", args="newsfeed") s3db.configure( "cms_post", #create_next = url_next, #delete_next = url_next, #update_next = url_next, crud_form=crud_form, # Don't include a Create form in 'More' popups listadd=False, ) elif r.representation == "xls": table.body.represent = None table.created_by.represent = s3base.s3_auth_user_represent_name #table.created_on.represent = datetime_represent utable = auth.settings.table_user utable.organisation_id.represent = s3db.org_organisation_represent list_fields = [ (T("Date"), "date"), #(T("Disaster"), "event_post.event_id"), (T("Type"), "series_id"), (T("Details"), "body"), ] lappend = list_fields.append # Which levels of Hierarchy are we using? gis = current.gis levels = gis.get_relevant_hierarchy_levels() hierarchy = gis.get_location_hierarchy() for level in levels: lappend((hierarchy[level], "location_id$%s" % level)) if contact_field: lappend((T("Contact"), contact_field)) if org_field: lappend((T("Organization"), org_field)) if org_group_field: lappend((T(group_label), org_group_field)) s3db.configure( "cms_post", list_fields=list_fields, ) elif r.representation == "plain": # Map Popups table.location_id.represent = s3db.gis_LocationRepresent(sep=" | ") table.created_by.represent = s3base.s3_auth_user_represent_name # Used by default popups series = table.series_id.represent(r.record.series_id) s3.crud_strings[ "cms_post"].title_display = "%(series)s Details" % dict( series=series) s3db.configure( "cms_post", popup_url="", ) table.avatar.readable = False table.body.label = "" table.expired.readable = False table.replies.readable = False table.created_by.readable = True table.created_by.label = T("Author") # Used by cms_post_popup #table.created_on.represent = datetime_represent elif r.representation == "geojson": r.table.age = Field.Method("age", cms_post_age) return True s3.prep = prep def postp(r, output): if r.interactive: if r.method == "datalist" and r.representation != "dl": # Hide side menu current.menu.options = None response.view = s3base.S3CRUD._view(r, "cms/newsfeed.html") return output s3.postp = postp output = s3_rest_controller("cms", "post") return output
def homepage(): """ Custom Homepage - DataList of CMS Posts """ if not current.auth.is_logged_in(): return login() T = current.T s3db = current.s3db request = current.request response = current.response s3 = response.s3 current.deployment_settings.ui.customize_cms_post() list_layout = render_homepage_posts filter_widgets = [ S3TextFilter(["body"], label="", _class="filter-search", _placeholder=T("Search").upper()), S3OptionsFilter("series_id", label=T("Filter by Type"), represent="%(name)s", cols=3), S3OptionsFilter("location_id", label=T("Filter by Location"), represent="%(name)s", widget="multiselect", cols=3), S3OptionsFilter("created_by$organisation_id", label=T("Filter by Organization"), represent="%(name)s", widget="multiselect", cols=3), S3DateFilter("created_on", label=T("Filter by Date")), ] s3db.configure( "cms_post", filter_formstyle=filter_formstyle, filter_submit=(T("Filter Results"), "btn btn-primary"), filter_widgets=filter_widgets, list_layout=list_layout, ) s3.dl_pagelength = 6 # 5 forces an AJAX call if "datalist_dl_post" in request.args: ajax = True else: ajax = False def prep(r): if ajax: r.representation = "dl" return True s3.prep = prep request.args = ["datalist"] output = current.rest_controller("cms", "post", list_ajaxurl=URL(f="index", args="datalist_dl_post")) if ajax: response.view = "plain.html" else: form = output["form"] # Remove duplicate Submit button form[0][-1] = "" if form.errors: s3.jquery_ready.append('''$("#myModal").modal("show")''') # Set Title & View after REST Controller, in order to override output[ "title"] = response.title = current.deployment_settings.get_system_name( ) view = path.join(request.folder, "private", "templates", "CSN", "views", "index.html") try: # Pass view as file not str to work in compiled mode response.view = open(view, "rb") except IOError: from gluon.http import HTTP raise HTTP(404, "Unable to open Custom View: %s" % view) # Latest 5 Disasters resource = s3db.resource("event_event") list_fields = [ "name", "zero_hour", "closed", ] orderby = resource.get_config("list_orderby", ~resource.table.created_on) datalist, numrows, ids = resource.datalist( fields=list_fields, start=None, limit=5, list_id="event_datalist", orderby=orderby, layout=render_homepage_events) if numrows == 0: # Empty table or just no match? table = resource.table if "deleted" in table: available_records = current.db(table.deleted != True) else: available_records = current.db(table._id > 0) if available_records.select(table._id, limitby=(0, 1)).first(): msg = DIV(S3CRUD.crud_string(resource.tablename, "msg_no_match"), _class="empty") else: msg = DIV(S3CRUD.crud_string(resource.tablename, "msg_list_empty"), _class="empty") data = msg else: # Render the list dl = datalist.html() data = dl output["disasters"] = data return output
def _newsfeed(): """ Custom Page - Filterable DataList of CMS Posts & a DataList of Events """ #if not current.auth.is_logged_in(): # current.auth.permission.fail() T = current.T s3db = current.s3db request = current.request response = current.response s3 = response.s3 # Ensure that filtered views translate into options which update the Widget get_vars = request.get_vars if "~.series_id$name" in get_vars: series_name = get_vars["~.series_id$name"] table = s3db.cms_series series = current.db(table.name == series_name).select( table.id, limitby=(0, 1)).first() if series: series_id = str(series.id) get_vars.pop("~.series_id$name") get_vars["~.series_id__belongs"] = series_id current.deployment_settings.ui.customize_cms_post() list_layout = s3.render_posts filter_widgets = [ S3TextFilter( ["body"], label="", _class="filter-search", #_placeholder=T("Search").upper(), ), S3OptionsFilter( "series_id", label=T("Filter by Type"), represent="%(name)s", widget="multiselect", hidden=True, ), S3LocationFilter( "location_id", label=T("Filter by Location"), levels=["L1", "L2", "L3"], widget="multiselect", hidden=True, ), S3OptionsFilter( "created_by$organisation_id", label=T("Filter by Organization"), # Can't use this for integers, use field.represent instead #represent="%(name)s", widget="multiselect", hidden=True, ), S3DateFilter( "created_on", label=T("Filter by Date"), hide_time=True, hidden=True, ), ] s3db.configure( "cms_post", # We use a custom Advanced widget filter_advanced=False, filter_formstyle=filter_formstyle, filter_submit=(T("SEARCH"), "btn btn-primary"), filter_widgets=filter_widgets, list_layout=list_layout, # Create form comes via AJAX in a Modal insertable=False, notify_fields=[ (T("Type"), "series_id"), (T("Date"), "date"), (T("Location"), "location_id"), (T("Description"), "body"), ], notify_template="notify_post", ) s3.dl_pagelength = 6 # 5 forces an AJAX call old_args = request.args if "datalist_dl_post" in old_args: # DataList pagination or Ajax-deletion request request.args = ["datalist_f"] ajax = "list" elif "datalist_dl_filter" in old_args: # FilterForm options update request request.args = ["filter"] ajax = "filter" elif "validate.json" in old_args: # Inline component validation request request.args = [] ajax = True elif current.auth.permission.format == "msg": # Subscription lookup request request.args = [] ajax = True else: # Default request.args = ["datalist_f"] ajax = None def prep(r): if ajax == "list": r.representation = "dl" elif ajax == "filter": r.representation = "json" return True s3.prep = prep output = current.rest_controller( "cms", "post", list_ajaxurl=URL(f="index", args="datalist_dl_post"), filter_ajax_url=URL(f="index", args="datalist_dl_filter", vars={}), ) request.args = old_args if ajax == "list": # Don't override view if this is an Ajax-deletion request if not "delete" in request.get_vars: response.view = "plain.html" elif not ajax: # Set Title & View after REST Controller, in order to override output["title"] = T("News Feed") view = path.join(request.folder, "private", "templates", THEME, "views", "newsfeed.html") try: # Pass view as file not str to work in compiled mode response.view = open(view, "rb") except IOError: from gluon.http import HTTP raise HTTP(404, "Unable to open Custom View: %s" % view) s3.js_global.append('''i18n.adv_search="%s"''' % T("Advanced Search")) s3.scripts.append("/%s/static/themes/%s/js/newsfeed.js" % (request.application, THEME)) # Latest 5 Disasters resource = s3db.resource("event_event") layout = render_events list_id = "event_datalist" limit = 5 orderby = "zero_hour desc" list_fields = [ "name", "event_type_id$name", "zero_hour", "closed", ] output["disasters"] = latest_records(resource, layout, list_id, limit, list_fields, orderby) return output
def custom_prep(r): # Call standard prep if callable(standard_prep): result = standard_prep(r) if not result: return False if r.interactive: messages = current.messages from s3.s3filter import S3TextFilter, S3OptionsFilter, S3LocationFilter, S3DateFilter filter_widgets = [ S3TextFilter(["project_id$name", "project_id$code", "project_id$description", "location_id$name", "project_id$organisation.name", "project_id$organisation.acronym", ], label=T("Name"), _class="filter-search", ), S3OptionsFilter("project_id$status_id", label=T("Status"), represent="%(name)s", #widget="multiselect", cols=3, #hidden=True, ), S3OptionsFilter("project_id$theme_project.theme_id", label=T("Theme"), represent="%(name)s", widget="multiselect", cols=3, #hidden=True, ), S3LocationFilter("location_id", label=T("Location"), levels=["L1", "L2"], widget="multiselect", cols=3, #hidden=True, ), # @ToDo: Widget to handle Start & End in 1! S3DateFilter("start_date", label=T("Start Date"), hide_time=True, #hidden=True, ), S3DateFilter("end_date", label=T("End Date"), hide_time=True, #hidden=True, ), ] report_fields = [ #(messages.COUNTRY, "location_id$L0"), "location_id$L1", "location_id$L2", #"location_id$L3", #"location_id$L4", (messages.ORGANISATION, "project_id$organisation_id"), (T("Project"), "project_id"), #(T("Activity Types"), "activity_type.activity_type_id"), (T("Themes"), "project_id$theme.name"), ] report_options = Storage( rows=report_fields, cols=report_fields, fact=report_fields, defaults=Storage(rows="location_id$L2", #cols=(T("Themes"), "project_id$theme.name"), cols="project_id$theme.name", # T("Projects") fact="count(project_id$name)", totals=True ) ) current.s3db.configure("project_location", filter_widgets = filter_widgets, report_options = report_options, ) return True
def custom_prep(r): # Call standard prep if callable(standard_prep): result = standard_prep(r) else: result = True if r.interactive or r.representation == "aadata": from s3.s3forms import S3SQLCustomForm, S3SQLInlineComponent, S3SQLInlineComponentCheckbox s3db = current.s3db table = r.table tablename = "project_project" table.code.label = T("Project blurb (max. 100 characters)") table.code.max_length = 100 table.comments.label = T("How people can help") script = '''$('#project_project_code').attr('maxlength','100')''' s3.jquery_ready.append(script) crud_form = S3SQLCustomForm( "organisation_id", "name", "code", "description", "status_id", "start_date", "end_date", "calendar", #"drr.hfa", #"objectives", "human_resource_id", # Activities S3SQLInlineComponent( "location", label = T("Location"), fields = ["location_id"], ), # Partner Orgs S3SQLInlineComponent( "organisation", name = "partner", label = T("Partner Organizations"), fields = ["organisation_id", "comments", # NB This is labelled 'Role' in DRRPP ], filterby = dict(field = "role", options = "2" ) ), S3SQLInlineComponent( "document", name = "media", label = T("URLs (media, fundraising, website, social media, etc."), fields = ["document_id", "name", "url", "comments", ], filterby = dict(field = "name") ), S3SQLInlineComponentCheckbox( "activity_type", label = T("Categories"), field = "activity_type_id", cols = 3, # Filter Activity Type by Project filter = {"linktable": "project_activity_type_project", "lkey": "project_id", "rkey": "activity_type_id", }, ), #"budget", #"currency", "comments", ) from s3.s3filter import S3TextFilter, S3OptionsFilter, S3LocationFilter, S3DateFilter filter_widgets = [ S3TextFilter(["name", "code", "description", "organisation.name", "organisation.acronym", ], label=T("Name"), _class="filter-search", ), S3OptionsFilter("status_id", label=T("Status"), represent="%(name)s", cols=3, ), #S3OptionsFilter("theme_project.theme_id", # label=T("Theme"), # represent="%(name)s", # widget="multiselect", # #hidden=True, # ), S3LocationFilter("location.location_id", label=T("Location"), levels=["L1", "L2", "L3", "L4"], widget="multiselect", #hidden=True, ), # @ToDo: Widget to handle Start & End in 1! S3DateFilter("start_date", label=T("Start Date"), hide_time=True, #hidden=True, ), S3DateFilter("end_date", label=T("End Date"), hide_time=True, #hidden=True, ), ] list_fields = ["id", "name", "code", "organisation_id", "start_date", "end_date", (T("Locations"), "location.location_id"), ] s3db.configure(tablename, crud_form = crud_form, filter_widgets = filter_widgets, list_fields = list_fields, ) return result