diff --git a/modules/bibclassify/lib/bibclassify_engine.py b/modules/bibclassify/lib/bibclassify_engine.py index a230c49b3..c89210b79 100644 --- a/modules/bibclassify/lib/bibclassify_engine.py +++ b/modules/bibclassify/lib/bibclassify_engine.py @@ -1,693 +1,701 @@ ## This file is part of Invenio. ## Copyright (C) 2008, 2009, 2010, 2011, 2012 CERN. ## ## Invenio is free software; you can redistribute it and/or ## modify it under the terms of the GNU General Public License as ## published by the Free Software Foundation; either version 2 of the ## License, or (at your option) any later version. ## ## Invenio is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. """ BibClassify engine. This module is the main module of BibClassify. its two main methods are output_keywords_for_sources and get_keywords_from_text. The first one output keywords for a list of sources (local files or URLs, PDF or text) while the second one outputs the keywords for text lines (which are obtained using the module bibclassify_text_normalizer). This module also takes care of the different outputs (text, MARCXML or HTML). But unfortunately there is a confusion between running in a standalone mode and producing output suitable for printing, and running in a web-based mode where the webtemplate is used. For the moment the pieces of the representation code are left in this module. This module is STANDALONE safe """ import os import random import sys import time +import cgi import bibclassify_config as bconfig log = bconfig.get_logger("bibclassify.engine") import bibclassify_ontology_reader as reader import bibclassify_text_extractor as extractor import bibclassify_text_normalizer as normalizer import bibclassify_keyword_analyzer as keyworder import bibclassify_acronym_analyzer as acronymer try: from invenio.urlutils import make_user_agent_string except ImportError: ## Not in Invenio, we simply use default agent def make_user_agent_string(component=None): return bconfig.CFG_BIBCLASSIFY_USER_AGENT +try: + from invenio.textutils import encode_for_xml +except ImportError: + ## Not in Invenio, we use a simple workaround + encode_for_xml = lambda text: text.replace('&', '&').replace('<', '<') + # --------------------------------------------------------------------- # API # --------------------------------------------------------------------- def output_keywords_for_sources(input_sources, taxonomy_name, output_mode="text", output_limit=bconfig.CFG_BIBCLASSIFY_DEFAULT_OUTPUT_NUMBER, spires=False, match_mode="full", no_cache=False, with_author_keywords=False, rebuild_cache=False, only_core_tags=False, extract_acronyms=False, **kwargs): """Outputs the keywords for each source in sources.""" # Inner function which does the job and it would be too much work to # refactor the call (and it must be outside the loop, before it did # not process multiple files) def process_lines(): if output_mode == "text": print "Input file: %s" % source output = get_keywords_from_text(text_lines, taxonomy_name, output_mode=output_mode, output_limit=output_limit, spires=spires, match_mode=match_mode, no_cache=no_cache, with_author_keywords=with_author_keywords, rebuild_cache=rebuild_cache, only_core_tags=only_core_tags, extract_acronyms=extract_acronyms ) print output # Get the fulltext for each source. for entry in input_sources: log.info("Trying to read input file %s." % entry) text_lines = None source = "" if os.path.isdir(entry): for filename in os.listdir(entry): filename = os.path.join(entry, filename) if os.path.isfile(filename): text_lines = extractor.text_lines_from_local_file(filename) if text_lines: source = filename process_lines() elif os.path.isfile(entry): text_lines = extractor.text_lines_from_local_file(entry) if text_lines: source = os.path.basename(entry) process_lines() else: # Treat as a URL. text_lines = extractor.text_lines_from_url(entry, user_agent=make_user_agent_string("BibClassify")) if text_lines: source = entry.split("/")[-1] process_lines() def get_keywords_from_local_file(local_file, taxonomy_name, output_mode="text", output_limit=bconfig.CFG_BIBCLASSIFY_DEFAULT_OUTPUT_NUMBER, spires=False, match_mode="full", no_cache=False, with_author_keywords=False, rebuild_cache=False, only_core_tags=False, extract_acronyms=False, **kwargs ): """Outputs keywords reading a local file. Arguments and output are the same as for @see: get_keywords_from_text() """ log.info("Analyzing keywords for local file %s." % local_file) text_lines = extractor.text_lines_from_local_file(local_file) return get_keywords_from_text(text_lines, taxonomy_name, output_mode=output_mode, output_limit=output_limit, spires=spires, match_mode=match_mode, no_cache=no_cache, with_author_keywords=with_author_keywords, rebuild_cache=rebuild_cache, only_core_tags=only_core_tags, extract_acronyms=extract_acronyms) def get_keywords_from_text(text_lines, taxonomy_name, output_mode="text", output_limit=bconfig.CFG_BIBCLASSIFY_DEFAULT_OUTPUT_NUMBER, spires=False, match_mode="full", no_cache=False, with_author_keywords=False, rebuild_cache=False, only_core_tags=False, extract_acronyms=False, **kwargs): """Extracts keywords from the list of strings @var text_lines: list of strings (will be normalized before being joined into one string) @keyword taxonomy_name: string, name of the taxonomy_name @keyword output_mode: string - text|html|marcxml|raw @keyword output_limit: int @keyword spires: boolean, if True marcxml output reflect spires codes @keyword match_mode: str - partial|full; in partial mode only beginning of the fulltext is searched @keyword no_cache: boolean, means loaded definitions will not be saved @keyword with_author_keywords: boolean, extract keywords from the pdfs @keyword rebuild_cache: boolean @keyword only_core_tags: boolean @return: if output_mode=raw, it will return (single_keywords, composite_keywords, author_keywords, acronyms) for other output modes it returns formatted string """ start_time = time.time() cache = reader.get_cache(taxonomy_name) if not cache: reader.set_cache(taxonomy_name, reader.get_regular_expressions(taxonomy_name, rebuild=rebuild_cache, no_cache=no_cache)) cache = reader.get_cache(taxonomy_name) _skw = cache[0] _ckw = cache[1] text_lines = normalizer.cut_references(text_lines) fulltext = normalizer.normalize_fulltext("\n".join(text_lines)) if match_mode == "partial": fulltext = _get_partial_text(fulltext) author_keywords = None if with_author_keywords: author_keywords = extract_author_keywords(_skw, _ckw, fulltext) acronyms = {} if extract_acronyms: acronyms = extract_abbreviations(fulltext) single_keywords = extract_single_keywords(_skw, fulltext) composite_keywords = extract_composite_keywords(_ckw, fulltext, single_keywords) if only_core_tags: single_keywords = clean_before_output(_filter_core_keywors(single_keywords)) composite_keywords = _filter_core_keywors(composite_keywords) else: # Filter out the "nonstandalone" keywords single_keywords = clean_before_output(single_keywords) log.info('Keywords generated in: %.1f sec' % (time.time() - start_time)) if output_mode == "raw": if output_limit: return (_kw(_sort_kw_matches(single_keywords, output_limit)), _kw(_sort_kw_matches(composite_keywords, output_limit)), author_keywords, # this we don't limit (?) _kw(_sort_kw_matches(acronyms, output_limit))) else: return (single_keywords, composite_keywords, author_keywords, acronyms) else: return get_keywords_output(single_keywords, composite_keywords, taxonomy_name, author_keywords, acronyms, output_mode, output_limit, spires, only_core_tags) def extract_single_keywords(skw_db, fulltext): """Find single keywords in the fulltext @var skw_db: list of KeywordToken objects @var fulltext: string, which will be searched @return : dictionary of matches in a format { , [[position, position...], ], .. } or empty {} """ return keyworder.get_single_keywords(skw_db, fulltext) or {} def extract_composite_keywords(ckw_db, fulltext, skw_spans): """Returns a list of composite keywords bound with the number of occurrences found in the text string. @var ckw_db: list of KewordToken objects (they are supposed to be composite ones) @var fulltext: string to search in @skw_spans: dictionary of already identified single keywords @return : dictionary of matches in a format { , [[position, position...], [info_about_matches] ], .. } or empty {} """ return keyworder.get_composite_keywords(ckw_db, fulltext, skw_spans) or {} def extract_abbreviations(fulltext): """Extract acronyms from the fulltext @var fulltext: utf-8 string @return: dictionary of matches in a formt { , [matched skw or ckw object, ....] } or empty {} """ acronyms = {} K = reader.KeywordToken for k, v in acronymer.get_acronyms(fulltext).items(): acronyms[K(k, type='acronym')] = v return acronyms def extract_author_keywords(skw_db, ckw_db, fulltext): """Finds out human defined keyowrds in a text string. Searches for the string "Keywords:" and its declinations and matches the following words. @var skw_db: list single kw object @var ckw_db: list of composite kw objects @var fulltext: utf-8 string @return: dictionary of matches in a formt { , [matched skw or ckw object, ....] } or empty {} """ akw = {} K = reader.KeywordToken for k, v in keyworder.get_author_keywords(skw_db, ckw_db, fulltext).items(): akw[K(k, type='author-kw')] = v return akw # --------------------------------------------------------------------- # presentation functions # --------------------------------------------------------------------- def get_keywords_output(single_keywords, composite_keywords, taxonomy_name, author_keywords=None, acronyms=None, style="text", output_limit=0, spires=False, only_core_tags=False): """Returns a formatted string representing the keywords according to the chosen style. This is the main routing call, this function will also strip unwanted keywords before output and limits the number of returned keywords @var single_keywords: list of single keywords @var composite_keywords: list of composite keywords @var taxonomy_name: string, taxonomy name @keyword author_keywords: dictionary of author keywords extracted from fulltext @keyword acronyms: dictionary of extracted acronyms @keyword style: text|html|marc @keyword output_limit: int, number of maximum keywords printed (it applies to single and composite keywords separately) @keyword spires: boolen meaning spires output style @keyword only_core_tags: boolean """ # sort the keywords, but don't limit them (that will be done later) single_keywords = _sort_kw_matches(single_keywords) composite_keywords = _sort_kw_matches(composite_keywords) if style == "text": return _output_text(single_keywords, composite_keywords, author_keywords, acronyms, spires, only_core_tags, limit=output_limit) elif style == "marcxml": return _output_marc(single_keywords, composite_keywords, author_keywords, acronyms) elif style == "html": return _output_html(single_keywords, composite_keywords, author_keywords, acronyms, spires, taxonomy_name, limit=output_limit) def build_marc(recid, single_keywords, composite_keywords, spires=False, author_keywords=None, acronyms=None): """Creates xml record @recid: ingeter @var single_keywords: dictionary of kws @var composite_keywords: dictionary of kws @keyword spires: please don't use, left for historical reasons @keyword author_keywords: dictionary of extracted keywords @keyword acronyms: dictionary of extracted acronyms @return: str, marxml """ output = ['\n' '%s' % recid] # no need to sort single_keywords = single_keywords.items() composite_keywords = composite_keywords.items() output.append(_output_marc(single_keywords, composite_keywords, author_keywords, acronyms)) output.append('') return '\n'.join(output) def _output_marc(skw_matches, ckw_matches, author_keywords, acronyms, spires=False, kw_field=bconfig.CFG_MAIN_FIELD, auth_field=bconfig.CFG_AUTH_FIELD, acro_field=bconfig.CFG_ACRON_FIELD, provenience='BibClassify'): """Outputs the keywords in the MARCXML format. @var skw_matches: list of single keywords @var ckw_matches: list of composite keywords @var author_keywords: dictionary of extracted author keywords @var acronyms: dictionary of acronyms @var spires: boolean, True=generate spires output - BUT NOTE: it is here only not to break compatibility, in fact spires output should never be used for xml because if we read marc back into the KeywordToken objects, we would not find them @keyword provenience: string that identifies source (authority) that assigned the contents of the field @return: string, formatted MARC""" kw_template = ('\n' ' %s\n' ' %s\n' ' %s\n' ' %s\n' '\n') output = [] tag, ind1, ind2 = _parse_marc_code(kw_field) for keywords in (skw_matches, ckw_matches): if keywords and len(keywords): for kw, info in keywords: - output.append(kw_template % (tag, ind1, ind2, provenience, - kw.output(spires), len(info[0]), kw.getType())) + output.append(kw_template % (tag, ind1, ind2, encode_for_xml(provenience), + encode_for_xml(kw.output(spires)), len(info[0]), + encode_for_xml(kw.getType()))) for field, keywords in ((auth_field, author_keywords), (acro_field, acronyms)): if keywords and len(keywords) and field: # field='' we shall not save the keywords tag, ind1, ind2 = _parse_marc_code(field) for kw, info in keywords.items(): - output.append(kw_template % (tag, ind1, ind2, provenience, - kw, '', kw.getType())) + output.append(kw_template % (tag, ind1, ind2, encode_for_xml(provenience), + encode_for_xml(kw), '', encode_for_xml(kw.getType()))) return "".join(output) def _output_text(skw_matches=None, ckw_matches=None, author_keywords=None, acronyms=None, spires=False, only_core_tags=False, limit=bconfig.CFG_BIBCLASSIFY_DEFAULT_OUTPUT_NUMBER): """Outputs the results obtained in text format. @var skw_matches: sorted list of single keywords @var ckw_matches: sorted list of composite keywords @var author_keywords: dictionary of author keywords @var acronyms: dictionary of acronyms @var spires: boolean @var only_core_tags: boolean @keyword limit: int, number of printed keywords @return: str, html formatted output """ output = [] if limit: resized_skw = skw_matches[0:limit] resized_ckw = ckw_matches[0:limit] else: resized_skw = skw_matches resized_ckw = ckw_matches if only_core_tags: output.append('\nCore keywords:\n' + '\n'.join(_get_core_keywords(skw_matches, ckw_matches, spires=spires) or ['--'])) else: output.append('\nAuthor keywords:\n' + '\n'.join(_get_author_keywords(author_keywords, spires=spires) or ['--'])) output.append('\nComposite keywords:\n' + '\n'.join(_get_compositekws(resized_ckw, spires=spires) or ['--'])) output.append('\nSingle keywords:\n' + '\n'.join(_get_singlekws(resized_skw, spires=spires) or ['--'])) output.append('\nCore keywords:\n' + '\n'.join(_get_core_keywords(skw_matches, ckw_matches, spires=spires) or ['--'])) output.append('\nField codes:\n' + '\n'.join(_get_fieldcodes(resized_skw, resized_ckw, spires=spires) or ['--'])) output.append('\nAcronyms:\n' + '\n'.join(_get_acronyms(acronyms) or ['--'])) output.append('\n--\n%s' % _signature()) return "\n".join(output) + "\n" def _output_html(skw_matches=None, ckw_matches=None, author_keywords=None, acronyms=None, spires=False, only_core_tags=False, limit=bconfig.CFG_BIBCLASSIFY_DEFAULT_OUTPUT_NUMBER): """Output the same as txt output does, but HTML formatted @var skw_matches: sorted list of single keywords @var ckw_matches: sorted list of composite keywords @var author_keywords: dictionary of extracted author keywords @var acronyms: dictionary of acronyms @var spires: boolean @var only_core_tags: boolean @keyword limit: int, number of printed keywords @return: str, html formatted output """ output = _output_text(skw_matches, ckw_matches, author_keywords, acronyms, spires, only_core_tags, limit) output = output.replace('\n', '
') return """ Automatically generated keywords by bibclassify %s """ % output def _get_singlekws(skw_matches, spires=False): """ @var skw_matches: dict of {keyword: [info,...]} @keyword spires: bool, to get the spires output @return: list of formatted keywords """ output = [] for single_keyword, info in skw_matches: output.append("%d %s" % (len(info[0]), single_keyword.output(spires))) return output def _get_compositekws(ckw_matches, spires=False): """ @var ckw_matches: dict of {keyword: [info,...]} @keyword spires: bool, to get the spires output @return: list of formatted keywords """ output = [] for composite_keyword, info in ckw_matches: output.append("%d %s %s" % (len(info[0]), composite_keyword.output(spires), info[1])) return output def _get_acronyms(acronyms): """Returns a formatted list of acronyms.""" acronyms_str = [] if acronyms: for acronym, expansions in acronyms.iteritems(): expansions_str = ", ".join(["%s (%d)" % expansion for expansion in expansions]) acronyms_str.append("%s %s" % (acronym, expansions_str)) return sorted(acronyms_str) def _get_author_keywords(author_keywords, spires=False): """Formats the output for the author keywords. @return: list of formatted author keywors """ out = [] if author_keywords: for keyword, matches in author_keywords.items(): skw_matches = matches[0] #dictionary of single keywords ckw_matches = matches[1] #dict of composite keywords matches_str = [] for ckw, spans in ckw_matches.items(): matches_str.append('"%s"' % ckw.output(spires)) for skw, spans in skw_matches.items(): matches_str.append('"%s"' % skw.output(spires)) if matches_str: out.append('"%s" matches %s' % (keyword, ", ".join(matches_str))) else: out.append('"%s" matches no keyword.' % keyword) return sorted(out) def _get_fieldcodes(skw_matches, ckw_matches, spires=False): """Returns the output for the field codes. @var skw_matches: dict of {keyword: [info,...]} @var ckw_matches: dict of {keyword: [info,...]} @keyword spires: bool, to get the spires output @return: string""" fieldcodes = {} output = [] for skw, _ in skw_matches: for fieldcode in skw.fieldcodes: fieldcodes.setdefault(fieldcode, set()).add(skw.output(spires)) for ckw, _ in ckw_matches: if len(ckw.fieldcodes): for fieldcode in ckw.fieldcodes: fieldcodes.setdefault(fieldcode, set()).add(ckw.output(spires)) else: #inherit field-codes from the composites for kw in ckw.getComponents(): for fieldcode in kw.fieldcodes: fieldcodes.setdefault(fieldcode, set()).add('%s*' % ckw.output(spires)) fieldcodes.setdefault('*', set()).add(kw.output(spires)) for fieldcode, keywords in fieldcodes.items(): output.append('%s: %s' % (fieldcode, ', '.join(keywords))) return sorted(output) def _get_core_keywords(skw_matches, ckw_matches, spires=False): """Returns the output for the field codes. @var skw_matches: dict of {keyword: [info,...]} @var ckw_matches: dict of {keyword: [info,...]} @keyword spires: bool, to get the spires output @return: set of formatted core keywords """ output = set() def _get_value_kw(kw): '''Inner function to help to sort the Core keywords''' i = 0 while kw[i].isdigit(): i += 1 if i > 0: return int(kw[:i]) else: return 0 for skw, info in skw_matches: if skw.core: output.add('%d %s' % (len(info[0]), skw.output(spires))) for ckw, info in ckw_matches: if ckw.core: output.add('%d %s' % (len(info[0]), ckw.output(spires))) else: #test if one of the components is not core i = 0 for c in ckw.getComponents(): if c.core: output.add('- %s (%s)' % (c.output(spires), info[1][i])) i += 1 return sorted(output, key=_get_value_kw , reverse=True) def _filter_core_keywors(keywords): matches = {} for kw, info in keywords.items(): if kw.core: matches[kw] = info return matches def _signature(): """Prints out the bibclassify signature @todo: add information about taxonomy, rdflib""" return 'bibclassify v%s' % (bconfig.VERSION,) def clean_before_output(kw_matches): """Returns a clean copy of the keywords data structure - ie. stripped off the standalone and other unwanted elements""" filtered_kw_matches = {} for kw_match, info in kw_matches.iteritems(): if not kw_match.nostandalone: filtered_kw_matches[kw_match] = info return filtered_kw_matches # --------------------------------------------------------------------- # helper functions # --------------------------------------------------------------------- def _skw_matches_comparator(kw0, kw1): """ Compares 2 single keywords objects - first by the number of their spans (ie. how many times they were found), if it is equal it compares them by lenghts of their labels. """ list_comparison = cmp(len(kw1[1][0]), len(kw0[1][0])) if list_comparison: return list_comparison if kw0[0].isComposite() and kw1[0].isComposite(): component_avg0 = sum(kw0[1][1]) / len(kw0[1][1]) component_avg1 = sum(kw1[1][1]) / len(kw1[1][1]) component_comparison = cmp(component_avg1, component_avg0) if component_comparison: return component_comparison return cmp(len(str(kw1[0])), len(str(kw0[0]))) def _kw(keywords): """Turns list of keywords into dictionary""" r = {} for k,v in keywords: r[k] = v return r def _sort_kw_matches(skw_matches, limit=0): """Returns a resized version of data structures of keywords to the given length.""" sorted_keywords = list(skw_matches.items()) sorted_keywords.sort(_skw_matches_comparator) return limit and sorted_keywords[:limit] or sorted_keywords def _get_partial_text(fulltext): """Returns a shortened version of the fulltext used with the partial matching mode. The version is composed of 20% in the beginning and 20% in the middle of the text.""" length = len(fulltext) get_index = lambda x: int(float(x) / 100 * length) partial_text = [fulltext[get_index(start):get_index(end)] for start, end in bconfig.CFG_BIBCLASSIFY_PARTIAL_TEXT] return "\n".join(partial_text) def save_keywords(filename, xml): tmp_dir = os.path.dirname(filename) if not os.path.isdir(tmp_dir): os.mkdir(tmp_dir) file_desc = open(filename, "w") file_desc.write(xml) file_desc.close() def get_tmp_file(recid): tmp_directory = "%s/bibclassify" % bconfig.CFG_TMPDIR if not os.path.isdir(tmp_directory): os.mkdir(tmp_directory) filename = "bibclassify_%s.xml" % recid abs_path = os.path.join(tmp_directory, filename) return abs_path def _parse_marc_code(field): """Parses marc field and return default indicators if not filled in""" field = str(field) if len(field) < 4: raise Exception ('Wrong field code: %s' % field) else: field += '__' tag = field[0:3] ind1 = field[3].replace('_', '') ind2 = field[4].replace('_', '') return tag, ind1, ind2 if __name__ == "__main__": log.error("Please use bibclassify_cli from now on.") diff --git a/modules/bibclassify/lib/bibclassify_templates.py b/modules/bibclassify/lib/bibclassify_templates.py index 1ecb1595c..09270a957 100644 --- a/modules/bibclassify/lib/bibclassify_templates.py +++ b/modules/bibclassify/lib/bibclassify_templates.py @@ -1,480 +1,481 @@ ## This file is part of Invenio. -## Copyright (C) 2010, 2011 CERN. +## Copyright (C) 2010, 2011, 2013 CERN. ## ## Invenio is free software; you can redistribute it and/or ## modify it under the terms of the GNU General Public License as ## published by the Free Software Foundation; either version 2 of the ## License, or (at your option) any later version. ## ## Invenio is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. __revision__ = "$Id$" """Template for the bibclassify - this modules is NOT standalone safe - it is not expected to be used in a stanalone mode ever. Some template variables are coming directly from the config module, those starting with CFG_BIBCLASSIFY_WEB.... """ +import cgi from invenio import config from invenio.messages import gettext_set_language from urllib import quote from invenio.htmlutils import escape_html import bibclassify_config as bconfig import bibclassify_ontology_reader as reader log = bconfig.get_logger("bibclassify.template") class Template: def tmpl_page(self, keywords=None, top='', middle='', bottom='', navbar=None, req=None, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): """This function generates the final output for every bibclassify page - it is called from the other templating functions to finalize the output. This way, all the logic about routing (which page to display) will rest with the webinterface, and templates care only for output. @keyword keywords: keywords to display @keyword top: string, what to put at top @keyword middle: string @keyword bottom: string @keyword navbar: if supplied, we will not add the generic navigation bar @keyword req: wsgi req object -- all the rest keyword parameters are common with the tmp_page_... calls @return: html string """ if navbar is None: navbar = self.tmpl_snippet_sorting_options(keywords, ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) # well, integration with other moduels needs to get better (but for now this will do) bottom += self.call_external_modules(keywords=keywords, req=req, ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) #thread_id, cache = reader.test_cache() #bottom += 'This is thread id: %s, cache id: %s, main cache: %s' % (thread_id, id(cache), id(reader._CACHE)) top = top and '
%s
' % top or '' return '''
%s
%s %s
%s
''' % (navbar, top, middle, bottom) def tmpl_page_msg(self, req=None, ln=None, msg=None): return self.tmpl_page(middle=msg) def tmpl_page_tagcloud(self, keywords, req=None, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): """Writes the html of the tag cloud @var keywords: dictionary of KeywordToken objects key is a KeywordToken object value is a list: [[(pos1,pos1), (pos2,pos2)..], font-level] @return: str, html page """ # Define the range of fonts. f_min = 12 f_increment = 3 f_number = 8 fonts = [f_min + i * f_increment for i in range(f_number)] # compute font levels _get_font_levels(keywords, no_steps=f_number) _ = gettext_set_language(ln) msg = _("Automatically generated single,\ composite, author,\ and other keywords.") cloud = [] cloud.append('
' % (' '.join(map(lambda x: '%spx' %x, fonts)))) format_link = self.tmpl_href max = config.CFG_BIBCLASSIFY_WEB_MAXKW or 1000 i = 0 if numbering == 'on': for kw, info in keywords.items()[0:max]: cloud.append('%s (%s)' % (fonts[info[-1]], format_link(kw, ln), len(info[0]))) else: for kw, info in keywords.items()[0:max]: cloud.append('%s ' % (fonts[info[-1]], format_link(kw, ln))) cloud.append('
') cloud = '''
%s
''' % ('\n'.join(cloud)) return self.tmpl_page(keywords=keywords, bottom=msg, middle=cloud, req=req, ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) def tmpl_page_list(self, keywords, req=None, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): """Page with keywords as a list""" _ = gettext_set_language(ln) kw = self.tmpl_list_of_keywords(keywords, ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) msg = _(_("Automatically generated single,\ composite, author,\ and other keywords.")) return self.tmpl_page(keywords=keywords, middle=kw, bottom=msg, req=req, ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) def tmpl_page_xml_output(self, keywords, xml=None, req=None, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): kw = '
%s
' % escape_html(xml) return self.tmpl_page(keywords, middle=kw, ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) def tmpl_page_generate_keywords(self, req=None, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): """ Text to return when no keywords are found""" _ = gettext_set_language(ln) msg = '''
%s
''' % (_('Automated keyword extraction wasn\'t run for this document yet.'), _('Generate keywords') ) return self.tmpl_page(top=msg, ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) def tmpl_page_no_keywords(self, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): _ = gettext_set_language(ln) return self.tmpl_page(top=_('There are no suitable keywords for display in this record.'), navbar='', ln=ln, generate=generate, sorting=sorting, type=type, numbering=numbering, showall=showall) def tmpl_list_of_keywords(self, keywords, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): """Formats the list of keywords - no distinction is made between weighted or not """ _ = gettext_set_language(ln) format_link = self.tmpl_href s_keywords = map(lambda x: (x[0], 1000 - len(x[1][0]), len(x[1][0])), keywords.items()) # need to sort by heights weight (reverse) and then alphabetically # that's why the substraction above s_keywords.sort(key=lambda x: (x[1], str(x[0])), reverse=False) if showall != 'on': s_keywords = s_keywords[0:config.CFG_BIBCLASSIFY_WEB_MAXKW] out = [] if numbering == 'on': for kw, weight, real_weight in s_keywords[0:config.CFG_BIBCLASSIFY_WEB_MAXKW]: out.append('%s (%s)' % (format_link(kw, ln), real_weight)) else: for kw, weight, real_weight in s_keywords[0:config.CFG_BIBCLASSIFY_WEB_MAXKW]: out.append(format_link(kw, ln)) if len(keywords) > len(s_keywords): out.append('%s' % ('?ln=%s&type=list&sorting=%s&showall=on' % (ln, sorting), 'show-more', _("Show more..."))) half = int(len(out) / 2) out = '
%s
%s
' % ('
'.join(out[0:half]), '
'.join(out[half:])) return '''
%s
''' % (out) def tmpl_format_list_of_keywords(self, keywords, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None): """Formats the list of keywords""" _ = gettext_set_language(ln) format_link = self.tmpl_href sorted_keywords = _get_sorted_keywords(keywords) _numbering = numbering is 'on' out = [] for type in ('composite', 'single'): if sorted_keywords['unweighted'][type]: out.append('%s' % _('Unweighted %s keywords:' % type)) for keyword, info in sorted_keywords['unweighted'][type]: out.append(format_link(keyword, ln)) for type in ('composite', 'single'): if sorted_keywords['weighted'][type]: out.append('%s' % _('Weighted %s keywords:' % type)) for keyword, info in sorted_keywords['weighted'][type]: if _numbering: out.append("%s (%d)" % (format_link(keyword, ln), len(info[0]))) else: out.append(format_link(keyword, ln)) return '''
%s
''' % ('
'.join(out)) def tmpl_search_link(self, keyword, ln): """Returns a link that searches for a keyword.""" return """%s/search?f=keyword&p=%s&ln=%s""" % ( config.CFG_SITE_URL, quote('"%s"' % keyword), ln) def tmpl_href(self, keyword, ln): - return '%s' % (self.tmpl_search_link(keyword, ln), keyword.getType(), keyword.isComposite() and 'composite' or 'single', str(keyword)) + return '%s' % (self.tmpl_search_link(keyword, ln), keyword.getType(), keyword.isComposite() and 'composite' or 'single', cgi.escape(str(keyword))) def tmpl_snippet_sorting_options(self, keywords, ln=None, generate=None, sorting=None, type=None, numbering=None, showall=None ): """Returns the HTML view of the sorting options. Takes care of enabling only some options based on the page shown.""" if not keywords: return '' _ = gettext_set_language(ln) out = '%s:\n' % _('Keywords') for (_type, label) in ( ('tagcloud', _('tag cloud')), ('list', _('list')), ('xml', _('XML')) ): k = {'langlink' : ln, 'type': _type, 'sorting' : sorting, 'label' : _(label)} if _type not in type: out += '[ %(label)s ]' % k else: out += '[ %(label)s ]' % k out += '\n
\n' """ out += 'Sort keywords:\n' for (sort_type, label) in ( ('occurences', 'by occurences'), ('related', 'by related documents'),): k = {'langlink' : ln, 'type': type_arg, 'sort' : sort_type, 'label' : _(label)} if sort_type not in sort_arg: out += '[ %(label)s ]' % k else: out += '[ %(label)s ]' % k """ return('''''' % out) def call_external_modules(self, **kwargs): """Give external modules chance to change bibclassify output - so far, there is no clear way how to discover modules etc. It is hardcoded now.""" _modules = bconfig.CFG_EXTERNAL_MODULES out = '' for m,v in _modules.items(): try: if not callable(v): x = __import__(m, globals=globals(), locals={}) if hasattr(x, v): v = getattr(x, v) _modules[m] = v else: raise Exception("The registered call %s does not exist in the module %s" % (v,m)) result = v('bibclassify', **kwargs) if result and isinstance(result, str): out += result else: log.error("Module %s returned wrong results? %s" % (m, str(result)[:50])) except Exception, msg: log.error("Error importing module: %s" % (m)) log.error(msg) del(_modules[m]) return out def _get_sorted_keywords(keywords): """Returns a list of keywords.""" # Separate keywords with and without weight, and single and # composite keywords. sorted_keywords = { 'unweighted': {'single': [], 'composite': []}, 'weighted': {'single': [], 'composite': []} } for k, info in keywords.items(): if len(info[0]) > 0: state = 'weighted' else: state = 'unweighted' if k.isComposite(): sorted_keywords[state]['composite'].append([k, info]) else: sorted_keywords[state]['single'].append([k, info]) for type in ('single', 'composite'): sorted_keywords['unweighted'][type].sort(key= lambda x: str(x[0]).lower()) #keyword label sorted_keywords['weighted'][type].sort(key= lambda x: len(x[1][0])) # number of spans return sorted_keywords def _get_font_levels(keywords, no_steps = 8): """Takes keywords dictionary {keyw1: [[], ]....} computes the fontlevel and adds it to the dictionary @return: nothing, it changes keywords dictionary directly""" if not keywords: return keywords # Extract the weights from the keywords. try: weights = map(lambda x: len(x[0]), keywords.values()) except IndexError: return keywords # Define the range of fonts. f_number = no_steps # Get some necessary values. w_min = float(min(weights)) w_max = float(max(weights)) # Compute the distribution function. if w_max == w_min: level = lambda weight: 1 else: slope = f_number / (w_max - w_min) y_intercept = - w_min * slope level = lambda weight: int(slope * weight + y_intercept) # Compute the font level for each weight. for keyword, info in keywords.items(): w = level(len(info[0])) if w >= f_number: w = f_number - 1 info.append(w) diff --git a/modules/bibclassify/lib/bibclassify_webinterface.py b/modules/bibclassify/lib/bibclassify_webinterface.py index 7629af998..16a38d7d5 100644 --- a/modules/bibclassify/lib/bibclassify_webinterface.py +++ b/modules/bibclassify/lib/bibclassify_webinterface.py @@ -1,362 +1,362 @@ # This file is part of Invenio. -# Copyright (C) 2008, 2009, 2010, 2011 CERN. +# Copyright (C) 2008, 2009, 2010, 2011, 2013 CERN. # # Invenio is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # Invenio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Invenio; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. """BibClassify's web interface. This module is NOT standalone safe - this component is never expected to run in a standalone mode, but always inside invenio.""" import os from cgi import escape from urllib import quote import time import bibupload from invenio.messages import gettext_set_language from invenio.bibdocfile import BibRecDocs from invenio.webinterface_handler import WebInterfaceDirectory from invenio.webpage import pageheaderonly, pagefooteronly from invenio.search_engine import get_colID, \ guess_primary_collection_of_a_record, create_navtrail_links, \ perform_request_search, get_record, print_record from invenio.websearchadminlib import get_detailed_page_tabs from invenio.template import load from invenio.webinterface_handler import wash_urlargd from invenio.webuser import collect_user_info from invenio import access_control_engine as acce from invenio import dbquery from invenio import bibtask from invenio import bibrecord import bibclassify_config as bconfig import bibclassify_text_extractor import bibclassify_engine import bibclassify_ontology_reader as bor log = bconfig.get_logger("bibclassify.webinterface") template = load('bibclassify') def main_page(req, recid, tabs, ln, template): """Generates the main page for the keyword tab - http://url/record/[recid]/keywords @var req: request object @var recid: int docid @var tabs: list of tab links @var ln: language id @var template: template object @return: nothing, writes using req object """ form = req.form argd = wash_urlargd(form, { 'generate': (str, 'no'), 'sorting': (str, 'occurences'), 'type': (str, 'tagcloud'), 'numbering': (str, 'off'), 'showall': (str, 'off'), }) for k,v in argd.items(): argd[k] = escape(v) req.write(template.detailed_record_container_top(recid, tabs, ln)) # Get the keywords from MARC (if any) success, keywords, marcrec = record_get_keywords(recid) if success: # check for the cached file and delete it (we don't need it anymore, data are in the DB) tmp_file = bibclassify_engine.get_tmp_file(recid) if os.path.exists(tmp_file): try: os.remove(tmp_file) except Exception, msg: log.error('Error removing the cached file: %s' % tmp_file) log.error(msg) else: # Give user possibility to generate them ONLY if not available already # we may have some keywords, but they are the old ones and we want to generate new new_found, new_keywords, marcrec = generate_keywords(req, recid, argd) if keywords and new_keywords: for key in keywords.keys(): if key in new_keywords: log.warning('The old "DESY" keyword will be overwritten by the newly extracted one: %s' % key) keywords.update(new_keywords) if keywords: # Output the keywords or the generate button or some message why kw not available write_keywords_body(keywords, req, recid, argd, marcrec=marcrec) req.write(template.detailed_record_container_bottom(recid, tabs, ln)) def write_keywords_body(keywords, req, recid, argd, marcrec=None): """Writes the bibclassify keyword output into req object""" if not keywords: req.write(template.tmpl_page_no_keywords(req=req, **argd)) return # test if more than half of the entries have weight (0,0) - ie. not weighted #if argd['type'] == 'tagcloud' and len(filter(lambda x: (0,0) in x[0], keywords.values())) > (len(keywords) * .5): # argd['type'] = 'list' if argd['type'] == 'list': # Display keywords as a list. req.write(template.tmpl_page_list(keywords, req=req, **argd)) elif argd['type'] == 'tagcloud': # Display keywords as a tag cloud. req.write(template.tmpl_page_tagcloud(keywords=keywords, req=req, **argd)) elif argd['type'] == 'xml': if marcrec: marcxml = filter_marcrec(marcrec) else: marcxml = bibclassify_engine.build_marc(recid, keywords, {}) req.write(template.tmpl_page_xml_output(keywords, marcxml, req=req, **argd)) else: _ = gettext_set_language(argd['ln']) req.write(template.tmpl_page(top=_('Unknown type: %s') % argd['type'], **argd)) def record_get_keywords(record, main_field=bconfig.CFG_MAIN_FIELD, others=bconfig.CFG_OTHER_FIELDS): """Returns a dictionary of keywordToken objects from the marc record. Weight is set to (0,0) if no weight can be found. This will load keywords from the field 653 and 695__a (which are the old 'DESY' keywords) @var record: int or marc record, if int - marc record is loaded from the database. If you pass record instance, keywords are extracted from it @return: tuple (found, keywords, marcxml) found - int indicating how many main_field keywords were found the other fields are not counted keywords - standard dictionary of keywordToken objects marcrec - marc record object loaded with data """ keywords = {} if isinstance(main_field, basestring): main_field = [main_field] if isinstance(others, basestring): others = [others] if isinstance(record, int): rec = get_record(record) else: rec = record found = 0 for m_field in main_field: tag, ind1, ind2 = bibclassify_engine._parse_marc_code(m_field) for field in rec.get(tag, []): keyword = '' weight = 0 type = '' for subfield in field[0]: if subfield[0] == 'a': keyword = subfield[1] elif subfield[0] == 'n': weight = int(subfield[1]) elif subfield[0] == '9': type = subfield[1] if keyword: found += 1 keywords[bor.KeywordToken(keyword, type=type)] = [[(0,0) for x in range(weight)]] if others: for field_no in others: tag, ind1, ind2 = bibclassify_engine._parse_marc_code(field_no) type = 'f%s' % field_no for field in rec.get(tag, []): keyword = '' for subfield in field[0]: if subfield[0] == 'a': keyword = subfield[1] keywords[bor.KeywordToken(keyword, type=type)] = [[(0,0)]] break return found, keywords, rec def generate_keywords(req, recid, argd): """Extracts keywords from the fulltexts (if found) for the given recid. It first checks whether the keywords are not already stored in the temp file (maybe from the previous run). @var req: req object @var recid: record id @var argd: arguments passed from web @keyword store_keywords: boolean, whether to save records in the file @return: standard dictionary of kw objects or {} """ ln = argd['ln'] _ = gettext_set_language(ln) keywords = {} # check the files were not already generated abs_path = bibclassify_engine.get_tmp_file(recid) if os.path.exists(abs_path): try: # Try to load the data from the tmp file recs = bibupload.xml_marc_to_records(bibupload.open_marc_file(abs_path)) return record_get_keywords(recs[0]) except: pass # check it is allowed (for this user) to generate pages (exit_stat, msg) = acce.acc_authorize_action(req, 'runbibclassify') if exit_stat != 0: log.info('Access denied: ' + msg) msg = _("The site settings do not allow automatic keyword extraction") req.write(template.tmpl_page_msg(msg=msg)) return 0, keywords, None # register generation bibdocfiles = BibRecDocs(recid).list_latest_files() if bibdocfiles: # User arrived at a page, but no keywords are available inprogress, msg = _doc_already_submitted(recid) if argd['generate'] != 'yes': # Display a form and give them possibility to generate keywords if inprogress: req.write(template.tmpl_page_msg(msg='
%s
' % _(msg))) else: req.write(template.tmpl_page_generate_keywords(req=req, **argd)) return 0, keywords, None else: # after user clicked on "generate" button if inprogress: req.write(template.tmpl_page_msg(msg='
%s
' % _(msg) )) else: schedule_extraction(recid, taxonomy=bconfig.CFG_EXTRACTION_TAXONOMY) req.write(template.tmpl_page_msg(msg='
%s
' % _('We have registered your request, the automated' 'keyword extraction will run after some time. Please return back in a while.'))) else: req.write(template.tmpl_page_msg(msg='
%s
' % _("Unfortunately, we don't have a PDF fulltext for this record in the storage, \ keywords cannot be generated using an automated process."))) return 0, keywords, None def upload_keywords(filename, mode='correct', recids=None): """Stores the extracted keywords in the database @var filename: fullpath to the file with marc record @keyword mode: correct|replace|add|delete use correct to add fields if they are different replace all fields with fields from the file add - add (even duplicate) fields delete - delete fields which are inside the file @keyword recids: list of record ids, this arg comes from the bibclassify daemon and it is used when the recids contains one entry (recid) - ie. one individual document was processed. We use it to mark the job title so that it is possible to query database if the bibclassify was run over that document (in case of collections with many recids, we simply construct a general title) """ if mode == 'correct': m = '-c' elif mode == 'replace': m = '-r' elif mode == 'add': m = '-a' elif mode == 'delete': m = '-d' else: raise Exception('Unknown mode') # let's use the user column to store the information, cause no better alternative in sight... user_title = 'bibclassify.upload' if recids and len(recids) == 1: user_title = 'extract:%d' % recids[0] bibtask.task_low_level_submission('bibupload', user_title, '-n', m, filename) def schedule_extraction(recid, taxonomy): bibtask.task_low_level_submission('bibclassify', 'extract:%s' % recid, '-k', taxonomy, '-i', '%s' % recid) def _doc_already_submitted(recid): # check extraction was already registered sql = "SELECT COUNT(proc) FROM schTASK WHERE proc='bibclassify' AND user=%s\ AND (status='WAITING' OR status='RUNNING')" if dbquery.run_sql(sql, ("extract:" + str(recid),))[0][0] > 0: return (True, "The automated keyword extraction \ for this document has been already scheduled. Please return back in a while.") # check the upload is inside the scheduled tasks sql = "SELECT COUNT(proc) FROM schTASK WHERE proc='bibupload' AND user=%s\ AND (status='WAITING' OR status='RUNNING')" if dbquery.run_sql(sql, ("extract:" + str(recid),))[0][0] > 0: return (True, 'The document was already processed, ' 'it will take a while for it to be ingested.') # or the task was run and is already archived sql = "SELECT COUNT(proc) FROM hstTASK WHERE proc='bibupload' AND user=%s" if dbquery.run_sql(sql, ("extract:" + str(recid),))[0][0] > 0: return (True, 'The document was already processed, ' 'at this moment, the automated extraction is not available.') # or the task was already ran sql = "SELECT COUNT(proc) FROM schTASK WHERE proc='bibclassify' AND user=%s\ AND (status='DONE')" if dbquery.run_sql(sql, ("extract:" + str(recid),))[0][0] > 0: return (True, 'The document was already processed, ' 'but automated extraction identified no suitable keywords.') # or the extraction is in error stat sql = "SELECT COUNT(proc) FROM schTASK WHERE proc='bibclassify' AND user=%s\ AND (status='ERROR')" if dbquery.run_sql(sql, ("extract:" + str(recid),))[0][0] > 0: return (True, 'The document was already scheduled, ' 'but an error happened. This requires an' 'administrator\'s intervention. Unfortunately, ' 'for the moment we cannot display any data.') return (False, None) def filter_marcrec(marcrec, main_field=bconfig.CFG_MAIN_FIELD, others=bconfig.CFG_OTHER_FIELDS): """Removes the unwanted fields and returns xml""" if isinstance(main_field, basestring): main_field = [main_field] if isinstance(others, basestring): others = [others] key_map = ['001'] for field in main_field + others: tag, ind1, ind2 = bibclassify_engine._parse_marc_code(field) key_map.append(tag) return bibrecord.print_rec(marcrec, 1, tags=key_map) diff --git a/modules/webcomment/lib/webcomment_templates.py b/modules/webcomment/lib/webcomment_templates.py index 93c230c05..2ecff8867 100644 --- a/modules/webcomment/lib/webcomment_templates.py +++ b/modules/webcomment/lib/webcomment_templates.py @@ -1,2536 +1,2536 @@ # -*- coding: utf-8 -*- ## Comments and reviews for records. ## This file is part of Invenio. -## Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 CERN. +## Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 CERN. ## ## Invenio is free software; you can redistribute it and/or ## modify it under the terms of the GNU General Public License as ## published by the Free Software Foundation; either version 2 of the ## License, or (at your option) any later version. ## ## Invenio is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. """HTML Templates for commenting features """ __revision__ = "$Id$" import cgi # Invenio imports from invenio.urlutils import create_html_link, create_url from invenio.webuser import get_user_info, collect_user_info, isGuestUser, get_email from invenio.dateutils import convert_datetext_to_dategui from invenio.webmessage_mailutils import email_quoted_txt2html from invenio.config import CFG_SITE_URL, \ CFG_SITE_SECURE_URL, \ CFG_SITE_LANG, \ CFG_SITE_NAME, \ CFG_SITE_NAME_INTL,\ CFG_SITE_SUPPORT_EMAIL,\ CFG_WEBCOMMENT_ALLOW_REVIEWS, \ CFG_WEBCOMMENT_ALLOW_COMMENTS, \ CFG_WEBCOMMENT_USE_RICH_TEXT_EDITOR, \ CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN, \ CFG_WEBCOMMENT_AUTHOR_DELETE_COMMENT_OPTION, \ CFG_CERN_SITE, \ CFG_SITE_RECORD, \ CFG_WEBCOMMENT_MAX_ATTACHED_FILES, \ CFG_WEBCOMMENT_MAX_ATTACHMENT_SIZE from invenio.htmlutils import get_html_text_editor, create_html_select from invenio.messages import gettext_set_language from invenio.bibformat import format_record from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import acc_get_user_roles_from_user_info, acc_get_role_id from invenio.search_engine_utils import get_fieldvalues class Template: """templating class, refer to webcomment.py for examples of call""" def tmpl_get_first_comments_without_ranking(self, recID, ln, comments, nb_comments_total, warnings): """ @param recID: record id @param ln: language @param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks @param nb_comments_total: total number of comments for this record @param warnings: list of warning tuples (warning_text, warning_color) @return: html of comments """ # load the right message language _ = gettext_set_language(ln) # naming data fields of comments c_nickname = 0 c_user_id = 1 c_date_creation = 2 c_body = 3 c_id = 6 warnings = self.tmpl_warnings(warnings, ln) # write button write_button_label = _("Write a comment") write_button_link = '%s/%s/%s/comments/add' % (CFG_SITE_URL, CFG_SITE_RECORD, recID) write_button_form = '' % ln write_button_form = self.createhiddenform(action=write_button_link, method="get", text=write_button_form, button=write_button_label) # comments comment_rows = '' last_comment_round_name = None comment_round_names = [comment[0] for comment in comments] if comment_round_names: last_comment_round_name = comment_round_names[-1] for comment_round_name, comments_list in comments: comment_rows += '
' % (comment_round_name) if comment_round_name: comment_rows += '
' + \ _('%(x_nb)i Comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name} + "
" else: comment_rows += '
' + \ _('%(x_nb)i Comments') % {'x_nb': len(comments_list),} + "
" for comment in comments_list: if comment[c_nickname]: nickname = comment[c_nickname] display = nickname else: (uid, nickname, display) = get_user_info(comment[c_user_id]) messaging_link = self.create_messaging_link(nickname, display, ln) comment_rows += """ """ report_link = '%s/%s/%s/comments/report?ln=%s&comid=%s' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln, comment[c_id]) reply_link = '%s/%s/%s/comments/add?ln=%s&comid=%s&action=REPLY' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln, comment[c_id]) comment_rows += self.tmpl_get_comment_without_ranking(req=None, ln=ln, nickname=messaging_link, comment_uid=comment[c_user_id], date_creation=comment[c_date_creation], body=comment[c_body], status='', nb_reports=0, report_link=report_link, reply_link=reply_link, recID=recID) comment_rows += """

""" # Close comment round comment_rows += '
' # output if nb_comments_total > 0: out = warnings comments_label = len(comments) > 1 and _("Showing the latest %i comments:") % len(comments) \ or "" out += """
%(comment_title)s
%(comments_label)s
%(comment_rows)s %(view_all_comments_link)s %(write_button_form)s
""" % \ {'comment_title': _("Discuss this document"), 'comments_label': comments_label, 'nb_comments_total' : nb_comments_total, 'recID': recID, 'comment_rows': comment_rows, 'tab': ' '*4, 'siteurl': CFG_SITE_URL, 's': nb_comments_total>1 and 's' or "", 'view_all_comments_link': nb_comments_total>0 and '''View all %s comments''' \ % (CFG_SITE_URL, CFG_SITE_RECORD, recID, nb_comments_total) or "", 'write_button_form': write_button_form, 'nb_comments': len(comments) } if not comments: out = """
%(discuss_label)s:
%(detailed_info)s
%(form)s """ % {'form': write_button_form, 'discuss_label': _("Discuss this document"), 'detailed_info': _("Start a discussion about any aspect of this document.") } return out def tmpl_record_not_found(self, status='missing', recID="", ln=CFG_SITE_LANG): """ Displays a page when bad or missing record ID was given. @param status: 'missing' : no recID was given 'inexistant': recID doesn't have an entry in the database 'nan' : recID is not a number 'invalid' : recID is an error code, i.e. in the interval [-99,-1] @param return: body of the page """ _ = gettext_set_language(ln) if status == 'inexistant': body = _("Sorry, the record %s does not seem to exist.") % (recID,) elif status in ('nan', 'invalid'): body = _("Sorry, %s is not a valid ID value.") % (recID,) else: body = _("Sorry, no record ID was provided.") body += "

" link = "%s." % (CFG_SITE_URL, ln, CFG_SITE_NAME_INTL.get(ln, CFG_SITE_NAME)) body += _("You may want to start browsing from %s") % link return body def tmpl_get_first_comments_with_ranking(self, recID, ln, comments=None, nb_comments_total=None, avg_score=None, warnings=[]): """ @param recID: record id @param ln: language @param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks @param nb_comments_total: total number of comments for this record @param avg_score: average score of all reviews @param warnings: list of warning tuples (warning_text, warning_color) @return: html of comments """ # load the right message language _ = gettext_set_language(ln) # naming data fields of comments c_nickname = 0 c_user_id = 1 c_date_creation = 2 c_body = 3 c_nb_votes_yes = 4 c_nb_votes_total = 5 c_star_score = 6 c_title = 7 c_id = 8 warnings = self.tmpl_warnings(warnings, ln) #stars if avg_score > 0: avg_score_img = 'stars-' + str(avg_score).split('.')[0] + '-' + str(avg_score).split('.')[1] + '.png' else: avg_score_img = "stars-0-0.png" # voting links useful_dict = { 'siteurl' : CFG_SITE_URL, 'CFG_SITE_RECORD' : CFG_SITE_RECORD, 'recID' : recID, 'ln' : ln, 'yes_img' : 'smchk_gr.gif', #'yes.gif', 'no_img' : 'iconcross.gif' #'no.gif' } link = '' + _("Yes") + '' useful_no = link + '&com_value=-1">' + _("No") + '' #comment row comment_rows = ' ' last_comment_round_name = None comment_round_names = [comment[0] for comment in comments] if comment_round_names: last_comment_round_name = comment_round_names[-1] for comment_round_name, comments_list in comments: comment_rows += '
' % (comment_round_name) comment_rows += _('%(x_nb)i comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name} + "
" for comment in comments_list: if comment[c_nickname]: nickname = comment[c_nickname] display = nickname else: (uid, nickname, display) = get_user_info(comment[c_user_id]) messaging_link = self.create_messaging_link(nickname, display, ln) comment_rows += ''' ''' report_link = '%s/%s/%s/reviews/report?ln=%s&comid=%s' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln, comment[c_id]) comment_rows += self.tmpl_get_comment_with_ranking(None, ln=ln, nickname=messaging_link, comment_uid=comment[c_user_id], date_creation=comment[c_date_creation], body=comment[c_body], status='', nb_reports=0, nb_votes_total=comment[c_nb_votes_total], nb_votes_yes=comment[c_nb_votes_yes], star_score=comment[c_star_score], title=comment[c_title], report_link=report_link, recID=recID) comment_rows += ''' %s %s / %s
''' % (_("Was this review helpful?"), useful_yes % {'comid':comment[c_id]}, useful_no % {'comid':comment[c_id]}) comment_rows += '''
''' # Close comment round comment_rows += '
' # write button write_button_link = '''%s/%s/%s/reviews/add''' % (CFG_SITE_URL, CFG_SITE_RECORD, recID) write_button_form = ' ' % ln write_button_form = self.createhiddenform(action=write_button_link, method="get", text=write_button_form, button=_("Write a review")) if nb_comments_total > 0: avg_score_img = str(avg_score_img) avg_score = str(avg_score) nb_comments_total = str(nb_comments_total) score = '' score += _("Average review score: %(x_nb_score)s based on %(x_nb_reviews)s reviews") % \ {'x_nb_score': '' + avg_score + '', 'x_nb_reviews': nb_comments_total} useful_label = _("Readers found the following %s reviews to be most helpful.") useful_label %= len(comments) > 1 and len(comments) or "" view_all_comments_link ='' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln) view_all_comments_link += _("View all %s reviews") % nb_comments_total view_all_comments_link += '
' out = warnings + """
%(comment_title)s:
%(score_label)s
%(useful_label)s %(comment_rows)s
%(view_all_comments_link)s %(write_button_form)s
""" % \ { 'comment_title' : _("Rate this document"), 'score_label' : score, 'useful_label' : useful_label, 'recID' : recID, 'view_all_comments' : _("View all %s reviews") % (nb_comments_total,), 'write_comment' : _("Write a review"), 'comment_rows' : comment_rows, 'tab' : ' '*4, 'siteurl' : CFG_SITE_URL, 'view_all_comments_link': nb_comments_total>0 and view_all_comments_link or "", 'write_button_form' : write_button_form } else: out = '''
%s:
%s
%s
''' % (_("Rate this document"), _('Be the first to review this document.'), write_button_form) return out def tmpl_get_comment_without_ranking(self, req, ln, nickname, comment_uid, date_creation, body, status, nb_reports, reply_link=None, report_link=None, undelete_link=None, delete_links=None, unreport_link=None, recID=-1, com_id='', attached_files=None, collapsed_p=False): """ private function @param req: request object to fetch user info @param ln: language @param nickname: nickname @param date_creation: date comment was written @param body: comment body @param status: status of the comment: da: deleted by author dm: deleted by moderator ok: active @param nb_reports: number of reports the comment has @param reply_link: if want reply and report, give the http links @param report_link: if want reply and report, give the http links @param undelete_link: http link to delete the message @param delete_links: http links to delete the message @param unreport_link: http link to unreport the comment @param recID: recID where the comment is posted @param com_id: ID of the comment displayed @param attached_files: list of attached files @param collapsed_p: if the comment should be collapsed or not @return: html table of comment """ from invenio.search_engine import guess_primary_collection_of_a_record # load the right message language _ = gettext_set_language(ln) user_info = collect_user_info(req) date_creation = convert_datetext_to_dategui(date_creation, ln=ln) if attached_files is None: attached_files = [] out = '' final_body = email_quoted_txt2html(body) title = nickname title += '' % (com_id, com_id) links = '' if not isGuestUser(user_info['uid']): # Add link to toggle comment visibility links += create_html_link(CFG_SITE_URL + '/' + CFG_SITE_RECORD + '/' + str(recID) + '/comments/toggle', {'comid': com_id, 'ln': ln, 'collapse': collapsed_p and '0' or '1', 'referer': user_info['uri']}, _("Close"), {'onclick': "return toggle_visibility(this, %s, 'fast');" % com_id}, escape_linkattrd=False) moderator_links = '' if reply_link: links += '' + _("Reply") +'' if report_link and status != 'ap': links += '' + _("Report abuse") + '' # Check if user is a comment moderator record_primary_collection = guess_primary_collection_of_a_record(recID) (auth_code, auth_msg) = acc_authorize_action(user_info, 'moderatecomments', collection=record_primary_collection) if status in ['dm', 'da'] and req: if not auth_code: if status == 'dm': final_body = '
(Comment deleted by the moderator) - not visible for users

' +\ final_body + '
' else: final_body = '
(Comment deleted by the author) - not visible for users

' +\ final_body + '
' links = '' moderator_links += '' + _("Undelete comment") + '' else: if status == 'dm': final_body = '
Comment deleted by the moderator
' else: final_body = '
Comment deleted by the author
' links = '' else: if not auth_code: moderator_links += '' + _("Delete comment") + '' elif (user_info['uid'] == comment_uid) and CFG_WEBCOMMENT_AUTHOR_DELETE_COMMENT_OPTION: moderator_links += '' + _("Delete comment") + '' if nb_reports >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN: if not auth_code: final_body = '
(Comment reported. Pending approval) - not visible for users

' + final_body + '
' links = '' moderator_links += '' + _("Unreport comment") + '' else: final_body = '
This comment is pending approval due to user reports
' links = '' if links and moderator_links: links = links + moderator_links elif not links: links = moderator_links attached_files_html = '' if attached_files: attached_files_html = '
%s:
' % (len(attached_files) == 1 and _("Attached file") or _("Attached files")) for (filename, filepath, fileurl) in attached_files: attached_files_html += create_html_link(urlbase=fileurl, urlargd={}, link_label=cgi.escape(filename)) + '
' attached_files_html += '
' toggle_visibility_block = '' if not isGuestUser(user_info['uid']): toggle_visibility_block = """""" % \ {'comid': com_id, 'toggle_url': create_url(CFG_SITE_URL + '/' + CFG_SITE_RECORD + '/' + str(recID) + '/comments/toggle', {'comid': com_id, 'ln': ln, 'collapse': collapsed_p and '0' or '1', 'referer': user_info['uri']}), 'collapse_ctr_class': collapsed_p and 'webcomment_collapse_ctr_right' or 'webcomment_collapse_ctr_down', 'collapse_label': collapsed_p and _("Open") or _("Close")} out += """
%(toggle_visibility_block)s
avatar
%(title)s
%(date)s
¶
%(body)s
%(attached_files_html)s
%(links)s
""" % \ {'title' : title, 'body' : final_body, 'links' : links, 'attached_files_html': attached_files_html, 'date': date_creation, 'site_url': CFG_SITE_URL, 'comid': com_id, 'collapsible_content_style': collapsed_p and 'display:none' or '', 'toggle_visibility_block': toggle_visibility_block, } return out def tmpl_get_comment_with_ranking(self, req, ln, nickname, comment_uid, date_creation, body, status, nb_reports, nb_votes_total, nb_votes_yes, star_score, title, report_link=None, delete_links=None, undelete_link=None, unreport_link=None, recID=-1): """ private function @param req: request object to fetch user info @param ln: language @param nickname: nickname @param date_creation: date comment was written @param body: comment body @param status: status of the comment @param nb_reports: number of reports the comment has @param nb_votes_total: total number of votes for this review @param nb_votes_yes: number of positive votes for this record @param star_score: star score for this record @param title: title of review @param report_link: if want reply and report, give the http links @param undelete_link: http link to delete the message @param delete_link: http link to delete the message @param unreport_link: http link to unreport the comment @param recID: recID where the comment is posted @return: html table of review """ from invenio.search_engine import guess_primary_collection_of_a_record # load the right message language _ = gettext_set_language(ln) if star_score > 0: star_score_img = 'stars-' + str(star_score) + '-0.png' else: star_score_img = 'stars-0-0.png' out = "" date_creation = convert_datetext_to_dategui(date_creation, ln=ln) reviewed_label = _("Reviewed by %(x_nickname)s on %(x_date)s") % {'x_nickname': nickname, 'x_date':date_creation} ## FIX nb_votes_yes = str(nb_votes_yes) nb_votes_total = str(nb_votes_total) useful_label = _("%(x_nb_people)s out of %(x_nb_total)s people found this review useful") % {'x_nb_people': nb_votes_yes, 'x_nb_total': nb_votes_total} links = '' _body = '' if body != '': _body = '''
%s
''' % email_quoted_txt2html(body, linebreak_html='') # Check if user is a comment moderator record_primary_collection = guess_primary_collection_of_a_record(recID) user_info = collect_user_info(req) (auth_code, auth_msg) = acc_authorize_action(user_info, 'moderatecomments', collection=record_primary_collection) if status in ['dm', 'da'] and req: if not auth_code: if status == 'dm': _body = '
(Review deleted by moderator) - not visible for users

' +\ _body + '
' else: _body = '
(Review deleted by author) - not visible for users

' +\ _body + '
' links = '' + _("Undelete review") + '' else: if status == 'dm': _body = '
Review deleted by moderator
' else: _body = '
Review deleted by author
' links = '' else: if not auth_code: links += '' + _("Delete review") + '' if nb_reports >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN: if not auth_code: _body = '
(Review reported. Pending approval) - not visible for users

' + _body + '
' links += ' | ' links += '' + _("Unreport review") + '' else: _body = '
This review is pending approval due to user reports.
' links = '' out += '''
%(star_score)s/>
       <div class=%(title)s
