class ProductView(ModelView): model_form_converter = MyCustomModelConverter #column_filters = ['name'] #column_searchable_list = ('name') form_subdocuments = { 'name': { 'form_subdocuments': { None: { # Add <hr> at the end of the form 'form_rules': ('lang', 'name', rules.HTML('<hr>')), 'form_widget_args': { 'name': { 'style': 'color: red' } } } } }, 'photo': { 'form_subdocuments': { None: { # Add <hr> at the end of the form 'form_rules': ('lang', 'order', 'photo', 'title', 'note', rules.HTML('<hr>')), } } } }
class PostView(AuthMixin, ModelView): edit_template = 'admin/model/ckeditor_edit.html' create_template = 'admin/model/ckeditor_edit.html' column_searchable_list = ( 'title', 'content', ) column_filters = ['published_date'] form_widget_args = {'content': {'class': 'ckeditor'}} form_subdocuments = { 'comments': { 'form_subdocuments': { None: { # Add <hr> at the end of the form 'form_rules': ('author', 'content', rules.HTML('<hr>')), 'form_widget_args': { 'content': { 'class': 'ckeditor' } } } } }, } form_ajax_refs = {'author': {'fields': ('email', ), 'page_size': 10}}
class PostView(ModelView): form_subdocuments = { 'inner': { 'form_subdocuments': { None: { # Add <hr> at the end of the form 'form_rules': ('name', 'tag', 'value', rules.HTML('<hr>')) } } } }
class PostView(ModelView): form_subdocuments = { 'inner': { 'form_subdocuments': { None: { # Add <hr> at the end of the form 'form_rules': ('name', 'tag', 'value', rules.HTML('<hr>')), 'form_widget_args': { 'name': { 'style': 'color: red' } } } } } }
class PreguntasView(MyView): """ Questions View. Entry view which lets teachers manage the questions in the system. """ column_exclude_list = ('usuario', 'verdadera', 'correcta') # default order for the records list column_default_sort = ('asignatura', 'num') # help text for some columns column_descriptions = dict( asignatura='Asignatura a la que corresponde la pregunta', tipo= 'Preguntas a desarrollar, test o preguntas de tipo verdadero o falso') # fields in which the search is performed column_searchable_list = ('texto', ) # choices for the column of the question type column_choices = { 'tipo': [(0, 'Desarrollo'), (1, 'Test'), (2, 'Verdadero o Falso')] } # options to show the subdocuments for column "opciones" form_subdocuments = { 'opciones': { 'form_subdocuments': { None: { # Add <hr> at the end of the form 'form_rules': ('letra', 'texto', rules.HTML('<hr>')), 'form_widget_args': { 'name': { 'style': 'color: red' } } } } } }
class SubmittedResourceView(AdminAuthMixin, ModelView): """ An administrative view for working with submitted resources pending administrator approval. """ can_view_details = True column_details_exclude_list = ('latitude', 'longitude', 'location', 'category_text', 'is_approved', 'visible', 'date_verified', 'overall_aggregate') # Disable model creation can_create = False # Allow exporting can_export = True export_max_rows = 0 column_export_list = ('name', 'organization', 'address', 'url', 'email', 'phone', 'fax', 'hours', 'hospital_affiliation', 'description', 'npi', 'categories', 'populations', 'is_icath', 'is_wpath', 'is_accessible', 'has_sliding_scale', 'submitted_user', 'submitted_date', 'submitted_ip', 'notes', 'advisory_notes', 'date_created', 'last_updated', 'id') column_formatters_export = resource_export_formatters column_list = ('name', 'organization', 'address', 'url', 'submitted_user', 'submitted_date') column_default_sort = 'submitted_date' column_sortable_list = ('name', 'organization', 'submitted_date', 'address', 'url', ('submitted_user', 'submitted_user.username')) column_searchable_list = ( 'name', 'description', 'organization', 'notes', 'advisory_notes', ) column_filters = ('submitted_date', ) form_excluded_columns = ('date_created', 'last_updated', 'category_text', 'reviews', 'aggregateratings', 'submitted_user', 'submitted_ip', 'submitted_date', 'is_approved', 'visible', 'source', 'overall_aggregate') edit_template = 'admin/submitted_resource_edit.html' # Use standard labels/descriptions/formatters column_labels = resource_column_labels column_descriptions = resource_column_descriptions column_formatters = resource_column_formatters form_extra_fields = { 'potential_dupes': StaticHtmlField('Detected'), 'submitted_user_text': StaticHtmlField(resource_column_labels['submitted_user']), 'submitted_ip_text': PlainTextField(resource_column_labels['submitted_ip']), 'submitted_date_text': PlainTextField(resource_column_labels['submitted_date']), 'review_rating': PlainTextField(review_column_labels['rating']), 'review_staff_rating': PlainTextField(review_column_labels['staff_rating']), 'review_intake_rating': PlainTextField(review_column_labels['intake_rating']), 'review_text': PlainTextField(review_column_labels['text']) } form_rules = [ rules.FieldSet( (rules.HTML('<hr />'), 'potential_dupes', rules.HTML('<hr />')), 'Potential Duplicates'), rules.FieldSet( (rules.HTML('<hr />'), 'name', 'organization', 'description', 'categories', 'populations', rules.HTML('<hr />')), 'Basic Information'), rules.FieldSet( (rules.HTML('<hr />'), 'address', 'latitude', 'longitude', 'location', 'phone', 'fax', 'email', 'url', 'hours', rules.HTML('<hr />')), 'Contact Information'), rules.FieldSet( (rules.HTML('<hr />'), 'hospital_affiliation', 'is_icath', 'is_wpath', 'is_accessible', 'has_sliding_scale', rules.HTML('<hr />')), 'Practice Information'), rules.FieldSet((rules.HTML('<hr />'), 'npi', 'date_verified', 'advisory_notes', 'notes', rules.HTML('<hr />')), 'Other'), rules.FieldSet( (rules.HTML('<hr />'), 'submitted_user_text', 'submitted_ip_text', 'submitted_date_text', rules.HTML('<hr />')), 'Submission Information'), rules.FieldSet( (rules.HTML('<hr />'), 'review_rating', 'review_staff_rating', 'review_intake_rating', 'review_text'), 'Review') ] def get_query(self): """ Returns the query for the model type. Returns: The query for the model type. """ query = self.session.query(self.model) return self.prepare_submitted_query(query) def get_count_query(self): """ Returns the count query for the model type. Returns: The count query for the model type. """ query = self.session.query(func.count('*')).select_from(self.model) return self.prepare_submitted_query(query) def prepare_submitted_query(self, query): """ Prepares the provided query by ensuring that only resources pending approval are included. Args: query: The query to update. Returns: The updated query. """ # Ensure a submission IP is defined query = query.filter(self.model.submitted_ip.isnot(None)) query = query.filter(self.model.submitted_ip != '') # Ensure that we're marked as visible and unapproved query = query.filter(self.model.visible == True) query = query.filter(self.model.is_approved == False) return query def edit_form(self, obj=None): """ Overrides the editing form to include additional read-only plain text and HTML fields regarding the submitted resource. """ form = super(SubmittedResourceView, self).edit_form(obj) # Try to detect duplicates based on matching names/NPIs dup_resources = self.session.query(Resource). \ filter(Resource.id != obj.id). \ filter(or_( and_( Resource.npi != '', Resource.npi.isnot(None), Resource.npi == obj.npi), Resource.name == obj.name.strip())). \ all() if len(dup_resources) > 0: # Build a list of potential duplicates with a link - # make sure we're escaping each item. form.potential_dupes.default = '<br />'.join([ get_resource_link(r) + ' (ID: ' + str(r.id) + ')' for r in dup_resources ]) else: form.potential_dupes.default = 'None' # Add read-only submission fields if obj.submitted_user is not None: # Get fancy and have a user link and email user_text = get_user_link(obj.submitted_user) + ' - ' + \ get_email_link( obj.submitted_user, 'Provider Submission - ' + obj.name) form.submitted_user_text.default = user_text else: form.submitted_user_text.default = 'Deleted User' form.submitted_ip_text.default = obj.submitted_ip form.submitted_date_text.default = obj.submitted_date # Add review fields review = obj.reviews.first() if review is not None: form.review_text.default = review.text form.review_rating.default = review.rating form.review_intake_rating.default = review.intake_rating form.review_staff_rating.default = review.staff_rating return form def scaffold_form(self): """ Scaffolds the creation/editing form so that the latitude and longitude fields are optional, but can still be set by the Google Places API integration. """ form_class = super(SubmittedResourceView, self).scaffold_form() # Scaffold our default stuff form_class = scaffold_resource_form(form_class) return form_class def on_model_change(self, form, model, is_created): """ Ensures that fields are updated in response to specific approval/rejection actions. Also updates the last_updated date on the provided model if is_created is false. """ if not is_created: model.last_updated = datetime.utcnow() # If we're approving, mark the resource as approved # and update the verified date. # If we're rejecting, mark the resource as hidden. if '_approve_resource' in request.form: model.is_approved = True model.date_verified = date.today() elif '_reject_resource' in request.form: model.visible = False def __init__(self, session, **kwargs): super(SubmittedResourceView, self).__init__(Resource, session, **kwargs)
class ResourceView(AdminAuthMixin, ModelView): """ An administrative view for working with resources. """ can_view_details = True column_details_exclude_list = ('latitude', 'longitude', 'location', 'category_text', 'overall_aggregate') # Allow exporting can_export = True export_max_rows = 0 column_export_list = ('name', 'organization', 'address', 'url', 'email', 'phone', 'fax', 'hours', 'hospital_affiliation', 'description', 'npi', 'categories', 'populations', 'is_icath', 'is_wpath', 'is_accessible', 'has_sliding_scale', 'visible', 'advisory_notes', 'is_approved', 'submitted_user', 'submitted_date', 'submitted_ip', 'source', 'notes', 'date_created', 'last_updated', 'date_verified', 'id') column_formatters_export = resource_export_formatters column_list = ('name', 'organization', 'address', 'url', 'source', 'last_updated') column_default_sort = 'name' column_searchable_list = ( 'name', 'description', 'organization', 'notes', 'advisory_notes', ) # By default, Flask-Admin isn't going to pick up on the fact # that our flags are nullable. Therefore, we need to manually # add FilterEmpty options. These use names identical to the # column labels for the normal filters so that they are # appropriately grouped. column_filters = ( 'visible', 'is_approved', 'source', 'npi', 'date_created', 'last_updated', 'date_verified', FilterEmpty(Resource.is_icath, 'Informed Consent/ICATH'), 'is_icath', FilterEmpty(Resource.is_wpath, 'WPATH'), 'is_wpath', FilterEmpty(Resource.is_accessible, 'ADA/Wheelchair Accessible'), 'is_accessible', FilterEmpty(Resource.has_sliding_scale, 'Sliding Scale'), 'has_sliding_scale', 'advisory_notes', ) form_excluded_columns = ('date_created', 'last_updated', 'category_text', 'reviews', 'aggregateratings', 'submitted_user', 'submitted_ip', 'submitted_date', 'is_approved', 'overall_aggregate') form_rules = [ rules.FieldSet( (rules.HTML('<hr />'), 'name', 'organization', 'description', 'categories', 'populations', 'visible', rules.HTML('<hr />')), 'Basic Information'), rules.FieldSet( (rules.HTML('<hr />'), 'address', 'latitude', 'longitude', 'location', 'phone', 'fax', 'email', 'url', 'hours', rules.HTML('<hr />')), 'Contact Information'), rules.FieldSet( (rules.HTML('<hr />'), 'hospital_affiliation', 'is_icath', 'is_wpath', 'is_accessible', 'has_sliding_scale', rules.HTML('<hr />')), 'Practice Information'), rules.FieldSet((rules.HTML('<hr />'), 'npi', 'date_verified', 'advisory_notes', 'notes', 'source'), 'Other') ] create_template = 'admin/resource_create.html' edit_template = 'admin/resource_edit.html' # Use standard labels/descriptions/formatters column_labels = resource_column_labels column_descriptions = resource_column_descriptions column_formatters = resource_column_formatters def edit_form(self, obj=None): """ Overrides the editing form to disable toggling active status on unapproved resources. """ form = super(ResourceView, self).edit_form(obj) # HACK: Indicate we shouldn't change the "Visible" field # if we're attempting to edit an unapproved resource. if obj is not None and not obj.is_approved: form.visible.description = \ 'Visibility should not be changed for unapproved resources.' return form def scaffold_form(self): """ Scaffolds the creation/editing form so that the latitude and longitude fields are optional, but can still be set by the Google Places API integration. """ form_class = super(ResourceView, self).scaffold_form() # Scaffold our default stuff form_class = scaffold_resource_form(form_class) return form_class def on_model_change(self, form, model, is_created): """ Updates the last_updated date on the provided model if is_created is false. """ if not is_created: model.last_updated = datetime.utcnow() @action('togglevisible', 'Toggle Visibility', 'Are you sure you wish to toggle visibility ' + 'for the selected resources?') def action_togglevisible(self, ids): """ Attempts to toggle visibility for each of the specified resources. Args: ids: The list of resource IDs, indicating which resources should have their visibility toggled. """ # Load all resources by the set of IDs - also, only # allow this for approved resources target_resources = self.get_query(). \ filter(self.model.id.in_(ids)). \ filter(self.model.is_approved == True). \ all() # Build a list of all the results results = [] if len(target_resources) > 0: for resource in target_resources: # Build a helpful message string to use for messages. resource_str = 'resource #' + str(resource.id) + \ ' (' + resource.name + ')' visible_status = '' try: if not resource.visible: resource.visible = True visible_status = ' as visible' else: resource.visible = False visible_status = ' as not visible' resource.last_updated = datetime.utcnow() except Exception as ex: results.append('Error changing ' + resource_str + ': ' + str(ex)) else: results.append('Marked ' + resource_str + visible_status + '.') # Save our changes. self.session.commit() else: results.append('No resources were selected.') # Flash the results of everything flash("\n".join(msg for msg in results)) @action('markverified', 'Mark Verified', 'Are you sure you wish to mark the selected resources as verified?' ) def action_markverified(self, ids): """ Attempts to mark each of the specified resources as verified on the current date. Args: ids: The list of resource IDs, indicating which resources should be marked as verified. """ # Load all resources by the set of IDs target_resources = self.get_query(). \ filter(self.model.id.in_(ids)).all() # Build a list of all the results results = [] if len(target_resources) > 0: for resource in target_resources: # Build a helpful message string to use for messages. resource_str = 'resource #' + str(resource.id) + \ ' (' + resource.name + ')' try: resource.date_verified = date.today() resource.last_updated = datetime.utcnow() except Exception as ex: results.append('Error changing ' + resource_str + ': ' + str(ex)) else: results.append('Marked ' + resource_str + ' as verified.') # Save our changes. self.session.commit() else: results.append('No resources were selected.') # Flash the results of everything flash("\n".join(msg for msg in results)) @action('assigncategories', 'Assign Categories') def action_assigncategories(self, ids): """ Sets up a redirection action for mass-assigning categories to the specified resources. Args: ids: The list of resource IDs that should be updated. """ return_url = get_redirect_target() or self.get_url('.index_view') return redirect( self.get_url('resourcecategoryassignview.index', url=return_url, ids=ids)) @action('assignpopulations', 'Assign Populations') def action_assignpopulations(self, ids): """ Sets up a redirection action for mass-assigning populations to the specified resources. Args: ids: The list of resource IDs that should be updated. """ return_url = get_redirect_target() or self.get_url('.index_view') return redirect( self.get_url('resourcepopulationassignview.index', url=return_url, ids=ids)) def __init__(self, session, **kwargs): super(ResourceView, self).__init__(Resource, session, **kwargs)