diff --git a/modules/webjournal/Makefile.am b/modules/webjournal/Makefile.am index 19afa5f8f..6ccce1654 100644 --- a/modules/webjournal/Makefile.am +++ b/modules/webjournal/Makefile.am @@ -1,22 +1,22 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -SUBDIRS = doc lib +SUBDIRS = doc lib web CLEANFILES = *~ diff --git a/modules/webjournal/doc/Makefile.am b/modules/webjournal/doc/Makefile.am index ce0516ee7..b0981c0f8 100644 --- a/modules/webjournal/doc/Makefile.am +++ b/modules/webjournal/doc/Makefile.am @@ -1,20 +1,20 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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. +## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. SUBDIRS = admin hacking diff --git a/modules/webjournal/lib/Makefile.am b/modules/webjournal/lib/Makefile.am index 0fb2e0d15..9b982e650 100644 --- a/modules/webjournal/lib/Makefile.am +++ b/modules/webjournal/lib/Makefile.am @@ -1,32 +1,32 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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. +## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. SUBDIRS = widgets pylibdir = $(libdir)/python/invenio pylib_DATA = webjournal_webinterface.py webjournal_utils.py \ webjournal_config.py webjournal.py webjournal_washer.py \ - webjournal_templates.py + webjournal_templates.py webjournaladminlib.py formatdir = $(pylibdir)/bibformat_elements format_DATA = bfe_ObjectLanguage.py EXTRA_DIST = $(pylib_DATA) $(format_DATA) CLEANFILES = *~ *.tmp *.pyc diff --git a/modules/webjournal/lib/webjournal.py b/modules/webjournal/lib/webjournal.py index 475301487..08bf9b36d 100644 --- a/modules/webjournal/lib/webjournal.py +++ b/modules/webjournal/lib/webjournal.py @@ -1,444 +1,279 @@ # -*- coding: utf-8 -*- +## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +""" +WebJournal - Main Public interface of the WebJournals +""" -from urllib2 import urlopen -import smtplib -import sets import time -from invenio.bibformat_engine import BibFormatObject, \ - format_with_format_template +from invenio.bibformat_engine import \ + BibFormatObject, \ + format_with_format_template from invenio.errorlib import register_exception -from invenio.webpage import page -from invenio.config import CFG_SITE_URL, CFG_ETCDIR +from invenio.config import \ + CFG_SITE_URL, \ + CFG_ACCESS_CONTROL_LEVEL_SITE from invenio.urlutils import redirect_to_url from invenio.webuser import collect_user_info - -from invenio.webjournal_config import InvenioWebJournalNoIndexTemplateError, \ - InvenioWebJournalNoIssueNumberTagError, \ - InvenioWebJournalNoArticleTemplateError, \ - InvenioWebJournalNoArticleRuleError, \ - InvenioWebJournalNoPopupTemplateError, \ - InvenioWebJournalReleaseUpdateError, \ - InvenioWebJournalIssueNotFoundDBError, \ - InvenioWebJournalJournalIdNotFoundDBError, \ - InvenioWebJournalArchiveDateWronglyFormedError, \ - InvenioWebJournalNoSearchTemplateError +from invenio.webjournal_config import \ + InvenioWebJournalNoIndexTemplateError, \ + InvenioWebJournalNoIssueNumberTagError, \ + InvenioWebJournalNoArticleTemplateError, \ + InvenioWebJournalNoArticleRuleError, \ + InvenioWebJournalNoPopupTemplateError, \ + InvenioWebJournalNoSearchTemplateError from invenio.webjournal_utils import get_xml_from_config -from invenio.webjournal_utils import get_recid_from_order_CERNBulletin, \ - get_article_page_from_cache, \ - cache_article_page, \ - createhtmlmail, \ - put_css_in_file, \ - get_monday_of_the_week, \ - get_current_issue_time, \ - get_all_issue_weeks, \ - release_journal_update, \ - get_next_journal_issues, \ - issue_times_to_week_strings, \ - issue_week_strings_to_times, \ - release_journal_issue, \ - was_alert_sent_for_issue, \ - update_DB_for_alert, \ - get_current_issue, \ - get_current_publication, \ - get_list_of_issues_for_publication, \ - count_down_to_monday, \ - count_week_string_up -from invenio.webjournal_templates import tmpl_webjournal_alert_success_msg, \ - tmpl_webjournal_alert_subject_CERNBulletin, \ - tmpl_webjournal_alert_plain_text_CERNBulletin, \ - tmpl_webjournal_alert_interface, \ - tmpl_webjournal_issue_control_interface, \ - tmpl_webjournal_issue_control_success_msg, \ - tmpl_webjournal_update_an_issue, \ - tmpl_webjournal_updated_issue_msg, \ - tmpl_webjournal_alert_was_already_sent, \ - tmpl_webjournal_admin_interface +from invenio.webjournal_utils import \ + get_article_page_from_cache, \ + cache_article_page, \ + issue_times_to_week_strings, \ + count_down_to_monday, \ + get_current_issue -def perform_request_index(req, journal_name, issue_number, language, category): +def perform_request_index(req, journal_name, issue_number, ln, + category, editor=False, verbose=0): """ Central logic function for index pages. Brings together format templates and MARC rules from the config, with the requested index page, given by the url parameters. From config: - page template for index pages -> formatting - MARC rule list -> Category Navigation - MARC tag used for issue numbers -> search (later in the format elements) Uses BibFormatObject and format_with_format_template to produce the required HTML. """ # init all the values we need from config.xml config_strings = get_xml_from_config(["index", "rule", "issue_number"], journal_name) try: try: index_page_template = config_strings["index"][0] except: - raise InvenioWebJournalNoIndexTemplateError(language, journal_name) + raise InvenioWebJournalNoIndexTemplateError(ln, journal_name) except InvenioWebJournalNoIndexTemplateError, e: register_exception(req=req) return e.user_box() index_page_template_path = 'webjournal/%s' % (index_page_template) rule_list = config_strings["rule"] try: if len(rule_list) == 0: - raise InvenioWebJournalNoArticleRuleError(language, journal_name) + raise InvenioWebJournalNoArticleRuleError(ln, journal_name) except InvenioWebJournalNoArticleRuleError, e: register_exception(req=req) return e.user_box() try: try: issue_number_tag = config_strings["issue_number"][0] except: - raise InvenioWebJournalNoIssueNumberTagError(language, journal_name) + raise InvenioWebJournalNoIssueNumberTagError(ln, journal_name) except InvenioWebJournalNoIssueNumberTagError, e: register_exception(req=req) return e.user_box() # get the current category for index display current_category_in_list = 0 i = 0 - if category != "": + if category: for rule_string in rule_list: category_from_config = rule_string.split(",")[0] if category_from_config.lower() == category.lower(): current_category_in_list = i - i+=1 - else: - # add the first category to the url string as a default - req.journal_defaults["category"] = rule_list[0].split(",")[0] + i += 1 +## else: +## # add the first category to the url string as a default +## req.journal_defaults["category"] = rule_list[0].split(",")[0] + # get the important values for the category from the config file rule_string = rule_list[current_category_in_list].replace(" ", "") category = rule_string.split(",")[0] rule = rule_string.split(",")[1] marc_datafield = rule.split(":")[0] rule_match = rule.split(":")[1] marc_tag = marc_datafield[:3] marc_ind1 = (str(marc_datafield[3]) == "_") and " " or marc_datafield[3] marc_ind2 = (str(marc_datafield[4]) == "_") and " " or marc_datafield[4] marc_subfield = marc_datafield[5] # create a marc record, containing category and issue number temp_marc = ''' 0 %s %s ''' % (issue_number_tag[:3], (issue_number_tag[3] == "_") and " " or issue_number_tag[3], (issue_number_tag[4] == "_") and " " or issue_number_tag[4], issue_number_tag[5], issue_number, marc_tag, marc_ind1, marc_ind2, marc_subfield, rule_match) #temp_marc = temp_marc.decode('utf-8').encode('utf-8') # create a record and get HTML back from bibformat user_info = collect_user_info(req) - bfo = BibFormatObject(0, ln=language, xml_record=temp_marc, user_info=user_info) + bfo = BibFormatObject(0, ln=ln, xml_record=temp_marc, + user_info=user_info) bfo.req = req - html = format_with_format_template(index_page_template_path, bfo)[0] + verbosity = 0 + if editor: + # Increase verbosity only for editors/admins + verbosity = verbose + + html = format_with_format_template(index_page_template_path, + bfo, + verbose=verbosity)[0] return html -def perform_request_article(req, journal_name, issue_number, language, - category, number, editor): +def perform_request_article(req, journal_name, issue_number, ln, + category, recid, editor=False, verbose=0): """ Central logic function for article pages. Loads the format template for article display and displays the requested article using BibFormat. - 'Editor' Mode genereates edit links on the article view page and disables + 'Editor' mode generates edit links on the article view page and disables caching. """ # init all the values we need from config.xml config_strings = get_xml_from_config(["detailed", "rule"], journal_name) try: try: index_page_template = config_strings["detailed"][0] except: - raise InvenioWebJournalNoArticleTemplateError(language, + raise InvenioWebJournalNoArticleTemplateError(ln, journal_name) except InvenioWebJournalNoArticleTemplateError, e: register_exception(req=req) return e.user_box() index_page_template_path = 'webjournal/%s' % (index_page_template) rule_list = config_strings["rule"] try: if len(rule_list) == 0: - raise InvenioWebJournalNoArticleRuleError(language, journal_name) + raise InvenioWebJournalNoArticleRuleError(ln, journal_name) except InvenioWebJournalNoArticleRuleError, e: register_exception(req=req) return e.user_box() # get the current category for index display current_category_in_list = 0 i = 0 if category != "": for rule_string in rule_list: category_from_config = rule_string.split(",")[0] if category_from_config.lower() == category.lower(): current_category_in_list = i - i+=1 + i += 1 rule_string = rule_list[current_category_in_list].replace(" ", "") rule = rule_string.split(",")[1] # try to get the page from the cache - recid = get_recid_from_order_CERNBulletin(number, rule, issue_number) cached_html = get_article_page_from_cache(journal_name, category, recid, - issue_number, language) - if cached_html and editor == "False": + issue_number, ln) + if cached_html and not editor: return cached_html # create a record and get HTML back from bibformat user_info = collect_user_info(req) - bfo = BibFormatObject(recid, ln=language, user_info=user_info) + bfo = BibFormatObject(recid, ln=ln, user_info=user_info) bfo.req = req + verbosity = 0 + if editor: + # Increase verbosity only for editors/admins + verbosity = verbose html_out = format_with_format_template(index_page_template_path, - bfo)[0] - # cache if not in editor mode - if editor == "False": + bfo, verbose=verbosity)[0] + # cache if not in editor mode, and if database is not down + if not editor and not CFG_ACCESS_CONTROL_LEVEL_SITE == 2: cache_article_page(html_out, journal_name, category, - recid, issue_number, language) + recid, issue_number, ln) return html_out -def perform_request_administrate(journal_name, language): - """ - """ - current_issue = get_current_issue(language, journal_name) - current_publication = get_current_publication(journal_name, - current_issue, - language) - issue_list = get_list_of_issues_for_publication(current_publication) - next_issue_number = count_week_string_up(issue_list[-1]) - return tmpl_webjournal_admin_interface(journal_name, current_issue, - current_publication, issue_list, - next_issue_number, language) - - -def perform_request_alert(req, journal_name, issue_number, language, - sent, plain_text, subject, recipients, - html_mail, force): - """ - All the logic for alert emails. - Messages are retrieved from templates. (should be migrated to msg class) - Mails can be edited by an interface form. - Sent in HTML/PlainText or only PlainText if wished so. - """ - subject = tmpl_webjournal_alert_subject_CERNBulletin(journal_name, - issue_number) - plain_text = tmpl_webjournal_alert_plain_text_CERNBulletin(journal_name, - language, - issue_number) - plain_text = plain_text.encode('utf-8') - - if sent == "False": - interface = tmpl_webjournal_alert_interface(language, journal_name, - subject, plain_text) - return page(title="alert system", body=interface) - else: - if was_alert_sent_for_issue(issue_number, - journal_name, - language) != False and force == "False": - return tmpl_webjournal_alert_was_already_sent(language, journal_name, - subject, plain_text, - recipients, - html_mail, issue_number) - if html_mail == "html": - html_file = urlopen('%s/journal/?name=%s&ln=en' - % (CFG_SITE_URL, journal_name)) - html_string = html_file.read() - html_file.close() - html_string = put_css_in_file(html_string, journal_name) - else: - html_string = plain_text.replace("\n", "
") - - message = createhtmlmail(html_string, plain_text, - subject, recipients) - - ## Transform the recipients string into a list for the mail server: - to_addresses = [raw_address.strip() for raw_address in \ - recipients.split(",")] - recipients = to_addresses - - ## Send the mail: - server = smtplib.SMTP("localhost", 25) - server.sendmail('Bulletin-Support@cern.ch', recipients, message) - # todo: has to go to some messages config - update_DB_for_alert(issue_number, journal_name, language) - return tmpl_webjournal_alert_success_msg(language, journal_name) - -def perform_request_issue_control(req, journal_name, issue_numbers, - language, add, action): - """ - Central logic for issue control. - Regenerates the flat files current_issue and issue_group that control - the which issue is currently active for the journal. - Todo: move issue control to DB - """ - if action == "cfg" or action == "Refresh" or action == "Add_One": - # find out if we are in update or release - try: - current_issue_time = get_current_issue_time(journal_name) - all_issue_weeks = get_all_issue_weeks(current_issue_time, - journal_name, - language) - except InvenioWebJournalIssueNotFoundDBError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalJournalIdNotFoundDBError, e: - register_exception(req=req) - return e.user_box() - if max(all_issue_weeks) > current_issue_time: - # propose an update - next_issue_week = None - all_issue_weeks.sort() - for issue_week in all_issue_weeks: - if issue_week > current_issue_time: - next_issue_week = issue_week - break - output = tmpl_webjournal_update_an_issue(language, - journal_name, - issue_times_to_week_strings([next_issue_week,])[0], - issue_times_to_week_strings([current_issue_time,])[0]) - else: - # propose a release - next_issues = get_next_journal_issues(current_issue_time, - journal_name) - next_issues = issue_times_to_week_strings(next_issues, - language) - if action == "Refresh": - next_issues += issue_numbers - next_issues = list(sets.Set(next_issues))# avoid double entries - elif action == "Add_One": - next_issues += issue_numbers - next_issues = list(sets.Set(next_issues))# avoid double entries - next_issues_times = issue_week_strings_to_times(next_issues, - language) - highest_issue_so_far = max(next_issues_times) - one_more_issue = get_next_journal_issues(highest_issue_so_far, - journal_name, - language, - 1) - one_more_issue = issue_times_to_week_strings(one_more_issue, - language) - next_issues += one_more_issue - next_issues = list(sets.Set(next_issues)) # avoid double entries - next_issues.sort() - else: - # get the next (default 2) issue numbers to publish - next_issues = get_next_journal_issues(current_issue_time, - journal_name, - language) - next_issues = issue_times_to_week_strings(next_issues, - language) - output = tmpl_webjournal_issue_control_interface(language, - journal_name, - next_issues) - elif action == "Publish": - publish_issues = issue_numbers - publish_issues = list(sets.Set(publish_issues)) # avoid double entries - publish_issues.sort() - try: - release_journal_issue(publish_issues, journal_name, language) - except InvenioWebJournalJournalIdNotFoundDBError, e: - register_exception(req=req) - return e.user_box() - output = tmpl_webjournal_issue_control_success_msg(language, - publish_issues, journal_name) - - elif action == "Update": - try: - try: - update_issue = issue_numbers[0] - except: - raise InvenioWebJournalReleaseUpdateError(language, journal_name) - except InvenioWebJournalReleaseUpdateError, e: - register_exception(req=req) - return e.user_box() - try: - release_journal_update(update_issue, journal_name, language) - except InvenioWebJournalJournalIdNotFoundDBError, e: - register_exception(req=req) - return e.user_box() - output = tmpl_webjournal_updated_issue_msg(language, update_issue, - journal_name) - - return page(title="Publish System", body=output) - -def perform_request_popup(req, language, journal_name, type, record): +def perform_request_popup(req, ln, journal_name, record): """ + Display the popup window """ config_strings = get_xml_from_config(["popup"], journal_name) try: try: popup_page_template = config_strings["popup"][0] except: - raise InvenioWebJournalNoPopupTemplateError(language) + raise InvenioWebJournalNoPopupTemplateError(ln) except InvenioWebJournalNoPopupTemplateError, e: register_exception(req=req) return e.user_box() popup_page_template_path = 'webjournal/%s' % popup_page_template user_info = collect_user_info(req) - bfo = BibFormatObject(record, ln=language, user_info=user_info) + bfo = BibFormatObject(record, ln=ln, user_info=user_info) bfo.req = req html = format_with_format_template(popup_page_template_path, bfo)[0] return html -def perform_request_search(journal_name, language, req, issue, - archive_year, archive_issue, archive_select, - archive_date, archive_search): +def perform_request_search(req, journal_name, ln, + archive_issue, archive_select, + archive_date, archive_search, verbose=0): """ Logic for the search / archive page. """ config_strings = get_xml_from_config(["search", "issue_number", "rule"], journal_name) try: try: search_page_template = config_strings["search"][0] except: - raise InvenioWebJournalNoSearchTemplateError(journal_name, language) + raise InvenioWebJournalNoSearchTemplateError(journal_name, + ln) except InvenioWebJournalNoSearchTemplateError, e: register_exception(req=req) return e.user_box() - search_page_template_path = 'webjournal/%s' % (search_page_template) - # just an empty buffer record, since all values are in req.journal_defaults + search_page_template_path = 'webjournal/%s' % (search_page_template) if archive_select == "False" and archive_search == "False": temp_marc = ''' 0 ''' user_info = collect_user_info(req) - bfo = BibFormatObject(0, ln=language, xml_record=temp_marc, user_info=user_info) + bfo = BibFormatObject(0, + ln=ln, + xml_record=temp_marc, + user_info=user_info) bfo.req = req - html = format_with_format_template(search_page_template_path, bfo)[0] + html = format_with_format_template(search_page_template_path, + bfo, + verbose=verbose)[0] return html elif archive_select == "Go": - redirect_to_url(req, "%s/journal/?name=%s&issue=%s&ln=%s" % (CFG_SITE_URL, - journal_name, - archive_issue, - language)) + redirect_to_url(req, "%s/journal/%s/%s/%s?ln=%s" % (CFG_SITE_URL, + journal_name, + archive_issue.split('/')[1], + archive_issue.split('/')[0], + ln)) elif archive_search == "Go": - archive_issue_time = time.strptime(archive_date, "%d/%m/%Y") - archive_issue_time = count_down_to_monday(archive_issue_time) - archive_issue = issue_times_to_week_strings([archive_issue_time,])[0] - redirect_to_url(req, "%s/journal/?name=%s&issue=%s&ln=%s" % (CFG_SITE_URL, - journal_name, - archive_issue, - language)) + try: + archive_issue_time = time.strptime(archive_date, "%d/%m/%Y") + archive_issue_time = count_down_to_monday(archive_issue_time) + archive_issue = issue_times_to_week_strings([archive_issue_time])[0] + except ValueError: + archive_issue = get_current_issue(ln, journal_name) + redirect_to_url(req, "%s/journal/%s/%s/%s?ln=%s" % (CFG_SITE_URL, + journal_name, + archive_issue.split('/')[1], + archive_issue.split('/')[0], + ln)) diff --git a/modules/webjournal/lib/webjournal_config.py b/modules/webjournal/lib/webjournal_config.py index 27658e124..26f15a02c 100644 --- a/modules/webjournal/lib/webjournal_config.py +++ b/modules/webjournal/lib/webjournal_config.py @@ -1,679 +1,652 @@ # -*- coding: utf-8 -*- ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. import os -from invenio.config import CFG_SITE_ADMIN_EMAIL, CFG_SITE_SUPPORT_EMAIL, CFG_ETCDIR, CFG_SITE_URL, CFG_SITE_LANG +from invenio.config import \ + CFG_SITE_ADMIN_EMAIL, \ + CFG_SITE_SUPPORT_EMAIL, \ + CFG_ETCDIR, \ + CFG_SITE_URL, \ + CFG_SITE_LANG from invenio.messages import gettext_set_language from invenio.webpage import page from invenio.htmlutils import escape_html -from invenio.messages import gettext_set_language -from invenio.webjournal_utils import parse_url_string -from invenio.webjournal_templates import tmpl_webjournal_error_box,\ - tmpl_webjournal_missing_info_box +import invenio.template +webjournal_templates = invenio.template.load('webjournal') + + #from invenio.data_cacher import SQLDataCacher # #CFG_JOURNAL_CONFIG_CACHE = {} # #def initialize_config_cache(): # """ # """ # journal_id_names = SQLDataCacher("SELECT * FROM jrnJOURNAL", affected_tables=(jrnJOURNAL)) class InvenioWebJournalNoIndexTemplateError(Exception): """Exception if no index template is specified in the config.""" - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """Initialisation.""" self.journal = journal_name - self.language = language + self.ln = ln def __str__(self): """String representation.""" return 'Admin did not provide a template for the index page of \ journal: %s. \ The path to such a file should be given in the config.xml of\ this journal under the tag ...\ ' % repr(self.journal) def user_box(self): """ user-friendly error message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Internal configuration error'), _('There is no format configured for this journals index page'), 'Admin did not provide a template for the index page of journal: %s. \ The path to such a file should be given in the config.xml of\ this journal under the tag ...\ ' % escape_html(self.journal)) class InvenioWebJournalNoArticleTemplateError(Exception): """ Exception if an article was called without its order number. """ - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """ Initialisation. """ self.journal = journal_name - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'Admin did not provide a template for the article view page of journal: %s. \ The path to such a file should be given in the config.xml of this journal \ under the tag ...' % repr(self.journal) def user_box(self): """ user-friendly error message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Internal configuration error'), _('There is no format configured for this journals index page'), 'Admin did not provide a template for the index page of journal: %s. \ The path to such a file should be given in the config.xml of\ this journal under the tag ...\ ' % escape_html(self.journal)) class InvenioWebJournalNoSearchTemplateError(Exception): """ Exception if an article was called without its order number. """ - def __init__(self, journal_name, language=CFG_SITE_LANG): + def __init__(self, journal_name, ln=CFG_SITE_LANG): """ Initialisation. """ self.journal = journal_name - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'Admin did not provide a template for the search page view page of journal: %s. \ The path to such a file should be given in the config.xml of this journal \ under the tag ...' % repr(self.journal) def user_box(self): """ user-friendly error message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Internal configuration error'), _('There is no format configured for this journals search page'), 'Admin did not provide a template for the search page of journal: %s. \ The path to such a file should be given in the config.xml of\ this journal under the tag ...\ ' % escape_html(self.journal)) class InvenioWebJournalNoPopupTemplateError(Exception): """ Exception if an article was called without its order number. """ - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """ Initialisation. """ self.journal = journal_name - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'Admin did not provide a template for the popup view page \ of journal: %s. \ The path to such a file should be given in the config.xml of this \ journal under the tag \ ...' % repr( self.journal) def user_box(self): """ user-friendly error message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Internal configuration error'), _('There is no format configured for this journals popup page'), 'Admin did not provide a template for the popup page of journal: %s. \ The path to such a file should be given in the config.xml of\ this journal under the tag ...\ ' % escape_html(self.journal)) class InvenioWebJournalNoArticleRuleError(Exception): """ Exception if there are no article type rules defined. """ - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """ Initialisation. """ self.journal = journal_name - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'The config.xml file for journal: %s does not contain any \ article rules. These rules are needed to associate collections from \ your Invenio installation to navigable article types. A rule should \ have the form of NameOfArticleType, \ marc_tag:ExpectedContentOfMarcTag' % escape_html(self.journal) def user_box(self): """ user-friendly error message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _("No journal articles"), _("Problem with the configuration of this journal"), "The system couldn't find the definitions for different article \ kinds (e.g. News, Sports, etc). If there is nothing defined, \ nothing can be shown and it thus indicates that there is either a \ problem with the setup of this journal or in the Software itself.\ There is nothing you can do at this moment. If you wish you can \ send an inquiry to the responsible developers. We apologize \ for the inconvenience.") class InvenioWebJournalNoIssueNumberTagError(Exception): """ Exception if there is no marc tag for issue number defined. """ - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """ Initialisation. """ self.journal = journal_name - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'The config.xml file for journal: %s does not contain a marc tag\ to deduce the issue number from. WebJournal is an issue number based \ system, meaning you have to give some form of numbering system in a \ dedicated marc tag, so the system can see which is the active journal \ publication of the date.' % repr(self.journal) def user_box(self): """ user-friendly error message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _("No journal issues"), _("Problem with the configuration of this journal"), "The system couldn't find a definition for an issue \ numbering system. Issue numbers conrol the date of the \ publication you are seing. This indicates that there is an \ error in the setup of this journal or the Software itself. \ There is nothing you can do at the moment. If you wish you \ can send an inquiry to the responsible developers. We \ apologize for the inconvenience.") class InvenioWebJournalNoArticleNumberError(Exception): """ Exception if an article was called without its order number. """ - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """ Initialisation. """ self.journal = journal_name - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'In Journal %s an article was called without specifying the order \ of this article in the issue. This parameter is mandatory and should be \ provided by internal links in any case. Maybe this was a bad direct url \ hack. Check where the request came from.' % repr(self.journal) def user_box(self): """ user-friendly error message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Journal article error'), _('We could not know which article you were looking for'), 'The url you passed did not provide an article number or the \ article number was badly formed. If you \ came to this page through some link on the journal page, please \ report this to the admin. If you got this link through some \ external resource, e.g. an email, you can try to put in a number \ for the article in the url by hand or just visit the front \ page at %s/journal/?name=%s' % (CFG_SITE_URL, self.journal)) class InvenioWebJournalNoJournalOnServerError(Exception): """ Exception that is thrown if there are no Journal instances on the server """ - def __init__(self, language): + def __init__(self, ln): """ Initialisation. """ - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'Apparently there are no journals configured on this \ installation of CDS Invenio. You can try to use the sample Invenio \ Atlantis Journal for testing.' def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('No journals available'), _('We could not provide you any journals'), _('It seems that there are no journals defined on this server. ' 'Please contact support if this is not right.')) class InvenioWebJournalNoNameError(Exception): """ """ - def __init__(self, language): + def __init__(self, ln): """ Initialisation. """ - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'User probably forgot to add the name parameter for the journal\ Maybe you also want to check if dns mappings are configured correctly.' def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return webjournal_missing_info_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_missing_info_box(self.ln, _("Select a journal on this server"), _("We couldn't guess which journal you are looking for"), _("You did not provide an argument for a journal name. " "Please select the journal you want to read in the list below.")) class InvenioWebJournalNoCurrentIssueError(Exception): """ """ - def __init__(self, language): + def __init__(self, ln): """ Initialisation. """ - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'There seems to be no current issue number stored for this \ journal. Is this the first time you use the journal? Otherwise, check\ configuration.' def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_error_box(self.ln, _('No current issue'), _('We could not find any informtion on the current issue'), _('The configuration for the current issue seems to be empty. ' 'Try providing an issue number or check with support.')) class InvenioWebJournalIssueNumberBadlyFormedError(Exception): """ """ - def __init__(self, language, issue): + def __init__(self, ln, issue): """ Initialisation. """ - self.language = language + self.ln = ln self.issue = issue def __str__(self): """ String representation. """ return 'The issue number was badly formed. If this comes from the \ user it is no problem.' def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Issue number badly formed'), _('We could not read the issue number you provided'), 'The issue number you provided in the url seems to be badly\ formed. Issue numbers have to be in the form of ww/YYYY, so\ e.g. 50/2007. You provided the issue number like so: \ %s.' % escape_html(self.issue)) class InvenioWebJournalArchiveDateWronglyFormedError (Exception): """ """ - def __init__(self, language, date): + def __init__(self, ln, date): """ Initialisation. """ - self.language = language + self.ln = ln self.date = date def __str__(self): """ String representation. """ return 'The archive date was badly formed. If this comes from the \ user it is no problem.' def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Archive date badly formed'), _('We could not read the archive date you provided'), 'The archive date you provided in the form seems to be badly\ formed. Archive dates have to be in the form of dd/mm/YYYY, so\ e.g. 02/12/2007. You provided the archive date like so: \ %s.' % escape_html(self.date)) -class IvenioWebJournalNoPopupTypeError(Exception): - """ - Exception that is thrown if a popup is requested without specifying the - type of the popup to call. - """ - def __init__(self, language, journal_name): - """ - Initialisation. - """ - self.language = language - self.journal_name = journal_name - - def __str__(self): - """ - String representation. - """ - return 'There was no popup type provided for a popup window on \ - journal %s.' % repr(self.journal_name) - - def user_box(self): - """ - user-friendly message with formatting. - """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, - _('No popup type'), - _('We could not know what kind of popup you requested'), - 'You called a popup window on CDS Invenio without \ - specifying the type of the popup. Does this link come \ - from a CDS Invenio Journal? If so, please contact \ - support.') - class InvenioWebJournalNoPopupRecordError(Exception): """ Exception that is thrown if a popup is requested without specifying the type of the popup to call. """ - def __init__(self, language, journal_name, recid): + def __init__(self, ln, journal_name, recid): """ Initialisation. """ - self.language = language + self.ln = ln self.journal_name = journal_name self.recid = recid def __str__(self): """ String representation. """ return 'There was no recid provided to the popup system of webjournal \ or the recid was badly formed. The recid was %s' % repr(self.recid) def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('No popup record'), _('We could not deduce the popup article you requested'), 'You called a popup window on CDS Invenio without \ specifying a record in which you are interested or the \ record was badly formed. Does this link come \ from a CDS Invenio Journal? If so, please contact \ support.') class InvenioWebJournalReleaseUpdateError(Exception): """ Exception that is thrown if an update release was not successful. """ - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """ Initialisation. """ - self.language = language + self.ln = ln self.journal_name = journal_name def __str__(self): """ String representation. """ return 'There were no updates submitted on a click on the update button.\ This should never happen and must be due to an internal error.' def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Update error'), _('There was an internal error'), 'We encountered an internal error trying to update the \ journal issue. You can try to launch the update again or \ contact the Administrator. We apologize for the \ inconvenience.') class InvenioWebJournalReleaseDBError(Exception): """ Exception that is thrown if an update release was not successful. """ - def __init__(self, language): + def __init__(self, ln): """ Initialisation. """ - self.language = language + self.ln = ln def __str__(self): """ String representation. """ return 'There was an error in synchronizing DB times with the actual \ python time objects. Debug the code in: \ webjournal_utils.issue_times_to_week_strings' def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Journal publishing DB error'), _('There was an internal error'), 'We encountered an internal error trying to publish the \ journal issue. You can try to launch the publish interface \ again or contact the Administrator. We apologize for the \ inconvenience.') class InvenioWebJournalIssueNotFoundDBError(Exception): """ Exception that is thrown if there was an issue number not found in the """ - def __init__(self, language, journal_name, issue_number): + def __init__(self, ln, journal_name, issue_number): """ Initialisation. """ - self.language = language + self.ln = ln self.journal_name = journal_name self.issue_number = issue_number def __str__(self): """ String representation. """ return 'The issue %s could not be found in the DB for journal %s.' % (self.issue_number, self.journal_name) def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Journal issue error'), _('We could not find a current issue in the Database'), 'We encountered an internal error trying to get an issue \ number. You can try to refresh the page or \ contact the Administrator. We apologize for the \ inconvenience.') class InvenioWebJournalJournalIdNotFoundDBError(Exception): """ Exception that is thrown if there was an issue number not found in the """ - def __init__(self, language, journal_name): + def __init__(self, ln, journal_name): """ Initialisation. """ - self.language = language + self.ln = ln self.journal_name = journal_name def __str__(self): """ String representation. """ return 'The id for journal %s was not found in the Database. Make \ sure the entry exists!' % (self.journal_name) def user_box(self): """ user-friendly message with formatting. """ - _ = gettext_set_language(self.language) - return tmpl_webjournal_error_box(self.language, + _ = gettext_set_language(self.ln) + return webjournal_templates.tmpl_webjournal_error_box(self.ln, _('Journal ID error'), _('We could not find the id for this journal in the Database'), 'We encountered an internal error trying to get the id \ for this journal. You can try to refresh the page or \ contact the Administrator. We apologize for the \ inconvenience.') #!!! depreceated !!!# -def webjournal_missing_info_box(language, title, msg_title, msg): +def webjournal_missing_info_box(ln, title, msg_title, msg): """ returns a box indicating that the given journal was not found on the server, leaving the opportunity to select an existing journal from a list. """ #params = parse_url_string(req) #try: - # language = params["ln"] + # ln = params["ln"] #except: - # language = CFG_SITE_LANG - _ = gettext_set_language(language) + # ln = CFG_SITE_LANG + _ = gettext_set_language(ln) title = _(title) box_title = _(msg_title) box_text = _(msg) box_list_title = _("Available journals") find_journals = lambda path: [entry for entry in os.listdir(str(path)) if os.path.isdir(str(path)+str(entry))] try: all_journals = find_journals('%s/webjournal/' % CFG_ETCDIR) except: all_journals = [] box = '''
%s