%(reviewed_label)s
%(useful_label)s
%(body)s
%(abuse)s''' % {'siteurl' : CFG_SITE_URL, 'star_score_img': star_score_img, 'star_score' : star_score, - 'title' : title, + 'title' : cgi.escape(title), 'reviewed_label': reviewed_label, 'useful_label' : useful_label, 'body' : _body, 'abuse' : links } return out def tmpl_get_comments(self, req, recID, ln, nb_per_page, page, nb_pages, display_order, display_since, CFG_WEBCOMMENT_ALLOW_REVIEWS, comments, total_nb_comments, avg_score, warnings, border=0, reviews=0, total_nb_reviews=0, nickname='', uid=-1, note='',score=5, can_send_comments=False, can_attach_files=False, user_is_subscribed_to_discussion=False, user_can_unsubscribe_from_discussion=False, display_comment_rounds=None): """ Get table of all comments @param recID: record id @param ln: language @param nb_per_page: number of results per page @param page: page number @param display_order: hh = highest helpful score, review only lh = lowest helpful score, review only hs = highest star score, review only ls = lowest star score, review only od = oldest date nd = newest date @param display_since: all= no filtering by date nd = n days ago nw = n weeks ago nm = n months ago ny = n years ago where n is a single digit integer between 0 and 9 @param CFG_WEBCOMMENT_ALLOW_REVIEWS: is ranking enable, get from config.py/CFG_WEBCOMMENT_ALLOW_REVIEWS @param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks @param total_nb_comments: total number of comments for this record @param avg_score: average score of reviews for this record @param warnings: list of warning tuples (warning_text, warning_color) @param border: boolean, active if want to show border around each comment/review @param reviews: boolean, enabled for reviews, disabled for comments @param can_send_comments: boolean, if user can send comments or not @param can_attach_files: boolean, if user can attach file to comment or not @param user_is_subscribed_to_discussion: True if user already receives new comments by email @param user_can_unsubscribe_from_discussion: True is user is allowed to unsubscribe from discussion """ # load the right message language _ = gettext_set_language(ln) # CERN hack begins: display full ATLAS user name. Check further below too. current_user_fullname = "" override_nickname_p = False if CFG_CERN_SITE: from invenio.search_engine import get_all_collections_of_a_record user_info = collect_user_info(uid) if 'atlas-readaccess-active-members [CERN]' in user_info['group']: # An ATLAS member is never anonymous to its colleagues # when commenting inside ATLAS collections recid_collections = get_all_collections_of_a_record(recID) if 'ATLAS' in str(recid_collections): override_nickname_p = True current_user_fullname = user_info.get('external_fullname', '') # CERN hack ends # naming data fields of comments if reviews: c_nickname = 0 c_user_id = 1 c_date_creation = 2 c_body = 3 c_status = 4 c_nb_reports = 5 c_nb_votes_yes = 6 c_nb_votes_total = 7 c_star_score = 8 c_title = 9 c_id = 10 c_round_name = 11 c_restriction = 12 reply_to = 13 c_visibility = 14 discussion = 'reviews' comments_link = '%s (%i)' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, _('Comments'), total_nb_comments) reviews_link = '%s (%i)' % (_('Reviews'), total_nb_reviews) add_comment_or_review = self.tmpl_add_comment_form_with_ranking(recID, uid, current_user_fullname or nickname, ln, '', score, note, warnings, show_title_p=True, can_attach_files=can_attach_files) else: c_nickname = 0 c_user_id = 1 c_date_creation = 2 c_body = 3 c_status = 4 c_nb_reports = 5 c_id = 6 c_round_name = 7 c_restriction = 8 reply_to = 9 c_visibility = 10 discussion = 'comments' comments_link = '%s (%i)' % (_('Comments'), total_nb_comments) reviews_link = '%s (%i)' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, _('Reviews'), total_nb_reviews) add_comment_or_review = self.tmpl_add_comment_form(recID, uid, nickname, ln, note, warnings, can_attach_files=can_attach_files, user_is_subscribed_to_discussion=user_is_subscribed_to_discussion) # voting links useful_dict = { 'siteurl' : CFG_SITE_URL, 'CFG_SITE_RECORD' : CFG_SITE_RECORD, 'recID' : recID, 'ln' : ln, 'do' : display_order, 'ds' : display_since, 'nb' : nb_per_page, 'p' : page, 'reviews' : reviews, 'discussion' : discussion } useful_yes = '' + _("Yes") + '' useful_yes %= useful_dict useful_no = '' + _("No") + '' useful_no %= useful_dict warnings = self.tmpl_warnings(warnings, ln) link_dic = { 'siteurl' : CFG_SITE_URL, 'CFG_SITE_RECORD' : CFG_SITE_RECORD, 'module' : 'comments', 'function' : 'index', 'discussion': discussion, 'arguments' : 'do=%s&ds=%s&nb=%s' % (display_order, display_since, nb_per_page), 'arg_page' : '&p=%s' % page, 'page' : page, 'rec_id' : recID} if not req: req = None ## comments table comments_rows = '' last_comment_round_name = None comment_round_names = [comment[0] for comment in comments] if comment_round_names: last_comment_round_name = comment_round_names[-1] for comment_round_name, comments_list in comments: comment_round_style = "display:none;" comment_round_is_open = False if comment_round_name in display_comment_rounds: comment_round_is_open = True comment_round_style = "" comments_rows += '
' % (comment_round_name) if not comment_round_is_open and \ (comment_round_name or len(comment_round_names) > 1): new_cmtgrp = list(display_comment_rounds) new_cmtgrp.append(comment_round_name) comments_rows += '''Open group ' comments_rows += _('%(x_nb)i comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name} + "
" elif comment_round_name or len(comment_round_names) > 1: new_cmtgrp = list(display_comment_rounds) new_cmtgrp.remove(comment_round_name) comments_rows += '''Close group ' comments_rows += _('%(x_nb)i comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name}+ "
" comments_rows += '
' % (comment_round_name, comment_round_style) comments_rows += ''' ''' % {'siteurl': CFG_SITE_URL, 'recID': recID, 'ln': ln, 'CFG_SITE_RECORD': CFG_SITE_RECORD, 'open_label': _("Open"), 'close_label': _("Close")} thread_history = [0] previous_depth = 0 for comment in comments_list: if comment[reply_to] not in thread_history: # Going one level down in the thread thread_history.append(comment[reply_to]) depth = thread_history.index(comment[reply_to]) else: depth = thread_history.index(comment[reply_to]) thread_history = thread_history[:depth + 1] if previous_depth > depth: comments_rows += ("""
""" * (previous_depth-depth)) if previous_depth < depth: comments_rows += ("""
""" * (depth-previous_depth)) previous_depth = depth # CERN hack begins: display full ATLAS user name. comment_user_fullname = "" if CFG_CERN_SITE and override_nickname_p: comment_user_fullname = get_email(comment[c_user_id]) # CERN hack ends if comment[c_nickname]: _nickname = comment[c_nickname] display = _nickname else: (uid, _nickname, display) = get_user_info(comment[c_user_id]) messaging_link = self.create_messaging_link(_nickname, comment_user_fullname or display, ln) from invenio.webcomment import get_attached_files # FIXME files = get_attached_files(recID, comment[c_id]) # do NOT delete the HTML comment below. It is used for parsing... (I plead unguilty!) comments_rows += """
""" delete_links = {} if not reviews: report_link = '%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/comments/report?ln=%(ln)s&comid=%%(comid)s&do=%(do)s&ds=%(ds)s&nb=%(nb)s&p=%(p)s&referer=%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/comments/display' % useful_dict % {'comid':comment[c_id]} reply_link = '%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/comments/add?ln=%(ln)s&action=REPLY&comid=%%(comid)s' % useful_dict % {'comid':comment[c_id]} delete_links['mod'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_mod?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) delete_links['auth'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_auth?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) undelete_link = "%s/admin/webcomment/webcommentadmin.py/undel_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) unreport_link = "%s/admin/webcomment/webcommentadmin.py/unreport_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) comments_rows += self.tmpl_get_comment_without_ranking(req, ln, messaging_link, comment[c_user_id], comment[c_date_creation], comment[c_body], comment[c_status], comment[c_nb_reports], reply_link, report_link, undelete_link, delete_links, unreport_link, recID, comment[c_id], files, comment[c_visibility]) else: report_link = '%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/reviews/report?ln=%(ln)s&comid=%%(comid)s&do=%(do)s&ds=%(ds)s&nb=%(nb)s&p=%(p)s&referer=%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/reviews/display' % useful_dict % {'comid': comment[c_id]} delete_links['mod'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_mod?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) delete_links['auth'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_auth?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) undelete_link = "%s/admin/webcomment/webcommentadmin.py/undel_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) unreport_link = "%s/admin/webcomment/webcommentadmin.py/unreport_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) comments_rows += self.tmpl_get_comment_with_ranking(req, ln, messaging_link, comment[c_user_id], comment[c_date_creation], comment[c_body], comment[c_status], comment[c_nb_reports], comment[c_nb_votes_total], comment[c_nb_votes_yes], comment[c_star_score], comment[c_title], report_link, delete_links, undelete_link, unreport_link, recID) helpful_label = _("Was this review helpful?") report_abuse_label = "(" + _("Report abuse") + ")" yes_no_separator = ' / ' if comment[c_nb_reports] >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN or comment[c_status] in ['dm', 'da']: report_abuse_label = "" helpful_label = "" useful_yes = "" useful_no = "" yes_no_separator = "" comments_rows += """ %(yes_no_separator)s
%(helpful_label)s %(tab)s %(yes)s %(no)s %(tab)s%(tab)s%(report_abuse_label)s
""" \ % {'helpful_label': helpful_label, 'yes' : useful_yes % {'comid':comment[c_id]}, 'yes_no_separator': yes_no_separator, 'no' : useful_no % {'comid':comment[c_id]}, 'report' : report_link % {'comid':comment[c_id]}, 'report_abuse_label': comment[c_nb_reports] >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN and '' or report_abuse_label, 'tab' : ' '*2} # do NOT remove HTML comment below. It is used for parsing... comments_rows += """
""" comments_rows += '
' ## page links page_links = '' # Previous if page != 1: link_dic['arg_page'] = 'p=%s' % (page - 1) page_links += '<< ' % link_dic else: page_links += ' %s ' % (' '*(len(_('Previous'))+7)) # Page Numbers for i in range(1, nb_pages+1): link_dic['arg_page'] = 'p=%s' % i link_dic['page'] = '%s' % i if i != page: page_links += ''' %(page)s ''' % link_dic else: page_links += ''' %s ''' % i # Next if page != nb_pages: link_dic['arg_page'] = 'p=%s' % (page + 1) page_links += ''' >> ''' % link_dic else: page_links += '%s' % (' '*(len(_('Next'))+7)) ## stuff for ranking if enabled if reviews: if avg_score > 0: avg_score_img = 'stars-' + str(avg_score).split('.')[0] + '-' + str(avg_score).split('.')[1] + '.png' else: avg_score_img = "stars-0-0.png" ranking_average = '
' ranking_average += _("Average review score: %(x_nb_score)s based on %(x_nb_reviews)s reviews") % \ {'x_nb_score': '' + str(avg_score) + '', 'x_nb_reviews': str(total_nb_reviews)} ranking_average += '
' else: ranking_average = "" write_button_link = '''%s/%s/%s/%s/add''' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, discussion) write_button_form = '' write_button_form = self.createhiddenform(action=write_button_link, method="get", text=write_button_form, button = reviews and _('Write a review') or _('Write a comment')) if reviews: total_label = _("There is a total of %s reviews") else: total_label = _("There is a total of %s comments") total_label %= total_nb_comments review_or_comment_first = '' if reviews == 0 and total_nb_comments == 0 and can_send_comments: review_or_comment_first = _("Start a discussion about any aspect of this document.") + '
' elif reviews == 1 and total_nb_reviews == 0 and can_send_comments: review_or_comment_first = _("Be the first to review this document.") + '
' # do NOT remove the HTML comments below. Used for parsing body = ''' %(comments_and_review_tabs)s
%(comments_rows)s
%(review_or_comment_first)s
''' % \ { 'record_label': _("Record"), 'back_label': _("Back to search results"), 'total_label': total_label, 'write_button_form' : write_button_form, 'write_button_form_again' : total_nb_comments>3 and write_button_form or "", 'comments_rows' : comments_rows, 'total_nb_comments' : total_nb_comments, 'comments_or_reviews' : reviews and _('review') or _('comment'), 'comments_or_reviews_title' : reviews and _('Review') or _('Comment'), 'siteurl' : CFG_SITE_URL, 'module' : "comments", 'recid' : recID, 'ln' : ln, #'border' : border, 'ranking_avg' : ranking_average, 'comments_and_review_tabs' : CFG_WEBCOMMENT_ALLOW_REVIEWS and \ CFG_WEBCOMMENT_ALLOW_COMMENTS and \ '%s | %s
' % \ (comments_link, reviews_link) or '', 'review_or_comment_first' : review_or_comment_first } # form is not currently used. reserved for an eventual purpose #form = """ # Display # comments per page that are # and sorted by # """ % \ # (reviews==1 and ''' # # # # # ''' or ''' # ''') # #form_link = "%(siteurl)s/%(module)s/%(function)s" % link_dic #form = self.createhiddenform(action=form_link, method="get", text=form, button='Go', recid=recID, p=1) pages = """
%(v_label)s %(comments_or_reviews)s %(results_nb_lower)s-%(results_nb_higher)s
%(page_links)s
""" % \ {'v_label': _("Viewing"), 'page_links': _("Page:") + page_links , 'comments_or_reviews': reviews and _('review') or _('comment'), 'results_nb_lower': len(comments)>0 and ((page-1) * nb_per_page)+1 or 0, 'results_nb_higher': page == nb_pages and (((page-1) * nb_per_page) + len(comments)) or (page * nb_per_page)} if nb_pages > 1: #body = warnings + body + form + pages body = warnings + body + pages else: body = warnings + body if reviews == 0: if not user_is_subscribed_to_discussion: body += '
' + '' % CFG_SITE_URL + \ ' ' + '' + create_html_link(urlbase=CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + \ str(recID) + '/comments/subscribe', urlargd={}, link_label=_('Subscribe')) + \ '' + ' to this discussion. You will then receive all new comments by email.' + '
' body += '
' elif user_can_unsubscribe_from_discussion: body += '
' + '' % CFG_SITE_URL + \ ' ' + '' + create_html_link(urlbase=CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + \ str(recID) + '/comments/unsubscribe', urlargd={}, link_label=_('Unsubscribe')) + \ '' + ' from this discussion. You will no longer receive emails about new comments.' + '
' body += '
' if can_send_comments: body += add_comment_or_review else: body += '
' + _("You are not authorized to comment or review.") + '' return '
' + body + '
' def create_messaging_link(self, to, display_name, ln=CFG_SITE_LANG): """prints a link to the messaging system""" link = "%s/yourmessages/write?msg_to=%s&ln=%s" % (CFG_SITE_URL, to, ln) if to: return '%s' % (link, display_name) else: return display_name def createhiddenform(self, action="", method="get", text="", button="confirm", cnfrm='', **hidden): """ create select with hidden values and submit button @param action: name of the action to perform on submit @param method: 'get' or 'post' @param text: additional text, can also be used to add non hidden input @param button: value/caption on the submit button @param cnfrm: if given, must check checkbox to confirm @param **hidden: dictionary with name=value pairs for hidden input @return: html form """ output = """
""" % (action, method.lower().strip() in ['get', 'post'] and method or 'get') output += """
""" output += text + '\n' if cnfrm: output += """ """ for key in hidden.keys(): if type(hidden[key]) is list: for value in hidden[key]: output += """ """ % (key, value) else: output += """ """ % (key, hidden[key]) output += """
""" output += """ """ % (button, ) output += """
""" return output def create_write_comment_hiddenform(self, action="", method="get", text="", button="confirm", cnfrm='', enctype='', form_id=None, form_name=None, **hidden): """ create select with hidden values and submit button @param action: name of the action to perform on submit @param method: 'get' or 'post' @param text: additional text, can also be used to add non hidden input @param button: value/caption on the submit button @param cnfrm: if given, must check checkbox to confirm @param form_id: HTML 'id' attribute of the form tag @param form_name: HTML 'name' attribute of the form tag @param **hidden: dictionary with name=value pairs for hidden input @return: html form """ enctype_attr = '' if enctype: enctype_attr = 'enctype="%s"' % enctype output = """
""" % \ (action, method.lower().strip() in ['get', 'post'] and method or 'get', enctype_attr, form_name and ' name="%s"' % form_name or '', form_id and ' id="%s"' % form_id or '') if cnfrm: output += """ """ for key in hidden.keys(): if type(hidden[key]) is list: for value in hidden[key]: output += """ """ % (key, value) else: output += """ """ % (key, hidden[key]) output += text + '\n' output += """
""" return output def tmpl_warnings(self, warnings=[], ln=CFG_SITE_LANG): """ Display len(warnings) warning fields @param warnings: list of warning tuples (warning_text, warning_color) @param ln=language @return: html output """ if type(warnings) is not list: warnings = [warnings] warningbox = "" if warnings: for i in range(len(warnings)): warning_text = warnings[i][0] warning_color = warnings[i][1] if warning_color == 'green': span_class = 'exampleleader' else: span_class = 'important' warningbox += ''' %(warning)s
''' % \ { 'span_class' : span_class, 'warning' : warning_text } return warningbox else: return "" def tmpl_error(self, error, ln=CFG_SITE_LANG): """ Display error @param error: string @param ln=language @return: html output """ _ = gettext_set_language(ln) errorbox = "" if error != "": errorbox = "
\n Error:\n" errorbox += "

" errorbox += error + "

" errorbox += "

\n" return errorbox def tmpl_add_comment_form(self, recID, uid, nickname, ln, msg, warnings, textual_msg=None, can_attach_files=False, user_is_subscribed_to_discussion=False, reply_to=None): """ Add form for comments @param recID: record id @param uid: user id @param ln: language @param msg: comment body contents for when refreshing due to warning, or when replying to a comment @param textual_msg: same as 'msg', but contains the textual version in case user cannot display CKeditor @param warnings: list of warning tuples (warning_text, warning_color) @param can_attach_files: if user can upload attach file to record or not @param user_is_subscribed_to_discussion: True if user already receives new comments by email @param reply_to: the ID of the comment we are replying to. None if not replying @return html add comment form """ _ = gettext_set_language(ln) link_dic = { 'siteurl' : CFG_SITE_URL, 'CFG_SITE_RECORD' : CFG_SITE_RECORD, 'module' : 'comments', 'function' : 'add', 'arguments' : 'ln=%s&action=%s' % (ln, 'SUBMIT'), 'recID' : recID} if textual_msg is None: textual_msg = msg # FIXME a cleaner handling of nicknames is needed. if not nickname: (uid, nickname, display) = get_user_info(uid) if nickname: note = _("Note: Your nickname, %s, will be displayed as author of this comment.") % ('' + nickname + '') else: (uid, nickname, display) = get_user_info(uid) link = '' % CFG_SITE_SECURE_URL note = _("Note: you have not %(x_url_open)sdefined your nickname%(x_url_close)s. %(x_nickname)s will be displayed as the author of this comment.") % \ {'x_url_open': link, 'x_url_close': '', 'x_nickname': '
' + display + ''} if not CFG_WEBCOMMENT_USE_RICH_TEXT_EDITOR: note += '
' + ' '*10 + cgi.escape('You can use some HTML tags: , ,
,
,

, ,

    ,
  • , , ') #from invenio.search_engine import print_record #record_details = print_record(recID=recID, format='hb', ln=ln) warnings = self.tmpl_warnings(warnings, ln) # Prepare file upload settings. We must enable file upload in # the ckeditor + a simple file upload interface (independant from editor) file_upload_url = None simple_attach_file_interface = '' if isGuestUser(uid): simple_attach_file_interface = "%s
    " % _("Once logged in, authorized users can also attach files.") if can_attach_files: # Note that files can be uploaded only when user is logged in #file_upload_url = '%s/%s/%i/comments/attachments/put' % \ # (CFG_SITE_URL, CFG_SITE_RECORD, recID) simple_attach_file_interface = '''
    %(attach_msg)s: (%(nb_files_limit_msg)s. %(file_size_limit_msg)s)

    ''' % \ {'CFG_WEBCOMMENT_MAX_ATTACHED_FILES': CFG_WEBCOMMENT_MAX_ATTACHED_FILES, 'attach_msg': CFG_WEBCOMMENT_MAX_ATTACHED_FILES == 1 and _("Optionally, attach a file to this comment") or \ _("Optionally, attach files to this comment"), 'nb_files_limit_msg': _("Max one file") and CFG_WEBCOMMENT_MAX_ATTACHED_FILES == 1 or \ _("Max %i files") % CFG_WEBCOMMENT_MAX_ATTACHED_FILES, 'file_size_limit_msg': CFG_WEBCOMMENT_MAX_ATTACHMENT_SIZE > 0 and _("Max %(x_nb_bytes)s per file") % {'x_nb_bytes': (CFG_WEBCOMMENT_MAX_ATTACHMENT_SIZE < 1024*1024 and (str(CFG_WEBCOMMENT_MAX_ATTACHMENT_SIZE/1024) + 'KB') or (str(CFG_WEBCOMMENT_MAX_ATTACHMENT_SIZE/(1024*1024)) + 'MB'))} or ''} editor = get_html_text_editor(name='msg', content=msg, textual_content=textual_msg, width='100%', height='400px', enabled=CFG_WEBCOMMENT_USE_RICH_TEXT_EDITOR, file_upload_url=file_upload_url, toolbar_set = "WebComment", ln=ln) subscribe_to_discussion = '' if not user_is_subscribed_to_discussion: # Offer to subscribe to discussion subscribe_to_discussion = '' % _("Send me an email when a new comment is posted") form = """

    %(add_comment)s

    %(editor)s
    %(simple_attach_file_interface)s %(note)s
    %(subscribe_to_discussion)s
    %(reply_to)s
    """ % {'note': note, 'record_label': _("Article") + ":", 'comment_label': _("Comment") + ":", 'add_comment': _('Add comment'), 'editor': editor, 'subscribe_to_discussion': subscribe_to_discussion, 'reply_to': reply_to and '' % reply_to or '', 'simple_attach_file_interface': simple_attach_file_interface} form_link = "%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/comments/%(function)s?%(arguments)s" % link_dic form = self.create_write_comment_hiddenform(action=form_link, method="post", text=form, button='Add comment', enctype='multipart/form-data', form_id='cmtForm', form_name='cmtForm') return warnings + form + self.tmpl_page_do_not_leave_comment_page_js(ln=ln) def tmpl_add_comment_form_with_ranking(self, recID, uid, nickname, ln, msg, score, note, warnings, textual_msg=None, show_title_p=False, can_attach_files=False): """ Add form for reviews @param recID: record id @param uid: user id @param ln: language @param msg: comment body contents for when refreshing due to warning @param textual_msg: the textual version of 'msg' when user cannot display Ckeditor @param score: review score @param note: review title @param warnings: list of warning tuples (warning_text, warning_color) @param show_title_p: if True, prefix the form with "Add Review" as title @param can_attach_files: if user can upload attach file to record or not @return: html add review form """ _ = gettext_set_language(ln) link_dic = { 'siteurl' : CFG_SITE_URL, 'CFG_SITE_RECORD' : CFG_SITE_RECORD, 'module' : 'comments', 'function' : 'add', 'arguments' : 'ln=%s&action=%s' % (ln, 'SUBMIT'), 'recID' : recID} warnings = self.tmpl_warnings(warnings, ln) if textual_msg is None: textual_msg = msg #from search_engine import print_record #record_details = print_record(recID=recID, format='hb', ln=ln) if nickname: note_label = _("Note: Your nickname, %s, will be displayed as the author of this review.") note_label %= ('' + nickname + '') else: (uid, nickname, display) = get_user_info(uid) link = '
    ' % CFG_SITE_SECURE_URL note_label = _("Note: you have not %(x_url_open)sdefined your nickname%(x_url_close)s. %(x_nickname)s will be displayed as the author of this comment.") % \ {'x_url_open': link, 'x_url_close': '', 'x_nickname': '
    ' + display + ''} selected0 = '' selected1 = '' selected2 = '' selected3 = '' selected4 = '' selected5 = '' if score == 0: selected0 = ' selected="selected"' elif score == 1: selected1 = ' selected="selected"' elif score == 2: selected2 = ' selected="selected"' elif score == 3: selected3 = ' selected="selected"' elif score == 4: selected4 = ' selected="selected"' elif score == 5: selected5 = ' selected="selected"' ## file_upload_url = None ## if can_attach_files: ## file_upload_url = '%s/%s/%i/comments/attachments/put' % \ ## (CFG_SITE_URL, CFG_SITE_RECORD, recID) editor = get_html_text_editor(name='msg', content=msg, textual_content=msg, width='90%', height='400px', enabled=CFG_WEBCOMMENT_USE_RICH_TEXT_EDITOR, # file_upload_url=file_upload_url, toolbar_set = "WebComment", ln=ln) form = """%(add_review)s
    %(rate_label)s:
    %(title_label)s:
    %(write_label)s:
    %(editor)s
    %(note_label)s
    """ % {'article_label': _('Article'), 'rate_label': _("Rate this article"), 'select_label': _("Select a score"), 'title_label': _("Give a title to your review"), 'write_label': _("Write your review"), 'note_label': note_label, 'note' : note!='' and note or "", 'msg' : msg!='' and msg or "", #'record' : record_details 'add_review': show_title_p and ('

    '+_('Add review')+'

    ') or '', 'selected0': selected0, 'selected1': selected1, 'selected2': selected2, 'selected3': selected3, 'selected4': selected4, 'selected5': selected5, 'editor': editor, } form_link = "%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/reviews/%(function)s?%(arguments)s" % link_dic form = self.createhiddenform(action=form_link, method="post", text=form, button=_('Add Review')) return warnings + form def tmpl_add_comment_successful(self, recID, ln, reviews, warnings, success): """ @param recID: record id @param ln: language @return: html page of successfully added comment/review """ _ = gettext_set_language(ln) link_dic = { 'siteurl' : CFG_SITE_URL, 'CFG_SITE_RECORD' : CFG_SITE_RECORD, 'module' : 'comments', 'function' : 'display', 'arguments' : 'ln=%s&do=od' % ln, 'recID' : recID, 'discussion': reviews == 1 and 'reviews' or 'comments'} link = "%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/%(discussion)s/%(function)s?%(arguments)s" % link_dic if warnings: out = self.tmpl_warnings(warnings, ln) + '

    ' else: if reviews: out = _("Your review was successfully added.") + '

    ' else: out = _("Your comment was successfully added.") + '

    ' link += "#C%s" % success out += '' % link out += _('Back to record') + '' return out def tmpl_create_multiple_actions_form(self, form_name="", form_action="", method="get", action_display={}, action_field_name="", button_label="", button_name="", content="", **hidden): """ Creates an HTML form with a multiple choice of actions and a button to select it. @param form_action: link to the receiver of the formular @param form_name: name of the HTML formular @param method: either 'GET' or 'POST' @param action_display: dictionary of actions. action is HTML name (name of action) display is the string provided in the popup @param action_field_name: html name of action field @param button_label: what's written on the button @param button_name: html name of the button @param content: what's inside te formular @param **hidden: dictionary of name/value pairs of hidden fields. """ output = """
    """ % (form_action, method) output += """
    """ output += content + '\n' for key in hidden.keys(): if type(hidden[key]) is list: for value in hidden[key]: output += """ """ % (key, value) else: output += """ """ % (key, hidden[key]) output += """
    """ if type(action_display) is dict and len(action_display.keys()): output += """ """ output += """ """ % (button_label, button_name) output += """
    """ return output def tmpl_admin_index(self, ln): """ Index page """ # load the right message language _ = gettext_set_language(ln) out = '
      ' if CFG_WEBCOMMENT_ALLOW_COMMENTS or CFG_WEBCOMMENT_ALLOW_REVIEWS: if CFG_WEBCOMMENT_ALLOW_COMMENTS: out += '

      Comments status

      ' out += '
    1. %(hot_cmt_label)s
    2. ' % \ {'siteurl': CFG_SITE_URL, 'ln': ln, 'hot_cmt_label': _("View most commented records")} out += '
    3. %(latest_cmt_label)s
    4. ' % \ {'siteurl': CFG_SITE_URL, 'ln': ln, 'latest_cmt_label': _("View latest commented records")} out += '
    5. %(reported_cmt_label)s
    6. ' % \ {'siteurl': CFG_SITE_URL, 'ln': ln, 'reported_cmt_label': _("View all comments reported as abuse")} if CFG_WEBCOMMENT_ALLOW_REVIEWS: out += '

      Reviews status

      ' out += '
    7. %(hot_rev_label)s
    8. ' % \ {'siteurl': CFG_SITE_URL, 'ln': ln, 'hot_rev_label': _("View most reviewed records")} out += '
    9. %(latest_rev_label)s
    10. ' % \ {'siteurl': CFG_SITE_URL, 'ln': ln, 'latest_rev_label': _("View latest reviewed records")} out += '
    11. %(reported_rev_label)s
    12. ' % \ {'siteurl': CFG_SITE_URL, 'ln': ln, 'reported_rev_label': _("View all reviews reported as abuse")} #
    13. %(delete_label)s
    14. out +="""

      General

    15. %(view_users)s
    16. %(guide)s
    17. """ % {'siteurl' : CFG_SITE_URL, #'delete_label': _("Delete/Undelete comment(s) or suppress abuse report(s)"), 'view_users': _("View all users who have been reported"), 'ln' : ln, 'guide' : _("Guide")} else: out += _("Comments and reviews are disabled") + '
      ' out += '
    ' from invenio.bibrankadminlib import addadminbox return addadminbox('%s'% _("Menu"), [out]) def tmpl_admin_delete_form(self, ln, warnings): """ Display admin interface to fetch list of records to delete @param warnings: list of warning tuples (warning_text, warning_color) see tmpl_warnings, warning_color is optional """ # load the right message language _ = gettext_set_language(ln) warnings = self.tmpl_warnings(warnings, ln) out = '''
    %s

    '''% _("Please enter the ID of the comment/review so that you can view it before deciding whether to delete it or not") form = '''
    %s


    %s

    %s


    ''' % (_("Comment ID:"), _("Or enter a record ID to list all the associated comments/reviews:"), _("Record ID:")) form_link = "%s/admin/webcomment/webcommentadmin.py/delete?ln=%s" % (CFG_SITE_URL, ln) form = self.createhiddenform(action=form_link, method="get", text=form, button=_('View Comment')) return warnings + out + form def tmpl_admin_users(self, ln, users_data): """ @param users_data: tuple of ct, i.e. (ct, ct, ...) where ct is a tuple (total_number_reported, total_comments_reported, total_reviews_reported, total_nb_votes_yes_of_reported, total_nb_votes_total_of_reported, user_id, user_email, user_nickname) sorted by order of ct having highest total_number_reported """ _ = gettext_set_language(ln) u_reports = 0 u_comment_reports = 1 u_reviews_reports = 2 u_nb_votes_yes = 3 u_nb_votes_total = 4 u_uid = 5 u_email = 6 u_nickname = 7 if not users_data: return self.tmpl_warnings([(_("There have been no reports so far."), 'green')]) user_rows = "" for utuple in users_data: com_label = _("View all %s reported comments") % utuple[u_comment_reports] com_link = '''%s
    ''' % \ (CFG_SITE_URL, ln, utuple[u_uid], com_label) rev_label = _("View all %s reported reviews") % utuple[u_reviews_reports] rev_link = '''%s''' % \ (CFG_SITE_URL, ln, utuple[u_uid], rev_label) if not utuple[u_nickname]: user_info = get_user_info(utuple[u_uid]) nickname = user_info[2] else: nickname = utuple[u_nickname] if CFG_WEBCOMMENT_ALLOW_REVIEWS: review_row = """ %s %s %s""" review_row %= (utuple[u_nb_votes_yes], utuple[u_nb_votes_total] - utuple[u_nb_votes_yes], utuple[u_nb_votes_total]) else: review_row = '' user_rows += """ %(nickname)s %(email)s %(uid)s%(review_row)s %(reports)s %(com_link)s%(rev_link)s """ % { 'nickname' : nickname, 'email' : utuple[u_email], 'uid' : utuple[u_uid], 'reports' : utuple[u_reports], 'review_row': review_row, 'siteurl' : CFG_SITE_URL, 'ln' : ln, 'com_link' : CFG_WEBCOMMENT_ALLOW_COMMENTS and com_link or "", 'rev_link' : CFG_WEBCOMMENT_ALLOW_REVIEWS and rev_link or "" } out = "
    " out += _("Here is a list, sorted by total number of reports, of all users who have had a comment reported at least once.") out += """

    \n' out += '\n' out += '\n' if CFG_WEBCOMMENT_ALLOW_REVIEWS > 0: out += '\n' out += '\n' out += '\n' out += '\n' out += '\n' out += """ %s
    """ out += _("Nickname") + '' + _("Email") + '' + _("User ID") + '' + _("Number positive votes") + '' + _("Number negative votes") + '' + _("Total number votes") + '' + _("Total number of reports") + '' + _("View all user's reported comments/reviews") + '
    """ % user_rows return out def tmpl_admin_select_comment_checkbox(self, cmt_id): """ outputs a checkbox named "comidXX" where XX is cmt_id """ return '' % int(cmt_id) def tmpl_admin_user_info(self, ln, nickname, uid, email): """ prepares informations about a user""" _ = gettext_set_language(ln) out = """ %(nickname_label)s: %(messaging)s
    %(uid_label)s: %(uid)i
    %(email_label)s: %(email)s""" out %= {'nickname_label': _("Nickname"), 'messaging': self.create_messaging_link(uid, nickname, ln), 'uid_label': _("User ID"), 'uid': int(uid), 'email_label': _("Email"), 'email': email} return out def tmpl_admin_review_info(self, ln, reviews, nb_reports, cmt_id, rec_id, status): """ outputs information about a review """ _ = gettext_set_language(ln) if reviews: reported_label = _("This review has been reported %i times") else: reported_label = _("This comment has been reported %i times") reported_label %= int(nb_reports) out = """ %(reported_label)s
    %(rec_id_label)s
    %(cmt_id_label)s""" out %= {'reported_label': reported_label, 'rec_id_label': _("Record") + ' #' + str(rec_id), 'siteurl': CFG_SITE_URL, 'CFG_SITE_RECORD' : CFG_SITE_RECORD, 'rec_id': int(rec_id), 'cmt_id_label': _("Comment") + ' #' + str(cmt_id), 'ln': ln} if status in ['dm', 'da']: out += '
    Marked as deleted
    ' return out def tmpl_admin_latest(self, ln, comment_data, comments, error, user_collections, collection): """ @param comment_data: same type of tuple as that which is return by webcommentadminlib.py/query_get_latest i.e. tuple (nickname, uid, date_creation, body, id) if latest comments or tuple (nickname, uid, date_creation, body, star_score, id) if latest reviews """ _ = gettext_set_language(ln) out = """ """ out += '
    ' % (CFG_SITE_URL, ln, comments) out += '' % ln out += '' % comments out += '
    Filter by collection:

    ' if error == 1: out += "User is not authorized to view such collection.
    " return out elif error == 2: out += "There are no %s for this collection.
    " % (comments and 'comments' or 'reviews') return out out += """
      """ for (cmt_tuple, meta_data) in comment_data: bibrec_id = meta_data[3] content = format_record(bibrec_id, "hs") if not comments: out += """
    1. %(content)s
      reviewed by %(user)s (%(stars)s) \"%(body)s\" on %(date)s

    2. """ % {'content': content, 'comment_url': CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(bibrec_id) + '/reviews', 'user':cmt_tuple[0] , 'stars': '*' * int(cmt_tuple[4]) , 'body': cmt_tuple[3][:20] + '...', 'date': cmt_tuple[2]} else: out += """
    3. %(content)s
      commented by %(user)s, \"%(body)s\" on %(date)s

    4. """ % {'content': content, 'comment_url': CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(bibrec_id) + '/comments', 'user':cmt_tuple[0] , 'body': cmt_tuple[3][:20] + '...', 'date': cmt_tuple[2]} out += """
    """ return out def tmpl_admin_hot(self, ln, comment_data, comments, error, user_collections, collection): """ @param comment_data: same type of tuple as that which is return by webcommentadminlib.py/query_get_hot i.e. tuple (id_bibrec, date_last_comment, users, count) """ _ = gettext_set_language(ln) out = """ """ out += '
    ' % (CFG_SITE_URL, ln, comments) out += '' % ln out += '' % comments out += '
    Filter by collection:

    ' if error == 1: out += "User is not authorized to view such collection.
    " return out elif error == 2: out += "There are no %s for this collection.
    " % (comments and 'comments' or 'reviews') return out for cmt_tuple in comment_data: bibrec_id = cmt_tuple[0] content = format_record(bibrec_id, "hs") last_comment_date = cmt_tuple[1] total_users = cmt_tuple[2] total_comments = cmt_tuple[3] if comments: comment_url = CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(bibrec_id) + '/comments' str_comment = int(total_comments) > 1 and 'comments' or 'comment' else: comment_url = CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(bibrec_id) + '/reviews' str_comment = int(total_comments) > 1 and 'reviews' or 'review' out += """
  • %(content)s
    %(total_comments)s %(str_comment)s (%(total_users)s %(user)s), latest on %(last_comment_date)s

  • """ % {'content': content, 'comment_url': comment_url , 'total_comments': total_comments, 'str_comment': str_comment, 'total_users': total_users, 'user': int(total_users) > 1 and 'users' or 'user', 'last_comment_date': last_comment_date} out += """""" return out def tmpl_admin_comments(self, ln, uid, comID, recID, comment_data, reviews, error, user_collections, collection): """ @param comment_data: same type of tuple as that which is returned by webcomment.py/query_retrieve_comments_or_remarks i.e. tuple of comment where comment is tuple (nickname, date_creation, body, id) if ranking disabled or tuple (nickname, date_creation, body, nb_votes_yes, nb_votes_total, star_score, title, id) """ _ = gettext_set_language(ln) coll_form = """ """ coll_form += '
    ' % (CFG_SITE_URL, ln, reviews) coll_form += '' % ln coll_form += '' % reviews coll_form += '
    Filter by collection:

    ' if error == 1: coll_form += "User is not authorized to view such collection.
    " return coll_form elif error == 2: coll_form += "There are no %s for this collection.
    " % (reviews and 'reviews' or 'comments') return coll_form comments = [] comments_info = [] checkboxes = [] users = [] for (cmt_tuple, meta_data) in comment_data: if reviews: comments.append(self.tmpl_get_comment_with_ranking(None,#request object ln, cmt_tuple[0],#nickname cmt_tuple[1],#userid cmt_tuple[2],#date_creation cmt_tuple[3],#body cmt_tuple[9],#status 0, cmt_tuple[5],#nb_votes_total cmt_tuple[4],#nb_votes_yes cmt_tuple[6],#star_score cmt_tuple[7]))#title else: comments.append(self.tmpl_get_comment_without_ranking(None,#request object ln, cmt_tuple[0],#nickname cmt_tuple[1],#userid cmt_tuple[2],#date_creation cmt_tuple[3],#body cmt_tuple[5],#status 0, None, #reply_link None, #report_link None, #undelete_link None, #delete_links None, #unreport_link -1, # recid cmt_tuple[4] # com_id )) users.append(self.tmpl_admin_user_info(ln, meta_data[0], #nickname meta_data[1], #uid meta_data[2]))#email if reviews: status = cmt_tuple[9] else: status = cmt_tuple[5] comments_info.append(self.tmpl_admin_review_info(ln, reviews, meta_data[5], # nb abuse reports meta_data[3], # cmt_id meta_data[4], # rec_id status)) # status checkboxes.append(self.tmpl_admin_select_comment_checkbox(meta_data[3])) form_link = "%s/admin/webcomment/webcommentadmin.py/del_com?ln=%s" % (CFG_SITE_URL, ln) out = """ """ % {'review_label': reviews and _("Review") or _("Comment"), 'written_by_label': _("Written by"), 'review_info_label': _("General informations"), 'select_label': _("Select")} for i in range (0, len(comments)): out += """ """ % (comments[i], users[i], comments_info[i], checkboxes[i]) out += """
    %(review_label)s %(written_by_label)s %(review_info_label)s %(select_label)s
    %s %s %s %s
    """ if reviews: action_display = { 'delete': _('Delete selected reviews'), 'unreport': _('Suppress selected abuse report'), 'undelete': _('Undelete selected reviews') } else: action_display = { 'undelete': _('Undelete selected comments'), 'delete': _('Delete selected comments'), 'unreport': _('Suppress selected abuse report') } form = self.tmpl_create_multiple_actions_form(form_name="admin_comment", form_action=form_link, method="post", action_display=action_display, action_field_name='action', button_label=_("OK"), button_name="okbutton", content=out) if uid > 0: header = '
    ' if reviews: header += _("Here are the reported reviews of user %s") % uid else: header += _("Here are the reported comments of user %s") % uid header += '

    ' if comID > 0 and recID <= 0 and uid <= 0: if reviews: header = '
    ' +_("Here is review %s")% comID + '

    ' else: header = '
    ' +_("Here is comment %s")% comID + '

    ' if uid > 0 and comID > 0 and recID <= 0: if reviews: header = '
    ' + _("Here is review %(x_cmtID)s written by user %(x_user)s") % {'x_cmtID': comID, 'x_user': uid} else: header = '
    ' + _("Here is comment %(x_cmtID)s written by user %(x_user)s") % {'x_cmtID': comID, 'x_user': uid} header += '

    ' if comID <= 0 and recID <= 0 and uid <= 0: header = '
    ' if reviews: header += _("Here are all reported reviews sorted by the most reported") else: header += _("Here are all reported comments sorted by the most reported") header += "

    " elif recID > 0: header = '
    ' if reviews: header += _("Here are all reviews for record %i, sorted by the most reported" % recID) header += '
    %s' % (CFG_SITE_URL, recID, _("Show comments")) else: header += _("Here are all comments for record %i, sorted by the most reported" % recID) header += '
    %s' % (CFG_SITE_URL, recID, _("Show reviews")) header += "

    " return coll_form + header + form def tmpl_admin_del_com(self, del_res, ln=CFG_SITE_LANG): """ @param del_res: list of the following tuple (comment_id, was_successfully_deleted), was_successfully_deleted is boolean (0=false, >0=true """ _ = gettext_set_language(ln) table_rows = '' for deltuple in del_res: table_rows += """ %s %s """ % (deltuple[0], deltuple[1]>0 and _("Yes") or "" +_("No") + "") out = """ %s
    %s %s
    """ % (_("comment ID"), _("successfully deleted"), table_rows) return out def tmpl_admin_undel_com(self, del_res, ln=CFG_SITE_LANG): """ @param del_res: list of the following tuple (comment_id, was_successfully_undeleted), was_successfully_undeleted is boolean (0=false, >0=true """ _ = gettext_set_language(ln) table_rows = '' for deltuple in del_res: table_rows += """ """ % (deltuple[0], deltuple[1]>0 and _("Yes") or "" +_("No") + "") out = """
    %s %s
    %s
    %s %s
    """ % (_("comment ID"), _("successfully undeleted"), table_rows) return out def tmpl_admin_suppress_abuse_report(self, del_res, ln=CFG_SITE_LANG): """ @param del_res: list of the following tuple (comment_id, was_successfully_deleted), was_successfully_deleted is boolean (0=false, >0=true """ _ = gettext_set_language(ln) table_rows = '' for deltuple in del_res: table_rows += """ """ % (deltuple[0], deltuple[1]>0 and _("Yes") or "" +_("No") + "") out = """
    %s %s
    %s
    %s %s
    """ % (_("comment ID"), _("successfully suppressed abuse report"), table_rows) return out def tmpl_mini_review(self, recID, ln=CFG_SITE_LANG, action='SUBMIT', avg_score=0, nb_comments_total=0): """Display the mini version of reviews (only the grading part)""" _ = gettext_set_language(ln) url = '%s/%s/%s/reviews/add?ln=%s&action=%s' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln, action) if avg_score > 0: score = _("Average review score: %(x_nb_score)s based on %(x_nb_reviews)s reviews") % \ {'x_nb_score': '%.1f' % avg_score, 'x_nb_reviews': nb_comments_total} else: score = '(' +_("Not yet reviewed") + ')' if avg_score == 5: s1, s2, s3, s4, s5 = 'full', 'full', 'full', 'full', 'full' elif avg_score >= 4.5: s1, s2, s3, s4, s5 = 'full', 'full', 'full', 'full', 'half' elif avg_score >= 4: s1, s2, s3, s4, s5 = 'full', 'full', 'full', 'full', '' elif avg_score >= 3.5: s1, s2, s3, s4, s5 = 'full', 'full', 'full', 'half', '' elif avg_score >= 3: s1, s2, s3, s4, s5 = 'full', 'full', 'full', '', '' elif avg_score >= 2.5: s1, s2, s3, s4, s5 = 'full', 'full', 'half', '', '' elif avg_score >= 2: s1, s2, s3, s4, s5 = 'full', 'full', '', '', '' elif avg_score >= 1.5: s1, s2, s3, s4, s5 = 'full', 'half', '', '', '' elif avg_score == 1: s1, s2, s3, s4, s5 = 'full', '', '', '', '' else: s1, s2, s3, s4, s5 = '', '', '', '', '' out = ''' %(rate)s:

    Rate this document:
    1
    2
    3
     
    %(score)s ''' % {'url': url, 'score': score, 'rate': _("Rate this document"), 's1': s1, 's2': s2, 's3': s3, 's4': s4, 's5': s5 } return out def tmpl_email_new_comment_header(self, recID, title, reviews, comID, report_numbers, can_unsubscribe=True, ln=CFG_SITE_LANG, uid=-1): """ Prints the email header used to notify subscribers that a new comment/review was added. @param recid: the ID of the commented/reviewed record @param title: the title of the commented/reviewed record @param reviews: True if it is a review, else if a comment @param comID: the comment ID @param report_numbers: the report number(s) of the record @param can_unsubscribe: True if user can unsubscribe from alert @param ln: language """ # load the right message language _ = gettext_set_language(ln) user_info = collect_user_info(uid) out = _("Hello:") + '\n\n' + \ (reviews and _("The following review was sent to %(CFG_SITE_NAME)s by %(user_nickname)s:") or \ _("The following comment was sent to %(CFG_SITE_NAME)s by %(user_nickname)s:")) % \ {'CFG_SITE_NAME': CFG_SITE_NAME, 'user_nickname': user_info['nickname']} out += '\n(<%s>)' % (CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(recID)) out += '\n\n\n' return out def tmpl_email_new_comment_footer(self, recID, title, reviews, comID, report_numbers, can_unsubscribe=True, ln=CFG_SITE_LANG): """ Prints the email footer used to notify subscribers that a new comment/review was added. @param recid: the ID of the commented/reviewed record @param title: the title of the commented/reviewed record @param reviews: True if it is a review, else if a comment @param comID: the comment ID @param report_numbers: the report number(s) of the record @param can_unsubscribe: True if user can unsubscribe from alert @param ln: language """ # load the right message language _ = gettext_set_language(ln) out = '\n\n-- \n' out += _("This is an automatic message, please don't reply to it.") out += '\n' out += _("To post another comment, go to <%(x_url)s> instead.") % \ {'x_url': CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(recID) + \ (reviews and '/reviews' or '/comments') + '/add'} out += '\n' if not reviews: out += _("To specifically reply to this comment, go to <%(x_url)s>") % \ {'x_url': CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(recID) + \ '/comments/add?action=REPLY&comid=' + str(comID)} out += '\n' if can_unsubscribe: out += _("To unsubscribe from this discussion, go to <%(x_url)s>") % \ {'x_url': CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + str(recID) + \ '/comments/unsubscribe'} out += '\n' out += _("For any question, please use <%(CFG_SITE_SUPPORT_EMAIL)s>") % \ {'CFG_SITE_SUPPORT_EMAIL': CFG_SITE_SUPPORT_EMAIL} return out def tmpl_email_new_comment_admin(self, recID): """ Prints the record information used in the email to notify the system administrator that a new comment has been posted. @param recID: the ID of the commented/reviewed record """ out = "" title = get_fieldvalues(recID, "245__a") authors = ', '.join(get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a")) #res_author = "" #res_rep_num = "" #for author in authors: # res_author = res_author + ' ' + author dates = get_fieldvalues(recID, "260__c") report_nums = get_fieldvalues(recID, "037__a") report_nums += get_fieldvalues(recID, "088__a") report_nums = ', '.join(report_nums) #for rep_num in report_nums: # res_rep_num = res_rep_num + ', ' + rep_num out += " Title = %s \n" % (title and title[0] or "No Title") out += " Authors = %s \n" % authors if dates: out += " Date = %s \n" % dates[0] out += " Report number = %s" % report_nums return out def tmpl_page_do_not_leave_comment_page_js(self, ln): """ Code to ask user confirmation when leaving the page, so that the comment is not lost if clicking by mistake on links. @param ln: the user language """ # load the right message language _ = gettext_set_language(ln) out = ''' ''' % {'message': _('Your comment will be lost.').replace('"', '\\"'), 'name': 'msg'} return out def tmpl_your_comments(self, user_info, comments, page_number=1, selected_order_by_option="lcf", selected_display_number_option="all", selected_display_format_option="rc", nb_total_results=0, nb_total_pages=0, ln=CFG_SITE_LANG): """ Display all submitted comments by the user @param user_info: standard user info object. @param comments: ordered list of tuples (id_bibrec, comid, date_creation, body, status, in_reply_to_id_cmtRECORDCOMMENT) @param page_number: page on which the user is. @type page_number: integer @param selected_order_by_option: seleccted ordering option. Can be one of: - ocf: Oldest comment first - lcf: Latest comment first - grof: Group by record, oldest commented first - grlf: Group by record, latest commented first @type selected_order_by_option: string @param selected_display_number_option: number of results to show per page. Can be a string-digit or 'all'. @type selected_display_number_option: string @param selected_display_format_option: how to show records. Can be one of: - rc: Records and comments - ro: Records only - co: Comments only @type selected_display_format_option: string @param nb_total_results: total number of items to display. @type nb_total_results: integer @param nb_total_pages: total number of pages. @type nb_total_pages: integer @ln: language @type ln: string """ # load the right message language _ = gettext_set_language(ln) your_comments_order_by_options = (('ocf', _("Oldest comment first")), ('lcf', _("Latest comment first")), ('grof', _("Group by record, oldest commented first")), ('grlf', _("Group by record, latest commented first")), ) your_comments_display_format_options = (('rc', _("Records and comments")), ('ro', _('Records only')), ('co', _('Comments only')), ) your_comments_display_number_options = (('20', _("%s items") % 20), ('50', _("%s items") % 50), ('100', _("%s items") % 100), ('500',_("%s items") % 500), ('all', _('All items')), ) out = "" out += _("Below is the list of the comments you have submitted so far.") + "
    " if CFG_CERN_SITE: if nb_total_results == 0: out = _('You have not yet submitted any comment in the document "discussion" tab.') + "
    " user_roles = acc_get_user_roles_from_user_info(user_info) if acc_get_role_id('ATLASDraftPublication') in user_roles: out += _('You might find other comments here: ') out += create_html_link(urlbase=CFG_SITE_URL + '/search', urlargd={'ln': ln, 'cc': 'ATLAS Publication Drafts Comments', 'p': user_info['email'], 'f': '859__f'}, link_label='ATLAS Publication Drafts Comments') elif acc_get_role_id('cmsphysicsmembers') in user_roles: out += _('You might find other comments here: ') out += create_html_link(urlbase=CFG_SITE_URL + '/search', urlargd={'ln': ln, 'cc': '', 'p': user_info['email'], 'f': '859__f'}, link_label='CMS Publication Drafts Comments') elif acc_get_role_id('LHCbDraftPublication') in user_roles: out += _('You might find other comments here: ') out += create_html_link(urlbase=CFG_SITE_URL + '/search', urlargd={'ln': ln, 'cc': '', 'p': user_info['email'], 'f': '859__f'}, link_label='LHCb Publication Drafts Comments') out += '
    ' if nb_total_results == 0: return out else: if nb_total_results == 0: return _("You have not yet submitted any comment. Browse documents from the search interface and take part to discussions!") # Show controls format_selection = create_html_select(your_comments_display_format_options, name="format", selected=selected_display_format_option, attrs={'id': 'format', 'onchange': 'this.form.submit();'}) order_by_selection = create_html_select(your_comments_order_by_options, name="order_by", selected=selected_order_by_option, attrs={'id': 'order_by', 'onchange': 'this.form.submit();'}) nb_per_page_selection = create_html_select(your_comments_display_number_options, name="per_page", selected=selected_display_number_option, attrs={'id': 'per_page', 'onchange': 'this.form.submit();'}) out += '''
    %(display_option_label)s: %(format_selection)s %(order_by_selection)s %(nb_per_page_selection)s
    ''' % {'format_selection_label': _("Display"), 'order_selection_label': _("Order by"), 'per_page_selection_label': _("Per page"), 'format_selection': format_selection, 'order_by_selection': order_by_selection, 'nb_per_page_selection': nb_per_page_selection, 'display_option_label': _("Display options"), 'refresh_label': _("Refresh"), } # Show comments last_id_bibrec = None nb_record_groups = 0 out += '
    ' for id_bibrec, comid, date_creation, body, status, in_reply_to_id_cmtRECORDCOMMENT in comments: if last_id_bibrec != id_bibrec and selected_display_format_option in ('rc', 'ro'): # We moved to another record. Show some info about # current record. if last_id_bibrec: # Close previous group out += "
    " nb_record_groups += 1 #You might want to hide this information if user does #not have access, though it would make sense that he #can at least know on which page is comment appears.. out += '''
    • ''' % {'recid': id_bibrec} + \ format_record(id_bibrec, of="HS") + '
    ' if selected_display_format_option != 'ro': final_body = email_quoted_txt2html(body) title = '' % (comid, comid) if status == "dm": final_body = '
    %s
    ' % _("Comment deleted by the moderator") elif status == "da": final_body = ('
    %s

    ' % _("You have deleted this comment: it is not visible by other users")) +\ final_body + '
    ' links = [] if in_reply_to_id_cmtRECORDCOMMENT: links.append(create_html_link(urlbase=CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + \ str(id_bibrec) + '/comments/', urlargd={'ln': ln}, link_label=_('(in reply to a comment)'), urlhash=str(in_reply_to_id_cmtRECORDCOMMENT))) links.append(create_html_link(urlbase=CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + \ str(id_bibrec) + '/comments/', urlargd={'ln': ln}, link_label=_('See comment on discussion page'), urlhash='C' + str(comid))) out += '''
    avatar
    %(title)s
    %(date)s
    ¶
    %(body)s
    %(links)s
    ''' % \ {'title' : title, 'body' : final_body, 'links' : " ".join(links), 'date' : date_creation, 'site_url' : CFG_SITE_URL, 'comid' : comid, } last_id_bibrec = id_bibrec out += '
    ' # end 'yourcommentsmaincontent' # Show page navigation page_links = '' if selected_display_format_option == 'ro' and \ selected_order_by_option in ('ocf', 'lcf'): # We just have an approximation here (we count by # comments, not record...) page_links += (_("%i comments found in total (not shown on this page)") % nb_total_results) + ' ' else: page_links += (_("%i items found in total") % nb_total_results) + ' ' if selected_display_number_option != 'all': # Previous if page_number != 1: page_links += create_html_link(CFG_SITE_URL + '/yourcomments/', {'page': page_number - 1, 'order_by': selected_order_by_option, 'per_page': selected_display_number_option, 'format': selected_display_format_option, 'ln': ln}, _("Previous")) # Page Numbers for i in range(1, nb_total_pages + 1): if i != page_number: page_links += '  ' + \ create_html_link(CFG_SITE_URL + '/yourcomments/', {'page': i, 'order_by': selected_order_by_option, 'per_page': selected_display_number_option, 'format': selected_display_format_option, 'ln': ln}, str(i)) + \ '  ' elif nb_total_pages > 1: page_links += '''  %s  ''' % i # Next if page_number != nb_total_pages: page_links += create_html_link(CFG_SITE_URL + '/yourcomments/', {'page': page_number + 1, 'order_by': selected_order_by_option, 'per_page': selected_display_number_option, 'format': selected_display_format_option, 'ln': ln}, _("Next")) out += '
    ' return out diff --git a/modules/websession/lib/websession_templates.py b/modules/websession/lib/websession_templates.py index 68e12fb84..ea4485f13 100644 --- a/modules/websession/lib/websession_templates.py +++ b/modules/websession/lib/websession_templates.py @@ -1,2592 +1,2593 @@ ## This file is part of Invenio. ## Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 CERN. ## ## Invenio is free software; you can redistribute it and/or ## modify it under the terms of the GNU General Public License as ## published by the Free Software Foundation; either version 2 of the ## License, or (at your option) any later version. ## ## Invenio is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. __revision__ = "$Id$" import urllib import cgi from invenio.config import \ CFG_CERN_SITE, \ CFG_SITE_LANG, \ CFG_SITE_NAME, \ CFG_SITE_NAME_INTL, \ CFG_SITE_SUPPORT_EMAIL, \ CFG_SITE_SECURE_URL, \ CFG_SITE_URL, \ CFG_WEBSESSION_RESET_PASSWORD_EXPIRE_IN_DAYS, \ CFG_WEBSESSION_ADDRESS_ACTIVATION_EXPIRE_IN_DAYS, \ CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS, \ CFG_WEBSEARCH_MAX_RECORDS_IN_GROUPS, \ CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \ CFG_SITE_RECORD from invenio.access_control_config import CFG_EXTERNAL_AUTH_USING_SSO, \ CFG_EXTERNAL_AUTH_LOGOUT_SSO, CFG_WEB_API_KEY_STATUS from invenio.urlutils import make_canonical_urlargd, create_url, create_html_link from invenio.htmlutils import escape_html, nmtoken_from_string from invenio.messages import gettext_set_language, language_list_long from invenio.websession_config import CFG_WEBSESSION_GROUP_JOIN_POLICY class Template: def tmpl_back_form(self, ln, message, url, link): """ A standard one-message-go-back-link page. Parameters: - 'ln' *string* - The language to display the interface in - 'message' *string* - The message to display - 'url' *string* - The url to go back to - 'link' *string* - The link text """ out = """
    %(message)s %(link)s
    """% { 'message' : message, 'url' : url, 'link' : link, 'ln' : ln } return out def tmpl_external_setting(self, ln, key, value): _ = gettext_set_language(ln) out = """ %s: %s """ % (key, value) return out def tmpl_external_user_settings(self, ln, html_settings): _ = gettext_set_language(ln) out = """

    %(external_user_settings)s

    %(html_settings)s

    %(external_user_groups)s

    %(consult_external_groups)s

    """ % { 'external_user_settings' : _('External account settings'), 'html_settings' : html_settings, 'consult_external_groups' : _('You can consult the list of your external groups directly in the %(x_url_open)sgroups page%(x_url_close)s.') % { 'x_url_open' : '' % ln, 'x_url_close' : '' }, 'external_user_groups' : _('External user groups'), } return out def tmpl_user_api_key(self, ln=CFG_SITE_LANG, keys_info=None): """ Displays all the API key that the user owns the user Parameters: - 'ln' *string* - The language to display the interface in - 'key_info' *tuples* - Contains the tuples with the key data (id, desciption, status) """ # load the right message language _ = gettext_set_language(ln) out = """

    %(user_api_key)s

    """ % { 'user_api_key' : _("API keys") } if keys_info and len(keys_info) != 0: out += "

    %(user_keys)s

    " % {'user_keys': _("These are your current API keys")} out += """ """ for key_info in keys_info: out += """ """ % { 'key_description': _("Description: " + cgi.escape(key_info[1])), 'key_status': _("Status: " + key_info[2]), 'key_id': _(key_info[0]), 'index': keys_info.index(key_info), 'key_label': _("API key"), 'remove_key' : _("Delete key"), 'sitesecureurl': CFG_SITE_SECURE_URL, 'input_type': ("submit", "hidden")[key_info[2] == CFG_WEB_API_KEY_STATUS['REVOKED']] } out += "
    %(key_description)s %(key_status)s
    %(key_label)s %(key_id)s
    " out += """

    %(create_new_key)s


    (%(mandatory)s)

    %(note)s: %(new_key_description_note)s
    """ % { 'create_new_key' : _("If you want to create a new API key, please enter a description for it"), 'new_key_description_label' : _("Description for the new API key"), 'mandatory' : _("mandatory"), 'note' : _("Note"), 'new_key_description_note': _("The description should be something meaningful for you to recognize the API key"), 'create_new_key_button' : _("Create new key"), 'sitesecureurl': CFG_SITE_SECURE_URL } return out def tmpl_user_preferences(self, ln, email, email_disabled, password_disabled, nickname): """ Displays a form for the user to change his email/password. Parameters: - 'ln' *string* - The language to display the interface in - 'email' *string* - The email of the user - 'email_disabled' *boolean* - If the user has the right to edit his email - 'password_disabled' *boolean* - If the user has the right to edit his password - 'nickname' *string* - The nickname of the user (empty string if user does not have it) """ # load the right message language _ = gettext_set_language(ln) out = """

    %(edit_params)s

    %(change_user)s


    (%(mandatory)s)
    %(nickname_prefix)s%(nickname)s%(nickname_suffix)s
    %(note)s: %(fixed_nickname_note)s

    (%(mandatory)s)

    %(example)s: john.doe@example.com
       
    """ % { 'change_user' : _("If you want to change your email or set for the first time your nickname, please set new values in the form below."), 'edit_params' : _("Edit login credentials"), 'nickname_label' : _("Nickname"), 'nickname' : nickname, 'nickname_prefix' : nickname=='' and '
    '+_("Example")+':johnd' or '', 'new_email' : _("New email address"), 'mandatory' : _("mandatory"), 'example' : _("Example"), 'note' : _("Note"), 'set_values' : _("Set new values"), 'email' : email, 'email_disabled' : email_disabled and "readonly" or "", 'sitesecureurl': CFG_SITE_SECURE_URL, 'fixed_nickname_note' : _('Since this is considered as a signature for comments and reviews, once set it can not be changed.') } if not password_disabled and not CFG_EXTERNAL_AUTH_USING_SSO: out += """

    %(change_pass)s



    %(note)s: %(old_password_note)s


    %(note)s: %(password_note)s
       
    """ % { 'change_pass' : _("If you want to change your password, please enter the old one and set the new value in the form below."), 'mandatory' : _("mandatory"), 'old_password' : _("Old password"), 'new_password' : _("New password"), 'optional' : _("optional"), 'note' : _("Note"), 'password_note' : _("The password phrase may contain punctuation, spaces, etc."), 'old_password_note' : _("You must fill the old password in order to set a new one."), 'retype_password' : _("Retype password"), 'set_values' : _("Set new password"), 'password_disabled' : password_disabled and "disabled" or "", 'sitesecureurl': CFG_SITE_SECURE_URL, } elif not CFG_EXTERNAL_AUTH_USING_SSO and CFG_CERN_SITE: out += "

    " + _("""If you are using a lightweight CERN account you can %(x_url_open)sreset the password%(x_url_close)s.""") % \ {'x_url_open' : \ '' \ % (make_canonical_urlargd({'email': email, 'returnurl' : CFG_SITE_SECURE_URL + '/youraccount/edit' + make_canonical_urlargd({'lang' : ln}, {})}, {})), 'x_url_close' : ''} + "

    " elif CFG_EXTERNAL_AUTH_USING_SSO and CFG_CERN_SITE: out += "

    " + _("""You can change or reset your CERN account password by means of the %(x_url_open)sCERN account system%(x_url_close)s.""") % \ {'x_url_open' : '', 'x_url_close' : ''} + "

    " return out def tmpl_user_bibcatalog_auth(self, bibcatalog_username="", bibcatalog_password="", ln=CFG_SITE_LANG): """template for setting username and pw for bibcatalog backend""" _ = gettext_set_language(ln) out = """

    %(edit_bibcatalog_settings)s

    %(username)s: %(password)s:
    """ % { 'sitesecureurl' : CFG_SITE_SECURE_URL, 'bibcatalog_username' : bibcatalog_username, 'bibcatalog_password' : bibcatalog_password, 'edit_bibcatalog_settings' : _("Edit cataloging interface settings"), 'username' : _("Username"), 'password' : _("Password"), 'update_settings' : _('Update settings') } return out def tmpl_user_lang_edit(self, ln, preferred_lang): _ = gettext_set_language(ln) out = """

    %(edit_lang_settings)s

    """ % { 'select_lang' : _('Select desired language of the web interface.'), 'update_settings' : _('Update settings') } return out def tmpl_user_websearch_edit(self, ln, current = 10, show_latestbox = True, show_helpbox = True): _ = gettext_set_language(ln) out = """

    %(edit_websearch_settings)s

    """ % { 'update_settings' : _("Update settings"), 'select_group_records' : _("Number of search results per page"), } return out def tmpl_user_external_auth(self, ln, methods, current, method_disabled): """ Displays a form for the user to change his authentication method. Parameters: - 'ln' *string* - The language to display the interface in - 'methods' *array* - The methods of authentication - 'method_disabled' *boolean* - If the user has the right to change this - 'current' *string* - The currently selected method """ # load the right message language _ = gettext_set_language(ln) out = """
    %(edit_method)s

    %(explain_method)s:

    %(select_method)s: """ % { 'edit_method' : _("Edit login method"), 'explain_method' : _("Please select which login method you would like to use to authenticate yourself"), 'select_method' : _("Select method"), 'sitesecureurl': CFG_SITE_SECURE_URL, } for system in methods: out += """
    """ % { 'system' : system, 'disabled' : method_disabled and 'disabled="disabled"' or "", 'selected' : current == system and 'checked="checked"' or "", 'id' : nmtoken_from_string(system), } out += """
     
    """ % { 'select_method' : _("Select method"), } return out def tmpl_lost_password_form(self, ln): """ Displays a form for the user to ask for his password sent by email. Parameters: - 'ln' *string* - The language to display the interface in - 'msg' *string* - Explicative message on top of the form. """ # load the right message language _ = gettext_set_language(ln) out = "

    " + _("If you have lost the password for your %(sitename)s %(x_fmt_open)sinternal account%(x_fmt_close)s, then please enter your email address in the following form in order to have a password reset link emailed to you.") % {'x_fmt_open' : '', 'x_fmt_close' : '', 'sitename' : CFG_SITE_NAME_INTL[ln]} + "

    " out += """
     
    """ % { 'ln': ln, 'email' : _("Email address"), 'send' : _("Send password reset link"), } if CFG_CERN_SITE: out += "

    " + _("If you have been using the %(x_fmt_open)sCERN login system%(x_fmt_close)s, then you can recover your password through the %(x_url_open)sCERN authentication system%(x_url_close)s.") % {'x_fmt_open' : '', 'x_fmt_close' : '', 'x_url_open' : '' \ % make_canonical_urlargd({'lf': 'auth', 'returnURL' : CFG_SITE_SECURE_URL + '/youraccount/login?ln='+ln}, {}), 'x_url_close' : ''} + " " else: out += "

    " + _("Note that if you have been using an external login system, then we cannot do anything and you have to ask there.") + " " out += _("Alternatively, you can ask %s to change your login system from external to internal.") % ("""%(email)s""" % { 'email' : CFG_SITE_SUPPORT_EMAIL }) + "

    " return out def tmpl_account_info(self, ln, uid, guest, CFG_CERN_SITE): """ Displays the account information Parameters: - 'ln' *string* - The language to display the interface in - 'uid' *string* - The user id - 'guest' *boolean* - If the user is guest - 'CFG_CERN_SITE' *boolean* - If the site is a CERN site """ # load the right message language _ = gettext_set_language(ln) out = """

    %(account_offer)s

    """ % { 'account_offer' : _("%s offers you the possibility to personalize the interface, to set up your own personal library of documents, or to set up an automatic alert query that would run periodically and would notify you of search results by email.") % CFG_SITE_NAME_INTL[ln], } if not guest: out += """
    %(your_settings)s
    %(change_account)s
    """ % { 'ln' : ln, 'your_settings' : _("Your Settings"), 'change_account' : _("Set or change your account email address or password. Specify your preferences about the look and feel of the interface.") } out += """
    %(your_searches)s
    %(search_explain)s
    """ % { 'ln' : ln, 'your_searches' : _("Your Searches"), 'search_explain' : _("View all the searches you performed during the last 30 days."), } out += """
    %(your_baskets)s
    %(basket_explain)s""" % { 'ln' : ln, 'your_baskets' : _("Your Baskets"), 'basket_explain' : _("With baskets you can define specific collections of items, store interesting records you want to access later or share with others."), } if not guest: out += """
    %(your_comments)s
    %(comments_explain)s""" % { 'ln' : ln, 'your_comments' : _("Your Comments"), 'comments_explain' : _("Display all the comments you have submitted so far."), } if guest and CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS: out += self.tmpl_warning_guest_user(ln = ln, type = "baskets") out += """
    %(your_alerts)s
    %(explain_alerts)s""" % { 'ln' : ln, 'your_alerts' : _("Your Alerts"), 'explain_alerts' : _("Subscribe to a search which will be run periodically by our service. The result can be sent to you via Email or stored in one of your baskets."), } if guest and CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS: out += self.tmpl_warning_guest_user(type="alerts", ln = ln) out += "
    " if CFG_CERN_SITE: out += """
    %(your_loans)s
    %(explain_loans)s
    """ % { 'your_loans' : _("Your Loans"), 'explain_loans' : _("Check out book you have on loan, submit borrowing requests, etc. Requires CERN ID."), 'ln': ln, 'CFG_SITE_SECURE_URL': CFG_SITE_SECURE_URL } out += """
    """ return out def tmpl_warning_guest_user(self, ln, type): """ Displays a warning message about the specified type Parameters: - 'ln' *string* - The language to display the interface in - 'type' *string* - The type of data that will get lost in case of guest account (for the moment: 'alerts' or 'baskets') """ # load the right message language _ = gettext_set_language(ln) if (type=='baskets'): msg = _("You are logged in as a guest user, so your baskets will disappear at the end of the current session.") + ' ' elif (type=='alerts'): msg = _("You are logged in as a guest user, so your alerts will disappear at the end of the current session.") + ' ' msg += _("If you wish you can %(x_url_open)slogin or register here%(x_url_close)s.") % {'x_url_open': '', 'x_url_close': ''} return """
    %s
    """ % msg def tmpl_account_body(self, ln, user): """ Displays the body of the actions of the user Parameters: - 'ln' *string* - The language to display the interface in - 'user' *string* - The username (nickname or email) """ # load the right message language _ = gettext_set_language(ln) out = _("You are logged in as %(x_user)s. You may want to a) %(x_url1_open)slogout%(x_url1_close)s; b) edit your %(x_url2_open)saccount settings%(x_url2_close)s.") %\ {'x_user': user, 'x_url1_open': '', 'x_url1_close': '', 'x_url2_open': '', 'x_url2_close': '', } return out + "

    " def tmpl_account_template(self, title, body, ln, url): """ Displays a block of the your account page Parameters: - 'ln' *string* - The language to display the interface in - 'title' *string* - The title of the block - 'body' *string* - The body of the block - 'url' *string* - The URL to go to the proper section """ out ="""
    %s
    %s
    """ % (url, title, body) return out def tmpl_account_page(self, ln, warnings, warning_list, accBody, baskets, alerts, searches, messages, loans, groups, submissions, approvals, tickets, administrative, comments): """ Displays the your account page Parameters: - 'ln' *string* - The language to display the interface in - 'accBody' *string* - The body of the heading block - 'baskets' *string* - The body of the baskets block - 'alerts' *string* - The body of the alerts block - 'searches' *string* - The body of the searches block - 'messages' *string* - The body of the messages block - 'groups' *string* - The body of the groups block - 'submissions' *string* - The body of the submission block - 'approvals' *string* - The body of the approvals block - 'administrative' *string* - The body of the administrative block - 'comments' *string* - The body of the comments block """ # load the right message language _ = gettext_set_language(ln) out = "" if warnings == "1": out += self.tmpl_general_warnings(warning_list) out += self.tmpl_account_template(_("Your Account"), accBody, ln, '/youraccount/edit?ln=%s' % ln) if messages: out += self.tmpl_account_template(_("Your Messages"), messages, ln, '/yourmessages/display?ln=%s' % ln) if loans: out += self.tmpl_account_template(_("Your Loans"), loans, ln, '/yourloans/display?ln=%s' % ln) if baskets: out += self.tmpl_account_template(_("Your Baskets"), baskets, ln, '/yourbaskets/display?ln=%s' % ln) if comments: comments_description = _("You can consult the list of %(x_url_open)syour comments%(x_url_close)s submitted so far.") comments_description %= {'x_url_open': '', 'x_url_close': ''} out += self.tmpl_account_template(_("Your Comments"), comments_description, ln, '/yourcomments/?ln=%s' % ln) if alerts: out += self.tmpl_account_template(_("Your Alert Searches"), alerts, ln, '/youralerts/list?ln=%s' % ln) if searches: out += self.tmpl_account_template(_("Your Searches"), searches, ln, '/youralerts/display?ln=%s' % ln) if groups: groups_description = _("You can consult the list of %(x_url_open)syour groups%(x_url_close)s you are administering or are a member of.") groups_description %= {'x_url_open': '', 'x_url_close': ''} out += self.tmpl_account_template(_("Your Groups"), groups_description, ln, '/yourgroups/display?ln=%s' % ln) if submissions: submission_description = _("You can consult the list of %(x_url_open)syour submissions%(x_url_close)s and inquire about their status.") submission_description %= {'x_url_open': '', 'x_url_close': ''} out += self.tmpl_account_template(_("Your Submissions"), submission_description, ln, '/yoursubmissions.py?ln=%s' % ln) if approvals: approval_description = _("You can consult the list of %(x_url_open)syour approvals%(x_url_close)s with the documents you approved or refereed.") approval_description %= {'x_url_open': '', 'x_url_close': ''} out += self.tmpl_account_template(_("Your Approvals"), approval_description, ln, '/yourapprovals.py?ln=%s' % ln) #check if this user might have tickets if tickets: ticket_description = _("You can consult the list of %(x_url_open)syour tickets%(x_url_close)s.") ticket_description %= {'x_url_open': '', 'x_url_close': ''} out += self.tmpl_account_template(_("Your Tickets"), ticket_description, ln, '/yourtickets?ln=%s' % ln) if administrative: out += self.tmpl_account_template(_("Your Administrative Activities"), administrative, ln, '/admin') return out def tmpl_account_emailMessage(self, ln, msg): """ Displays a link to retrieve the lost password Parameters: - 'ln' *string* - The language to display the interface in - 'msg' *string* - Explicative message on top of the form. """ # load the right message language _ = gettext_set_language(ln) out ="" out +=""" %(msg)s %(try_again)s """ % { 'ln' : ln, 'msg' : msg, 'try_again' : _("Try again") } return out def tmpl_account_reset_password_email_body(self, email, reset_key, ip_address, ln=CFG_SITE_LANG): """ The body of the email that sends lost internal account passwords to users. """ _ = gettext_set_language(ln) out = """ %(intro)s %(intro2)s <%(link)s> %(outro)s %(outro2)s""" % { 'intro': _("Somebody (possibly you) coming from %(x_ip_address)s " "has asked\nfor a password reset at %(x_sitename)s\nfor " "the account \"%(x_email)s\"." % { 'x_sitename' :CFG_SITE_NAME_INTL.get(ln, CFG_SITE_NAME), 'x_email' : email, 'x_ip_address' : ip_address, } ), 'intro2' : _("If you want to reset the password for this account, please go to:"), 'link' : "%s/youraccount/access%s" % (CFG_SITE_SECURE_URL, make_canonical_urlargd({ 'ln' : ln, 'mailcookie' : reset_key }, {})), 'outro' : _("in order to confirm the validity of this request."), 'outro2' : _("Please note that this URL will remain valid for about %(days)s days only.") % {'days': CFG_WEBSESSION_RESET_PASSWORD_EXPIRE_IN_DAYS}, } return out def tmpl_account_address_activation_email_body(self, email, address_activation_key, ip_address, ln=CFG_SITE_LANG): """ The body of the email that sends email address activation cookie passwords to users. """ _ = gettext_set_language(ln) out = """ %(intro)s %(intro2)s <%(link)s> %(outro)s %(outro2)s""" % { 'intro': _("Somebody (possibly you) coming from %(x_ip_address)s " "has asked\nto register a new account at %(x_sitename)s\nfor the " "email address \"%(x_email)s\"." % { 'x_sitename' :CFG_SITE_NAME_INTL.get(ln, CFG_SITE_NAME), 'x_email' : email, 'x_ip_address' : ip_address, } ), 'intro2' : _("If you want to complete this account registration, please go to:"), 'link' : "%s/youraccount/access%s" % (CFG_SITE_SECURE_URL, make_canonical_urlargd({ 'ln' : ln, 'mailcookie' : address_activation_key }, {})), 'outro' : _("in order to confirm the validity of this request."), 'outro2' : _("Please note that this URL will remain valid for about %(days)s days only.") % {'days' : CFG_WEBSESSION_ADDRESS_ACTIVATION_EXPIRE_IN_DAYS}, } return out def tmpl_account_emailSent(self, ln, email): """ Displays a confirmation message for an email sent Parameters: - 'ln' *string* - The language to display the interface in - 'email' *string* - The email to which the message has been sent """ # load the right message language _ = gettext_set_language(ln) out ="" out += _("Okay, a password reset link has been emailed to %s.") % email return out def tmpl_account_delete(self, ln): """ Displays a confirmation message about deleting the account Parameters: - 'ln' *string* - The language to display the interface in """ # load the right message language _ = gettext_set_language(ln) out = "

    " + _("""Deleting your account""") + '

    ' return out def tmpl_account_logout(self, ln): """ Displays a confirmation message about logging out Parameters: - 'ln' *string* - The language to display the interface in """ # load the right message language _ = gettext_set_language(ln) out = _("You are no longer recognized by our system.") + ' ' if CFG_EXTERNAL_AUTH_USING_SSO and CFG_EXTERNAL_AUTH_LOGOUT_SSO: out += _("""You are still recognized by the centralized %(x_fmt_open)sSSO%(x_fmt_close)s system. You can %(x_url_open)slogout from SSO%(x_url_close)s, too.""") % \ {'x_fmt_open' : '', 'x_fmt_close' : '', 'x_url_open' : '' % CFG_EXTERNAL_AUTH_LOGOUT_SSO, 'x_url_close' : ''} out += '
    ' out += _("If you wish you can %(x_url_open)slogin here%(x_url_close)s.") % \ {'x_url_open': '', 'x_url_close': ''} return out def tmpl_login_form(self, ln, referer, internal, register_available, methods, selected_method, msg=None): """ Displays a login form Parameters: - 'ln' *string* - The language to display the interface in - 'referer' *string* - The referer URL - will be redirected upon after login - 'internal' *boolean* - If we are producing an internal authentication - 'register_available' *boolean* - If users can register freely in the system - 'methods' *array* - The available authentication methods - 'selected_method' *string* - The default authentication method - 'msg' *string* - The message to print before the form, if needed """ # load the right message language _ = gettext_set_language(ln) if msg is "": out = "

    %(please_login)s

    " % { 'please_login' : cgi.escape(_("If you already have an account, please login using the form below.")) } if CFG_CERN_SITE: out += "

    " + _("If you don't own a CERN account yet, you can register a %(x_url_open)snew CERN lightweight account%(x_url_close)s.") % {'x_url_open' : '', 'x_url_close' : ''} + "

    " else: if register_available: out += "

    "+_("If you don't own an account yet, please %(x_url_open)sregister%(x_url_close)s an internal account.") %\ {'x_url_open': '', 'x_url_close': ''} + "

    " else: # users cannot register accounts, so advise them # how to get one, or be silent about register # facility if account level is more than 4: if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 5: out += "

    " + _("If you don't own an account yet, please contact %s.") % ('%s' % (cgi.escape(CFG_SITE_SUPPORT_EMAIL, True), cgi.escape(CFG_SITE_SUPPORT_EMAIL))) + "

    " else: out = "

    %s

    " % msg out += """
    """ % {'CFG_SITE_SECURE_URL': CFG_SITE_SECURE_URL} if len(methods) > 1: # more than one method, must make a select login_select = """" out += """ """ % { 'login_title' : cgi.escape(_("Login method:")), 'login_select' : login_select, } else: # only one login method available out += """""" % cgi.escape(methods[0], True) out += """
    %(login_select)s
    """ % { 'ln': cgi.escape(ln, True), 'referer' : cgi.escape(referer, True), 'username' : cgi.escape(_("Username")), 'password' : cgi.escape(_("Password")), 'remember_me' : cgi.escape(_("Remember login on this computer.")), 'login' : cgi.escape(_("login")), } if internal: out += """   (%(lost_pass)s)""" % { 'ln' : cgi.escape(ln, True), 'lost_pass' : cgi.escape(_("Lost your password?")) } out += """
    """ out += """

    %(note)s: %(note_text)s

    """ % { 'note' : cgi.escape(_("Note")), 'note_text': cgi.escape(_("You can use your nickname or your email address to login."))} return out def tmpl_lost_your_password_teaser(self, ln=CFG_SITE_LANG): """Displays a short sentence to attract user to the fact that maybe he lost his password. Used by the registration page. """ _ = gettext_set_language(ln) out = "" out += """%(maybe_lost_pass)s""" % { 'ln' : ln, 'maybe_lost_pass': ("Maybe you have lost your password?") } return out def tmpl_reset_password_form(self, ln, email, reset_key, msg=''): """Display a form to reset the password.""" _ = gettext_set_language(ln) out = "" out = "

    %s

    " % _("Your request is valid. Please set the new " "desired password in the following form.") if msg: out += """

    %s

    """ % msg out += """
    %(set_password_for)s:%(email)s
    """ % { 'ln' : ln, 'reset_key' : reset_key, 'email' : email, 'set_password_for' : _('Set a new password for'), 'type_new_password' : _('Type the new password'), 'type_it_again' : _('Type again the new password'), 'set_new_password' : _('Set the new password') } return out def tmpl_register_page(self, ln, referer, level): """ Displays a login form Parameters: - 'ln' *string* - The language to display the interface in - 'referer' *string* - The referer URL - will be redirected upon after login - 'level' *int* - Login level (0 - all access, 1 - accounts activated, 2+ - no self-registration) """ # load the right message language _ = gettext_set_language(ln) out = "" if level <= 1: out += _("Please enter your email address and desired nickname and password:") if level == 1: out += _("It will not be possible to use the account before it has been verified and activated.") out += """

    (%(mandatory)s)

    %(example)s: john.doe@example.com

    (%(mandatory)s)

    %(example)s: johnd

    (%(optional)s)

    %(note)s: %(password_contain)s

    %(note)s: %(explain_acc)s""" % { 'referer' : cgi.escape(referer), 'ln' : cgi.escape(ln), 'email_address' : _("Email address"), 'nickname' : _("Nickname"), 'password' : _("Password"), 'mandatory' : _("mandatory"), 'optional' : _("optional"), 'example' : _("Example"), 'note' : _("Note"), 'password_contain' : _("The password phrase may contain punctuation, spaces, etc."), 'retype' : _("Retype Password"), 'register' : _("register"), 'explain_acc' : _("Please do not use valuable passwords such as your Unix, AFS or NICE passwords with this service. Your email address will stay strictly confidential and will not be disclosed to any third party. It will be used to identify you for personal services of %s. For example, you may set up an automatic alert search that will look for new preprints and will notify you daily of new arrivals by email.") % CFG_SITE_NAME, } else: # level >=2, so users cannot register accounts out += "

    " + _("It is not possible to create an account yourself. Contact %s if you want an account.") % ('%s' % (CFG_SITE_SUPPORT_EMAIL, CFG_SITE_SUPPORT_EMAIL)) + "

    " return out def tmpl_account_adminactivities(self, ln, uid, guest, roles, activities): """ Displays the admin activities block for this user Parameters: - 'ln' *string* - The language to display the interface in - 'uid' *string* - The used id - 'guest' *boolean* - If the user is guest - 'roles' *array* - The current user roles - 'activities' *array* - The user allowed activities """ # load the right message language _ = gettext_set_language(ln) out = "" # guest condition if guest: return _("You seem to be a guest user. You have to %(x_url_open)slogin%(x_url_close)s first.") % \ {'x_url_open': '', 'x_url_close': ''} # no rights condition if not roles: return "

    " + _("You are not authorized to access administrative functions.") + "

    " # displaying form out += "

    " + _("You are enabled to the following roles: %(x_role)s.") % {'x_role': ('' + ", ".join(roles) + "")} + '

    ' if activities: # print proposed links: activities.sort(lambda x, y: cmp(x.lower(), y.lower())) tmp_out = '' for action in activities: if action == "runbibedit": tmp_out += """
       
    %s""" % (CFG_SITE_URL, CFG_SITE_RECORD, _("Run Record Editor")) if action == "runbibeditmulti": tmp_out += """
        %s""" % (CFG_SITE_URL, CFG_SITE_RECORD, _("Run Multi-Record Editor")) if action == "runbibcirculation": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Run BibCirculation")) if action == "runbibmerge": tmp_out += """
        %s""" % (CFG_SITE_URL, CFG_SITE_RECORD, _("Run Record Merger")) if action == "runbibswordclient": tmp_out += """
        %s""" % (CFG_SITE_URL, CFG_SITE_RECORD, _("Run BibSword Client")) if action == "runbatchuploader": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Run Batch Uploader")) if action == "cfgbibformat": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure BibFormat")) + if action == "cfgbibknowledge": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure BibKnowledge")) if action == "cfgoaiharvest": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure OAI Harvest")) if action == "cfgoairepository": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure OAI Repository")) if action == "cfgbibindex": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure BibIndex")) if action == "cfgbibrank": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure BibRank")) if action == "cfgwebaccess": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure WebAccess")) if action == "cfgwebcomment": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure WebComment")) if action == "cfgweblinkback": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure WebLinkback")) if action == "cfgwebjournal": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure WebJournal")) if action == "cfgwebsearch": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure WebSearch")) if action == "cfgwebsubmit": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure WebSubmit")) if action == "runbibdocfile": tmp_out += """
        %s""" % (CFG_SITE_URL, CFG_SITE_RECORD, ln, _("Run Document File Manager")) if action == "cfgbibsort": tmp_out += """
        %s""" % (CFG_SITE_URL, ln, _("Configure BibSort")) if tmp_out: out += _("Here are some interesting web admin links for you:") + tmp_out out += "
    " + _("For more admin-level activities, see the complete %(x_url_open)sAdmin Area%(x_url_close)s.") %\ {'x_url_open': '', 'x_url_close': ''} return out def tmpl_create_userinfobox(self, ln, url_referer, guest, username, submitter, referee, admin, usebaskets, usemessages, usealerts, usegroups, useloans, usestats): """ Displays the user block Parameters: - 'ln' *string* - The language to display the interface in - 'url_referer' *string* - URL of the page being displayed - 'guest' *boolean* - If the user is guest - 'username' *string* - The username (nickname or email) - 'submitter' *boolean* - If the user is submitter - 'referee' *boolean* - If the user is referee - 'admin' *boolean* - If the user is admin - 'usebaskets' *boolean* - If baskets are enabled for the user - 'usemessages' *boolean* - If messages are enabled for the user - 'usealerts' *boolean* - If alerts are enabled for the user - 'usegroups' *boolean* - If groups are enabled for the user - 'useloans' *boolean* - If loans are enabled for the user - 'usestats' *boolean* - If stats are enabled for the user @note: with the update of CSS classes (cds.cds -> invenio.css), the variables useloans etc are not used in this function, since they are in the menus. But we keep them in the function signature for backwards compatibility. """ # load the right message language _ = gettext_set_language(ln) out = """ """ % CFG_SITE_URL if guest: out += """%(guest_msg)s :: %(login)s""" % { 'sitesecureurl': CFG_SITE_SECURE_URL, 'ln' : ln, 'guest_msg' : _("guest"), 'referer' : url_referer and ('&referer=%s' % urllib.quote(url_referer)) or '', 'login' : _('login') } else: out += """ %(username)s :: """ % { 'sitesecureurl' : CFG_SITE_SECURE_URL, 'ln' : ln, 'username' : username } out += """%(logout)s""" % { 'sitesecureurl' : CFG_SITE_SECURE_URL, 'ln' : ln, 'logout' : _("logout"), } return out def tmpl_create_useractivities_menu(self, ln, selected, url_referer, guest, username, submitter, referee, admin, usebaskets, usemessages, usealerts, usegroups, useloans, usestats, usecomments): """ Returns the main navigation menu with actions based on user's priviledges @param ln: The language to display the interface in @type ln: string @param selected: If the menu is currently selected @type selected: boolean @param url_referer: URL of the page being displayed @type url_referer: string @param guest: If the user is guest @type guest: string @param username: The username (nickname or email) @type username: string @param submitter: If the user is submitter @type submitter: boolean @param referee: If the user is referee @type referee: boolean @param admin: If the user is admin @type admin: boolean @param usebaskets: If baskets are enabled for the user @type usebaskets: boolean @param usemessages: If messages are enabled for the user @type usemessages: boolean @param usealerts: If alerts are enabled for the user @type usealerts: boolean @param usegroups: If groups are enabled for the user @type usegroups: boolean @param useloans: If loans are enabled for the user @type useloans: boolean @param usestats: If stats are enabled for the user @type usestats: boolean @param usecomments: If comments are enabled for the user @type usecomments: boolean @return: html menu of the user activities @rtype: string """ # load the right message language _ = gettext_set_language(ln) out = '''
    %(personalize)s
      ''' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'personalize': _("Personalize"), 'on': selected and " on" or '', 'selected': selected and "selected" or '' } if not guest: out += '
    • %(account)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'account' : _('Your account') } if usealerts or guest: out += '
    • %(alerts)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'alerts' : _('Your alerts') } if referee: out += '
    • %(approvals)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'approvals' : _('Your approvals') } if usebaskets or guest: out += '
    • %(baskets)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'baskets' : _('Your baskets') } if usecomments: out += '
    • %(comments)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'comments' : _('Your comments') } if usegroups: out += '
    • %(groups)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'groups' : _('Your groups') } if useloans: out += '
    • %(loans)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'loans' : _('Your loans') } if usemessages: out += '
    • %(messages)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'messages' : _('Your messages') } if submitter: out += '
    • %(submissions)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'submissions' : _('Your submissions') } if usealerts or guest: out += '
    • %(searches)s
    • ' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'searches' : _('Your searches') } out += '
    ' return out def tmpl_create_adminactivities_menu(self, ln, selected, url_referer, guest, username, submitter, referee, admin, usebaskets, usemessages, usealerts, usegroups, useloans, usestats, activities): """ Returns the main navigation menu with actions based on user's priviledges @param ln: The language to display the interface in @type ln: string @param selected: If the menu is currently selected @type selected: boolean @param url_referer: URL of the page being displayed @type url_referer: string @param guest: If the user is guest @type guest: string @param username: The username (nickname or email) @type username: string @param submitter: If the user is submitter @type submitter: boolean @param referee: If the user is referee @type referee: boolean @param admin: If the user is admin @type admin: boolean @param usebaskets: If baskets are enabled for the user @type usebaskets: boolean @param usemessages: If messages are enabled for the user @type usemessages: boolean @param usealerts: If alerts are enabled for the user @type usealerts: boolean @param usegroups: If groups are enabled for the user @type usegroups: boolean @param useloans: If loans are enabled for the user @type useloans: boolean @param usestats: If stats are enabled for the user @type usestats: boolean @param activities: dictionary of admin activities @rtype activities: dict @return: html menu of the user activities @rtype: string """ # load the right message language _ = gettext_set_language(ln) out = '' if activities: out += '''
    %(admin)s
      ''' % { 'CFG_SITE_SECURE_URL' : CFG_SITE_SECURE_URL, 'ln' : ln, 'admin': _("Administration"), 'on': selected and " on" or '', 'selected': selected and "selected" or '' } for name in sorted(activities.iterkeys()): url = activities[name] out += '
    • %(name)s
    • ' % { 'url': url, 'name': name } if usestats: out += """
    • %(stats)s
    • """ % { 'CFG_SITE_URL' : CFG_SITE_URL, 'ln' : ln, 'stats' : _("Statistics"), } out += '
    ' return out def tmpl_warning(self, warnings, ln=CFG_SITE_LANG): """ Display len(warnings) warning fields @param infos: list of strings @param ln=language @return: html output """ if not((type(warnings) is list) or (type(warnings) is tuple)): warnings = [warnings] warningbox = "" if warnings != []: warningbox = "
    \n Warning:\n" for warning in warnings: lines = warning.split("\n") warningbox += "

    " for line in lines[0:-1]: warningbox += line + "
    \n" warningbox += lines[-1] + "

    " warningbox += "

    \n" return warningbox def tmpl_error(self, error, ln=CFG_SITE_LANG): """ Display error @param error: string @param ln=language @return: html output """ _ = gettext_set_language(ln) errorbox = "" if error != "": errorbox = "
    \n Error:\n" errorbox += "

    " errorbox += error + "

    " errorbox += "

    \n" return errorbox def tmpl_display_all_groups(self, infos, admin_group_html, member_group_html, external_group_html = None, warnings=[], ln=CFG_SITE_LANG): """ Displays the 3 tables of groups: admin, member and external Parameters: - 'ln' *string* - The language to display the interface in - 'admin_group_html' *string* - HTML code for displaying all the groups the user is the administrator of - 'member_group_html' *string* - HTML code for displaying all the groups the user is member of - 'external_group_html' *string* - HTML code for displaying all the external groups the user is member of """ _ = gettext_set_language(ln) group_text = self.tmpl_infobox(infos) group_text += self.tmpl_warning(warnings) if external_group_html: group_text += """
    %s

    %s

    %s
    """ %(admin_group_html, member_group_html, external_group_html) else: group_text += """
    %s

    %s
    """ %(admin_group_html, member_group_html) return group_text def tmpl_display_admin_groups(self, groups, ln=CFG_SITE_LANG): """ Display the groups the user is admin of. Parameters: - 'ln' *string* - The language to display the interface in - 'groups' *list* - All the group the user is admin of - 'infos' *list* - Display infos on top of admin group table """ _ = gettext_set_language(ln) img_link = """ %(text)s
    %(text)s
    """ out = self.tmpl_group_table_title(img="/img/group_admin.png", text=_("You are an administrator of the following groups:") ) out += """ """ %(_("Group"), _("Description")) if len(groups) == 0: out += """ """ %(_("You are not an administrator of any groups."),) for group_data in groups: (grpID, name, description) = group_data edit_link = img_link % {'siteurl' : CFG_SITE_URL, 'grpID' : grpID, 'ln': ln, 'img':"webbasket_create_small.png", 'text':_("Edit group"), 'action':"edit" } members_link = img_link % {'siteurl' : CFG_SITE_URL, 'grpID' : grpID, 'ln': ln, 'img':"webbasket_usergroup.png", 'text':_("Edit %s members") % '', 'action':"members" } out += """ """ % (cgi.escape(name), cgi.escape(description), edit_link, members_link) out += """
    %s %s    
    %s
    %s %s %s %s
         
    """ % {'ln': ln, 'write_label': _("Create new group"), } return out def tmpl_display_member_groups(self, groups, ln=CFG_SITE_LANG): """ Display the groups the user is member of. Parameters: - 'ln' *string* - The language to display the interface in - 'groups' *list* - All the group the user is member of """ _ = gettext_set_language(ln) group_text = self.tmpl_group_table_title(img="/img/webbasket_us.png", text=_("You are a member of the following groups:")) group_text += """ """ % (_("Group"), _("Description")) if len(groups) == 0: group_text += """ """ %(_("You are not a member of any groups."),) for group_data in groups: (id, name, description) = group_data group_text += """ """ % (cgi.escape(name), cgi.escape(description)) group_text += """
    %s %s
    %s
    %s %s
    """ % {'ln': ln, 'join_label': _("Join new group"), 'leave_label':_("Leave group") } return group_text def tmpl_display_external_groups(self, groups, ln=CFG_SITE_LANG): """ Display the external groups the user is member of. Parameters: - 'ln' *string* - The language to display the interface in - 'groups' *list* - All the group the user is member of """ _ = gettext_set_language(ln) group_text = self.tmpl_group_table_title(img="/img/webbasket_us.png", text=_("You are a member of the following external groups:")) group_text += """ """ % (_("Group"), _("Description")) if len(groups) == 0: group_text += """ """ %(_("You are not a member of any external groups."),) for group_data in groups: (id, name, description) = group_data group_text += """ """ % (cgi.escape(name), cgi.escape(description)) group_text += """
    %s %s
    %s
    %s %s
    """ return group_text def tmpl_display_input_group_info(self, group_name, group_description, join_policy, act_type="create", grpID=None, warnings=[], ln=CFG_SITE_LANG): """ Display group data when creating or updating a group: Name, description, join_policy. Parameters: - 'ln' *string* - The language to display the interface in - 'group_name' *string* - name of the group - 'group_description' *string* - description of the group - 'join_policy' *string* - join policy - 'act_type' *string* - info about action : create or edit(update) - 'grpID' *int* - ID of the group(not None in case of group editing) - 'warnings' *list* - Display warning if values are not correct """ _ = gettext_set_language(ln) #default hidden_id ="" form_name = "create_group" action = CFG_SITE_URL + '/yourgroups/create' button_label = _("Create new group") button_name = "create_button" label = _("Create new group") delete_text = "" if act_type == "update": form_name = "update_group" action = CFG_SITE_URL + '/yourgroups/edit' button_label = _("Update group") button_name = "update" label = _('Edit group %s') % cgi.escape(group_name) delete_text = """""" delete_text %= (_("Delete group"),"delete") if grpID is not None: hidden_id = """""" hidden_id %= grpID out = self.tmpl_warning(warnings) out += """
    %(label)s %(label)s
    %(join_policy_label)s %(join_policy)s
    %(hidden_id)s
    %(delete_text)s
    """ out %= {'action' : action, 'logo': CFG_SITE_URL + '/img/webbasket_create.png', 'label': label, 'form_name' : form_name, 'name_label': _("Group name:"), 'delete_text': delete_text, 'description_label': _("Group description:"), 'join_policy_label': _("Group join policy:"), 'group_name': cgi.escape(group_name, 1), 'group_description': cgi.escape(group_description, 1), 'button_label': button_label, 'button_name':button_name, 'cancel_label':_("Cancel"), 'hidden_id':hidden_id, 'ln': ln, 'join_policy' :self.__create_join_policy_selection_menu("join_policy", join_policy, ln) } return out def tmpl_display_input_join_group(self, group_list, group_name, group_from_search, search, warnings=[], ln=CFG_SITE_LANG): """ Display the groups the user can join. He can use default select list or the search box Parameters: - 'ln' *string* - The language to display the interface in - 'group_list' *list* - All the group the user can join - 'group_name' *string* - Name of the group the user is looking for - 'group_from search' *list* - List of the group the user can join matching group_name - 'search' *int* - User is looking for group using group_name - 'warnings' *list* - Display warning if two group are selected """ _ = gettext_set_language(ln) out = self.tmpl_warning(warnings) search_content = "" if search: search_content = """ """ if group_from_search != []: search_content += self.__create_select_menu('grpID', group_from_search, _("Please select:")) else: search_content += _("No matching group") search_content += """ """ out += """
    %(label)s %(label)s
    %(search_content)s
    %(list_label)s %(group_list)s  



    """ out %= {'action' : CFG_SITE_URL + '/yourgroups/join', 'logo': CFG_SITE_URL + '/img/webbasket_create.png', 'label': _("Join group"), 'group_name': cgi.escape(group_name, 1), 'label2':_("or find it") + ': ', 'list_label':_("Choose group:"), 'ln': ln, 'find_label': _("Find group"), 'cancel_label':_("Cancel"), 'group_list' :self.__create_select_menu("grpID",group_list, _("Please select:")), 'search_content' : search_content } return out def tmpl_display_manage_member(self, grpID, group_name, members, pending_members, infos=[], warnings=[], ln=CFG_SITE_LANG): """Display current members and waiting members of a group. Parameters: - 'ln' *string* - The language to display the interface in - 'grpID *int* - ID of the group - 'group_name' *string* - Name of the group - 'members' *list* - List of the current members - 'pending_members' *list* - List of the waiting members - 'infos' *tuple of 2 lists* - Message to inform user about his last action - 'warnings' *list* - Display warning if two group are selected """ _ = gettext_set_language(ln) out = self.tmpl_warning(warnings) out += self.tmpl_infobox(infos) out += """

    %(title)s

    %(img_alt_header1)s %(header1)s
     
    %(member_text)s
    %(img_alt_header2)s %(header2)s
     
    %(pending_text)s
    %(img_alt_header3)s %(header3)s
     
    %(invite_text)s
    """ if members : member_list = self.__create_select_menu("member_id", members, _("Please select:")) member_text = """ %s """ % (member_list,_("Remove member")) else : member_text = """%s""" % _("No members.") if pending_members : pending_list = self.__create_select_menu("pending_member_id", pending_members, _("Please select:")) pending_text = """ %s """ % (pending_list,_("Accept member"), _("Reject member")) else : pending_text = """%s""" % _("No members awaiting approval.") header1 = self.tmpl_group_table_title(text=_("Current members")) header2 = self.tmpl_group_table_title(text=_("Members awaiting approval")) header3 = _("Invite new members") write_a_message_url = create_url( "%s/yourmessages/write" % CFG_SITE_URL, { 'ln' : ln, 'msg_subject' : _('Invitation to join "%s" group' % escape_html(group_name)), 'msg_body' : _("""\ Hello: I think you might be interested in joining the group "%(x_name)s". You can join by clicking here: %(x_url)s. Best regards. """) % {'x_name': group_name, 'x_url': create_html_link("%s/yourgroups/join" % CFG_SITE_URL, { 'grpID' : grpID, 'join_button' : "1", }, link_label=group_name, escape_urlargd=True, escape_linkattrd=True)}}) link_open = '' % escape_html(write_a_message_url) invite_text = _("If you want to invite new members to join your group, please use the %(x_url_open)sweb message%(x_url_close)s system.") % \ {'x_url_open': link_open, 'x_url_close': ''} action = CFG_SITE_URL + '/yourgroups/members?ln=' + ln out %= {'title':_('Group: %s') % escape_html(group_name), 'member_text' : member_text, 'pending_text' :pending_text, 'action':action, 'grpID':grpID, 'header1': header1, 'header2': header2, 'header3': header3, 'img_alt_header1': _("Current members"), 'img_alt_header2': _("Members awaiting approval"), 'img_alt_header3': _("Invite new members"), 'invite_text': invite_text, 'imgurl': CFG_SITE_URL + '/img', 'cancel_label':_("Cancel"), 'ln':ln } return out def tmpl_display_input_leave_group(self, groups, warnings=[], ln=CFG_SITE_LANG): """Display groups the user can leave. Parameters: - 'ln' *string* - The language to display the interface in - 'groups' *list* - List of groups the user is currently member of - 'warnings' *list* - Display warning if no group is selected """ _ = gettext_set_language(ln) out = self.tmpl_warning(warnings) out += """
    %(label)s %(label)s
    %(list_label)s %(groups)s  
    %(submit)s
    """ if groups: groups = self.__create_select_menu("grpID", groups, _("Please select:")) list_label = _("Group list") submit = """""" % _("Leave group") else : groups = _("You are not member of any group.") list_label = "" submit = "" action = CFG_SITE_URL + '/yourgroups/leave?ln=%s' action %= (ln) out %= {'groups' : groups, 'list_label' : list_label, 'action':action, 'logo': CFG_SITE_URL + '/img/webbasket_create.png', 'label' : _("Leave group"), 'cancel_label':_("Cancel"), 'ln' :ln, 'submit' : submit } return out def tmpl_confirm_delete(self, grpID, ln=CFG_SITE_LANG): """ display a confirm message when deleting a group @param grpID *int* - ID of the group @param ln: language @return: html output """ _ = gettext_set_language(ln) action = CFG_SITE_URL + '/yourgroups/edit' out = """
    %(message)s
    """% {'message': _("Are you sure you want to delete this group?"), 'ln':ln, 'yes_label': _("Yes"), 'no_label': _("No"), 'grpID':grpID, 'action': action } return out def tmpl_confirm_leave(self, uid, grpID, ln=CFG_SITE_LANG): """ display a confirm message @param grpID *int* - ID of the group @param ln: language @return: html output """ _ = gettext_set_language(ln) action = CFG_SITE_URL + '/yourgroups/leave' out = """
    %(message)s
    """% {'message': _("Are you sure you want to leave this group?"), 'ln':ln, 'yes_label': _("Yes"), 'no_label': _("No"), 'grpID':grpID, 'action': action } return out def __create_join_policy_selection_menu(self, name, current_join_policy, ln=CFG_SITE_LANG): """Private function. create a drop down menu for selection of join policy @param current_join_policy: join policy as defined in CFG_WEBSESSION_GROUP_JOIN_POLICY @param ln: language """ _ = gettext_set_language(ln) elements = [(CFG_WEBSESSION_GROUP_JOIN_POLICY['VISIBLEOPEN'], _("Visible and open for new members")), (CFG_WEBSESSION_GROUP_JOIN_POLICY['VISIBLEMAIL'], _("Visible but new members need approval")) ] select_text = _("Please select:") return self.__create_select_menu(name, elements, select_text, selected_key=current_join_policy) def __create_select_menu(self, name, elements, select_text, multiple=0, selected_key=None): """ private function, returns a popup menu @param name: name of HTML control @param elements: list of (key, value) """ if multiple : out = """ """ % name out += '' % (select_text) for (key, label) in elements: selected = '' if key == selected_key: selected = ' selected="selected"' out += ''% (key, selected, label) out += '' return out def tmpl_infobox(self, infos, ln=CFG_SITE_LANG): """Display len(infos) information fields @param infos: list of strings @param ln=language @return: html output """ _ = gettext_set_language(ln) if not((type(infos) is list) or (type(infos) is tuple)): infos = [infos] infobox = "" for info in infos: infobox += '
    ' lines = info.split("\n") for line in lines[0:-1]: infobox += line + "
    \n" infobox += lines[-1] + "
    \n" return infobox def tmpl_navtrail(self, ln=CFG_SITE_LANG, title=""): """ display the navtrail, e.g.: Your account > Your group > title @param title: the last part of the navtrail. Is not a link @param ln: language return html formatted navtrail """ _ = gettext_set_language(ln) nav_h1 = '%s' nav_h2 = "" if (title != ""): nav_h2 = ' > %s' nav_h2 = nav_h2 % (CFG_SITE_URL, _("Your Groups")) return nav_h1 % (CFG_SITE_URL, _("Your Account")) + nav_h2 def tmpl_group_table_title(self, img="", text="", ln=CFG_SITE_LANG): """ display the title of a table: - 'img' *string* - img path - 'text' *string* - title - 'ln' *string* - The language to display the interface in """ out = "
    " if img: out += """ """ % (CFG_SITE_URL + img) out += """ %s
    """ % text return out def tmpl_admin_msg(self, group_name, grpID, ln=CFG_SITE_LANG): """ return message content for joining group - 'group_name' *string* - name of the group - 'grpID' *int* - ID of the group - 'ln' *string* - The language to display the interface in """ _ = gettext_set_language(ln) subject = _("Group %s: New membership request") % group_name url = CFG_SITE_URL + "/yourgroups/members?grpID=%s&ln=%s" url %= (grpID, ln) # FIXME: which user? We should show his nickname. body = (_("A user wants to join the group %s.") % group_name) + '
    ' body += _("Please %(x_url_open)saccept or reject%(x_url_close)s this user's request.") % {'x_url_open': '', 'x_url_close': ''} body += '
    ' return subject, body def tmpl_member_msg(self, group_name, accepted=0, ln=CFG_SITE_LANG): """ return message content when new member is accepted/rejected - 'group_name' *string* - name of the group - 'accepted' *int* - 1 if new membership has been accepted, 0 if it has been rejected - 'ln' *string* - The language to display the interface in """ _ = gettext_set_language(ln) if accepted: subject = _("Group %s: Join request has been accepted") % (group_name) body = _("Your request for joining group %s has been accepted.") % (group_name) else: subject = _("Group %s: Join request has been rejected") % (group_name) body = _("Your request for joining group %s has been rejected.") % (group_name) url = CFG_SITE_URL + "/yourgroups/display?ln=" + ln body += '
    ' body += _("You can consult the list of %(x_url_open)syour groups%(x_url_close)s.") % {'x_url_open': '', 'x_url_close': ''} body += '
    ' return subject, body def tmpl_delete_msg(self, group_name, ln=CFG_SITE_LANG): """ return message content when new member is accepted/rejected - 'group_name' *string* - name of the group - 'ln' *string* - The language to display the interface in """ _ = gettext_set_language(ln) subject = _("Group %s has been deleted") % group_name url = CFG_SITE_URL + "/yourgroups/display?ln=" + ln body = _("Group %s has been deleted by its administrator.") % group_name body += '
    ' body += _("You can consult the list of %(x_url_open)syour groups%(x_url_close)s.") % {'x_url_open': '', 'x_url_close': ''} body += '
    ' return subject, body def tmpl_group_info(self, nb_admin_groups=0, nb_member_groups=0, nb_total_groups=0, ln=CFG_SITE_LANG): """ display infos about groups (used by myaccount.py) @param nb_admin_group: number of groups the user is admin of @param nb_member_group: number of groups the user is member of @param total_group: number of groups the user belongs to @param ln: language return: html output. """ _ = gettext_set_language(ln) out = _("You can consult the list of %(x_url_open)s%(x_nb_total)i groups%(x_url_close)s you are subscribed to (%(x_nb_member)i) or administering (%(x_nb_admin)i).") out %= {'x_url_open': '', 'x_nb_total': nb_total_groups, 'x_url_close': '', 'x_nb_admin': nb_admin_groups, 'x_nb_member': nb_member_groups} return out def tmpl_general_warnings(self, warning_list, ln=CFG_SITE_LANG): """ display information to the admin user about possible ssecurity problems in the system. """ message = "" _ = gettext_set_language(ln) #Try and connect to the mysql database with the default invenio password if "warning_mysql_password_equal_to_invenio_password" in warning_list: message += "

    " message += _("Warning: The password set for MySQL root user is the same as the default Invenio password. For security purposes, you may want to change the password.") message += "

    " #Try and connect to the invenio database with the default invenio password if "warning_invenio_password_equal_to_default" in warning_list: message += "

    " message += _("Warning: The password set for the Invenio MySQL user is the same as the shipped default. For security purposes, you may want to change the password.") message += "

    " #Check if the admin password is empty if "warning_empty_admin_password" in warning_list: message += "

    " message += _("Warning: The password set for the Invenio admin user is currently empty. For security purposes, it is strongly recommended that you add a password.") message += "

    " #Check if the admin email has been changed from the default if "warning_site_support_email_equal_to_default" in warning_list: message += "

    " message += _("Warning: The email address set for support email is currently set to info@invenio-software.org. It is recommended that you change this to your own address.") message += "

    " #Check for a new release if "note_new_release_available" in warning_list: message += "

    " message += _("A newer version of Invenio is available for download. You may want to visit ") message += "http://invenio-software.org/wiki/Installation/Download" message += "

    " #Error downloading release notes if "error_cannot_download_release_notes" in warning_list: message += "

    " message += _("Cannot download or parse release notes from http://invenio-software.org/repo/invenio/tree/RELEASE-NOTES") message += "

    " return message