The bake system for the page with all stored documents.
Module whakerkit.responses
Class DocsResponse
Description
Constructor
View Source
def __init__(self):
super(DocsResponse, self).__init__(name=None, title=get_msg(MSG_TITLE_TAB))
self.__doc_manager = WhakerKitDocsManager()
self.__doc_manager.collect_docs()
Public functions
create
Override. Create the page tree.
Set page name and add required js in the tree->head.
View Source
def create(self) -> None:
"""Override. Create the page tree.
Set page name and add required js in the tree->head.
"""
get_base_response_class().create(self)
self.set_pagename('documents.html')
js = 'application/javascript'
css = 'text/css'
self._htree.head.script(src=whakerkit.sg.whakerexa + 'js/sortatable.js', script_type=js)
self._htree.head.script(src=whakerkit.sg.whakerexa + 'js/toggleselect.js', script_type=js)
self._htree.head.link(rel='stylesheet', href=whakerkit.sg.whakerexa + 'css/sortatable.css', link_type=css)
self._htree.head.link(rel='stylesheet', href=whakerkit.sg.whakerexa + 'css/toggleselect.css', link_type=css)
self._htree.head.script(src=whakerkit.sg.whakerexa + 'js/dialog.js', script_type=js)
self._htree.head.script(src=whakerkit.sg.path + 'statics/js/doc_details.js', script_type='module')
self._htree.head.script(src=whakerkit.sg.path + 'statics/js/documents.js', script_type='module')
new_body_script = HTMLNode(self._htree.get_body_identifier(), 'body_script', 'script', value=BODY_SCRIPT)
new_body_script.add_attribute('type', 'module')
self._htree.set_body_script(new_body_script)
set_pagename
Set the name of this page as seen in the url.
Parameters
- page_name: (str) Name of the HTML page.
View Source
def set_pagename(self, page_name: str):
"""Set the name of this page as seen in the url.
:param page_name: (str) Name of the HTML page.
"""
self._page_name = page_name
get_all_filetypes
Get all file types.
Returns
- (list) File types
View Source
def get_all_filetypes(self):
"""Get all file types.
:return: (list) File types
"""
filetypes = [doc.filetype for doc in self.__doc_manager]
return list(set(filetypes))
get_all_authors
Get all authors.
Returns
- (list) Authors
View Source
def get_all_authors(self):
"""Get all authors.
:return: (list) Authors
"""
authors = sorted([doc.author for doc in self.__doc_manager])
counts = Counter(authors)
return [item for (item, count) in counts.most_common()]
get_filtered_documents
Return the serialized content with the list of filtered documents.
Parameters
- filters: (dict) the filters
- conditions: (dict) the conditions
Returns
- (str)
View Source
def get_filtered_documents(self, filters: dict, conditions: dict) -> str:
"""Return the serialized content with the list of filtered documents.
:param filters: (dict) the filters
:param conditions: (dict) the conditions
:return: (str)
"""
logging.debug(' ... Get all the filtered documents into an HTML table')
filters_match_all = conditions.get('general_condition', True)
descr_cond = conditions.get('description_condition', 'acontains')
descr_match_all = conditions.get('switch_description', True)
logging.debug(f' ... ... Filters: {filters}')
logging.debug(f' ... ... Match all filters (and): {filters_match_all} -> {type(filters_match_all)}')
logging.debug(f' ... ... Descr condition: {descr_cond}')
logging.debug(f' ... ... Description match all (and): {descr_match_all} -> {type(descr_match_all)}')
try:
docs = self.__filter_documents(filters, descr_cond, filters_match_all, descr_match_all)
manager = WhakerKitDocsManager()
manager.add_docs(docs)
div = HTMLNode(None, None, 'div')
self.__append_documents(div, manager, filtered=True)
except Exception as e:
logging.error(e)
self._data = {'error': 'Filter error. ' + str(e)}
else:
return div.serialize()
return ''
are_equals
Check if two lists contain the same elements, regardless of order.
Parameters
- l1: (list) First list of elements.
- l2: (list) Second list of elements.
Returns
- (bool) True if both lists contain the same elements, False otherwise.
View Source
@staticmethod
def are_equals(l1: list, l2: list) -> bool:
"""Check if two lists contain the same elements, regardless of order.
:param l1: (list) First list of elements.
:param l2: (list) Second list of elements.
:return: (bool) True if both lists contain the same elements, False otherwise.
"""
return set(l1) == set(l2)
Private functions
_process_events
Process the given events coming from the POST of any form.
Parameters
- events: (dict) the posted events
- kwargs: (dict) the keyword arguments
Returns
- (bool) True to bake the page, False otherwise
View Source
def _process_events(self, events: dict, **kwargs) -> bool:
"""Process the given events coming from the POST of any form.
:param events: (dict) the posted events
:param kwargs: (dict) the keyword arguments
:return: (bool) True to bake the page, False otherwise
"""
logging.debug(f'DocumentsResponse._process_events: {events.keys()}.')
self._status.code = 200
if 'event_name' in events:
if events['event_name'] == 'increment_downloads':
folder_name = events.get('folder_name', '')
if len(folder_name) > 0:
nb = self.__doc_manager.increment(folder_name)
self._data['downloads'] = nb
return False
elif events['event_name'] == 'filter_documents':
filters = events.get('filters', {})
if len(filters) > 0:
conditions = events.get('conditions', {})
content = self.get_filtered_documents(filters, conditions)
if len(content) > 0:
self._status.code = 200
self._data['content'] = content
else:
self._status.code = 400
return False
else:
logging.error('Requested to filter documents with no given filters!')
self._status.code = 400
self._data['error'] = 'Requested to filter documents with no given filters!'
return True
_bake
Create the dynamic content in the body->main of the page.
View Source
def _bake(self) -> None:
"""Create the dynamic content in the body->main of the page.
"""
h1 = self._htree.element('h1')
h1.set_value(get_msg(MSG_TITLE_DOCS))
self.__append_filters()
self.__append_hidden_dialogs()
div = self._htree.element('div')
div.set_attribute('id', 'documents_div')
self.__append_documents(div, self.__doc_manager)
Protected functions
__append_hidden_dialogs
Append the hidden dialogs for info and error.
View Source
def __append_hidden_dialogs(self):
"""Append the hidden dialogs for info and error.
"""
dlg = self._htree.element('dialog')
dlg.add_attribute('id', 'error_dialog')
dlg.add_attribute('role', 'alertdialog')
dlg.add_attribute('class', 'error hidden-alert')
dlg = self._htree.element('dialog')
dlg.add_attribute('id', 'info_dialog')
dlg.add_attribute('role', 'alertdialog')
dlg.add_attribute('class', 'info hidden-alert')
__append_filters
Append a section with filters for documents.
View Source
def __append_filters(self):
"""Append a section with filters for documents.
"""
docs_filter = WhakerKitFilterNode(self._htree.body_main.identifier, self.get_all_filetypes(), self.get_all_authors())
self._htree.body_main.append_child(docs_filter)
__append_documents
Append a section with the documents.
Parameters
- parent
- doc_manager
- filtered
View Source
@staticmethod
def __append_documents(parent: HTMLNode, doc_manager: WhakerKitDocsManager, filtered=False):
"""Append a section with the documents.
"""
p_value = get_msg(MSG_NB_DOCS.format(nb=len(doc_manager)))
if filtered is True:
p_value += get_msg(MSG_ARE_FILTERED)
p = HTMLNode(parent.identifier, None, 'p', value=p_value + '.')
parent.append_child(p)
selector = ToggleColumnsNode(parent.identifier)
parent.append_child(selector)
all_docs = DocumentsNode(parent.identifier, doc_manager)
parent.append_child(all_docs)
aside = WhakerKitDocAsideNode(parent.identifier)
parent.append_child(aside)
__filter_documents
Apply given filters to the list of documents of the document manager.
This method formats the given filters according to the expected format of the document manager and retrieves the filtered documents.
Parameters
- filters: (dict) the filters
- match_all: (bool) the general condition to match all criteria (True by default)
- descr_cond: (str) the description condition ("acontains" by default)
- matchalldescr: (str) must match all tokens in description (True by default)
Raises
- ValueError
- TypeError
Returns
- (list) List of filtered documents
View Source
def __filter_documents(self, filters: dict, descr_cond: str, match_all: bool=True, match_all_descr: bool=True) -> list:
"""Apply given filters to the list of documents of the document manager.
This method formats the given filters according to the expected
format of the document manager and retrieves the filtered documents.
:param filters: (dict) the filters
:param match_all: (bool) the general condition to match all criteria (True by default)
:param descr_cond: (str) the description condition ("acontains" by default)
:param match_all_descr: (str) must match all tokens in description (True by default)
:raises: ValueError:
:raises: TypeError:
:return: (list) List of filtered documents
"""
filetypes = filters['filetype']
authors = filters['authors']
if self.__check_filters(filetypes, authors) is False:
return list()
filtered_sets = list()
if self.are_equals(filetypes, self.get_all_filetypes()) is False:
filtered_sets.append(self.__filter_by_filetype(filetypes))
if self.are_equals(authors, self.get_all_authors()) is False:
filtered_sets.append(self.__filter_by_authors(authors))
if len(filters['dates']['start']) > 0 or len(filters['dates']['end']) > 0:
filtered_sets.append(self.__filter_by_dates(filters['dates']))
if len(filters['description'].strip()) > 0:
filtered_sets.append(self.__filter_by_description(filters['description'], descr_cond, match_all_descr))
if len(filtered_sets) == 0:
self._data = {'info': get_msg(MSG_NO_FILTER)}
return [d for d in self.__doc_manager]
filtered_docs = self.__merge_and_log(filtered_sets, match_all)
return [doc for doc in filtered_docs]
__merge_and_log
View Source
def __merge_and_log(self, filtered_sets: list, match_all: bool) -> FilteredSet:
if match_all is False:
f = FilteredSet()
for doc in self.__doc_manager:
f.append(doc)
filtered_sets.append(f)
logging.info(f'Merging filtered sets: {filtered_sets} ({len(filtered_sets)} filters), with match-all: {match_all}.')
filtered_docs = DocumentsFilters.merge_data(filtered_sets, match_all)
logging.info(f'Found {len(filtered_docs)} documents.')
if len(filtered_docs) == 0 or len(filtered_docs) == len(self.__doc_manager):
if len(filtered_docs) == 0:
self._data = {'info': get_msg(MSG_NO_DOC)}
logging.info('None of the documents is matching the filters.')
else:
self._data = {'info': get_msg(MSG_ALL_DOCS)}
logging.info('All documents are matching the filters.')
else:
logging.info(f'{len(self.__doc_manager)} documents are matching the filters.')
return filtered_docs
__check_filters
View Source
def __check_filters(self, filetypes: list, authors: list) -> bool:
if len(filetypes) == 0:
self._data = {'info': get_msg(MSG_NO_FILETYPE)}
return False
if len(authors) == 0:
self._data = {'info': get_msg(MSG_NO_AUTHOR)}
return False
return True
__filter_by_filetype
Filter documents by filetype.
Parameters
- selected_filetypes: (list) the selected filetypes to filter by
Returns
- (FilteredSet) Set of documents
View Source
def __filter_by_filetype(self, selected_filetypes: list) -> FilteredSet:
"""Filter documents by filetype.
:param selected_filetypes: (list) the selected filetypes to filter by
:return: (FilteredSet) Set of documents
"""
formatted_filters = [('filetype', 'iexact', selected_filetypes)]
logging.info(f'Applying filetype filters: {formatted_filters}.')
return self.__apply_filters(formatted_filters, False)
__filter_by_authors
Filter documents by authors.
Parameters
- selected_authors: (list) the selected authors to filter by
Returns
- (FilteredSet) Set of documents
View Source
def __filter_by_authors(self, selected_authors: list):
"""Filter documents by authors.
:param selected_authors: (list) the selected authors to filter by
:return: (FilteredSet) Set of documents
"""
formatted_filters = [('author', 'iexact', selected_authors)]
return self.__apply_filters(formatted_filters, False)
__filter_by_dates
Filter documents by date range.
Parameters
- date_filters: (dict) dictionary containing start and end dates
Returns
- (FilteredSet) Set of documents
View Source
def __filter_by_dates(self, date_filters: dict):
"""Filter documents by date range.
:param date_filters: (dict) dictionary containing start and end dates
:return: (FilteredSet) Set of documents
"""
formatted_filters = list()
if date_filters['start']:
formatted_filters.append(('date', 'ge', [f"{date_filters['start']}-01-01"]))
if date_filters['end']:
formatted_filters.append(('date', 'le', [f"{date_filters['end']}-12-31"]))
if len(formatted_filters) > 0:
return self.__apply_filters(formatted_filters, True)
return FilteredSet()
__filter_by_description
Filter documents by description.
Parameters
- description: (str) the description filter
- descr_cond: (str) the condition for filtering description
- matchalldescr: (bool) True if all tokens of the description should be matched
Returns
- Filtered set of documents or None if no filter applied
View Source
def __filter_by_description(self, description: str, descr_cond: str, match_all_descr: bool) -> FilteredSet:
"""Filter documents by description.
:param description: (str) the description filter
:param descr_cond: (str) the condition for filtering description
:param match_all_descr: (bool) True if all tokens of the description should be matched
:return: Filtered set of documents or None if no filter applied
"""
if descr_cond not in ('contains', 'not_contains'):
description = TypesDealer.remove_diacritics_and_non_ascii(description)
tokens = description.split(' ')
if match_all_descr is True:
filtered_set = None
for token in tokens:
formatted_filters = list()
formatted_filters.append(('filename', descr_cond, [token]))
formatted_filters.append(('description', descr_cond, [token]))
f = self.__apply_filters(formatted_filters, 'not' in descr_cond)
if filtered_set is None:
filtered_set = f
else:
filtered_set = f & filtered_set
if len(filtered_set) == 0:
return filtered_set
return filtered_set
else:
formatted_filters = list()
formatted_filters.append(('filename', descr_cond, tokens))
formatted_filters.append(('description', descr_cond, tokens))
return self.__apply_filters(formatted_filters, 'not' in descr_cond)
__apply_filters
View Source
def __apply_filters(self, formatted_filters, match_all):
logging.info(f'Apply filters: {formatted_filters}.')
return self.__doc_manager.filter_docs(formatted_filters, match_all, out_filterset=True)