%s

%s

    %s

Mail the Administrator.
''' % (CFG_SITE_URL, box_title, box_text, box_list_title, "".join(['
  • %s
  • ' % (CFG_SITE_URL, journal, journal) for journal in all_journals]), CFG_SITE_ADMIN_EMAIL) return page(title=title, body=box) #!!! depreceated !!!# -def webjournal_error_box(language, title, title_msg, msg): +def webjournal_error_box(ln, title, title_msg, msg): """ """ #params = parse_url_string(req) #try: - # language = params["ln"] + # ln = params["ln"] #except: - # language = CFG_SITE_LANG - _ = gettext_set_language(language) + # ln = CFG_SITE_LANG + _ = gettext_set_language(ln) title = _(title) title_msg = _(title_msg) msg = _(msg) box = '''
    %s

    %s


    Mail the Developers.
    ''' % (CFG_SITE_URL, title_msg, msg, CFG_SITE_SUPPORT_EMAIL) return page(title=title, body=box) diff --git a/modules/webjournal/lib/webjournal_templates.py b/modules/webjournal/lib/webjournal_templates.py index 3def7c822..e58750383 100644 --- a/modules/webjournal/lib/webjournal_templates.py +++ b/modules/webjournal/lib/webjournal_templates.py @@ -1,447 +1,670 @@ # -*- coding: utf-8 -*- ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. import os import time -from invenio.config import CFG_SITE_ADMIN_EMAIL, CFG_SITE_SUPPORT_EMAIL, CFG_ETCDIR, CFG_SITE_URL, CFG_SITE_LANG +from invenio.config import \ + CFG_SITE_ADMIN_EMAIL, \ + CFG_SITE_SUPPORT_EMAIL, \ + CFG_ETCDIR, \ + CFG_SITE_URL, \ + CFG_SITE_LANG from invenio.messages import gettext_set_language from invenio.webpage import page -from invenio.webjournal_utils import get_number_of_articles_for_issue, \ - get_release_time, \ - get_announcement_time, \ - get_current_publication - -def tmpl_webjournal_missing_info_box(language, title, msg_title, msg): - """ - returns a box indicating that the given journal was not found on the - server, leaving the opportunity to select an existing journal from a list. - """ - _ = gettext_set_language(language) - box_title = msg_title - box_text = msg - box_list_title = _("Available Journals") - # todo: move to DB call - find_journals = lambda path: [entry for entry in os.listdir(str(path)) if os.path.isdir(str(path)+str(entry))] - try: - all_journals = find_journals('%s/webjournal/' % CFG_ETCDIR) - except: - all_journals = [] - box = ''' -
    -
    - - %s - -

    %s

    -

    %s

    -
      - %s -
    -
    -
    - Mail - the Administrator. -
    -
    -
    - ''' % (CFG_SITE_URL, - box_title, - box_text, - box_list_title, - "".join(['
  • %s
  • ' - % (CFG_SITE_URL, - journal, - journal) for journal in all_journals]), - CFG_SITE_ADMIN_EMAIL) - return page(title=title, body=box) - -def tmpl_webjournal_error_box(language, title, title_msg, msg): - """ - returns an error box for webjournal errors. - """ - _ = gettext_set_language(language) - title = _(title) - title_msg = _(title_msg) - msg = _(msg) - mail_msg = _("Mail %(x_url_open)sdevelopers%(x_url_close)s") % {'x_url_open' : - '' % CFG_SITE_SUPPORT_EMAIL, - 'x_url_close' : ''} - box = ''' -
    -
    - - %s - -

    %s

    -
    -
    - %s -
    -
    -
    - ''' % (CFG_SITE_URL, title_msg, msg, mail_msg) - return page(title=title, body=box) - -def tmpl_webjournal_regenerate_success(language, journal_name, issue_number): - """ - Success message if a user applied the "regenerate" link. Links back to - the regenerated journal. - """ - _ = gettext_set_language(language) - return page( - title=_("Issue regenerated"), - body = ''' - The issue number %s for the journal %s has been successfully - regenerated. - Look at your changes: >> %s - ''' % (issue_number, journal_name, CFG_SITE_URL, journal_name, journal_name)) - -def tmpl_webjournal_regenerate_error(language, journal_name, issue_number): - """ - Failure message for a regeneration try. - """ - _ = gettext_set_language(language) - return page( - title=_("Regeneration Error"), - body = _("The issue could not be correctly regenerated. " - "Please contact your administrator.")) - -def tmpl_webjournal_feature_record_interface(language, journal_name): - """ - Draws an interface form to feature a specific record from CDS Invenio. - """ - _ = gettext_set_language(language) - interface = ''' -
    - -

    Featured Record ID:

    - -

    Link to the picture that should be displayed

    - -
    - -
    - ''' % (CFG_SITE_URL, journal_name) - return page(title=_("Feature a record"), body=interface) - -def tmpl_webjournal_feature_record_success(language, journal_name, recid): - """ - Draw a success message for featuring a record and a backlink to the journal - """ - _ = gettext_set_language(language) - title = "Successfully featured record: %s" % recid - msg = '''Return to your journal here >> - %s''' % (CFG_SITE_URL, - journal_name, - journal_name) - return page(title = title, body = msg) - -def tmpl_webjournal_alert_plain_text_CERNBulletin(journal_name, language, issue): - """ - Plain Text message for alert of CERN Bulletin. No multilanguage since the - message should always be in two languages. - """ - current_publication = get_current_publication(journal_name, issue) - plain_text = u'''Dear Subscriber, - -The latest issue of the CERN Bulletin, no. %s, has been released. -You can access it at the following URL: -http://bulletin.cern.ch/ - -Best Wishes, -CERN Bulletin team - ----- +from invenio.webjournal_utils import \ + get_number_of_articles_for_issue, \ + get_release_time, \ + get_announcement_time, \ + get_current_publication + +class Template: + """Templating class, refer to bibformat.py for examples of call""" + + def tmpl_webjournal_missing_info_box(self, ln, title, msg_title, msg): + """ + returns a box indicating that the given journal was not found on the + server, leaving the opportunity to select an existing journal from a list. + """ + _ = gettext_set_language(ln) + box_title = msg_title + box_text = msg + box_list_title = _("Available Journals") + # todo: move to DB call + find_journals = lambda path: [entry for entry in os.listdir(str(path)) \ + if os.path.isdir(str(path)+str(entry))] + try: + all_journals = find_journals('%s/webjournal/' % CFG_ETCDIR) + except: + all_journals = [] + box = ''' +
    +
    + + %s + +

    %s

    +

    %s

    +
      + %s +
    +
    +
    + Mail + the Administrator. +
    +
    +
    + ''' % (CFG_SITE_URL, + box_title, + box_text, + box_list_title, + "".join(['
  • %s
  • ' + % (CFG_SITE_URL, + journal, + journal) for journal in all_journals]), + CFG_SITE_ADMIN_EMAIL) + return page(title=title, body=box) + + def tmpl_webjournal_error_box(self, ln, title, title_msg, msg): + """ + returns an error box for webjournal errors. + """ + _ = gettext_set_language(ln) + title = _(title) + title_msg = _(title_msg) + msg = _(msg) + mail_msg = _("Mail %(x_url_open)sdevelopers%(x_url_close)s") % {'x_url_open' : + '' % CFG_SITE_SUPPORT_EMAIL, + 'x_url_close' : ''} + box = ''' +
    +
    + + %s + +

    %s

    +
    +
    + %s +
    +
    +
    + ''' % (CFG_SITE_URL, title_msg, msg, mail_msg) + return page(title=title, body=box) + + def tmpl_admin_regenerate_success(self, ln, journal_name, issue): + """ + Success message if a user applied the "regenerate" link. Links back to + the regenerated journal. + """ + _ = gettext_set_language(ln) + + out = ''' + The issue number %(issue)s for the %(journal_name)s journal has been successfully + regenerated.
    + Look at your changes: >> %(journal_name)s
    or go back to this journal administration interface. + ''' % {'issue': issue, + 'journal_name': journal_name, + 'CFG_SITE_URL': CFG_SITE_URL, + 'issue_year': issue.split('/')[1], + 'issue_number': issue.split('/')[0]} + + return out + + def tmpl_admin_regenerate_error(self, ln, journal_name, issue): + """ + Failure message for a regeneration try. + """ + _ = gettext_set_language(ln) + return page( + title=_("Regeneration Error"), + body = _("The issue could not be correctly regenerated. " + "Please contact your administrator.")) + + def tmpl_admin_feature_record(self, journal_name, + featured_records=[], + ln=CFG_SITE_LANG, + msg=None): + """ + Display an interface form to feature a specific record from CDS Invenio. + """ + _ = gettext_set_language(ln) + out = '' + out += ''' + + + + + + + +
    %(menu)s
    0. Administrate 1. Feature a Record 2. Edit Configuration 3. Go to the Journal 

    ''' % {'journal_name': journal_name, + 'menu': _("Menu"), + 'CFG_SITE_URL': CFG_SITE_URL} + if msg is not None: + out += msg + out += '

    ' + out += ''' + + + ''' + color = "fff" + for (recid, img_url) in featured_records: + out += ''' + + + + ''' % {'color': color, + 'journal_name': journal_name, + 'recid': recid, + 'img_url': img_url, + 'CFG_SITE_URL': CFG_SITE_URL} + if color == 'fff': + color = 'EBF7FF' + else: + color = 'fff' + if len(featured_records) == 0: + out += '' + out += '
    Featured records
    Record %(recid)sremove
    No record featured for the moment. Add one using the form below.
    ' + out += ''' +


    +
    + + + + + + + + + + + + + + + + + +
    Add a new featured record:

    Image displayed along the featured record
    +
    + ''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'journal_name': journal_name} + return out + + def tmpl_admin_alert_plain_text(self, journal_name, ln, issue): + """ + Default plain text message for email alert of journal updates. + This will be used to pre-fill the content of the mail alert, that + can be modified by the admin. + + Customize this function to return different default texts + based on journal name and language, + """ + current_publication = get_current_publication(journal_name, issue) + plain_text = u'''Dear Subscriber, + + The latest issue of the CERN Bulletin, no. %s, has been released. + You can access it at the following URL: + http://bulletin.cern.ch/ + + Best Wishes, + CERN Bulletin team + + ---- Cher Abonné, -Le nouveau numéro du CERN Bulletin, no. %s, vient de paraître. -Vous pouvez y accéder à cette adresse : -http://bulletin.cern.ch/fre - -Bonne lecture, -L'équipe du Bulletin du CERN -''' % (current_publication, current_publication) - return plain_text - -def tmpl_webjournal_alert_subject_CERNBulletin(journal_name, issue): - """ - Subject text for the CERN Bulletin release. - """ - return "CERN bulletin %s released" % get_current_publication(journal_name, - issue) - -def tmpl_webjournal_alert_interface(language, journal_name, subject, - plain_text): - """ - Alert eMail interface. - """ - _ = gettext_set_language(language) - interface = ''' -
    - -

    Recipients:

    - -

    Subject:

    - -

    Plain Text Message:

    - -

    Send Homepage as html: - -

    -
    - -
    ''' % (CFG_SITE_URL, journal_name, subject, plain_text) - return interface - -def tmpl_webjournal_alert_was_already_sent(language, journal_name, - subject, plain_text, recipients, - html_mail, issue): - """ - """ - _ = gettext_set_language(language) - interface = ''' -
    - - - - - - -

    ATTENTION! The alert email for the issue %s has already been - sent. Are you absolutely sure you want to resend it?

    -

    Maybe you forgot to release an update issue? If so, please do this - first here.

    -

    Be aware, if you go on with this, the whole configured mailing list - will receive this message a second time. Only proceed if you know what - you are doing!

    -
    - -
    - ''' % (CFG_SITE_URL, journal_name, recipients, - subject, plain_text, html_mail, issue, CFG_SITE_URL, journal_name, - issue) - return page(title="Confirmation Required", body=interface) - -def tmpl_webjournal_alert_success_msg(language, journal_name): - """ - Success messge for the alert system. - """ - _ = gettext_set_language(language) - title = _("Alert sent successfully!") - body = 'Return to your journal here: >> \ - %s ' % (CFG_SITE_URL, journal_name, - journal_name) - return page(title=title, body=body) - -def tmpl_webjournal_issue_control_interface(language, journal_name, - active_issues): - """ - """ - _ = gettext_set_language(language) - interface = ''' -
    -

    Publishing Interface

    -

    This interface gives you the possibilite to create - your current webjournal publication. Every checked - issue number will be in the current publication. Once - you've made your selection you can publish the new - issue by clicking the Publish button at the end. -

    -
    - -
      -

      Issue Numbers to publish::..

      - %s + Le nouveau numéro du CERN Bulletin, no. %s, vient de paraître. + Vous pouvez y accéder à cette adresse : + http://bulletin.cern.ch/fre + + Bonne lecture, + L'équipe du Bulletin du CERN + ''' % (current_publication, current_publication) + return plain_text + # ' + + def tmpl_admin_alert_subject(self, journal_name, ln, issue): + """ + Default subject for email alert of journal updates. + + Customize this function to return different default texts + based on journal name and language, + """ + return "CERN bulletin %s released" % get_current_publication(journal_name, + issue) + + def tmpl_admin_alert_recipients(self, journal_name, ln, issue): + """ + Default recipients for email alert of journal updates. + + Customize this function to return different recipients + based on journal name and language. + Must return a list of comma-separated emails + """ + return "bulletin-alert-eng@cern.ch,bulletin-alert-fre@cern.ch,cern-staff@cern.ch,cern-fellows@cern.ch" + + def tmpl_admin_alert_interface(self, ln, journal_name, default_subject, + default_msg, default_recipients): + """ + Alert eMail interface. + """ + _ = gettext_set_language(ln) + interface = ''' + + +

      Recipients:

      + +

      Subject:

      + +

      Plain Text Message:

      + +

      Send Homepage as html: + +


      - -

      Add a higher issue number by clicking "Add_One"

      - -

      .. or add a custom issue number by typing it here and pressing "Refresh"

      - - + + ''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'journal_name': journal_name, + 'subject': default_subject, + 'plain_text': default_msg, + 'default_recipients': default_recipients} + + return interface + + def tmpl_admin_alert_was_already_sent(self, ln, journal_name, + subject, plain_text, recipients, + html_mail, issue): + """ + """ + _ = gettext_set_language(ln) + out = ''' +
      + + + + + + +

      ATTENTION! The alert email for the issue %(issue)s has already been + sent. Are you absolutely sure you want to resend it?

      +

      Maybe you forgot to release an update issue? If so, please do this + first here.

      +

      Be aware, if you go on with this, the whole configured mailing list + will receive this message a second time. Only proceed if you know what + you are doing!


      -
      -

      If all issues you want to publish are correctly checked, proceed \ - by clicking "Publish".

      - +
      -
    - ''' % (CFG_SITE_URL, - journal_name, - "".join(['
  •  %s
  • ' - % (issue, issue) for issue in active_issues]), - ) - - return interface - -def tmpl_webjournal_issue_control_success_msg(language, - active_issues, journal_name): - """ - """ - _ = gettext_set_language(language) - issue_string = "".join([" - %s" % issue for issue in active_issues]) - title = '

    Bulletin %s created successfully!

    ' % issue_string - body = '

    Now you can:

    \ -

    Return to your journal here: >> \ - %s \ -

    \ -

    Make additional publications here: >> \ - Issue Interface \ -

    \ -

    Send an alert email here: >> \ - Send an alert \ -

    ' % (CFG_SITE_URL, journal_name, - journal_name, CFG_SITE_URL, - journal_name, CFG_SITE_URL, journal_name) - return title + body - -def tmpl_webjournal_update_an_issue(language, journal_name, next_issue, - current_issue): - """ - A form that lets a user make an update to an issue number. - """ - _ = gettext_set_language(language) - current_articles = get_number_of_articles_for_issue(current_issue, - journal_name, - language) - next_articles = get_number_of_articles_for_issue(next_issue, - journal_name, - language) - - html = ''' -

    The Issue that was released on week %s has pending updates scheduled. The - next update for this issue is %s.

    -

    Note: If you want to make a new release, please click through all the - pending updates first.

    -

    Do you want to release the update from issue

    - %s (%s)
    - to issue %s (%s)

    - now?

    -
    - - - -
    - ''' % (current_issue, next_issue, - current_issue, - ",".join(["%s : %s" % (item[0], item[1]) for item in current_articles.iteritems()]), - next_issue, - ",".join(["%s : %s" % (item[0], item[1]) for item in next_articles.iteritems()]), - CFG_SITE_URL, journal_name, next_issue) - return html - -def tmpl_webjournal_updated_issue_msg(language, update_issue, journal_name): - """ - Prints a success message for the Update release of a journal. - """ - _ = gettext_set_language(language) - title = '

    Journal update %s published successfully!

    ' % update_issue - body = '

    Now you can:

    \ -

    Return to your journal here: >> \ - %s \ -

    \ -

    Go back to the publishing interface: >> \ - Issue Interface \ -

    \ -

    Send an alert email here: >> \ - Send an alert \ -

    ' % (CFG_SITE_URL, journal_name, journal_name, - CFG_SITE_URL, journal_name, CFG_SITE_URL, journal_name) - return title + body - -def tmpl_webjournal_admin_interface(journal_name, current_issue, + ''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'journal_name': journal_name, + 'recipients': recipients, + 'subject': subject, + 'plain_text': plain_text, + 'html_mail': html_mail, + 'issue': issue} + return out + + def tmpl_admin_alert_unreleased_issue(self, ln, journal_name): + """ + Tried to announce an unreleased issue + """ + _ = gettext_set_language(ln) + out = '''

    An alert cannot be send for this issue!

    + + You tried to send an alert for an issue that has not yet been released. + Release it first and retry.
    + + Go back to the administration interface. + ''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'journal_name': journal_name} + return out + + def tmpl_admin_alert_success_msg(self, ln, journal_name): + """ + Success messge for the alert system. + """ + _ = gettext_set_language(ln) + out = '''

    Alert sent successfully!

    + Return to your journal here: >> \ + %(journal_name)s
    + or go back to the administration interface''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'journal_name': journal_name} + return out + + def tmpl_admin_control_issue(self, ln, journal_name, + active_issues): + """ + Display the interface allowing to set the current issue. + """ + _ = gettext_set_language(ln) + out = ''' +

    This interface gives you the possibility to create your + current webjournal publication. Every checked issue number + will be in the current publication. Once you have made your + selection you can publish the new issue by clicking the %(publish)s + button at the end. +

    +
    + + Issue Numbers to publish: + +
    + +

    Add a higher issue number by clicking "%(add)s"

    + +

    .. or add a custom issue number by typing it here and pressing "%(refresh)s"

    + + +
    +
    +

    If all issues you want to publish are correctly checked, proceed \ + by clicking "%(publish)s".

    + +
    + ''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'journal_name': journal_name, + 'issues_list': "".join(['
  •  %s
  • ' + % (issue, issue) for issue in active_issues]), + 'add' : _("Add"), + 'publish' : _("Publish"), + 'refresh' : _("Refresh") + } + + return out + + def tmpl_admin_control_issue_success_msg(self, ln, + active_issues, journal_name): + """ + An issue was successfully published + """ + _ = gettext_set_language(ln) + issue_string = "".join([" - %s" % issue for issue in active_issues]) + title = '

    Issue(s) %s created successfully!

    ' % issue_string + body = '

    Now you can:

    \ +

    Return to your journal here: >> \ + %s \ +

    \ +

    Make additional publications here: >> \ + Issue Interface \ +

    \ +

    Send an alert email here: >> \ + Send an alert \ +

    ' % (CFG_SITE_URL, journal_name, + journal_name, CFG_SITE_URL, + journal_name, CFG_SITE_URL, journal_name) + return title + body + + def tmpl_admin_update_issue(self, ln, journal_name, next_issue, + current_issue): + """ + A form that lets a user make an update to an issue number. + """ + _ = gettext_set_language(ln) + current_articles = get_number_of_articles_for_issue(current_issue, + journal_name, + ln) + next_articles = get_number_of_articles_for_issue(next_issue, + journal_name, + ln) + + html = ''' +

    The Issue that was released on week %(current_issue)s has pending updates scheduled. The + next update for this issue is %(next_issue)s.

    +

    Note: If you want to make a new release, please click through all the + pending updates first.

    +

    Do you want to release the update from issue:
    +       %(current_issue)s (%(current_articles)s)
    + to issue:
    +       %(next_issue)s (%(next_articles)s)
    + now?

    +
    + + + +
    + ''' % {'current_issue': current_issue, + 'next_issue' : next_issue, + 'current_articles': ",".join(["%s : %s" % (item[0], item[1]) \ + for item in current_articles.iteritems()]), + 'next_articles': ",".join(["%s : %s" % (item[0], item[1]) \ + for item in next_articles.iteritems()]), + 'CFG_SITE_URL' : CFG_SITE_URL, + 'journal_name': journal_name, + 'update': _("Update")} + return html + + def tmpl_admin_updated_issue_msg(self, ln, update_issue, journal_name): + """ + Prints a success message for the Update release of a journal. + """ + _ = gettext_set_language(ln) + title = '

    Journal update %s published successfully!

    ' % update_issue + body = '

    Now you can:

    \ +

    Return to your journal here: >> \ + %s \ +

    \ +

    Go back to the publishing interface: >> \ + Issue Interface \ +

    \ +

    Send an alert email here: >> \ + Send an alert \ +

    ' % (CFG_SITE_URL, journal_name, journal_name, + CFG_SITE_URL, journal_name, CFG_SITE_URL, journal_name) + return title + body + + def tmpl_admin_administrate(self, journal_name, current_issue, current_publication, issue_list, - next_issue_number, language=CFG_SITE_LANG): - """ - Returns an administration interface that shows the current publication and - supports links to all important actions. - """ - _ = gettext_set_language(language) - title = _('Webjournal Administration Interface') - # format the issues - issue_boxes = [] - issue_list.append(next_issue_number) - for issue in issue_list: - articles = get_number_of_articles_for_issue(issue, - journal_name, - language) - released_on = get_release_time(issue, journal_name, language) - announced_on = get_announcement_time(issue, journal_name, language) - issue_box = ''' - - - -

    Issue: %s

    -

    Publication: %s

    - - - %s - - -

    %s

    -

    %s

    - - -

    Not implemented yet

    -

    >regenerate

    - - - ''' % ((issue==current_issue) and "background:#00FF00;" or "background:#F1F1F1;", - - issue, (issue==next_issue_number) and "?" or current_publication, - - "\n".join(['

    %s : %s >edit

    ' % - (item[0], item[1], - CFG_SITE_URL, journal_name, - issue, item[0]) for item in articles.iteritems()]), - - (released_on==False) and - 'not released
    >release now' % (CFG_SITE_URL, journal_name) or - 'released on: %s' % time.strftime("%d.%m.%Y", released_on), - - (announced_on==False) - and 'not announced
    >announce now' % (CFG_SITE_URL, journal_name, issue) or - 'announced on: %s
    >re-announce' % (time.strftime("%d.%m.%Y", announced_on), CFG_SITE_URL, journal_name, issue), - - CFG_SITE_URL, journal_name, issue - ) - issue_boxes.append(issue_box) - body = ''' - - - - - - - - - - %s - -
    Issue / PublicationArticlesRelease / AnnouncementCache Status
    - -

    Submit a Breaking News

    -

    Feature a Record

    -

    >Go to the Journal

    - ''' % ("\n".join([issue_box for issue_box in issue_boxes]), - CFG_SITE_URL, CFG_SITE_URL, journal_name, CFG_SITE_URL, journal_name) - - return page(title=title, body=body) + next_issue_number, ln=CFG_SITE_LANG): + """ + Returns an administration interface that shows the current publication and + supports links to all important actions. + """ + _ = gettext_set_language(ln) + out = '' + + out += ''' + + + + + + + +
    %(menu)s
    0. Administrate 1. Feature a Record 2. Edit Configuration 3. Go to the Journal 

    ''' % {'journal_name': journal_name, + 'menu': _("Menu"), + 'CFG_SITE_URL': CFG_SITE_URL} + + # format the issues + issue_boxes = [] + issue_list.append(next_issue_number) + for issue in issue_list: + articles = get_number_of_articles_for_issue(issue, + journal_name, + ln) + released_on = get_release_time(issue, journal_name, ln) + announced_on = get_announcement_time(issue, journal_name, ln) + issue_box = ''' + + + +

    Issue: %s

    +

    Publication: %s

    + + + %s + + +

    %s

    +

    %s

    + + +

    >regenerate

    + + + ''' % ((issue==current_issue) and "background:#00FF00;" or "background:#F1F1F1;", + + issue, (issue==next_issue_number) and "?" or current_publication, + + "\n".join(['

    %s : %s >edit

    ' % + (item[0], item[1], + CFG_SITE_URL, journal_name, + issue.split('/')[1], issue.split('/')[0], item[0]) \ + for item in articles.iteritems()]), + + (released_on==False) and + 'not released
    >release now' % (CFG_SITE_URL, journal_name) or + 'released on: %s' % time.strftime("%d.%m.%Y", released_on), + + (announced_on==False) + and 'not announced
    >announce now' % (CFG_SITE_URL, journal_name, issue) or + 'announced on: %s
    >re-announce' % (time.strftime("%d.%m.%Y", announced_on), CFG_SITE_URL, journal_name, issue), + + CFG_SITE_URL, journal_name, issue + ) + issue_boxes.append(issue_box) + out += ''' + + + + + + + + + + %s + +
    Issue / PublicationArticlesRelease / AnnouncementCache Status
    + ''' % ("\n".join([issue_box for issue_box in issue_boxes])) + + return out + + def tmpl_admin_index(self, ln, journals, msg=None): + """ + Returns the admin index page content. + + Lists the journals, and offers options to edit them, delete them + or add new journal + + params: + ln - ln + journals - list of tuples (journal_id, journal_name) + msg - message to be displayed + """ + out = "" + if msg is not None: + out += msg + out += ''' +

    Choose the journal you want to administrate.

    + + + + + + ''' + color = "fff" + for journal_info in journals: + out += ''' + + + + ''' % {'color': color, + 'journal_name': journal_info['name'], + 'journal_id': journal_info['id'], + 'CFG_SITE_URL': CFG_SITE_URL} + if color == 'fff': + color = 'EBF7FF' + else: + color = 'fff' + out += ''' + + ''' % {'color': color, + 'CFG_SITE_URL': CFG_SITE_URL} + out += '
    Journals 
    %(journal_name)seditdelete
    Add new journal
    ' + return out + + def tmpl_admin_configure_journal(self, ln, journal_name='', xml_config=None, + action='edit', msg=None): + """ + Display a page to change the settings of a journal. Also used to + add a new journal. + """ + out = '' + _ = gettext_set_language(ln) + journal_name_readonly = 'readonly="readonly" disabled="disabled"' + journal_name_note = '' + submit_button_label = _('Apply') + if action == 'add': + journal_name = '' + journal_name_readonly = '' + journal_name_note = 'Used in URLs. Choose it short and meaningful. This cannot be changed later' + submit_button_label = _('Add') + elif action in ['edit', 'editDone']: + # Display navigation menu + out += ''' + + + + + + + +
    %(menu)s
    0. Administrate 1. Feature a Record 2. Edit Configuration 3. Go to the Journal 

    ''' % {'journal_name': journal_name, + 'menu': _("Menu"), + 'CFG_SITE_URL': CFG_SITE_URL} + if msg is not None: + out += msg + out += '

    ' + + out += ''' +
    + + + + + + + + + + + + + + + + +
    + Journal settings
    %(journal_name_note)s
    +
    + ''' % {'journal_name': journal_name, + 'ln': ln, + 'readonly': '', + 'disabled': '', + 'xml_config': xml_config.encode('utf-8'), + 'journal_name_note': journal_name_note, + 'submit_button_label': submit_button_label, + 'journal_name_readonly': journal_name_readonly} + + return out diff --git a/modules/webjournal/lib/webjournal_utils.py b/modules/webjournal/lib/webjournal_utils.py index d4c52950f..f0add1045 100644 --- a/modules/webjournal/lib/webjournal_utils.py +++ b/modules/webjournal/lib/webjournal_utils.py @@ -1,1242 +1,1187 @@ # -*- coding: utf-8 -*- ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - """ Various utilities for WebJournal, e.g. config parser, etc. """ -from invenio.bibformat_engine import BibFormatObject -from invenio.errorlib import register_exception -from invenio.search_engine import search_pattern -from invenio.config import CFG_ETCDIR, CFG_SITE_URL, CFG_SITE_ADMIN_EMAIL, CFG_CACHEDIR, CFG_SITE_LANG -from invenio.messages import gettext_set_language -from invenio.webpage import page -from invenio.dbquery import run_sql -from xml.dom import minidom -from urllib2 import urlopen import time import datetime import re import os import cPickle +import urllib +from MySQLdb import OperationalError +from xml.dom import minidom + +from invenio.config import \ + CFG_ETCDIR, \ + CFG_SITE_URL, \ + CFG_CACHEDIR, \ + CFG_SITE_LANG, \ + CFG_ACCESS_CONTROL_LEVEL_SITE +from invenio.dbquery import run_sql +from invenio.bibformat_engine import BibFormatObject +from invenio.search_engine import search_pattern + +########################### REGULAR EXPRESSIONS ############################### + +header_pattern = re.compile('\s*(?P
    .*?)\s*

    ') +para_pattern = re.compile('(?P.+?)

    ', re.DOTALL) +image_pattern = re.compile(r''' + (\S*)["']?>)?# get the link location for the image + \s*# after each tag we can have arbitrary whitespaces +
    # the image is always centered + \s* + \S*)\s*border=1\s*(/)?># getting the image itself + \s* +
    + \s* + ()? + (
    |
    |
    )*# the caption can be separated by any nr of line breaks + ( + + \s* + + \s* +
    (?P.*?)
    # getting the caption + \s* +
    + \s* +
    + )?''', re.DOTALL | re.VERBOSE | re.IGNORECASE ) + #''',re.DOTALL | re.IGNORECASE | re.VERBOSE | re.MULTILINE) + ############################ MAPPING FUNCTIONS ################################ -def get_order_dict_from_recid_list(list, issue_number): +def get_featured_records(journal_name): """ - this is a centralized function that takes a list of recid's and brings it in - order using a centralized algorithm. this always has to be in sync with - the reverse function get_recid_from_order(order) + Returns the 'featured' records i.e. records chosen to be displayed + with an image on the main page, in the widgets section, for the + given journal. + + parameter: + + journal_name - (str) the name of the journal for which we want + to get the featured records + + returns: + list of tuples (recid, img_url) + """ + try: + feature_file = open('%s/webjournal/%s/featured_record' % \ + (CFG_ETCDIR, journal_name)) + except: + return [] + records = feature_file.readlines() + return [(record.split('---', 1)[0], record.split('---', 1)[1]) \ + for record in records if "---" in record] + +def add_featured_record(journal_name, recid, img_url): + """ + Adds the given record to the list of featured records of the given + journal. parameters: - list: a list of all recid's that should be brought into order - issue_number: the issue_number for which we are deriving the order - (this has to be one number) + journal_name - (str) the name of the journal to which the record + should be added. + + recid - (int) the record id of the record to be featured. + + img_url - (str) a url to an image icon displayed along the + featured record. returns: - ordered_records: a dictionary with the recids ordered by keys + 0 if everything went ok + 1 if record is already in the list + 2 if other problems """ - ordered_records = {} - for record in list: - temp_rec = BibFormatObject(record) - issue_numbers = temp_rec.fields('773__n') - order_number = temp_rec.fields('773__c') - # todo: the marc fields have to be set'able by some sort of config interface - n = 0 - for temp_issue in issue_numbers: - if temp_issue == issue_number: - try: - order_number = int(order_number[n]) - except: - # todo: Warning, record does not support numbering scheme - order_number = -1 - n+=1 - if order_number != -1: - try: - ordered_records[order_number] = record - except: - pass - # todo: Error, there are two records with the same order_number in the issue - else: - ordered_records[max(ordered_records.keys()) + 1] = record + # Check that record is not already there + featured_records = get_featured_records(journal_name) + for featured_recid, featured_img in featured_records: + if featured_recid == str(recid): + return 1 - return ordered_records + try: + fptr = open('%s/webjournal/%s/featured_record' + % (CFG_ETCDIR, journal_name), "a") + fptr.write(str(recid) + '---' + img_url + '\n') + fptr.close() + except: + return 2 + return 0 -def get_records_in_same_issue_in_order(recid): +def remove_featured_record(journal_name, recid): """ + Removes the given record from the list of featured records of the + given journal. + + parameters: + + journal_name - (str) the name of the journal to which the record + should be added. + + recid - (int) the record id of the record to be featured. """ - raise ("Not implemented yet.") + featured_records = get_featured_records(journal_name) + try: + fptr = open('%s/webjournal/%s/featured_record' + % (CFG_ETCDIR, journal_name), "w") + for featured_recid, featured_img in featured_records: + if str(featured_recid) != str(recid): + fptr.write(str(featured_recid) + '---' + featured_img + \ + '\n') + fptr.close() + except: + return 1 + return 0 -def get_recid_from_order(order, rule, issue_number): +def get_order_dict_from_recid_list(recids, issue_number): """ - takes the order of a record in the journal as passed in the url arguments - and derives the recid using the current issue number and the record - rule for this kind of records. + Returns the ordered list of input recids, for given + 'issue_number'. + + Since there might be several articles at the same position, the + returned structure is a dictionary with keys being order number + indicated in record metadata, and values being list of recids for + this order number (recids for one position are ordered from + highest to lowest recid). + Eg: {'1': [2390, 2386, 2385], + '3': [2388], + '2': [2389], + '4': [2387]} parameters: - order: the order at which the record appears in the journal as passed - in the url - rule: the defining rule of the journal record category - issue_number: the issue number for which we are searching + recids: a list of all recid's that should be brought into order + issue_number: the issue_number for which we are deriving the order + (this has to be one number) returns: - recid: the recid of the ordered record + ordered_records: a dictionary with the recids ordered by keys + """ - # get the id list - all_records = list(search_pattern(p="%s and 773__n:%s" % - (rule, issue_number), - f="&action_search=Search")) ordered_records = {} - for record in all_records: + records_without_defined_order = [] + for record in recids: temp_rec = BibFormatObject(record) - issue_numbers = temp_rec.fields('773__n') - order_number = temp_rec.fields('773__c') - # todo: fields for issue number and order number have to become generic - n = 0 - for temp_issue in issue_numbers: - if temp_issue == issue_number: - try: - order_number = int(order_number[n]) - except: - # todo: Warning, record does not support numbering scheme - order_number = -1 - n+=1 + articles_info = temp_rec.fields('773__') + for article_info in articles_info: + if article_info.get('n', '') == issue_number: + if article_info.has_key('c'): + order_number = article_info.get('c', '') + if ordered_records.has_key(order_number): + ordered_records[order_number].append(record) + else: + ordered_records[order_number] = [record] + else: + # No order? No problem! Append it at the end. + records_without_defined_order.append(record) - if order_number != -1: - try: - ordered_records[order_number] = record - except: - pass - # todo: Error, there are two records with the same order_number in the issue - else: - ordered_records[max(ordered_records.keys()) + 1] = record - try: - recid = ordered_records[int(order)] - except: - pass - # todo: ERROR, numbering scheme inconsistency - return recid + for record in records_without_defined_order: + ordered_records[max(ordered_records.keys()) + 1] = record -# todo: move to a template -def please_login(req, journal_name, ln="en", title="", message="", backlink=""): + for (order, records) in ordered_records.iteritems(): + # Reverse so that if there are several articles at same + # positon, newest appear first + records.reverse() + + return ordered_records + +def get_records_in_same_issue_in_order(recid): """ + TODO: Remove? """ - _ = gettext_set_language(ln) - if title == "": - title_out = _("Please login to perform this action.") - else: - title_out = title - if message == "": - message_out = _("In order to publish webjournal issues you must be logged \ - in and be authorized for this kind of task. If you have a \ - login, use the link \ - below to login.") - else: - message_out = message - - if backlink == "": - backlink_out = "%s/journal/issue_control?name=%s" % (CFG_SITE_URL, journal_name) - else: - backlink_out = backlink - - title_msg = _("We need you to login") - body_out = '''
    -
    - %s -

    %s

    -
    -

    Login

    -
    - -
    -
    - ''' % (CFG_SITE_URL, - title_msg, - message_out, - CFG_SITE_URL, - backlink_out, - CFG_SITE_ADMIN_EMAIL) - - return page(title = title_out, - body = body_out, - description = "", - keywords = "", - language = ln, - req = req) + raise ("Not implemented yet.") def get_rule_string_from_rule_list(rule_list, category): """ """ i = 0 current_category_in_list = 0 for rule_string in rule_list: category_from_config = rule_string.split(",")[0] if category_from_config.lower() == category.lower(): current_category_in_list = i - i+=1 + i += 1 try: rule_string = rule_list[current_category_in_list] except: rule_string = "" # todo: exception return rule_string def get_category_from_rule_string(rule_string): """ + TODO: Remove? """ pass def get_rule_string_from_category(category): """ + TODO: Remove? """ pass ######################## TIME / ISSUE FUNCTIONS ############################### def get_monday_of_the_week(week_number, year): """ CERN Bulletin specific function that returns a string indicating the Monday of each week as: Monday
    """ timetuple = issue_week_strings_to_times(['%s/%s' % (week_number, year), ])[0] return time.strftime("%A %d %B %Y", timetuple) -def get_issue_number_display(issue_number, journal_name, language=CFG_SITE_LANG): +def get_issue_number_display(issue_number, journal_name, ln=CFG_SITE_LANG): """ Returns the display string for a given issue number. """ - journal_id = get_journal_id(journal_name, language) + journal_id = get_journal_id(journal_name, ln) issue_display = run_sql("SELECT issue_display FROM jrnISSUE \ WHERE issue_number=%s AND id_jrnJOURNAL=%s", (issue_number, journal_id))[0][0] return issue_display -def get_current_issue_time(journal_name, language=CFG_SITE_LANG): +def get_current_issue_time(journal_name, ln=CFG_SITE_LANG): """ Return the current issue of a journal as a time object. """ - current_issue = get_current_issue(language, journal_name) + current_issue = get_current_issue(ln, journal_name) week_number = current_issue.split("/")[0] year = current_issue.split("/")[1] current_issue_time = issue_week_strings_to_times(['%s/%s' % (week_number, year), ])[0] return current_issue_time -def get_all_issue_weeks(issue_time, journal_name, language): +def get_all_issue_weeks(issue_time, journal_name, ln): """ Function that takes an issue_number, checks the DB for the issue_display which can contain the other (update) weeks involved with this issue and returns all issues in a list of timetuples (always for Monday of each week). """ from invenio.webjournal_config import InvenioWebJournalIssueNotFoundDBError journal_id = get_journal_id(journal_name) - issue_string = issue_times_to_week_strings([issue_time,])[0] + issue_string = issue_times_to_week_strings([issue_time])[0] try: issue_display = run_sql( "SELECT issue_display FROM jrnISSUE WHERE issue_number=%s \ AND id_jrnJOURNAL=%s", (issue_string, journal_id))[0][0] except: - raise InvenioWebJournalIssueNotFoundDBError(language, journal_name, + raise InvenioWebJournalIssueNotFoundDBError(ln, journal_name, issue_string) issue_bounds = issue_display.split("/")[0].split("-") year = issue_display.split("/")[1] all_issue_weeks = [] if len(issue_bounds) == 2: # is the year changing? -> "52-02/2008" if int(issue_bounds[0]) > int(issue_bounds[1]): # get everything from the old year old_year_issues = [] low_bound_time = issue_week_strings_to_times(['%s/%s' % (issue_bounds[0], str(int(year)-1)), ])[0] # if the year changes over the week we always take the higher year low_bound_date = datetime.date(int(time.strftime("%Y", low_bound_time)), int(time.strftime("%m", low_bound_time)), int(time.strftime("%d", low_bound_time))) week_counter = datetime.timedelta(weeks=1) date = low_bound_date # count up the weeks until you get to the new year while date.year != int(year): old_year_issues.append(date.timetuple()) #format = time.strftime("%W/%Y", date.timetuple()) date = date + week_counter # get everything from the new year new_year_issues = [] for i in range(1, int(issue_bounds[1])+1): - to_append = issue_week_strings_to_times(['%s/%s' % (i, year),])[0] + to_append = issue_week_strings_to_times(['%s/%s' % (i, year)])[0] new_year_issues.append(to_append) all_issue_weeks += old_year_issues all_issue_weeks += new_year_issues else: for i in range(int(issue_bounds[0]), int(issue_bounds[1])+1): - to_append = issue_week_strings_to_times(['%s/%s' % (i, year),])[0] + to_append = issue_week_strings_to_times(['%s/%s' % (i, year)])[0] all_issue_weeks.append(to_append) elif len(issue_bounds) == 1: to_append = issue_week_strings_to_times(['%s/%s' % - (issue_bounds[0], year),])[0] + (issue_bounds[0], year)])[0] all_issue_weeks.append(to_append) else: return False return all_issue_weeks def count_down_to_monday(current_time): """ Takes a timetuple and counts it down to the next monday and returns this time. """ next_monday = datetime.date(int(time.strftime("%Y", current_time)), int(time.strftime("%m", current_time)), int(time.strftime("%d", current_time))) counter = datetime.timedelta(days=-1) while next_monday.weekday() != 0: next_monday = next_monday + counter return next_monday.timetuple() def get_next_journal_issues(current_issue_time, journal_name, - language=CFG_SITE_LANG, number=2): + ln=CFG_SITE_LANG, number=2): """ Returns the next issue numbers from the current_issue_time. """ #now = '%s-%s-%s 00:00:00' % (int(time.strftime("%Y", current_issue_time)), # int(time.strftime("%m", current_issue_time)), # int(time.strftime("%d", current_issue_time))) # now = datetime.date(int(time.strftime("%Y", current_issue_time)), int(time.strftime("%m", current_issue_time)), int(time.strftime("%d", current_issue_time))) week_counter = datetime.timedelta(weeks=1) date = now next_issues = [] for i in range(1, number+1): date = date + week_counter #date = run_sql("SELECT %s + INTERVAL 1 WEEK", (date,))[0][0] #date_formated = time.strptime(date, "%Y-%m-%d %H:%M:%S") #raise '%s %s' % (repr(now), repr(date_formated)) next_issues.append(date.timetuple()) #next_issues.append(date_formated) return next_issues -def issue_times_to_week_strings(issue_times, language=CFG_SITE_LANG): +def issue_times_to_week_strings(issue_times, ln=CFG_SITE_LANG): """ Function that approaches a correct python time to MySQL time week string conversion by looking up and down the time horizon and always rechecking the python time with the mysql result until a week string match is found. """ issue_strings = [] for issue in issue_times: # do the initial pythonic week view week = time.strftime("%W/%Y", issue) week += " Monday" - Limit = 5 + limit = 5 counter = 0 success = False # try going up 5 - while success == False and counter <= Limit: + while success == False and counter <= limit: counter += 1 success = get_consistent_issue_week(issue, week) if success == False: week = count_week_string_up(week) else: break # try going down 5 counter = 0 - while success == False and counter <= Limit: + while success == False and counter <= limit: counter += 1 success = get_consistent_issue_week(issue, week) if success == False: week = count_week_string_down(week) else: break - from webjournal_config import InvenioWebJournalReleaseDBError + from invenio.webjournal_config import InvenioWebJournalReleaseDBError if success == False: - raise InvenioWebJournalReleaseDBError(language) + raise InvenioWebJournalReleaseDBError(ln) #check_for_time = run_sql("SELECT STR_TO_DATE(%s, %s)", # (week, conversion_rule))[0][0] #while (issue != check_for_time.timetuple()): # week = str(int(week.split("/")[0]) + 1) + "/" + week.split("/")[1] # if week[1] == "/": # week = "0" + week # #raise repr(week) # check_for_time = run_sql("SELECT STR_TO_DATE(%s, %s)", # (week, conversion_rule))[0][0] issue_strings.append(week.split(" ")[0]) return issue_strings def count_week_string_up(week): """ Function that takes a week string representation and counts it up by one. """ week_nr = week.split("/")[0] year = week.split("/")[1] if week_nr == "53": week_nr = "01" year = str(int(year) + 1) else: week_nr = str(int(week_nr) + 1) if len(week_nr) == 1: week_nr = "0" + week_nr return "%s/%s" % (week_nr, year) def count_week_string_down(week): """ Function that takes a week string representation and counts it down by one. """ week_nr = week.split("/")[0] year = week.split("/")[1] if week_nr == "01": week_nr = "53" year = str(int(year)-1) else: week_nr = str(int(week_nr)-1) if len(week_nr) == 1: week_nr = "0" + week_nr return "%s/%s" % (week_nr, year) def get_consistent_issue_week(issue_time, issue_week): """ This is the central consistency function between our Python and MySQL dates. We use mysql times because of a bug in Scientific Linux that does not allow us to reconvert a week number to a timetuple. The function takes a week string, e.g. "02/2008" and its according timetuple from our functions. Then it retrieves the mysql timetuple for this week and compares the two times. If they are equal our times are consistent, if not, we return False and some function should try to approach a consisten result (see example in issue_times_to_week_strings()). """ conversion_rule = '%v/%x %W' mysql_repr = run_sql("SELECT STR_TO_DATE(%s, %s)", (issue_week, conversion_rule))[0][0] if mysql_repr.timetuple() == issue_time: return issue_week else: return False -def issue_week_strings_to_times(issue_weeks, language=CFG_SITE_LANG): +def issue_week_strings_to_times(issue_weeks, ln=CFG_SITE_LANG): """ Converts a list of issue week strings (WW/YYYY) to python time objects. """ issue_times = [] for issue in issue_weeks: week_number = issue.split("/")[0] year = issue.split("/")[1] to_convert = '%s/%s Monday' % (year, week_number) conversion_rule = '%x/%v %W' result = run_sql("SELECT STR_TO_DATE(%s, %s)", (to_convert, conversion_rule))[0][0] issue_times.append(result.timetuple()) return issue_times -def release_journal_update(update_issue, journal_name, language=CFG_SITE_LANG): - """ - Releases an update to a journal. - """ - journal_id = get_journal_id(journal_name, language) - run_sql("UPDATE jrnISSUE set date_released=NOW() \ - WHERE issue_number=%s \ - AND id_jrnJOURNAL=%s", (update_issue, - journal_id)) - def sort_by_week_number(x, y): """ Sorts a list of week numbers. """ year_x = x.split("/")[1] year_y = y.split("/")[1] if cmp(year_x, year_y) != 0: return cmp(year_x, year_y) else: week_x = x.split("/")[0] week_y = y.split("/")[0] return cmp(week_x, week_y) -def release_journal_issue(publish_issues, journal_name, language=CFG_SITE_LANG): - """ - Releases a new issue. - """ - journal_id = get_journal_id(journal_name, language) - if len(publish_issues) > 1: - publish_issues.sort(sort_by_week_number) - low_bound = publish_issues[0] - high_bound = publish_issues[-1] - issue_display = '%s-%s/%s' % (low_bound.split("/")[0], - high_bound.split("/")[0], - high_bound.split("/")[1]) - # remember convention: if we are going over a new year, take the higher - else: - issue_display = publish_issues[0] - # produce the DB lines - for publish_issue in publish_issues: - run_sql("INSERT INTO jrnISSUE (id_jrnJOURNAL, issue_number, issue_display) \ - VALUES(%s, %s, %s)", (journal_id, - publish_issue, - issue_display)) - # set first issue to published - release_journal_update(publish_issues[0], journal_name, language) - -def delete_journal_issue(issue, journal_name, language=CFG_SITE_LANG): - """ - Deletes an issue from the DB. - """ - journal_id = get_journal_id(journal_name, language) - run_sql("DELETE FROM jrnISSUE WHERE issue_number=%s \ - AND id_jrnJOURNAL=%s",(issue, journal_id)) - -def was_alert_sent_for_issue(issue, journal_name, language): - """ - """ - journal_id = get_journal_id(journal_name, language) - date_announced = run_sql("SELECT date_announced FROM jrnISSUE \ - WHERE issue_number=%s \ - AND id_jrnJOURNAL=%s", (issue, journal_id))[0][0] - if date_announced == None: - return False - else: - return date_announced.timetuple() - -def update_DB_for_alert(issue, journal_name, language): - """ - """ - journal_id = get_journal_id(journal_name, language) - run_sql("UPDATE jrnISSUE set date_announced=NOW() \ - WHERE issue_number=%s \ - AND id_jrnJOURNAL=%s", (issue, - journal_id)) - -def get_number_of_articles_for_issue(issue, journal_name, language=CFG_SITE_LANG): +def get_number_of_articles_for_issue(issue, journal_name, ln=CFG_SITE_LANG): """ Function that returns a dictionary with all categories and number of articles in each category. """ - config_strings = get_xml_from_config(["rule",], journal_name) + config_strings = get_xml_from_config(["rule"], journal_name) rule_list = config_strings["rule"] all_articles = {} for rule in rule_list: category_name = rule.split(",")[0] if issue[0] == "0" and len(issue) == 7: week_nr = issue.split("/")[0] year = issue.split("/")[1] issue_nr_alternative = "%s/%s" % (week_nr[1], year) all_records_of_a_type = list(search_pattern(p='65017a:"%s" and 773__n:%s' % - (category_name, issue), - f="&action_search=Search")) + (category_name, issue))) all_records_of_a_type += list(search_pattern(p='65017a:"%s" and 773__n:%s' % - (category_name, issue_nr_alternative), - f="&action_search=Search")) + (category_name, issue_nr_alternative))) else: all_records_of_a_type = list(search_pattern(p='65017a:"%s" and 773__n:%s' % - (category_name, issue), - f="&action_search=Search")) + (category_name, issue))) all_articles[category_name] = len(all_records_of_a_type) return all_articles def get_list_of_issues_for_publication(publication): """ Takes a publication string, e.g. 23-24/2008 and splits it down to a list of single issues. """ year = publication.split("/")[1] issues_string = publication.split("/")[0] bounds = issues_string.split("-") issues = [] if len(bounds) == 2: low_bound = issues_string.split("-")[0] high_bound = issues_string.split("-")[1] if int(low_bound) < int(high_bound): for i in range(int(low_bound), int(high_bound)+1): issue_nr = str(i) if len(issue_nr) == 1: issue_nr = "0" + issue_nr issues.append("%s/%s" % (issue_nr, year)) else: for i in range(int(low_bound), 53+1): issue_nr = str(i) if len(issue_nr) == 1: issue_nr = "0" + issue_nr issues.append("%s/%s" % (issue_nr, str(int(year)-1))) for i in range(1, int(high_bound) + 1): issue_nr = str(i) if len(issue_nr) == 1: issue_nr = "0" + issue_nr issues.append("%s/%s" % (issue_nr, year)) else: issues.append("%s/%s" % (bounds[0], year)) return issues -def get_release_time(issue, journal_name, language=CFG_SITE_LANG): +def get_release_time(issue, journal_name, ln=CFG_SITE_LANG): """ Gets the date at which an issue was released from the DB. + Returns False if issue has not yet been released. """ - journal_id = get_journal_id(journal_name, language) + journal_id = get_journal_id(journal_name, ln) try: release_date = run_sql("SELECT date_released FROM jrnISSUE \ WHERE issue_number=%s AND id_jrnJOURNAL=%s", (issue, journal_id))[0][0] except: return False if release_date == None: return False else: return release_date.timetuple() -def get_announcement_time(issue, journal_name, language=CFG_SITE_LANG): +def get_announcement_time(issue, journal_name, ln=CFG_SITE_LANG): """ Get the date at which an issue was announced through the alert system. """ - journal_id = get_journal_id(journal_name, language) + journal_id = get_journal_id(journal_name, ln) try: announce_date = run_sql("SELECT date_announced FROM jrnISSUE \ WHERE issue_number=%s AND id_jrnJOURNAL=%s", (issue, journal_id))[0][0] except: return False if announce_date == None: return False else: return announce_date.timetuple() ######################## GET DEFAULTS FUNCTIONS ############################### -def get_journal_id(journal_name, language=CFG_SITE_LANG): +def get_journal_info_path(journal_name): + """ + Returns the path to the info file of the given journal. The info + file should be used to get information about a journal when database + is not available. + + Returns None if path cannot be determined + """ + # We must make sure we don't try to read outside of webjournal + # cache dir + info_path = os.path.realpath("%s/webjournal/%s/info.dat"% \ + (CFG_CACHEDIR, journal_name)) + if info_path.startswith(CFG_CACHEDIR + '/webjournal/'): + return info_path + else: + return None + +def get_journal_id(journal_name, ln=CFG_SITE_LANG): """ - Get the id for this journal from the DB. + Get the id for this journal from the DB. If DB is down, try to get + from cache. """ + journal_id = None from invenio.webjournal_config import InvenioWebJournalJournalIdNotFoundDBError - try: - journal_id = run_sql("SELECT id FROM jrnJOURNAL WHERE name=%s", - (journal_name,))[0][0] - except: - raise InvenioWebJournalJournalIdNotFoundDBError(language, journal_name) + + if CFG_ACCESS_CONTROL_LEVEL_SITE == 2: + # do not connect to the database as the site is closed for + # maintenance: + journal_info_path = get_journal_info_path(journal_name) + try: + journal_info_file = open(journal_info_path, 'r') + journal_info = cPickle.load(journal_info_file) + journal_id = journal_info.get('journal_id', None) + except cPickle.PickleError, e: + journal_id = None + except IOError: + journal_id = None + else: + try: + res = run_sql("SELECT id FROM jrnJOURNAL WHERE name=%s", + (journal_name,)) + if len(res) > 0: + journal_id = res[0][0] + except OperationalError, e: + # Cannot connect to database. Try to read from cache + journal_info_path = get_journal_info_path(journal_name) + try: + journal_info_file = open(journal_info_path, 'r') + journal_info = cPickle.load(journal_info_file) + journal_id = journal_info['journal_id'] + except cPickle.PickleError, e: + journal_id = None + except IOError: + journal_id = None + + if journal_id is None: + raise InvenioWebJournalJournalIdNotFoundDBError(ln, journal_name) + return journal_id -def guess_journal_name(language): +def guess_journal_name(ln): """ tries to take a guess what a user was looking for on the server if not providing a name for the journal. if there is only one journal on the server, returns the name of which, otherwise redirects to a list with possible journals. """ from invenio.webjournal_config import InvenioWebJournalNoJournalOnServerError from invenio.webjournal_config import InvenioWebJournalNoNameError - all_journals = run_sql("SELECT * FROM jrnJOURNAL ORDER BY id") - if len(all_journals) == 0: - raise InvenioWebJournalNoJournalOnServerError(language) - elif len(all_journals) == 1: - return all_journals[0][1] - else: - raise InvenioWebJournalNoNameError(language) -def get_current_issue(language, journal_name): + journals_id_and_names = get_journals_ids_and_names() + if len(journals_id_and_names) == 0: + raise InvenioWebJournalNoJournalOnServerError(ln) + elif len(journals_id_and_names) > 0 and \ + journals_id_and_names[0].has_key('journal_name'): + return journals_id_and_names[0]['journal_name'] + else: + raise InvenioWebJournalNoNameError(ln) + +## all_journals = run_sql("SELECT * FROM jrnJOURNAL ORDER BY id") +## if len(all_journals) == 0: +## # try to get from file, in case DB is down +## raise InvenioWebJournalNoJournalOnServerError(ln) +## elif len(all_journals) > 0: +## return all_journals[0][1] +## else: +## raise InvenioWebJournalNoNameError(ln) + +def get_journals_ids_and_names(): + """ + Returns the list of existing journals IDs and names. Try to read + from the DB, or from cache if DB is not accessible. + """ + journals = [] + + if CFG_ACCESS_CONTROL_LEVEL_SITE == 2: + # do not connect to the database as the site is closed for + # maintenance: + files = os.listdir("%s/webjournal" % CFG_CACHEDIR) + info_files = [path + os.sep + 'info.dat' for path in files if \ + os.path.isdir(path) and \ + os.path.exists(path + os.sep + 'info.dat')] + for info_file in info_files: + try: + journal_info_file = open(info_file, 'r') + journal_info = cPickle.load(journal_info_file) + journal_id = journal_info.get('journal_id', None) + journal_name = journal_info.get('journal_name', None) + current_issue = journal_info.get('current_issue', None) + if journal_id is not None and \ + journal_name is not None: + journals.append({'journal_id': journal_id, + 'journal_name': journal_name, + 'current_issue': current_issue}) + except cPickle.PickleError, e: + # Well, can't do anything... + continue + except IOError: + # Well, can't do anything... + continue + else: + try: + res = run_sql("SELECT id, name FROM jrnJOURNAL ORDER BY id") + for journal_id, journal_name in res: + journals.append({'id': journal_id, + 'name': journal_name}) + except OperationalError, e: + # Cannot connect to database. Try to read from cache + files = os.listdir("%s/webjournal" % CFG_CACHEDIR) + info_files = [path + os.sep + 'info.dat' for path in files if \ + os.path.isdir(path) and \ + os.path.exists(path + os.sep + 'info.dat')] + for info_file in info_files: + try: + journal_info_file = open(info_file, 'r') + journal_info = cPickle.load(journal_info_file) + journal_id = journal_info.get('journal_id', None) + journal_name = journal_info.get('journal_name', None) + current_issue = journal_info.get('current_issue', None) + if journal_id is not None and \ + journal_name is not None: + journals.append({'journal_id': journal_id, + 'journal_name': journal_name, + 'current_issue': current_issue}) + except cPickle.PickleError, e: + # Well, can't do anything... + continue + except IOError: + # Well, can't do anything... + continue + + return journals + +def get_current_issue(ln, journal_name): """ Returns the current issue of a journal as a string. """ - journal_id = get_journal_id(journal_name, language) + journal_id = get_journal_id(journal_name, ln) try: current_issue = run_sql("SELECT issue_number FROM jrnISSUE \ WHERE date_released <= NOW() AND id_jrnJOURNAL=%s \ ORDER BY date_released DESC LIMIT 1", (journal_id,))[0][0] except: # start the first journal ever with the day of today current_issue = time.strftime("%W/%Y", time.localtime()) run_sql("INSERT INTO jrnISSUE \ (id_jrnJOURNAL, issue_number, issue_display) \ VALUES(%s, %s, %s)", (journal_id, current_issue, current_issue)) return current_issue -def get_current_publication(journal_name, current_issue, language=CFG_SITE_LANG): +def get_current_publication(journal_name, current_issue, ln=CFG_SITE_LANG): """ Returns the current publication string (current issue + updates). """ - journal_id = get_journal_id(journal_name, language) + journal_id = get_journal_id(journal_name, ln) current_publication = run_sql("SELECT issue_display FROM jrnISSUE \ WHERE issue_number=%s AND \ id_jrnJOURNAL=%s", (current_issue, journal_id))[0][0] return current_publication def get_xml_from_config(xpath_list, journal_name): """ wrapper for minidom.getElementsByTagName() Takes a list of string expressions and a journal name and searches the config file of this journal for the given xpath queries. Returns a dictionary with a key for each query and a list of string (innerXml) results for each key. Has a special field "config_fetching_error" that returns an error when something has gone wrong. """ # get and open the config file results = {} config_path = '%s/webjournal/%s/config.xml' % (CFG_ETCDIR, journal_name) config_file = minidom.Document try: config_file = minidom.parse("%s" % config_path) except: #todo: raise exception "error: no config file found" results["config_fetching_error"] = "could not find config file" return results for xpath in xpath_list: result_list = config_file.getElementsByTagName(xpath) results[xpath] = [] for result in result_list: try: result_string = result.firstChild.toxml(encoding="utf-8") except: # WARNING, config did not have a value continue results[xpath].append(result_string) return results -def parse_url_string(req): +def parse_url_string(uri): """ - centralized function to parse any url string given in webjournal. + Centralized function to parse any url string given in + webjournal. Useful to retrieve current category, journal, + etc. from within format elements returns: args: all arguments in dict form """ - args = {} - # first get what you can from the argument string - try: - argument_string = req.args#"name=CERNBulletin&issue=22/2007"#req.args - except: - argument_string = "" - try: - arg_list = argument_string.split("&") - except: - # no arguments - arg_list = [] - for entry in arg_list: - try: - key = entry.split("=")[0] - except KeyError: - # todo: WARNING, could not parse one argument - continue - try: - val = entry.split("=")[1] - except: - # todo: WARNING, could not parse one argument - continue - try: - args[key] = val - except: - # todo: WARNING, argument given twice - continue - - # secondly try to get default arguments - try: - for entry in req.journal_defaults.keys(): - try: - args[entry] = req.journal_defaults[entry] - except: - # todo: Error, duplicate entry from args and defaults - pass - except: - # no defaults - pass + args = {'journal_name' : '', + 'issue_year' : '', + 'issue_number' : '', + 'issue' : '', + 'category' : '', + 'recid' : '', + 'verbose' : 0, + 'ln' : CFG_SITE_LANG, + 'archive_year' : ''} + + # Take everything after journal and before first question mark + splitted_uri = uri.split('journal', 1) + second_part = splitted_uri[1] + splitted_uri = second_part.split('?') + uri_middle_part = splitted_uri[0] + uri_arguments = '' + if len(splitted_uri) > 1: + uri_arguments = splitted_uri[1] + + arg_list = uri_arguments.split("&") + args['ln'] = 'en' + args['verbose'] = 0 + for arg_pair in arg_list: + arg_and_value = arg_pair.split('=') + if len(arg_and_value) == 2: + if arg_and_value[0] == 'ln': + args['ln'] = arg_and_value[1] + elif arg_and_value[0] == 'verbose' and \ + arg_and_value[1].isdigit(): + args['verbose'] = arg_and_value[1] + elif arg_and_value[0] == 'archive_year': + args['archive_year'] = arg_and_value[1] + + arg_list = uri_middle_part.split("/") + if len(arg_list) > 1 and arg_list[1] != 'search': + args['journal_name'] = urllib.unquote(arg_list[1]) + else: + args['journal_name'] = guess_journal_name(args['ln']) + if len(arg_list) > 2: + args['issue_year'] = urllib.unquote(arg_list[2]) + else: + issue = get_current_issue(args['ln'], + args['journal_name']) + args['issue'] = issue + args['issue_year'] = issue.split('/')[1] + args['issue_number'] = issue.split('/')[0] + if len(arg_list) > 3: + args['issue_number'] = urllib.unquote(arg_list[3]) + args['issue'] = args['issue_number'] + "/" + args['issue_year'] + if len(arg_list) > 4: + args['category'] = urllib.unquote(arg_list[4]) + if len(arg_list) > 5: + args['recid'] = urllib.unquote(arg_list[5]) + + # TODO : wash arguments return args -######################## EMAIL HELPER FUNCTIONS ############################### - -def createhtmlmail (html, text, subject, toaddr): - """ - Create a mime-message that will render HTML in popular - MUAs, text in better ones. - """ - import MimeWriter - import mimetools - import cStringIO - - out = cStringIO.StringIO() # output buffer for our message - htmlin = cStringIO.StringIO(html) - txtin = cStringIO.StringIO(text) +def make_journal_url(current_uri, custom_parameters={}): + """ + Create a url, using the current uri and overriding values + with the given custom_parameters + """ + default_params = parse_url_string(current_uri) + for key, value in custom_parameters.iteritems(): + # Override default params with custom params + default_params[key] = str(value) + + uri = CFG_SITE_URL + '/journal/' + if default_params['journal_name']: + uri += urllib.quote(default_params['journal_name']) + '/' + if default_params['issue_year']: + uri += urllib.quote(default_params['issue_year']) + '/' + if default_params['issue_number']: + uri += urllib.quote(default_params['issue_number']) + '/' + if default_params['category']: + uri += urllib.quote(default_params['category']) + if default_params['recid']: + uri += '/' + urllib.quote(str(default_params['recid'])) + + printed_question_mark = False + if default_params['ln']: + uri += '?ln=' + default_params['ln'] + printed_question_mark = True + + if default_params['verbose'] != 0: + if printed_question_mark: + uri += '&verbose=' + str(default_params['verbose']) + else: + uri += '?verbose=' + str(default_params['verbose']) - writer = MimeWriter.MimeWriter(out) - # - # set up some basic headers... we put subject here - # because smtplib.sendmail expects it to be in the - # message body - # - writer.addheader("Subject", subject) - writer.addheader("MIME-Version", "1.0") - - ## Instead of a comma-separated "To" field, add a new "To" header for - ## each of the addresses: - to_addresses = [raw_address.strip() for raw_address in toaddr.split(",")] - for to_address in to_addresses: - writer.addheader("To", to_address) - # - # start the multipart section of the message - # multipart/alternative seems to work better - # on some MUAs than multipart/mixed - # - writer.startmultipartbody("alternative") - writer.flushheaders() - # - # the plain text section - # - subpart = writer.nextpart() - subpart.addheader("Content-Transfer-Encoding", "quoted-printable") - #pout = subpart.startbody("text/plain", [("charset", 'us-ascii')]) - pout = subpart.startbody("text/plain", [("charset", 'utf-8')]) - mimetools.encode(txtin, pout, 'quoted-printable') - txtin.close() - # - # start the html subpart of the message - # - subpart = writer.nextpart() - subpart.addheader("Content-Transfer-Encoding", "quoted-printable") - txtin.close() - # - # start the html subpart of the message - # - subpart = writer.nextpart() - subpart.addheader("Content-Transfer-Encoding", "quoted-printable") - # - # returns us a file-ish object we can write to - # - #pout = subpart.startbody("text/html", [("charset", 'us-ascii')]) - pout = subpart.startbody("text/html", [("charset", 'utf-8')]) - mimetools.encode(htmlin, pout, 'quoted-printable') - htmlin.close() - # - # Now that we're done, close our writer and - # return the message body - # - writer.lastpart() - msg = out.getvalue() - out.close() - print msg - return msg + return uri -def put_css_in_file(html_message, journal_name): - """ - Takes an external css file and puts all the content of it in the head - of an HTML file in style tags. (Used for HTML emails) - """ - config_strings = get_xml_from_config(["screen"], journal_name) - try: - css_path = config_strings["screen"][0] - except: - register_exception(req=None, - suffix="No css file for journal %s. Is this right?" - % journal_name) - return - css_file = urlopen('%s/%s' % (CFG_SITE_URL, css_path)) - css = css_file.read() - css = make_full_paths_in_css(css, journal_name) - html_parted = html_message.split("") - if len(html_parted) > 1: - html = '%s%s' % (html_parted[0], - css, - html_parted[1]) - else: - html_parted = html_message.split("") - if len(html_parted) > 1: - html = '%s%s' % (html_parted[0], - css, - html_parted[1]) - else: - return - return html - -def make_full_paths_in_css(css, journal_name): - """ - """ - url_pattern = re.compile('''url\(["']?\s*(?P\S*)\s*["']?\)''', - re.DOTALL) - url_iter = url_pattern.finditer(css) - rel_to_full_path = {} - for url in url_iter: - url_string = url.group("url") - url_string = url_string.replace("\"", "") - url_string = url_string.replace("\'", "") - if url_string[:6] != "http://": - rel_to_full_path[url_string] = '"%s/img/%s/%s"' % (CFG_SITE_URL, - journal_name, - url_string) - for url in rel_to_full_path.keys(): - css = css.replace(url, rel_to_full_path[url]) - return css - -############################ CACHING FUNCTIONS ################################ +############################" CACHING FUNCTIONS ################################ def cache_index_page(html, journal_name, category, issue, ln): """ Caches the index page main area of a Bulletin (right hand menu cannot be cached) """ issue = issue.replace("/", "_") category = category.replace(" ", "") - if not (os.path.isdir('%s/webjournal/%s' % (CFG_CACHEDIR, journal_name) )): - os.makedirs('%s/webjournal/%s' % (CFG_CACHEDIR, journal_name)) - cached_file = open('%s/webjournal/%s/%s_index_%s_%s.html' % (CFG_CACHEDIR, - journal_name, - issue, category, - ln), "w") - cached_file.write(html) - cached_file.close() + cache_path = os.path.realpath('%s/webjournal/%s/%s_index_%s_%s.html' % \ + (CFG_CACHEDIR, journal_name, + issue, category, + ln)) + if not cache_path.startswith(CFG_CACHEDIR + '/webjournal'): + # Mmh, not accessing correct path. Stop caching + return False + cache_path_dir = '%s/webjournal/%s' % (CFG_CACHEDIR, journal_name) + if not os.path.isdir(cache_path_dir): + os.makedirs(cache_path_dir) + cached_file = open(cache_path, "w") + cached_file.write(html) + cached_file.close() def get_index_page_from_cache(journal_name, category, issue, ln): """ Function to get an index page from the cache. False if not in cache. """ issue = issue.replace("/", "_") category = category.replace(" ", "") + + cache_path = os.path.realpath('%s/webjournal/%s/%s_index_%s_%s.html' % \ + (CFG_CACHEDIR, journal_name, + issue, category, ln)) + if not cache_path.startswith(CFG_CACHEDIR + '/webjournal'): + # Mmh, not accessing correct path. Stop reading cache + return False + try: - cached_file = open('%s/webjournal/%s/%s_index_%s_%s.html' - % (CFG_CACHEDIR, journal_name, issue, category, ln)).read() + cached_file = open(cache_path).read() except: return False return cached_file def cache_article_page(html, journal_name, category, recid, issue, ln): """ Caches an article view of a journal. """ issue = issue.replace("/", "_") category = category.replace(" ", "") - if not (os.path.isdir('%s/webjournal/%s' % (CFG_CACHEDIR, journal_name) )): - os.makedirs('%s/webjournal/%s' % (CFG_CACHEDIR, journal_name)) - cached_file = open('%s/webjournal/%s/%s_article_%s_%s_%s.html' - % (CFG_CACHEDIR, journal_name, issue, category, recid, ln), - "w") + cache_path = os.path.realpath('%s/webjournal/%s/%s_article_%s_%s_%s.html' % \ + (CFG_CACHEDIR, journal_name, + issue, category, recid, ln)) + if not cache_path.startswith(CFG_CACHEDIR + '/webjournal'): + # Mmh, not accessing correct path. Stop caching + return + cache_path_dir = '%s/webjournal/%s' % (CFG_CACHEDIR, journal_name) + if not os.path.isdir(cache_path_dir): + os.makedirs(cache_path_dir) + cached_file = open(cache_path, "w") cached_file.write(html) cached_file.close() def get_article_page_from_cache(journal_name, category, recid, issue, ln): """ Gets an article view of a journal from cache. False if not in cache. """ issue = issue.replace("/", "_") category = category.replace(" ", "") + + cache_path = os.path.realpath('%s/webjournal/%s/%s_article_%s_%s_%s.html' % \ + (CFG_CACHEDIR, journal_name, + issue, category, recid, ln)) + if not cache_path.startswith(CFG_CACHEDIR + '/webjournal'): + # Mmh, not accessing correct path. Stop reading cache + return False try: - cached_file = open('%s/webjournal/%s/%s_article_%s_%s_%s.html' - % (CFG_CACHEDIR, journal_name, issue, category, recid, ln)).read() + cached_file = open(cache_path).read() except: return False return cached_file def clear_cache_for_article(journal_name, category, recid, issue): """ Resets the cache for an article (e.g. after an article has been modified) """ issue = issue.replace("/", "_") category = category.replace(" ", "") + + cache_path = os.path.realpath('%s/webjournal/%s/%s_article_%s_%s_%s.html' % \ + (CFG_CACHEDIR, journal_name)) + if not cache_path.startswith(CFG_CACHEDIR + '/webjournal'): + # Mmh, not accessing correct path. Stop deleting cache + return False + # try to delete the article cached file try: os.remove('%s/webjournal/%s/%s_article_%s_%s_en.html' % (CFG_CACHEDIR, journal_name, issue, category, recid)) except: pass try: os.remove('%s/webjournal/%s/%s_article_%s_%s_fr.html' % (CFG_CACHEDIR, journal_name, issue, category, recid)) except: pass # delete the index page for the category try: os.remove('%s/webjournal/%s/%s_index_%s_en.html' % (CFG_CACHEDIR, journal_name, issue, category)) except: pass try: os.remove('%s/webjournal/%s/%s_index_%s_fr.html' % (CFG_CACHEDIR, journal_name, issue, category)) except: pass # delete the entry in the recid_order_map # todo: make this per entry try: os.remove('%s/webjournal/%s/%s_recid_order_map.dat' % (CFG_CACHEDIR, journal_name, issue)) except: pass return True def clear_cache_for_issue(journal_name, issue): """ clears the cache of a whole issue. """ issue = issue.replace("/", "_") - all_cached_files = os.listdir('%s/webjournal/%s/' - % (CFG_CACHEDIR, journal_name)) + cache_path_dir = os.path.realpath('%s/webjournal/%s' % \ + (CFG_CACHEDIR, journal_name)) + if not cache_path_dir.startswith(CFG_CACHEDIR + '/webjournal'): + # Mmh, not accessing correct path. Stop deleting cache + return False + + all_cached_files = os.listdir(cache_path_dir) for cached_file in all_cached_files: if cached_file[:7] == issue: try: - os.remove('%s/webjournal/%s/%s' - % (CFG_CACHEDIR, journal_name, cached_file)) + os.remove(cache_path_dir + '/' + cached_file) except: return False return True -def cache_recid_data_dict_CERNBulletin(recid, issue, rule, order): - """ - The CERN Bulletin has a specific recid data dict that is cached - using cPickle. - """ - issue = issue.replace("/", "_") - # get whats in there - if not os.path.isdir('%s/webjournal/CERNBulletin' % CFG_CACHEDIR): - os.makedirs('%s/webjournal/CERNBulletin' % CFG_CACHEDIR) - try: - temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' - % (CFG_CACHEDIR, issue)) - except: - temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' - % (CFG_CACHEDIR, issue), "w") - try: - recid_map = cPickle.load(temp_file) - except: - recid_map = "" - temp_file.close() - # add new recid - if recid_map == "": - recid_map = {} - if not recid_map.has_key(rule): - recid_map[rule] = {} - recid_map[rule][order] = recid - # save back - temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' - % (CFG_CACHEDIR, issue), "w") - cPickle.dump(recid_map, temp_file) - temp_file.close() - -def get_cached_recid_data_dict_CERNBulletin(issue, rule): - """ - Function to restore from cache the dict Data Type that the CERN Bulletin - uses for mapping between the order of an article and its recid. - """ - issue = issue.replace("/", "_") - try: - temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' - % (CFG_CACHEDIR, issue)) - except: - return {} - try: - recid_map = cPickle.load(temp_file) - except: - return {} - try: - recid_dict = recid_map[rule] - except: - recid_dict = {} - return recid_dict +## def cache_recid_data_dict_CERNBulletin(recid, issue, rule, order): +## """ +## The CERN Bulletin has a specific recid data dict that is cached +## using cPickle. +## """ +## issue = issue.replace("/", "_") +## # get whats in there +## if not os.path.isdir('%s/webjournal/CERNBulletin' % CFG_CACHEDIR): +## os.makedirs('%s/webjournal/CERNBulletin' % CFG_CACHEDIR) +## try: +## temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' +## % (CFG_CACHEDIR, issue)) +## except: +## temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' +## % (CFG_CACHEDIR, issue), "w") +## try: +## recid_map = cPickle.load(temp_file) +## except: +## recid_map = "" +## temp_file.close() +## # add new recid +## if recid_map == "": +## recid_map = {} +## if not recid_map.has_key(rule): +## recid_map[rule] = {} +## recid_map[rule][order] = recid +## # save back +## temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' +## % (CFG_CACHEDIR, issue), "w") +## cPickle.dump(recid_map, temp_file) +## temp_file.close() + +## def get_cached_recid_data_dict_CERNBulletin(issue, rule): +## """ +## Function to restore from cache the dict Data Type that the CERN Bulletin +## uses for mapping between the order of an article and its recid. +## """ +## issue = issue.replace("/", "_") +## try: +## temp_file = open('%s/webjournal/CERNBulletin/%s_recid_order_map.dat' +## % (CFG_CACHEDIR, issue)) +## except: +## return {} +## try: +## recid_map = cPickle.load(temp_file) +## except: +## return {} +## try: +## recid_dict = recid_map[rule] +## except: +## recid_dict = {} +## return recid_dict + ######################### CERN SPECIFIC FUNCTIONS ############################# -def get_order_dict_from_recid_list_CERNBulletin(list, issue_number): - """ - special derivative of the get_order_dict_from_recid_list function that - extends the behavior insofar as too return a dictionary in which every - entry is a dict (there can be several number 1 articles) and every dict entry - is a tuple with an additional boolean to indicate if there is a graphical "new" - flag. the dict key on the second level is the upload time in epoch seconds. - e.g. - {1:{10349:(rec, true), 24792:(rec, false)}, 2:{736424:(rec,false)}, 24791:{1:(rec:false}} - the ordering inside an order number is given by upload date. so it is an ordering - 1-level -> number - 2-level -> date +def get_recid_from_legacy_number(issue_number, category, number): """ - ordered_records = {} - for record in list: - temp_rec = BibFormatObject(record) - issue_numbers = temp_rec.fields('773__n') - order_number = temp_rec.fields('773__c') - try: -# upload_date = run_sql("SELECT modification_date FROM bibrec WHERE id=%s", (record, ))[0][0] - upload_date = run_sql("SELECT creation_date FROM bibrec WHERE id=%s", (record, ))[0][0] - except: - pass - #return repr(time.mktime(upload_date.timetuple())) - # todo: the marc fields have to be set'able by some sort of config interface - n = 0 - for temp_issue in issue_numbers: - if temp_issue == issue_number: - try: - order_number = int(order_number[n]) - except: - # todo: Warning, record does not support numbering scheme - order_number = -1 - n+=1 - if order_number != -1: - try: - if ordered_records.has_key(order_number): - ordered_records[order_number][int(time.mktime(upload_date.timetuple()))] = (record, True) - else: - ordered_records[order_number] = {int(time.mktime(upload_date.timetuple())):(record, False)} - except: - pass - # todo: Error, there are two records with the same order_number in the issue - else: - ordered_records[max(ordered_records.keys()) + 1] = record + Returns the recid based on the issue number, category and + 'number'. - return ordered_records + This is used to support URLs using the now deprecated 'number' + argument. The function tries to reproduce the behaviour of the + old way of doing, even keeping some of its 'problems' (so that we + reach the same article as before with a given number).. -def get_recid_from_order_CERNBulletin(order, rule, issue_number): + Returns the recid as int, or -1 if not found """ - same functionality as get_recid_from_order above, but extends it for - the CERN Bulletin in a way so multiple entries for the first article are - possible. - - parameters: - order: the order at which the record appears in the journal as passed - in the url - rule: the defining rule of the journal record category - issue_number: the issue number for which we are searching - - returns: - recid: the recid of the ordered record - """ - # try to get it from cache - recid_dict = {} - recid_dict = get_cached_recid_data_dict_CERNBulletin(issue_number, rule) - if recid_dict.has_key(order): - recid = recid_dict[order] - return recid - alternative_issue_number = "00/0000" - # get the id list + recids = [] if issue_number[0] == "0": alternative_issue_number = issue_number[1:] - all_records = list(search_pattern(p="%s and 773__n:%s" % - (rule, issue_number), - f="&action_search=Search")) - all_records += list(search_pattern(p="%s and 773__n:%s" % - (rule, alternative_issue_number), - f="&action_search=Search")) + recids = list(search_pattern(p='65017a:"%s" and 773__n:%s' % + (category, issue_number))) + recids.extend(list(search_pattern(p='65017a:"%s" and 773__n:%s' % + (category, alternative_issue_number)))) else: - all_records = list(search_pattern(p="%s and 773__n:%s" % - (rule, issue_number), - f="&action_search=Search")) - #raise repr(all_records) - ordered_records = {} - new_addition_records = [] - for record in all_records: - temp_rec = BibFormatObject(record) # todo: refactor with get_fieldValues from search_engine - issue_numbers = temp_rec.fields('773__n') - order_number = temp_rec.fields('773__c') - #raise "%s:%s" % (repr(issue_numbers), repr(order_number)) - # todo: fields for issue number and order number have to become generic - n = 0 - for temp_issue in issue_numbers: - if temp_issue == issue_number or temp_issue == alternative_issue_number: - try: - order_number = int(order_number[n]) - except: - register_exception(stream="warning", suffix="There \ - was an article in the journal that does not support \ - a numbering scheme") - order_number = -1000 - n+=1 - if order_number == -1000: - ordered_records[max(ordered_records.keys()) + 1] = record - elif order_number <= 1: - new_addition_records.append(record) - else: - try: - ordered_records[order_number] = record - except: - register_exception(stream='warning', suffix="There \ - were double entries for an order in this journal.") - - # process the CERN Bulletin specific new additions - if len(new_addition_records) > 1 and int(order) <= 1: - # if we are dealing with a new addition (order number smaller 1) - ordered_new_additions = {} - for record in new_addition_records: - #upload_date = run_sql("SELECT modification_date FROM bibrec WHERE id=%s", (record, ))[0][0] - upload_date = run_sql("SELECT creation_date FROM bibrec WHERE id=%s", (record, ))[0][0] - ordered_new_additions[int(time.mktime(upload_date.timetuple()))] = record - i = 1 - while len(ordered_new_additions) > 0: - temp_key = pop_oldest_article_CERNBulletin(ordered_new_additions) - record = ordered_new_additions.pop(int(temp_key)) - ordered_records[i] = record - i -=1 + recids = list(search_pattern(p='65017:"%s" and 773__n:%s' % + (category, issue_number))) + + # Now must order the records and pick the one at index 'number'. + # But we have to take into account that there can be multiple + # records at position 1, and that these additional records should + # be numbered with negative numbers: + # 1, 1, 1, 2, 3 -> 1, -1, -2, 2, 3... + negative_index_records = {} + positive_index_records = {} + # Fill in 'negative_index_records' and 'positive_index_records' + # lists with the following loop + for recid in recids: + bfo = BibFormatObject(recid) + order = [subfield['c'] for subfield in bfo.fields('773__') if \ + issue_number in subfield['n']] + + if len(order) > 0: + # If several orders are defined for the same article and + # the same issue, keep the first one + order = order[0] + if order.isdigit(): + # Order must be an int. Otherwise skip + order = int(order) + if order == 1 and positive_index_records.has_key(1): + # This is then a negative number for this record + index = (len(negative_index_records.keys()) > 0 and \ + min(negative_index_records.keys()) -1) or 0 + negative_index_records[index] = recid + else: + # Positive number for this record + if not positive_index_records.has_key(order): + positive_index_records[order] = recid + else: + # We make the assumption that we cannot have + # twice the same position for two + # articles. Previous WebJournal module was not + # clear about that. Just drop this record + # (better than crashing or looping forever..) + pass + + recid_to_return = -1 + # Ok, we can finally pick the recid corresponding to 'number' + if number <= 0: + negative_indexes = negative_index_records.keys() + negative_indexes.sort() + negative_indexes.reverse() + if len(negative_indexes) > abs(number): + recid_to_return = negative_index_records[negative_indexes[abs(number)]] else: - # if we have only one record on 1 just push it through - ordered_records[1] = new_addition_records[0] - try: - recid = ordered_records[int(order)] - except: - register_exception() - - cache_recid_data_dict_CERNBulletin(recid, issue_number, rule, order) - return recid - -def pop_newest_article_CERNBulletin(news_article_dict): - """ - pop key of the most recent article (highest c-timestamp) - """ - keys = news_article_dict.keys() - keys.sort() - key = keys[len(keys)-1] - return key - -def pop_oldest_article_CERNBulletin(news_article_dict): - """ - pop key of the oldest article (lowest c-timestamp) - """ - keys = news_article_dict.keys() - keys.sort() - key = keys[0] - return key - -########################### REGULAR EXPRESSIONS ############################### - -header_pattern = re.compile('\s*(?P
    .*?)\s*

    ') -para_pattern = re.compile('(?P.+?)

    ', re.DOTALL) -image_pattern = re.compile(r''' - (\S*)["']?>)?# get the link location for the image - \s*# after each tag we can have arbitrary whitespaces -
    # the image is always centered - \s* - \S*)\s*border=1\s*(/)?># getting the image itself - \s* -
    - \s* - ()? - (
    |
    |
    )*# the caption can be separated by any nr of line breaks - ( - - \s* - - \s* -
    (?P.*?)
    # getting the caption - \s* -
    - \s* -
    - )?''', re.DOTALL | re.VERBOSE | re.IGNORECASE ) - #''',re.DOTALL | re.IGNORECASE | re.VERBOSE | re.MULTILINE) - -# (\S*)["']?>)?\s*
    \s*\S*)\s*border=1\s*(/)?> -# \s*
    \s*()?(
    |
    |
    )*(\s*\s*
    (?P.*?)
    \s*
    \s*
    )? -#url(["']?(?P\S*)["']?) + #positive_indexes = positive_index_records.keys() + #positive_indexes.sort() + #if len(positive_indexes) >= number: + # recid_to_return = positive_index_records[positive_indexes[number -1]] + if positive_index_records.has_key(number): + recid_to_return = positive_index_records[number] + + return recid_to_return diff --git a/modules/webjournal/lib/webjournal_washer.py b/modules/webjournal/lib/webjournal_washer.py index 664edd920..53aa75951 100644 --- a/modules/webjournal/lib/webjournal_washer.py +++ b/modules/webjournal/lib/webjournal_washer.py @@ -1,126 +1,118 @@ # -*- coding: utf-8 -*- ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. import time import re -from invenio.webjournal_config import InvenioWebJournalIssueNumberBadlyFormedError, \ - InvenioWebJournalNoArticleNumberError, \ - InvenioWebJournalArchiveDateWronglyFormedError, \ - IvenioWebJournalNoPopupTypeError, \ - InvenioWebJournalNoPopupRecordError -from invenio.webjournal_utils import get_current_issue, \ - guess_journal_name - +from invenio.webjournal_config import \ + InvenioWebJournalIssueNumberBadlyFormedError, \ + InvenioWebJournalNoArticleNumberError, \ + InvenioWebJournalArchiveDateWronglyFormedError, \ + InvenioWebJournalNoPopupRecordError +from invenio.webjournal_utils import \ + get_current_issue, \ + guess_journal_name from invenio.config import CFG_SITE_LANG # precompiled patterns for the parameters issue_number_pattern = re.compile("^\d{1,2}/\d{4}$") -def wash_journal_language(language): +def wash_journal_language(ln): """ Washes the language parameter. If there is a language, return this, otherwise return CFG_SITE_LANG constant """ - if language == "": + if ln == "": return CFG_SITE_LANG else: - return language + return ln -def wash_journal_name(language, journal_name): +def wash_journal_name(ln, journal_name): """ Washes the journal name parameter. In case of non-empty string, returns it, otherwise redirects to a guessing function. """ if journal_name == "": - return guess_journal_name(language) + return guess_journal_name(ln) else: return journal_name -def wash_issue_number(language, journal_name, issue_number): +def wash_issue_number(ln, journal_name, issue_number): """ Washes an issue number to fit the pattern ww/YYYY, e.g. 50/2007 w/YYYY is also accepted and transformed to 0w/YYYY, e.g. 2/2007 -> 02/2007 If no issue number is found, tries to get the current issue """ if issue_number == "": - return get_current_issue(language, journal_name) + return get_current_issue(ln, journal_name) else: issue_number_match = issue_number_pattern.match(issue_number) if issue_number_match: issue_number = issue_number_match.group() if len(issue_number.split("/")[0]) == 1: issue_number = "0%s" % issue_number return issue_number else: - raise InvenioWebJournalIssueNumberBadlyFormedError(language, + raise InvenioWebJournalIssueNumberBadlyFormedError(ln, issue_number) -def wash_category(language, category): +def wash_category(ln, category): """ Wahses a category name. No washing criterions so far. """ return category -def wash_article_number(language, number, journal_name): +def wash_article_number(ln, number, journal_name): """ Washes an article number. First checks if it is non-empty, then if it is convertable to int. If all passes, returns the number, else throws exception. """ if number == "": - raise InvenioWebJournalNoArticleNumberError(language, journal_name) + raise InvenioWebJournalNoArticleNumberError(ln, journal_name) try: int(number) except: - raise InvenioWebJournalNoArticleNumberError(language, journal_name) + raise InvenioWebJournalNoArticleNumberError(ln, journal_name) return number -def wash_popup_type(language, type, journal_name): - """ - """ - if type == "": - raise IvenioWebJournalNoPopupTypeError(language, journal_name) - else: - return type - -def wash_popup_record(language, record, journal_name): +def wash_popup_record(ln, record, journal_name): """ """ if record == "": - raise InvenioWebJournalNoPopupRecordError(language, journal_name, + raise InvenioWebJournalNoPopupRecordError(ln, journal_name, "no recid") try: int(record) except: - raise InvenioWebJournalNoPopupRecordError(language, journal_name, + raise InvenioWebJournalNoPopupRecordError(ln, journal_name, record) return record -def wash_archive_date(language, journal_name, archive_date): +def wash_archive_date(ln, journal_name, archive_date): """ Washes an archive date to the form dd/mm/yyyy or empty. """ if archive_date == "": return "" try: time.strptime(archive_date, "%d/%m/%Y") except: - raise InvenioWebJournalArchiveDateWronglyFormedError(language, + raise InvenioWebJournalArchiveDateWronglyFormedError(ln, archive_date) return archive_date diff --git a/modules/webjournal/lib/webjournal_webinterface.py b/modules/webjournal/lib/webjournal_webinterface.py index 20a7bdb50..be073852b 100644 --- a/modules/webjournal/lib/webjournal_webinterface.py +++ b/modules/webjournal/lib/webjournal_webinterface.py @@ -1,625 +1,457 @@ # -*- coding: utf-8 -*- ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. """WebJournal Web Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" -import time -import os import urllib -from urllib2 import urlopen -from email import message_from_string -from xml.dom import minidom -from mod_python import apache from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory - from invenio.access_control_engine import acc_authorize_action -from invenio.config import CFG_SITE_URL, CFG_WEBDIR, CFG_SITE_LANG, CFG_ETCDIR -from invenio.webpage import page +from invenio.config import CFG_SITE_URL, CFG_SITE_LANG from invenio.webuser import getUid from invenio.urlutils import redirect_to_url from invenio.errorlib import register_exception -from invenio.bibformat_engine import format_with_format_template, BibFormatObject -from invenio.search_engine import search_pattern - -from webjournal_config import * -from invenio.webjournal_utils import get_recid_from_order, \ - get_recid_from_order_CERNBulletin, \ - parse_url_string, \ - get_xml_from_config, \ - please_login, \ - get_current_issue, \ - get_rule_string_from_rule_list, \ - get_monday_of_the_week, \ - cache_index_page, \ - get_index_page_from_cache, \ - get_article_page_from_cache, \ - cache_article_page, \ - clear_cache_for_issue - -from invenio.webjournal_washer import wash_category, \ - wash_issue_number, \ - wash_journal_name, \ - wash_journal_language, \ - wash_article_number, \ - wash_popup_type, \ - wash_popup_record, \ - wash_archive_date -from invenio.webjournal import perform_request_index, \ - perform_request_article, \ - perform_request_alert, \ - perform_request_issue_control, \ - perform_request_popup, \ - perform_request_administrate, \ - perform_request_search -from invenio.webjournal_templates import tmpl_webjournal_regenerate_success, \ - tmpl_webjournal_regenerate_error, \ - tmpl_webjournal_feature_record_interface, \ - tmpl_webjournal_feature_record_success, \ - tmpl_webjournal_alert_plain_text_CERNBulletin, \ - tmpl_webjournal_alert_subject_CERNBulletin, \ - tmpl_webjournal_alert_success_msg, \ - tmpl_webjournal_alert_interface +from invenio.webjournal_config import \ + InvenioWebJournalNoJournalOnServerError, \ + InvenioWebJournalNoNameError, \ + InvenioWebJournalNoCurrentIssueError, \ + InvenioWebJournalIssueNumberBadlyFormedError, \ + InvenioWebJournalArchiveDateWronglyFormedError, \ + InvenioWebJournalJournalIdNotFoundDBError, \ + InvenioWebJournalNoArticleNumberError, \ + InvenioWebJournalNoPopupRecordError +from invenio.webjournal_utils import \ + get_xml_from_config, \ + get_current_issue, \ + guess_journal_name, \ + get_current_issue, \ + get_journal_id, \ + get_recid_from_legacy_number +from invenio.webjournal_washer import \ + wash_category, \ + wash_issue_number, \ + wash_journal_name, \ + wash_journal_language, \ + wash_article_number, \ + wash_popup_record, \ + wash_archive_date +from invenio.webjournal import \ + perform_request_index, \ + perform_request_article, \ + perform_request_popup, \ + perform_request_search + +import invenio.template +webjournal_templates = invenio.template.load('webjournal') class WebInterfaceJournalPages(WebInterfaceDirectory): """Defines the set of /journal pages.""" - _exports = ['', 'article', 'issue_control', 'edit_article', 'alert', 'search', - 'feature_record', 'popup', 'regenerate', 'administrate'] - # profiler - #def index(self, req, form): - # import hotshot - # pr = hotshot.Profile('/tmp/journal_profile') - # return pr.runcall(self.index_bla, req=req, form=form) + journal_name = None + journal_issue_year = None + journal_issue_number = None + category = None + article_id = None + + _exports = ['popup', 'search'] + + def _lookup(self, component, path): + """ This handler is invoked for the dynamic URLs """ + if component in ['article', 'issue_control', 'edit_article', 'alert', + 'feature_record', 'regenerate', 'administrate']: + return WebInterfaceJournalPagesLegacy(), [component] + + # TODO : wash and get default values + self.journal_name = None # Reinit + self.journal_issue_year = None # Reinit + self.journal_issue_number = None # Reinit + self.category = None # Reinit + self.article_id = None # Reinit + + self.journal_name = component + if len(path) > 0: + self.journal_issue_year = path[0] + if len(path) > 1: + self.journal_issue_number = path[1] + if len(path) > 2: + self.category = urllib.unquote(path[2]) + if len(path) > 3 and path[3].isdigit(): + self.article_id = path[3] + + return self, [] + + def __call__(self, req, form): + """ Maybe resolve the final / of a directory """ + ## Support for legacy journal/[empty]?(args*) urls. There are + ## these parameters only in that case + argd = wash_urlargd(form, {'name': (str, ""), + 'issue': (str, ""), + 'category': (str, ""), + 'ln': (str, CFG_SITE_LANG), + 'number': (int, None), + 'verbose': (int, 0)} + ) + + if 'name' in form.keys() or \ + 'issue' in form.keys() or \ + 'category' in form.keys() :#or \ + + ln = wash_journal_language(argd['ln']) + journal_name = wash_journal_name(ln, argd['name']) + issue = wash_issue_number(ln, journal_name, + argd['issue']) + issue_year = issue.split('/')[1] + issue_number = issue.split('/')[0] + category = wash_category(ln, argd['category']) + return redirect_to_url(req, CFG_SITE_URL + '/journal/%(name)s/%(issue_year)s/%(issue_number)s/%(category)s/?ln=%(ln)s' % \ + {'name': journal_name, + 'issue_year': issue_year, + 'issue_number': issue_number, + 'category': category, + 'ln': ln}) + ## End support for legacy urls + + # Check that given journal name exists. + if self.journal_name: + try: + get_journal_id(self.journal_name) + except InvenioWebJournalJournalIdNotFoundDBError, e: + register_exception(req=req) + return e.user_box() + + # If some parameters are missing, deduce them and + # redirect + if not self.journal_name or \ + not self.journal_issue_year or \ + not self.journal_issue_number or \ + not self.category: + if not self.journal_name: + self.journal_name = guess_journal_name(argd['ln']) + + if not self.journal_issue_year or not self.journal_issue_number: + journal_issue = get_current_issue(argd['ln'], self.journal_name) + self.journal_issue_year = journal_issue.split('/')[1] + self.journal_issue_number = journal_issue.split('/')[0] + + if not self.category: + config_strings = get_xml_from_config(["index", "rule", "issue_number"], + self.journal_name) + rule_list = config_strings["rule"] + self.category = rule_list[0].split(",")[0] + + return redirect_to_url(req, CFG_SITE_URL + '/journal/%(name)s/%(issue_year)s/%(issue_number)s/%(category)s/?ln=%(ln)s' % \ + {'name': self.journal_name, + 'issue_year': self.journal_issue_year, + 'issue_number': self.journal_issue_number, + 'category': self.category, + 'ln': argd['ln']}) + journal_issue = "" + if self.journal_issue_year is not None and \ + self.journal_issue_number is not None: + journal_issue = self.journal_issue_number + '/' + \ + self.journal_issue_year + + editor = False + if acc_authorize_action(getUid(req), 'cfgwebjournal', + name="%s" % self.journal_name)[0] == 0: + editor = True + + if self.article_id is None: + html = perform_request_index(req, + self.journal_name, + journal_issue, + argd['ln'], + self.category, + editor, + verbose=argd['verbose']) + else: + #req.journal_defaults["editor"] = editor + html = perform_request_article(req, + self.journal_name, + journal_issue, + argd['ln'], + self.category, + self.article_id, + editor, + verbose=argd['verbose']) + return html + + def popup(self, req, form): + """ + simple pass-through function that serves as a checker for popups. + """ + argd = wash_urlargd(form, {'name': (str, ""), + 'record': (str, ""), + 'ln': (str, "") + }) + try: + ln = wash_journal_language(argd['ln']) + journal_name = wash_journal_name(ln, argd['name']) + record = wash_popup_record(ln, argd['record'], journal_name) + except InvenioWebJournalNoJournalOnServerError, e: + register_exception(req=req) + return e.user_box() + except InvenioWebJournalNoNameError, e: + register_exception(req=req) + return e.user_box() + except InvenioWebJournalNoPopupRecordError, e: + register_exception(req=req) + return e.user_box() + + html = perform_request_popup(req, ln, journal_name, record) + + return html + + def search(self, req, form): + """ + Display search interface + """ + argd = wash_urlargd(form, {'name': (str, ""), + 'issue': (str, ""), + 'archive_year': (str, ""), + 'archive_issue': (str, ""), + 'archive_select': (str, "False"), + 'archive_date': (str, ""), + 'archive_search': (str, "False"), + 'ln': (str, CFG_SITE_LANG), + 'verbose': (int, 0)}) + try: + ln = wash_journal_language(argd['ln']) + journal_name = wash_journal_name(ln, argd['name']) + archive_issue = wash_issue_number(ln, journal_name, + argd['archive_issue']) + archive_date = wash_archive_date(ln, journal_name, + argd['archive_date']) + archive_select = argd['archive_select'] + archive_search = argd['archive_search'] + except InvenioWebJournalNoJournalOnServerError, e: + register_exception(req=req) + return e.user_box() + except InvenioWebJournalNoNameError, e: + register_exception(req=req) + return e.user_box() + except InvenioWebJournalNoCurrentIssueError, e: + register_exception(req=req) + return e.user_box() + except InvenioWebJournalIssueNumberBadlyFormedError, e: + register_exception(req=req) + return e.user_box() + except InvenioWebJournalArchiveDateWronglyFormedError, e: + register_exception(req=req) + return e.user_box() + + html = perform_request_search(req=req, + journal_name=journal_name, + ln=ln, + archive_issue=archive_issue, + archive_select=archive_select, + archive_date=archive_date, + archive_search=archive_search, + verbose=argd['verbose']) + return html + + + index = __call__ + + +class WebInterfaceJournalPagesLegacy(WebInterfaceDirectory): + """Defines the set of /journal pages.""" + + _exports = ['', 'article', 'issue_control', 'edit_article', 'alert', + 'feature_record', 'regenerate', 'administrate'] def index(self, req, form): """ Index page. Washes all the parameters and stores them in journal_defaults dict for subsequent format_elements. Passes on to logic function and eventually returns HTML. """ argd = wash_urlargd(form, {'name': (str, ""), 'issue': (str, ""), 'category': (str, ""), 'ln': (str, "")} ) try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - issue_number = wash_issue_number(language, journal_name, + ln = wash_journal_language(argd['ln']) + journal_name = wash_journal_name(ln, argd['name']) + issue_number = wash_issue_number(ln, journal_name, argd['issue']) - category = wash_category(language, argd['category']) + category = wash_category(ln, argd['category']) except InvenioWebJournalNoJournalOnServerError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalNoNameError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalNoCurrentIssueError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalIssueNumberBadlyFormedError, e: register_exception(req=req) return e.user_box() # the journal_defaults will be used by format elements that have no # direct access to the params here, no more checking needed req.journal_defaults = {"name": journal_name, "issue": issue_number, - "ln": language, + "ln": ln, "category": category} - html = perform_request_index(req, journal_name, issue_number, language, + html = perform_request_index(req, journal_name, issue_number, ln, category) return html def article(self, req, form): """ Article page. Washes all the parameters and stores them in journal_defaults dict for subsequent format_elements. Passes on to logic function and eventually returns HTML. """ argd = wash_urlargd(form, {'name': (str, ""), 'issue': (str, ""), 'category': (str, ""), 'number': (str, ""), 'ln': (str, ""), - 'editor': (str, "False")} + } ) try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - issue_number = wash_issue_number(language, journal_name, - argd['issue']) - category = wash_category(language, argd['category']) - number = wash_article_number(language, argd['number'], journal_name) - editor = argd['editor'] + ln = wash_journal_language(argd['ln']) + journal_name = wash_journal_name(ln, argd['name']) + issue = wash_issue_number(ln, journal_name, + argd['issue']) + issue_year = issue.split('/')[1] + issue_number = issue.split('/')[0] + category = wash_category(ln, argd['category']) + number = wash_article_number(ln, argd['number'], journal_name) + recid = get_recid_from_legacy_number(issue, category, int(number)) except InvenioWebJournalNoJournalOnServerError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalNoNameError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalNoCurrentIssueError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalIssueNumberBadlyFormedError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalNoArticleNumberError, e: register_exception(req=req) return e.user_box() - # automatically make all logged in users of cfgwebjournal editors - if acc_authorize_action(getUid(req), 'cfgwebjournal', - name="%s" % journal_name)[0] == 0: - editor = "True" - # the journal_defaults will be used by format elements that have no - # direct access to the params here, no more checking needed - req.journal_defaults = {"name" : journal_name, - "issue" : issue_number, - "ln" : language, - "category" : category, - "editor" : editor, - "number" : number} - - html = perform_request_article(req, journal_name, issue_number, - language, category, number, editor) - return html - - def edit_article(self, req, form): - """ - Simple url redirecter to toggle the edit mode on for article pages. - Checks if user is logged in. - """ - argd = wash_urlargd(form, {'name': (str, ""), - 'ln': (str, "")}) - try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - except InvenioWebJournalNoJournalOnServerError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoNameError, e: - register_exception(req=req) - return e.user_box() - if acc_authorize_action(getUid(req), 'cfgwebjournal', - name="%s" % journal_name)[0] != 0: - return please_login(req, journal_name, - backlink='%s/journal/edit_article?%s' - % (CFG_SITE_URL, urllib.quote(req.args))) - # todo: use make_canonical_url from urlutils - redirect_to_url(req, - "%s/journal/article?%s&editor=True" - % (CFG_SITE_URL, req.args)) + if recid != -1: + # Found a corresponding record + redirect_to_url(req, CFG_SITE_URL + \ + '/journal/' + journal_name + '/' + issue_year + \ + '/' + issue_number + '/' + category + \ + '/' + str(recid) + '?ln=' + ln) + else: + # Corresponding record not found. Display index + redirect_to_url(req, CFG_SITE_URL + \ + '/journal/' + journal_name + '/' + issue_year + \ + '/' + issue_number + '/' + category + \ + '?ln=' + ln) def administrate(self, req, form): """Index page.""" argd = wash_urlargd(form, {'name': (str, ""), 'ln': (str, "") }) try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) + ln = wash_journal_language(argd['ln']) + journal_name = wash_journal_name(ln, argd['name']) except InvenioWebJournalNoJournalOnServerError, e: register_exception(req=req) return e.user_box() except InvenioWebJournalNoNameError, e: register_exception(req=req) return e.user_box() - # check for user rights - if acc_authorize_action(getUid(req), 'cfgwebjournal', - name="%s" % journal_name)[0] != 0: - return please_login(req, journal_name, - backlink='%s/journal/administrate?name=%s' - % (CFG_SITE_URL, journal_name)) - - return perform_request_administrate(journal_name, language) + redirect_to_url(req, CFG_SITE_URL + \ + '/admin/webjournal/webjournaladmin.py/administrate?journal_name=' + \ + journal_name + '&ln=' + ln) def feature_record(self, req, form): """ Interface to feature a record. Will be saved in a flat file. """ argd = wash_urlargd(form, {'name': (str, ""), - 'recid': (str, "init"), - 'featured': (str, "false"), - 'url': (str, "init"), - 'ln': (str, "") - }) - try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - recid = argd['recid'] - url = argd['url'] - featured = argd['featured'] - except InvenioWebJournalNoJournalOnServerError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoNameError, e: - register_exception(req=req) - return e.user_box() - # check for user rights - if acc_authorize_action(getUid(req), 'cfgwebjournal', - name="%s" % journal_name)[0] != 0: - return please_login(req, journal_name, - backlink='%s/journal/feature_record?name=%s' - % (CFG_SITE_URL, journal_name)) - - if recid == "init": - return tmpl_webjournal_feature_record_interface(language, - journal_name) - else: - # todo: move to DB, maybe? - fptr = open('%s/webjournal/%s/featured_record' - % (CFG_ETCDIR, journal_name), "w") - fptr.write(recid) - fptr.write('\n') - fptr.write(argd['url']) - fptr.close() - return tmpl_webjournal_feature_record_success(language, - journal_name, recid) + 'recid': (str, "init"), + 'url': (str, "init"), + 'ln': (str, "")}) + + redirect_to_url(req, CFG_SITE_URL + \ + '/admin/webjournal/webjournaladmin.py/feature_record?journal_name=' + \ + argd['name'] + '&ln=' + argd['ln'] + '&recid='+ argd['recid'] + '&url='+ argd['url']) def regenerate(self, req, form): """ Clears the cache for the issue given. """ argd = wash_urlargd(form, {'name': (str, ""), - 'issue': (str, ""), - 'ln': (str, "")}) - try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - issue_number = wash_issue_number(language, journal_name, - argd['issue']) - except InvenioWebJournalNoJournalOnServerError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoNameError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoCurrentIssueError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalIssueNumberBadlyFormedError, e: - register_exception(req=req) - return e.user_box() - # check for user rights - if acc_authorize_action(getUid(req), 'cfgwebjournal', - name="%s" % journal_name)[0] != 0: - return please_login(req, journal_name, - backlink='%s/journal/regenerate?name=%s' - % (CFG_SITE_URL, journal_name)) - # clear cache - success = clear_cache_for_issue(journal_name, issue_number) - if success: - return tmpl_webjournal_regenerate_success(language, journal_name, - issue_number) - else: - return tmpl_webjournal_regenerate_error(language, journal_name, - issue_number) + 'issue': (str, ""), + 'ln': (str, "")}) + + redirect_to_url(req, CFG_SITE_URL + \ + '/admin/webjournal/webjournaladmin.py/regenerate?journal_name=' + \ + argd['name'] + '&ln=' + argd['ln'] + '&issue=' + argd['issue']) def alert(self, req, form): """ Alert system. Sends an email alert, in HTML/PlainText or only PlainText to a mailing list to alert for new journal releases. """ argd = wash_urlargd(form, {'name': (str, ""), - 'sent': (str, "False"), - 'plainText': (str, u''), - 'htmlMail': (str, ""), - 'recipients': (str, ""), - 'subject': (str, ""), - 'ln': (str, ""), - 'issue': (str, ""), - 'force': (str, "False")}) - try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - issue_number = wash_issue_number(language, journal_name, - argd['issue']) - plain_text = argd['plainText'] - html_mail = argd['htmlMail'] - recipients = argd['recipients'] - subject = argd['subject'] - sent = argd['sent'] - force = argd['force'] - except InvenioWebJournalNoJournalOnServerError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoNameError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoCurrentIssueError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalIssueNumberBadlyFormedError, e: - register_exception(req=req) - return e.user_box() - # login - if acc_authorize_action(getUid(req), 'cfgwebjournal', - name="%s" % journal_name)[0] != 0: - return please_login(req, journal_name, - backlink='%s/journal/alert?name=%s' - % (CFG_SITE_URL, journal_name)) - - html = perform_request_alert(req, journal_name, issue_number, language, - sent, plain_text, subject, recipients, - html_mail, force) - return html + 'sent': (str, "False"), + 'plainText': (str, u''), + 'htmlMail': (str, ""), + 'recipients': (str, ""), + 'subject': (str, ""), + 'ln': (str, ""), + 'issue': (str, ""), + 'force': (str, "False")}) + + redirect_to_url(req, CFG_SITE_URL + \ + '/admin/webjournal/webjournaladmin.py/alert?journal_name=' + \ + argd['name'] + '&ln=' + argd['ln'] + '&issue=' + argd['issue'] + \ + '&sent=' + argd['sent'] + '&plainText=' + argd['plainText'] + \ + '&htmlMail=' + argd['htmlMail'] + '&recipients=' + argd['recipients'] + \ + '&force=' + argd['force'] + '&subject=' + argd['subject']) def issue_control(self, req, form): """ page that allows full control over creating, backtracing, adding to, removing from issues. """ argd = wash_urlargd(form, {'name': (str, ""), - 'add': (str, ""), - 'action_publish': (str, "cfg"), - 'issue_number': (list, []), - 'ln': (str, "")} - ) - try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - issue_numbers = [] - for number in argd['issue_number']: - if number != "ww/YYYY": - issue_numbers.append(wash_issue_number(language, - journal_name, - number)) - add = argd['add'] - action = argd['action_publish'] - except InvenioWebJournalNoJournalOnServerError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoNameError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoCurrentIssueError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalIssueNumberBadlyFormedError, e: - register_exception(req=req) - return e.user_box() - # check user rights - if acc_authorize_action(getUid(req), 'cfgwebjournal', - name="%s" % journal_name)[0] != 0: - return please_login(req, journal_name) - - html = perform_request_issue_control(req, journal_name, issue_numbers, - language, add, action) - - return html - - def popup(self, req, form): - """ - simple pass-through function that serves as a checker for popups. - """ - argd = wash_urlargd(form, {'name': (str, ""), - 'record': (str, ""), - 'type': (str, ""), - 'ln': (str, "") - }) - try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - type = wash_popup_type(language, argd['type'], journal_name) - record = wash_popup_record(language, argd['record'], journal_name) - except InvenioWebJournalNoJournalOnServerError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoNameError, e: - register_exception(req=req) - return e.user_box() - except IvenioWebJournalNoPopupTypeError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoPopupRecordError, e: - register_exception(req=req) - return e.user_box() - - html = perform_request_popup(req, language, journal_name, type, record) - - return html - - - - def search(self, req, form): - """ - Creates a temporary record containing all the information needed for - the search, meaning list of issue_numbers (timeframe), list of keywords, - list of categories to search in. In this way everything can be configured - globally in the config for the given webjournal and we can reuse the bibformat - for whatever search we want. - """ - argd = wash_urlargd(form, {'name': (str, ""), - 'issue': (str, ""), - 'archive_year': (str, ""), - 'archive_issue': (str, ""), - 'archive_select': (str, "False"), - 'archive_date': (str, ""), - 'archive_search': (str, "False"), - 'ln': (str, CFG_SITE_LANG)}) - try: - language = wash_journal_language(argd['ln']) - journal_name = wash_journal_name(language, argd['name']) - archive_issue = wash_issue_number(language, journal_name, - argd['archive_issue']) - archive_date = wash_archive_date(language, journal_name, - argd['archive_date']) - issue_number = wash_issue_number(language, journal_name, - argd['issue']) - archive_year = argd['archive_year'] - archive_select = argd['archive_select'] - archive_search = argd['archive_search'] - except InvenioWebJournalNoJournalOnServerError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoNameError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalNoCurrentIssueError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalIssueNumberBadlyFormedError, e: - register_exception(req=req) - return e.user_box() - except InvenioWebJournalArchiveDateWronglyFormedError, e: - register_exception(req=req) - return e.user_box() - req.journal_defaults = {"name" : journal_name, - "issue" : issue_number, - "archive_year" : archive_year, - "archive_issue" : archive_issue, - "archive_select" : archive_select, - "archive_date" : archive_date, - "archive_search" : archive_search, - "language" : language, - } - - html = perform_request_search(journal_name, language, req, issue_number, - archive_year, archive_issue, - archive_select, archive_date, archive_search) - return html - - #if argd['name'] == "": - # register_exception(stream='warning', - # suffix="User tried to search without providing a journal name.") - # return webjournal_missing_info_box(req, title="Journal not found", - # msg_title="We don't know which journal you are looking for", - # msg='''You were looking for a journal without providing a name. - # Unfortunately we cannot know which journal you are looking for. - # Below you have a selection of journals that are available on this server. - # If you should find your journal there, just click the link, - # otherwise please contact the server admin and ask for existence - # of the journal you are looking for.''') - #else: - # journal_name = argd['name'] - - # config_strings = get_xml_from_config(["search", "issue_number", "rule"], journal_name) - # try: - # try: - # search_page_template = config_strings["search"][0] - # except: - # raise InvenioWebJournalNoArticleTemplateError(journal_name) # todo: new exception - # except InvenioWebJournalNoArticleTemplateError: - # register_exception(req=req) - # return webjournal_error_box(req, - # "Search Page Template not found", - # "Problem with the configuration for this journal.", - # "The system couldn't find the template for the search result page of this journal. This is a mandatory file and thus indicates that the journal was setup wrong or produced an internal error. If you are neither admin nor developer there is nothing you can do at this point, but send an email request. We apologize for the inconvenience.") - # search_page_template_path = 'webjournal/%s' % (search_page_template) - # try: - # try: - # issue_number_tag = config_strings["issue_number"][0] - # except KeyError: - # raise InvenioWebJournalNoIssueNumberTagError(journal_name) - # except InvenioWebJournalNoIssueNumberTagError: - # register_exception(req=req) - # return webjournal_error_box(req, - # title="No Issues", - # title_msg="Problem with the configuration of this journal", - # msg="The system couldn't find a definition for an issue numbering system. Issue numbers conrol the date of the publication you are seing. This indicates that there is an error in the setup of this journal or the Software itself. There is nothing you can do at the moment. If you wish you can send an inquiry to the responsible developers. We apologize for the inconvenience.") - # rule_list = config_strings["rule"] - # try: - # if len(rule_list) == 0: - # raise InvenioWebJournalNoArticleRuleError() - # except InvenioWebJournalNoArticleRuleError, e: - # register_exception(req=req) - # return webjournal_error_box(req, - # "No searchable Articles", - # "Problem with the configuration of this journal", - # "The system couldn't find the definitions for different article kinds (e.g. News, Sports, etc.). If there is nothing defined, nothing can be shown and it thus indicates that there is either a problem with the setup of this journal or in the Software itself. There is nothing you can do at this moment. If you wish you can send an inquiry to the responsible developers. We apologize for the inconvenience.") - # category_rules = [] - # if argd['category'] == []: - # # append all categories - # for rule_string in rule_list: - # marc = {} - # marc["category"] = rule_string.split(",")[0] - # rule = rule_string.split(",")[1] - # marc_datafield = rule.split(":")[0] - # marc["rule_match"] = rule.split(":")[1] - # marc["marc_tag"] = marc_datafield[1:4] - # marc["marc_ind1"] = (marc_datafield[4] == "_") and " " or marc_datafield[4] - # marc["marc_ind2"] = (marc_datafield[5] == "_") and " " or marc_datafield[5] - # marc["marc_subfield"] = marc_datafield[6] - # category_rules.append(marc) - # else: - # # append only categories from the url param - # for single_category in argd['category']: - # rule_string = get_rule_string_from_rule_list(rule_list, single_category) - # marc = {} - # marc["category"] = rule_string.split(",")[0] - # rule = rule_string.split(",")[1] - # marc_datafield = rule.split(":")[0] - # marc["rule_match"] = rule.split(":")[1] - # marc["marc_tag"] = marc_datafield[1:4] - # marc["marc_ind1"] = (marc_datafield[4] == "_") and " " or marc_datafield[4] - # marc["marc_ind2"] = (marc_datafield[5] == "_") and " " or marc_datafield[5] - # marc["marc_subfield"] = marc_datafield[6] - # category_rules.append(marc) - # - # category_fields = "\n".join([''' - # - # %s - # - # ''' % (marc["marc_tag"], - # marc["marc_ind1"], - # marc["marc_ind2"], - # marc["marc_subfield"], - # marc["rule_match"]) for marc in category_rules]) - # - # issue_number_fields = "\n".join([''' - # - # %s - # - # ''' % (issue_number_tag[:3], - # (issue_number_tag[3] == "_") and " " or issue_number_tag[3], - # (issue_number_tag[4] == "_") and " " or issue_number_tag[4], - # issue_number_tag[5], - # issue_number) for issue_number in argd['issue']]) - # - # temp_marc = ''' - # 0 - # %s - # %s - # ''' % (issue_number_fields, category_fields) - # - # - # # create a record and get HTML back from bibformat - # bfo = BibFormatObject(0, ln=argd['ln'], xml_record=temp_marc, req=req) # pass 0 for rn, we don't need it - # html_out = format_with_format_template(search_page_template_path, bfo)[0] - # - # #perform_request_search(cc="News Articles", p="families and 773__n:23/2007") - # #cc = argd['category'] - # #p = keyword - # #for issue_number in argd['issue_number']: - # # p += " and 773__n:%s" % issue_number - # ## todo: issue number tag generic from config - # #results = perform_request_search(cc=cc, p=p) - # - # return html_out - + 'add': (str, ""), + 'action_publish': (str, "cfg"), + 'issue_number': (list, []), + 'ln': (str, "")}) + redirect_to_url(req, CFG_SITE_URL + \ + '/admin/webjournal/webjournaladmin.py/issue_control?journal_name=' + \ + argd['name'] + '&ln=' + argd['ln'] + '&issue=' + argd['issue_number'] + \ + '&action=' + argd['action_publish']) diff --git a/modules/webjournal/lib/webjournaladminlib.py b/modules/webjournal/lib/webjournaladminlib.py new file mode 100644 index 000000000..98e8a062d --- /dev/null +++ b/modules/webjournal/lib/webjournaladminlib.py @@ -0,0 +1,852 @@ +## $Id$ +## +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. +## +## CDS 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. +## +## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +# pylint: disable-msg=C0301 +"""CDS Invenio WebJournal Administration Interface.""" + +__revision__ = "$Id$" + +import sets +import smtplib +import cPickle +import re +import os +import MimeWriter +import mimetools +import cStringIO +from urllib2 import urlopen +from invenio.errorlib import register_exception +from invenio.config import \ + CFG_SITE_URL, \ + CFG_SITE_LANG, \ + CFG_SITE_NAME, \ + CFG_ETCDIR +from invenio.messages import gettext_set_language +from invenio.webjournal_config import \ + InvenioWebJournalJournalIdNotFoundDBError, \ + InvenioWebJournalReleaseUpdateError, \ + InvenioWebJournalIssueNotFoundDBError +from invenio.webjournal_utils import \ + get_journals_ids_and_names, \ + guess_journal_name, \ + get_current_issue, \ + get_current_publication, \ + get_list_of_issues_for_publication, \ + count_week_string_up, \ + get_featured_records, \ + add_featured_record, \ + remove_featured_record, \ + clear_cache_for_issue, \ + get_current_issue_time, \ + get_all_issue_weeks, \ + get_next_journal_issues, \ + issue_times_to_week_strings, \ + issue_week_strings_to_times, \ + get_release_time, \ + get_journal_id, \ + sort_by_week_number, \ + get_xml_from_config, \ + get_journal_info_path + +from invenio.dbquery import run_sql + +import invenio.template +wjt = invenio.template.load('webjournal') + +def getnavtrail(previous = ''): + """Get the navtrail""" + + navtrail = """Admin Area """ % (CFG_SITE_URL,) + navtrail = navtrail + previous + return navtrail + +def perform_index(ln=CFG_SITE_LANG, journal_name=None, action=None): + """ + Index page + + Lists the journals, and offers options to edit them, delete them + or add new journal. + + Parameters: + journal_name - the journal affected by action, if any + action - one of ['', 'askDelete', _('Delete'), _('Cancel')] + ln - language + """ + _ = gettext_set_language(ln) + + msg = None + if action == 'askDelete' and journal_name is not None: + msg = '''
    + Delete Journal ConfigurationAre you sure you want to delete the configuration of %(journal_name)s? +
    + + + +
    ''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'journal_name': journal_name, + 'delete': _("Delete"), + 'cancel': _("Cancel")} + + if action == _("Delete") and journal_name is not None: + # User confirmed and clicked on "Delete" button + remove_journal(journal_name) + + journals = get_journals_ids_and_names() + return wjt.tmpl_admin_index(ln=ln, + journals=journals, + msg=msg) + +def perform_administrate(ln=CFG_SITE_LANG, journal_name=None): + """ + Administration of a journal + + Show the current and next issues/publications, and display links + to more specific administrative pages. + + Parameters: + journal_name - the journal to be administrated + ln - language + """ + if journal_name is None: + try: + journal_name = guess_journal_name(ln) + except InvenioWebJournalNoJournalOnServerError, e: + return e.user_box() + + if not can_read_xml_config(journal_name): + return 'Configuration could not be read. Please check that %s/webjournal/%s/config.xml exists and can be read by the server.
    ' % (CFG_ETCDIR, journal_name) + + current_issue = get_current_issue(ln, journal_name) + current_publication = get_current_publication(journal_name, + current_issue, + ln) + issue_list = get_list_of_issues_for_publication(current_publication) + next_issue_number = count_week_string_up(issue_list[-1]) + return wjt.tmpl_admin_administrate(journal_name, + current_issue, + current_publication, + issue_list, + next_issue_number, + ln) + +def perform_feature_record(journal_name, + recid, + img_url='', + action='', + ln=CFG_SITE_LANG): + """ + Interface to feature a record + + Used to list, add and remove featured records of the journal. + + Parameters: + journal_name - the journal for which the article is featured + recid - the record affected by 'action' + img_url - the URL to image displayed with given record + (only when action == 'add') + action - One of ['', 'add', 'askremove', _('Remove'), _('Cancel')] + ln - language + """ + _ = gettext_set_language(ln) + + if action == 'add': + result = add_featured_record(journal_name, recid, img_url) + if result == 0: + msg ='''Successfully featured + record %(recid)s. + Go to the %(name)s journal to + see the result.''' % {'CFG_SITE_URL': CFG_SITE_URL, + 'name': journal_name, + 'recid': recid} + elif result == 1: + msg = '''record %(recid)s is already featured. Choose another one or remove it first.''' % \ + {'CFG_SITE_URL': CFG_SITE_URL, + 'recid': recid} + else: + msg = '''Record could not be featured. Check file permission.''' + + featured_records = get_featured_records(journal_name) + return wjt.tmpl_admin_feature_record(ln=ln, + journal_name=journal_name, + featured_records=featured_records, + msg=msg) + elif action == 'askremove': + msg = '''
    + Remove featured recordAre you sure you want to remove record %(recid)s from the list of featured record? +
    + + + + +
    ''' % \ + {'CFG_SITE_URL': CFG_SITE_URL, + 'name': journal_name, + 'recid': recid, + 'cancel': _("Cancel"), + 'remove': _("Remove")} + featured_records = get_featured_records(journal_name) + return wjt.tmpl_admin_feature_record(ln=ln, + journal_name=journal_name, + featured_records=featured_records, + msg=msg) + elif action == _("Remove"): + result = remove_featured_record(journal_name, recid) + msg = '''Record %(recid)s + has been removed.''' % \ + {'CFG_SITE_URL': CFG_SITE_URL, + 'recid': recid} + featured_records = get_featured_records(journal_name) + return wjt.tmpl_admin_feature_record(ln=ln, + journal_name=journal_name, + featured_records=featured_records, + msg=msg) + else: + msg = '''Here you can choose which records from the %s should + be featured on the journal webpage.''' % CFG_SITE_NAME + featured_records = get_featured_records(journal_name) + return wjt.tmpl_admin_feature_record(ln=ln, + journal_name=journal_name, + featured_records=featured_records, + msg=msg) +def perform_regenerate_issue(issue, + journal_name, + ln=CFG_SITE_LANG): + """ + Clears the cache for the given issue. + + Parameters: + journal_name - the journal for which the cache should be + deleted + issue - the issue for which the cache should be deleted + ln - language + """ + success = clear_cache_for_issue(journal_name, + issue) + if success: + return wjt.tmpl_admin_regenerate_success(ln, + journal_name, + issue) + else: + return wjt.tmpl_admin_regenerate_error(ln, + journal_name, + issue) +def perform_request_issue_control(journal_name, issues, + action, ln=CFG_SITE_LANG): + """ + Central logic for issue control. + + Regenerates the flat files 'current_issue' and 'issue_group' of + the journal that control which issue is currently active for the + journal. + + Parameters: + journal_name - the journal affected by 'action' + issues - list of issues affected by 'action' TODO: check + action - One of ['cfg', _('Add'), _('Refresh'), + _('Publish'), _('Update')] + ln - language + """ + _ = gettext_set_language(ln) + + out = '' + if action == "cfg" or action == _("Refresh") or action == _("Add"): + # find out if we are in update or release + try: + current_issue_time = get_current_issue_time(journal_name) + all_issue_weeks = get_all_issue_weeks(current_issue_time, + journal_name, + ln) + except InvenioWebJournalIssueNotFoundDBError, e: + register_exception(req=None) + return e.user_box() + except InvenioWebJournalJournalIdNotFoundDBError, e: + register_exception(req=None) + return e.user_box() + if max(all_issue_weeks) > current_issue_time: + # propose an update + next_issue_week = None + all_issue_weeks.sort() + for issue_week in all_issue_weeks: + if issue_week > current_issue_time: + next_issue_week = issue_week + break + out = wjt.tmpl_admin_update_issue(ln, + journal_name, + issue_times_to_week_strings([next_issue_week,])[0], + issue_times_to_week_strings([current_issue_time,])[0]) + else: + # propose a release + next_issues = get_next_journal_issues(current_issue_time, + journal_name) + next_issues = issue_times_to_week_strings(next_issues, + ln) + if action == _("Refresh"): + next_issues += issues + next_issues = list(sets.Set(next_issues))# avoid double entries + elif action == _("Add"): + next_issues += issues + next_issues = list(sets.Set(next_issues))# avoid double entries + next_issues_times = issue_week_strings_to_times(next_issues, + ln) + highest_issue_so_far = max(next_issues_times) + one_more_issue = get_next_journal_issues(highest_issue_so_far, + journal_name, + ln, + 1) + one_more_issue = issue_times_to_week_strings(one_more_issue, + ln) + next_issues += one_more_issue + next_issues = list(sets.Set(next_issues)) # avoid double entries + next_issues.sort() + else: + # get the next (default 2) issue numbers to publish + next_issues = get_next_journal_issues(current_issue_time, + journal_name, + ln) + next_issues = issue_times_to_week_strings(next_issues, + ln) + out = wjt.tmpl_admin_control_issue(ln, + journal_name, + next_issues) + elif action == _("Publish"): + # Publish the given issues (mark them as current issues) + publish_issues = issues + publish_issues = list(sets.Set(publish_issues)) # avoid double entries + publish_issues.sort() + try: + release_journal_issue(publish_issues, journal_name, ln) + except InvenioWebJournalJournalIdNotFoundDBError, e: + register_exception(req=None) + return e.user_box() + out = wjt.tmpl_admin_control_issue_success_msg(ln, + publish_issues, + journal_name) + + elif action == _("Update"): + try: + try: + update_issue = issues[0] + except: + raise InvenioWebJournalReleaseUpdateError(ln, journal_name) + except InvenioWebJournalReleaseUpdateError, e: + register_exception(req=None) + return e.user_box() + try: + release_journal_update(update_issue, journal_name, ln) + except InvenioWebJournalJournalIdNotFoundDBError, e: + register_exception(req=None) + return e.user_box() + out = wjt.tmpl_admin_updated_issue_msg(ln, + update_issue, + journal_name) + + return out + +def perform_request_alert(journal_name, issue, + sent, plain_text, subject, recipients, + html_mail, force, ln=CFG_SITE_LANG): + """ + All the logic for alert emails. + + Display a form to edit email/recipients and options to send the + email. Sent in HTML/PlainText or only PlainText if wished so. + Also prevent mistake of sending the alert more than one for a + particular issue. + + Parameters: + journal_name - the journal for which the alert is sent + issue - the issue for which the alert is sent + sent - Display interface to edit email if "False" + (string). Else send the email. + plain_text - the text of the mail + subject - the subject of the mail + recipients - the recipients of the mail (string with + comma-separated emails) + html_mail - if 'html', also send email as HTML (copying + from the current issue on the web) + force - if different than "False", the email is sent + even if it has already been sent. + ln - language + """ + + if not get_release_time(issue, journal_name, ln): + # Trying to send an alert for an unreleased issue + return wjt.tmpl_admin_alert_unreleased_issue(ln, + journal_name) + if sent == "False": + # Retrieve default message, subject and recipients, and + # display email editor + subject = wjt.tmpl_admin_alert_subject(journal_name, + ln, + issue) + plain_text = wjt.tmpl_admin_alert_plain_text(journal_name, + ln, + issue) + plain_text = plain_text.encode('utf-8') + recipients = wjt.tmpl_admin_alert_recipients(journal_name, + ln, + issue) + return wjt.tmpl_admin_alert_interface(ln, + journal_name, + subject, + plain_text, + recipients) + else: + # User asked to send the mail + if was_alert_sent_for_issue(issue, + journal_name, + ln) != False and force == "False": + # Mmh, email already sent before for this issue. Ask + # confirmation + return wjt.tmpl_admin_alert_was_already_sent(ln, + journal_name, + subject, + plain_text, + recipients, + html_mail, + issue) + if html_mail == "html": + # Also send as HTML: retrieve from current issue + html_file = urlopen('%s/journal/%s?ln=en' + % (CFG_SITE_URL, journal_name)) + html_string = html_file.read() + html_file.close() + html_string = put_css_in_file(html_string, journal_name) + else: + # Send just as plain text + html_string = plain_text.replace("\n", "
    ") + + message = createhtmlmail(html_string, plain_text, + subject, recipients) + + ## Transform the recipients string into a list for the mail server: + to_addresses = [raw_address.strip() for raw_address in \ + recipients.split(",")] + recipients = to_addresses + + ## Send the mail: + server = smtplib.SMTP("localhost", 25) + server.sendmail('Bulletin-Support@cern.ch', recipients, message) + # todo: has to go to some messages config + update_DB_for_alert(issue, journal_name, ln) + return wjt.tmpl_admin_alert_success_msg(ln, + journal_name) + +def perform_request_configure(journal_name, xml_config, action, ln=CFG_SITE_LANG): + """ + Add a new journal or configure the settings of an existing journal. + + Parameters: + journal_name - the journal to configure, or name of the new journal + xml_config - the xml configuration of the journal (string) + action - One of ['edit', 'editDone', 'add', 'addDone'] + ln - language + """ + + msg = None + if action == 'edit': + # Read existing config + if journal_name is not None: + if not can_read_xml_config(journal_name): + return 'Configuration could not be read. Please check that %s/webjournal/%s/config.xml exists and can be read by the server.
    ' % (CFG_ETCDIR, journal_name) + config_path = '%s/webjournal/%s/config.xml' % (CFG_ETCDIR, journal_name) + xml_config = file(config_path).read() + else: + # cannot edit unknown journal... + return 'You must specify a journal name' + if action in ['editDone', 'addDone']: + # Save config + if action == 'addDone': + res = add_journal(journal_name, xml_config) + if res == -1: + msg = 'A journal with that name already exists. Please choose another name.' + action = 'add' + elif res == -2: + msg = 'Configuration could not be written (no permission). Please manually copy your config to %s/webjournal/%s/config.xml
    ' % (CFG_ETCDIR, journal_name) + action = 'edit' + elif res > 0: + msg = 'Journal successfully added.' + action = 'edit' + else: + msg = 'An error occurred. The journal could not be added' + action = 'edit' + if action == 'add': + # Display a sample config. TODO: makes it less CERN-specific + xml_config = ''' + + + CERN Bulletin + http://bulletin.cern.ch + + img/webjournal_CERNBulletin/webjournal_CERNBulletin_screen.css + img/webjournal_CERNBulletin/webjournal_CERNBulletin_print.css + + + img/Objects/Common + + + CERN_Bulletin_Index.bft + CERN_Bulletin_Detailed.bft + CERN_Bulletin_Search.bft + CERN_Bulletin_Popup.bft + + + + + + News Articles, 980__a:BULLETINNEWS + Official News, 980__a:BULLETINOFFICIAL + Training and Development, 980__a:BULLETINTRAINING + General Information, 980__a:BULLETINGENERAL + + + + + webjournal_weather + 14 + True + + 980__a + 773__n + + +''' + + out = wjt.tmpl_admin_configure_journal(ln=ln, + journal_name=journal_name, + xml_config=xml_config, + action=action, + msg=msg) + + return out + +######################## ADDING/REMOVING JOURNALS ############################### + +def add_journal(journal_name, xml_config): + """ + Add a new journal to the DB. Also create the configuration file + + Parameters: + journal_name - the name (used in URLs) of the new journal + xml_config - the xml configuration of the journal (string) + Returns: + the id of the journal if successfully added + -1 if could not be added because journal name already exists + -2 if config could not be saved + -3 if could not be added for other reasons + """ + try: + get_journal_id(journal_name) + except InvenioWebJournalJournalIdNotFoundDBError: + # Perfect, journal does not exist + res = run_sql("INSERT INTO jrnJOURNAL (name) VALUES(%s)", (journal_name,)) + # Also save xml_config + config_dir = '%s/webjournal/%s/' % (CFG_ETCDIR, journal_name) + try: + if not os.path.exists(config_dir): + os.makedirs(config_dir) + xml_config_file = file(config_dir + 'config.xml', 'w') + xml_config_file.write(xml_config) + xml_config_file.close() + except Exception: + res = -2 + # And save some info in file in case database is down + journal_info_path = get_journal_info_path(journal_name) + journal_info_file = open(journal_info_path, 'w') + cPickle.dump({'journal_id': res, + 'journal_name': journal_name, + 'current_issue':'01/2000'}, journal_info_file) + return res + return -1 + +def remove_journal(journal_name): + """ + Remove a journal from the DB. Keep everything else, since the + journal should still be accessible. + TODO: Think about removing config.xml file too if needed. + + Parameters: + journal_name - the journal to remove + + Returns: + the id of the journal if successfully removed or + -1 if could not be removed because journal name does not exist or + -2 if could not be removed for other reasons + """ + run_sql("DELETE FROM jrnJOURNAL WHERE name=%s", (journal_name,)) + +######################## TIME / ISSUE FUNCTIONS ############################### + + +def release_journal_issue(publish_issues, journal_name, ln=CFG_SITE_LANG): + """ + Releases a new issue. + + This sets the current issue in the database to 'publish_issues' for + given 'journal_name' + + Parameters: + journal_name - the journal for which we release a new issue + publish_issues - the list of issues that will be considered as + current (there can be several) + ln - language + """ + journal_id = get_journal_id(journal_name, ln) + if len(publish_issues) > 1: + publish_issues.sort(sort_by_week_number) + low_bound = publish_issues[0] + high_bound = publish_issues[-1] + issue_display = '%s-%s/%s' % (low_bound.split("/")[0], + high_bound.split("/")[0], + high_bound.split("/")[1]) + # remember convention: if we are going over a new year, take the higher + else: + issue_display = publish_issues[0] + # produce the DB lines + for publish_issue in publish_issues: + run_sql("INSERT INTO jrnISSUE (id_jrnJOURNAL, issue_number, issue_display) \ + VALUES(%s, %s, %s)", (journal_id, + publish_issue, + issue_display)) + # set first issue to published + release_journal_update(publish_issues[0], journal_name, ln) + + # update information in file (in case DB is down) + journal_info_path = get_journal_info_path(journal_name) + journal_info_file = open(journal_info_path, 'w') + cPickle.dump({'journal_id': journal_id, + 'journal_name': journal_name, + 'current_issue': get_current_issue(ln, journal_name)}, + journal_info_file) + +def delete_journal_issue(issue, journal_name, ln=CFG_SITE_LANG): + """ + Deletes an issue from the DB. + (Not currently used) + """ + journal_id = get_journal_id(journal_name, ln) + run_sql("DELETE FROM jrnISSUE WHERE issue_number=%s \ + AND id_jrnJOURNAL=%s",(issue, journal_id)) + + # update information in file (in case DB is down) + journal_info_path = get_journal_info_path(journal_name) + journal_info_file = open(journal_info_path, 'w') + cPickle.dump({'journal_id': journal_id, + 'journal_name': journal_name, + 'current_issue': get_current_issue(ln, journal_name)}, + journal_info_file) + +def was_alert_sent_for_issue(issue, journal_name, ln): + """ + Returns False if alert has not already been sent for given journal and + issue, else returns time of last alert, as time tuple + + Parameters: + journal_name - the journal for which we want to check last alert + issue - the issue for which we want to check last alert + ln - language + Returns: + time tuple or False. Eg: (2008, 4, 25, 7, 58, 37, 4, 116, -1) + """ + journal_id = get_journal_id(journal_name, ln) + date_announced = run_sql("SELECT date_announced FROM jrnISSUE \ + WHERE issue_number=%s \ + AND id_jrnJOURNAL=%s", (issue, journal_id))[0][0] + if date_announced == None: + return False + else: + return date_announced.timetuple() + +def update_DB_for_alert(issue, journal_name, ln): + """ + Update the 'last sent alert' timestamp for the given journal and + issue. + + Parameters: + journal_name - the journal for which we want to update the time + of last alert + issue - the issue for which we want to update the time + of last alert + ln - language + """ + journal_id = get_journal_id(journal_name, ln) + run_sql("UPDATE jrnISSUE set date_announced=NOW() \ + WHERE issue_number=%s \ + AND id_jrnJOURNAL=%s", (issue, + journal_id)) + +def release_journal_update(update_issue, journal_name, ln=CFG_SITE_LANG): + """ + Releases an update to a journal. + """ + journal_id = get_journal_id(journal_name, ln) + run_sql("UPDATE jrnISSUE set date_released=NOW() \ + WHERE issue_number=%s \ + AND id_jrnJOURNAL=%s", (update_issue, + journal_id)) + +######################## XML CONFIG ############################### + +def can_read_xml_config(journal_name): + """ + Check that configuration xml for given journal name is exists and + can be read. + """ + config_path = '%s/webjournal/%s/config.xml' % (CFG_ETCDIR, journal_name) + try: + file(config_path).read() + except IOError: + return False + + return True + +######################## EMAIL HELPER FUNCTIONS ############################### + +def createhtmlmail (html, text, subject, toaddr): + """ + Create a mime-message that will render HTML in popular + MUAs, text in better ones. + """ + out = cStringIO.StringIO() # output buffer for our message + htmlin = cStringIO.StringIO(html) + txtin = cStringIO.StringIO(text) + + writer = MimeWriter.MimeWriter(out) + # + # set up some basic headers... we put subject here + # because smtplib.sendmail expects it to be in the + # message body + # + writer.addheader("Subject", subject) + writer.addheader("MIME-Version", "1.0") + + ## Instead of a comma-separated "To" field, add a new "To" header for + ## each of the addresses: + to_addresses = [raw_address.strip() for raw_address in toaddr.split(",")] + for to_address in to_addresses: + writer.addheader("To", to_address) + # + # start the multipart section of the message + # multipart/alternative seems to work better + # on some MUAs than multipart/mixed + # + writer.startmultipartbody("alternative") + writer.flushheaders() + # + # the plain text section + # + subpart = writer.nextpart() + subpart.addheader("Content-Transfer-Encoding", "quoted-printable") + #pout = subpart.startbody("text/plain", [("charset", 'us-ascii')]) + pout = subpart.startbody("text/plain", [("charset", 'utf-8')]) + mimetools.encode(txtin, pout, 'quoted-printable') + txtin.close() + # + # start the html subpart of the message + # + subpart = writer.nextpart() + subpart.addheader("Content-Transfer-Encoding", "quoted-printable") + txtin.close() + # + # start the html subpart of the message + # + subpart = writer.nextpart() + subpart.addheader("Content-Transfer-Encoding", "quoted-printable") + # + # returns us a file-ish object we can write to + # + #pout = subpart.startbody("text/html", [("charset", 'us-ascii')]) + pout = subpart.startbody("text/html", [("charset", 'utf-8')]) + mimetools.encode(htmlin, pout, 'quoted-printable') + htmlin.close() + # + # Now that we're done, close our writer and + # return the message body + # + writer.lastpart() + msg = out.getvalue() + out.close() + print msg + return msg + +def put_css_in_file(html_message, journal_name): + """ + Retrieve the CSS of the journal and insert/inline it in the + section of the given html_message. (Used for HTML alert emails) + + Parameters: + journal_name - the journal name + html_message - the html message (string) in which the CSS + should be inserted + Returns: + the HTML message with its CSS inlined + """ + config_strings = get_xml_from_config(["screen"], journal_name) + try: + css_path = config_strings["screen"][0] + except Exception: + register_exception(req=None, + suffix="No css file for journal %s. Is this right?" + % journal_name) + return + css_file = urlopen('%s/%s' % (CFG_SITE_URL, css_path)) + css = css_file.read() + css = make_full_paths_in_css(css, journal_name) + html_parted = html_message.split("") + if len(html_parted) > 1: + html = '%s%s' % (html_parted[0], + css, + html_parted[1]) + else: + html_parted = html_message.split("") + if len(html_parted) > 1: + html = '%s%s' % (html_parted[0], + css, + html_parted[1]) + else: + return + return html + +def make_full_paths_in_css(css, journal_name): + """ + Update the URLs in a CSS from relative to absolute URLs, so that the + URLs are accessible from anywhere (Used for HTML alert emails) + + Parameters: + journal_name - the journal name + css - a cascading stylesheet (string) + Returns: + (str) the given css with relative paths converted to absolute paths + """ + url_pattern = re.compile('''url\(["']?\s*(?P\S*)\s*["']?\)''', + re.DOTALL) + url_iter = url_pattern.finditer(css) + rel_to_full_path = {} + for url in url_iter: + url_string = url.group("url") + url_string = url_string.replace("\"", "") + url_string = url_string.replace("\'", "") + if url_string[:6] != "http://": + rel_to_full_path[url_string] = '"%s/img/%s/%s"' % (CFG_SITE_URL, + journal_name, + url_string) + for url in rel_to_full_path.keys(): + css = css.replace(url, rel_to_full_path[url]) + return css + + diff --git a/modules/webjournal/lib/widgets/Makefile.am b/modules/webjournal/lib/widgets/Makefile.am index 504dd18e7..b0a71c3f6 100644 --- a/modules/webjournal/lib/widgets/Makefile.am +++ b/modules/webjournal/lib/widgets/Makefile.am @@ -1,25 +1,25 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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. +## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. pylibdir=$(libdir)/python/invenio/bibformat_elements pylib_DATA = bfe_webjournal_widget_weather.py bfe_webjournal_widget_seminars.py bfe_webjournal_widget_latestPhoto.py EXTRA_DIST = $(pylib_DATA) $(tmp_DATA) CLEANFILES = *~ *.tmp diff --git a/modules/webjournal/lib/widgets/bfe_webjournal_widget_latestPhoto.py b/modules/webjournal/lib/widgets/bfe_webjournal_widget_latestPhoto.py index 40e9a9c3c..17852c869 100644 --- a/modules/webjournal/lib/widgets/bfe_webjournal_widget_latestPhoto.py +++ b/modules/webjournal/lib/widgets/bfe_webjournal_widget_latestPhoto.py @@ -1,104 +1,106 @@ # -*- coding: utf-8 -*- ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. from invenio.bibformat_engine import BibFormatObject from invenio.search_engine import perform_request_search CDS_Photo_URL = "http://cdsweb.cern.ch/search?cc=Press+Office+Photo+Selection&as=1&rg=1&of=xm" Recursion_Upper_Limit = 10 def format(bfo): """ """ out = get_widget_HTML(bfo.lang, 1) return out def escape_values(bfo): """ + Called by BibFormat in order to check if output of this element + should be escaped. """ return 0 def get_widget_HTML(language, number): """ """ # limit the recursion if int(number) > int(Recursion_Upper_Limit): return "" latest_photo_id = perform_request_search(cc='Press Office Photo Selection', rg=number, as=1, of='id') # todo: change cc='Press+Office+Photo+Selection' try: latest_photo_record = BibFormatObject(latest_photo_id[number - 1]) except: # todo: Exception, no photo in this selection return "" recid = latest_photo_record.control_field("001") if language == "fr": try: title = latest_photo_record.fields('246_1a')[0] except KeyError: title = "" else: try: title = latest_photo_record.fields('245__a')[0] except KeyError: # todo: exception, picture with no title title = "" # first try to get the images from dfs, this should be the format they are in! icon_url = {} i = 1 dfs_images = latest_photo_record.fields('8567_') for image_block in dfs_images: try: if image_block["y"] == "Icon": if image_block["u"][:7] == "http://": if image_block["8"] != "": icon_url[int(image_block["8"])] = image_block["u"] else: try: icon_url[i] = image_block["u"] except: # icon could not be added pass except: # probably some key error, thats ok pass i+=1 # todo: does this return the first? try: icon_tuple = icon_url.popitem() icon_url = icon_tuple[1] except: # oh well, no dfs data... try to go for doc machine doc_machine_images = latest_photo_record.fields('8564_') # todo: implement parsing for external doc machine pages! html_out = "" if icon_url == "": html_out = get_widget_HTML("en", number+1) else: # assemble the HTML html_out = 'latest Photo%s' % ("http://test-multimedia-gallery.web.cern.ch/test-multimedia-gallery/PhotoGallery_Detailed.aspx?searchTerm=recid:" + recid + "&page=1&order=1", icon_url, title) # ## #Detail of the sensor from the first CMS half tracker inner barrel # return html_out if __name__ == "__main__": get_widget_HTML("en", 1) diff --git a/modules/webjournal/lib/widgets/bfe_webjournal_widget_seminars.py b/modules/webjournal/lib/widgets/bfe_webjournal_widget_seminars.py index df67bb5f3..745f26569 100644 --- a/modules/webjournal/lib/widgets/bfe_webjournal_widget_seminars.py +++ b/modules/webjournal/lib/widgets/bfe_webjournal_widget_seminars.py @@ -1,155 +1,156 @@ # -*- coding: utf-8 -*- ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. from invenio.config import CFG_CACHEDIR from urllib2 import urlopen from xml.dom import minidom import time Cached_Filename = "webjournal_widget_seminars.xml" -Indico_Seminar_Location = "http://indico.cern.ch/tools/export.py?fid=1l7&date=today&days=1&of=xml" +Indico_Seminar_Location = "http://indico.cern.ch/tools/export.py?fid=1l7&date=today&days=1&of=xml" Update_Frequency = 3600 # in seconds def format(bfo): """ """ out = get_widget_HTML(bfo) return out def escape_values(bfo): """ + Called by BibFormat in order to check if output of this element + should be escaped. """ return 0 def get_widget_HTML(bfo): """ Indico seminars of the day service Gets seminars of the day from CERN Indico every 60 minutes and displays them in a widget. """ try: seminar_xml = minidom.parse('%s/%s' % (CFG_CACHEDIR, Cached_Filename)) except: _update_seminars() seminar_xml = minidom.parse('%s/%s' % (CFG_CACHEDIR, Cached_Filename)) try: timestamp = seminar_xml.firstChild.getAttribute("time") except: timestamp = time.struct_time() last_update = time.mktime(time.strptime(timestamp, "%a, %d %b %Y %H:%M:%S %Z")) now = time.mktime(time.gmtime()) if last_update + Update_Frequency < now: _update_seminars() seminar_xml = minidom.parse('%s/%s' % (CFG_CACHEDIR, Cached_Filename)) html = "" seminars = seminar_xml.getElementsByTagName("seminar") if len(seminars) == 0: return "
  • no seminars today
  • " for seminar in seminars: html += "
  • " try: seminar_time = seminar.getElementsByTagName("start_time")[0].firstChild.toxml() except: seminar_time = "" try: category = seminar.getElementsByTagName("category")[0].firstChild.toxml() except: category = "Seminar" html += '%s %s
    ' % (seminar_time, category) try: title = seminar.getElementsByTagName("title")[0].firstChild.toxml() except: title = "" try: url = seminar.getElementsByTagName("url")[0].firstChild.toxml() except: url = "#" try: speaker = seminar.getElementsByTagName("speaker")[0].firstChild.toxml() except: speaker = "" if (title != ""): html += '%s, %s
    ' % (url, title, speaker) try: room = seminar.getElementsByTagName("room")[0].firstChild.toxml() except: room = "" html += room html += "
  • " - return html.encode('utf-8') def _update_seminars(): """ helper function that gets the xml data source from CERN Indico and creates a dedicated xml file in the cache for easy use in the widget. """ indico_xml = urlopen(Indico_Seminar_Location) xml_file_handler = minidom.parseString(indico_xml.read()) seminar_xml = ['' % time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()), ] agenda_items = xml_file_handler.getElementsByTagName("agenda_item") for item in agenda_items: seminar_xml.extend(["", ]) try: start_time = item.getElementsByTagName("start_time")[0].firstChild.toxml() except: start_time = "" seminar_xml.extend(["%s" % start_time, ]) try: category = item.getElementsByTagName("category")[0].firstChild.toxml() category = category.split("/")[-1] category = category.replace("&", "") category = category.replace("nbsp;", "") category = category.replace(" ", "") except: category = "" seminar_xml.extend(["%s" % category, ]) try: title = item.getElementsByTagName("title")[0].firstChild.toxml() except: title = "" seminar_xml.extend(["%s" % title, ]) try: url = item.getElementsByTagName("agenda_url")[0].firstChild.toxml() except: url = "#" seminar_xml.extend(["%s" % url, ]) try: speaker = item.getElementsByTagName("speaker")[0].firstChild.toxml() except: speaker = "" seminar_xml.extend(["%s" % speaker, ]) try: room = item.getElementsByTagName("room")[0].firstChild.toxml() except: room = "" seminar_xml.extend(["%s" % room, ]) seminar_xml.extend(["", ]) seminar_xml.extend(["", ]) # write the created file to cache fptr = open("%s/%s" % (CFG_CACHEDIR, Cached_Filename), "w") fptr.write(("\n".join(seminar_xml)).encode('utf-8')) fptr.close() if __name__ == "__main__": get_widget_HTML() diff --git a/modules/webjournal/lib/widgets/bfe_webjournal_widget_weather.py b/modules/webjournal/lib/widgets/bfe_webjournal_widget_weather.py index 07e231020..09026b8aa 100644 --- a/modules/webjournal/lib/widgets/bfe_webjournal_widget_weather.py +++ b/modules/webjournal/lib/widgets/bfe_webjournal_widget_weather.py @@ -1,132 +1,140 @@ # -*- coding: utf-8 -*- ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN. ## ## CDS 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. ## ## CDS 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 CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. """ """ from invenio import errorlib from invenio.config import CFG_CACHEDIR -import feedparser +try: + import feedparser + feedparser_available = 1 +except ImportError: + feedparser_available = 0 import time from urllib2 import urlopen from invenio.errorlib import register_exception import re Weather_Service = "Yahoo! Weather" # rss feed on yahoo weather, check developer.yahoo.com/weather for details RSS_Feed = "http://weather.yahooapis.com/forecastrss?p=SZXX0008&u=c" # filename of the rss feed in cache Cached_Filename = "webjournal_widget_YahooWeather.rss" # filename of flat file in cache that holds the expire time Expire_Time_Filename = "weather_RSS_expires" image_pattern = re.compile(''' \S*)\s*/>* - ''' - ,re.DOTALL | re.IGNORECASE | re.VERBOSE) + ''', re.DOTALL | re.IGNORECASE | re.VERBOSE) def format(bfo, title_en="", title_fr=""): """ wrapper function needed for BibFormat to route the widget HTML """ out = get_widget_HTML() if bfo.lang == "fr": title = title_fr else: title = title_en if title != "": try: weather_image_match = image_pattern.findall(out)[0] weather_image = weather_image_match[1] out = re.sub(image_pattern, "", out) except: register_exception(req=bfo.req) weather_image = "" weather_image = weather_image.replace("\"", "\'") out = '''

    %s

    -
      +

      %s -

    +

    ''' % (weather_image, title, out) return out def escape_values(bfo): """ + Called by BibFormat in order to check if output of this element + should be escaped. """ return 0 def get_widget_HTML(): """ weather forecast using Yahoo! Weather service we check and store the "expires" data from the rss feed to decide when an update is needed. there always resides a cached version in cds CFG_CACHEDIR along with a flat file that indicates the time when the feed expires. """ + if not feedparser_available: + return '' + try: weather_feed = feedparser.parse('%s/%s' % (CFG_CACHEDIR, Cached_Filename)) except: _update_feed() weather_feed = feedparser.parse('%s/%s' % (CFG_CACHEDIR, Cached_Filename)) now_in_gmt = time.gmtime() now_time_string = time.strftime( "%a, %d %b %Y %H:%M:%S GMT", now_in_gmt) try: expire_time_string = open('%s/%s' % (CFG_CACHEDIR, Expire_Time_Filename)).read() expire_time = time.strptime(open(Expire_Time_Filename).read(), "%a, %d %b %Y %H:%M:%S %Z") #expire_time['tm_isdt'] = 0 expire_in_seconds = time.mktime(expire_time) now_in_seconds = time.mktime(now_in_gmt) diff = time.mktime(expire_time) - time.mktime(now_in_gmt) except: diff = -1 if diff < 0: _update_feed() weather_feed = feedparser.parse('%s/%s' % (CFG_CACHEDIR, Cached_Filename)) # construct the HTML html = weather_feed.entries[0]['summary'] return html def _update_feed(): """ helper function that updates the feed by copying the new rss file to the cache dir and resetting the time string on the expireTime flat file """ feed = urlopen(RSS_Feed) cached_file = open('%s/%s' % (CFG_CACHEDIR, Cached_Filename), 'w') cached_file.write(feed.read()) cached_file.close() feed_data = feedparser.parse(RSS_Feed) expire_time = feed_data.headers['expires'] expire_file = open('%s/%s' % (CFG_CACHEDIR, Expire_Time_Filename), 'w') expire_file.write(expire_time) expire_file.close() if __name__ == "__main__": from invenio.bibformat_engine import BibFormatObject myrec = BibFormatObject(7) format(myrec)