WhakerKit 2.0

https://sourceforge.net/projects/whakerkit/

Module whakerkit.responses

Class DocsResponse

Description

The bake system for the page with all stored documents.

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)