diff --git a/Makefile.am b/Makefile.am index 044c34aed..00f8b3bff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,272 +1,275 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. confignicedir = $(sysconfdir)/build confignice_SCRIPTS=config.nice SUBDIRS = po config modules EXTRA_DIST = UNINSTALL CREDITS RELEASE-NOTES configure-tests.py config.nice.in ## submit stuff for demo data link creation sbmdir = $(localstatedir)/www/submit/access/protected sbmdat = SBITEXT MBITEXT FTTTEXT SRVTEXT TFUTEXT \ SBIRTEXT MBIRTEXT FTTRTEXT SRVRTEXT TFURTEXT APPRTEXT \ SBIPICT MBIPICT FTTPICT \ SBIRPICT MBIRPICT FTTRPICT APPRPICT all: @echo "**************************************************************" @echo "** CDS Invenio has been successfully built. Proceed now by **" @echo "** running 'make install'. **" @echo "**************************************************************" test: @if [ -e @prefix@/bin/testsuite ]; then \ @prefix@/bin/testsuite ; \ else \ echo "Hmm, testsuite does not seem to be installed. Please do 'make install' first."; \ fi regression-test: @if [ -e @prefix@/bin/regressiontestsuite ]; then \ @prefix@/bin/regressiontestsuite ; \ else \ echo "Hmm, regressiontestsuite does not seem to be installed. Please do 'make install' first."; \ fi kwalitee-check: $(PYTHON) $(top_srcdir)/modules/miscutil/lib/kwalitee.py $(top_srcdir) install-data-local: for d in / /cache /log /tmp /data /run ; do \ mkdir -p $(localstatedir)$$d && \ chmod ug=rwx $(localstatedir)$$d ; \ done @echo "************************************************************" @echo "** CDS Invenio has been successfully installed! **" @echo "** **" @echo "** If you are installing CDS Invenio for the first time, **" @echo "** please continue with the Apache httpd configuration **" @echo "** step, as described in the INSTALL file. **" @echo "** Afterwards you may want to run 'make create-demo-site' **" @echo "** to test your new installation. **" @echo "** **" @echo "** If you are reinstalling CDS Invenio because you have **" @echo "** edited CDS Invenio sources or its WML configuration, **" @echo "** you may want to restart your Apache server now by **" @echo "** running 'sudo apachectl restart'. **" @echo "************************************************************" create-tables: local-dbexec local-tabfill ./modules/miscutil/bin/dbexec < $(top_srcdir)/modules/miscutil/sql/tabcreate.sql ./modules/miscutil/bin/dbexec < ./modules/miscutil/sql/tabfill.sql update-v0.3.0-tables update-v0.3.1-tables: local-dbexec echo "ALTER TABLE idxINDEXNAME CHANGE id_idxINDEX id_idxINDEX mediumint(9) unsigned NOT NULL FIRST;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE rnkMETHODNAME CHANGE id_rnkMETHOD id_rnkMETHOD mediumint(9) unsigned NOT NULL FIRST;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE collectionname CHANGE id_collection id_collection mediumint(9) unsigned NOT NULL FIRST;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE formatname CHANGE id_format id_format mediumint(9) unsigned NOT NULL FIRST;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE fieldname CHANGE id_field id_field mediumint(9) unsigned NOT NULL FIRST;" | ./modules/miscutil/bin/dbexec echo "INSERT INTO accACTION (id,name,description,allowedkeywords,optional) VALUES (NULL,'runbibrank','run BibRank','','no');" | ./modules/miscutil/bin/dbexec echo "INSERT INTO accACTION (id,name,description,allowedkeywords,optional) VALUES (NULL,'cfgbibrank','configure BibRank','','no');" | ./modules/miscutil/bin/dbexec update-v0.3.2-tables: local-dbexec echo "ALTER TABLE sbmCOLLECTION_sbmDOCTYPE CHANGE id_son id_son char(10) NOT NULL default '0';" | ./modules/miscutil/bin/dbexec update-v0.3.3-tables: local-dbexec ./modules/miscutil/bin/dbexec < $(top_srcdir)/modules/miscutil/sql/tabcreate.sql echo "ALTER TABLE flxLINKTYPEPARAMS CHANGE pname pname varchar(78) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE rnkMETHOD DROP star_category_ranges;" | ./modules/miscutil/bin/dbexec echo "DROP TABLE rnkSET;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE schTASK CHANGE arguments arguments LONGTEXT;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE schTASK CHANGE status status varchar(50);" | ./modules/miscutil/bin/dbexec update-v0.5.0-tables: local-dbexec ./modules/miscutil/bin/dbexec < $(top_srcdir)/modules/miscutil/sql/tabcreate.sql echo "ALTER TABLE session ADD INDEX uid (uid);" | ./modules/miscutil/bin/dbexec echo "UPDATE idxINDEXNAME SET ln='cs' WHERE ln='cz';" | ./modules/miscutil/bin/dbexec echo "UPDATE rnkMETHODNAME SET ln='cs' WHERE ln='cz';" | ./modules/miscutil/bin/dbexec echo "UPDATE collectionname SET ln='cs' WHERE ln='cz';" | ./modules/miscutil/bin/dbexec echo "UPDATE collection_portalbox SET ln='cs' WHERE ln='cz';" | ./modules/miscutil/bin/dbexec echo "UPDATE formatname SET ln='cs' WHERE ln='cz';" | ./modules/miscutil/bin/dbexec echo "UPDATE fieldname SET ln='cs' WHERE ln='cz';" | ./modules/miscutil/bin/dbexec echo "UPDATE idxINDEXNAME SET ln='sv' WHERE ln='se';" | ./modules/miscutil/bin/dbexec echo "UPDATE rnkMETHODNAME SET ln='sv' WHERE ln='se';" | ./modules/miscutil/bin/dbexec echo "UPDATE collectionname SET ln='sv' WHERE ln='se';" | ./modules/miscutil/bin/dbexec echo "UPDATE collection_portalbox SET ln='sv' WHERE ln='se';" | ./modules/miscutil/bin/dbexec echo "UPDATE formatname SET ln='sv' WHERE ln='se';" | ./modules/miscutil/bin/dbexec echo "UPDATE fieldname SET ln='sv' WHERE ln='se';" | ./modules/miscutil/bin/dbexec update-v0.7.1-tables: local-dbexec echo "DROP TABLE oaiHARVEST;" | ./modules/miscutil/bin/dbexec ./modules/miscutil/bin/dbexec < $(top_srcdir)/modules/miscutil/sql/tabcreate.sql echo "INSERT INTO accACTION (id,name,description,allowedkeywords,optional) VALUES (NULL,'cfgbibharvest','configure BibHarvest','','no');" | ./modules/miscutil/bin/dbexec echo "INSERT INTO accACTION (id,name,description,allowedkeywords,optional) VALUES (NULL,'runoaiharvest','run BibHarvest oaiharvest','','no');" | ./modules/miscutil/bin/dbexec echo "INSERT INTO accACTION (id,name,description,allowedkeywords,optional) VALUES (NULL,'cfgwebcomment','configure WebComment','','no');" | ./modules/miscutil/bin/dbexec echo "INSERT INTO accACTION (id,name,description,allowedkeywords,optional) VALUES (NULL,'runoaiarchive','run BibHarvest oaiarchive','','no');" | ./modules/miscutil/bin/dbexec echo "INSERT INTO accACTION (id,name,description,allowedkeywords,optional) VALUES (NULL,'runbibedit','run BibEdit','','no');" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE user ADD nickname varchar(255) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE user ADD last_login datetime NOT NULL default '0000-00-00 00:00:00';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE user ADD INDEX nickname (nickname);" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE sbmFIELD CHANGE subname subname varchar(13) default NULL;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE user_query_basket CHANGE alert_name alert_name varchar(30) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "TRUNCATE TABLE session;" | ./modules/miscutil/bin/dbexec @echo "**********************************************************" @echo "** Do not forget to run the basket migration now: **" @echo "** @PYTHON@ modules/webbasket/lib/webbasket_migration_kit.py " @echo "** Please see the RELEASE-NOTES for details. **" @echo "**********************************************************" @echo "INSERT INTO oaiARCHIVE (id, setName, setSpec, setDescription, setDefinition, setRecList) SELECT id, setName, setSpec, CONCAT_WS('', setDescription), setDefinition, setRecList FROM oaiSET;" update-v0.90.0-tables: local-dbexec ./modules/miscutil/bin/dbexec < $(top_srcdir)/modules/miscutil/sql/tabcreate.sql echo "ALTER TABLE format ADD COLUMN (description varchar(255) default '');" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE format ADD COLUMN (content_type varchar(255) default '');" | ./modules/miscutil/bin/dbexec update-v0.90.1-tables: local-dbexec ./modules/miscutil/bin/dbexec < $(top_srcdir)/modules/miscutil/sql/tabcreate.sql echo "ALTER TABLE schTASK ADD INDEX status (status);" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE schTASK ADD INDEX runtime (runtime);" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE sbmCATEGORIES ADD COLUMN score TINYINT UNSIGNED NOT NULL DEFAULT 0;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE sbmCATEGORIES ADD PRIMARY KEY (doctype, sname);" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE sbmCATEGORIES ADD KEY doctype (doctype);" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiHARVEST ADD COLUMN setspecs TEXT NOT NULL DEFAULT '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE setDescription setDescription text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE p1 p1 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE f1 f1 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE m1 m1 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE p2 p2 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE f2 f2 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE m2 m2 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE p3 p3 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE f3 f3 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiARCHIVE CHANGE m3 m3 text NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "UPDATE bibdoc SET status=0 WHERE status='';" | ./modules/miscutil/bin/dbexec echo "UPDATE bibdoc SET status=1 WHERE status='deleted';" | ./modules/miscutil/bin/dbexec update-v0.92.0-tables: local-dbexec echo "UPDATE bibdoc SET status=0 WHERE status='';" | ./modules/miscutil/bin/dbexec echo "UPDATE bibdoc SET status=1 WHERE status='deleted';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE schTASK CHANGE arguments arguments mediumblob;" | ./modules/miscutil/bin/dbexec echo "UPDATE user SET note=1 WHERE nickname='admin' AND note IS NULL;" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE usergroup CHANGE name name varchar(255) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE usergroup ADD login_method varchar(255) NOT NULL default 'INTERNAL';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE usergroup ADD UNIQUE KEY login_method_name (login_method(70), name);" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE user CHANGE settings settings blob default NULL;" | ./modules/miscutil/bin/dbexec echo "INSERT INTO sbmALLFUNCDESCR VALUES ('Get_Recid', 'This function gets the recid for a document with a given report-number (as stored in the global variable rn).');" | ./modules/miscutil/bin/dbexec update-v0.92.1-tables: local-dbexec echo "UPDATE bibdoc SET status=0 WHERE status='';" | ./modules/miscutil/bin/dbexec echo "UPDATE bibdoc SET status=1 WHERE status='deleted';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiHARVEST CHANGE postprocess postprocess varchar(20) NOT NULL default 'h';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE oaiHARVEST ADD COLUMN bibfilterprogram varchar(255) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE idxINDEXNAME CHANGE ln ln char(5) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE rnkMETHODNAME CHANGE ln ln char(5) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE collectionname CHANGE ln ln char(5) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE collection_portalbox CHANGE ln ln char(5) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE formatname CHANGE ln ln char(5) NOT NULL default '';" | ./modules/miscutil/bin/dbexec echo "ALTER TABLE fieldname CHANGE ln ln char(5) NOT NULL default '';" | ./modules/miscutil/bin/dbexec - echo "ALTER TABLE bibrec ADD COLUMN rules tinyblob NULL;" | ./modules/miscutil/bin/dbexec - + echo "ALTER TABLE accROLE ADD COLUMN firerole_def_ser tinyblob NULL;" | ./modules/miscutil/bin/dbexec + echo "ALTER TABLE accROLE ADD COLUMN firerole_def_src tinytext NULL;" | ./modules/miscutil/bin/dbexec + echo "INSERT INTO accACTION VALUES (22,'accrestrcoll','view restricted collection','collection','no');" | ./modules/miscutil/bin/dbexec + drop-tables: local-dbexec ./modules/miscutil/bin/dbexec < $(srcdir)/modules/miscutil/sql/tabdrop.sql local-dbexec: (cd ./modules/miscutil/bin; make) local-tabfill: $(srcdir)/modules/miscutil/sql/tabfill.sql.wml (cd ./modules/miscutil/sql; make) create-demo-site: # for f in $(sbmdat); do \ # if [ ! -e $(sbmdir)/$$f.shtml ]; then \ # ln -s $(sbmdir)/go.shtml $(sbmdir)/$$f.shtml ; \ # else \ # echo "link $(sbmdir)/$$f.shtml already exists"; \ # fi \ # done ./modules/miscutil/bin/dbexec < ./modules/miscutil/demo/democfgdata.sql + ./modules/webaccess/bin/webaccessadmin -u admin compile-role-definitions echo "TRUNCATE schTASK;" | ${prefix}/bin/dbexec ${prefix}/bin/webcoll -uadmin ${prefix}/bin/webcoll 1 @echo "***********************************************************************" @echo "** The demo site has been successfully created. **" @echo "** **" @echo "** Please point your browser to @WEBURL@ " @echo "** It should ressemble our 'Atlantis Institute of Fictive Science' **" @echo "** demo site that is available at , **" @echo "** with the exception that no demo records have been loaded yet. **" @echo "** **" @echo "** To load demo records, you can run 'make load-demo-records'. **" @echo "** To drop the demo site, you can run 'make drop-demo-site'. **" @echo "***********************************************************************" load-demo-records: echo "TRUNCATE schTASK;" | ${prefix}/bin/dbexec ${prefix}/bin/bibupload -i $(srcdir)/modules/miscutil/demo/demobibdata.xml ${prefix}/bin/bibupload 1 ${prefix}/bin/bibindex -uadmin ${prefix}/bin/bibindex 2 ${prefix}/bin/bibreformat -uadmin -oHB ${prefix}/bin/bibreformat 3 ${prefix}/bin/bibupload 4 ${prefix}/bin/webcoll -uadmin ${prefix}/bin/webcoll 5 ${prefix}/bin/bibrank -uadmin ${prefix}/bin/bibrank 6 @echo "***********************************************************************" @echo "** The demo records have been successfully loaded. **" @echo "** **" @echo "** Please point your browser to @WEBURL@ " @echo "** It should ressemble our 'Atlantis Institute of Fictive Science' **" @echo "** demo site that is available at . **" @echo "** **" @echo "** To remove demo records, you can run 'make remove-demo-records'. **" @echo "** To drop also the demo site collection etc configurations, **" @echo "** you can run 'make drop-demo-site'. **" @echo "***********************************************************************" drop-demo-site: ./modules/miscutil/bin/dbexec < $(srcdir)/modules/miscutil/sql/tabdrop.sql ./modules/miscutil/bin/dbexec < $(srcdir)/modules/miscutil/sql/tabcreate.sql ./modules/miscutil/bin/dbexec < ./modules/miscutil/sql/tabfill.sql echo "TRUNCATE schTASK;" | ${prefix}/bin/dbexec ${prefix}/bin/webcoll -uadmin ${prefix}/bin/webcoll 1 # for f in $(sbmdat); do rm -f $(sbmdir)/$$f.shtml ; done @echo "***************************************************************" @echo "** The demo site and records have been successfully dropped. **" @echo "***************************************************************" remove-demo-records: ./modules/miscutil/bin/dbexec < $(srcdir)/modules/miscutil/sql/tabbibclean.sql echo "TRUNCATE schTASK;" | ${prefix}/bin/dbexec ${prefix}/bin/webcoll -uadmin ${prefix}/bin/webcoll 1 @echo "**********************************************************" @echo "** The demo records have been successfully removed. **" @echo "** The demo collection and submit configurations **" @echo "** have been preserved. **" @echo "** **" @echo "** Note that you can run 'make drop-demo-site' to drop **" @echo "** the demo site fully. **" @echo "**********************************************************" CLEANFILES = *~ diff --git a/config/config.wml b/config/config.wml index 45e197648..409593c05 100644 --- a/config/config.wml +++ b/config/config.wml @@ -1,810 +1,819 @@ ## -*- mode: html; coding: utf-8; -*- ## $Id$ ## This file enables you to configure the parameters of your local CDS ## installation. It should be self-explanatory. Just go ahead and ## change the values within "define-tag" elements according to your ## needs. When done, return to the main CDS Invenio source directory and ## type 'make'. ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. ## ##################### ## About "config.wml" ## ## ##################### -## This file ('config.wml') consists of several relatively independent +## This file ('config.wml') consists of several relatively independent ## configuration parts: ## ## Part 1: Essential parameters ## Part 2: CDS page elements ## Part 3: CDS navigation bar -## Part 5: WebSearch parameters +## Part 5: WebSearch parameters ## Part 4: BibHarvest OAI parameters ## Part 6: WebSubmit parameters ## Part 7: Fulltext Archive parameters ## Part 8: BibFormat parameters ## Part 9: BibIndex parameters ## Part 10: Access Control parameters ## -## The configuration is done by editing the content of the "define-tag" +## The configuration is done by editing the content of the "define-tag" ## WML elements below. Feel free to edit as many as you need. When done, ## return to the main CDS Invenio source directory and type 'make'. Good luck! :-) ## Before starting, let's include helper functions: #include "cdswmllib.wml" #include "configbis.wml" ################################### ## Part 1: Essential parameters ## ################################### ## This part defines essential CDS Invenio internal parameters that ## everybody should modify, like the name of the server or the email -## address of the local CDS Invenio administrator. +## address of the local CDS Invenio administrator. ## CDSNAME -- the visible name of your CDS Invenio installation: ## (example: "My Document Server") Atlantis Institute of Fictive Science ## CDSNAMEINTL -- the international versions of CDSNAME in various ## languages, defined using the standard locale-like language codes. ## (example: "Mon Serveur des Documents") Atlantis Institute of Fictive Science Atlantis Institut des Sciences Fictives Atlantis Institut der fiktiven Wissenschaft Atlantis Instituto de la Ciencia Fictive Institut Atlantis de Ciència Fictícia Instituto Atlantis de Ciência Fictícia Atlantis Istituto di Scienza Fittizia Атлантис Институт фиктивных Наук Atlantis Inštitút Fiktívnych Vied Atlantis Institut Fiktivních Věd Atlantis Institutt for Fiktiv Vitenskap Atlantis Institut för Fiktiv Vetenskap Ινστιτούτο Φανταστικών Επιστημών Ατλαντίδος Інститут вигаданих наук в Атлантісі Fictive 科学のAtlantis の協会 Instytut Fikcyjnej Nauki Atlantis Институт за фиктивни науки Атлантис Institut Fiktivnih Znanosti Atlantis 阿特兰提斯虚拟科学学院 阿特蘭提斯虛擬科學學院 ## CDSLANG -- the default language of the interface: ## (example: "en") en ## CDSLANGS -- list of all languages the user interface should be ## available in, separated by commas. The order specified below will ## be respected on the interface pages. A good default would be to ## use the alphabetical order. Currently supported languages include ## Bulgarian, Catalan, Czech, German, Greek, English, Spanish, French, ## Italian, Japanese, Norwegian, Polish, Portuguese, Russian, Slovak, Swedish, ## and Ukrainian, Chinese (China), Chinese (Taiwan), so that the current ## eventual maximum you can currently select is ## "bg,ca,cs,de,el,en,es,fr,hr,it,ja,no,pl,pt,ru,sk,sv,uk,zh_CN,zh_TW". ## (example: "de,en,fr,it") bg,ca,cs,de,el,en,es,fr,hr,it,ja,no,pl,pt,ru,sk,sv,uk,zh_CN,zh_TW ## ALERTENGINEEMAIL -- the email address from which the alert emails ## will appear to be send: ## (example: "cds.alert@cdsware.cern.ch") cds.alert@cdsdev.cern.ch ## SUPPORTEMAIL -- the email address of the support team for this ## installation: ## (example: "cds.support@cern.ch") cds.support@cern.ch ## ADMINEMAIL -- the email address of the 'superuser' for this ## installation. Enter your email address below and login with this ## address when using CDS Invenio administration modules. You will then ## be automatically recognized as superuser of the system. ## (example: "cds.support@cern.ch") cds.support@cern.ch ## CFG_MAX_RECID -- maximum record ID number possible, i.e. the upper ## estimate of the total number of documents in the database. A ## reasonable estimate is: if you have 500,000 records in the database ## now, and the size is growing by 10,000 records per month, then a ## value of 700,000 sounds reasonable, as it should suffice for two ## years. Note that if in 6 months you'll suddenly have to upload a ## lot of new input records, so that it may grow past the present ## CFG_MAX_RECID limit, nothing bad happens: you only have to change ## this parameter and reindex the full database content. Note also ## that the lower CFG_MAX_RECID, the faster the search engine and the ## indexation engines are, so you have interest not to put it ## unnecessarily high. The relation between the speed and the value ## of CFG_MAX_RECID is about linear, so that cutting CFG_MAX_RECID by ## half will speed up the indexation about twice. ## (example: "8000") 8000 +## CFG_MAX_CACHED_QUERIES -- maximum cached queries number possible +## after reaching this number of cached queries the cache is pruned +## deleting half of the older accessed cached queries. +## (example: "10000") + +10000 + + + ## CFG_APACHE_PASSWORD_FILE -- the file where Apache user credentials ## are stored. Must be an absolute pathname. If the value does not ## start by a slash, it is considered to be the filename of a file ## located under prefix/var/tmp directory. This is useful for the ## demo site testing purposes. For the production site, if you plan ## to restrict access to some collections based on the Apache user ## authentication mechanism, you should put here an absolute path to ## your Apache password file. ## (example: "/usr/local/apache/passwd/passwords") demo-site-apache-user-passwords ## CFG_APACHE_GROUP_FILE -- the file where Apache user groups are ## defined. See the documentation of the preceding config variable. ## (example: "/usr/local/apache/passwd/groups") demo-site-apache-user-groups ## CFG_CERN_SITE -- do we want to enable CERN-specific code, like the ## one that proposes links to famous HEP sites such as Spires and KEK? ## Put "1" for "yes" and "0" for "no". (example: "0") 0 ################################ ## Part 2: CDS page elements ## ################################ ## This part defines CDS portal-like page style and its elements. ## Here is a schematic overview of all the WML-configurable parts: ## ## +-----------------------------------------------------------------------------------------+ ## | CDSPAGEHEADER | ## | (cdspageheaderadd) | ## +-------------------------+------------------------------------+--------------------------+ ## | CDSPAGEBOXLEFTTOP | | CDSPAGEBOXRIGHTTOP | ## | (cdspageboxlefttopadd) | | (cdspageboxrighttopadd) | ## | | | | ## | | | | ## | | | | ## | | | | ## | | main page body | | ## | | | | ## | | | | ## | | | | ## | | | | ## | | | | ## | | | | ## |(cdspageboxleftbottomadd)| |(cdspageboxrightbottomadd)| ## | CDSPAGEBOXLEFTBOTTOM | | CDSPAGEBOXRIGHTBOTTOM | ## +-------------------------+------------------------------------+--------------------------+ ## | (cdspagefooteradd) | ## | CDSPAGEFOOTER | ## +-----------------------------------------------------------------------------------------+ ## ## Here, (i) the upper case elements like CDSPAGEHEADER are globally ## defined in this 'config.wml' file, see below. (ii) the lower case ## elements in parentheses like "(cdspageheaderadd)" are optional ## local add-ons that each WML page can define locally and pass to the ## global WML template as parameters. (iii) Note also that the style ## and colours of all these elements is defined in the cascading style ## sheet in the file 'htdocs/img/cds.css' that you can change at your ## will too. -## CFG_TEMPLATE_SKIN -- what template skin do you want to use? +## CFG_TEMPLATE_SKIN -- what template skin do you want to use? ## (example: "default") default ## CDSPAGEHEADER -- eventual global HTML page header: ## (example: "")
           
## CDSPAGEBOXLEFTTOP -- eventual global HTML left top box: ## (example: "") ## CDSPAGEBOXLEFTBOTTOM -- eventual global HTML left bottom box: ## (example: "") ## CDSPAGEBOXRIGHTTOP -- eventual global HTML right top box: ## (example: "") ## CDSPAGEBOXRIGHTBOTTOM -- eventual global HTML right bottom box: ## (example: "") ## CDSPAGEFOOTER -- eventual global HTML page footer: ## (example: "")
 ::  ::  ::  :: 
CDS Invenio v

################################ ## Part 3: CDS navigation bar ## ################################ ## The navigation bar and sub-bars are defined in a separate ## "cdsnavbar.wml" file. You may want to modify it now, if you ## really know what you are doing. :-) ################################## ## Part 4: WebSearch parameters ## ################################## ## This section contains some WML-based configuration parameters for ## WebSearch module. Please note that WebSearch is mostly configured ## on run-time via its WebSearch Admin web interface. The parameters ## below are the ones that you do not probably want to modify very ## often during the runtime. (Note that you may modify them ## afterwards too, though.) ## CFG_SEARCH_CACHE_SIZE -- how many queries we want to cache in ## memory per one Apache httpd process? This cache is used mainly for ## "next/previous page" functionality, but it caches also "popular" ## user queries if more than one user happen to search for the same ## thing. Note that large numbers may lead to great memory ## consumption. We recommend a value not greater than 100. ## (example: "100") 100 ## CFG_FIELDS_CONVERT -- if you migrate from an older system, you may ## want to map field codes of your old system (such as 'ti') to ## CDS Invenio/MySQL ("title"). Use Python dictionary syntax for the ## translation table, see the example below. Usually you don't want ## to do that, and would use empty dict {}. ## (example: "{'wau':'author', 'wti':'title'}") {} ## CFG_SIMPLESEARCH_PATTERN_BOX_WIDTH -- width of the search pattern ## window in the simple search interface, in characters. ## (example: "50") 40 ## CFG_ADVANCEDSEARCH_PATTERN_BOX_WIDTH -- width of the search pattern ## window in the advanced search interface, in characters. ## (example: "50") 30 ## CFG_NB_RECORDS_TO_SORT -- how many records do we still want to ## sort? For higher numbers we print only a warning and won't perform ## any sorting other than default 'latest records first', as sorting ## would be very time consuming then. We recommend a value of not ## more than a couple of thousands. ## (example: "1000") 1000 ## CFG_CALL_BIBFORMAT -- if a record is being displayed but it was not ## preformatted in the "HTML brief" format, do we want to call ## BibFormatting on the fly? Put "1" for "yes" and "0" for "no". ## Note that "1" will display the record exactly as if it were fully ## preformatted, but it may be slow due to on-the-fly processing; "0" ## will display a default format very fast, but it may not have all ## the fields as in the fully preformatted HTML brief format. When ## usure, set "0" here. ## (example: "0") 0 ## CFG_USE_OLD_SYSNOS -- do we want to make old SYSNOs visible rather ## than MySQL's record IDs? You may use this if you migrate from a ## different e-doc system, and you store your old system numbers into ## 970__a. Put "1" for "yes" and "0" for "no". Usually you don't want ## to do that, though. ## (example: "0") 0 ## CFG_NB_LATEST_ADDITIONS -- the number of records to display under ## 'Latest Additions' in the web collection pages ## (example: "10") 10 ## CFG_AUTHOR_ET_AL_THRESHOLD -- up to how many author names to print ## explicitely; for more print "et al". Note that this is used in ## default formatting that is seldomly used, as usually BibFormat ## defines all the format. The value below is only used when ## BibFormat fails, for example. ## (example: "3") 3 ## CFG_NARROW_SEARCH_SHOW_GRANDSONS -- whether to show or not ## collection grandsons in Narrow Search boxes (sons are shown ## by default, grandsons are configurable here). Use 0 for no ## and 1 for yes. ## (example: "0") 1 ## CFG_CREATE_SIMILARLY_NAMED_AUTHORS_LINK_BOX -- shall we create help ## links for Ellis, Nick or Ellis, Nicholas and friends when Ellis, N ## was searched for? Useful if you have one author stored in the ## database under several name formats, namely surname comma firstname ## and surname comma initial cataloging policy. Use 0 for no and 1 ## for yes. ## (example: "1") 1 ####################################### ## Part 5: BibHarvest OAI parameters ## ####################################### ## This part defines parameters for the CDS Invenio OAI gateway. ## Useful if you are running CDS Invenio as OAI data provider. -## CFG_OAI_ID_SCHEME -- OAI identifier scheme: +## CFG_OAI_ID_SCHEME -- OAI identifier scheme: ## (example: "oai") oai -## CFG_OAI_ID_TAG -- OAI identifier tag: +## CFG_OAI_ID_TAG -- OAI identifier tag: ## (example: "0248_a") 909COo -## CFG_OAI_SET_TAG -- OAI set tag: +## CFG_OAI_SET_TAG -- OAI set tag: ## (example: "0248_p") 909COp ## CFG_OAI_DELETED_TAG -- OAI tag for deleted records mark. OAI record -## is considered deleted if the value of this field is set to +## is considered deleted if the value of this field is set to ## "DELETED" and the OAI deleted records policy is set either to ## "transient" or "persistent". ## (example: "980__c") 980__c ## CFG_OAI_DELETED_POLICY -- OAI deletedrecordspolicy ## (example: no/transient/persistent) no -## CFG_OAI_ID_PREFIX -- OAI identifier prefix: +## CFG_OAI_ID_PREFIX -- OAI identifier prefix: ## (example: "cds.cern.ch") atlantis.cern.ch -## CFG_OAI_SAMPLE_IDENTIFIER -- OAI sample identifier: +## CFG_OAI_SAMPLE_IDENTIFIER -- OAI sample identifier: ## (example: "oai:cds.cern.ch:CERN-TH-4036") ::CERN-TH-4036 ## CFG_OAI_IDENTIFY_DESCRIPTION -- description for the OAI Identify verb (optional): ## (example:"") : http:/// Free and unlimited use by anybody with obligation to refer to original record Full content, i.e. preprints may not be harvested by robots Submission restricted. Submitted documents are subject of approval by OAI repository admins. ## CFG_OAI_LOAD -- OAI number of records in a response: ## (example: "1000") 1000 ## CFG_OAI_EXPIRE -- OAI resumptionToken expiration time: ## (example: "1000") 90000 -## CFG_OAI_SLEEP -- service unavailable between two consecutive +## CFG_OAI_SLEEP -- service unavailable between two consecutive ## requests for CFG_OAI_SLEEP seconds: ## (example: "10") 10 ################################## ## Part 6: WebSubmit parameters ## ################################## ## This section contains some WML-based configuration parameters for ## WebSubmit module. Please note that WebSubmit is mostly configured ## on run-time via its WebSubmit Admin web interface. The parameters ## below are the ones that you do not probably want to modify during ## the runtime. ## CFG_SUBMIT_COUNTER -- indicates where the counters used by websubmit ## are stored /submit/counters ## CFG_SUBMIT_DIR -- this indicates where the websubmit system will ## keep each submissions running data /submit/storage ######################################### ## Part 7: Fulltext Archive parameters ## ######################################### ## This section contains some WML-based configuration parameters for ## fulltext archive. -## CFG_FILE_DIR -- this indicates where the fulltext files will be +## CFG_FILE_DIR -- this indicates where the fulltext files will be ## stored /files ## CFG_FILE_DIR_SIZE -- all attached fulltext files are stored ## under the CFG_FILE_DIR directory, inside subdirectories called gX ## this variable indicates the maximum number of files stored in each ## subdirectories 5000 ################################## ## Part 8: BibFormat parameters ## ################################## ## This section contains some WML-based configuration parameters for ## BibFormat module. Please note that BibFormat is mostly configured ## on run-time via its BibFormat Admin web interface. The parameters ## below are the ones that you do not probably want to modify very ## often during the runtime. ## CFG_BIBFORMAT_TIME_LIMIT -- the time limit of BibFormat process ## after which the task will terminate. This is useful to avoid ## eventual runaways. ## (example: "1000") 1000 ################################# ## Part 9: BibIndex parameters ## ################################# ## This section contains some WML-based configuration parameters for ## BibIndex module. Please note that BibIndex is mostly configured ## on run-time via its BibIndex Admin web interface. The parameters ## below are the ones that you do not probably want to modify very ## often during the runtime. ## CFG_BIBINDEX_FULLTEXT_INDEX_LOCAL_FILES_ONLY -- when fulltext indexing, do ## you want to index locally stored files only, or also external URLs? ## Use "0" to say "no" and "1" to say "yes". ## (example: "0") 0 ## CFG_BIBINDEX_STEMMER_DEFAULT_LANGUAGE -- when indexing, do you want to use ## stemming? If so, stem according to which language? Use '' for ## no stemming, 'fr' for French, 'en' for English, 'no' for Norwegian, ## 'sv' for Swedish, 'de' for German, 'it' for Italian, 'pt' for ## Portuguese'. This feature is still somewhat experimental. We ## recommend to say nothing ("") at this stage of things. ## (example: "") ## CFG_BIBINDEX_REMOVE_STOPWORDS -- when indexing, do we want to remove ## stopwords? Use "0" to say "no" and "1" to say "yes". ## (example: "0") 0 ## CFG_BIBINDEX_PATH_TO_STOPWORDS_FILE -- path to the stopwords file. You ## probably don't want to change this path, although you may want to ## change the content of that file. Note that the file is used by the ## rank engine internally, so it should be given even if stopword ## removal in the indexes is not used. /bibrank/stopwords.kb ## CFG_BIBINDEX_CHARS_ALPHANUMERIC_SEPARATORS -- characters considered as ## alphanumeric separators of word-blocks inside words. You probably ## don't want to change this. ## (example: "\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~") \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ ## CFG_BIBINDEX_CHARS_PUNCTUATION -- characters considered as punctuation ## between word-blocks inside words. You probably don't want to ## change this. ## (example: "\.\,\:\;\?\!\"") \.\,\:\;\?\!\" ## CFG_BIBINDEX_REMOVE_HTML_MARKUP -- should we attempt to remove HTML markup ## before indexing? Use 1 if you have HTML markup inside metadata ## (e.g. in abstracts), use 0 otherwise. ## (example: "0") 0 ## CFG_BIBINDEX_MIN_WORD_LENGTH -- minimum word length allowed to be added to ## index. The terms smaller then this amount will be discarded. ## Useful to keep the database clean, however you can safely leave ## this value on 0 for up to 1,000,000 documents. ## (example: "0") 0 ## CFG_BIBINDEX_URLOPENER_USERNAME and CFG_BIBINDEX_URLOPENER_PASSWORD -- ## access credentials to access restricted URLs, interesting only if ## you are fulltext-indexing files located on a remote server that is ## only available via username/password. But it's probably better to ## handle this case via IP or some convention; the current scheme is ## mostly there for demo only. ## (example: "mysuperuser") mysuperuser mysuperpass ######################################## ## Part 10: Access control parameters ## ######################################## ## This section contains some WML-based configuration parameters for ## the access control system. Please note that WebAccess is mostly ## configured on run-time via its WebAccess Admin web interface. The ## parameters below are the ones that you do not probably want to ## modify very often during the runtime. (If you do want to modify ## them during runtime, for example te deny access temporarily because ## of backups, you can edit access_control_config.py directly, no need ## to get back here and no need to redo the make process.) ## CFG_ACCESS_CONTROL_LEVEL_SITE -- defines how open this site is. ## Use 0 for normal operation of the site, 1 for read-only site (all ## write operations temporarily closed), 2 for site fully closed. ## Useful for site maintenance. ## (example: "0") 0 ## CFG_ACCESS_CONTROL_LEVEL_GUESTS -- guest users access policy. Use ## 0 to allow guest users, 1 not to allow them (all users must login). ## (example: "0") 0 ## CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS -- account registration and ## activation policy. When 0, users can register and accounts are ## automatically activated. When 1, users can register but admin must ## activate the accounts. When 2, users cannot register nor update ## their email address, only admin can register accounts. When 3, ## users cannot register nor update email address nor password, only ## admin can register accounts. When 4, the same as 3 applies, nor ## user cannot change his login method. ## (example: "0") 0 ## CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN -- limit account ## registration to certain email addresses? If wanted, give domain ## name below. If not wanted, leave it empty. ## (example: "cern.ch"): ## CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS -- send a ## notification email to the administrator when a new account is ## created? Use 0 for no, 1 for yes. ## (example: "0") 0 ## CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT -- send a ## notification email to the user when a new account is created? Use ## 0 for no, 1 for yes. ## (example: "0") 0 ## CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION -- send a ## notification email to the user when a new account is activated? ## Use 0 for no, 1 for yes. ## (example: "0") 0 ## CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION -- send a ## notification email to the user when a new account is deleted or ## account demand rejected? Use 0 for no, 1 for yes. ## (example: "0") 0 ########################## ## THAT's ALL, FOLKS! ## ########################## - + ## And this is the end of "config.wml" WML configuration phase. Now ## please return to the main CDS source directory and type 'make'. ## (Note: if you have bravely edited the "cdsnavbar.wml" file too, ## then please do "make clean" before doing "make".) diff --git a/modules/bibedit/web/admin/bibeditadmin.py b/modules/bibedit/web/admin/bibeditadmin.py index f2790b3a0..bc7685c2e 100644 --- a/modules/bibedit/web/admin/bibeditadmin.py +++ b/modules/bibedit/web/admin/bibeditadmin.py @@ -1,137 +1,137 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio BibEdit Administrator Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" from invenio.config import cdslang, weburl from invenio.webpage import page from invenio.webuser import getUid, page_not_authorized from invenio.bibedit_engine import perform_request_index, perform_request_edit, perform_request_submit from invenio.search_engine import record_exists from invenio.access_control_engine import acc_authorize_action from invenio.messages import gettext_set_language, wash_language from invenio.urlutils import wash_url_argument, redirect_to_url navtrail = """ Admin Area > BibEdit Admin """ % (weburl, weburl) def index(req, ln=cdslang, recid=None, temp="false", format_tag='marc', edit_tag=None, delete_tag=None, num_field=None, add=0, cancel=0, - delete=0 ,confirm_delete=0, **args): + delete=0 ,confirm_delete=0, **args): """ BibEdit Admin interface. """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - + recid = wash_url_argument(recid, "int") add = wash_url_argument(add, "int") cancel = wash_url_argument(cancel, "int") delete = wash_url_argument(delete, "int") confirm_delete = wash_url_argument(confirm_delete, "int") - - (auth_code, auth_message) = acc_authorize_action(uid,'runbibedit') + + (auth_code, auth_message) = acc_authorize_action(req,'runbibedit') if auth_code == 0: (body, errors, warnings) = perform_request_index(ln, recid, cancel, delete, confirm_delete, uid, temp, format_tag, edit_tag, delete_tag, num_field, add, args) else: return page_not_authorized(req=req, text=auth_message, navtrail=navtrail) if recid != 0: title = _("Record") + " #" + str(recid) if add == 3: title = _("Record %s - Add a field") % ('#' + str(recid)) else: title = _("BibEdit Admin Interface") - + return page(title = title, body = body, errors = errors, warnings = warnings, uid = getUid(req), language = ln, - navtrail = navtrail, + navtrail = navtrail, lastupdated = __lastupdated__, - req = req) + req = req) def edit(req, recid=None, tag=None, num_field='0', num_subfield=0, format_tag='marc', - del_subfield=None, temp="false", add=0, ln=cdslang, **args): + del_subfield=None, temp="false", add=0, ln=cdslang, **args): """ Edit Field page. """ ln = wash_language(ln) _ = gettext_set_language(ln) - + uid = getUid(req) recid = wash_url_argument(recid, "int") num_field = wash_url_argument(num_field, "int") add = wash_url_argument(add, "int") num_subfield = wash_url_argument(num_subfield, "int") - - (auth_code, auth_message) = acc_authorize_action(uid,'runbibedit') + + (auth_code, auth_message) = acc_authorize_action(req,'runbibedit') if (auth_code == 0): if (recid and tag and (record_exists(recid)>0)): (body, errors, warnings) = perform_request_edit(ln, recid, uid, tag, num_field, num_subfield, format_tag, temp, del_subfield, add, args) else: redirect_to_url(req, 'index?ln=' + ln) else: return page_not_authorized(req=req, text=auth_message, navtrail=navtrail) title = _("Edit record %(x_recid)s, field %(x_field)s") % {'x_recid': '#' + str(recid), 'x_field': '#' + str(tag[:3])} if add == 1: title = _("Edit record %(x_recid)s, field %(x_field)s - Add a subfield") % {'x_recid': '#' + str(recid), - 'x_field': '#' + str(tag[:3])} + 'x_field': '#' + str(tag[:3])} return page(title = title, body = body, errors = errors, warnings = warnings, uid = getUid(req), language = ln, navtrail = navtrail, lastupdated = __lastupdated__, - req = req) + req = req) def submit(req, recid='', ln=cdslang): """ Submit temp_record on database. """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) recid = wash_url_argument(recid, "int") - (auth_code, auth_message) = acc_authorize_action(uid,'runbibedit') + (auth_code, auth_message) = acc_authorize_action(req,'runbibedit') if auth_code == 0: if (recid and (record_exists(recid)>0)): (body, errors, warnings) = perform_request_submit(ln, recid) else: redirect_to_url(req, 'index?ln=' + ln) else: return page_not_authorized(req=req, text=auth_message, navtrail=navtrail) return page(title = _("Submit and save record %s") % ('#' + str(recid)), body = body, errors = errors, warnings = warnings, uid = getUid(req), language = ln, navtrail = navtrail, lastupdated = __lastupdated__, - req = req) + req = req) diff --git a/modules/bibformat/lib/bibformat_engine.py b/modules/bibformat/lib/bibformat_engine.py index 2f3818483..62a84756d 100644 --- a/modules/bibformat/lib/bibformat_engine.py +++ b/modules/bibformat/lib/bibformat_engine.py @@ -1,1879 +1,1883 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """ Formats a single XML Marc record using specified format. There is no API for the engine. Instead use bibformat.py. SEE: bibformat.py, bibformat_utils.py """ __revision__ = "$Id$" import re import sys import os import inspect import traceback import zlib import cgi from invenio.config import \ CFG_PATH_PHP, \ bindir, \ cdslang from invenio.errorlib import \ register_errors, \ get_msgs_for_code_list from invenio.bibrecord import \ create_record, \ record_get_field_instances, \ record_get_field_value, \ record_get_field_values from invenio.bibformat_xslt_engine import format from invenio.dbquery import run_sql from invenio.messages import \ language_list_long, \ wash_language from invenio import bibformat_dblayer from invenio.bibformat_config import \ CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION, \ CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION, \ CFG_BIBFORMAT_TEMPLATES_PATH, \ CFG_BIBFORMAT_ELEMENTS_PATH, \ CFG_BIBFORMAT_OUTPUTS_PATH, \ CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH from bibformat_utils import \ record_get_xml, \ parse_tag from invenio.htmlutils import HTMLWasher from xml.dom import minidom #Remove when call_old_bibformat is removed # Cache for data we have already read and parsed format_templates_cache = {} format_elements_cache = {} format_outputs_cache = {} kb_mappings_cache = {} cdslangs = language_list_long() html_field = '' # String indicating that field should be # treated as HTML (and therefore no escaping of # HTML tags should occur. # Appears in some field values. washer = HTMLWasher() # Used to remove dangerous tags from HTML # sources # Regular expression for finding ... tag in format templates pattern_lang = re.compile(r''' #closing start tag (?P.*?) #anything but the next group (greedy) () #end tag ''', re.IGNORECASE | re.DOTALL | re.VERBOSE) # Builds regular expression for finding each known language in tags ln_pattern_text = r"<(" for lang in cdslangs: ln_pattern_text += lang[0] +r"|" - + ln_pattern_text = ln_pattern_text.rstrip(r"|") ln_pattern_text += r")>(.*?)" - + ln_pattern = re.compile(ln_pattern_text) # Regular expression for finding tag in format templates pattern_format_template_name = re.compile(r''' #closing start tag (?P.*?) #name value. any char that is not end tag ()(\n)? #end tag ''', re.IGNORECASE | re.DOTALL | re.VERBOSE) # Regular expression for finding tag in format templates pattern_format_template_desc = re.compile(r''' #closing start tag (?P.*?) #description value. any char that is not end tag (\n)? #end tag ''', re.IGNORECASE | re.DOTALL | re.VERBOSE) # Regular expression for finding tags in format templates pattern_tag = re.compile(r''' [^/\s]+) #any char but a space or slash \s* #any number of spaces (?P(\s* #params here (?P([^=\s])*)\s* #param name: any chars that is not a white space or equality. Followed by space(s) =\s* #equality: = followed by any number of spaces (?P[\'"]) #one of the separators (?P.*?) #param value: any chars that is not a separator like previous one (?P=sep) #same separator as starting one )*) #many params \s* #any number of spaces (/)?> #end of the tag ''', re.IGNORECASE | re.DOTALL | re.VERBOSE) # Regular expression for finding params inside tags in format templates pattern_function_params = re.compile(''' (?P([^=\s])*)\s* # Param name: any chars that is not a white space or equality. Followed by space(s) =\s* # Equality: = followed by any number of spaces (?P[\'"]) # One of the separators (?P.*?) # Param value: any chars that is not a separator like previous one (?P=sep) # Same separator as starting one ''', re.VERBOSE | re.DOTALL ) # Regular expression for finding format elements "params" attributes # (defined by @param) pattern_format_element_params = re.compile(''' @param\s* # Begins with @param keyword followed by space(s) (?P[^\s=]*)\s* # A single keyword, and then space(s) #(=\s*(?P[\'"]) # Equality, space(s) and then one of the separators #(?P.*?) # Default value: any chars that is not a separator like previous one #(?P=sep) # Same separator as starting one #)?\s* # Default value for param is optional. Followed by space(s) (?P.*) # Any text that is not end of line (thanks to MULTILINE parameter) ''', re.VERBOSE | re.MULTILINE) # Regular expression for finding format elements "see also" attribute # (defined by @see) pattern_format_element_seealso = re.compile('''@see\s*(?P.*)''', re.VERBOSE | re.MULTILINE) #Regular expression for finding 2 expressions in quotes, separated by #comma (as in template("1st","2nd") ) #Used when parsing output formats ## pattern_parse_tuple_in_quotes = re.compile(''' ## (?P[\'"]) ## (?P.*) ## (?P=sep1) ## \s*,\s* ## (?P[\'"]) ## (?P.*) ## (?P=sep2) -## ''', re.VERBOSE | re.MULTILINE) +## ''', re.VERBOSE | re.MULTILINE) def call_old_bibformat(recID, format="HD", on_the_fly=False, verbose=0): """ FIXME: REMOVE FUNCTION WHEN MIGRATION IS DONE Calls BibFormat for the record RECID in the desired output format FORMAT. @param on_the_fly if False, try to return an already preformatted version of the record in the database Note: this functions always try to return HTML, so when bibformat returns XML with embedded HTML format inside the tag FMT $g, as is suitable for prestoring output formats, we perform un-XML-izing here in order to return HTML body only. """ out = "" res = [] if not on_the_fly: # look for formatted notice existence: query = "SELECT value, last_updated FROM bibfmt WHERE "\ "id_bibrec='%s' AND format='%s'" % (recID, format) res = run_sql(query, None, 1) if res: # record 'recID' is formatted in 'format', so print it if verbose == 9: last_updated = res[0][1] out += """\n
Found preformatted output for record %i (cache updated on %s). """ % (recID, last_updated) decompress = zlib.decompress return "%s" % decompress(res[0][0]) else: # record 'recID' is not formatted in 'format', # so try to call BibFormat on the fly or use default format: if verbose == 9: out += """\n
Formatting record %i on-the-fly with old BibFormat.
""" % recID pipe_input, pipe_output, pipe_error = os.popen3(["%s/bibformat" % bindir, "otype=%s" % format], 'rw') # Retrieve MARCXML # Build it on-the-fly only if 'call_old_bibformat' was called # with format=xm and on_the_fly=True xm_record = record_get_xml(recID, 'xm', on_the_fly=(on_the_fly and format == 'xm')) pipe_input.write(xm_record) pipe_input.close() bibformat_output = pipe_output.read() pipe_output.close() pipe_error.close() if bibformat_output.startswith(""): dom = minidom.parseString(bibformat_output) for e in dom.getElementsByTagName('subfield'): if e.getAttribute('code') == 'g': for t in e.childNodes: out += t.data.encode('utf-8') else: out += bibformat_output return out def format_record(recID, of, ln=cdslang, verbose=0, search_pattern=[], xml_record=None, uid=None): """ Formats a record given output format. Main entry function of bibformat engine. - + Returns a formatted version of the record in the specified language, search pattern, and with the specified output format. The function will define which format template must be applied. You can either specify an record ID to format, or give its xml representation. if 'xml_record' is not None, then use it instead of recID. 'uid' allows to grant access to some functionalities on a page depending - on the user's priviledges. - + on the user's priviledges. + @param recID the ID of record to format @param of an output format code (or short identifier for the output format) @param ln the language to use to format the record @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, stop if error in format elements 9: errors and warnings, stop if error (debug mode )) @param search_pattern list of strings representing the user request in web interface @param xml_record an xml string representing the record to format @param uid the user id of the person who will view the formatted page @return formatted record """ out = "" errors_ = [] # Temporary workflow (during migration of formats): # Call new BibFormat - # But if format not found for new BibFormat, then call old BibFormat + # But if format not found for new BibFormat, then call old BibFormat - #Create a BibFormat Object to pass that contain record and context + #Create a BibFormat Object to pass that contain record and context bfo = BibFormatObject(recID, ln, search_pattern, xml_record, uid, of) - + #Find out which format template to use based on record and output format. template = decide_format_template(bfo, of) if verbose == 9 and template is not None: out += """\n
Using %s template for record %i. """ % (template, recID) ############### FIXME: REMOVE WHEN MIGRATION IS DONE ############### path = "%s%s%s" % (CFG_BIBFORMAT_TEMPLATES_PATH, os.sep, template) - if template is None or not os.access(path, os.R_OK): + if template is None or not os.access(path, os.R_OK): # template not found in new BibFormat. Call old one if verbose == 9: if template is None: out += """\n
- No template found for output format %s and record %i. + No template found for output format %s and record %i. (Check invenio.err log file for more details) """ % (of, recID) else: out += """\n
Template %s could not be read. """ % (template) if CFG_PATH_PHP: if verbose == 9: out+= """\n
Using old BibFormat for record %s. """ % recID return out + call_old_bibformat(recID, format=of, on_the_fly=True, verbose=verbose) ############################# END ################################## - + error = get_msgs_for_code_list([("ERR_BIBFORMAT_NO_TEMPLATE_FOUND", of)], stream='error', ln=cdslang) errors_.append(error) if verbose == 0: register_errors(error, 'error') elif verbose > 5: - return out + error[0][1] + return out + error[0][1] return out # Format with template (out_, errors) = format_with_format_template(template, bfo, verbose) errors_.extend(errors) - + out += out_ - + return out def decide_format_template(bfo, of): """ Returns the format template name that should be used for formatting given output format and BibFormatObject. Look at of rules, and take the first matching one. If no rule matches, returns None To match we ignore lettercase and spaces before and after value of rule and value of record @param bfo a BibFormatObject @param of the code of the output format to use """ output_format = get_output_format(of) for rule in output_format['rules']: value = bfo.field(rule['field']).strip()#Remove spaces pattern = rule['value'].strip() #Remove spaces match_obj = re.match(pattern, value, re.IGNORECASE) if match_obj is not None and \ match_obj.start() == 0 and match_obj.end() == len(value): return rule['template'] template = output_format['default'] if template != '': return template else: return None - + def format_with_format_template(format_template_filename, bfo, verbose=0, format_template_code=None): """ Format a record given a format template. Also returns errors - + Returns a formatted version of the record represented by bfo, in the language specified in bfo, and with the specified format template. If format_template_code is provided, the template will not be loaded from format_template_filename (but format_template_filename will still be used to determine if bft or xsl transformation applies). This allows to preview format code without having to save file on disk. - + @param format_template_filename the dilename of a format template @param bfo the object containing parameters for the current formatting @param format_template_code if not empty, use code as template instead of reading format_template_filename (used for previews) @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, 9: errors and warnings, stop if error (debug mode )) @return tuple (formatted text, errors) """ errors_ = [] if format_template_code is not None: - format_content = str(format_template_code) + format_content = str(format_template_code) else: format_content = get_format_template(format_template_filename)['code'] if format_template_filename is None or \ format_template_filename.endswith("."+CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION): # .bft localized_format = filter_languages(format_content, bfo.lang) (evaluated_format, errors) = eval_format_template_elements(localized_format, bfo, verbose) errors_ = errors else: #.xsl # Fetch MARCXML. On-the-fly xm if we are now formatting in xm xml_record = record_get_xml(bfo.recID, 'xm', on_the_fly=(bfo.format != 'xm')) # Transform MARCXML using stylesheet evaluated_format = format(xml_record, template_source=format_content) - + return (evaluated_format, errors_) def eval_format_template_elements(format_template, bfo, verbose=0): """ Evalutes the format elements of the given template and replace each element with its value. Also returns errors. - + Prepare the format template content so that we can directly replace the marc code by their value. This implies: 1) Look for special tags 2) replace special tags by their evaluation - + @param format_template the format template code @param bfo the object containing parameters for the current formatting @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, 9: errors and warnings, stop if error (debug mode )) @return tuple (result, errors) """ errors_ = [] - + # First define insert_element_code(match), used in re.sub() function def insert_element_code(match): """ Analyses 'match', interpret the corresponding code, and return the result of the evaluation. Called by substitution in 'eval_format_template_elements(...)' @param match a match object corresponding to the special tag that must be interpreted """ function_name = match.group("function_name") try: format_element = get_format_element(function_name, verbose) except Exception, e: if verbose >= 5: return '' + \ cgi.escape(str(e)).replace('\n', '
') + \ '
' if format_element is None: error = get_msgs_for_code_list([("ERR_BIBFORMAT_CANNOT_RESOLVE_ELEMENT_NAME", function_name)], stream='error', ln=cdslang) errors_.append(error) if verbose >= 5: return '' + \ error[0][1]+'' else: params = {} # Look for function parameters given in format template code all_params = match.group('params') if all_params is not None: function_params_iterator = pattern_function_params.finditer(all_params) for param_match in function_params_iterator: name = param_match.group('param') value = param_match.group('value') params[name] = value # Evaluate element with params and return (Do not return errors) (result, errors) = eval_format_element(format_element, bfo, params, verbose) errors_.append(errors) return result - - + + # Substitute special tags in the format by our own text. # Special tags have the form format = pattern_tag.sub(insert_element_code, format_template) - + return (format, errors_) def eval_format_element(format_element, bfo, parameters={}, verbose=0): """ Returns the result of the evaluation of the given format element name, with given BibFormatObject and parameters. Also returns the errors of the evaluation. @param format_element a format element structure as returned by get_format_element @param bfo a BibFormatObject used for formatting @param parameters a dict of parameters to be used for formatting. Key is parameter and value is value of parameter @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, 9: errors and warnings, stop if error (debug mode )) @return tuple (result, errors) """ - + errors = [] #Load special values given as parameters prefix = parameters.get('prefix', "") suffix = parameters.get('suffix', "") default_value = parameters.get('default', "") escape = parameters.get('escape', "") - + # 3 possible cases: # a) format element file is found: we execute it # b) format element file is not found, but exist in tag table (e.g. bfe_isbn) # c) format element is totally unknown. Do nothing or report error - + if format_element is not None and format_element['type'] == "python": # a) We found an element with the tag name, of type "python" # Prepare a dict 'params' to pass as parameter to 'format' # function of element params = {} # Look for parameters defined in format element # Fill them with specified default values and values # given as parameters for param in format_element['attrs']['params']: name = param['name'] default = param['default'] params[name] = parameters.get(name, default) - + # Add BibFormatObject params['bfo'] = bfo # Execute function with given parameters and return result. function = format_element['code'] - + try: output_text = apply(function, (), params) except Exception, e: name = format_element['attrs']['name'] error = ("ERR_BIBFORMAT_EVALUATING_ELEMENT", name, str(params)) errors.append(error) if verbose == 0: register_errors(errors, 'error') elif verbose >= 5: tb = sys.exc_info()[2] error_string = get_msgs_for_code_list(error, stream='error', ln=cdslang) stack = traceback.format_exception(Exception, e, tb, limit=None) output_text = ''+ \ str(error_string[0][1]) + "".join(stack) +' ' # None can be returned when evaluating function if output_text is None: output_text = "" else: output_text = str(output_text) # Escaping: # (1) By default, everything is escaped in mode 1 # (2) If evaluated element has 'escape_values()' function, use # its returned value as escape mode, and override (1) # (3) If template has a defined parameter (in allowed values), # use it, and override (1) and (2) # (1) escape_mode = 1 # (2) escape_function = format_element['escape_function'] if escape_function is not None: try: escape_mode = apply(escape_function, (), {'bfo': bfo}) except Exception, e: error = ("ERR_BIBFORMAT_EVALUATING_ELEMENT_ESCAPE", name) errors.append(error) if verbose == 0: register_errors(errors, 'error') elif verbose >= 5: tb = sys.exc_info()[2] error_string = get_msgs_for_code_list(error, stream='error', ln=cdslang) output_text += ''+ \ str(error_string[0][1]) +' ' # (3) if escape in ['0', '1']: escape_mode = int(escape) #If escape is equal to 1, then escape all # HTML reserved chars. if escape_mode == 1: output_text = cgi.escape(output_text) - + # Add prefix and suffix if they have been given as parameters and if # the evaluation of element is not empty if output_text.strip() != "": output_text = prefix + output_text + suffix # Add the default value if output_text is empty if output_text == "": output_text = default_value - + return (output_text, errors) - + elif format_element is not None and format_element['type'] == "field": # b) We have not found an element in files that has the tag # name. Then look for it in the table "tag" # # # # Load special values given as parameters separator = parameters.get('separator ', "") nbMax = parameters.get('nbMax', "") escape = parameters.get('escape', "1") # By default, escape here - + # Get the fields tags that have to be printed tags = format_element['attrs']['tags'] output_text = [] # Get values corresponding to tags for tag in tags: p_tag = parse_tag(tag) values = record_get_field_values(bfo.get_record(), p_tag[0], p_tag[1], p_tag[2], p_tag[3]) if len(values)>0 and isinstance(values[0], dict): #flatten dict to its values only values_list = map(lambda x: x.values(), values) #output_text.extend(values) for values in values_list: output_text.extend(values) else: output_text.extend(values) if nbMax != "": try: nbMax = int(nbMax) output_text = output_text[:nbMax] except: name = format_element['attrs']['name'] error = ("ERR_BIBFORMAT_NBMAX_NOT_INT", name) errors.append(error) if verbose < 5: register_errors(error, 'error') elif verbose >= 5: error_string = get_msgs_for_code_list(error, stream='error', ln=cdslang) output_text = output_text.append(error_string[0][1]) # Add prefix and suffix if they have been given as parameters and if # the evaluation of element is not empty. # If evaluation is empty string, return default value if it exists. # Else return empty string if ("".join(output_text)).strip() != "": # If escape is equal to 1, then escape all # HTML reserved chars. if escape == '1': output_text = cgi.escape(separator.join(output_text)) else: output_text = separator.join(output_text) - + output_text = prefix + output_text + suffix else: #Return default value output_text = default_value - + return (output_text, errors) else: # c) Element is unknown error = get_msgs_for_code_list([("ERR_BIBFORMAT_CANNOT_RESOLVE_ELEMENT_NAME", format_element)], stream='error', ln=cdslang) errors.append(error) if verbose < 5: register_errors(error, 'error') return ("", errors) elif verbose >= 5: if verbose >= 9: sys.exit(error[0][1]) return ('' + \ error[0][1]+'', errors) - + def filter_languages(format_template, ln='en'): """ Filters the language tags that do not correspond to the specified language. - + @param format_template the format template code @param ln the language that is NOT filtered out from the template @return the format template with unnecessary languages filtered out """ # First define search_lang_tag(match) and clean_language_tag(match), used # in re.sub() function def search_lang_tag(match): """ Searches for the ... tag and remove inner localized tags such as , , that are not current_lang. If current_lang cannot be found inside ... , try to use 'cdslang' @param match a match object corresponding to the special tag that must be interpreted """ current_lang = ln def clean_language_tag(match): """ Return tag text content if tag language of match is output language. Called by substitution in 'filter_languages(...)' @param match a match object corresponding to the special tag that must be interpreted """ if match.group(1) == current_lang: return match.group(2) else: return "" # End of clean_language_tag - + lang_tag_content = match.group("langs") # Try to find tag with current lang. If it does not exists, # then current_lang becomes cdslang until the end of this # replace pattern_current_lang = re.compile(r"<"+current_lang+ \ "\s*>(.*?)") if re.search(pattern_current_lang, lang_tag_content) is None: current_lang = cdslang cleaned_lang_tag = ln_pattern.sub(clean_language_tag, lang_tag_content) return cleaned_lang_tag # End of search_lang_tag - + filtered_format_template = pattern_lang.sub(search_lang_tag, format_template) return filtered_format_template def get_format_template(filename, with_attributes=False): """ Returns the structured content of the given formate template. if 'with_attributes' is true, returns the name and description. Else 'attrs' is not returned as key in dictionary (it might, if it has already been loaded previously) {'code':"Some template code" 'attrs': {'name': "a name", 'description': "a description"} } @param filename the filename of an format template @param with_attributes if True, fetch the attributes (names and description) for format' @return strucured content of format template """ # Get from cache whenever possible global format_templates_cache if not filename.endswith("."+CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION) and \ not filename.endswith(".xsl"): return None - + if format_templates_cache.has_key(filename): # If we must return with attributes and template exist in # cache with attributes then return cache. # Else reload with attributes if with_attributes and \ format_templates_cache[filename].has_key('attrs'): return format_templates_cache[filename] format_template = {'code':""} try: - + path = "%s%s%s" % (CFG_BIBFORMAT_TEMPLATES_PATH, os.sep, filename) format_file = open(path) format_content = format_file.read() format_file.close() # Load format template code # Remove name and description if filename.endswith("."+CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION): code_and_description = pattern_format_template_name.sub("", format_content) code = pattern_format_template_desc.sub("", code_and_description) else: code = format_content - + format_template['code'] = code except Exception, e: errors = get_msgs_for_code_list([("ERR_BIBFORMAT_CANNOT_READ_TEMPLATE_FILE", filename, str(e))], stream='error', ln=cdslang) register_errors(errors, 'error') # Save attributes if necessary if with_attributes: format_template['attrs'] = get_format_template_attrs(filename) - # Cache and return + # Cache and return format_templates_cache[filename] = format_template return format_template def get_format_templates(with_attributes=False): """ Returns the list of all format templates, as dictionary with filenames as keys if 'with_attributes' is true, returns the name and description. Else 'attrs' is not returned as key in each dictionary (it might, if it has already been loaded previously) [{'code':"Some template code" 'attrs': {'name': "a name", 'description': "a description"} }, ... } @param with_attributes if True, fetch the attributes (names and description) for formats """ format_templates = {} files = os.listdir(CFG_BIBFORMAT_TEMPLATES_PATH) - + for filename in files: if filename.endswith("."+CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION) or \ filename.endswith(".xsl"): format_templates[filename] = get_format_template(filename, with_attributes) - + return format_templates def get_format_template_attrs(filename): """ Returns the attributes of the format template with given filename - + The attributes are {'name', 'description'} Caution: the function does not check that path exists or that the format element is valid. @param the path to a format element """ attrs = {} attrs['name'] = "" attrs['description'] = "" try: template_file = open("%s%s%s" % (CFG_BIBFORMAT_TEMPLATES_PATH, os.sep, filename)) code = template_file.read() template_file.close() match = None if filename.endswith(".xsl"): # .xsl attrs['name'] = filename[:-4] else: # .bft match = pattern_format_template_name.search(code) if match is not None: attrs['name'] = match.group('name') else: attrs['name'] = filename - - + + match = pattern_format_template_desc.search(code) if match is not None: attrs['description'] = match.group('desc').rstrip('.') except Exception, e: errors = get_msgs_for_code_list([("ERR_BIBFORMAT_CANNOT_READ_TEMPLATE_FILE", filename, str(e))], stream='error', ln=cdslang) register_errors(errors, 'error') attrs['name'] = filename return attrs def get_format_element(element_name, verbose=0, with_built_in_params=False): """ Returns the format element structured content. Return None if element cannot be loaded (file not found, not readable or invalid) - The returned structure is {'attrs': {some attributes in dict. See get_format_element_attrs_from_*} + The returned structure is {'attrs': {some attributes in dict. See get_format_element_attrs_from_*} 'code': the_function_code, 'type':"field" or "python" depending if element is defined in file or table, 'escape_function': the function to call to know if element output must be escaped} @param element_name the name of the format element to load @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, 9: errors and warnings, stop if error (debug mode )) - @param with_built_in_params if True, load the parameters built in all elements + @param with_built_in_params if True, load the parameters built in all elements @return a dictionary with format element attributes """ # Get from cache whenever possible global format_elements_cache errors = [] # Resolve filename and prepare 'name' as key for the cache filename = resolve_format_element_filename(element_name) if filename is not None: name = filename.upper() else: name = element_name.upper() - + if format_elements_cache.has_key(name): element = format_elements_cache[name] if not with_built_in_params or \ (with_built_in_params and \ element['attrs'].has_key('builtin_params')): return element if filename is None: # Element is maybe in tag table if bibformat_dblayer.tag_exists_for_name(element_name): format_element = {'attrs': get_format_element_attrs_from_table( \ element_name, with_built_in_params), 'code':None, 'escape_function':None, 'type':"field"} # Cache and returns format_elements_cache[name] = format_element return format_element - + else: errors = get_msgs_for_code_list([("ERR_BIBFORMAT_FORMAT_ELEMENT_NOT_FOUND", element_name)], stream='error', ln=cdslang) if verbose == 0: register_errors(errors, 'error') elif verbose >= 5: - sys.stderr.write(errors[0][1]) + sys.stderr.write(errors[0][1]) return None - + else: format_element = {} - + module_name = filename if module_name.endswith(".py"): module_name = module_name[:-3] # Load element try: module = __import__(CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH + \ "." + module_name) # Load last module in import path # For eg. load bfe_name in # invenio.bibformat_elements.bfe_name # Used to keep flexibility regarding where elements # directory is (for eg. test cases) components = CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH.split(".") for comp in components[1:]: module = getattr(module, comp) - + except Exception, e: # We catch all exceptions here, as we just want to print # traceback in all cases tb = sys.exc_info()[2] stack = traceback.format_exception(Exception, e, tb, limit=None) errors = get_msgs_for_code_list([("ERR_BIBFORMAT_IN_FORMAT_ELEMENT", element_name,"\n" + "\n".join(stack[-2:-1]))], stream='error', ln=cdslang) if verbose == 0: register_errors(errors, 'error') elif verbose >= 5: sys.stderr.write(errors[0][1]) if errors: if verbose >= 7: raise Exception, errors[0][1] return None # Load function 'format()' inside element try: function_format = module.__dict__[module_name].format format_element['code'] = function_format except AttributeError, e: errors = get_msgs_for_code_list([("ERR_BIBFORMAT_FORMAT_ELEMENT_FORMAT_FUNCTION", element_name)], stream='warning', ln=cdslang) if verbose == 0: register_errors(errors, 'error') elif verbose >= 5: sys.stderr.write(errors[0][1]) if errors: if verbose >= 7: raise Exception, errors[0][1] return None - + # Load function 'escape_values()' inside element function_escape = getattr(module.__dict__[module_name], 'escape_values', None) format_element['escape_function'] = function_escape # Prepare, cache and return format_element['attrs'] = get_format_element_attrs_from_function( \ function_format, element_name, with_built_in_params) format_element['type'] = "python" format_elements_cache[name] = format_element return format_element - + def get_format_elements(with_built_in_params=False): """ Returns the list of format elements attributes as dictionary structure - + Elements declared in files have priority over element declared in 'tag' table The returned object has this format: {element_name1: {'attrs': {'description':..., 'seealso':... 'params':[{'name':..., 'default':..., 'description':...}, ...] 'builtin_params':[{'name':..., 'default':..., 'description':...}, ...] }, 'code': code_of_the_element }, element_name2: {...}, ...} Returns only elements that could be loaded (not error in code) - + @return a dict of format elements with name as key, and a dict as attributes - @param with_built_in_params if True, load the parameters built in all elements + @param with_built_in_params if True, load the parameters built in all elements """ format_elements = {} - + mappings = bibformat_dblayer.get_all_name_tag_mappings() for name in mappings: format_elements[name.upper().replace(" ", "_").strip()] = get_format_element(name, with_built_in_params=with_built_in_params) - + files = os.listdir(CFG_BIBFORMAT_ELEMENTS_PATH) for filename in files: filename_test = filename.upper().replace(" ", "_") if filename_test.endswith(".PY") and filename.upper() != "__INIT__.PY": if filename_test.startswith("BFE_"): filename_test = filename_test[4:] element_name = filename_test[:-3] element = get_format_element(element_name, with_built_in_params=with_built_in_params) if element is not None: format_elements[element_name] = element - + return format_elements def get_format_element_attrs_from_function(function, element_name, with_built_in_params=False): """ Returns the attributes of the function given as parameter. - + It looks for standard parameters of the function, default values and comments in the docstring. The attributes are {'description', 'seealso':['element.py', ...], 'params':{name:{'name', 'default', 'description'}, ...], name2:{}} - + The attributes are {'name' : "name of element" #basically the name of 'name' parameter 'description': "a string description of the element", 'seealso' : ["element_1.py", "element_2.py", ...] #a list of related elements 'params': [{'name':"param_name", #a list of parameters for this element (except 'bfo') 'default':"default value", 'description': "a description"}, ...], 'builtin_params': {name: {'name':"param_name",#the parameters builtin for all elem of this kind 'default':"default value", 'description': "a description"}, ...}, } @param function the formatting function of a format element @param element_name the name of the element - @param with_built_in_params if True, load the parameters built in all elements + @param with_built_in_params if True, load the parameters built in all elements """ - + attrs = {} attrs['description'] = "" attrs['name'] = element_name.replace(" ", "_").upper() attrs['seealso'] = [] docstring = function.__doc__ if isinstance(docstring, str): # Look for function description in docstring #match = pattern_format_element_desc.search(docstring) description = docstring.split("@param")[0] description = description.split("@see")[0] attrs['description'] = description.strip().rstrip('.') # Look for @see in docstring match = pattern_format_element_seealso.search(docstring) if match is not None: elements = match.group('see').rstrip('.').split(",") for element in elements: attrs['seealso'].append(element.strip()) params = {} # Look for parameters in function definition (args, varargs, varkw, defaults) = inspect.getargspec(function) # Prepare args and defaults_list such that we can have a mapping # from args to defaults args.reverse() if defaults is not None: defaults_list = list(defaults) defaults_list.reverse() else: defaults_list = [] - + for arg, default in map(None, args, defaults_list): if arg == "bfo": #Don't keep this as parameter. It is hidden to users, and #exists in all elements of this kind - continue + continue param = {} param['name'] = arg if default is None: #In case no check is made inside element, we prefer to #print "" (nothing) than None in output - param['default'] = "" + param['default'] = "" else: param['default'] = default param['description'] = "(no description provided)" - + params[arg] = param if isinstance(docstring, str): # Look for @param descriptions in docstring. # Add description to existing parameters in params dict params_iterator = pattern_format_element_params.finditer(docstring) for match in params_iterator: name = match.group('name') if params.has_key(name): params[name]['description'] = match.group('desc').rstrip('.') attrs['params'] = params.values() - + # Load built-in parameters if necessary if with_built_in_params: - + builtin_params = [] # Add 'prefix' parameter param_prefix = {} param_prefix['name'] = "prefix" param_prefix['default'] = "" param_prefix['description'] = """A prefix printed only if the record has a value for this element""" builtin_params.append(param_prefix) # Add 'suffix' parameter param_suffix = {} param_suffix['name'] = "suffix" param_suffix['default'] = "" param_suffix['description'] = """A suffix printed only if the record has a value for this element""" builtin_params.append(param_suffix) # Add 'default' parameter param_default = {} param_default['name'] = "default" param_default['default'] = "" param_default['description'] = """A default value printed if the record has no value for this element""" builtin_params.append(param_default) # Add 'escape' parameter param_escape = {} param_escape['name'] = "escape" param_escape['default'] = "" param_escape['description'] = """If set to 1, replaces special characters '&', '<' and '>' of this element by SGML entities""" builtin_params.append(param_escape) attrs['builtin_params'] = builtin_params - + return attrs def get_format_element_attrs_from_table(element_name, with_built_in_params=False): """ Returns the attributes of the format element with given name in 'tag' table. Returns None if element_name does not exist in tag table. The attributes are {'name' : "name of element" #basically the name of 'element_name' parameter 'description': "a string description of the element", 'seealso' : [] #a list of related elements. Always empty in this case 'params': [], #a list of parameters for this element. Always empty in this case 'builtin_params': [{'name':"param_name", #the parameters builtin for all elem of this kind 'default':"default value", 'description': "a description"}, ...], 'tags':["950.1", 203.a] #the list of tags printed by this element } - + @param element_name an element name in database @param element_name the name of the element - @param with_built_in_params if True, load the parameters built in all elements + @param with_built_in_params if True, load the parameters built in all elements """ attrs = {} tags = bibformat_dblayer.get_tags_from_name(element_name) field_label = "field" if len(tags)>1: field_label = "fields" attrs['description'] = "Prints %s %s of the record" % (field_label, ", ".join(tags)) attrs['name'] = element_name.replace(" ", "_").upper() attrs['seealso'] = [] attrs['params'] = [] attrs['tags'] = tags - + # Load built-in parameters if necessary if with_built_in_params: builtin_params = [] - + # Add 'prefix' parameter param_prefix = {} param_prefix['name'] = "prefix" param_prefix['default'] = "" param_prefix['description'] = """A prefix printed only if the record has a value for this element""" builtin_params.append(param_prefix) # Add 'suffix' parameter param_suffix = {} param_suffix['name'] = "suffix" param_suffix['default'] = "" param_suffix['description'] = """A suffix printed only if the record has a value for this element""" builtin_params.append(param_suffix) # Add 'separator' parameter param_separator = {} param_separator['name'] = "separator" param_separator['default'] = " " param_separator['description'] = """A separator between elements of the field""" builtin_params.append(param_separator) # Add 'nbMax' parameter param_nbMax = {} param_nbMax['name'] = "nbMax" param_nbMax['default'] = "" param_nbMax['description'] = """The maximum number of values to print for this element. No limit if not specified""" builtin_params.append(param_nbMax) # Add 'default' parameter param_default = {} param_default['name'] = "default" param_default['default'] = "" param_default['description'] = """A default value printed if the record has no value for this element""" builtin_params.append(param_default) # Add 'escape' parameter param_escape = {} param_escape['name'] = "escape" param_escape['default'] = "" param_escape['description'] = """If set to 1, replaces special characters '&', '<' and '>' of this element by SGML entities""" builtin_params.append(param_escape) attrs['builtin_params'] = builtin_params return attrs - + def get_output_format(code, with_attributes=False, verbose=0): """ Returns the structured content of the given output format If 'with_attributes' is true, also returns the names and description of the output formats, else 'attrs' is not returned in dict (it might, if it has already been loaded previously). if output format corresponding to 'code' is not found return an empty structure. - + See get_output_format_attrs() to learn more on the attributes - + {'rules': [ {'field': "980__a", 'value': "PREPRINT", 'template': "filename_a.bft", }, {...} ], 'attrs': {'names': {'generic':"a name", 'sn':{'en': "a name", 'fr':"un nom"}, 'ln':{'en':"a long name"}} 'description': "a description" 'code': "fnm1", 'content_type': "application/ms-excel" - } + } 'default':"filename_b.bft" } - + @param code the code of an output_format @param with_attributes if True, fetch the attributes (names and description) for format @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, 9: errors and warnings, stop if error (debug mode )) @return strucured content of output format """ output_format = {'rules':[], 'default':""} filename = resolve_output_format_filename(code, verbose) - + if filename is None: errors = get_msgs_for_code_list([("ERR_BIBFORMAT_OUTPUT_FORMAT_CODE_UNKNOWN", code)], stream='error', ln=cdslang) register_errors(errors, 'error') if with_attributes: #Create empty attrs if asked for attributes output_format['attrs'] = get_output_format_attrs(code, verbose) return output_format - + # Get from cache whenever possible global format_outputs_cache if format_outputs_cache.has_key(filename): # If was must return with attributes but cache has not # attributes, then load attributes if with_attributes and not \ format_outputs_cache[filename].has_key('attrs'): format_outputs_cache[filename]['attrs'] = get_output_format_attrs(code, verbose) return format_outputs_cache[filename] try: if with_attributes: output_format['attrs'] = get_output_format_attrs(code, verbose) path = "%s%s%s" % (CFG_BIBFORMAT_OUTPUTS_PATH, os.sep, filename ) format_file = open(path) current_tag = '' for line in format_file: line = line.strip() if line == "": # Ignore blank lines continue if line.endswith(":"): # Retrieve tag # Remove : spaces and eol at the end of line clean_line = line.rstrip(": \n\r") # The tag starts at second position - current_tag = "".join(clean_line.split()[1:]).strip() + current_tag = "".join(clean_line.split()[1:]).strip() elif line.find('---') != -1: words = line.split('---') template = words[-1].strip() condition = ''.join(words[:-1]) value = "" - + output_format['rules'].append({'field': current_tag, 'value': condition, 'template': template, }) - + elif line.find(':') != -1: # Default case default = line.split(':')[1].strip() output_format['default'] = default except Exception, e: errors = get_msgs_for_code_list([("ERR_BIBFORMAT_CANNOT_READ_OUTPUT_FILE", filename, str(e))], stream='error', ln=cdslang) register_errors(errors, 'error') - - # Cache and return + + # Cache and return format_outputs_cache[filename] = output_format return output_format def get_output_format_attrs(code, verbose=0): """ Returns the attributes of an output format. The attributes contain 'code', which is the short identifier of the output format (to be given as parameter in format_record function to specify the output format), 'description', a description of the output format, and 'names', the localized names of the output format. If 'content_type' is specified then the search_engine will send a file with this content type and with result of formatting as content to the user. The 'names' dict always contais 'generic', 'ln' (for long name) and 'sn' (for short names) keys. 'generic' is the default name for output format. 'ln' and 'sn' contain long and short localized names of the output format. Only the languages for which a localization exist are used. {'names': {'generic':"a name", 'sn':{'en': "a name", 'fr':"un nom"}, 'ln':{'en':"a long name"}} 'description': "a description" 'code': "fnm1", 'content_type': "application/ms-excel" - } + } @param code the short identifier of the format @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, 9: errors and warnings, stop if error (debug mode )) @return strucured content of output format attributes """ if code.endswith("."+CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION): code = code[:-(len(CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION) + 1)] attrs = {'names':{'generic':"", 'ln':{}, 'sn':{}}, 'description':'', 'code':code.upper(), 'content_type':""} - + filename = resolve_output_format_filename(code, verbose) if filename is None: return attrs - + attrs['names'] = bibformat_dblayer.get_output_format_names(code) attrs['description'] = bibformat_dblayer.get_output_format_description(code) attrs['content_type'] = bibformat_dblayer.get_output_format_content_type(code) - + return attrs - + def get_output_formats(with_attributes=False): """ Returns the list of all output format, as a dictionary with their filename as key If 'with_attributes' is true, also returns the names and description of the output formats, else 'attrs' is not returned in dicts (it might, if it has already been loaded previously). - + See get_output_format_attrs() to learn more on the attributes - + {'filename_1.bfo': {'rules': [ {'field': "980__a", 'value': "PREPRINT", 'template': "filename_a.bft", }, {...} ], 'attrs': {'names': {'generic':"a name", 'sn':{'en': "a name", 'fr':"un nom"}, 'ln':{'en':"a long name"}} 'description': "a description" 'code': "fnm1" - } + } 'default':"filename_b.bft" }, - + 'filename_2.bfo': {...}, ... } @return the list of output formats """ output_formats = {} files = os.listdir(CFG_BIBFORMAT_OUTPUTS_PATH) - + for filename in files: if filename.endswith("."+CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION): code = "".join(filename.split(".")[:-1]) output_formats[filename] = get_output_format(code, with_attributes) return output_formats - + def get_kb_mapping(kb, string, default=""): """ Returns the value of the string' in the knowledge base 'kb'. - + If kb does not exist or string does not exist in kb, returns 'default' string value. - + @param kb a knowledge base name @param string a key in a knowledge base @param default a default value if 'string' is not in 'kb' - @return the value corresponding to the given string in given kb + @return the value corresponding to the given string in given kb """ - + global kb_mappings_cache - + if kb_mappings_cache.has_key(kb): kb_cache = kb_mappings_cache[kb] if kb_cache.has_key(string): value = kb_mappings_cache[kb][string] if value is None: return default else: return value else: # Precreate for caching this kb kb_mappings_cache[kb] = {} - + value = bibformat_dblayer.get_kb_mapping_value(kb, string) kb_mappings_cache[kb][str(string)] = value if value is None: return default else: return value def resolve_format_element_filename(string): """ Returns the filename of element corresponding to string This is necessary since format templates code call elements by ignoring case, for eg. is the same as . It is also recommended that format elements filenames are prefixed with bfe_ . We need to look for these too. The name of the element has to start with "BFE_". - + @param name a name for a format element @return the corresponding filename, with right case """ - + if not string.endswith(".py"): name = string.replace(" ", "_").upper() +".PY" else: name = string.replace(" ", "_").upper() - + files = os.listdir(CFG_BIBFORMAT_ELEMENTS_PATH) for filename in files: test_filename = filename.replace(" ", "_").upper() - + if test_filename == name or \ test_filename == "BFE_" + name or \ "BFE_" + test_filename == name: return filename # No element with that name found # Do not log error, as it might be a normal execution case: # element can be in database return None def resolve_output_format_filename(code, verbose=0): """ Returns the filename of output corresponding to code This is necessary since output formats names are not case sensitive but most file systems are. - + @param code the code for an output format @param verbose the level of verbosity from 0 to 9 (O: silent, 5: errors, 7: errors and warnings, 9: errors and warnings, stop if error (debug mode )) @return the corresponding filename, with right case, or None if not found """ #Remove non alphanumeric chars (except .) - code = re.sub(r"[^.0-9a-zA-Z]", "", code) + code = re.sub(r"[^.0-9a-zA-Z]", "", code) if not code.endswith("."+CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION): code = re.sub(r"\W", "", code) code += "."+CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION files = os.listdir(CFG_BIBFORMAT_OUTPUTS_PATH) for filename in files: if filename.upper() == code.upper(): return filename # No output format with that name found errors = get_msgs_for_code_list([("ERR_BIBFORMAT_CANNOT_RESOLVE_OUTPUT_NAME", code)], stream='error', ln=cdslang) if verbose == 0: register_errors(errors, 'error') elif verbose >= 5: sys.stderr.write(errors[0][1]) if verbose >= 9: sys.exit(errors[0][1]) return None def get_fresh_format_template_filename(name): """ Returns a new filename and name for template with given name. - + Used when writing a new template to a file, so that the name has no space, is unique in template directory Returns (unique_filename, modified_name) - + @param a name for a format template @return the corresponding filename, and modified name if necessary """ #name = re.sub(r"\W", "", name) #Remove non alphanumeric chars name = name.replace(" ", "_") filename = name # Remove non alphanumeric chars (except .) - filename = re.sub(r"[^.0-9a-zA-Z]", "", filename) + filename = re.sub(r"[^.0-9a-zA-Z]", "", filename) path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename \ + "." + CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION index = 1 while os.path.exists(path): index += 1 filename = name + str(index) path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename \ + "." + CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION if index > 1: returned_name = (name + str(index)).replace("_", " ") else: returned_name = name.replace("_", " ") - + return (filename + "." + CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION, returned_name) #filename.replace("_", " ")) def get_fresh_output_format_filename(code): """ Returns a new filename for output format with given code. - + Used when writing a new output format to a file, so that the code has no space, is unique in output format directory. The filename also need to be at most 6 chars long, as the convention is that filename == output format code (+ .extension) We return an uppercase code Returns (unique_filename, modified_code) - + @param code the code of an output format @return the corresponding filename, and modified code if necessary """ #code = re.sub(r"\W", "", code) #Remove non alphanumeric chars code = code.upper().replace(" ", "_") # Remove non alphanumeric chars (except .) - code = re.sub(r"[^.0-9a-zA-Z]", "", code) + code = re.sub(r"[^.0-9a-zA-Z]", "", code) if len(code) > 6: code = code[:6] - + filename = code path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename \ + "." + CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION index = 2 while os.path.exists(path): filename = code + str(index) if len(filename) > 6: filename = code[:-(len(str(index)))]+str(index) index += 1 path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename \ + "." + CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION # We should not try more than 99999... Well I don't see how we # could get there.. Sanity check. if index >= 99999: errors = get_msgs_for_code_list([("ERR_BIBFORMAT_NB_OUTPUTS_LIMIT_REACHED", code)], stream='error', ln=cdslang) register_errors(errors, 'error') sys.exit("Output format cannot be named as %s"%code) - + return (filename + "." + CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION, filename) - + def clear_caches(): """ Clear the caches (Output Format, Format Templates and Format Elements) """ global format_templates_cache, format_elements_cache , \ format_outputs_cache, kb_mappings_cache format_templates_cache = {} format_elements_cache = {} format_outputs_cache = {} kb_mappings_cache = {} class BibFormatObject: """ An object that encapsulates a record and associated methods, and that is given as parameter to all format elements 'format' function. The object is made specifically for a given formatting, i.e. it includes for example the language for the formatting. The object provides basic accessors to the record. For full access, one can get the record with get_record() and then use BibRecord methods on the returned object. """ # The record record = None # The language in which the formatting has to be done lang = cdslang # A list of string describing the context in which the record has # to be formatted. # It represents the words of the user request in web interface search search_pattern = [] # The id of the record recID = 0 # The user id of the person who will view the formatted page (if applicable) # This allows for example to print a "edit record" link for people # who have right to edit a record. uid = None # The format in which the record is being formatted format = '' - + + # The mod_python request object + req = None + def __init__(self, recID, ln=cdslang, search_pattern=[], - xml_record=None, uid=None, format=''): + xml_record=None, uid=None, format='', req=None): """ Creates a new bibformat object, with given record. You can either specify an record ID to format, or give its xml representation. if 'xml_record' is not None, use 'xml_record' instead of recID for the record. 'uid' allows to grant access to some functionalities on a page depending on the user's priviledges. - + @param recID the id of a record @param ln the language in which the record has to be formatted @param search_pattern list of string representing the request used by the user in web interface @param xml_record a xml string of the record to format @param uid the user id of the person who will view the formatted page @param format the format used for formatting this record """ if xml_record is not None: # If record is given as parameter self.record = create_record(xml_record)[0] recID = record_get_field_value(self.record,"001") - + self.lang = wash_language(ln) self.search_pattern = search_pattern self.recID = recID self.uid = uid self.format = format - + self.req = req + def get_record(self): """ Returns the record of this BibFormatObject instance @return the record structure as returned by BibRecord """ # Create record if necessary if self.record is None: # on-the-fly creation if current output is xm record = create_record(record_get_xml(self.recID, 'xm', on_the_fly=(self.format.lower() == 'xm'))) self.record = record[0] return self.record - + def control_field(self, tag, escape=0): """ Returns the value of control field given by tag in record - + @param tag the marc code of a field @param escape 1 if returned value should be escaped. Else 0. @return value of field tag in record """ if self.get_record() is None: #Case where BibRecord could not parse object return '' - + p_tag = parse_tag(tag) field_value = record_get_field_value(self.get_record(), p_tag[0], p_tag[1], p_tag[2], p_tag[3]) if escape == 0: return field_value else: return escape_field(field_value, escape) - + def field(self, tag, escape=0): """ Returns the value of the field corresponding to tag in the current record. If the value does not exist, return empty string 'escape' parameter allows to escape special characters of the field. The value of escape can be: 0 - no escaping 1 - escape all HTML characters 2 - escape all HTML characters by default. If field starts with , escape only unsafe characters, but leave basic HTML tags. @param tag the marc code of a field @param escape 1 if returned value should be escaped. Else 0. (see above for other modes) @return value of field tag in record """ list_of_fields = self.fields(tag) if len(list_of_fields) > 0: # Escaping below if escape == 0: return list_of_fields[0] else: return escape_field(list_of_fields[0], escape) else: return "" def fields(self, tag, escape=0): """ Returns the list of values corresonding to "tag". If tag has an undefined subcode (such as 999C5), the function returns a list of dictionaries, whoose keys are the subcodes and the values are the values of tag.subcode. If the tag has a subcode, simply returns list of values corresponding to tag. 'escape' parameter allows to escape special characters of the fields. The value of escape can be: 0 - no escaping 1 - escape all HTML characters 2 - escape all HTML characters by default. If field starts with , escape only unsafe characters, but leave basic HTML tags. - + @param tag the marc code of a field @param escape 1 if returned values should be escaped. Else 0. @return values of field tag in record """ if self.get_record() is None: # Case where BibRecord could not parse object return [] - + p_tag = parse_tag(tag) if p_tag[3] != "": # Subcode has been defined. Simply returns list of values values = record_get_field_values(self.get_record(), p_tag[0], p_tag[1], p_tag[2], p_tag[3]) if escape == 0: return values else: return [escape_field(value, escape) for value in values] else: # Subcode is undefined. Returns list of dicts. # However it might be the case of a control field. instances = record_get_field_instances(self.get_record(), p_tag[0], p_tag[1], p_tag[2]) if escape == 0: return [dict(instance[0]) for instance in instances] else: return [dict([ (subfield[0], escape_field(subfield[1], escape)) \ for subfield in instance[0] ]) \ for instance in instances] def kb(self, kb, string, default=""): """ Returns the value of the "string" in the knowledge base "kb". - + If kb does not exist or string does not exist in kb, returns 'default' string or empty string if not specified. @param kb a knowledge base name @param string the string we want to translate @param default a default value returned if 'string' not found in 'kb' """ if string is None: return default - + val = get_kb_mapping(kb, string, default) if val is None: return default else: return val def escape_field(value, mode=0): """ Utility function used to escape the value of a field in given mode. - mode 0: no escaping - mode 1: escaping all HTML/XML characters - mode 2: escaping dangerous HTML tags to avoid XSS, but keep basic one (such as
) - mode 3: mix of mode 1 and mode 2. If field_value starts with , then use mode 2. Else use mode 1. """ if mode == 1: return cgi.escape(value) elif mode == 2: return washer.wash(value, allowed_attribute_whitelist=['href', 'name', 'class'] ) elif mode == 3: if value.lstrip(' \n').startswith(html_field): return washer.wash(value, allowed_attribute_whitelist=['href', 'name', 'class'] ) else: return cgi.escape(value) else: return value def bf_profile(): """ Runs a benchmark """ for i in range(1, 51): format_record(i, "HD", ln=cdslang, verbose=9, search_pattern=[]) - return + return -if __name__ == "__main__": +if __name__ == "__main__": import profile import pstats #bf_profile() profile.run('bf_profile()', "bibformat_profile") p = pstats.Stats("bibformat_profile") p.strip_dirs().sort_stats("cumulative").print_stats() diff --git a/modules/bibformat/lib/bibformatadminlib.py b/modules/bibformat/lib/bibformatadminlib.py index d82ce4d91..faf051030 100644 --- a/modules/bibformat/lib/bibformatadminlib.py +++ b/modules/bibformat/lib/bibformatadminlib.py @@ -1,1597 +1,1598 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """ Handle requests from the web interface to configure BibFormat. """ __revision__ = "$Id$" import os import re import stat import time import cgi from invenio.config import cdslang, weburl, etcdir from invenio.bibformat_config import \ CFG_BIBFORMAT_TEMPLATES_PATH, \ CFG_BIBFORMAT_OUTPUTS_PATH, \ CFG_BIBFORMAT_ELEMENTS_PATH, \ CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION from invenio.urlutils import wash_url_argument from invenio.errorlib import get_msgs_for_code_list from invenio.messages import gettext_set_language, wash_language, language_list_long from invenio.search_engine import perform_request_search, encode_for_xml from invenio import bibformat_dblayer from invenio import bibformat_engine import invenio.template bibformat_templates = invenio.template.load('bibformat') def getnavtrail(previous = '', ln=cdslang): """Get the navtrail""" previous = wash_url_argument(previous, 'str') ln = wash_language(ln) _ = gettext_set_language(ln) navtrail = '''%s > %s ''' % (weburl, ln, _("Admin Area"), weburl, ln, _("BibFormat Admin")) navtrail = navtrail + previous return navtrail def perform_request_index(ln=cdslang, warnings=None, is_admin=False): """ Returns the main BibFormat admin page. - + This is the only page where the code needs to be cleaned when the migration kit will be removed. #TODO: remove when removing migration_kit - + @param ln language @param warnings a list of messages to display at top of the page, that prevents writability in etc @param is_admin indicate if user is authorized to use BibFormat @return the main admin page """ if warnings is not None and len(warnings) > 0: warnings = get_msgs_for_code_list(warnings, 'warning', ln) warnings = [x[1] for x in warnings] # Get only message, not code return bibformat_templates.tmpl_admin_index(ln, warnings, is_admin) def perform_request_format_templates_management(ln=cdslang, checking=0): """ Returns the main management console for format templates - + @param ln language @param checking the level of checking (0: basic, 1:extensive (time consuming) ) @return the main page for format templates management """ - + # Reload in case a format was changed bibformat_engine.clear_caches() - + # Get formats lists of attributes formats = bibformat_engine.get_format_templates(with_attributes=True) formats_attrs = [] for filename in formats: attrs = formats[filename]['attrs'] attrs['filename'] = filename if filename.endswith('.xsl'): attrs['name'] += ' (XSL)' attrs['editable'] = can_write_format_template(filename) path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename attrs['last_mod_date'] = time.ctime(os.stat(path)[stat.ST_MTIME]) status = check_format_template(filename, checking) if len(status) > 1 or (len(status)==1 and status[0][0] != 'ERR_BIBFORMAT_CANNOT_READ_TEMPLATE_FILE'): status = ''' Not OK ''' % {'weburl':weburl, 'ln':ln, 'bft':filename} else: status = 'OK' attrs['status'] = status formats_attrs.append(attrs) - + def sort_by_attr(seq): """ Sort 'seq' by attribute name. @param seq a list of dictionaries, containing each one key named 'name' """ intermed = [ (x['name'].lower(), i, x) for i, x in enumerate(seq)] intermed.sort() return [x[-1] for x in intermed] - + sorted_format_templates = sort_by_attr(formats_attrs) - + return bibformat_templates.tmpl_admin_format_templates_management(ln, sorted_format_templates) def perform_request_format_template_show(bft, ln=cdslang, code=None, ln_for_preview=cdslang, pattern_for_preview="", content_type_for_preview="text/html"): """ Returns the editor for format templates. @param ln language @param bft the template to edit @param code, the code being edited @param ln_for_preview the language for the preview (for bfo) @param pattern_for_preview the search pattern to be used for the preview (for bfo) @return the main page for formats management """ format_template = bibformat_engine.get_format_template(filename=bft, with_attributes=True) # Either use code being edited, or the original code inside template if code is None: code = cgi.escape(format_template['code']) - + # Build a default pattern if it is empty if pattern_for_preview == "": recIDs = perform_request_search() if len(recIDs) > 0: recID = recIDs[0] pattern_for_preview = "recid:%s" % recID editable = can_write_format_template(bft) # Look for all existing content_types content_types = bibformat_dblayer.get_existing_content_types() - + return bibformat_templates.tmpl_admin_format_template_show(ln, format_template['attrs']['name'], format_template['attrs']['description'], code, bft, ln_for_preview=ln_for_preview, pattern_for_preview=pattern_for_preview, editable=editable, content_type_for_preview=content_type_for_preview, content_types=content_types) def perform_request_format_template_show_dependencies(bft, ln=cdslang): """ Show the dependencies (on elements) of the given format. - + @param ln language @param bft the filename of the template to show """ format_template = bibformat_engine.get_format_template(filename=bft, with_attributes=True) name = format_template['attrs']['name'] output_formats = get_outputs_that_use_template(bft) format_elements = get_elements_used_by_template(bft) tags = [] for output_format in output_formats: for tag in output_format['tags']: tags.append(tag) for format_element in format_elements: for tag in format_element['tags']: - tags.append(tag) + tags.append(tag) tags.sort() return bibformat_templates.tmpl_admin_format_template_show_dependencies(ln, name, bft, output_formats, format_elements, tags) - + def perform_request_format_template_show_attributes(bft, ln=cdslang, new=False): """ Page for template name and descrition attributes edition. - - If format template is new, offer the possibility to + + If format template is new, offer the possibility to make a duplicate of an existing format template. @param ln language @param bft the template to edit @param new if True, the template has just been added (is new) @return the main page for format templates attributes edition """ all_templates = [] if new: all_templates_attrs = bibformat_engine.get_format_templates(with_attributes=True) if all_templates_attrs.has_key(bft): # Sanity check. Should always be true at this stage del all_templates_attrs[bft] # Remove in order not to make a duplicate of self.. - + # Sort according to name, inspired from Python Cookbook def sort_by_name(seq, keys): """ - Sort the sequence 'seq' by 'keys' + Sort the sequence 'seq' by 'keys' """ intermed = [(x['attrs']['name'], keys[i], i, x) for i, x in enumerate(seq)] intermed.sort() return [(x[1], x[0]) for x in intermed] all_templates = sort_by_name(all_templates_attrs.values(), all_templates_attrs.keys()) #keys = all_templates_attrs.keys() #keys.sort() - #all_templates = map(lambda x: (x, all_templates_attrs.get(x)['attrs']['name']), keys) + #all_templates = map(lambda x: (x, all_templates_attrs.get(x)['attrs']['name']), keys) format_template = bibformat_engine.get_format_template(filename=bft, with_attributes=True) name = format_template['attrs']['name'] description = format_template['attrs']['description'] editable = can_write_format_template(bft) - + return bibformat_templates.tmpl_admin_format_template_show_attributes(ln, name, description, bft, editable, all_templates, new) - + def perform_request_format_template_show_short_doc(ln=cdslang, search_doc_pattern=""): """ Returns the format elements documentation to be included inside format templated editor. Keep only elements that have 'search_doc_pattern' text inside description, if pattern not empty @param ln language @param search_doc_pattern a search pattern that specified which elements to display @return a brief version of the format element documentation """ # Get format elements lists of attributes elements = bibformat_engine.get_format_elements(with_built_in_params=True) keys = elements.keys() keys.sort() - elements = map(elements.get, keys) + elements = map(elements.get, keys) def filter_elem(element): """Keep element if is string representation contains all keywords of search_doc_pattern, and if its name does not start with a number (to remove 'garbage' from elements in tags table)""" if element['type'] != 'python' and \ element['attrs']['name'][0] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: return False text = str(element).upper() # Basic text representation if search_doc_pattern != "": for word in search_doc_pattern.split(): if word.upper() != "AND" and text.find(word.upper()) == -1: return False - + return True - + elements = filter(filter_elem, elements) - - + + return bibformat_templates.tmpl_admin_format_template_show_short_doc(ln, elements) def perform_request_format_elements_documentation(ln=cdslang): """ Returns the main management console for format elements. Includes list of format elements and associated administration tools. @param ln language @return the main page for format elements management """ # Get format elements lists of attributes elements = bibformat_engine.get_format_elements(with_built_in_params=True) - + keys = elements.keys() keys.sort() elements = map(elements.get, keys) # Remove all elements found in table and that begin with a number (to remove 'garbage') filtered_elements = [element for element in elements if element['type'] == 'python' or \ element['attrs']['name'][0] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']] - + return bibformat_templates.tmpl_admin_format_elements_documentation(ln, filtered_elements) def perform_request_format_element_show_dependencies(bfe, ln=cdslang): """ Show the dependencies of the given format. @param ln language @param bfe the filename of the format element to show """ format_templates = get_templates_that_use_element(bfe) tags = get_tags_used_by_element(bfe) - + return bibformat_templates.tmpl_admin_format_element_show_dependencies(ln, bfe, format_templates, tags) -def perform_request_format_element_test(bfe, ln=cdslang, param_values=None, uid=None): +def perform_request_format_element_test(bfe, ln=cdslang, param_values=None, uid=None, req=None): """ Show the dependencies of the given format. 'param_values' is the list of values to pass to 'format' function of the element as parameters, in the order ... If params is None, this means that they have not be defined by user yet. - + @param ln language @param bfe the name of the format element to show @param params the list of parameters to pass to element format function @param uid the user id for this request + @param req the mod_python request object """ _ = gettext_set_language(ln) format_element = bibformat_engine.get_format_element(bfe, with_built_in_params=True) # Load parameter names and description ## param_names = [] param_descriptions = [] - + # First value is a search pattern to choose the record param_names.append(_("Test with record:")) # Caution: keep in sync with same text below param_descriptions.append(_("Enter a search query here.")) - + # Parameters defined in this element for param in format_element['attrs']['params']: param_names.append(param['name']) param_descriptions.append(param['description']) # Parameters common to all elements of a kind for param in format_element['attrs']['builtin_params']: param_names.append(param['name']) param_descriptions.append(param['description']) - + # Load parameters values ## - + if param_values is None: #First time the page is loaded param_values = [] # Propose an existing record id by default recIDs = perform_request_search() if len(recIDs) > 0: recID = recIDs[0] param_values.append("recid:%s" % recID) - + # Default values defined in this element for param in format_element['attrs']['params']: param_values.append(param['default']) #Parameters common to all elements of a kind for param in format_element['attrs']['builtin_params']: param_values.append(param['default']) # Execute element with parameters ## params = dict(zip(param_names, param_values)) # Find a record corresponding to search pattern search_pattern = params[_("Test with record:")] # Caution keep in sync with same text above and below recIDs = perform_request_search(p=search_pattern) del params[_("Test with record:")] # Caution keep in sync with same text above - + if len(recIDs) > 0: - bfo = bibformat_engine.BibFormatObject(recIDs[0], ln, search_pattern, None, uid) + bfo = bibformat_engine.BibFormatObject(recIDs[0], ln, search_pattern, None, uid, req) (result, errors) = bibformat_engine.eval_format_element(format_element, bfo, params) else: result = get_msgs_for_code_list([("ERR_BIBFORMAT_NO_RECORD_FOUND_FOR_PATTERN", search_pattern)], stream='error', ln=cdslang)[0][1] return bibformat_templates.tmpl_admin_format_element_test(ln, bfe, format_element['attrs']['description'], param_names, param_values, param_descriptions, result) def perform_request_output_formats_management(ln=cdslang, sortby="code"): """ Returns the main management console for output formats. Includes list of output formats and associated administration tools. @param ln language @param sortby the sorting crieteria (can be 'code' or 'name') @return the main page for output formats management """ # Reload in case a format was changed bibformat_engine.clear_caches() - + # Get output formats lists of attributes output_formats_list = bibformat_engine.get_output_formats(with_attributes=True) output_formats = {} for filename in output_formats_list: output_format = output_formats_list[filename] code = output_format['attrs']['code'] path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename output_format['editable'] = can_write_output_format(code) output_format['last_mod_date'] = time.ctime(os.stat(path)[stat.ST_MTIME]) # Validate the output format status = check_output_format(code) # If there is an error but the error is just 'format is not writable', do not display as error if len(status) > 1 or (len(status)==1 and status[0][0] != 'ERR_BIBFORMAT_CANNOT_WRITE_OUTPUT_FILE'): status = ''' Not OK ''' % {'weburl':weburl, 'ln':ln, 'bfo':code} else: status = 'OK' output_format['status'] = status output_formats[filename] = output_format - + # Sort according to code or name, inspired from Python Cookbook def get_attr(dic, attr): """ Returns the value given by 'attr' in the dictionary 'dic', representing an output format attributes. If attr is equal to 'code', returns the code attribute of the dictionary. Else returns the generic name @param dic a dictionary of the attribute of an output format, as returned by bibformat_engine.get_output_format @param the attribute we want to fetch. Either 'code' or any other string """ if attr == "code": return dic['attrs']['code'] else: return dic['attrs']['names']['generic'] - + def sort_by_attr(seq, attr): """ Sort dictionaries given in 'seq' according to parameter 'attr' """ intermed = [ (get_attr(x, attr), i, x) for i, x in enumerate(seq)] intermed.sort() return [x[-1] for x in intermed] if sortby != "code" and sortby != "name": sortby = "code" - + sorted_output_formats = sort_by_attr(output_formats.values(), sortby) return bibformat_templates.tmpl_admin_output_formats_management(ln, sorted_output_formats) def perform_request_output_format_show(bfo, ln=cdslang, r_fld=[], r_val=[], r_tpl=[], default="", r_upd="", args={}): """ Returns the editing tools for a given output format. The page either shows the output format from file, or from user's POST session, as we want to let him edit the rules without saving. Policy is: r_fld, r_val, rules_tpl are list of attributes of the rules. If they are empty, load from file. Else use POST. The i th value of each list is one of the attributes of rule i. Rule i is the i th rule in order of evaluation. All list have the same number of item. r_upd contains an action that has to be performed on rules. It can composed of a number (i, the rule we want to modify) and an operator : "save" to save the rules, "add" or "del". syntax: operator [number] For eg: r_upd = _("Save Changes") saves all rules (no int should be specified). For eg: r_upd = _("Add New Rule") adds a rule (no int should be specified). For eg: r_upd = _("Remove Rule") + " 5" deletes rule at position 5. The number is used only for operation delete. An action can also be in **args. We must look there for string starting with '(+|-) [number]' to increase (+) or decrease (-) a rule given by its index (number). For example "+ 5" increase priority of rule 5 (put it at fourth position). The string in **args can be followed by some garbage that looks like .x or .y, as this is returned as the coordinate of the click on the . We HAVE to use args and reason on its keys, because for of type image, iexplorer does not return the value of the tag, but only the name. Action is executed only if we are working from user's POST session (means we must have loaded the output format first, which is totally normal and expected behaviour) IMPORTANT: we display rules evaluation index starting at 1 in interface, but we start internally at 0 - + @param ln language @param bfo the filename of the output format to show @param r_fld the list of 'field' attribute for each rule @param r_val the list of 'value' attribute for each rule @param r_tpl the list of 'template' attribute for each rule @param default the default format template used by this output format @param r_upd the rule that we want to increase/decrease in order of evaluation """ - output_format = bibformat_engine.get_output_format(bfo, with_attributes=True) + output_format = bibformat_engine.get_output_format(bfo, with_attributes=True) format_templates = bibformat_engine.get_format_templates(with_attributes=True) name = output_format['attrs']['names']['generic'] rules = [] debug = "" if len(r_fld) == 0 and r_upd=="": # Retrieve rules from file rules = output_format['rules'] default = output_format['default'] else: # Retrieve rules from given lists # Transform a single rule (not considered as a list with length # 1 by the templating system) into a list if not isinstance(r_fld, list): r_fld = [r_fld] r_val = [r_val] r_tpl = [r_tpl] - + for i in range(len(r_fld)): rule = {'field': r_fld[i], 'value': r_val[i], 'template': r_tpl[i]} rules.append(rule) # Execute action _ = gettext_set_language(ln) if r_upd.startswith(_("Remove Rule")): # Remove rule - index = int(r_upd.split(" ")[-1]) -1 + index = int(r_upd.split(" ")[-1]) -1 del rules[index] elif r_upd.startswith(_("Save Changes")): # Save update_output_format_rules(bfo, rules, default) elif r_upd.startswith(_("Add New Rule")): # Add new rule rule = {'field': "", 'value': "", 'template': ""} rules.append(rule) else: # Get the action in 'args' # The action must be constructed from string of the kind: # + 5 or - 4 or + 5.x or -4.y for button_val in args.keys():#for all elements of form not handled yet action = button_val.split(" ") if action[0] == '-' or action[0] == '+': index = int(action[1].split(".")[0]) -1 if action[0] == '-': # Decrease priority rule = rules[index] del rules[index] rules.insert(index + 1, rule) # debug = 'Decrease rule '+ str(index) break elif action[0] == '+': # Increase priority rule = rules[index] del rules[index] rules.insert(index - 1, rule) # debug = 'Increase rule ' + str(index) break editable = can_write_output_format(bfo) return bibformat_templates.tmpl_admin_output_format_show(ln, bfo, name, rules, default, format_templates, editable) def perform_request_output_format_show_dependencies(bfo, ln=cdslang): """ Show the dependencies of the given format. - + @param ln language @param bfo the filename of the output format to show """ output_format = bibformat_engine.get_output_format(code=bfo, with_attributes=True) name = output_format['attrs']['names']['generic'] format_templates = get_templates_used_by_output(bfo) - + return bibformat_templates.tmpl_admin_output_format_show_dependencies(ln, name, bfo, format_templates) - + def perform_request_output_format_show_attributes(bfo, ln=cdslang): """ Page for output format names and description attributes edition. - + @param ln language @param bfo filename of output format to edit @return the main page for output format attributes edition """ output_format = bibformat_engine.get_output_format(code=bfo, with_attributes=True) name = output_format['attrs']['names']['generic'] description = output_format['attrs']['description'] content_type = output_format['attrs']['content_type'] # Get translated names. Limit to long names now. # Translation are given in order of languages in language_list_long() names_trans = [] for lang in language_list_long(): name_trans = output_format['attrs']['names']['ln'].get(lang[0], "") names_trans.append({'lang':lang[1], 'trans':name_trans}) editable = can_write_output_format(bfo) - + return bibformat_templates.tmpl_admin_output_format_show_attributes(ln, name, description, content_type, bfo, names_trans, editable) def perform_request_knowledge_bases_management(ln=cdslang): """ Returns the main page for knowledge bases management. - + @param ln language @return the main page for knowledge bases management """ kbs = bibformat_dblayer.get_kbs() - + return bibformat_templates.tmpl_admin_kbs_management(ln, kbs) def perform_request_knowledge_base_show(kb_id, ln=cdslang, sortby="to"): """ Show the content of a knowledge base - + @param ln language @param kb a knowledge base id @param sortby the sorting criteria ('from' or 'to') @return the content of the given knowledge base """ name = bibformat_dblayer.get_kb_name(kb_id) mappings = bibformat_dblayer.get_kb_mappings(name, sortby) - + return bibformat_templates.tmpl_admin_kb_show(ln, kb_id, name, mappings, sortby) def perform_request_knowledge_base_show_attributes(kb_id, ln=cdslang, sortby="to"): """ Show the attributes of a knowledge base - + @param ln language @param kb a knowledge base id @param sortby the sorting criteria ('from' or 'to') @return the content of the given knowledge base """ name = bibformat_dblayer.get_kb_name(kb_id) description = bibformat_dblayer.get_kb_description(name) - + return bibformat_templates.tmpl_admin_kb_show_attributes(ln, kb_id, name, description, sortby) def perform_request_knowledge_base_show_dependencies(kb_id, ln=cdslang, sortby="to"): """ Show the dependencies of a kb - + @param ln language @param kb a knowledge base id @param sortby the sorting criteria ('from' or 'to') @return the dependencies of the given knowledge base """ name = bibformat_dblayer.get_kb_name(kb_id) format_elements = get_elements_that_use_kb(name) - + return bibformat_templates.tmpl_admin_kb_show_dependencies(ln, kb_id, name, sortby, format_elements) def add_format_template(): """ Adds a new format template (mainly create file with unique name) @return the filename of the created format """ (filename, name) = bibformat_engine.get_fresh_format_template_filename("Untitled") - + out = '%(name)s' % {'name':name} path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename format = open(path, 'w') format.write(out) format.close return filename def delete_format_template(filename): """ Delete a format template given by its filename If format template is not writable, do not remove @param filename the format template filename """ if not can_write_format_template(filename): return - + path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename os.remove(path) bibformat_engine.clear_caches() - + def update_format_template_code(filename, code=""): """ Saves code inside template given by filename """ format_template = bibformat_engine.get_format_template_attrs(filename) name = format_template['name'] description = format_template['description'] - + out = ''' %(name)s %(description)s %(code)s ''' % {'name':name, 'description':description, 'code':code} path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename format = open(path, 'w') format.write(out) format.close - + bibformat_engine.clear_caches() - + def update_format_template_attributes(filename, name="", description="", duplicate=None): """ Saves name and description inside template given by filename. the filename must change according to name, and every output format having reference to filename must be updated. If name already exist, use fresh filename (we never overwrite other templates) amd remove old one. if duplicate is different from None and is not empty string, then it means that we must copy the code of the template whoose filename is given in 'duplicate' for the code of our template. @param duplicate the filename of a template that we want to copy @return the filename of the modified format """ if filename.endswith('.'+CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION): format_template = bibformat_engine.get_format_template(filename, with_attributes=True) if duplicate is not None and duplicate != "": format_template_to_copy = bibformat_engine.get_format_template(duplicate) code = format_template_to_copy['code'] else: code = format_template['code'] if format_template['attrs']['name'] != name: # Name has changed, so update filename old_filename = filename old_path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + old_filename # Remove old one os.remove(old_path) (filename, name) = bibformat_engine.get_fresh_format_template_filename(name) # Change output formats that calls this template output_formats = bibformat_engine.get_output_formats() for output_format_filename in output_formats: if can_read_output_format(output_format_filename) and can_write_output_format(output_format_filename): output_path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + output_format_filename format = open(output_path, 'r') output_text = format.read() format.close output_pattern = re.compile("---(\s)*" + old_filename, re.IGNORECASE) mod_output_text = output_pattern.sub("--- " + filename, output_text) if output_text != mod_output_text: format = open(output_path, 'w') format.write(mod_output_text) format.close - + description = cgi.escape(description) name = cgi.escape(name) # Write updated format template out = '''%(name)s%(description)s%(code)s''' % {'name':name, 'description':description, 'code':code} path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename format = open(path, 'w') format.write(out) format.close bibformat_engine.clear_caches() return filename def add_output_format(): """ Adds a new output format (mainly create file with unique name) @return the code of the created format """ (filename, code) = bibformat_engine.get_fresh_output_format_filename("UNTLD") - + # Add entry in database bibformat_dblayer.add_output_format(code) bibformat_dblayer.set_output_format_name(code, "Untitled", lang="generic") bibformat_dblayer.set_output_format_content_type(code, "text/html") - - # Add file + + # Add file out = "" path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename format = open(path, 'w') format.write(out) format.close return code def delete_output_format(code): """ Delete a format template given by its code if file is not writable, don't remove @param code the 6 letters code of the output format to remove """ if not can_write_output_format(code): return - + # Remove entry from database bibformat_dblayer.remove_output_format(code) # Remove file filename = bibformat_engine.resolve_output_format_filename(code) path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename os.remove(path) bibformat_engine.clear_caches() - - + + def update_output_format_rules(code, rules=[], default=""): """ Saves rules inside output format given by code """ # Generate output format syntax # Try to group rules by field previous_field = "" out = "" for rule in rules: field = rule["field"] value = rule["value"] template = rule["template"] if previous_field != field: out += "tag %s:\n" % field out +="%(value)s --- %(template)s\n" % {'value':value, 'template':template} previous_field = field out += "default: %s" % default filename = bibformat_engine.resolve_output_format_filename(code) path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename format = open(path, 'w') format.write(out) format.close bibformat_engine.clear_caches() def update_output_format_attributes(code, name="", description="", new_code="", content_type="", names_trans=[]): """ Saves name and description inside output format given by filename. If new_code already exist, use fresh code (we never overwrite other output). @param description the new description @param name the new name @param code the new short code (== new bfo) of the output format @param code the code of the output format to update @param names_trans the translations in the same order as the languages from get_languages() @param content_type the new content_type of the output format @return the filename of the modified format """ - + bibformat_dblayer.set_output_format_description(code, description) bibformat_dblayer.set_output_format_content_type(code, content_type) bibformat_dblayer.set_output_format_name(code, name, lang="generic") i = 0 for lang in language_list_long(): if names_trans[i] != "": bibformat_dblayer.set_output_format_name(code, names_trans[i], lang[0]) i += 1 new_code = new_code.upper() if code != new_code: # If code has changed, we must update filename with a new unique code old_filename = bibformat_engine.resolve_output_format_filename(code) old_path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + old_filename (new_filename, new_code) = bibformat_engine.get_fresh_output_format_filename(new_code) new_path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + new_filename os.rename(old_path, new_path) - bibformat_dblayer.change_output_format_code(code, new_code) - + bibformat_dblayer.change_output_format_code(code, new_code) + bibformat_engine.clear_caches() return new_code - + def add_kb_mapping(kb_name, key, value=""): """ Adds a new mapping to given kb @param kb_name the name of the kb where to insert the new value @param key the key of the mapping @param value the value of the mapping """ bibformat_dblayer.add_kb_mapping(kb_name, key, value) def remove_kb_mapping(kb_name, key): """ Delete an existing kb mapping in kb - + @param kb_name the name of the kb where to insert the new value @param key the key of the mapping """ bibformat_dblayer.remove_kb_mapping(kb_name, key) def update_kb_mapping(kb_name, old_key, key, value): """ Update an existing kb mapping with key old_key with a new key and value - + @param kb_name the name of the kb where to insert the new value @param the key of the mapping in the kb @param key the new key of the mapping @param value the new value of the mapping """ bibformat_dblayer.update_kb_mapping(kb_name, old_key, key, value) def kb_exists(kb_name): """Returns True if a kb with the given name exists""" return bibformat_dblayer.kb_exists(kb_name) def get_kb_name(kb_id): """ Returns the name of the kb given by id """ return bibformat_dblayer.get_kb_name(kb_id) def update_kb_attributes(kb_name, new_name, new_description): """ Updates given kb_name with a new name and new description @param kb_name the name of the kb to update @param new_name the new name for the kb @param new_description the new description for the kb """ bibformat_dblayer.update_kb(kb_name, new_name, new_description) def add_kb(kb_name="Untitled"): """ Adds a new kb in database, and returns its id The name of the kb will be 'Untitled#' such that it is unique. @param kb_name the name of the kb @return the id of the newly created kb """ name = kb_name i = 1 while bibformat_dblayer.kb_exists(name): name = kb_name + " " + str(i) i += 1 - + kb_id = bibformat_dblayer.add_kb(name, "") return kb_id def delete_kb(kb_name): """ Deletes given kb from database """ bibformat_dblayer.delete_kb(kb_name) def can_read_format_template(filename): """ Returns 0 if we have read permission on given format template, else returns other integer """ path = "%s%s%s" % (CFG_BIBFORMAT_TEMPLATES_PATH, os.sep, filename) return os.access(path, os.R_OK) - + def can_read_output_format(bfo): """ Returns 0 if we have read permission on given output format, else returns other integer """ filename = bibformat_engine.resolve_output_format_filename(bfo) path = "%s%s%s" % (CFG_BIBFORMAT_OUTPUTS_PATH, os.sep, filename) return os.access(path, os.R_OK) - + def can_read_format_element(name): """ Returns 0 if we have read permission on given format element, else returns other integer """ filename = bibformat_engine.resolve_format_element_filename(name) path = "%s%s%s" % (CFG_BIBFORMAT_ELEMENTS_PATH, os.sep, filename) return os.access(path, os.R_OK) - + def can_write_format_template(bft): """ Returns 0 if we have write permission on given format template, else returns other integer """ if not can_read_format_template(bft): return False path = "%s%s%s" % (CFG_BIBFORMAT_TEMPLATES_PATH, os.sep, bft) return os.access(path, os.W_OK) def can_write_output_format(bfo): """ Returns 0 if we have write permission on given output format, else returns other integer """ if not can_read_output_format(bfo): return False - + filename = bibformat_engine.resolve_output_format_filename(bfo) path = "%s%s%s" % (CFG_BIBFORMAT_OUTPUTS_PATH, os.sep, filename) return os.access(path, os.W_OK) def can_write_etc_bibformat_dir(): """ Returns true if we can write in etc/bibformat dir. """ path = "%s%sbibformat" % (etcdir, os.sep) return os.access(path, os.W_OK) - + def get_outputs_that_use_template(filename): """ Returns a list of output formats that call the given format template. The returned output formats also give their dependencies on tags. - + We don't return the complete output formats but some reference to them (filename + names) [ {'filename':"filename_1.bfo" 'names': {'en':"a name", 'fr': "un nom", 'generic':"a name"} 'tags': ['710__a', '920__'] }, ... ] Returns output formats references sorted by (generic) name @param filename a format template filename """ output_formats_list = {} tags = [] output_formats = bibformat_engine.get_output_formats(with_attributes=True) for output_format in output_formats: name = output_formats[output_format]['attrs']['names']['generic'] # First look at default template, and add it if necessary if output_formats[output_format]['default'] == filename: output_formats_list[name] = {'filename':output_format, 'names':output_formats[output_format]['attrs']['names'], 'tags':[]} # Second look at each rule found = False for rule in output_formats[output_format]['rules']: if rule['template'] == filename: found = True tags.append(rule['field']) #Also build dependencies on tags # Finally add dependency on template from rule (overwrite default dependency, # which is weaker in term of tag) if found: output_formats_list[name] = {'filename':output_format, 'names':output_formats[output_format]['attrs']['names'], 'tags':tags} - + keys = output_formats_list.keys() keys.sort() - return map(output_formats_list.get, keys) + return map(output_formats_list.get, keys) def get_elements_used_by_template(filename): """ Returns a list of format elements that are called by the given format template. The returned elements also give their dependencies on tags. Dependencies on tag might be approximative. See get_tags_used_by_element() doc string. We must handle usage of bfe_field in a special way if we want to retrieve used tag: used tag is given in "tag" parameter, not inside element code. The list is returned sorted by name [ {'filename':"filename_1.py" 'name':"filename_1" 'tags': ['710__a', '920__'] }, ... ] Returns elements sorted by name @param filename a format template filename """ format_elements = {} format_template = bibformat_engine.get_format_template(filename=filename, with_attributes=True) code = format_template['code'] format_elements_iter = bibformat_engine.pattern_tag.finditer(code) for result in format_elements_iter: function_name = result.group("function_name").lower() if function_name is not None and not format_elements.has_key(function_name) \ and not function_name == "field": filename = bibformat_engine.resolve_format_element_filename("BFE_"+function_name) if filename is not None: tags = get_tags_used_by_element(filename) format_elements[function_name] = {'name':function_name.lower(), 'filename':filename, 'tags':tags} elif function_name == "field": # Handle bfe_field element in a special way if not format_elements.has_key(function_name): #Indicate usage of bfe_field if not already done filename = bibformat_engine.resolve_format_element_filename("BFE_"+function_name) format_elements[function_name] = {'name':function_name.lower(), 'filename':filename, 'tags':[]} # Retrieve value of parameter "tag" all_params = result.group('params') function_params_iterator = bibformat_engine.pattern_function_params.finditer(all_params) for param_match in function_params_iterator: name = param_match.group('param') if name == "tag": value = param_match.group('value') if not value in format_elements[function_name]['tags']: format_elements[function_name]['tags'].append(value) break keys = format_elements.keys() keys.sort() return map(format_elements.get, keys) # Format Elements Dependencies ## def get_tags_used_by_element(filename): """ Returns a list of tags used by given format element APPROXIMATIVE RESULTS: the tag are retrieved in field(), fields() and control_field() function. If they are used computed, or saved in a variable somewhere else, they are not retrieved @TODO: There is room for improvements. For example catch call to BibRecord functions. Returns tags sorted by value - - @param filename a format element filename + + @param filename a format element filename """ tags = {} format_element = bibformat_engine.get_format_element(filename) if format_element is None: return [] elif format_element['type']=="field": tags = format_element['attrs']['tags'] return tags - + filename = bibformat_engine.resolve_format_element_filename(filename) path = CFG_BIBFORMAT_ELEMENTS_PATH + os.sep + filename format = open(path, 'r') code = format.read() format.close tags_pattern = re.compile(''' (field|fields|control_field)\s* #Function call \(\s* #Opening parenthesis [\'"]+ #Single or double quote (?P.+?) #Tag [\'"]+\s* #Single or double quote (,[^\)]+)* #Additional function param \) #Closing parenthesis ''', re.VERBOSE | re.MULTILINE) - + tags_iter = tags_pattern.finditer(code) for result in tags_iter: tags[result.group("tag")] = result.group("tag") return tags.values() def get_templates_that_use_element(name): """ Returns a list of format templates that call the given format element. The returned format templates also give their dependencies on tags. [ {'filename':"filename_1.bft" 'name': "a name" 'tags': ['710__a', '920__'] }, ... ] Returns templates sorted by name - + @param name a format element name """ format_templates = {} tags = [] files = os.listdir(CFG_BIBFORMAT_TEMPLATES_PATH) #Retrieve all templates for possible_template in files: if possible_template.endswith(CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION): format_elements = get_elements_used_by_template(possible_template) #Look for elements used in template format_elements = map(lambda x: x['name'].lower(), format_elements) try: #Look for element format_elements.index(name.lower()) #If not found, get out of "try" statement - + format_template = bibformat_engine.get_format_template(filename=possible_template, with_attributes=True) template_name = format_template['attrs']['name'] format_templates[template_name] = {'name':template_name, 'filename':possible_template} except: print name+" not found in "+str(format_elements) pass - + keys = format_templates.keys() keys.sort() - return map(format_templates.get, keys) + return map(format_templates.get, keys) # Output Formats Dependencies ## def get_templates_used_by_output(code): """ Returns a list of templates used inside an output format give by its code The returned format templates also give their dependencies on elements and tags [ {'filename':"filename_1.bft" 'name': "a name" 'elements': [{'filename':"filename_1.py", 'name':"filename_1", 'tags': ['710__a', '920__'] }, ...] }, ... ] Returns templates sorted by name - + """ format_templates = {} output_format = bibformat_engine.get_output_format(code, with_attributes=True) filenames = map(lambda x: x['template'], output_format['rules']) if output_format['default'] != "": filenames.append(output_format['default']) - + for filename in filenames: template = bibformat_engine.get_format_template(filename, with_attributes=True) name = template['attrs']['name'] elements = get_elements_used_by_template(filename) format_templates[name] = {'name':name, 'filename':filename, 'elements':elements} keys = format_templates.keys() keys.sort() - return map(format_templates.get, keys) + return map(format_templates.get, keys) # Knowledge Bases Dependencies ## def get_elements_that_use_kb(name): """ Returns a list of elements that call given kb [ {'filename':"filename_1.py" 'name': "a name" }, ... ] - + Returns elements sorted by name """ format_elements = {} files = os.listdir(CFG_BIBFORMAT_ELEMENTS_PATH) #Retrieve all elements in files for filename in files: if filename.endswith(".py"): path = CFG_BIBFORMAT_ELEMENTS_PATH + os.sep + filename format = open(path, 'r') code = format.read() format.close # Search for use of kb inside code kb_pattern = re.compile(''' (bfo.kb)\s* #Function call \(\s* #Opening parenthesis [\'"]+ #Single or double quote (?P%s) #kb [\'"]+\s* #Single or double quote , #comma ''' % name, re.VERBOSE | re.MULTILINE | re.IGNORECASE) - + result = kb_pattern.search(code) if result is not None: name = ("".join(filename.split(".")[:-1])).lower() if name.startswith("bfe_"): name = name[4:] format_elements[name] = {'filename':filename, 'name': name} - - + + keys = format_elements.keys() keys.sort() - return map(format_elements.get, keys) + return map(format_elements.get, keys) # Validation tools ## def perform_request_format_validate(ln=cdslang, bfo=None, bft=None, bfe=None): """ Returns a page showing the status of an output format or format template or format element. This page is called from output formats management page or format template management page or format elements documentation. The page only shows the status of one of the format, depending on the specified one. If multiple are specified, shows the first one. @param ln language @param bfo an output format 6 chars code @param bft a format element filename @param bfe a format element name """ if bfo is not None: errors = check_output_format(bfo) messages = get_msgs_for_code_list(code_list = errors, ln=ln) elif bft is not None: errors = check_format_template(bft, checking=1) messages = get_msgs_for_code_list(code_list = errors, ln=ln) elif bfe is not None: errors = check_format_element(bfe) messages = get_msgs_for_code_list(code_list = errors, ln=ln) if messages is None: messages = [] messages = map(lambda x: encode_for_xml(x[1]), messages) - + return bibformat_templates.tmpl_admin_validate_format(ln, messages) - - + + def check_output_format(code): """ Returns the list of errors in the output format given by code The errors are the formatted errors defined in bibformat_config.py file. @param code the 6 chars code of the output format to check @return a list of errors """ errors = [] filename = bibformat_engine.resolve_output_format_filename(code) if can_read_output_format(code): path = CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename format = open(path) current_tag = '' i = 0 for line in format: i += 1 if line.strip() == "": # Ignore blank lines continue clean_line = line.rstrip("\n\r ") #remove spaces and eol if line.strip().endswith(":") or (line.strip().lower().startswith("tag") and line.find('---') == -1): # Check tag if not clean_line.endswith(":"): - # Column misses at the end of line + # Column misses at the end of line errors.append(("ERR_BIBFORMAT_OUTPUT_RULE_FIELD_COL", line, i)) if not clean_line.lower().startswith("tag"): # Tag keyword is missing errors.append(("ERR_BIBFORMAT_OUTPUT_TAG_MISSING", line, i)) elif not clean_line.startswith("tag"): # Tag was not lower case errors.append(("ERR_BIBFORMAT_OUTPUT_WRONG_TAG_CASE", line, i)) - + clean_line = clean_line.rstrip(": ") #remove : and spaces at the end of line - + current_tag = "".join(clean_line.split()[1:]).strip() #the tag starts at second position if len(clean_line.split()) > 2: #We should only have 'tag' keyword and tag - errors.append(("ERR_BIBFORMAT_INVALID_OUTPUT_RULE_FIELD", i)) + errors.append(("ERR_BIBFORMAT_INVALID_OUTPUT_RULE_FIELD", i)) else: if len(check_tag(current_tag)) > 0: # Invalid tag errors.append(("ERR_BIBFORMAT_INVALID_OUTPUT_RULE_FIELD_tag", current_tag, i)) if not clean_line.startswith("tag"): errors.append(("ERR_BIBFORMAT_INVALID_OUTPUT_RULE_FIELD", i)) elif line.find('---') != -1: # Check condition if current_tag == "": errors.append(("ERR_BIBFORMAT_OUTPUT_CONDITION_OUTSIDE_FIELD", line, i)) - + words = line.split('---') if len(words) != 2: errors.append(("ERR_BIBFORMAT_INVALID_OUTPUT_CONDITION", line, i)) template = words[-1].strip() path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + template if not os.path.exists(path): errors.append(("ERR_BIBFORMAT_WRONG_OUTPUT_RULE_TEMPLATE_REF", template, i)) - + elif line.find(':') != -1 or (line.strip().lower().startswith("default") and line.find('---') == -1): # Check default template clean_line = line.strip() if line.find(':') == -1: - # Column misses after default + # Column misses after default errors.append(("ERR_BIBFORMAT_OUTPUT_RULE_DEFAULT_COL", line, i)) if not clean_line.startswith("default"): # Default keyword is missing errors.append(("ERR_BIBFORMAT_OUTPUT_DEFAULT_MISSING", line, i)) if not clean_line.startswith("default"): # Default was not lower case errors.append(("ERR_BIBFORMAT_OUTPUT_WRONG_DEFAULT_CASE", line, i)) default = "".join(line.split(':')[1]).strip() path = CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + default if not os.path.exists(path): errors.append(("ERR_BIBFORMAT_WRONG_OUTPUT_RULE_TEMPLATE_REF", default, i)) - + else: # Check others errors.append(("ERR_BIBFORMAT_WRONG_OUTPUT_LINE", line, i)) else: errors.append(("ERR_BIBFORMAT_CANNOT_READ_OUTPUT_FILE", filename, "")) - + return errors def check_format_template(filename, checking=0): """ Returns the list of errors in the format template given by its filename The errors are the formatted errors defined in bibformat_config.py file. @param filename the filename of the format template to check @param checking the level of checking (0:basic, >=1 extensive (time-consuming)) @return a list of errors """ errors = [] if can_read_format_template(filename):#Can template be read? if filename.endswith('.'+CFG_BIBFORMAT_FORMAT_TEMPLATE_EXTENSION): #format_template = bibformat_engine.get_format_template(filename, with_attributes=True) format = open("%s%s%s" % (CFG_BIBFORMAT_TEMPLATES_PATH, os.sep, filename)) code = format.read() format.close() # Look for name match = bibformat_engine.pattern_format_template_name.search(code) if match is None:#Is tag defined in template? errors.append(("ERR_BIBFORMAT_TEMPLATE_HAS_NO_NAME", filename)) # Look for description match = bibformat_engine.pattern_format_template_desc.search(code) if match is None:#Is tag defined in template? errors.append(("ERR_BIBFORMAT_TEMPLATE_HAS_NO_DESCRIPTION", filename)) format_template = bibformat_engine.get_format_template(filename, with_attributes=False) code = format_template['code'] # Look for calls to format elements # Check existence of elements and attributes used in call elements_call = bibformat_engine.pattern_tag.finditer(code) for element_match in elements_call: element_name = element_match.group("function_name") filename = bibformat_engine.resolve_format_element_filename(element_name) if filename is None and not bibformat_dblayer.tag_exists_for_name(element_name): #Is element defined? errors.append(("ERR_BIBFORMAT_TEMPLATE_CALLS_UNDEFINED_ELEM", filename, element_name)) else: format_element = bibformat_engine.get_format_element(element_name, with_built_in_params=True) if format_element is None:#Can element be loaded? if not can_read_format_element(element_name): errors.append(("ERR_BIBFORMAT_TEMPLATE_CALLS_UNREADABLE_ELEM", filename, element_name)) else: errors.append(("ERR_BIBFORMAT_TEMPLATE_CALLS_UNLOADABLE_ELEM", element_name, filename)) else: # Are the parameters used defined in element? params_call = bibformat_engine.pattern_function_params.finditer(element_match.group()) all_params = {} for param_match in params_call: param = param_match.group("param") value = param_match.group("value") all_params[param] = value allowed_params = [] # Built-in params for allowed_param in format_element['attrs']['builtin_params']: allowed_params.append(allowed_param['name']) # Params defined in element for allowed_param in format_element['attrs']['params']: allowed_params.append(allowed_param['name']) if not param in allowed_params: errors.append(("ERR_BIBFORMAT_TEMPLATE_WRONG_ELEM_ARG", element_name, param, filename)) # The following code is too much time consuming. Only do where really requested if checking > 0: # Try to evaluate, with any object and pattern recIDs = perform_request_search() if len(recIDs) > 0: recID = recIDs[0] bfo = bibformat_engine.BibFormatObject(recID, search_pattern="Test") (result, errors_) = bibformat_engine.eval_format_element(format_element, bfo, all_params, verbose=7) errors.extend(errors_) - + else:# Template cannot be read errors.append(("ERR_BIBFORMAT_CANNOT_READ_TEMPLATE_FILE", filename, "")) return errors def check_format_element(name): """ Returns the list of errors in the format element given by its name The errors are the formatted errors defined in bibformat_config.py file. @param name the name of the format element to check @return a list of errors """ errors = [] filename = bibformat_engine.resolve_format_element_filename(name) if filename is not None:#Can element be found in files? if can_read_format_element(name):#Can element be read? # Try to load try: module_name = filename if module_name.endswith(".py"): module_name = module_name[:-3] - + module = __import__("invenio.bibformat_elements."+module_name) function_format = module.bibformat_elements.__dict__[module_name].format # Try to evaluate, with any object and pattern recIDs = perform_request_search() if len(recIDs) > 0: recID = recIDs[0] bfo = bibformat_engine.BibFormatObject(recID, search_pattern="Test") element = bibformat_engine.get_format_element(name) (result, errors_) = bibformat_engine.eval_format_element(element, bfo, verbose=7) errors.extend(errors_) except Exception, e: - errors.append(("ERR_BIBFORMAT_IN_FORMAT_ELEMENT", name, e)) + errors.append(("ERR_BIBFORMAT_IN_FORMAT_ELEMENT", name, e)) else: errors.append(("ERR_BIBFORMAT_CANNOT_READ_ELEMENT_FILE", filename, "")) elif bibformat_dblayer.tag_exists_for_name(name):#Can element be found in database? pass else: errors.append(("ERR_BIBFORMAT_CANNOT_RESOLVE_ELEMENT_NAME", name)) return errors def check_tag(tag): """ Checks the validity of a tag """ errors = [] return errors def perform_request_dreamweaver_floater(): """ Returns a floater for Dreamweaver with all Format Elements avalaible. """ # Get format elements lists of attributes elements = bibformat_engine.get_format_elements(with_built_in_params=True) keys = elements.keys() keys.sort() - elements = map(elements.get, keys) + elements = map(elements.get, keys) def filter_elem(element): """Keep element if is string representation contains all keywords of search_doc_pattern, and if its name does not start with a number (to remove 'garbage' from elements in tags table)""" if element['type'] != 'python' and \ element['attrs']['name'][0] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: return False else: return True - + elements = filter(filter_elem, elements) - - + + return bibformat_templates.tmpl_dreamweaver_floater(cdslang, elements) diff --git a/modules/bibformat/lib/elements/bfe_edit_record.py b/modules/bibformat/lib/elements/bfe_edit_record.py index 7a2ac7b58..9e00412d9 100644 --- a/modules/bibformat/lib/elements/bfe_edit_record.py +++ b/modules/bibformat/lib/elements/bfe_edit_record.py @@ -1,57 +1,62 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """BibFormat element - Prints a link to BibEdit """ __revision__ = "$Id$" def format(bfo, style): """ Prints a link to BibEdit, if authorization is granted @param style the CSS style to be applied to the link. """ from invenio.config import weburl from invenio.access_control_engine import acc_authorize_action - + out = "" - + uid = bfo.uid + req = bfo.rec if uid is not None: - (auth_code, auth_message) = acc_authorize_action(uid,'runbibedit') + if (req): + (auth_code, auth_message) = acc_authorize_action(req,'runbibedit') + else: + (auth_code, auth_message) = + acc_authorize_action(uid, 'runbibedit') if auth_code == 0: print_style = '' if style != '': print_style = 'style="' + style + '"' - + out += 'Edit This Record' - + return out def escape_values(bfo): """ Called by BibFormat in order to check if output of this element should be escaped. """ return 0 diff --git a/modules/bibformat/web/admin/bibformat_migration_kit_assistant.py b/modules/bibformat/web/admin/bibformat_migration_kit_assistant.py index 0fb47c52b..2ee18a840 100644 --- a/modules/bibformat/web/admin/bibformat_migration_kit_assistant.py +++ b/modules/bibformat/web/admin/bibformat_migration_kit_assistant.py @@ -1,189 +1,189 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """ Web based assistant for the migration old PHP BibFormat settings to new Python BibFormat configuration files """ __revision__ = "$Id$" __lastupdated__ = """$Date$""" from invenio.dbquery import Error from invenio.bibformat_migration_kit_assistant_lib import * from invenio.bibrankadminlib import check_user from invenio.webpage import page, create_error_box from invenio.config import weburl, cdslang, cdsname from invenio.webuser import getUid, page_not_authorized from invenio.urlutils import wash_url_argument, redirect_to_url from invenio.messages import wash_language, gettext_set_language def index(req, ln=cdslang): """ Shows status of migration and options to continue migration """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail() try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: return page(title=_("Migrate BibFormat Settings"), body=perform_request_migration_kit_status(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) - + def migrate_kb(req, ln=cdslang): """ Migrate kbs and tell users the result of migration """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail(' > Migration Kit'%weburl) try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: return page(title=_("Migrate Knowledge Bases"), body=perform_request_migration_kit_knowledge_bases(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def migrate_behaviours(req, ln=cdslang): """ Migrate behaviours and tell users the result of migration """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail(' > Migration Kit'%weburl) try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: return page(title=_("Migrate Behaviours"), body=perform_request_migration_kit_behaviours(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def migrate_formats(req, ln=cdslang): """ Shows the interface for migrating formats to format templates and format elements """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail(' > Migration Kit'%weburl) try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: return page(title=_("Migrate Formats"), body=perform_request_migration_kit_formats(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: - return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def migrate_formats_do(req, ln=cdslang): """ Migrate formats and tell user how migration went """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail(' > Migration Kit'%weburl) try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: return page(title=_("Migrate Formats"), body=perform_request_migration_kit_formats_do(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: - return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) diff --git a/modules/bibformat/web/admin/bibformatadmin.py b/modules/bibformat/web/admin/bibformatadmin.py index 5e32649c2..6345f64cf 100644 --- a/modules/bibformat/web/admin/bibformatadmin.py +++ b/modules/bibformat/web/admin/bibformatadmin.py @@ -1,1478 +1,1478 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio BibFormat Administrator Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" import MySQLdb from invenio import bibformatadminlib, \ config, \ bibformat_dblayer,\ bibformat_engine from invenio.bibrankadminlib import check_user from invenio.webpage import page, create_error_box from invenio.webuser import getUid, page_not_authorized from invenio.messages import wash_language, gettext_set_language from invenio.urlutils import wash_url_argument, redirect_to_url from invenio.search_engine import perform_request_search, \ create_basic_search_units def index(req, ln=config.cdslang): """ Main BibFormat administration page. Displays a warning if we find out that etc/biformat dir is not writable by us (as most opeation of BibFormat must write in this directory). @param ln: language """ warnings = [] #FIXME Remove when removing Migration Kit from invenio.bibformat_migration_kit_assistant_lib \ - import can_write_migration_status_file + import can_write_migration_status_file if not can_write_migration_status_file(): warnings.append(("WRN_BIBFORMAT_CANNOT_WRITE_MIGRATION_STATUS")) - + if not bibformatadminlib.can_write_etc_bibformat_dir(): warnings.append(("WRN_BIBFORMAT_CANNOT_WRITE_IN_ETC_BIBFORMAT")) - + ln = wash_language(ln) _ = gettext_set_language(ln) # Check if user is authorized to administer # If not, still display page but offer to log in try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: - is_admin = True + is_admin = True else: is_admin = False - + navtrail = '''%s''' % \ (config.weburl, ln, _("Admin Area")) - + return page(title=_("BibFormat Admin"), body=bibformatadminlib.perform_request_index(ln=ln, warnings=warnings, is_admin=is_admin), language=ln, uid=uid, navtrail = navtrail, lastupdated=__lastupdated__, req=req, warnings=warnings) def output_formats_manage(req, ln=config.cdslang, sortby="code"): """ Main page for output formats management. Check for authentication and print output formats list. @param ln language @param sortby the sorting crieteria (can be 'code' or 'name') """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail() try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: sortby = wash_url_argument(sortby, 'str') return page(title=_("Manage Output Formats"), body=bibformatadminlib.perform_request_output_formats_management(ln=ln, sortby=sortby), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) - + def output_format_show(req, bfo, ln=config.cdslang, r_fld=[], r_val=[], r_tpl=[], default="", r_upd="", chosen_option="", **args): """ Show a single output format. Check for authentication and print output format settings. The page either shows the output format from file, or from user's POST session, as we want to let him edit the rules without saving. Policy is: r_fld, r_val, rules_tpl are list of attributes of the rules. If they are empty, load from file. Else use POST. The i th value of each list is one of the attributes of rule i. Rule i is the i th rule in order of evaluation. All list have the same number of item. r_upd contains an action that has to be performed on rules. It can composed of a number (i, the rule we want to modify) and an operator : "save" to save the rules, "add" or "del". syntax: operator [number] For eg: r_upd = _("Save Changes") saves all rules (no int should be specified). For eg: r_upd = _("Add New Rule") adds a rule (no int should be specified). For eg: r_upd = _("Remove Rule") + " 5" deletes rule at position 5. The number is used only for operation delete. An action can also be in **args. We must look there for string starting with '(+|-) [number]' to increase (+) or decrease (-) a rule given by its index (number). For example "+ 5" increase priority of rule 5 (put it at fourth position). The string in **args can be followed by some garbage that looks like .x or .y, as this is returned as the coordinate of the click on the . We HAVE to use args and reason on its keys, because for of type image, iexplorer does not return the value of the tag, but only the name. Action is executed only if we are working from user's POST session (means we must have loaded the output format first, which is totally normal and expected behaviour) - - + + @param ln language @param bfo the filename of the output format to show @param r_fld the list of 'field' attribute for each rule @param r_val the list of 'value' attribute for each rule @param r_tpl the list of 'template' attribute for each rule @param default the default format template used by this output format @param r_upd the rule that we want to increase/decrease in order of evaluation """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Output Formats"))) code = wash_url_argument(bfo, 'str') - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bfo = wash_url_argument(bfo, 'str') default = wash_url_argument(default, 'str') r_upd = wash_url_argument(r_upd, 'str') if not bibformatadminlib.can_read_output_format(bfo): #No read permission return page(title=_("Restricted Output Format"), body = """You don't have permission to view this output format.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_OUTPUT_FILE", bfo , "")], lastupdated=__lastupdated__, req=req) - + output_format = bibformat_engine.get_output_format(code=bfo, with_attributes=True) name = output_format['attrs']['names']['generic'] if name == "": name = bfo - + if not bibformatadminlib.can_write_output_format(bfo) and \ chosen_option == "":#No write permission return dialog_box(req=req, ln=ln, title="File Permission on %s" % name, message="You don't have write permission" \ "on %s.
You can view the output " \ "format, but not edit it." % name, navtrail=navtrail_previous_links, options=[ _("Ok")]) return page(title=_('Output Format %s Rules' % name), body=bibformatadminlib.perform_request_output_format_show(bfo=bfo, ln=ln, r_fld=r_fld, r_val=r_val, r_tpl=r_tpl, default=default, r_upd=r_upd, args=args), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def output_format_show_attributes(req, bfo, ln=config.cdslang): """ Page for output format names and descrition attributes edition. - + @param ln language - @param bfo the filename of the template to show + @param bfo the filename of the template to show """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln , _("Manage Output Formats"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bfo = wash_url_argument(bfo, 'str') if not bibformatadminlib.can_read_output_format(bfo): #No read permission return page(title=_("Restricted Output Format"), body = """You don't have permission to view this output format.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_OUTPUT_FILE", bfo ,"")], lastupdated=__lastupdated__, req=req) - + output_format = bibformat_engine.get_output_format(code=bfo, with_attributes=True) name = output_format['attrs']['names']['generic'] - + return page(title=_("Output Format %s Attributes" % name), body=bibformatadminlib.perform_request_output_format_show_attributes(bfo, ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links , lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg) def output_format_show_dependencies(req, bfo, ln=config.cdslang): """ Show the dependencies of the given output format. - + @param ln language @param bfo the filename of the output format to show """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s ''' % (config.weburl, ln, _("Manage Output Formats"))) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bfo = wash_url_argument(bfo, 'str') if not bibformatadminlib.can_read_output_format(bfo): #No read permission return page(title=_("Restricted Output Format"), body = """You don't have permission to view this output format.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_OUTPUT_FILE", bfo , "")], lastupdated=__lastupdated__, req=req) - + format_name = bibformat_engine.get_output_format_attrs(bfo)['names']['generic'] return page(title=_("Output Format %s Dependencies" % format_name), body=bibformatadminlib.perform_request_output_format_show_dependencies(bfo, ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg) def output_format_update_attributes(req, bfo, ln=config.cdslang, name = "", description="", code="", content_type="", names_trans=[]): """ Update the name, description and code of given output format - + @param ln language @param description the new description @param name the new name @param code the new short code (== new bfo) of the output format @param content_type the new content_type of the output format @param bfo the filename of the output format to update @param names_trans the translations in the same order as the languages from get_languages() """ ln = wash_language(ln) _ = gettext_set_language(ln) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: name = wash_url_argument(name, 'str') description = wash_url_argument(description, 'str') bfo = wash_url_argument(bfo, 'str') code = wash_url_argument(code, 'str') bfo = bibformatadminlib.update_output_format_attributes(bfo, name, description, code, content_type, names_trans) - + redirect_to_url(req, "output_format_show?ln=%(ln)s&bfo=%(bfo)s" % {'ln':ln, 'bfo':bfo, 'names_trans':names_trans}) else: return page_not_authorized(req=req, text=auth_msg, chosen_option="") def output_format_delete(req, bfo, ln=config.cdslang, chosen_option=""): """ Delete an output format @param bfo the filename of the output format to delete """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s > %s''' % (config.weburl, ln, _("Manage Output Formats"), _("Delete Output Format"))) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: - + #Ask confirmation to user if not already done chosen_option = wash_url_argument(chosen_option, 'str') if chosen_option == "": bfo = wash_url_argument(bfo, 'str') format_name = bibformat_dblayer.get_output_format_names(bfo)['generic'] return dialog_box(req=req, ln=ln, title="Delete %s"%format_name, message="Are you sure you want to" \ "delete output format %s?" % format_name, navtrail=navtrail_previous_links, options=[_("Cancel"), _("Delete")]) - + elif chosen_option==_("Delete"): bibformatadminlib.delete_output_format(bfo) redirect_to_url(req, "output_formats_manage?ln=%(ln)s"%{'ln':ln}) else: return page_not_authorized(req=req, text=auth_msg) - + def output_format_add(req, ln=config.cdslang): """ Adds a new output format """ ln = wash_language(ln) _ = gettext_set_language(ln) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bfo = bibformatadminlib.add_output_format() redirect_to_url(req, "output_format_show_attributes?ln=%(ln)s&bfo=%(bfo)s" % {'ln':ln, 'bfo':bfo}) else: return page_not_authorized(req=req, text=auth_msg) def format_templates_manage(req, ln=config.cdslang, checking='0'): """ Main page for formats templates management. Check for authentication and print formats list. @param ln language @param checking if 0, basic checking. Else perform extensive checking (time-consuming) """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail() try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: checking_level = wash_url_argument(checking, 'int') return page(title=_("Manage Format Templates"), body=bibformatadminlib.perform_request_format_templates_management(ln=ln, checking=checking_level), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def format_template_show(req, bft, code=None, ln=config.cdslang, ln_for_preview=config.cdslang, pattern_for_preview="", content_type_for_preview="text/html", chosen_option=""): """ Main page for template edition. Check for authentication and print formats editor. - + @param ln language @param code the code being edited @param bft the name of the template to show @param ln_for_preview the language for the preview (for bfo) @param pattern_for_preview the search pattern to be used for the preview (for bfo) @param content_type_for_preview the (MIME) content type of the preview @param chosen_option returned value for dialog_box warning """ ln = wash_language(ln) _ = gettext_set_language(ln) - + navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln , _("Manage Format Templates"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: format_template = wash_url_argument(bft, 'str') ln_preview = wash_language(ln_for_preview) pattern_preview = wash_url_argument(pattern_for_preview, 'str') if not bibformatadminlib.can_read_format_template(bft): #No read permission return page(title=_("Restricted Format Template"), body = """You don't have permission to view this format template.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_TEMPLATE_FILE", format_template , "")], lastupdated=__lastupdated__, req=req) - + format_name = bibformat_engine.get_format_template_attrs(bft)['name'] if not bibformatadminlib.can_write_format_template(bft) and \ chosen_option == "": #No write permission return dialog_box(req=req, ln=ln, title="File Permission on %s" % format_name, message="You don't have write permission" \ "on %s.
You can view the template" \ ", but not edit it." % format_name, navtrail=navtrail_previous_links, options=[ _("Ok")]) - + if bft.endswith('.xsl'): format_name += ' (XSL)' return page(title=_("Format Template %s"%format_name), body=bibformatadminlib.perform_request_format_template_show(format_template, code=code, ln=ln, ln_for_preview=ln_preview, pattern_for_preview=pattern_preview, content_type_for_preview=content_type_for_preview), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def format_template_show_attributes(req, bft, ln=config.cdslang, new=0): """ Page for template name and descrition attributes edition. - + This is also the first page shown when a format template has just been added. In that case new is different from False and we can offer specific option to user (for ex let him make a duplicate of existing template). @param ln language - @param bft the name of the template to show + @param bft the name of the template to show @param new if "False", the template has not just been added """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Format Templates"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: format_template = wash_url_argument(bft, 'str') format_name = bibformat_engine.get_format_template_attrs(bft)['name'] is_new = wash_url_argument(new, 'int') if not bibformatadminlib.can_read_format_template(bft): #No read permission return page(title=_("Restricted Format Template"), body = """You don't have permission to view this format template.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_TEMPLATE_FILE", format_template , "")], lastupdated=__lastupdated__, req=req) - + return page(title=_("Format Template %s Attributes"%format_name), body=bibformatadminlib.perform_request_format_template_show_attributes(bft, ln=ln, new=is_new), uid=uid, language=ln, navtrail = navtrail_previous_links , lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg) def format_template_show_dependencies(req, bft, ln=config.cdslang): """ Show the dependencies (on elements) of the given format. - + @param ln language @param bft the filename of the template to show """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Format Templates"))) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: format_template = wash_url_argument(bft, 'str') format_name = bibformat_engine.get_format_template_attrs(bft)['name'] - + return page(title=_("Format Template %s Dependencies" % format_name), body=bibformatadminlib.perform_request_format_template_show_dependencies(bft, ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg) def format_template_update_attributes(req, bft, ln=config.cdslang, name = "", description="", duplicate=None): """ Update the name and description of given format template - + @param ln language @param description the new description @param name the new name @param bft the filename of the template to update @param duplicate the filename of template that we want to copy (the code) """ ln = wash_language(ln) _ = gettext_set_language(ln) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: if duplicate is not None: duplicate = wash_url_argument(duplicate, 'str') name = wash_url_argument(name, 'str') description = wash_url_argument(description, 'str') bft = bibformatadminlib.update_format_template_attributes(bft, name, description, duplicate) - + redirect_to_url(req, "format_template_show?ln=%(ln)s&bft=%(bft)s" % {'ln':ln, 'bft':bft}) else: return page_not_authorized(req=req, text=auth_msg) def format_template_delete(req, bft, ln=config.cdslang, chosen_option=""): """ Delete a format template """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s > %s''' % (config.weburl, ln ,_("Manage Format Templates"),_("Delete Format Template"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: #Ask confirmation to user if not already done chosen_option = wash_url_argument(chosen_option, 'str') if chosen_option == "": format_template = wash_url_argument(bft, 'str') format_name = bibformat_engine.get_format_template_attrs(bft)['name'] return dialog_box(req=req, ln=ln, title="Delete %s" % format_name, message="Are you sure you want to delete" \ "format template %s?" % format_name, navtrail=navtrail_previous_links, options=[_("Cancel"), _("Delete")]) - + elif chosen_option==_("Delete"): bibformatadminlib.delete_format_template(bft) - + redirect_to_url(req, "format_templates_manage?ln=%(ln)s" % {'ln':ln}) else: return page_not_authorized(req=req, text=auth_msg) - + def format_template_add(req, ln=config.cdslang): """ Adds a new format template """ ln = wash_language(ln) _ = gettext_set_language(ln) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bft = bibformatadminlib.add_format_template() redirect_to_url(req, "format_template_show_attributes?ln=%(ln)s&bft=%(bft)s&new=1" % {'ln':ln, 'bft':bft}) else: return page_not_authorized(req=req, text=auth_msg) - + def format_template_show_preview_or_save(req, bft, ln=config.cdslang, code=None, ln_for_preview=config.cdslang, pattern_for_preview="", content_type_for_preview='text/html', save_action=None, navtrail=""): """ Print the preview of a record with a format template. To be included inside Format template editor. If the save_action has a value, then the code should also be saved at the same time - @param code the code of a template to use for formatting + @param code the code of a template to use for formatting @param ln_for_preview the language for the preview (for bfo) @param pattern_for_preview the search pattern to be used for the preview (for bfo) @param save_action has a value if the code has to be saved @param bft the filename of the template to save @param navtrail standard navtrail """ ln = wash_language(ln) _ = gettext_set_language(ln) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bft = wash_url_argument(bft, 'str') if save_action is not None and code is not None: #save bibformatadminlib.update_format_template_code(bft, code=code) bibformat_engine.clear_caches() if code is None: code = bibformat_engine.get_format_template(bft)['code'] ln_for_preview = wash_language(ln_for_preview) pattern_for_preview = wash_url_argument(pattern_for_preview, 'str') if pattern_for_preview == "": recIDs = perform_request_search() if len(recIDs) == 0: return page(title="No Document Found", body="", uid=uid, language=ln_for_preview, navtrail = "", lastupdated=__lastupdated__, req=req, navmenuid='search') else: recID = recIDs[0] pattern_for_preview = "recid:%s" % recID else: recIDs = perform_request_search(p=pattern_for_preview) if len(recIDs) == 0: return page(title="No Record Found for %s" % pattern_for_preview, body="", uid=uid, language=ln_for_preview, navtrail = "", lastupdated=__lastupdated__, - req=req) + req=req) else: recID = recIDs[0] units = create_basic_search_units(None, pattern_for_preview, None) keywords = [unit[1] for unit in units if unit[0] != '-'] bfo = bibformat_engine.BibFormatObject(recID, ln_for_preview, keywords, None, - getUid(req)) + getUid(req), req=req) (body, errors) = bibformat_engine.format_with_format_template(bft, bfo, verbose=7, format_template_code=code) - + if content_type_for_preview == 'text/html': #Standard page display with CDS headers, etc. return page(title="", body=body, uid=uid, language=ln_for_preview, navtrail = navtrail, lastupdated=__lastupdated__, req=req, navmenuid='search') else: #Output with chosen content-type. req.content_type = content_type_for_preview req.send_http_header() req.write(body) else: return page_not_authorized(req=req, text=auth_msg) def format_template_show_short_doc(req, ln=config.cdslang, search_doc_pattern=""): """ Prints the format elements documentation in a brief way. To be included inside Format template editor. - + @param ln: language @param search_doc_pattern a search pattern that specified which elements to display @param bft the name of the template to show """ ln = wash_language(ln) _ = gettext_set_language(ln) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: search_doc_pattern = wash_url_argument(search_doc_pattern, 'str') return bibformatadminlib.perform_request_format_template_show_short_doc(ln=ln, search_doc_pattern=search_doc_pattern) else: return page_not_authorized(req=req, text=auth_msg) - - + + def format_elements_doc(req, ln=config.cdslang): """ Main page for format elements documentation. Check for authentication and print format elements list. @param ln language """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail() try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: return page(title=_("Format Elements Documentation"), body=bibformatadminlib.perform_request_format_elements_documentation(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def format_element_show_dependencies(req, bfe, ln=config.cdslang): """ Shows format element dependencies @param bfe the name of the bfe to show @param ln language """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln , _("Format Elements Documentation"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bfe = wash_url_argument(bfe, 'str') return page(title=_("Format Element %s Dependencies" % bfe), body=bibformatadminlib.perform_request_format_element_show_dependencies(bfe=bfe, ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def format_element_test(req, bfe, ln=config.cdslang, param_values=None): """ Allows user to test element with different parameters and check output 'param_values' is the list of values to pass to 'format' function of the element as parameters, in the order ... If params is None, this means that they have not be defined by user yet. @param bfe the name of the element to test @param ln language @param param_values the list of parameters to pass to element format function """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' %( config.weburl, ln , _("Format Elements Documentation"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: bfe = wash_url_argument(bfe, 'str') return page(title=_("Test Format Element %s" % bfe), body=bibformatadminlib.perform_request_format_element_test(bfe=bfe, ln=ln, param_values=param_values, - uid=getUid(req)), + uid=getUid(req), req=req), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def kb_manage(req, ln=config.cdslang): """ Main page for knowledge bases management. Check for authentication. - + @param ln: language """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail() try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: return page(title=_("Manage Knowledge Bases"), body=bibformatadminlib.perform_request_knowledge_bases_management(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) - + def kb_show(req, kb, sortby="to", ln=config.cdslang): """ Shows the content of the given knowledge base id. Check for authentication and kb existence. Before displaying the content of the knowledge base, check if a form was submitted asking for adding, editing or removing a value. - + @param ln language @param kb the kb id to show @param sortby the sorting criteria ('from' or 'to') """ - + ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: - + kb_id = wash_url_argument(kb, 'int') kb_name = bibformatadminlib.get_kb_name(kb_id) if kb_name is None: return page(title=_("Unknown Knowledge Base"), body = "", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_KB_ID_UNKNOWN", kb)], lastupdated=__lastupdated__, req=req) return page(title=_("Knowledge Base %s" % kb_name), body=bibformatadminlib.perform_request_knowledge_base_show(ln=ln, kb_id=kb_id, sortby=sortby), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def kb_show_attributes(req, kb, ln=config.cdslang, sortby="to"): """ Shows the attributes (name, description) of a given kb - + @param ln language @param kb the kb id to show @param sortby the sorting criteria ('from' or 'to') """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: - + kb_id = wash_url_argument(kb, 'int') kb_name = bibformatadminlib.get_kb_name(kb_id) if kb_name is None: return page(title=_("Unknown Knowledge Base"), body = "", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_KB_ID_UNKNOWN", kb)], lastupdated=__lastupdated__, req=req) return page(title=_("Knowledge Base %s Attributes" % kb_name), body=bibformatadminlib.perform_request_knowledge_base_show_attributes(ln=ln, kb_id=kb_id, sortby=sortby), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def kb_show_dependencies(req, kb, ln=config.cdslang, sortby="to"): """ Shows the dependencies of a given kb - + @param ln language @param kb the kb id to show @param sortby the sorting criteria ('from' or 'to') """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: - + kb_id = wash_url_argument(kb, 'int') kb_name = bibformatadminlib.get_kb_name(kb_id) if kb_name is None: return page(title=_("Unknown Knowledge Base"), body = "", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_KB_ID_UNKNOWN", kb)], lastupdated=__lastupdated__, req=req) return page(title=_("Knowledge Base %s Dependencies" % kb_name), body=bibformatadminlib.perform_request_knowledge_base_show_dependencies(ln=ln, kb_id=kb_id, sortby=sortby), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) - + def kb_add_mapping(req, kb, mapFrom, mapTo, sortby="to", ln=config.cdslang): """ Adds a new mapping to a kb. - + @param ln language @param kb the kb id to show @param sortby the sorting criteria ('from' or 'to') """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: kb_id = wash_url_argument(kb, 'int') kb_name = bibformatadminlib.get_kb_name(kb_id) - + if kb_name is None: return page(title=_("Unknown Knowledge Base"), body = "", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_KB_ID_UNKNOWN", kb)], lastupdated=__lastupdated__, req=req) - + key = wash_url_argument(mapFrom, 'str') value = wash_url_argument(mapTo, 'str') - + bibformatadminlib.add_kb_mapping(kb_name, key, value) redirect_to_url(req, "kb_show?ln=%(ln)s&kb=%(kb)s&sortby=%(sortby)s" % {'ln':ln, 'kb':kb_id, 'sortby':sortby}) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def kb_edit_mapping(req, kb, key, mapFrom, mapTo, update="", delete="", sortby="to", ln=config.cdslang): """ Edit a mapping to in kb. Edit can be "update old value" or "delete existing value" @param kb the knowledge base id to edit @param key the key of the mapping that will be modified @param mapFrom the new key of the mapping @param mapTo the new value of the mapping @param update contains a value if the mapping is to be updated @param delete contains a value if the mapping is to be deleted @param sortby the sorting criteria ('from' or 'to') """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: kb_id = wash_url_argument(kb, 'int') kb_name = bibformatadminlib.get_kb_name(kb_id) - + if kb_name is None: return page(title=_("Unknown Knowledge Base"), body = "", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_KB_ID_UNKNOWN", kb)], lastupdated=__lastupdated__, req=req) - + key = wash_url_argument(key, 'str') if delete != "": #Delete bibformatadminlib.remove_kb_mapping(kb_name, key) else: #Update new_key = wash_url_argument(mapFrom, 'str') new_value = wash_url_argument(mapTo, 'str') bibformatadminlib.update_kb_mapping(kb_name, key, new_key, new_value) redirect_to_url(req, "kb_show?ln=%(ln)s&kb=%(kb)s&sortby=%(sortby)s" % {'ln':ln, 'kb':kb_id, 'sortby':sortby}) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def kb_update_attributes(req, kb="", name="", description="", sortby="to", ln=config.cdslang, chosen_option=None): """ Update the attributes of the kb - + @param ln language @param kb the kb id to update @param sortby the sorting criteria ('from' or 'to') @param name the new name of the kn @param description the new description of the kb @param chosen_option set to dialog box value """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) - + try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: kb_id = wash_url_argument(kb, 'int') if chosen_option is not None: # Update could not be performed. # Redirect to kb attributes page redirect_to_url(req, "kb_show_attributes?ln=%(ln)s&kb=%(kb)s&sortby=%(sortby)s" % {'ln':ln, 'kb':kb_id, 'sortby':sortby}) - + kb_name = bibformatadminlib.get_kb_name(kb_id) if kb_name is None: return page(title=_("Unknown Knowledge Base"), body = "", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_KB_ID_UNKNOWN", kb)], lastupdated=__lastupdated__, req=req) new_name = wash_url_argument(name, 'str') if kb_name != new_name and bibformatadminlib.kb_exists(new_name): #A knowledge base with that name already exist #Do not update return dialog_box(req=req, ln=ln, title="Name already in use", message="""%s cannot be renamed to %s: Another knowledge base already has that name.
Please choose another name.""" % (kb_name, new_name), navtrail=navtrail_previous_links, options=[ _("Ok")]) - + new_desc = wash_url_argument(description, 'str') bibformatadminlib.update_kb_attributes(kb_name, new_name, new_desc) redirect_to_url(req, "kb_show?ln=%(ln)s&kb=%(kb)s&sortby=%(sortby)s" % {'ln':ln, 'kb':kb_id, 'sortby':sortby}) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) - + def kb_add(req, ln=config.cdslang, sortby="to"): """ Adds a new kb """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: kb_id = bibformatadminlib.add_kb() redirect_to_url(req, "kb_show_attributes?ln=%(ln)s&kb=%(kb)s" % {'ln':ln, 'kb':kb_id, 'sortby':sortby}) else: navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"))) - + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) - + def kb_delete(req, kb, ln=config.cdslang, chosen_option="", sortby="to"): """ Deletes an existing kb @param kb the kb id to delete """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s > %s''' % (config.weburl, ln, _("Manage Knowledge Bases"), _("Delete Knowledge Base"))) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: kb_id = wash_url_argument(kb, 'int') kb_name = bibformatadminlib.get_kb_name(kb_id) if kb_name is None: return page(title=_("Unknown Knowledge Base"), body = "", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_KB_ID_UNKNOWN", kb)], lastupdated=__lastupdated__, req=req) #Ask confirmation to user if not already done chosen_option = wash_url_argument(chosen_option, 'str') if chosen_option == "": return dialog_box(req=req, ln=ln, title="Delete %s" % kb_name, message="""Are you sure you want to delete knowledge base %s?""" % kb_name, navtrail=navtrail_previous_links, options=[_("Cancel"), _("Delete")]) - + elif chosen_option==_("Delete"): bibformatadminlib.delete_kb(kb_name) - + redirect_to_url(req, "kb_manage?ln=%(ln)s" % {'ln':ln}) else: navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s'''%(config.weburl, _("Manage Knowledge Bases"))) - + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def validate_format(req, ln=config.cdslang, bfo=None, bft=None, bfe=None): """ Returns a page showing the status of an output format or format template or format element. This page is called from output formats management page or format template management page or format elements documentation. The page only shows the status of one of the format, depending on the specified one. If multiple are specified, shows the first one. @param ln language @param bfo an output format 6 chars code @param bft a format element filename @param bfe a format element name """ ln = wash_language(ln) _ = gettext_set_language(ln) try: uid = getUid(req) except MySQLdb.Error, e: return error_page(req) - (auth_code, auth_msg) = check_user(uid, 'cfgbibformat') + (auth_code, auth_msg) = check_user(req, 'cfgbibformat') if not auth_code: if bfo is not None: #Output format validation bfo = wash_url_argument(bfo, 'str') navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s'''%(config.weburl, ln, _("Manage Output Formats"))) - + if not bibformatadminlib.can_read_output_format(bfo): #No read permission return page(title=_("Restricted Output Format"), body = """You don't have permission to view this output format.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_OUTPUT_FILE", bfo , "")], lastupdated=__lastupdated__, req=req) - + output_format = bibformat_engine.get_output_format(code=bfo, with_attributes=True) name = output_format['attrs']['names']['generic'] title = _("Validation of Output Format %s" % name) - + elif bft is not None: #Format template validation bft = wash_url_argument(bft, 'str') navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln, _("Manage Format Templates"))) - + if not bibformatadminlib.can_read_format_template(bft): #No read permission return page(title=_("Restricted Format Template"), body = """You don't have permission to view this format template.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_TEMPLATE_FILE", bft , "")], lastupdated=__lastupdated__, req=req) name = bibformat_engine.get_format_template_attrs(bft)['name'] title = _("Validation of Format Template %s" % name) - + elif bfe is not None: #Format element validation bfe = wash_url_argument(bfe, 'str') navtrail_previous_links = bibformatadminlib.getnavtrail(''' > %s''' % (config.weburl, ln , bfe.upper() , _("Format Elements Documentation"))) - + if not bibformatadminlib.can_read_format_element(bfe) and \ not bibformat_dblayer.tag_exists_for_name(bfe): #No read permission return page(title=_("Restricted Format Element"), body = """You don't have permission to view this format element.""", language=ln, navtrail = navtrail_previous_links, errors = [("ERR_BIBFORMAT_CANNOT_READ_ELEMENT_FILE", bfe ,"")], lastupdated=__lastupdated__, req=req) title = _("Validation of Format Element %s" % bfe) else: #No format specified return page(title=_("Format Validation"), uid=uid, language=ln, errors = [("ERR_BIBFORMAT_VALIDATE_NO_FORMAT")], navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) return page(title=title, body=bibformatadminlib.perform_request_format_validate(ln=ln, bfo=bfo, bft=bft, bfe=bfe), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: navtrail_previous_links = bibformatadminlib.getnavtrail(''' > Define below the sets to expose through the OAI harvesting protocol.
You will have to run the
oaiarchive utility to apply the settings you have defined here.

''' % {'weburl': weburl} titlebar = bibharvest_templates.tmpl_draw_titlebar(ln = cdslang, weburl = weburl, title = "OAI repository", guideurl = guideurl, extraname = "add new OAI set", extraurl = "admin/bibharvest/oaiarchiveadmin.py/addset") header = ['id','setSpec','setName','setCollection','p1','f1','m1','p2','f2','m2','p3','f3','m3','','',''] oai_set = get_oai_set() sets = [] - + for (id, setSpec, setName, setCollection, setDescription, p1, f1, m1, p2, f2, m2, p3, f3, m3) in oai_set: del_request = 'delete' - + edit_request = 'edit' sets.append([id, setSpec, setName, setCollection, p1,f1,m1, p2,f2,m2, p3,f3,m3, del_request, edit_request]) add_request = 'Add new OAI set definition' - + sets.append(['',add_request,'','','','','','','','','','','','']) out += transform_tuple(header=header, tuple=sets) - + out += "

" return out def perform_request_addset(oai_set_name='', oai_set_spec='', oai_set_collection='', oai_set_description='', oai_set_definition='', oai_set_reclist='', oai_set_p1='', oai_set_f1='',oai_set_m1='', oai_set_p2='', oai_set_f2='', oai_set_m2='', oai_set_p3='', oai_set_f3='', oai_set_m3='', ln=cdslang, func=0): """add a new OAI set""" out = "" if func in ["0", 0]: text = input_form(oai_set_name, oai_set_spec, oai_set_collection, oai_set_description, oai_set_definition, oai_set_reclist, oai_set_p1, oai_set_f1,oai_set_m1, oai_set_p2, oai_set_f2,oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3, ln=cdslang) out = createform(action="addset", text=text, ln=ln, button="Add new OAI set definition line", func=1) lnargs = [["ln", ln]] if func in ["1", 1]: out += "
" res = add_oai_set(oai_set_name, oai_set_spec, oai_set_collection, oai_set_description, oai_set_definition, oai_set_reclist, oai_set_p1, oai_set_f1,oai_set_m1, oai_set_p2, oai_set_f2,oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3) if res[0] == 1: out += bibharvest_templates.tmpl_print_info(cdslang, "OAI set definition %s added." % oai_set_name) out += "
" lnargs = [["ln", ln]] out += "

" out += bibharvest_templates.tmpl_link_with_args(ln = cdslang, weburl = weburl, funcurl = "admin/bibharvest/oaiarchiveadmin.py/index", title = "Return to main selection", args = lnargs) body = [out] return nice_box("", body) def perform_request_editset(oai_set_id=None, oai_set_name='', oai_set_spec='', oai_set_collection='', oai_set_description='', oai_set_definition='', oai_set_reclist='', oai_set_p1='', oai_set_f1='', oai_set_m1='', oai_set_p2='', oai_set_f2='', oai_set_m2='', oai_set_p3='', oai_set_f3='', oai_set_m3='', ln=cdslang, func=0): """creates html form to edit an OAI set.""" if oai_set_id is None: return "No OAI set ID selected." out = "" if func in [0, "0"]: oai_set = get_oai_set(oai_set_id) oai_set_spec = oai_set[0][1] oai_set_name = oai_set[0][2] oai_set_collection = oai_set[0][3] oai_set_description = oai_set[0][4] oai_set_definition = '' oai_set_reclist = '' oai_set_p1 = oai_set[0][5] oai_set_f1 = oai_set[0][6] oai_set_m1 = oai_set[0][7] oai_set_p2 = oai_set[0][8] oai_set_f2 = oai_set[0][9] oai_set_m2 = oai_set[0][10] oai_set_p3 = oai_set[0][11] oai_set_f3 = oai_set[0][12] oai_set_m3 = oai_set[0][13] text = input_form(oai_set_name, oai_set_spec, oai_set_collection, oai_set_description, oai_set_definition, oai_set_reclist, oai_set_p1, oai_set_f1, oai_set_m1, oai_set_p2, oai_set_f2, oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3, ln=cdslang) out += extended_input_form(action="editset", text=text, button="Modify", oai_set_id=oai_set_id, ln=ln, func=1) if func in [1, "1"]: res = modify_oai_set(oai_set_id, oai_set_name, oai_set_spec, oai_set_collection, oai_set_description, oai_set_p1, oai_set_f1, oai_set_m1, oai_set_p2, oai_set_f2, oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3) out += "
" if res[0] == 1: out += bibharvest_templates.tmpl_print_info(cdslang, "OAI set definition #%s edited." % oai_set_id) out += "
" - + lnargs = [["ln", ln]] out += "
" - + out += bibharvest_templates.tmpl_link_with_args(ln = cdslang, weburl = weburl, funcurl = "admin/bibharvest/oaiarchiveadmin.py/index", title = "Return to main selection", args = lnargs) body = [out] return nice_box("", body) def perform_request_delset(oai_set_id=None, ln=cdslang, callback='yes', func=0): """creates html form to delete an OAI set""" out = "" if oai_set_id: oai_set = get_oai_set(oai_set_id) nameset = (oai_set[0][1]) pagetitle = """Delete OAI set: %s""" % nameset if func in ["0", 0]: oai_set = get_oai_set(oai_set_id) oai_set_spec = oai_set[0][1] oai_set_name = oai_set[0][2] oai_set_collection = oai_set[0][3] oai_set_description = oai_set[0][4] oai_set_definition = '' oai_set_reclist = '' oai_set_p1 = oai_set[0][5] - oai_set_f1 = oai_set[0][6] - oai_set_m1 = oai_set[0][7] - oai_set_p2 = oai_set[0][8] - oai_set_f2 = oai_set[0][9] + oai_set_f1 = oai_set[0][6] + oai_set_m1 = oai_set[0][7] + oai_set_p2 = oai_set[0][8] + oai_set_f2 = oai_set[0][9] oai_set_m2 = oai_set[0][10] oai_set_p3 = oai_set[0][11] oai_set_f3 = oai_set[0][12] oai_set_m3 = oai_set[0][13] if oai_set: question = """Do you want to delete the OAI definition #%s?""" % oai_set_id text = bibharvest_templates.tmpl_print_info(cdslang, question) text += "


" text += pagebody_text("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s" % (oai_set_spec, oai_set_name, oai_set_collection, oai_set_p1, oai_set_f1, oai_set_m1, oai_set_p2, oai_set_f2, oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3)) out += createform(action="delset", text=text, button="Delete", oai_set_id=oai_set_id, func=1) else: return bibharvest_templates.tmpl_print_info(cdslang, "OAI set does not exist.") elif func in ["1", 1]: res = delete_oai_set(oai_set_id) if res[0] == 1: out += bibharvest_templates.tmpl_print_info(cdslang, "OAI set definition #%s deleted." % oai_set_id) out += "
" else: pass - + lnargs = [["ln", ln]] out += "

" out += bibharvest_templates.tmpl_link_with_args(ln = cdslang, weburl = weburl, funcurl = "admin/bibharvest/oaiarchiveadmin.py/index", title = "Return to main selection", args = lnargs ) body = [out] return nice_box("", body) def get_oai_set(id=''): """Returns a row parameters for a given id""" sets = [] - sql = "SELECT id, setSpec, setName, setCollection, setDescription, p1,f1,m1, p2,f2,m2, p3,f3,m3, setDefinition FROM oaiARCHIVE" + sql = "SELECT id, setSpec, setName, setCollection, setDescription, p1,f1,m1, p2,f2,m2, p3,f3,m3, setDefinition FROM oaiARCHIVE" try: if id: sql += " WHERE id=%s" % id sql += " ORDER BY setSpec asc" res = run_sql(sql) for row in res: set = ['']*14 set[0] = row[0] set[1] = row[1] set[2] = row[2] params = parse_set_definition(row[14]) set[3] = params.get('c', '') set[5] = params.get('p1', '') set[6] = params.get('f1', '') set[7] = params.get('m1', '') set[8] = params.get('p2', '') set[9] = params.get('f2', '') set[10] = params.get('m2', '') set[11] = params.get('p3', '') set[12] = params.get('f3', '') set[13] = params.get('m3', '') sets.append(set) return sets except StandardError, e: return str(e) def modify_oai_set(oai_set_id, oai_set_name, oai_set_spec, oai_set_collection, oai_set_description, oai_set_p1, oai_set_f1,oai_set_m1, oai_set_p2, oai_set_f2,oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3): """Modifies a row's parameters""" - + try: set_definition = 'c=' + oai_set_collection + ';' + \ 'p1=' + oai_set_p1 + ';' + \ 'f1=' + oai_set_f1 + ';' + \ 'm1=' + oai_set_m1 + ';' + \ 'p2=' + oai_set_p2 + ';' + \ 'f2=' + oai_set_f2 + ';' + \ 'm2=' + oai_set_m2 + ';' + \ 'p3=' + oai_set_p3 + ';' + \ 'f3=' + oai_set_f3 + ';' + \ 'm3=' + oai_set_m3 + ';' sql = """UPDATE oaiARCHIVE SET setName='%s', setSpec='%s', setCollection='%s', setDescription='%s', setDefinition='%s', p1='%s', f1='%s', m1='%s', p2='%s', f2='%s', m2='%s', p3='%s', f3='%s', m3='%s' WHERE id=%s""" % ( escape_string(oai_set_name), \ escape_string(oai_set_spec), \ escape_string(oai_set_collection), \ escape_string(oai_set_description), \ escape_string(set_definition), \ escape_string(oai_set_p1), \ escape_string(oai_set_f1), \ escape_string(oai_set_m1), \ escape_string(oai_set_p2), \ escape_string(oai_set_f2), \ escape_string(oai_set_m2), \ escape_string(oai_set_p3), \ escape_string(oai_set_f3), \ escape_string(oai_set_m3), \ oai_set_id \ ) - + res = run_sql(sql) return (1, "") except StandardError, e: return (0, e) def add_oai_set(oai_set_name, oai_set_spec, oai_set_collection, oai_set_description, oai_set_definition, oai_set_reclist, oai_set_p1, oai_set_f1,oai_set_m1, oai_set_p2, oai_set_f2,oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3): """Add a definition into the OAI archive""" try: set_definition = 'c=' + oai_set_collection + ';' + \ 'p1=' + oai_set_p1 + ';' + \ 'f1=' + oai_set_f1 + ';' + \ 'm1=' + oai_set_m1 + ';' + \ 'p2=' + oai_set_p2 + ';' + \ 'f2=' + oai_set_f2 + ';' + \ 'm2=' + oai_set_m2 + ';' + \ 'p3=' + oai_set_p3 + ';' + \ 'f3=' + oai_set_f3 + ';' + \ 'm3=' + oai_set_m3 + ';' sql = "insert into oaiARCHIVE values (0, '%s', '%s', '%s', '%s', '%s', NULL, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')" % ( escape_string(oai_set_name), \ escape_string(oai_set_spec), \ escape_string(oai_set_collection), \ escape_string(oai_set_description), \ escape_string(set_definition), \ escape_string(oai_set_p1), \ escape_string(oai_set_f1), \ escape_string(oai_set_m1), \ escape_string(oai_set_p2), \ escape_string(oai_set_f2), \ escape_string(oai_set_m2), \ escape_string(oai_set_p3), \ escape_string(oai_set_f3), \ escape_string(oai_set_m3) \ ) - + res = run_sql(sql) return (1, "") except StandardError, e: return (0, e) - + def delete_oai_set(oai_set_id): """""" try: res = run_sql("DELETE FROM oaiARCHIVE WHERE id=%s" % oai_set_id) return (1, "") except StandardError, e: return (0, e) def drop_down_menu(boxname, list=['Select', 'selected', 'select']): """""" text = "" return text def create_drop_down_menu(sql): """""" list = [] res = run_sql(sql) for item in res: tmp_list = [] tmp_list.append(item) tmp_list.append("") tmp_list.append(item) list.append(tmp_list) return list def createform(action="", text="", button="func", cnfrm='', **hidden): """""" out = '
\n' % (action, ) out += text if cnfrm: - out += ' ' + out += ' ' for key in hidden.keys(): if type(hidden[key]) is list: for value in hidden[key]: out += ' \n' % (key, value) else: out += ' \n' % (key, hidden[key]) out += ' \n' % (button, ) out += '
\n' return out def oai_table(ln=cdslang): """""" - + titlebar = bibharvest_templates.tmpl_draw_titlebar(ln = cdslang, weburl = weburl, title = "OAI repository", guideurl = guideurl, extraname = "add new OAI set" , extraurl = "admin/bibharvest/oaiarchiveadmin.py/addset" ) header = ['id', 'setSpec', 'setName', 'setCollection', 'p1', 'f1', 'm1', 'p2', 'f2', 'm2', 'p3', 'f3', 'm3', '', ''] oai_set = get_oai_set() sets = [] for (id, setSpec, setName, setCollection, setDescription, p1,f1,m1, p2,f2,m2, p3,f3,m3) in oai_set: del_request = 'delete' sets.append([id, setSpec, setName, setCollection, p1,f1,m1, p2,f2,m2, p3,f3,m3, del_request]) add_request = 'Add new OAI set definition' sets.append(['',add_request,'','','','','','','','','','','','']) - + out = transform_tuple(header=header, tuple=sets) out += "

" - + return out - + def input_text(ln, title, name, value): """""" if name is None: name = "" if value is None: value = "" text = """""" % title - text += """
%s
""" % (cgi.escape(name,1), cgi.escape(value, 1)) + text += """""" % (cgi.escape(name,1), cgi.escape(value, 1)) return text def pagebody_text(title): """""" text = """%s""" % title return text def bar_text(title): """""" text = """%s""" % title return text def input_form(oai_set_name, oai_set_spec, oai_set_collection, oai_set_description, oai_set_definition, oai_set_reclist, oai_set_p1, oai_set_f1,oai_set_m1, oai_set_p2, oai_set_f2,oai_set_m2, oai_set_p3, oai_set_f3, oai_set_m3, ln=cdslang): """""" - + modes = { 'r' : 'Regular Expression', 'a' : 'All of the words', 'y' : 'Any of the words', 'e' : 'Exact phrase', 'p' : 'Partial phrase' } mode_dropdown = [['r','',modes['r']], ['e','',modes['e']], ['p','',modes['p']], ['a','',modes['a']], ['y','',modes['y']], ['','','']] text = "
" text += "
" text += input_text(ln = cdslang, title = "OAI Set spec:", name = "oai_set_spec", value = oai_set_spec) text += "
" text += input_text(ln = cdslang, title = "OAI Set name:", name = "oai_set_name", value = oai_set_name) text += "
 
" # text += input_text(ln = cdslang, title = "OAI Set description", name = "oai_set_description", value = oai_set_description) #text += "" #menu = create_drop_down_menu("SELECT distinct(name) from collection") #menu.append(['','','']) #if (oai_set_collection): # menu.append([oai_set_collection,'selected',oai_set_collection]) #else: # menu.append(['','selected','Collection']) - + text += input_text(ln = cdslang, title = "Collection(s):", name="oai_set_collection", value=oai_set_collection) #text += drop_down_menu("oai_set_collection", menu) - + text += "
" text += input_text(ln = cdslang, title = "Phrase:", name = "oai_set_p1", value = oai_set_p1) text += "" fields = create_drop_down_menu("SELECT distinct(code) from field") fields.append(['','','']) if (oai_set_f1): fields.append([oai_set_f1,'selected',oai_set_f1]) - else: + else: fields.append(['','selected','Field']) if (oai_set_m1): mode_dropdown.append([oai_set_m1,'selected',modes[oai_set_m1]]) - else: + else: mode_dropdown.append(['','selected','Mode']) text += drop_down_menu("oai_set_f1", fields) text += "" text += drop_down_menu("oai_set_m1", mode_dropdown) - + text += "" text += bar_text(" and") text += "
" text += input_text(ln = cdslang, title = "Phrase:", name = "oai_set_p2", value = oai_set_p2) text += "" fields = create_drop_down_menu("SELECT distinct(code) from field") fields.append(['','','']) if (oai_set_f2): fields.append([oai_set_f2,'selected',oai_set_f2]) else: fields.append(['','selected','Field']) if (oai_set_m2): mode_dropdown.append([oai_set_m2,'selected',modes[oai_set_m2]]) else: mode_dropdown.append(['','selected','Mode']) - + text += drop_down_menu("oai_set_f2", fields) text += "" text += drop_down_menu("oai_set_m2", mode_dropdown) text += "" text += bar_text(" and") text += "
" text += input_text(ln = cdslang, title = "Phrase:", name = "oai_set_p3", value = oai_set_p3) text += "" fields = create_drop_down_menu("SELECT distinct(code) from field") fields.append(['','','']) if (oai_set_f3): fields.append([oai_set_f3,'selected',oai_set_f3]) else: fields.append(['','selected','Field']) if (oai_set_m3): mode_dropdown.append([oai_set_m3,'selected',modes[oai_set_m3]]) else: mode_dropdown.append(['','selected','Mode']) text += drop_down_menu("oai_set_f3", fields) text += "" text += drop_down_menu("oai_set_m3", mode_dropdown) - + text += "
" return text -def check_user(uid, role, adminarea=2, authorized=0): +def check_user(req, role, adminarea=2, authorized=0): """""" - (auth_code, auth_message) = access_manager.acc_authorize_action(uid, role) + (auth_code, auth_message) = access_manager.acc_authorize_action(req, role) if not authorized and auth_code != 0: return ("false", auth_message) return ("", auth_message) def transform_tuple(header=[], tuple=[], start='', end='', extracolumn=''): """""" align = [] try: firstrow = tuple[0] - - if type(firstrow) in [int, long]: + + if type(firstrow) in [int, long]: align = ['admintdright'] elif type(firstrow) in [str, dict]: align = ['admintdleft'] else: for item in firstrow: if type(item) is int: align.append('admintdright') else: align.append('admintdleft') except IndexError: firstrow = [] - + tblstr = '' for h in header + ['']: tblstr += ' %s\n' % (h, ) if tblstr: tblstr = ' \n%s\n \n' % (tblstr, ) - + tblstr = start + '\n' + tblstr - - try: + + try: extra = '' if type(firstrow) not in [int, long, str, dict]: for i in range(len(firstrow)): extra += '\n' % (align[i], firstrow[i]) else: extra += ' \n' % (align[0], firstrow) extra += '\n\n' % (len(tuple), extracolumn) except IndexError: extra = '' tblstr += extra for row in tuple[1:]: tblstr += ' \n' if type(row) not in [int, long, str, dict]: for i in range(len(row)): tblstr += '\n' % (align[i], row[i]) else: tblstr += ' \n' % (align[0], row) tblstr += ' \n' tblstr += '
%s%s\n%s\n
%s%s
\n ' tblstr += end - + return tblstr def nice_box(header='', datalist=[], cls="admin_wvar"): """""" if len(datalist) == 1: per = '100' else: per = '75' - + out = '\n' out += """ """ % (len(datalist), header) out += ' \n' out += """ """ % (per+'%', datalist[0]) if len(datalist) > 1: out += """ """ % ('25%', datalist[1]) - + out += ' \n' - + out += """
%s
- %s + %s - %s + %s
""" return out def extended_input_form(action="", text="", button="func", cnfrm='', **hidden): """""" - + out = '
\n' % (action, ) out += '\n
' out += text if cnfrm: - out += ' ' + out += ' ' for key in hidden.keys(): if type(hidden[key]) is list: for value in hidden[key]: out += ' \n' % (key, value) else: out += ' \n' % (key, hidden[key]) out += '' out += ' \n' % (button, ) out += '
' out += '
\n' return out diff --git a/modules/bibharvest/web/admin/bibharvestadmin.py b/modules/bibharvest/web/admin/bibharvestadmin.py index aefb7ad38..1f9ea7e07 100644 --- a/modules/bibharvest/web/admin/bibharvestadmin.py +++ b/modules/bibharvest/web/admin/bibharvestadmin.py @@ -1,161 +1,161 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio BibHarvest Administrator Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" import invenio.bibharvestadminlib as bhc from invenio.webpage import page, create_error_box from invenio.config import cdsname, weburl, cdslang from invenio.dbquery import Error from invenio.webuser import getUid, page_not_authorized def index(req, ln=cdslang): navtrail_previous_links = bhc.getnavtrail() - + try: uid = getUid(req) except Error, e: return page(title="BibHarvest Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: return page(title="BibHarvest Admin Interface", body=bhc.perform_request_index(ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def editsource(req, oai_src_id=None, oai_src_name='', oai_src_baseurl='', oai_src_prefix='', oai_src_frequency='', oai_src_config='', oai_src_post='', ln=cdslang, mtype='', callback='yes', confirm=-1, oai_src_sets=[], oai_src_bibfilter=''): navtrail_previous_links = bhc.getnavtrail() + """> BibHarvest Admin Interface """ % (weburl) try: uid = getUid(req) except Error, e: return page(title="BibHarvest Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: if isinstance(oai_src_sets, str): oai_src_sets = [oai_src_sets] return page(title="Edit OAI Source", body=bhc.perform_request_editsource(oai_src_id=oai_src_id, oai_src_name=oai_src_name, oai_src_baseurl=oai_src_baseurl, oai_src_prefix=oai_src_prefix, oai_src_frequency=oai_src_frequency, oai_src_config=oai_src_config, oai_src_post=oai_src_post, oai_src_sets=oai_src_sets, oai_src_bibfilter=oai_src_bibfilter, ln=ln, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addsource(req, ln=cdslang, oai_src_name='', oai_src_baseurl ='', oai_src_prefix='', oai_src_frequency='', oai_src_lastrun='', oai_src_config='', oai_src_post='', confirm=-1, oai_src_sets=[], oai_src_bibfilter=''): navtrail_previous_links = bhc.getnavtrail() + """> BibHarvest Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return page(title="BibHarvest Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: if isinstance(oai_src_sets, str): oai_src_sets = [oai_src_sets] return page(title="Add new OAI Source", body=bhc.perform_request_addsource(oai_src_name=oai_src_name, oai_src_baseurl=oai_src_baseurl, oai_src_prefix=oai_src_prefix, oai_src_frequency=oai_src_frequency, oai_src_lastrun=oai_src_lastrun, oai_src_config=oai_src_config, oai_src_post=oai_src_post, oai_src_sets=oai_src_sets, oai_src_bibfilter=oai_src_bibfilter, ln=cdslang, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def delsource(req, oai_src_id=None, ln=cdslang, confirm=0): navtrail_previous_links = bhc.getnavtrail() + """> BibHarvest Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return page(title="BibHarvest Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: return page(title="Delete OAI Source", body=bhc.perform_request_delsource(oai_src_id=oai_src_id, ln=ln, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) diff --git a/modules/bibharvest/web/admin/oaiarchiveadmin.py b/modules/bibharvest/web/admin/oaiarchiveadmin.py index 35d6bfafe..e7994633c 100644 --- a/modules/bibharvest/web/admin/oaiarchiveadmin.py +++ b/modules/bibharvest/web/admin/oaiarchiveadmin.py @@ -1,176 +1,176 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio OAI Archive Administrator Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" import sys import invenio.oaiarchiveadminlib as bhc from invenio.webpage import page, create_error_box from invenio.config import weburl,cdslang from invenio.dbquery import Error from invenio.webuser import getUid, page_not_authorized def index(req, ln=cdslang): navtrail_previous_links = bhc.getnavtrail() - + try: uid = getUid(req) except Error, e: return page(title="OAI Archive Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: return page(title="OAI Repository Admin Interface", body=bhc.perform_request_index(ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addset(req, oai_set_name='', oai_set_spec='', oai_set_collection='', oai_set_description='', oai_set_definition='', oai_set_reclist='', oai_set_p1='', oai_set_f1='',oai_set_m1='', oai_set_p2='', oai_set_f2='', oai_set_m2='', oai_set_p3='', oai_set_f3='', oai_set_m3='', ln=cdslang, func=0): navtrail_previous_links = bhc.getnavtrail() + """> OAI Repository Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return page(title="OAI Archive Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: return page(title="Add new OAI Set", body=bhc.perform_request_addset(oai_set_name=oai_set_name, oai_set_spec=oai_set_spec, oai_set_collection=oai_set_collection, oai_set_description=oai_set_description, oai_set_definition=oai_set_definition, oai_set_reclist=oai_set_reclist, oai_set_p1=oai_set_p1, oai_set_f1=oai_set_f1, oai_set_m1=oai_set_m1, oai_set_p2=oai_set_p2, oai_set_f2=oai_set_f2, oai_set_m2=oai_set_m2, oai_set_p3=oai_set_p3, oai_set_f3=oai_set_f3, oai_set_m3=oai_set_m3, ln=cdslang, func=func), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def delset(req, oai_set_id=None, ln=cdslang, func=0): navtrail_previous_links = bhc.getnavtrail() + """> OAI Repository Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return page(title="OAI Archive Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: return page(title="Delete OAI Set", body=bhc.perform_request_delset(oai_set_id=oai_set_id, ln=ln, func=func), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def editset(req, oai_set_id=None, oai_set_name='', oai_set_spec='', oai_set_collection='', oai_set_description='', oai_set_definition='', oai_set_reclist='', oai_set_p1='', oai_set_f1='', oai_set_m1='', oai_set_p2='', oai_set_f2='', oai_set_m2='', oai_set_p3='', oai_set_f3='', oai_set_m3='', ln=cdslang, func=0): navtrail_previous_links = bhc.getnavtrail() + """> OAI Repository Admin Interface """ % (weburl) try: uid = getUid(req) except Error, e: return page(title="OAI Archive Admin Interface - Error", body=e, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) - auth = bhc.check_user(uid,'cfgbibharvest') + auth = bhc.check_user(req,'cfgbibharvest') if not auth[0]: return page(title="Edit OAI Set", body=bhc.perform_request_editset(oai_set_id=oai_set_id, oai_set_name=oai_set_name, oai_set_spec=oai_set_spec, oai_set_collection=oai_set_collection, oai_set_description=oai_set_description, oai_set_definition=oai_set_definition, oai_set_reclist=oai_set_reclist, oai_set_p1=oai_set_p1, oai_set_f1=oai_set_f1, oai_set_m1=oai_set_m1, oai_set_p2=oai_set_p2, oai_set_f2=oai_set_f2, oai_set_m2=oai_set_m2, oai_set_p3=oai_set_p3, oai_set_f3=oai_set_f3, oai_set_m3=oai_set_m3, ln=ln, func=func), - + uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) diff --git a/modules/bibindex/web/admin/bibindexadmin.py b/modules/bibindex/web/admin/bibindexadmin.py index 4e39c45ec..17c5bfae7 100644 --- a/modules/bibindex/web/admin/bibindexadmin.py +++ b/modules/bibindex/web/admin/bibindexadmin.py @@ -1,644 +1,644 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio BibIndex Administrator Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" import sys import invenio.bibindexadminlib as bic from invenio.webpage import page, create_error_box from invenio.config import weburl, cdslang, cdsname from invenio.dbquery import Error from invenio.webuser import getUid, page_not_authorized def deletetag(req, fldID, ln=cdslang, tagID=-1, callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_deletetag(fldID=fldID, ln=ln, tagID=tagID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def addtag(req, fldID, ln=cdslang, value=['',-1], name='', callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - - auth = bic.check_user(uid,'cfgbibindex') + + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_addtag(fldID=fldID, ln=ln, value=value, name=name, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifyfieldtags(req, fldID, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_modifyfieldtags(fldID=fldID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addindexfield(req, idxID, ln=cdslang, fldID='', callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage indexes """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - - auth = bic.check_user(uid,'cfgbibindex') + + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Index", body=bic.perform_addindexfield(idxID=idxID, ln=ln, fldID=fldID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyindexfields(req, idxID, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage Indexes """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Index", body=bic.perform_modifyindexfields(idxID=idxID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showdetailsfieldtag(req, fldID, tagID, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_showdetailsfieldtag(fldID=fldID, tagID=tagID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def showdetailsfield(req, fldID, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_showdetailsfield(fldID=fldID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifyfield(req, fldID, ln=cdslang, code='', callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_modifyfield(fldID=fldID, ln=ln, code=code, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyindex(req, idxID, ln=cdslang, idxNAME='', idxDESC='', callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage Indexes """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Index", body=bic.perform_modifyindex(idxID=idxID, ln=ln, idxNAME=idxNAME, idxDESC=idxDESC, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifytag(req, fldID, tagID, ln=cdslang, name='', value='', callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_modifytag(fldID=fldID, tagID=tagID, ln=ln, name=name, value=value, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def deletefield(req, fldID, ln=cdslang, confirm=0): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_deletefield(fldID=fldID, ln=ln, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def deleteindex(req, idxID, ln=cdslang, confirm=0): navtrail_previous_links = bic.getnavtrail() + """> Manage Indexes """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Index", body=bic.perform_deleteindex(idxID=idxID, ln=ln, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showfieldoverview(req, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Manage logical fields", body=bic.perform_showfieldoverview(ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def editfields(req, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Manage logical fields", body=bic.perform_editfields(ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def editfield(req, fldID, ln=cdslang, mtype='', callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_editfield(fldID=fldID, ln=ln, mtype=mtype, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def editindex(req, idxID, ln=cdslang, mtype='', callback='yes', confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage Indexes """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Index", body=bic.perform_editindex(idxID=idxID, ln=ln, mtype=mtype, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyindextranslations(req, idxID, ln=cdslang, sel_type='', trans = [], confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage Indexes """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Index", body=bic.perform_modifyindextranslations(idxID=idxID, ln=ln, sel_type=sel_type, trans=trans, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyfieldtranslations(req, fldID, ln=cdslang, sel_type='', trans = [], confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_modifyfieldtranslations(fldID=fldID, ln=ln, sel_type=sel_type, trans=trans, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addfield(req, ln=cdslang, fldNAME='', code='', callback="yes", confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = bic.check_user(uid,'cfgbibindex') + + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Manage logical fields", body=bic.perform_addfield(ln=cdslang, fldNAME=fldNAME, code=code, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addindex(req, ln=cdslang, idxNAME='', callback="yes", confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage Indexes """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = bic.check_user(uid,'cfgbibindex') + + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Manage Indexes", body=bic.perform_addindex(ln=cdslang, idxNAME=idxNAME, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def switchtagscore(req, fldID, id_1, id_2, ln=cdslang): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_switchtagscore(fldID=fldID, id_1=id_1, id_2=id_2, ln=ln), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def removeindexfield(req, idxID, fldID, ln=cdslang, callback="yes", confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage Indexes """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = bic.check_user(uid,'cfgbibindex') + + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Index", body=bic.perform_removeindexfield(idxID=idxID, fldID=fldID, ln=cdslang, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def removefieldtag(req, fldID, tagID, ln=cdslang, callback="yes", confirm=-1): navtrail_previous_links = bic.getnavtrail() + """> Manage logical fields """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = bic.check_user(uid,'cfgbibindex') + + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Edit Logical Field", body=bic.perform_removefieldtag(fldID=fldID, tagID=tagID, ln=cdslang, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def index(req, ln=cdslang, mtype='', content=''): navtrail_previous_links = bic.getnavtrail() try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Manage Indexes", body=bic.perform_index(ln=ln, mtype=mtype, content=content), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def field(req, ln=cdslang, mtype='', content=''): navtrail_previous_links = bic.getnavtrail() try: uid = getUid(req) except Error, e: return error_page(req) - auth = bic.check_user(uid,'cfgbibindex') + auth = bic.check_user(req,'cfgbibindex') if not auth[0]: return page(title="Manage logical fields", body=bic.perform_field(ln=ln, mtype=mtype, content=content), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def error_page(req, ln=cdslang, verbose=1): return page(title="Internal Error", body = create_error_box(req, verbose=verbose, ln=ln), - description="%s - Internal Error" % cdsname, + description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) diff --git a/modules/bibrank/lib/bibrank_citation_indexer.py b/modules/bibrank/lib/bibrank_citation_indexer.py index dc77dea7e..7b4aafdbb 100644 --- a/modules/bibrank/lib/bibrank_citation_indexer.py +++ b/modules/bibrank/lib/bibrank_citation_indexer.py @@ -1,328 +1,328 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" import time import os -from marshal import loads, dumps +import marshal from zlib import decompress, compress from invenio.dbquery import run_sql, escape_string from invenio.search_engine import print_record, search_pattern from invenio.bibrecord import create_records, record_get_field_values from invenio.bibformat_utils import parse_tag class memoise: def __init__(self, function): self.memo = {} self.function = function def __call__(self, *args): if self.memo.has_key(args): return self.memo[args] else: object = self.memo[args] = self.function(*args) return object def get_recids_matching_query(pvalue, fvalue): """Return list of recIDs matching query for PVALUE and FVALUE.""" rec_id = search_pattern(p=pvalue, f=fvalue, m='e').tolist() return rec_id get_recids_matching_query = memoise(get_recids_matching_query) def get_citation_weight(rank_method_code, config): """return a dictionary which is used by bibrank daemon for generating the index of sorted research results by citation inforamtion """ begin_time = time.time() last_update_time = get_bibrankmethod_lastupdate(rank_method_code) last_modified_records = get_last_modified_rec(last_update_time) - + if last_modified_records: updated_recid_list = create_recordid_list(last_modified_records) result_intermediate = last_updated_result(rank_method_code, updated_recid_list) citation_weight_dic_intermediate = result_intermediate[0] citation_list_intermediate = result_intermediate[1] reference_list_intermediate = result_intermediate[2] citation_informations = get_citation_informations(updated_recid_list, config) dic = ref_analyzer(citation_informations, citation_weight_dic_intermediate, citation_list_intermediate, reference_list_intermediate) end_time = time.time() print "Total time of software: ", (end_time - begin_time) else: dic = {} print "No new records added since last time this rank method was executed" return dic def get_bibrankmethod_lastupdate(rank_method_code): """return the last excution date of bibrank method """ query = """select last_updated from rnkMETHOD where name ='%s'""" % rank_method_code last_update_time = run_sql(query) return last_update_time[0][0] def get_last_modified_rec(bibrank_method_lastupdate): """ return the list of recods which have been modified after the last execution of bibrank method. The result is expected to have ascending numerical order. """ query = """SELECT id FROM bibrec WHERE modification_date>= '%s' """ % bibrank_method_lastupdate query += "order by id ASC" list = run_sql(query) return list def create_recordid_list(rec_ids): """Create a list of record ids out of RECIDS. The result is expected to have ascending numerical order. """ rec_list = [] for row in rec_ids: rec_list.append(row[0]) return rec_list def create_record_tuple(list): """Creates a tuple of record id from a list of id. The result is expected to have ascending numerical order. """ list_length = len(list) if list_length: rec_tuple = '(' for row in list[0:list_length-1]: rec_tuple += str(row) rec_tuple += ',' rec_tuple += str(list[list_length-1]) rec_tuple += ')' else: rec_tuple = '()' return rec_tuple def last_updated_result(rank_method_code, recid_list): """ return the last value of dictionary in rnkMETHODDATA table if it exists and initialize the value of last updated records by zero,otherwise an initial dictionary with zero as value for all recids """ query = """select relevance_data from rnkMETHOD, rnkMETHODDATA where rnkMETHOD.id = rnkMETHODDATA.id_rnkMETHOD and rnkMETHOD.Name = '%s'"""% rank_method_code dict = run_sql(query) if dict: - dic = loads(decompress(dict[0][0])) + dic = marshal.loads(decompress(dict[0][0])) query = "select citation_data from rnkCITATIONDATA" cit_compressed = run_sql(query) - cit = loads(decompress(cit_compressed[0][0])) + cit = marshal.loads(decompress(cit_compressed[0][0])) query = "select citation_data_reversed from rnkCITATIONDATA" ref_compressed = run_sql(query) - ref = loads(decompress(ref_compressed[0][0])) + ref = marshal.loads(decompress(ref_compressed[0][0])) result = get_initial_result(dic, cit, ref, recid_list) else: result = make_initial_result() return result def get_initial_result(dic, cit, ref, recid_list): """initialieze the citation weights of the last updated record with zero for recalculating it later """ for recid in recid_list: dic[recid] = 0 cit[recid] = [] if ref.has_key(recid) and ref[recid]: for id in ref[recid]: if cit.has_key(id) and recid in cit[id]: cit[id].remove(recid) dic[id] -= 1 if cit.has_key(recid) and cit[recid]: for id in cit[recid]: if ref.has_key(id) and recid in ref[id]: ref[id].remove(recid) ref[recid] = [] return [dic, cit, ref] def make_initial_result(): """return an initial dictinary with recID as key and zero as value """ dic = {} cit = {} ref = {} query = "select id from bibrec" res = run_sql(query) for key in res: dic[key[0]] = 0 cit[key[0]] = [] ref[key[0]] = [] return [dic, cit, ref] def get_citation_informations(recid_list, config): """return une dictionary that contains the citation information of cds records """ begin_time = os.times()[4] d_reports_numbers = {} d_references_report_numbers = {} d_references_s = {} d_records_s = {} citation_informations = [] record_pri_number_tag = config.get(config.get("rank_method", "function"),"publication_primary_number_tag") record_add_number_tag = config.get(config.get("rank_method", "function"),"publication_aditional_number_tag") reference_number_tag = config.get(config.get("rank_method", "function"),"publication_reference_number_tag") reference_tag = config.get(config.get("rank_method", "function"),"publication_reference_tag") record_publication_info_tag = config.get(config.get("rank_method", "function"),"publication_info_tag") - + p_record_pri_number_tag = parse_tag(record_pri_number_tag) p_record_add_number_tag = parse_tag(record_add_number_tag) p_reference_number_tag = parse_tag(reference_number_tag) p_reference_tag = parse_tag(reference_tag) p_record_publication_info_tag = parse_tag(record_publication_info_tag) - + for recid in recid_list: xml = print_record(int(recid),'xm') rs = create_records(xml) recs = map((lambda x:x[0]), rs) l_report_numbers = [] for rec in recs: pri_report_number = record_get_field_values(rec, p_record_pri_number_tag[0], ind1=p_record_pri_number_tag[1], ind2=p_record_pri_number_tag[2], code=record_pri_number_tag[3]) add_report_numbers = record_get_field_values(rec, p_record_add_number_tag[0], ind1=p_record_add_number_tag[1], ind2=p_record_add_number_tag[2], code=record_add_number_tag[3]) if pri_report_number: l_report_numbers.extend(pri_report_number) if add_report_numbers: l_report_numbers.extend(add_report_numbers) d_reports_numbers[recid] = l_report_numbers reference_report_number = record_get_field_values(rec, p_reference_number_tag[0], ind1=p_reference_number_tag[1], ind2=p_reference_number_tag[2], code=p_reference_number_tag[3]) if reference_report_number: d_references_report_numbers[recid] = reference_report_number references_s = record_get_field_values(rec, p_reference_tag[0], ind1=p_reference_tag[1], ind2=p_reference_tag[2], code=p_reference_tag[3]) if references_s: d_references_s[recid] = references_s record_s = record_get_field_values(rec, p_record_publication_info_tag[0], ind1=p_record_publication_info_tag[1], ind2=p_record_publication_info_tag[2], code=p_record_publication_info_tag[3]) if record_s: d_records_s[recid] = record_s[0] citation_informations.append(d_reports_numbers) citation_informations.append(d_references_report_numbers) citation_informations.append(d_references_s) citation_informations.append(d_records_s) end_time = os.times()[4] print "Execution time for generating citation inforamtions by parsing xml contents: ", (end_time - begin_time) return citation_informations def ref_analyzer(citation_informations, initialresult, initial_citationlist, initial_referencelist): """Analyze the citation informations and calculate the citation weight and cited by list dictionary """ citation_list = initial_citationlist reference_list = initial_referencelist result = initialresult d_reports_numbers = citation_informations[0] d_references_report_numbers = citation_informations[1] d_references_s = citation_informations[2] d_records_s = citation_informations[3] t1 = os.times()[4] for recid, refnumbers in d_references_report_numbers.iteritems(): for refnumber in refnumbers: p = refnumber f = 'reportnumber' rec_id = get_recids_matching_query(p, f) if rec_id: result[rec_id[0]] += 1 citation_list[rec_id[0]].append(recid) reference_list[recid].append(rec_id[0]) t2 = os.times()[4] for recid, refss in d_references_s.iteritems(): for refs in refss: p = refs f = 'publref' rec_id = get_recids_matching_query(p, f) if rec_id and not recid in citation_list[rec_id[0]]: result[rec_id[0]] += 1 citation_list[rec_id[0]].append(recid) if rec_id and not rec_id[0] in reference_list[recid]: reference_list[recid].append(rec_id[0]) t3 = os.times()[4] for rec_id, recnumbers in d_reports_numbers.iteritems(): for recnumber in recnumbers: p = recnumber f = '999C5r' recid_list = get_recids_matching_query(p, f) if recid_list: for recid in recid_list: if not recid in citation_list[rec_id]: result[rec_id] += 1 citation_list[rec_id].append(recid) if not rec_id in reference_list[recid]: reference_list[recid].append(rec_id) t4 = os.times()[4] for recid, recs in d_records_s.iteritems(): tmp = recs.find("-") if tmp < 0: recs_modified = recs else: recs_modified = recs[:tmp] p = recs_modified f = '999C5s' rec_ids = get_recids_matching_query(p, f) if rec_ids: for rec_id in rec_ids: if not rec_id in citation_list[recid]: result[recid] += 1 citation_list[recid].append(rec_id) if not recid in reference_list[rec_id]: reference_list[rec_id].append(recid) t5 = os.times()[4] insert_cit_ref_list_intodb(citation_list, reference_list) print "\nExecution time for analizing the citation information generating the dictionary: " print "checking ref number: ", (t2-t1) print "checking ref ypvt: ", (t3-t2) print "checking rec number: ", (t4-t3) print "checking rec ypvt: ", (t5-t4) print "total time of refAnalize: ", (t5-t1) return result def get_decompressed_xml(xml): """return a decompressed content of xml into a xml content """ decompressed_xml = create_records(decompress(xml)) return decompressed_xml def insert_cit_ref_list_intodb(citation_dic, reference_dic): """Insert the reference and citation list into the database""" date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) id = run_sql("SELECT * from rnkCITATIONDATA ") if id: run_sql("update rnkCITATIONDATA set citation_data_reversed = '%s'"% (get_compressed_dictionary(reference_dic))) run_sql("update rnkCITATIONDATA set citation_data = '%s'" % (get_compressed_dictionary(citation_dic))) else: run_sql("INSERT INTO rnkCITATIONDATA VALUES ('%s', null)" % (get_compressed_dictionary(citation_dic))) run_sql("update rnkCITATIONDATA set citation_data_reversed = '%s'"% (get_compressed_dictionary(reference_dic))) - + def get_compressed_dictionary(dic): """Serialize Python object vi a marshal into a compressed string.""" - return escape_string(compress(dumps(dic))) + return escape_string(compress(marshal.dumps(dic))) diff --git a/modules/bibrank/lib/bibrank_citation_searcher.py b/modules/bibrank/lib/bibrank_citation_searcher.py index c8ed85800..e6988e24b 100644 --- a/modules/bibrank/lib/bibrank_citation_searcher.py +++ b/modules/bibrank/lib/bibrank_citation_searcher.py @@ -1,112 +1,112 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" -from marshal import loads +import marshal from zlib import decompress from invenio.dbquery import run_sql, OperationalError def init_cited_by_dictionary(): """return citation list dictionary from rnkCITATIONDATA """ query = "select citation_data from rnkCITATIONDATA" try: compressed_citation_dic = run_sql(query) except OperationalError: compressed_citation_dic = [] citation_dic = None if compressed_citation_dic and compressed_citation_dic[0]: - citation_dic = loads(decompress(compressed_citation_dic[0][0])) + citation_dic = marshal.loads(decompress(compressed_citation_dic[0][0])) return citation_dic def init_reference_list_dictionary(): """return reference list dictionary from rnkCITATIONDATA """ query = "select citation_data_reversed from rnkCITATIONDATA" try: compressed_ref_dic = run_sql(query) except OperationalError: compressed_ref_dic = [] ref_dic = None if compressed_ref_dic and compressed_ref_dic[0]: - ref_dic = loads(decompress(compressed_ref_dic[0][0])) + ref_dic = marshal.loads(decompress(compressed_ref_dic[0][0])) return ref_dic cache_cited_by_dictionary = init_cited_by_dictionary() cache_reference_list_dictionary = init_reference_list_dictionary() ### INTERFACE def calculate_cited_by_list(record_id, sort_order="d"): """Return a tuple of ([recid,citation_weight],...) for all the record in citing RECORD_ID. The resulting recids is sorted by ascending/descending citation weights depending or SORT_ORDER. """ citation_list = [] result = [] # determine which record cite RECORD_ID: if cache_cited_by_dictionary: citation_list = cache_cited_by_dictionary.get(record_id, []) # get their weights: query = "select relevance_data from rnkMETHODDATA, rnkMETHOD WHERE rnkMETHOD.id=rnkMETHODDATA.id_rnkMETHOD and rnkMETHOD.name='cit'" compressed_citation_weight_dic = run_sql(query) if compressed_citation_weight_dic and compressed_citation_weight_dic[0]: - citation_dic = loads(decompress(compressed_citation_weight_dic[0][0])) + citation_dic = marshal.loads(decompress(compressed_citation_weight_dic[0][0])) for id in citation_list: tmp = [id, citation_dic[id]] result.append(tmp) # sort them: if result: if sort_order == "d": result.sort(lambda x, y: cmp(y[1], x[1])) else: result.sort(lambda x, y: cmp(x[1], y[1])) return result def calculate_co_cited_with_list(record_id, sort_order="d"): """Return a tuple of ([recid,co-cited weight],...) for records that are co-cited with RECORD_ID. The resulting recids is sorted by ascending/descending citation weights depending or SORT_ORDER. """ result = [] result_intermediate = {} citation_list = [] if cache_cited_by_dictionary: citation_list = cache_cited_by_dictionary.get(record_id, []) for cit_id in citation_list: reference_list = [] if cache_reference_list_dictionary: reference_list = cache_reference_list_dictionary.get(cit_id, []) for ref_id in reference_list: if not result_intermediate.has_key(ref_id): result_intermediate[ref_id] = 1 else: result_intermediate[ref_id] += 1 for key, value in result_intermediate.iteritems(): if not (key==record_id): result.append([key, value]) if result: if sort_order == "d": result.sort(lambda x, y: cmp(y[1], x[1])) else: result.sort(lambda x, y: cmp(x[1], y[1])) return result diff --git a/modules/bibrank/lib/bibrank_record_sorter_tests.py b/modules/bibrank/lib/bibrank_record_sorter_tests.py index 49174db4e..0a88636cf 100644 --- a/modules/bibrank/lib/bibrank_record_sorter_tests.py +++ b/modules/bibrank/lib/bibrank_record_sorter_tests.py @@ -1,56 +1,56 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """Unit tests for the ranking engine.""" __revision__ = "$Id$" import unittest from invenio import bibrank_record_sorter from invenio.search_engine import HitSet class TestListSetOperations(unittest.TestCase): """Test list set operations.""" def test_record_sorter(self): """bibrank record sorter - sorting records""" hitset = HitSet() hitset.addlist((1,2,5)) hitset2 = HitSet() hitset2.add(5) rec_termcount = {1: 1, 2: 1, 5: 1} (res1, res2) = bibrank_record_sorter.sort_record_relevance({1: 50, 2:30, 3:70,4:10},rec_termcount,hitset, 50,0) self.assertEqual(([(1, 71), (3, 100)], hitset2.tolist()), (res1, res2.tolist())) - + def test_calculate_record_relevance(self): """bibrank record sorter - calculating relevances""" hitset = HitSet() hitset.addlist((1,2,5)) - self.assertEqual(({1: 7, 2: 7, 5: 5}, {1: 1, 2: 1, 5: 1}), bibrank_record_sorter.calculate_record_relevance(("testterm", 2.0), + self.assertEqual(({1: 7, 2: 7, 5: 5}, {1: 1, 2: 1, 5: 1}), bibrank_record_sorter.calculate_record_relevance(("testterm", 2.0), {"Gi":(0, 50.0), 1: (3, 4.0), 2: (4, 5.0), 5: (1, 3.5)}, hitset, {}, {}, 0, None)) def create_test_suite(): """Return test suite for the indexing engine.""" return unittest.TestSuite((unittest.makeSuite(TestListSetOperations,'test'),)) if __name__ == "__main__": unittest.TextTestRunner(verbosity=2).run(create_test_suite()) diff --git a/modules/bibrank/lib/bibrank_tag_based_indexer.py b/modules/bibrank/lib/bibrank_tag_based_indexer.py index 4d421fec8..4302a083f 100644 --- a/modules/bibrank/lib/bibrank_tag_based_indexer.py +++ b/modules/bibrank/lib/bibrank_tag_based_indexer.py @@ -1,615 +1,615 @@ # -*- coding: utf-8 -*- ## $Id$ ## Ranking of records using different parameters and methods. ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" -from marshal import loads,dumps +import marshal from zlib import compress,decompress from string import split,translate,lower,upper import getopt import getpass import string import os import sre import sys import time import Numeric import urllib import signal import tempfile import unicodedata import traceback import cStringIO import re import copy import types import ConfigParser from invenio.config import \ CFG_MAX_RECID, \ cdslang, \ etcdir, \ version -from invenio.search_engine import perform_request_search, strip_accents -from invenio.search_engine import HitSet, get_index_id, create_basic_search_units +from invenio.search_engine import perform_request_search, strip_accents, HitSet +from invenio.search_engine import get_index_id, create_basic_search_units from invenio.bibrank_citation_indexer import get_citation_weight from invenio.bibrank_downloads_indexer import * from invenio.dbquery import run_sql, escape_string options = {} def citation_exec(rank_method_code, name, config): """Creating the rank method data for citation""" dict = get_citation_weight(rank_method_code, config) date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) if dict: intoDB(dict, date, rank_method_code) else: print "no need to update the indexes for citations" def single_tag_rank_method_exec(rank_method_code, name, config): """Creating the rank method data""" startCreate = time.time() rnkset = {} rnkset_old = fromDB(rank_method_code) date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) rnkset_new = single_tag_rank(config) rnkset = union_dicts(rnkset_old, rnkset_new) intoDB(rnkset, date, rank_method_code) def download_weight_filtering_user(row,run): return bibrank_engine(row,run) def download_weight_total(row,run): return bibrank_engine(row,run) def file_similarity_by_times_downloaded(row,run): return bibrank_engine(row,run) def download_weight_filtering_user_exec (rank_method_code, name, config): """Ranking by number of downloads per User. Only one full Text Download is taken in account for one specific userIP address""" time1 = time.time() dic = fromDB(rank_method_code) last_updated = get_lastupdated(rank_method_code) keys = new_downloads_to_index(last_updated) filter_downloads_per_hour(keys,last_updated) dic = get_download_weight_filtering_user(dic, keys) date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) intoDB(dic, date, rank_method_code) time2 = time.time() return {"time":time2-time1} def download_weight_total_exec(rank_method_code, name, config): """rankink by total number of downloads without check the user ip if users downloads 3 time the same full text document it has to be count as 3 downloads""" time1 = time.time() dic = fromDB(rank_method_code) last_updated = get_lastupdated(rank_method_code) keys = new_downloads_to_index(last_updated) filter_downloads_per_hour(keys,last_updated) dic = get_download_weight_total(dic, keys) date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) intoDB(dic, date, rank_method_code) time2 = time.time() return {"time":time2-time1} def file_similarity_by_times_downloaded_exec(rank_method_code, name, config): """update dictionnary {recid:[(recid,nb page similarity),()..]}""" time1 = time.time() dic = fromDB(rank_method_code) last_updated = get_lastupdated(rank_method_code) keys = new_downloads_to_index(last_updated) filter_downloads_per_hour(keys,last_updated) dic = get_file_similarity_by_times_downloaded(dic, keys) date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) intoDB(dic, date, rank_method_code) time2 = time.time() return {"time":time2-time1} def single_tag_rank_method_exec(rank_method_code, name, config): """Creating the rank method data""" startCreate = time.time() rnkset = {} rnkset_old = fromDB(rank_method_code) date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) rnkset_new = single_tag_rank(config) rnkset = union_dicts(rnkset_old, rnkset_new) intoDB(rnkset, date, rank_method_code) def single_tag_rank(config): """Connect the given tag with the data from the kb file given""" if options["verbose"] >= 9: write_message("Loading knowledgebase file") kb_data = {} records = [] write_message("Reading knowledgebase file: %s" % config.get(config.get("rank_method", "function"), "kb_src")) input = open(config.get(config.get("rank_method", "function"), "kb_src"), 'r') data = input.readlines() for line in data: if not line[0:1] == "#": kb_data[string.strip((string.split(string.strip(line),"---"))[0])] = (string.split(string.strip(line), "---"))[1] write_message("Number of lines read from knowledgebase file: %s" % len(kb_data)) tag = config.get(config.get("rank_method", "function"),"tag") tags = split(config.get(config.get("rank_method", "function"), "check_mandatory_tags"),",") if tags == ['']: tags = "" - + records = [] for (recids,recide) in options["recid_range"]: write_message("......Processing records #%s-%s" % (recids, recide)) recs = run_sql("SELECT id_bibrec,value FROM bib%sx,bibrec_bib%sx WHERE tag='%s' AND id_bibxxx=id and id_bibrec >=%s and id_bibrec<=%s" % (tag[0:2], tag[0:2], tag, recids, recide)) valid = HitSet(Numeric.ones(CFG_MAX_RECID + 1)) for key in tags: newset = HitSet() newset.addlist(run_sql("SELECT id_bibrec FROM bib%sx,bibrec_bib%sx WHERE id_bibxxx=id AND tag='%s' AND id_bibxxx=id and id_bibrec >=%s and id_bibrec<=%s" % (tag[0:2], tag[0:2], key, recids, recide))) valid.intersect(newset) if tags: recs = filter(lambda x: valid.contains(x[0]), recs) records = records + list(recs) write_message("Number of records found with the necessary tags: %s" % len(records)) records = filter(lambda x: options["validset"].contains(x[0]), records) rnkset = {} for key,value in records: if kb_data.has_key(value): if not rnkset.has_key(key): rnkset[key] = float(kb_data[value]) else: if kb_data.has_key(rnkset[key]) and float(kb_data[value]) > float((rnkset[key])[1]): rnkset[key] = float(kb_data[value]) else: rnkset[key] = 0 write_message("Number of records available in rank method: %s" % len(rnkset)) return rnkset def get_lastupdated(rank_method_code): """Get the last time the rank method was updated""" res = run_sql("SELECT rnkMETHOD.last_updated FROM rnkMETHOD WHERE name='%s'" % rank_method_code) if res: return res[0][0] else: raise Exception("Is this the first run? Please do a complete update.") def intoDB(dict, date, rank_method_code): """Insert the rank method data into the database""" id = run_sql("SELECT id from rnkMETHOD where name='%s'" % rank_method_code) del_rank_method_codeDATA(rank_method_code) run_sql("INSERT INTO rnkMETHODDATA(id_rnkMETHOD, relevance_data) VALUES ('%s','%s')" % (id[0][0], serialize_via_marshal(dict))) run_sql("UPDATE rnkMETHOD SET last_updated='%s' WHERE name='%s'" % (date, rank_method_code)) def fromDB(rank_method_code): """Get the data for a rank method""" id = run_sql("SELECT id from rnkMETHOD where name='%s'" % rank_method_code) res = run_sql("SELECT relevance_data FROM rnkMETHODDATA WHERE id_rnkMETHOD=%s" % id[0][0]) if res: return deserialize_via_marshal(res[0][0]) else: return {} def del_rank_method_codeDATA(rank_method_code): """Delete the data for a rank method""" id = run_sql("SELECT id from rnkMETHOD where name='%s'" % rank_method_code) res = run_sql("DELETE FROM rnkMETHODDATA WHERE id_rnkMETHOD=%s" % id[0][0]) def del_recids(rank_method_code, range_rec): """Delete some records from the rank method""" id = run_sql("SELECT id from rnkMETHOD where name='%s'" % rank_method_code) res = run_sql("SELECT relevance_data FROM rnkMETHODDATA WHERE id_rnkMETHOD=%s" % id[0][0]) if res: rec_dict = deserialize_via_marshal(res[0][0]) write_message("Old size: %s" % len(rec_dict)) for (recids,recide) in range_rec: for i in range(int(recids), int(recide)): if rec_dict.has_key(i): - del rec_dict[i] + del rec_dict[i] write_message("New size: %s" % len(rec_dict)) date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) intoDB(rec_dict, date, rank_method_code) else: print "Create before deleting!" - + def union_dicts(dict1, dict2): "Returns union of the two dicts." union_dict = {} for (key, value) in dict1.iteritems(): union_dict[key] = value for (key, value) in dict2.iteritems(): union_dict[key] = value return union_dict def rank_method_code_statistics(rank_method_code): """Print statistics""" - - method = fromDB(rank_method_code) + + method = fromDB(rank_method_code) max = ('',-999999) maxcount = 0 min = ('',999999) mincount = 0 for (recID, value) in method.iteritems(): if value < min and value > 0: min = value if value > max: max = value - + for (recID, value) in method.iteritems(): if value == min: mincount += 1 if value == max: maxcount += 1 write_message("Showing statistic for selected method") write_message("Method name: %s" % getName(rank_method_code)) write_message("Short name: %s" % rank_method_code) write_message("Last run: %s" % get_lastupdated(rank_method_code)) write_message("Number of records: %s" % len(method)) write_message("Lowest value: %s - Number of records: %s" % (min, mincount)) write_message("Highest value: %s - Number of records: %s" % (max, maxcount)) write_message("Divided into 10 sets:") for i in range(1,11): setcount = 0 distinct_values = {} lower = -1.0 + ((float(max + 1) / 10)) * (i - 1) upper = -1.0 + ((float(max + 1) / 10)) * i for (recID, value) in method.iteritems(): if value >= lower and value <= upper: setcount += 1 distinct_values[value] = 1 - write_message("Set %s (%s-%s) %s Distinct values: %s" % (i, lower, upper, len(distinct_values), setcount)) + write_message("Set %s (%s-%s) %s Distinct values: %s" % (i, lower, upper, len(distinct_values), setcount)) def check_method(rank_method_code): write_message("Checking rank method...") if len(fromDB(rank_method_code)) == 0: write_message("Rank method not yet executed, please run it to create the necessary data.") else: if len(add_recIDs_by_date(rank_method_code)) > 0: write_message("Records modified, update recommended") else: write_message("No records modified, update not necessary") - + def write_message(msg, stream = sys.stdout): """Write message and flush output stream (may be sys.stdout or sys.stderr). Useful for debugging stuff.""" if stream == sys.stdout or stream == sys.stderr: stream.write(time.strftime("%Y-%m-%d %H:%M:%S --> ", time.localtime())) try: stream.write("%s\n" % msg) except UnicodeEncodeError: stream.write("%s\n" % msg.encode('ascii', 'backslashreplace')) stream.flush() else: sys.stderr.write("Unknown stream %s. [must be sys.stdout or sys.stderr]\n" % stream) return def get_datetime(var, format_string="%Y-%m-%d %H:%M:%S"): """Returns a date string according to the format string. It can handle normal date strings and shifts with respect to now.""" date = time.time() shift_re = sre.compile("([-\+]{0,1})([\d]+)([dhms])") factors = {"d":24*3600, "h":3600, "m":60, "s":1} m = shift_re.match(var) if m: sign = m.groups()[0] == "-" and -1 or 1 factor = factors[m.groups()[2]] value = float(m.groups()[1]) date = time.localtime(date + sign * factor * value) date = time.strftime(format_string, date) else: date = time.strptime(var, format_string) date = time.strftime(format_string, date) return date def task_sig_sleep(sig, frame): """Signal handler for the 'sleep' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_sleep(), got signal %s frame %s" % (sig, frame)) write_message("sleeping...") task_update_status("SLEEPING") signal.pause() # wait for wake-up signal def task_sig_wakeup(sig, frame): """Signal handler for the 'wakeup' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_wakeup(), got signal %s frame %s" % (sig, frame)) write_message("continuing...") task_update_status("CONTINUING") def task_sig_stop(sig, frame): """Signal handler for the 'stop' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_stop(), got signal %s frame %s" % (sig, frame)) write_message("stopping...") task_update_status("STOPPING") errcode = 0 try: task_sig_stop_commands() write_message("stopped") task_update_status("STOPPED") except StandardError, err: write_message("Error during stopping! %e" % err) task_update_status("STOPPINGFAILED") errcode = 1 sys.exit(errcode) def task_sig_stop_commands(): """Do all the commands necessary to stop the task before quitting. Useful for task_sig_stop() handler. """ write_message("stopping commands started") write_message("stopping commands ended") def task_sig_suicide(sig, frame): """Signal handler for the 'suicide' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_suicide(), got signal %s frame %s" % (sig, frame)) write_message("suiciding myself now...") task_update_status("SUICIDING") write_message("suicided") task_update_status("SUICIDED") sys.exit(0) def task_sig_unknown(sig, frame): """Signal handler for the other unknown signals sent by shell or user.""" # do nothing for unknown signals: - write_message("unknown signal %d (frame %s) ignored" % (sig, frame)) + write_message("unknown signal %d (frame %s) ignored" % (sig, frame)) def task_update_progress(msg): """Updates progress information in the BibSched task table.""" query = "UPDATE schTASK SET progress='%s' where id=%d" % (escape_string(msg), options["task"]) if options["verbose"]>= 9: write_message(query) run_sql(query) return def task_update_status(val): """Updates state information in the BibSched task table.""" query = "UPDATE schTASK SET status='%s' where id=%d" % (escape_string(val), options["task"]) if options["verbose"]>= 9: write_message(query) run_sql(query) return def split_ranges(parse_string): recIDs = [] ranges = string.split(parse_string, ",") for arange in ranges: tmp_recIDs = string.split(arange, "-") - + if len(tmp_recIDs)==1: recIDs.append([int(tmp_recIDs[0]), int(tmp_recIDs[0])]) else: if int(tmp_recIDs[0]) > int(tmp_recIDs[1]): # sanity check tmp = tmp_recIDs[0] tmp_recIDs[0] = tmp_recIDs[1] tmp_recIDs[1] = tmp recIDs.append([int(tmp_recIDs[0]), int(tmp_recIDs[1])]) return recIDs def bibrank_engine(row, run): """Run the indexing task. The row argument is the BibSched task queue row, containing if, arguments, etc. Return 1 in case of success and 0 in case of failure. """ - + try: import psyco - psyco.bind(single_tag_rank) + psyco.bind(single_tag_rank) psyco.bind(single_tag_rank_method_exec) psyco.bind(serialize_via_numeric_array) psyco.bind(deserialize_via_numeric_array) - except StandardError, e: - print "Psyco ERROR",e + except StandardError, e: + print "Psyco ERROR",e startCreate = time.time() global options task_id = row[0] task_proc = row[1] - options = loads(row[6]) + options = marshal.loads(row[6]) task_starting_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) signal.signal(signal.SIGUSR1, task_sig_sleep) signal.signal(signal.SIGTERM, task_sig_stop) signal.signal(signal.SIGABRT, task_sig_suicide) signal.signal(signal.SIGCONT, task_sig_wakeup) signal.signal(signal.SIGINT, task_sig_unknown) sets = {} try: options["run"] = [] options["run"].append(run) for rank_method_code in options["run"]: cfg_name = getName(rank_method_code) if options["verbose"] >= 0: write_message("Running rank method: %s." % cfg_name) file = etcdir + "/bibrank/" + rank_method_code + ".cfg" config = ConfigParser.ConfigParser() try: config.readfp(open(file)) except StandardError, e: write_message("Cannot find configurationfile: %s" % file, sys.stderr) raise StandardError cfg_short = rank_method_code cfg_function = config.get("rank_method", "function") + "_exec" cfg_name = getName(cfg_short) options["validset"] = get_valid_range(rank_method_code) if options["collection"]: l_of_colls = string.split(options["collection"], ",") recIDs = perform_request_search(c=l_of_colls) recIDs_range = [] for recID in recIDs: recIDs_range.append([recID,recID]) options["recid_range"] = recIDs_range elif options["id"]: options["recid_range"] = options["id"] elif options["modified"]: options["recid_range"] = add_recIDs_by_date(rank_method_code, options["modified"]) elif options["last_updated"]: options["recid_range"] = add_recIDs_by_date(rank_method_code) else: if options["verbose"] > 1: write_message("No records specified, updating all") min_id = run_sql("SELECT min(id) from bibrec")[0][0] max_id = run_sql("SELECT max(id) from bibrec")[0][0] - options["recid_range"] = [[min_id, max_id]] + options["recid_range"] = [[min_id, max_id]] if options["quick"] == "no" and options["verbose"] >= 9: write_message("Recalculate parameter not used, parameter ignored.") if options["cmd"] == "del": del_recids(cfg_short, options["recid_range"]) elif options["cmd"] == "add": func_object = globals().get(cfg_function) func_object(rank_method_code, cfg_name, config) elif options["cmd"] == "stat": rank_method_code_statistics(rank_method_code) elif options["cmd"] == "check": check_method(rank_method_code) elif options["cmd"] == "repair": pass else: write_message("Invalid command found processing %s" % rank_method_code, sys.stderr) raise StandardError except StandardError, e: write_message("\nException caught: %s" % e, sys.stderr) - if options["verbose"] >= 9: + if options["verbose"] >= 9: traceback.print_tb(sys.exc_info()[2]) raise StandardError if options["verbose"]: showtime((time.time() - startCreate)) return 1 def get_valid_range(rank_method_code): """Return a range of records""" if options["verbose"] >=9: write_message("Getting records from collections enabled for rank method.") res = run_sql("SELECT collection.name FROM collection,collection_rnkMETHOD,rnkMETHOD WHERE collection.id=id_collection and id_rnkMETHOD=rnkMETHOD.id and rnkMETHOD.name='%s'" % rank_method_code) l_of_colls = [] for coll in res: l_of_colls.append(coll[0]) if len(l_of_colls) > 0: recIDs = perform_request_search(c=l_of_colls) else: recIDs = [] valid = HitSet() valid.addlist(recIDs) return valid - + def add_recIDs_by_date(rank_method_code, dates=""): """Return recID range from records modified between DATES[0] and DATES[1]. If DATES is not set, then add records modified since the last run of the ranking method RANK_METHOD_CODE. """ if not dates: try: dates = (get_lastupdated(rank_method_code),'') except Exception, e: dates = ("0000-00-00 00:00:00", '') query = """SELECT b.id FROM bibrec AS b WHERE b.modification_date >= '%s'""" % dates[0] if dates[1]: query += "and b.modification_date <= '%s'" % dates[1] query += "ORDER BY b.id ASC""" - res = run_sql(query) + res = run_sql(query) list = create_range_list(res) if not list: if options["verbose"]: write_message("No new records added since last time method was run") return list def getName(rank_method_code, ln=cdslang, type='ln'): """Returns the name of the method if it exists""" try: rnkid = run_sql("SELECT id FROM rnkMETHOD where name='%s'" % rank_method_code) if rnkid: rnkid = str(rnkid[0][0]) res = run_sql("SELECT value FROM rnkMETHODNAME where type='%s' and ln='%s' and id_rnkMETHOD=%s" % (type, ln, rnkid)) if not res: res = run_sql("SELECT value FROM rnkMETHODNAME WHERE ln='%s' and id_rnkMETHOD=%s and type='%s'" % (cdslang, rnkid, type)) - if not res: + if not res: return rank_method_code return res[0][0] else: raise Exception except Exception, e: write_message("Cannot run rank method, either given code for method is wrong, or it has not been added using the webinterface.") raise Exception def create_range_list(res): """Creates a range list from a recID select query result contained in res. The result is expected to have ascending numerical order.""" if not res: return [] row = res[0] if not row: return [] else: range_list = [[row[0],row[0]]] for row in res[1:]: id = row[0] if id == range_list[-1][1] + 1: range_list[-1][1] = id else: range_list.append([id,id]) return range_list def single_tag_rank_method(row, run): return bibrank_engine(row, run) def serialize_via_numeric_array_dumps(arr): return Numeric.dumps(arr) def serialize_via_numeric_array_compr(str): return compress(str) def serialize_via_numeric_array_escape(str): return escape_string(str) def serialize_via_numeric_array(arr): """Serialize Numeric array into a compressed string.""" return serialize_via_numeric_array_escape(serialize_via_numeric_array_compr(serialize_via_numeric_array_dumps(arr))) def deserialize_via_numeric_array(string): """Decompress and deserialize string into a Numeric array.""" return Numeric.loads(decompress(string)) def serialize_via_marshal(obj): """Serialize Python object via marshal into a compressed string.""" - return escape_string(compress(dumps(obj))) + return escape_string(compress(marshal.dumps(obj))) def deserialize_via_marshal(string): """Decompress and deserialize string into a Python object via marshal.""" - return loads(decompress(string)) + return marshal.loads(decompress(string)) def showtime(timeused): """Show time used for method""" if options["verbose"] >= 9: write_message("Time used: %d second(s)." % timeused) def citation(row,run): return bibrank_engine(row, run) diff --git a/modules/bibrank/lib/bibrankadminlib.py b/modules/bibrank/lib/bibrankadminlib.py index cef3bfca3..1a2a83abf 100644 --- a/modules/bibrank/lib/bibrankadminlib.py +++ b/modules/bibrank/lib/bibrankadminlib.py @@ -1,1072 +1,1072 @@ ## $Id$ ## Administrator interface for BibRank ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. ## ## Youshould 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. """CDS Invenio BibRank Administrator Interface.""" __revision__ = "$Id$" import cgi import re import Numeric import os import ConfigParser from zlib import compress,decompress import marshal from mod_python import apache from invenio.config import \ cdslang, \ etcdir, \ version, \ weburl import invenio.access_control_engine as acce from invenio.messages import language_list_long from invenio.dbquery import run_sql, escape_string from invenio.webpage import page, pageheaderonly, pagefooteronly from invenio.webuser import getUid, get_email def getnavtrail(previous = ''): navtrail = """Admin Area > BibRank Admin """ % (weburl, weburl) navtrail = navtrail + previous return navtrail -def check_user(uid, role, adminarea=2, authorized=0): - (auth_code, auth_message) = is_adminuser(uid, role) +def check_user(req, role, adminarea=2, authorized=0): + (auth_code, auth_message) = is_adminuser(req, role) if not authorized and auth_code != 0: return ("false", auth_message) return ("", auth_message) - -def is_adminuser(uid, role): + +def is_adminuser(req, role): """check if user is a registered administrator. """ - return acce.acc_authorize_action(uid, role) + return acce.acc_authorize_action(req, role) def perform_index(ln=cdslang): """create the bibrank main area menu page.""" - + header = ['Code', 'Translations', 'Collections', 'Rank method'] rnk_list = get_def_name('', "rnkMETHOD") actions = [] - + for (rnkID, name) in rnk_list: actions.append([name]) - + for col in [(('Modify', 'modifytranslations'),), (('Modify', 'modifycollection'),), (('Show Details', 'showrankdetails'), ('Modify', 'modifyrank'), ('Delete', 'deleterank'))]: actions[-1].append('%s' % (weburl, col[0][1], rnkID, ln, col[0][0])) for (str, function) in col[1:]: actions[-1][-1] += ' / %s' % (weburl, function, rnkID, ln, str) output = """ Add new rank method

""" % (weburl, ln) - + output += tupletotable(header=header, tuple=actions) return addadminbox("""Overview of rank methods   [?]""" % weburl, datalist=[output, '']) def perform_modifycollection(rnkID='', ln=cdslang, func='', colID='', confirm=0): """Modify which collections the rank method is visible to""" - + output = "" subtitle = "" if rnkID: rnkNAME = get_def_name(rnkID, "rnkMETHOD")[0][1] if func in ["0", 0] and confirm in ["1", 1]: finresult = attach_col_rnk(rnkID, colID) elif func in ["1", 1] and confirm in ["1", 1]: finresult = detach_col_rnk(rnkID, colID) if colID: colNAME = get_def_name(colID, "collection")[0][1] subtitle = """Step 1 - Select collection to enable/disable rank method '%s' for""" % rnkNAME output = """
The rank method is currently enabled for these collections:
""" col_list = get_rnk_col(rnkID, ln) if not col_list: output += """No collections""" else: for (id, name) in col_list: output += """%s, """ % name output += """
""" - + col_list = get_def_name('', "collection") col_rnk = dict(get_rnk_col(rnkID)) col_list = filter(lambda x: not col_rnk.has_key(x[0]), col_list) if col_list: text = """ Enable for: """ output += createhiddenform(action="modifycollection", text=text, button="Enable", rnkID=rnkID, ln=ln, func=0, confirm=1) if confirm in ["0", 0] and func in ["0", 0] and colID: subtitle = "Step 2 - Confirm to enable rank method for the chosen collection" text = "

Please confirm to enable rank method '%s' for the collection '%s'

" % (rnkNAME, colNAME) output += createhiddenform(action="modifycollection", text=text, button="Confirm", rnkID=rnkID, ln=ln, colID=colID, func=0, confirm=1) elif confirm in ["1", 1] and func in ["0", 0] and colID: subtitle = "Step 3 - Result" output += write_outcome(finresult) elif confirm not in ["0", 0] and func in ["0", 0]: output += """Please select a collection.""" - + col_list = get_rnk_col(rnkID, ln) if col_list: text = """ Disable for: """ output += createhiddenform(action="modifycollection", text=text, button="Disable", rnkID=rnkID, ln=ln, func=1, confirm=1) - + if confirm in ["1", 1] and func in ["1", 1] and colID: subtitle = "Step 3 - Result" output += write_outcome(finresult) elif confirm not in ["0", 0] and func in ["1", 1]: output += """Please select a collection.""" body = [output] - + return addadminbox(subtitle + """   [?]""" % weburl, body) def perform_modifytranslations(rnkID, ln, sel_type, trans, confirm, callback='yes'): """Modify the translations of a rank method""" - + output = '' subtitle = '' cdslangs = get_languages() cdslangs.sort() - + if confirm in ["2", 2] and rnkID: finresult = modify_translations(rnkID, cdslangs, sel_type, trans, "rnkMETHOD") - + rnk_name = get_def_name(rnkID, "rnkMETHOD")[0][1] rnk_dict = dict(get_i8n_name('', ln, get_rnk_nametypes()[0][0], "rnkMETHOD")) if rnkID and rnk_dict.has_key(int(rnkID)): rnkID = int(rnkID) subtitle = """3. Modify translations for rank method '%s'""" % rnk_name - + if type(trans) is str: trans = [trans] if sel_type == '': sel_type = get_rnk_nametypes()[0][0] - + header = ['Language', 'Translation'] actions = [] - + text = """ Name type """ - + output += createhiddenform(action="modifytranslations", text=text, button="Select", rnkID=rnkID, ln=ln, confirm=0) if confirm in [-1, "-1", 0, "0"]: trans = [] for key, value in cdslangs: try: trans_names = get_name(rnkID, key, sel_type, "rnkMETHOD") trans.append(trans_names[0][0]) except StandardError, e: trans.append('') for nr in range(0,len(cdslangs)): actions.append(["%s %s" % (cdslangs[nr][1], (cdslangs[nr][0]==cdslang and '(def)' or ''))]) actions[-1].append('' % trans[nr]) text = tupletotable(header=header, tuple=actions) output += createhiddenform(action="modifytranslations", text=text, button="Modify", rnkID=rnkID, sel_type=sel_type, ln=ln, confirm=2) if sel_type and len(trans) and confirm in ["2", 2]: output += write_outcome(finresult) - + body = [output] return addadminbox(subtitle + """   [?]""" % weburl, body) - + def perform_addrankarea(rnkcode='', ln=cdslang, template='', confirm=-1): """form to add a new rank method with these values:""" - + subtitle = 'Step 1 - Create new rank method' output = """
BibRank code:
A unique code that identifies a rank method, is used when running the bibrank daemon and used to name the configuration file for the method.
The template files includes the necessary parameters for the chosen rank method, and only needs to be edited with the correct tags and paths.
For more information, please go to the BibRank guide and read the section about adding a rank method
""" % weburl text = """ BibRank code """ % (rnkcode) - + text += """
Cfg template """ - + output += createhiddenform(action="addrankarea", text=text, button="Add rank method", ln=ln, confirm=1) - + if rnkcode: if confirm in ["0", 0]: subtitle = 'Step 2 - Confirm addition of rank method' text = """Add rank method with BibRank code: '%s'.""" % (rnkcode) if template: text += """
Using configuration template: '%s'.""" % (template) else: text += """
Create empty configuration file.""" output += createhiddenform(action="addrankarea", text=text, rnkcode=rnkcode, button="Confirm", template=template, confirm=1) - + elif confirm in ["1", 1]: rnkID = add_rnk(rnkcode) subtitle = "Step 3 - Result" if rnkID[0] == 1: rnkID = rnkID[1] text = """Added new rank method with BibRank code '%s'""" % rnkcode try: if template: infile = open("%s/bibrank/%s" % (etcdir, template), 'r') indata = infile.readlines() infile.close() else: indata = () file = open("%s/bibrank/%s.cfg" % (etcdir, get_rnk_code(rnkID)[0][0]), 'w') for line in indata: file.write(line) file.close() if template: text += """
Configuration file created using '%s' as template.
""" % template else: text += """
Empty configuration file created.
""" except StandardError, e: text += """
Sorry, could not create configuration file: '%s/bibrank/%s.cfg', either because it already exists, or not enough rights to create file.
Please create the file in the path given.
""" % (etcdir, get_rnk_code(rnkID)[0][0]) - + else: text = """Sorry, could not add rank method, rank method with the same BibRank code probably exists.""" output += text elif not rnkcode and confirm not in [-1, "-1"]: output += """Sorry, could not add rank method, not enough data submitted.""" - + body = [output] return addadminbox(subtitle + """   [?]""" % weburl, body) - + def perform_modifyrank(rnkID, rnkcode='', ln=cdslang, template='', cfgfile='', confirm=0): """form to modify a rank method rnkID - id of the rank method """ - + if not rnkID: return "No ranking method selected." if not get_rnk_code(rnkID): return "Ranking method %s does not seem to exist." % str(rnkID) subtitle = 'Step 1 - Please modify the wanted values below' if not rnkcode: oldcode = get_rnk_code(rnkID)[0] else: oldcode = rnkcode output = """
When changing the BibRank code of a rank method, you must also change any scheduled tasks using the old value.
For more information, please go to the BibRank guide and read the section about modifying a rank method's BibRank code.
""" % weburl - + text = """ BibRank code
""" % (oldcode) - + try: text += """Cfg file""" textarea = "" if cfgfile: textarea +=cfgfile else: file = open("%s/bibrank/%s.cfg" % (etcdir, get_rnk_code(rnkID)[0][0])) for line in file.readlines(): textarea += line text += """""" except StandardError, e: text += """Cannot load file, either it does not exist, or not enough rights to read it: '%s/bibrank/%s.cfg'
Please create the file in the path given.
""" % (etcdir, get_rnk_code(rnkID)[0][0]) - + output += createhiddenform(action="modifyrank", text=text, rnkID=rnkID, button="Modify", confirm=1) - + if rnkcode and confirm in ["1", 1] and get_rnk_code(rnkID)[0][0] != rnkcode: oldcode = get_rnk_code(rnkID)[0][0] result = modify_rnk(rnkID, rnkcode) subtitle = "Step 3 - Result" if result: text = """Rank method modified.""" try: file = open("%s/bibrank/%s.cfg" % (etcdir, oldcode), 'r') file2 = open("%s/bibrank/%s.cfg" % (etcdir, rnkcode), 'w') lines = file.readlines() for line in lines: file2.write(line) file.close() file2.close() os.remove("%s/bibrank/%s.cfg" % (etcdir, oldcode)) except StandardError, e: text = """Sorry, could not change name of cfg file, must be done manually: '%s/bibrank/%s.cfg'""" % (etcdir, oldcode) else: text = """Sorry, could not modify rank method.""" output += text if cfgfile and confirm in ["1", 1]: try: file = open("%s/bibrank/%s.cfg" % (etcdir, get_rnk_code(rnkID)[0][0]), 'w') file.write(cfgfile) file.close() text = """
Configuration file modified: '%s/bibrank/%s.cfg'
""" % (etcdir, get_rnk_code(rnkID)[0][0]) except StandardError, e: text = """
Sorry, could not modify configuration file, please check for rights to do so: '%s/bibrank/%s.cfg'
Please modify the file manually.
""" % (etcdir, get_rnk_code(rnkID)[0][0]) output += text finoutput = addadminbox(subtitle + """   [?]""" % weburl, [output]) output = "" - + text = """ Select
""" output += createhiddenform(action="modifyrank", text=text, rnkID=rnkID, button="Show template", confirm=0) try: if template: textarea = "" - text = """Content:""" + text = """Content:""" file = open("%s/bibrank/%s" % (etcdir, template), 'r') lines = file.readlines() for line in lines: textarea += line file.close() text += """""" output += text except StandardError, e: output += """Cannot load file, either it does not exist, or not enough rights to read it: '%s/bibrank/%s'""" % (etcdir, template) finoutput += addadminbox("View templates", [output]) return finoutput def perform_deleterank(rnkID, ln=cdslang, confirm=0): """form to delete a rank method """ subtitle ='' output = """
WARNING:
When deleting a rank method, you also deletes all data related to the rank method, like translations, which collections it was attached to and the data necessary to rank the searchresults. Any scheduled tasks using the deleted rank method will also stop working.

For more information, please go to the BibRank guide and read the section regarding deleting a rank method.
""" % weburl - + if rnkID: if confirm in ["0", 0]: rnkNAME = get_def_name(rnkID, "rnkMETHOD")[0][1] subtitle = 'Step 1 - Confirm deletion' text = """Delete rank method '%s'.""" % (rnkNAME) output += createhiddenform(action="deleterank", text=text, button="Confirm", rnkID=rnkID, confirm=1) elif confirm in ["1", 1]: try: rnkNAME = get_def_name(rnkID, "rnkMETHOD")[0][1] rnkcode = get_rnk_code(rnkID)[0][0] table = "" try: config = ConfigParser.ConfigParser() config.readfp(open("%s/bibrank/%s.cfg" % (etcdir, rnkcode), 'r')) table = config.get(config.get('rank_method', "function"), "table") except Exception: pass result = delete_rnk(rnkID, table) subtitle = "Step 2 - Result" if result: text = """Rank method deleted""" try: os.remove("%s/bibrank/%s.cfg" % (etcdir, rnkcode)) text += """
Configuration file deleted: '%s/bibrank/%s.cfg'.""" % (etcdir, rnkcode) except StandardError, e: text += """
Sorry, could not delete configuration file: '%s/bibrank/%s.cfg'.
Please delete the file manually.
""" % (etcdir, rnkcode) else: text = """Sorry, could not delete rank method""" except StandardError, e: text = """Sorry, could not delete rank method, most likely already deleted""" output = text - + body = [output] return addadminbox(subtitle + """   [?]""" % weburl, body) def perform_showrankdetails(rnkID, ln=cdslang): """Returns details about the rank method given by rnkID""" if not rnkID: return "No ranking method selected." if not get_rnk_code(rnkID): return "Ranking method %s does not seem to exist." % str(rnkID) - + subtitle = """Overview [Modify]""" % (weburl, rnkID, ln) text = """ BibRank code: %s
Last updated by BibRank: """ % (get_rnk_code(rnkID)[0][0]) if get_rnk(rnkID)[0][2]: text += "%s
" % get_rnk(rnkID)[0][2] else: text += "Not yet run.
" output = addadminbox(subtitle, [text]) subtitle = """Rank method statistics""" text = "" try: text = "Not yet implemented" except StandardError, e: text = "BibRank not yet run, cannot show statistics for method" output += addadminbox(subtitle, [text]) subtitle = """Attached to collections [Modify]""" % (weburl, rnkID, ln) text = "" col = get_rnk_col(rnkID, ln) for key, value in col: text+= "%s
" % value if not col: text +="No collections" output += addadminbox(subtitle, [text]) subtitle = """Translations [Modify]""" % (weburl, rnkID, ln) prev_lang = '' trans = get_translations(rnkID) types = get_rnk_nametypes() types = dict(map(lambda x: (x[0], x[1]), types)) text = "" languages = dict(get_languages()) if trans: for lang, type, name in trans: if lang and languages.has_key(lang) and type and name: if prev_lang != lang: prev_lang = lang text += """%s:
""" % (languages[lang]) if types.has_key(type): text+= """'%s'(%s)
""" % (name, types[type]) else: text = """No translations exists""" output += addadminbox(subtitle, [text]) subtitle = """Configuration file: '%s/bibrank/%s.cfg' [Modify]""" % (etcdir, get_rnk_code(rnkID)[0][0], weburl, rnkID, ln) text = "" try: file = open("%s/bibrank/%s.cfg" % (etcdir, get_rnk_code(rnkID)[0][0])) text += """
"""
         for line in file.readlines():
             text += line
         text += """
""" except StandardError, e: text = """Cannot load file, either it does not exist, or not enough rights to read it.""" output += addadminbox(subtitle, [text]) return output def compare_on_val(second, first): return cmp(second[1], first[1]) def get_rnk_code(rnkID): """Returns the name from rnkMETHOD based on argument rnkID - id from rnkMETHOD""" - + try: res = run_sql("SELECT name FROM rnkMETHOD where id=%s" % (rnkID)) return res except StandardError, e: return () def get_rnk(rnkID=''): """Return one or all rank methods rnkID - return the rank method given, or all if not given""" - + try: if rnkID: res = run_sql("SELECT id,name,DATE_FORMAT(last_updated, '%%Y-%%m-%%d %%H:%%i:%%s') from rnkMETHOD WHERE id=%s" % rnkID) else: res = run_sql("SELECT id,name,DATE_FORMAT(last_updated, '%%Y-%%m-%%d %%H:%%i:%%s') from rnkMETHOD") return res except StandardError, e: return () def get_translations(rnkID): """Returns the translations in rnkMETHODNAME for a rankmethod rnkID - the id of the rankmethod from rnkMETHOD """ - + try: res = run_sql("SELECT ln, type, value FROM rnkMETHODNAME where id_rnkMETHOD=%s ORDER BY ln,type" % (rnkID)) return res except StandardError, e: return () - + def get_rnk_nametypes(): """Return a list of the various translationnames for the rank methods""" - + type = [] type.append(('ln', 'Long name')) #type.append(('sn', 'Short name')) return type def get_col_nametypes(): """Return a list of the various translationnames for the rank methods""" - + type = [] type.append(('ln', 'Long name')) return type def get_rnk_col(rnkID, ln=cdslang): """ Returns a list of the collections the given rank method is attached to rnkID - id from rnkMETHOD""" - + try: res1 = dict(run_sql("SELECT id_collection, '' FROM collection_rnkMETHOD WHERE id_rnkMETHOD=%s" % rnkID)) res2 = get_def_name('', "collection") result = filter(lambda x: res1.has_key(x[0]), res2) return result except StandardError, e: return () def get_templates(): """Read etcdir/bibrank and returns a list of all files with 'template' """ - + templates = [] files = os.listdir(etcdir + "/bibrank/") for file in files: if str.find(file,"template_") != -1: templates.append(file) return templates def attach_col_rnk(rnkID, colID): """attach rank method to collection rnkID - id from rnkMETHOD table colID - id of collection, as in collection table """ - + try: res = run_sql("INSERT INTO collection_rnkMETHOD(id_collection, id_rnkMETHOD) values (%s,%s)" % (colID, rnkID)) return (1, "") except StandardError, e: return (0, e) def detach_col_rnk(rnkID, colID): """detach rank method from collection rnkID - id from rnkMETHOD table colID - id of collection, as in collection table """ - + try: res = run_sql("DELETE FROM collection_rnkMETHOD WHERE id_collection=%s AND id_rnkMETHOD=%s" % (colID, rnkID)) return (1, "") except StandardError, e: return (0, e) def delete_rnk(rnkID, table=""): """Deletes all data for the given rank method rnkID - delete all data in the tables associated with ranking and this id """ - + try: res = run_sql("DELETE FROM rnkMETHOD WHERE id=%s" % rnkID) res = run_sql("DELETE FROM rnkMETHODNAME WHERE id_rnkMETHOD=%s" % rnkID) res = run_sql("DELETE FROM collection_rnkMETHOD WHERE id_rnkMETHOD=%s" % rnkID) res = run_sql("DELETE FROM rnkMETHODDATA WHERE id_rnkMETHOD=%s" % rnkID) if table: res = run_sql("truncate %s" % table) res = run_sql("truncate %sR" % table[:-1]) return (1, "") except StandardError, e: return (0, e) def modify_rnk(rnkID, rnkcode): """change the code for the rank method given rnkID - change in rnkMETHOD where id is like this rnkcode - new value for field 'name' in rnkMETHOD """ - + try: res = run_sql("UPDATE rnkMETHOD set name='%s' WHERE id=%s" % (escape_string(rnkcode), rnkID)) return (1, "") except StandardError, e: return (0, e) def add_rnk(rnkcode): """Adds a new rank method to rnkMETHOD rnkcode - the "code" for the rank method, to be used by bibrank daemon """ - + try: res = run_sql("INSERT INTO rnkMETHOD(name) VALUES('%s')" % escape_string(rnkcode)) res = run_sql("SELECT id FROM rnkMETHOD WHERE name='%s'" % escape_string(rnkcode)) if res: return (1, res[0][0]) else: raise StandardError except StandardError, e: return (0, e) def addadminbox(header='', datalist=[], cls="admin_wvar"): """used to create table around main data on a page, row based. header - header on top of the table datalist - list of the data to be added row by row cls - possible to select wich css-class to format the look of the table.""" if len(datalist) == 1: per = '100' else: per = '75' - + output = '\n' output += """ """ % (len(datalist), header) output += ' \n' output += """ """ % (per+'%', datalist[0]) if len(datalist) > 1: output += """ """ % ('25%', datalist[1]) - + output += ' \n' - + output += """
%s
- %s + %s - %s + %s
""" return output def tupletotable(header=[], tuple=[], start='', end='', extracolumn=''): """create html table for a tuple. header - optional header for the columns - + tuple - create table of this - + start - text to be added in the beginning, most likely beginning of a form - + end - text to be added in the end, mot likely end of a form. - + extracolumn - mainly used to put in a button. """ # study first row in tuple for alignment align = [] - try: + try: firstrow = tuple[0] - - if type(firstrow) in [int, long]: + + if type(firstrow) in [int, long]: align = ['admintdright'] elif type(firstrow) in [str, dict]: align = ['admintdleft'] else: for item in firstrow: if type(item) is int: align.append('admintdright') else: align.append('admintdleft') except IndexError: firstrow = [] - + tblstr = '' for h in header + ['']: tblstr += ' %s\n' % (h, ) if tblstr: tblstr = ' \n%s\n \n' % (tblstr, ) - + tblstr = start + '\n' + tblstr - + # extra column - try: + try: extra = '' if type(firstrow) not in [int, long, str, dict]: # for data in firstrow: extra += '\n' % ('admintd', data) for i in range(len(firstrow)): extra += '\n' % (align[i], firstrow[i]) else: extra += ' \n' % (align[0], firstrow) extra += '\n\n' % (len(tuple), extracolumn) except IndexError: extra = '' tblstr += extra # for i in range(1, len(tuple)): for row in tuple[1:]: tblstr += ' \n' # row = tuple[i] if type(row) not in [int, long, str, dict]: # for data in row: tblstr += '\n' % (data,) for i in range(len(row)): tblstr += '\n' % (align[i], row[i]) else: tblstr += ' \n' % (align[0], row) tblstr += ' \n' tblstr += '
%s%s%s\n%s\n
%s%s%s
\n ' tblstr += end - + return tblstr def tupletotable_onlyselected(header=[], tuple=[], selected=[], start='', end='', extracolumn=''): """create html table for a tuple. header - optional header for the columns tuple - create table of this selected - indexes of selected rows in the tuple start - put this in the beginning end - put this in the beginning extracolumn - mainly used to put in a button""" tuple2 = [] for index in selected: tuple2.append(tuple[int(index)-1]) return tupletotable(header=header, tuple=tuple2, start=start, end=end, extracolumn=extracolumn) def addcheckboxes(datalist=[], name='authids', startindex=1, checked=[]): """adds checkboxes in front of the listdata. datalist - add checkboxes in front of this list name - name of all the checkboxes, values will be associated with this name startindex - usually 1 because of the header checked - values of checkboxes to be pre-checked """ - + if not type(checked) is list: checked = [checked] for row in datalist: if 1 or row[0] not in [-1, "-1", 0, "0"]: # always box, check another place chkstr = str(startindex) in checked and 'checked="checked"' or '' row.insert(0, '' % (name, startindex, chkstr)) else: row.insert(0, '') startindex += 1 return datalist def createhiddenform(action="", text="", button="confirm", cnfrm='', **hidden): """create select with hidden values and submit button action - name of the action to perform on submit text - additional text, can also be used to add non hidden input button - value/caption on the submit button cnfrm - if given, must check checkbox to confirm **hidden - dictionary with name=value pairs for hidden input """ - + output = '
\n' % (action, ) output += '\n
' output += text if cnfrm: - output += ' ' + output += ' ' for key in hidden.keys(): if type(hidden[key]) is list: for value in hidden[key]: output += ' \n' % (key, value) else: output += ' \n' % (key, hidden[key]) output += '' output += ' \n' % (button, ) output += '
' output += '
\n' return output def adderrorbox(header='', datalist=[]): """used to create table around main data on a page, row based""" try: perc= str(100 // len(datalist)) + '%' except ZeroDivisionError: perc= 1 output = '' output += '' % (len(datalist), header) output += '' for row in [datalist]: output += '' for data in row: output += '' output += '' output += '
%s
' % (perc, ) output += data output += '
' return output def serialize_via_numeric_array_dumps(arr): return Numeric.dumps(arr) def serialize_via_numeric_array_compr(str): return compress(str) def serialize_via_numeric_array_escape(str): return escape_string(str) def serialize_via_numeric_array(arr): """Serialize Numeric array into a compressed string.""" return serialize_via_numeric_array_escape(serialize_via_numeric_array_compr(serialize_via_numeric_array_dumps(arr))) def deserialize_via_numeric_array(string): """Decompress and deserialize string into a Numeric array.""" return Numeric.loads(decompress(string)) def serialize_via_marshal(obj): """Serialize Python object via marshal into a compressed string.""" return escape_string(compress(marshal.dumps(obj))) def deserialize_via_marshal(string): """Decompress and deserialize string into a Python object via marshal.""" return marshal.loads(decompress(string)) def get_languages(): languages = [] for (lang, lang_namelong) in language_list_long(): languages.append((lang, lang_namelong)) languages.sort() return languages def get_def_name(ID, table): """Returns a list of the names, either with the name in the current language, the default language, or just the name from the given table ln - a language supported by CDS Invenio type - the type of value wanted, like 'ln', 'sn'""" name = "name" if table[-1:].isupper(): name = "NAME" try: if ID: res = run_sql("SELECT id,name FROM %s where id=%s" % (table, ID)) else: res = run_sql("SELECT id,name FROM %s" % table) res = list(res) - res.sort(compare_on_val) + res.sort(compare_on_val) return res except StandardError, e: return [] - + def get_i8n_name(ID, ln, rtype, table): """Returns a list of the names, either with the name in the current language, the default language, or just the name from the given table ln - a language supported by CDS Invenio type - the type of value wanted, like 'ln', 'sn'""" name = "name" if table[-1:].isupper(): name = "NAME" try: res = "" if ID: res = run_sql("SELECT id_%s,value FROM %s%s where type='%s' and ln='%s' and id_%s=%s" % (table, table, name, rtype,ln, table, ID)) else: res = run_sql("SELECT id_%s,value FROM %s%s where type='%s' and ln='%s'" % (table, table, name, rtype,ln)) if ln != cdslang: if ID: res1 = run_sql("SELECT id_%s,value FROM %s%s WHERE ln='%s' and type='%s' and id_%s=%s" % (table, table, name, cdslang, rtype, table, ID)) else: res1 = run_sql("SELECT id_%s,value FROM %s%s WHERE ln='%s' and type='%s'" % (table, table, name, cdslang, rtype)) res2 = dict(res) result = filter(lambda x: not res2.has_key(x[0]), res1) res = res + result if ID: res1 = run_sql("SELECT id,name FROM %s where id=%s" % (table, ID)) else: res1 = run_sql("SELECT id,name FROM %s" % table) res2 = dict(res) result = filter(lambda x: not res2.has_key(x[0]), res1) res = res + result res = list(res) - res.sort(compare_on_val) + res.sort(compare_on_val) return res except StandardError, e: raise StandardError - + def get_name(ID, ln, rtype, table): """Returns the value from the table name based on arguments - ID - id + ID - id ln - a language supported by CDS Invenio type - the type of value wanted, like 'ln', 'sn' table - tablename""" name = "name" if table[-1:].isupper(): name = "NAME" - + try: res = run_sql("SELECT value FROM %s%s WHERE type='%s' and ln='%s' and id_%s=%s" % (table, name, rtype, ln, table, ID)) return res except StandardError, e: return () def modify_translations(ID, langs, sel_type, trans, table): """add or modify translations in tables given by table frmID - the id of the format from the format table sel_type - the name type langs - the languages trans - the translations, in same order as in langs table - the table""" name = "name" if table[-1:].isupper(): name = "NAME" - + try: for nr in range(0,len(langs)): res = run_sql("SELECT value FROM %s%s WHERE id_%s=%s AND type='%s' AND ln='%s'" % (table, name, table, ID, sel_type, langs[nr][0])) if res: if trans[nr]: res = run_sql("UPDATE %s%s SET value='%s' WHERE id_%s=%s AND type='%s' AND ln='%s'" % (table, name, escape_string(trans[nr]), table, ID, sel_type, langs[nr][0])) else: - res = run_sql("DELETE FROM %s%s WHERE id_%s=%s AND type='%s' AND ln='%s'" % (table, name, table, ID, sel_type, langs[nr][0])) + res = run_sql("DELETE FROM %s%s WHERE id_%s=%s AND type='%s' AND ln='%s'" % (table, name, table, ID, sel_type, langs[nr][0])) else: if trans[nr]: res = run_sql("INSERT INTO %s%s(id_%s, type, ln, value) VALUES (%s,'%s','%s','%s')" % (table, name, table, ID, sel_type, langs[nr][0], escape_string(trans[nr]))) return (1, "") except StandardError, e: return (0, e) def write_outcome(res): try: if res and res[0] == 1: return """Operation successfully completed.""" elif res: return """Operation failed. Reason:
%s""" % res[1][1] except Exception, e: return """Operation failed. Reason unknown
""" - + diff --git a/modules/bibrank/web/admin/bibrankadmin.py b/modules/bibrank/web/admin/bibrankadmin.py index 85034b247..c50286f00 100644 --- a/modules/bibrank/web/admin/bibrankadmin.py +++ b/modules/bibrank/web/admin/bibrankadmin.py @@ -1,199 +1,199 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio BibRank Administrator Interface.""" __revision__ = "$Id$" - + __lastupdated__ = """$Date$""" import sys import invenio.bibrankadminlib as brc #reload(brc) from invenio.webpage import page, create_error_box from invenio.config import weburl, cdslang, cdsname from invenio.dbquery import Error from invenio.webuser import getUid, page_not_authorized def index(req, ln=cdslang): navtrail_previous_links = brc.getnavtrail() # + """> BibRank Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = brc.check_user(uid,'cfgbibrank') + auth = brc.check_user(req,'cfgbibrank') if not auth[0]: return page(title="BibRank Admin Interface", body=brc.perform_index(ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addrankarea(req, ln=cdslang, rnkcode='', template='', confirm=-1): navtrail_previous_links = brc.getnavtrail() + """> BibRank Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = brc.check_user(uid,'cfgbibrank') + auth = brc.check_user(req,'cfgbibrank') if not auth[0]: return page(title="Add new rank method", body=brc.perform_addrankarea(rnkcode=rnkcode, ln=cdslang, template=template, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifytranslations(req, rnkID='', ln=cdslang, sel_type='', trans = [], confirm=0): navtrail_previous_links = brc.getnavtrail() + """> BibRank Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = brc.check_user(uid,'cfgbibrank') + auth = brc.check_user(req,'cfgbibrank') if not auth[0]: return page(title="Modify translations", body=brc.perform_modifytranslations(rnkID=rnkID, ln=ln, sel_type=sel_type, trans=trans, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifycollection(req, ln=cdslang, rnkID='', func='', colID='', confirm=0): navtrail_previous_links = brc.getnavtrail() + """> BibRank Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = brc.check_user(uid,'cfgbibrank') + auth = brc.check_user(req,'cfgbibrank') if not auth[0]: return page(title="Modify visibility toward collections", body=brc.perform_modifycollection(rnkID=rnkID, ln=ln, func=func, colID=colID, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def deleterank(req, ln=cdslang, rnkID='', confirm=0): navtrail_previous_links = brc.getnavtrail() + """> BibRank Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = brc.check_user(uid,'cfgbibrank') + auth = brc.check_user(req,'cfgbibrank') if not auth[0]: return page(title="Delete rank method", body=brc.perform_deleterank(rnkID=rnkID, ln=ln, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyrank(req, ln=cdslang, rnkID='', rnkcode='', template='', cfgfile='', confirm=0): navtrail_previous_links = brc.getnavtrail() + """> BibRank Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = brc.check_user(uid,'cfgbibrank') + auth = brc.check_user(req,'cfgbibrank') if not auth[0]: return page(title="Modify rank method", body=brc.perform_modifyrank(rnkID=rnkID, ln=ln, rnkcode=rnkcode, cfgfile=cfgfile, template=template, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showrankdetails(req, ln=cdslang, rnkID=''): navtrail_previous_links = brc.getnavtrail() + """> BibRank Admin Interface """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = brc.check_user(uid,'cfgbibrank') + auth = brc.check_user(req,'cfgbibrank') if not auth[0]: return page(title="Rank method details", body=brc.perform_showrankdetails(rnkID=rnkID, ln=ln), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def error_page(req, ln=cdslang, verbose=1): return page(title="Internal Error", body = create_error_box(req, verbose=verbose, ln=ln), - description="%s - Internal Error" % cdsname, + description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) diff --git a/modules/bibupload/lib/bibupload.py b/modules/bibupload/lib/bibupload.py index 1a69e65b2..6754b3c72 100644 --- a/modules/bibupload/lib/bibupload.py +++ b/modules/bibupload/lib/bibupload.py @@ -1,1712 +1,1712 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """ BibUpload: Receive MARC XML file and update the appropriate database tables according to options. Usage: bibupload [options] input.xml - Examples: + Examples: $ bibupload -i input.xml Options: -a, --append new fields are appended to the existing record -c, --correct fields are replaced by the new ones in the existing record -f, --format takes only the FMT fields into account. Does not update -i, --insert insert the new record in the database -r, --replace the existing record is entirely replaced by the new one -z, --reference update references (update only 999 fields) -s, --stage=STAGE stage to start from in the algorithm (0: always done; 1: FMT tags; 2: FFT tags; 3: BibFmt; 4: Metadata update; 5: time update) -n, --notimechange do not change record last modification date when updating Scheduling options: -u, --user=USER user name to store task, password needed - + General options: -h, --help print this help and exit -v, --verbose=LEVEL verbose level (from 0 to 9, default 1) - -V --version print the script version + -V --version print the script version """ - + __revision__ = "$Id$" import os import sys import getopt import getpass import signal import string import marshal import time import traceback from zlib import compress import MySQLdb import re import urllib from invenio.config import CFG_OAI_ID_FIELD -from invenio.bibupload_config import * +from invenio.bibupload_config import * from invenio.access_control_engine import acc_authorize_action from invenio.dbquery import run_sql, \ Error from invenio.bibrecord import create_records, \ create_record, \ record_add_field, \ record_delete_field, \ record_xml_output, \ record_get_field_instances, \ record_get_field_values, \ field_get_subfield_values from invenio.dateutils import convert_datestruct_to_datetext from invenio.bibformat import format_record from invenio.config import filedir, \ filedirsize, \ htdocsurl, \ tmpdir, \ CFG_PREFIX # Global variables options = {} options['mode'] = None -options['verbose'] = 1 +options['verbose'] = 1 options['tag'] = None options['file_path'] = None options['notimechange'] = 0 options['stage_to_start_from'] = 1 #Statistic variables stat = {} stat['nb_records_to_upload'] = 0 stat['nb_records_updated'] = 0 stat['nb_records_inserted'] = 0 stat['nb_errors'] = 0 stat['exectime'] = time.localtime() ### bibsched task related functions: def write_message(msg, stream=sys.stdout, verbose=1): """Write message and flush output stream (may be sys.stdout or sys.stderr). Useful for debugging stuff. Do not print anything if the global verbose option is lower than VERBOSE. """ if stream == sys.stdout or stream == sys.stderr: if options['verbose'] >= verbose: stream.write(time.strftime("%Y-%m-%d %H:%M:%S --> ", time.localtime())) try: stream.write("%s\n" % msg) except UnicodeEncodeError: stream.write("%s\n" % msg.encode('ascii', 'backslashreplace')) stream.flush() else: sys.stderr.write("Unknown stream %s. [must be sys.stdout or sys.stderr]\n" % stream) return def task_sig_sleep(sig, frame): """Signal handler for the 'sleep' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_sleep(), got signal %s frame %s" % (sig, frame)) write_message("sleeping...") task_update_status("SLEEPING") signal.pause() # wait for wake-up signal def task_sig_wakeup(sig, frame): """Signal handler for the 'wakeup' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_wakeup(), got signal %s frame %s" % (sig, frame)) write_message("continuing...") task_update_status("CONTINUING") def task_sig_stop(sig, frame): """Signal handler for the 'stop' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_stop(), got signal %s frame %s" % (sig, frame)) write_message("stopping...") task_update_status("STOPPING") write_message("flushing cache or whatever...") time.sleep(3) write_message("closing tables or whatever...") time.sleep(1) write_message("stopped") task_update_status("STOPPED") sys.exit(0) - + def task_sig_suicide(sig, frame): """Signal handler for the 'suicide' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_suicide(), got signal %s frame %s" % (sig, frame)) write_message("suiciding myself now...") task_update_status("SUICIDING") write_message("suicided") task_update_status("SUICIDED") sys.exit(0) def task_sig_unknown(sig, frame): """Signal handler for the other unknown signals sent by shell or user.""" # do nothing for unknown signals: - write_message("unknown signal %d (frame %s) ignored" % (sig, frame)) + write_message("unknown signal %d (frame %s) ignored" % (sig, frame)) def authenticate(user, header="BibUpload Task Submission", action="runbibupload"): """Authenticate the user against the user database. Check for its password, if it exists. Check for action access rights. Return user name upon authorization success, do system exit upon authorization failure. """ # FIXME: for the time being do not authenticate but always let the # tasks in, because of automated inserts. Maybe we shall design # an internal user here that will always be let in. return user print header print "=" * len(header) if user == "": print >> sys.stdout, "\rUsername: ", user = string.strip(string.lower(sys.stdin.readline())) else: - print >> sys.stdout, "\rUsername:", user + print >> sys.stdout, "\rUsername:", user ## first check user pw: res = run_sql("select id,password from user where email=%s", (user,), 1) + \ run_sql("select id,password from user where nickname=%s", (user,), 1) if not res: print "Sorry, %s does not exist." % user - sys.exit(1) + sys.exit(1) else: (uid_db, password_db) = res[0] if password_db: password_entered = getpass.getpass() if password_db == password_entered: pass else: print "Sorry, wrong credentials for %s." % user sys.exit(1) ## secondly check authorization for the action: (auth_code, auth_message) = acc_authorize_action(uid_db, action) if auth_code != 0: print auth_message sys.exit(1) return user def task_submit(): """Submits task to the BibSched task queue. This is what people will be invoking via command line. """ global options ## sanity check: remove eventual "task" option: if options.has_key("task"): del options["task"] ## authenticate user: user = authenticate(options.get("user", "")) ## submit task: if options["verbose"] >= 9: print "" write_message("storing task options %s\n" % options) task_id = run_sql("""INSERT INTO schTASK (id,proc,user,runtime,sleeptime,status,arguments) VALUES (NULL,'bibupload',%s,%s,%s,'WAITING',%s)""", (user, options["runtime"], options["sleeptime"], marshal.dumps(options))) - ## update task number: + ## update task number: options["task"] = task_id run_sql("""UPDATE schTASK SET arguments=%s WHERE id=%s""", (marshal.dumps(options), task_id)) - write_message("Task #%d submitted." % task_id) + write_message("Task #%d submitted." % task_id) return task_id def task_update_progress(msg): """Updates progress information in the BibSched task table.""" global options if options["verbose"] >= 9: write_message("Updating task progress to %s." % msg) return run_sql("UPDATE schTASK SET progress=%s WHERE id=%s", (msg, options["task"])) def task_update_status(val): """Updates status information in the BibSched task table.""" global options if options["verbose"] >= 9: write_message("Updating task status to %s." % val) - return run_sql("UPDATE schTASK SET status=%s WHERE id=%s", (val, options["task"])) + return run_sql("UPDATE schTASK SET status=%s WHERE id=%s", (val, options["task"])) def task_read_status(task_id): """Read status information in the BibSched task table.""" res = run_sql("SELECT status FROM schTASK where id=%s", (task_id,), 1) try: out = res[0][0] except: out = 'UNKNOWN' return out def task_get_options(task_id): """Returns options for the task 'task_id' read from the BibSched task queue table.""" out = {} res = run_sql("SELECT arguments FROM schTASK WHERE id=%s AND proc='bibupload'", (task_id,)) try: out = marshal.loads(res[0][0]) except: write_message("Error: BibUpload task %d does not seem to exist." % \ task_id, sys.stderr) sys.exit(1) return out def task_run(task_id): """Runs the task by fetching arguments from the BibSched task queue. This is what BibSched will be invoking via daemon call. Return 1 in case of success and 0 in case of failure. """ - + global options, stat options = task_get_options(task_id) # get options from BibSched task table ## check task id: if not options.has_key("task"): write_message("Error: The task #%d does not seem to be a BibUpload task." % task_id, sys.stderr) return 0 ## check task status: task_status = task_read_status(task_id) if task_status != "WAITING": write_message("Error: The task #%d is %s. I expected WAITING." % \ (task_id, task_status), sys.stderr) return 0 ## we can run the task now: if options["verbose"]: write_message("Task #%d started." % task_id) task_update_status("RUNNING") ## initialize signal handler: signal.signal(signal.SIGUSR1, task_sig_sleep) signal.signal(signal.SIGTERM, task_sig_stop) signal.signal(signal.SIGABRT, task_sig_suicide) signal.signal(signal.SIGCONT, task_sig_wakeup) signal.signal(signal.SIGINT, task_sig_unknown) ## run the task: error = 0 write_message("Input file '%s', input mode '%s'." % (options['file_path'], options['mode'])) write_message("STAGE 0:", verbose=2) - - if options['file_path'] is not None: + + if options['file_path'] is not None: recs = xml_marc_to_records(open_marc_file(options['file_path'])) stat['nb_records_to_upload'] = len(recs) write_message(" -Open XML marc: DONE", verbose=2) if recs is not None: # We proceed each record by record for record in recs: error = bibupload(record) if error[0] == 1: - if record: + if record: sys.stderr.write("\n"+record_xml_output(record)+"\n\n") else: sys.stderr.write("\nRecord could not have been parsed.\n\n") stat['nb_errors'] += 1 task_update_progress("Done %d out of %d." % \ (stat['nb_records_inserted'] + \ stat['nb_records_updated'], stat['nb_records_to_upload'])) else: write_message(" Error bibupload failed: No record found", verbose=1, stream=sys.stderr) - + if options['verbose'] >= 1: # Print out the statistics print_out_bibupload_statistics() - + # Check if they were errors if stat['nb_errors'] >= 1: task_update_status("DONE WITH ERRORS") else: ## we are done: - task_update_status("DONE") + task_update_status("DONE") if options["verbose"]: write_message("Task #%d finished." % task_id) return 1 ### bibupload engine functions: def parse_command(): """Analyze the command line and retrieve arguments (xml file, mode, etc) into global options variable. Return 0 in case everything went well, 1 in case of errors, 2 in case only help or version number were asked for. """ # FIXME: add treatment of `time' try: opts, args = getopt.getopt(sys.argv[1:], "ircazs:fu:hv:Vn", [ "insert", "replace", "correct", "append", "reference", "stage=", "format", "user=", "help", "verbose=", "version", "notimechange", ]) except getopt.GetoptError,erro: usage() write_message("Stage 0 error: %s" % erro, verbose=1, stream=sys.stderr) return 1 # set the proper mode depending on the argument value for opt, opt_value in opts: # Verbose mode option if opt in ["-v", "--verbose"]: try: options['verbose'] = int(opt_value) except ValueError: write_message("Failed: enter a valid number for verbose mode (between 0 and 9).", verbose=1, stream=sys.stderr) return 1 # stage mode option if opt in ["-s", "--stage"]: try: options['stage_to_start_from'] = int(opt_value) except ValueError: write_message("Failed: enter a valid number for the stage to start from(>0).", verbose=1, stream=sys.stderr) return 1 # No time change option - if opt in ["-n", "--notimechange"]: + if opt in ["-n", "--notimechange"]: options['notimechange'] = 1 # Insert mode option if opt in ["-i", "--insert"]: if options['mode'] == 'replace': # if also replace found, then set to replace_or_insert options['mode'] = 'replace_or_insert' else: options['mode'] = 'insert' options['file_path'] = os.path.abspath(args[0]) # Replace mode option if opt in ["-r", "--replace"]: if options['mode'] == 'insert': # if also insert found, then set to replace_or_insert options['mode'] = 'replace_or_insert' else: options['mode'] = 'replace' options['file_path'] = os.path.abspath(args[0]) - + # Correct mode option if opt in ["-c", "--correct"]: options['mode'] = 'correct' options['file_path'] = os.path.abspath(args[0]) # Append mode option if opt in ["-a", "--append"]: options['mode'] = 'append' options['file_path'] = os.path.abspath(args[0]) # Reference mode option if opt in ["-z", "--reference"]: options['mode'] = 'reference' options['file_path'] = os.path.abspath(args[0]) # Format mode option if opt in ["-f", "--format"]: options['mode'] = 'format' options['file_path'] = os.path.abspath(args[0]) - + # Detection of user - if opt in ["-u", "--user"]: + if opt in ["-u", "--user"]: options['user'] = opt_value # Help mode option - if opt in ["-h", "--help"]: + if opt in ["-h", "--help"]: usage() return 2 # Version mode option if opt in ["-V", "--version"]: write_message(__revision__, verbose=1) return 2 if options['mode'] is None: write_message("Please specify at least one update/insert mode!") return 1 if options['file_path'] is None: write_message("Missing filename! -h for help.") return 1 return 0 - + def bibupload(record): """Main function: process a record and fit it in the tables bibfmt, bibrec, bibrec_bibxxx, bibxxx with proper record metadata. Return (error_code, recID) of the processed record. """ error = None # If there are special tags to proceed check if it exists in the record if options['tag'] is not None and not(record.has_key(options['tag'])): write_message(" Failed: Tag not found, enter a valid tag to update.", verbose=1, stream=sys.stderr) return (1, -1) - + # Extraction of the Record Id from 001, SYSNO or OAIID tags: rec_id = retrieve_rec_id(record) if rec_id == -1: return (1, -1) elif rec_id > 0: write_message(" -Retrieve record ID (found %s): DONE." % rec_id, verbose=2) if not record.has_key('001'): # Found record ID by means of SYSNO or OAIID, and the # input MARCXML buffer does not have this 001 tag, so we # should add it now: error = record_add_field(record, '001', '', '', rec_id, [], 0) if error is None: write_message(" Failed: " \ "Error during adding the 001 controlfield " \ "to the record", verbose=1, stream=sys.stderr) return (1, int(rec_id)) else: error = None write_message(" -Added tag 001: DONE.", verbose=2) write_message(" -Check if the xml marc file is already in the database: DONE" , verbose=2) - - # Reference mode check if there are reference tag + + # Reference mode check if there are reference tag if options['mode'] == 'reference': error = extract_tag_from_record(record, CFG_BIBUPLOAD_REFERENCE_TAG) if error is None: write_message(" Failed: No reference tags has been found...", verbose=1, stream=sys.stderr) return (1, -1) else: error = None write_message(" -Check if reference tags exist: DONE", verbose=2) - + if options['mode'] == 'insert' or \ (options['mode'] == 'replace_or_insert' and rec_id is None): insert_mode_p = True # Insert the record into the bibrec databases to have a recordId rec_id = create_new_record() write_message(" -Creation of a new record id (%d): DONE" % rec_id, verbose=2) - + # we add the record Id control field to the record error = record_add_field(record, '001', '', '', rec_id, [], 0) if error is None: write_message(" Failed: " \ "Error during adding the 001 controlfield " \ "to the record", verbose=1, stream=sys.stderr) return (1, int(rec_id)) else: error = None elif options['mode'] != 'insert' and options['mode'] != 'format' and options['stage_to_start_from'] != 5: insert_mode_p = False # Update Mode # Retrieve the old record to update rec_old = create_record(format_record(int(rec_id), 'xm'), 2)[0] if rec_old is None: write_message(" Failed during the creation of the old record!", verbose=1, stream=sys.stderr) return (1, int(rec_id)) else: write_message(" -Retrieve the old record to update: DONE", verbose=2) - + # Delete tags to correct in the record if options['mode'] == 'correct' or options['mode'] == 'reference': delete_tags_to_correct(record, rec_old) write_message(" -Delete the old tags to correct in the old record: DONE", verbose=2) - + # Append new tag to the old record and update the new record with the old_record modified if options['mode'] == 'append' or options['mode'] == 'correct' or options['mode'] == 'reference': record = append_new_tag_to_old_record(record, rec_old) write_message(" -Append new tags to the old record: DONE", verbose=2) # now we clear all the rows from bibrec_bibxxx from the old # record (they will be populated later (if needed) during # stage 4 below): delete_bibrec_bibxxx(rec_old, rec_id) write_message(" -Clean bibrec_bibxxx: DONE", verbose=2) write_message(" -Stage COMPLETED", verbose=2) # Have a look if we have FMT tags write_message("Stage 1: Start (Insert of FMT tags if exist).", verbose=2) if options['stage_to_start_from'] <= 1 and extract_tag_from_record(record, 'FMT') is not None: record = insert_fmt_tags(record, rec_id) if record is None: write_message(" Stage 1 failed: Error while inserting FMT tags", verbose=1, stream=sys.stderr) return (1, int(rec_id)) elif record == 0: # Mode format finished stat['nb_records_updated'] += 1 return (0, int(rec_id)) write_message(" -Stage COMPLETED", verbose=2) else: write_message(" -Stage NOT NEEDED", verbose=2) - - # Have a look if we have FFT tags + + # Have a look if we have FFT tags write_message("Stage 2: Start (Process FFT tags if exist).", verbose=2) if options['stage_to_start_from'] <= 2 and extract_tag_from_record(record, 'FFT') is not None: - + if insert_mode_p or options['mode'] == 'append': record = insert_fft_tags(record, rec_id) else: update_fft_tag(record, rec_id) write_message(" -Stage COMPLETED", verbose=2) else: write_message(" -Stage NOT NEEDED", verbose=2) - + # Update of the BibFmt write_message("Stage 3: Start (Update bibfmt).", verbose=2) if options['stage_to_start_from'] <= 3: # format the single record as xml rec_xml_new = record_xml_output(record) # Update bibfmt with the format xm of this record - if options['mode'] != 'format': + if options['mode'] != 'format': error = update_bibfmt_format(rec_id, rec_xml_new, 'xm') if error == 1: write_message(" Failed: error during update_bibfmt_format", verbose=1, stream=sys.stderr) return (1, int(rec_id)) write_message(" -Stage COMPLETED", verbose=2) - + # Update the database MetaData write_message("Stage 4: Start (Update the database with the metadata).", verbose=2) if options['stage_to_start_from'] <= 4: if options['mode'] == 'insert' or \ options['mode'] == 'replace' or \ options['mode'] == 'replace_or_insert' or \ options['mode'] == 'append' or \ options['mode'] == 'correct' or \ options['mode'] == 'reference': update_database_with_metadata(record, rec_id) else: write_message(" -Stage NOT NEEDED in mode %s" % options['mode'], verbose=2) write_message(" -Stage COMPLETED", verbose=2) else: write_message(" -Stage NOT NEEDED", verbose=2) - + # Finally we update the bibrec table with the current date write_message("Stage 5: Start (Update bibrec table with current date).", verbose=2) if options['stage_to_start_from'] <= 5 and \ options['notimechange'] == 0 and \ not insert_mode_p: now = convert_datestruct_to_datetext(time.localtime()) write_message(" -Retrieved current localtime: DONE", verbose=2) update_bibrec_modif_date(now, rec_id) write_message(" -Stage COMPLETED", verbose=2) else: write_message(" -Stage NOT NEEDED", verbose=2) # Increase statistics if insert_mode_p: stat['nb_records_inserted'] += 1 else: stat['nb_records_updated'] += 1 - + # Upload of this record finish write_message("Record "+str(rec_id)+" DONE", verbose=1) return (0, int(rec_id)) def usage(): """Print help""" print """Receive MARC XML file and update appropriate database tables according to options. Usage: bibupload [options] input.xml - Examples: + Examples: $ bibupload -i input.xml Options: -a, --append new fields are appended to the existing record -c, --correct fields are replaced by the new ones in the existing record -f, --format takes only the FMT fields into account. Does not update -i, --insert insert the new record in the database -r, --replace the existing record is entirely replaced by the new one -z, --reference update references (update only 999 fields) -s, --stage=STAGE stage to start from in the algorithm (0: always done; 1: FMT tags; 2: FFT tags; 3: BibFmt; 4: Metadata update; 5: time update) -n, --notimechange do not change record last modification date when updating Scheduling options: -u, --user=USER user name to store task, password needed - + General options: -h, --help print this help and exit -v, --verbose=LEVEL verbose level (from 0 to 9, default 1) - -V --version print the script version - """ - + -V --version print the script version + """ + def print_out_bibupload_statistics(): """Print the statistics of the process""" out = "Task stats: %(nb_input)d input records, %(nb_updated)d updated, " \ "%(nb_inserted)d inserted, %(nb_errors)d errors. Time %(nb_sec).2f sec." % { \ 'nb_input': stat['nb_records_to_upload'], 'nb_updated': stat['nb_records_updated'], 'nb_inserted': stat['nb_records_inserted'], 'nb_errors': stat['nb_errors'], 'nb_sec': time.time() - time.mktime(stat['exectime']) } - write_message(out) - + write_message(out) + def open_marc_file(path): """Open a file and return the data""" try: # open the file containing the marc document marc_file = open(path,'r') marc = marc_file.read() marc_file.close() except IOError, erro: write_message("Error: %s" % erro, verbose=1, stream=sys.stderr) write_message("Exiting.", sys.stderr) - task_update_status("ERROR") + task_update_status("ERROR") sys.exit(1) return marc def xml_marc_to_records(xml_marc): """create the records""" # Creation of the records from the xml Marc in argument recs = create_records(xml_marc, 1, 1) if recs == []: write_message("Error: Cannot parse MARCXML file.", verbose=1, stream=sys.stderr) write_message("Exiting.", sys.stderr) - task_update_status("ERROR") - sys.exit(1) + task_update_status("ERROR") + sys.exit(1) elif recs[0][0] is None: write_message("Error: MARCXML file has wrong format: %s" % recs, verbose=1, stream=sys.stderr) write_message("Exiting.", sys.stderr) - task_update_status("ERROR") + task_update_status("ERROR") sys.exit(1) else: recs = map((lambda x:x[0]), recs) return recs - + def find_record_format(rec_id, format): """Look whether record REC_ID is formatted in FORMAT, i.e. whether FORMAT exists in the bibfmt table for this record. - + Return the number of times it is formatted: 0 if not, 1 if yes, 2 if found more than once (should never occur). """ out = 0 query = """SELECT COUNT(id) FROM bibfmt WHERE id_bibrec=%s AND format=%s""" params = (rec_id, format) res = [] try: res = run_sql(query, params) out = res[0][0] except Error, error: - write_message(" Error during find_record_format() : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during find_record_format() : %s " % error, verbose=1, stream=sys.stderr) return out def find_record_bibfmt(marc): """ receives the xmlmarc containing a record and returns the id in bibrec if the record exists in bibfmt""" # compress the marc value pickled_marc = MySQLdb.escape_string(compress(marc)) query = """SELECT id_bibrec FROM bibfmt WHERE value = %s""" # format for marc xml is xm params = (pickled_marc,) try: res = run_sql(query, params) except Error, error: - write_message(" Error during find_record_bibfmt function : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during find_record_bibfmt function : %s " % error, verbose=1, stream=sys.stderr) if len(res): return res else: return None def find_record_from_recid(rec_id): """ Try to find record in the database from the REC_ID number. Return record ID if found, None otherwise. """ try: res = run_sql("SELECT id FROM bibrec WHERE id=%s", (rec_id,)) except Error, error: write_message(" Error during find_record_bibrec() : %s " % error, - verbose=1, stream=sys.stderr) + verbose=1, stream=sys.stderr) if res: return res[0][0] else: return None - + def find_record_from_sysno(sysno): """ Try to find record in the database from the external SYSNO number. Return record ID if found, None otherwise. """ bibxxx = 'bib'+CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:2]+'x' bibrec_bibxxx = 'bibrec_' + bibxxx try: res = run_sql("""SELECT bb.id_bibrec FROM %(bibrec_bibxxx)s AS bb, %(bibxxx)s AS b WHERE b.tag=%%s AND b.value=%%s AND bb.id_bibxxx=b.id""" % \ {'bibxxx': bibxxx, 'bibrec_bibxxx': bibrec_bibxxx}, (CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG, sysno,)) except Error, error: write_message(" Error during find_record_from_sysno(): %s " % error, - verbose=1, stream=sys.stderr) + verbose=1, stream=sys.stderr) if res: return res[0][0] else: return None def find_record_from_extoaiid(extoaiid): """ Try to find record in the database from the external EXTOAIID number. Return record ID if found, None otherwise. """ bibxxx = 'bib'+CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:2]+'x' bibrec_bibxxx = 'bibrec_' + bibxxx try: res = run_sql("""SELECT bb.id_bibrec FROM %(bibrec_bibxxx)s AS bb, %(bibxxx)s AS b WHERE b.tag=%%s AND b.value=%%s AND bb.id_bibxxx=b.id""" % \ {'bibxxx': bibxxx, 'bibrec_bibxxx': bibrec_bibxxx}, (CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG, extoaiid,)) except Error, error: write_message(" Error during find_record_from_extoaiid(): %s " % error, - verbose=1, stream=sys.stderr) + verbose=1, stream=sys.stderr) if res: return res[0][0] else: return None def find_record_from_oaiid(oaiid): """ Try to find record in the database from the OAI ID number. Return record ID if found, None otherwise. """ bibxxx = 'bib'+CFG_OAI_ID_FIELD[0:2]+'x' bibrec_bibxxx = 'bibrec_' + bibxxx try: res = run_sql("""SELECT bb.id_bibrec FROM %(bibrec_bibxxx)s AS bb, %(bibxxx)s AS b WHERE b.tag=%%s AND b.value=%%s AND bb.id_bibxxx=b.id""" % \ {'bibxxx': bibxxx, 'bibrec_bibxxx': bibrec_bibxxx}, (CFG_OAI_ID_FIELD, oaiid,)) except Error, error: write_message(" Error during find_record_from_oaiid(): %s " % error, - verbose=1, stream=sys.stderr) + verbose=1, stream=sys.stderr) if res: return res[0][0] else: return None def extract_tag_from_record(record, tag_number): """ Extract the tag_number for record.""" # first step verify if the record is not already in the database if record: return record.get(tag_number, None) return None - + def retrieve_rec_id(record): """Retrieve the record Id from a record by using tag 001 or SYSNO or OAI ID tag.""" rec_id = None - + # 1st step: we look for the tag 001 tag_001 = extract_tag_from_record(record, '001') if tag_001 is not None: # We extract the record ID from the tag - rec_id = tag_001[0][3] + rec_id = tag_001[0][3] # if we are in insert mode => error if options['mode'] == 'insert': write_message(" Failed : Error tag 001 found in the xml" \ " submitted, you should use the option replace," \ " correct or append to replace an existing" \ " record. (-h for help)", verbose=1, stream=sys.stderr) - return -1 + return -1 else: # we found the rec id and we are not in insert mode => continue # we try to match rec_id against the database: if find_record_from_recid(rec_id) is not None: # okay, 001 corresponds to some known record return rec_id else: # The record doesn't exist yet. We shall have try to check - # the SYSNO or OAI id later. + # the SYSNO or OAI id later. write_message(" -Tag 001 value not found in database.", verbose=9) rec_id = None else: write_message(" -Tag 001 not found in the xml marc file.", verbose=9) if rec_id is None: - # 2nd step we look for the SYSNO + # 2nd step we look for the SYSNO sysnos = record_get_field_values(record, CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3], CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] != "_" and \ CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] or "", CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] != "_" and \ CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] or "", CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6]) if sysnos: sysno = sysnos[0] # there should be only one external SYSNO write_message(" -Checking if SYSNO " + sysno + \ " exists in the database", verbose=9) # try to find the corresponding rec id from the database rec_id = find_record_from_sysno(sysno) if rec_id is not None: # rec_id found pass else: # The record doesn't exist yet. We will try to check - # external and internal OAI ids later. + # external and internal OAI ids later. write_message(" -Tag SYSNO value not found in database.", verbose=9) rec_id = None else: write_message(" -Tag SYSNO not found in the xml marc file.", verbose=9) if rec_id is None: # 2nd step we look for the external OAIID extoaiids = record_get_field_values(record, CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3], CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] != "_" and \ CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] or "", CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] != "_" and \ CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] or "", CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6]) if extoaiids: extoaiid = extoaiids[0] # there should be only one external OAI ID write_message(" -Checking if EXTOAIID " + extoaiid + \ " exists in the database", verbose=9) # try to find the corresponding rec id from the database rec_id = find_record_from_extoaiid(extoaiid) if rec_id is not None: # rec_id found pass else: # The record doesn't exist yet. We will try to check - # OAI id later. + # OAI id later. write_message(" -Tag EXTOAIID value not found in database.", verbose=9) rec_id = None else: write_message(" -Tag EXTOAIID not found in the xml marc file.", verbose=9) if rec_id is None: # 4th step we look for the OAI ID oaiidvalues = record_get_field_values(record, CFG_OAI_ID_FIELD[0:3], CFG_OAI_ID_FIELD[3:4] != "_" and \ CFG_OAI_ID_FIELD[3:4] or "", CFG_OAI_ID_FIELD[4:5] != "_" and \ CFG_OAI_ID_FIELD[4:5] or "", CFG_OAI_ID_FIELD[5:6]) if oaiidvalues: oaiid = oaiidvalues[0] # there should be only one OAI ID write_message(" -Check if local OAI ID " + oaiid + \ " exist in the database", verbose=9) - + # try to find the corresponding rec id from the database rec_id = find_record_from_oaiid(oaiid) if rec_id is not None: # rec_id found pass else: write_message(" -Tag OAI ID value not found in database.", verbose=9) rec_id = None else: write_message(" -Tag SYSNO not found in the xml marc file.", verbose=9) # Now we should have detected rec_id from SYSNO or OAIID - # tags. (None otherwise.) + # tags. (None otherwise.) if rec_id: if options['mode'] == 'insert': write_message(" Failed : Record found in the database," \ " you should use the option replace," \ " correct or append to replace an existing" \ " record. (-h for help)", verbose=1, stream=sys.stderr) return -1 else: if options['mode'] != 'insert' and \ options['mode'] != 'replace_or_insert': write_message(" Failed : Record not found in the database."\ " Please insert the file before updating it."\ " (-h for help)", verbose=1, stream=sys.stderr) return -1 return rec_id ### Insert functions def create_new_record(): """Create new record in the database""" now = convert_datestruct_to_datetext(time.localtime()) query = """INSERT INTO bibrec (creation_date, modification_date) VALUES (%s, %s)""" params = (now, now) try: rec_id = run_sql(query, params) return rec_id except Error, error: - write_message(" Error during the creation_new_record function : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during the creation_new_record function : %s " % error, verbose=1, stream=sys.stderr) return None - + def insert_bibfmt(id_bibrec, marc, format): """Insert the format in the table bibfmt""" # compress the marc value #pickled_marc = MySQLdb.escape_string(compress(marc)) pickled_marc = compress(marc) # get the current time now = convert_datestruct_to_datetext(time.localtime()) query = """INSERT INTO bibfmt (id_bibrec, format, last_updated, value) VALUES (%s, %s, %s, %s)""" try: row_id = run_sql(query, (id_bibrec, format, now, pickled_marc)) return row_id except Error, error: - write_message(" Error during the insert_bibfmt function : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during the insert_bibfmt function : %s " % error, verbose=1, stream=sys.stderr) return None def insert_record_bibxxx(tag, value): """Insert the record into bibxxx""" # determine into which table one should insert the record table_name = 'bib'+tag[0:2]+'x' # check if the tag, value combination exists in the table query = """SELECT id,value FROM %s """ % table_name query += """ WHERE tag=%s AND value=%s""" params = (tag, value) try: res = run_sql(query, params) except Error, error: - write_message(" Error during the insert_record_bibxxx function : %s " % error, verbose=1, stream=sys.stderr) - + write_message(" Error during the insert_record_bibxxx function : %s " % error, verbose=1, stream=sys.stderr) + # Note: compare now the found values one by one and look for # string binary equality (e.g. to respect lowercase/uppercase # match), regardless of the charset etc settings. Ideally we # could use a BINARY operator in the above SELECT statement, but # we would have to check compatibility on various MySQLdb versions # etc; this approach checks all matched values in Python, not in # MySQL, which is less cool, but more conservative, so it should # work better on most setups. for row in res: row_id = row[0] row_value = row[1] if row_value == value: return (table_name, row_id) # We got here only when the tag,value combination was not found, # so it is now necessary to insert the tag,value combination into # bibxxx table as new. query = """INSERT INTO %s """ % table_name - query += """ (tag, value) values (%s , %s)""" + query += """ (tag, value) values (%s , %s)""" params = (tag, value) try: row_id = run_sql(query, params) except Error, error: write_message(" Error during the insert_record_bibxxx function : %s " % error, - verbose=1, stream=sys.stderr) + verbose=1, stream=sys.stderr) return (table_name, row_id) def insert_record_bibrec_bibxxx(table_name, id_bibxxx, field_number, id_bibrec): """Insert the record into bibrec_bibxxx""" # determine into which table one should insert the record full_table_name = 'bibrec_'+ table_name # insert the proper row into the table query = """INSERT INTO %s """ % full_table_name query += """(id_bibrec,id_bibxxx, field_number) values (%s , %s, %s)""" params = (id_bibrec, id_bibxxx, field_number) try: res = run_sql(query, params) except Error, error: - write_message(" Error during the insert_record_bibrec_bibxxx function 2nd query : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during the insert_record_bibrec_bibxxx function 2nd query : %s " % error, verbose=1, stream=sys.stderr) return res - + def insert_fft_tags(record, rec_id, cfg_bibupload_wget_sleep_time=1, cfg_bibupload_max_download_retires=10): """ Process FFT tags that should contain $a with file pathes or URLs to get the fulltext from. This function enriches record with proper 8564 URL tags, downloads fulltext files and stores them into var/data structure where appropriate. CFG_BIBUPLOAD_WGET_SLEEP_TIME defines time to sleep in seconds in between URL downloads. Note: if an FFT tag contains multiple $a subfields, we upload them into different 856 URL tags in the metadata. See regression test case test_multiple_fft_insert_via_http(). """ curdir = os.getcwd() os.chdir(tmpdir) tuple_list = None tuple_list = extract_tag_from_record(record, 'FFT') # If there is a FFT TAG add_local_fulltext = True downloads_err_count = {} if tuple_list is not None: write_message("insert_fft_tags, all FFTs: "+str(tuple_list), verbose=9) for aurl in record_get_field_values(record, 'FFT', ' ', ' ', 'a'): file_exists_already = False docuri = string.split(aurl,"//") write_message("now processing FFT: "+str(docuri), verbose=9) # Determine if docuri is a local file or a url if len(docuri) == 1: # it is something like /dfs/fs/sdfs/sdf.pdf docpath = docuri[0] if not (string.find(docpath, CFG_PREFIX) > -1 or string.find(docpath, "/home/") > -1): write_message("FFT tag contains path to a forbidden directory: " + docpath, stream=sys.stderr) - docpath = "" + docpath = "" if len(docuri) == 2: if docuri[0] == "file:": # it is something like file:///dfs/fs/sdfs/sdf.pdf docpath = docuri[1] if not (string.find(docpath, CFG_PREFIX) > -1 or string.find(docpath, "/home/") > -1): write_message("FFT tag contains path to a forbidden directory: " + docpath, stream=sys.stderr) docpath = "" elif docuri[0] == "http:": # it is something like http://arXiv.org/sdf/sdf.pdf base_url = string.split(docuri[1], "/")[0] fname = string.split(docuri[1], "/")[-1] if not base_url in downloads_err_count.keys(): downloads_err_count[base_url] = 0 - if not downloads_err_count[base_url] > cfg_bibupload_max_download_retires: + if not downloads_err_count[base_url] > cfg_bibupload_max_download_retires: try: if False: # switch to True for testing - aurl = string.replace(aurl, "export.", "") + aurl = string.replace(aurl, "export.", "") time.sleep(cfg_bibupload_wget_sleep_time) write_message("Downloading: " + aurl) if os.path.exists(fname): write_message("insert_fft_tags: " + fname + " already exists!", verbose=3, stream=sys.stderr) file_exists_already = True os.rename(fname , fname + ".renamed_by_bibupload_fft" ) os.system("wget -T 60 --tries 1 -q --user-agent='Mozilla/4.0' " + \ "http://"+ urllib.quote(aurl[7:]) ) except OSError, errormsg: add_local_fulltext = False write_message("Error, pobabily in downloading " + aurl + " errormsg: " + errormsg, verbose=1, stream=sys.stderr) downloads_err_count[base_url] += 1 docpath = os.getcwd() + "/" + fname - + if not os.path.exists(fname): add_local_fulltext = False write_message("Error in renaming " + string.split(docuri[1], "/")[-1], - verbose=1, stream=sys.stderr) + verbose=1, stream=sys.stderr) # add tag 856 of source if download failed urlad = aurl if string.find(urlad, "arxiv.org") > -1 and string.find(urlad, "export.") > -1: urlad = string.replace(urlad, "export.", "") - subfield_list = [('u', urlad)] + subfield_list = [('u', urlad)] newfield_number = record_add_field(record, "856", "4", "", "", subfield_list) if add_local_fulltext and not docpath=="": #if not (string.find(docpath, CFG_PREFIX) > -1 or string.find(docpath, "/home/") > -1): # write_message("FFT tag contains path to a forbidden directory: " + docpath, stream=sys.stderr) # docpath = "" docname = re.sub("\..*", "", os.path.basename(docpath)) extension = re.sub("^[^\.]*.", "", os.path.basename(docpath)).lower() # Create a new docId try: bib_doc_id = run_sql("insert into bibdoc (docname,status,creation_date,modification_date) values(%s,0,NOW(),NOW())", (docname,)) write_message(" -Insert of the file %s into bibdoc : DONE" % docname, verbose=2) except Error, error: - write_message(" Error during the insert_fft_tags function : %s " % error, verbose=1, stream=sys.stderr) - + write_message(" Error during the insert_fft_tags function : %s " % error, verbose=1, stream=sys.stderr) + if bib_doc_id is not None: # we link the document to the record if a rec_id was specified if rec_id != "": - + # FIXME: doc_type : main or additional (with babbage.py , only main is needed) doc_type = "Main" try: res = run_sql("insert into bibrec_bibdoc values(%s,%s,%s)", (rec_id, bib_doc_id, doc_type)) if res is None: write_message(" Failed during creation of link between doc Id and rec Id).", verbose=1, stream=sys.stderr) else: write_message(" -Insert of the link bibrec bibdoc for %s : DONE" % docname, verbose=2) except Error, error: - write_message(" Error during the insert_fft_tags function : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during the insert_fft_tags function : %s " % error, verbose=1, stream=sys.stderr) else: write_message(" Failed during creation of the new doc Id.", verbose=1, stream=sys.stderr) # Move the file to the correct place # Variables from the config file archivepath = filedir archivesize = filedirsize url_path = None group = "g"+str(int(int(bib_doc_id)/archivesize)) basedir = "%s/%s/%s" % (archivepath, group, bib_doc_id) # we create the corresponding storage directory if not os.path.exists(basedir): try: os.makedirs(basedir) write_message(" -Create a new directory %s : DONE" % basedir, verbose=2) except OSError, error: - write_message(" Error making the directory : %s " % error, verbose=1, stream=sys.stderr) - + write_message(" Error making the directory : %s " % error, verbose=1, stream=sys.stderr) + # and save the father record id if it exists if rec_id != "": try: filep = open("%s/.recid" % basedir, "w") filep.write(str(rec_id)) filep.close() except IOError, error: - write_message(" Error writing the file : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error writing the file : %s " % error, verbose=1, stream=sys.stderr) # Move the file to the good directory try: dest = basedir + "/" + string.split(docpath,"/")[-1] + ";1" os.rename(docpath, dest ) write_message(" -Move the file %s to %s : DONE" % (docpath, dest), verbose=8) except OSError, error: write_message(" Error moving the file : %s " % error, verbose=1, stream=sys.stderr) # Renames the orignial file if it had to be moved if file_exists_already: try: os.rename(fname + ".renamed_by_bibupload_fft", fname ) except: pass - + # Create the Url Path url_path = htdocsurl + "/record/" + str(rec_id) + "/files/" + docname + "." + extension - + # add tag 856 to the xml marc to proceed - subfield_list = [('u', url_path)] + subfield_list = [('u', url_path)] newfield_number = record_add_field(record, "856", "4", " ", "", subfield_list) if newfield_number is None: write_message(" Error when adding the field"+ aurl, verbose=1, stream=sys.stderr) else: write_message(" -Add the new tag 856 to the record for %s : DONE" % docname, verbose=8) - + # Delete FFT tag :) record_delete_field(record, 'FFT', ' ', ' ') write_message(" -Delete FFT tag from source : DONE", verbose=2) - os.chdir(curdir) + os.chdir(curdir) return record def update_fft_tag(record, rec_id, cfg_bibupload_wget_sleep_time=1): """ Processes and updates fulltexts documents in FFT tags. - + It tries to match filename and upps version of the file by downloading it (no local file support). - + Important note: There is a fundamental difference with metadata correct mode. This function does not touch existing files, it just adds the new ones. - + Beware: if no matching filename is found in invenio this will increment the version of an existing file no matter what the new filename is. - + BEFORE: - file.pdf;2 + file.pdf;2 thesis.ppt;14 - + INPUT: thesis.ppt - + AFTER: file.pdf;2 thesis.ppt;15 - + *** - + BEFORE: - thesis.pdf;2 + thesis.pdf;2 thesis.ppt;14 - + INPUT: thesis.ppt - + AFTER: ? (devrait pas arriver, mais...) - + *** - + BEFORE: - file.pdf;2 + file.pdf;2 thesis.ppt;14 - + INPUT: my_photo.jpeg - + AFTER: file.jpeg;3 - ??? thesis.ppt;14 - + *** - - - + + + """ - + download_errors = 0 rec = record - + if "FFT" in rec.keys(): for uri in record_get_field_values(record, 'FFT', ' ', ' ', 'a'): fname = string.split(uri, "/")[-1] file_exists_already = False - + uri_type = "url" if not "http://" in uri: uri_type = "file" if not ((CFG_PREFIX in uri) or ("/home/" in uri)): uri = "" write_message("Local file "+uri+" is not in a permitted path (/home or CFG_PREFIX).", verbose=1, stream=sys.stderr) if "file://" in uri: uri.replace("file://","") - + # Getting docid for this recid res = run_sql("select id_bibdoc from bibrec_bibdoc where id_bibrec=%s", (rec_id,)) type_file = "" type_exists = False is_bibdocs = False if len(res) == 0: write_message("Error: no id_bibdoc for the rec_id " + str(rec_id),verbose=1, stream=sys.stderr) else: is_bibdocs= True - for res_s in res: - bib_doc_id = res_s[0] + for res_s in res: + bib_doc_id = res_s[0] # Determinig dir for this docid archivepath = filedir archivesize = filedirsize group = "g"+str(int(int(bib_doc_id)/archivesize)) basedir = "%s/%s/%s" % (archivepath, group, bib_doc_id) - + # Listing and analysing content of this directory: does this type of document exist ? ls = os.listdir(basedir) for filename in ls: if fname in filename: type_exists = True type_file = filename # Atributes an existing filename if the right one was not found, etc. if type_file == "" and is_bibdocs: ls.sort() - write_message("Trying to atribute an existing filename to fulltext: the right one was not found.", verbose=9, stream=sys.stderr) + write_message("Trying to atribute an existing filename to fulltext: the right one was not found.", verbose=9, stream=sys.stderr) for filename in ls: if filename.find("recid") == -1 : type_file = filename type_exists = True write_message("Attributed filename to update: " + type_file, verbose=9, stream=sys.stderr) if type_file == "": write_message("No fulltext to update in this recid.", verbose=1, stream=sys.stderr) type_exists = False - + # Determine the new version, by taking next intger. If there is no vesion: assigning version 1 if not len(res) == 0: version = 0 for filename in ls: if ";" in filename: version_str = string.split(filename, ";")[1] is_int = True try: version_i = int(version_str) except: is_int = False if is_int: if version_i > version : version = version_i version = str(version + 1) else: version = "1" - + # determining new filename, if no fulltext is found, just taking the first file if type_exists: base_filename = string.split (type_file,";") [0] full_filename = basedir + "/" + base_filename + ";" + version write_message("New filename: " + full_filename, verbose=9) # Downloads revised fulltext if it is ok and moves it where it must be stored if not type_file == "" and type_exists: - + if uri_type == "url": if download_errors < 10: cdir = os.getcwd() os.chdir(tmpdir) try: if os.path.exists(fname): file_exists_already = True os.rename(fname, fname + ".renamed_by_bibupload_fft") os.system("wget -T 60 --tries 1 -q --user-agent='CDS' " + uri) time.sleep(cfg_bibupload_wget_sleep_time) write_message("renaming from " + fname + " // to " + full_filename, verbose=1, stream=sys.stderr ) os.rename( fname , full_filename) if file_exists_already: os.rename(fname + ".renamed_by_bibupload_fft", fname) except OSError: write_message("Error in downloading " + uri, verbose=1, stream=sys.stderr) download_errors += 1 os.chdir(cdir) else: try: os.rename(uri , full_filename) except OSError: write_message("Local file "+uri+" in FFT field does not exist.", verbose=1, stream=sys.stderr) - + else: pass # deleted records have no FFT tags - + def insert_fmt_tags(record, rec_id): """Process and insert FMT tags""" fmt_fields = record_get_field_instances(record, 'FMT') if fmt_fields: for fmt_field in fmt_fields: # Get the f, g subfields of the FMT tag try: f_value = field_get_subfield_values(fmt_field, "f")[0] except IndexError: f_value = "" try: - g_value = field_get_subfield_values(fmt_field, "g")[0] + g_value = field_get_subfield_values(fmt_field, "g")[0] except IndexError: g_value = "" # Update the format res = update_bibfmt_format(rec_id, g_value, f_value) if res == 1: write_message(" Failed: Error during update_bibfmt", verbose=1, stream=sys.stderr) - + # If we are in format mode, we only care about the FMT tag if options['mode'] == 'format': return 0 # We delete the FMT Tag of the record record_delete_field(record, 'FMT') write_message(" -Delete field FMT from record : DONE", verbose=2) return record elif options['mode'] == 'format': write_message(" Failed: Format updated failed : No tag FMT found", verbose=1, stream=sys.stderr) return None else: return record - + ### Update functions - + def update_bibrec_modif_date(now, bibrec_id): - """Update the date of the record in bibrec table """ + """Update the date of the record in bibrec table """ query = """UPDATE bibrec SET modification_date=%s WHERE id=%s""" params = (now, bibrec_id) try: run_sql(query, params) write_message(" -Update record modification date : DONE" , verbose=2) except Error, error: write_message(" Error during update_bibrec_modif_date function : %s" % error, verbose=1, stream=sys.stderr) def update_bibfmt_format(id_bibrec, format_value, format_name): """Update the format in the table bibfmt""" # We check if the format is already in bibFmt nb_found = find_record_format(id_bibrec, format_name) - + if nb_found == 1: # Update the format # get the current time now = convert_datestruct_to_datetext(time.localtime()) # compress the format_value value pickled_format_value = compress(format_value) - - query = """UPDATE bibfmt SET last_updated=%s, value=%s WHERE id_bibrec=%s AND format=%s""" + + query = """UPDATE bibfmt SET last_updated=%s, value=%s WHERE id_bibrec=%s AND format=%s""" params = (now, pickled_format_value, id_bibrec, format_name) try: row_id = run_sql(query, params) if row_id is None: write_message(" Failed: Error during update_bibfmt_format function", verbose=1, stream=sys.stderr) return 1 else: write_message(" -Update the format %s in bibfmt : DONE" % format_name , verbose=2) return 0 except Error, error: - write_message(" Error during the update_bibfmt_format function : %s " % error, verbose=1, stream=sys.stderr) - + write_message(" Error during the update_bibfmt_format function : %s " % error, verbose=1, stream=sys.stderr) + elif nb_found > 1: write_message(" Failed: Same format %s found several time in bibfmt for the same record." % format_name, verbose=1, stream=sys.stderr) return 1 else: # Insert the format information in BibFMT res = insert_bibfmt(id_bibrec, format_value, format_name) if res is None: write_message(" Failed: Error during insert_bibfmt", verbose=1, stream=sys.stderr) return 1 else: write_message(" -Insert the format %s in bibfmt : DONE" % format_name , verbose=2) return 0 - + def update_database_with_metadata(record, rec_id): """Update the database tables with the record and the record id given in parameter""" for tag in record.keys(): # check if tag is not a special one: if tag not in CFG_BIBUPLOAD_SPECIAL_TAGS: # for each tag there is a list of tuples representing datafields tuple_list = record[tag] # this list should contain the elements of a full tag [tag, ind1, ind2, subfield_code] tag_list = [] tag_list.append(tag) for single_tuple in tuple_list: # these are the contents of a single tuple subfield_list = single_tuple[0] ind1 = single_tuple[1] ind2 = single_tuple[2] # append the ind's to the full tag if ind1 == '' or ind1 == ' ': tag_list.append('_') else: tag_list.append(ind1) if ind2 == '' or ind2 == ' ': tag_list.append('_') else: tag_list.append(ind2) datafield_number = single_tuple[4] - + if tag in CFG_BIBUPLOAD_SPECIAL_TAGS: # nothing to do for special tags (FFT, FMT) pass elif tag in CFG_BIBUPLOAD_CONTROLFIELD_TAGS and tag != "001": value = single_tuple[3] # get the full tag full_tag = ''.join(tag_list) - + # update the tables write_message(" insertion of the tag "+full_tag+" with the value "+value, verbose=9) # insert the tag and value into into bibxxx (table_name, bibxxx_row_id) = insert_record_bibxxx(full_tag, value) #print 'tname, bibrow', table_name, bibxxx_row_id; if table_name is None or bibxxx_row_id is None: write_message(" Failed : during insert_record_bibxxx", verbose=1, stream=sys.stderr) # connect bibxxx and bibrec with the table bibrec_bibxxx res = insert_record_bibrec_bibxxx(table_name, bibxxx_row_id, datafield_number, rec_id) if res is None: write_message(" Failed : during insert_record_bibrec_bibxxx", verbose=1, stream=sys.stderr) else: # get the tag and value from the content of each subfield for subfield in subfield_list: subtag = subfield[0] value = subfield[1] tag_list.append(subtag) # get the full tag full_tag = ''.join(tag_list) # update the tables write_message(" insertion of the tag "+full_tag+" with the value "+value, verbose=9) # insert the tag and value into into bibxxx (table_name, bibxxx_row_id) = insert_record_bibxxx(full_tag, value) if table_name is None or bibxxx_row_id is None: write_message(" Failed : during insert_record_bibxxx", verbose=1, stream=sys.stderr) # connect bibxxx and bibrec with the table bibrec_bibxxx res = insert_record_bibrec_bibxxx(table_name, bibxxx_row_id, datafield_number, rec_id) if res is None: write_message(" Failed : during insert_record_bibrec_bibxxx", verbose=1, stream=sys.stderr) # remove the subtag from the list tag_list.pop() tag_list.pop() tag_list.pop() tag_list.pop() write_message(" -Update the database with metadata : DONE", verbose=2) def append_new_tag_to_old_record(record, rec_old): """Append new tags to a old record""" if options['tag'] is not None: tag = options['tag'] if tag in CFG_BIBUPLOAD_CONTROLFIELD_TAGS: if tag == '001': pass else: # if it is a controlfield,just access the value for single_tuple in record[tag]: controlfield_value = single_tuple[3] # add the field to the old record newfield_number = record_add_field(rec_old, tag, "", "", controlfield_value) if newfield_number is None: write_message(" Error when adding the field"+tag, verbose=1, stream=sys.stderr) else: # For each tag there is a list of tuples representing datafields - for single_tuple in record[tag]: + for single_tuple in record[tag]: # We retrieve the information of the tag subfield_list = single_tuple[0] ind1 = single_tuple[1] ind2 = single_tuple[2] # We add the datafield to the old record if options['verbose'] == 9: print " Adding tag: ", tag, " ind1=", ind1, " ind2=", ind2, " code=", subfield_list newfield_number = record_add_field(rec_old, tag, ind1, ind2, "", subfield_list) if newfield_number is None: write_message("Error when adding the field"+tag, verbose=1, stream=sys.stderr) else: # Go through each tag in the appended record for tag in record.keys(): # Reference mode append only reference tag if options['mode'] == 'reference': if tag == CFG_BIBUPLOAD_REFERENCE_TAG: - for single_tuple in record[tag]: + for single_tuple in record[tag]: # We retrieve the information of the tag subfield_list = single_tuple[0] ind1 = single_tuple[1] ind2 = single_tuple[2] # We add the datafield to the old record if options['verbose'] == 9: print " Adding tag: ", tag, " ind1=", ind1, " ind2=", ind2, " code=", subfield_list newfield_number = record_add_field(rec_old, tag, ind1, ind2, "", subfield_list) if newfield_number is None: write_message(" Error when adding the field"+tag, verbose=1, stream=sys.stderr) else: if tag in CFG_BIBUPLOAD_CONTROLFIELD_TAGS: if tag == '001': pass else: # if it is a controlfield,just access the value for single_tuple in record[tag]: controlfield_value = single_tuple[3] # add the field to the old record newfield_number = record_add_field(rec_old, tag, "", "", controlfield_value) if newfield_number is None: write_message(" Error when adding the field"+tag, verbose=1, stream=sys.stderr) else: # For each tag there is a list of tuples representing datafields - for single_tuple in record[tag]: + for single_tuple in record[tag]: # We retrieve the information of the tag subfield_list = single_tuple[0] ind1 = single_tuple[1] ind2 = single_tuple[2] # We add the datafield to the old record if options['verbose'] == 9: print " Adding tag: ", tag, " ind1=", ind1, " ind2=", ind2, " code=", subfield_list newfield_number = record_add_field(rec_old, tag, ind1, ind2, "", subfield_list) if newfield_number is None: write_message(" Error when adding the field"+tag, verbose=1, stream=sys.stderr) return rec_old - - + + ### Delete functions def delete_tags_to_correct(record, rec_old): """ Delete tags from REC_OLD which are also existing in RECORD. When deleting, pay attention not only to tags, but also to indicators, so that fields with the same tags but different indicators are not deleted. """ # browse through all the tags from the MARCXML file: for tag in record.keys(): # do we have to delete only a special tag or any tag? if options['tag'] is None or options['tag'] == tag: # check if the tag exists in the old record too: if rec_old.has_key(tag) and tag != '001': # the tag does exist, so delete all record's tag+ind1+ind2 combinations from rec_old for dummy_sf_vals, ind1, ind2, dummy_cf, dummy_field_number in record[tag]: write_message(" Delete tag: " + tag + " ind1=" + ind1 + " ind2=" + ind2, verbose=9) record_delete_field(rec_old, tag, ind1, ind2) def delete_bibrec_bibxxx(record, id_bibrec): """Delete the database record from the table bibxxx given in parameters""" - # we clear all the rows from bibrec_bibxxx from the old record + # we clear all the rows from bibrec_bibxxx from the old record for tag in record.keys(): - if tag not in CFG_BIBUPLOAD_SPECIAL_TAGS: + if tag not in CFG_BIBUPLOAD_SPECIAL_TAGS: # for each name construct the bibrec_bibxxx table name table_name = 'bibrec_bib'+tag[0:2]+'x' # delete all the records with proper id_bibrec query = """DELETE FROM `%s` where id_bibrec = %s""" params = (table_name, id_bibrec) try: run_sql(query % params) except Error, error: - write_message(" Error during the delete_bibrec_bibxxx function : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during the delete_bibrec_bibxxx function : %s " % error, verbose=1, stream=sys.stderr) def wipe_out_record_from_all_tables(recid): """ Wipe out completely the record and all its traces of RECID from the database (bibrec, bibrec_bibxxx, bibxxx, bibfmt). Useful for the time being for test cases. """ # delete from bibrec: run_sql("DELETE FROM bibrec WHERE id=%s", (recid,)) # delete from bibrec_bibxxx: for i in range(0, 10): for j in range(0, 10): run_sql("DELETE FROM %(bibrec_bibxxx)s WHERE id_bibrec=%%s" % \ {'bibrec_bibxxx': "bibrec_bib%i%ix" % (i, j)}, (recid,)) # delete all unused bibxxx values: for i in range(0, 10): for j in range(0, 10): run_sql("DELETE %(bibxxx)s FROM %(bibxxx)s " \ " LEFT JOIN %(bibrec_bibxxx)s " \ " ON %(bibxxx)s.id=%(bibrec_bibxxx)s.id_bibxxx " \ " WHERE %(bibrec_bibxxx)s.id_bibrec IS NULL" % \ {'bibxxx': "bib%i%ix" % (i, j), 'bibrec_bibxxx': "bibrec_bib%i%ix" % (i, j)}) # delete from bibfmt: run_sql("DELETE FROM bibfmt WHERE id_bibrec=%s", (recid,)) # delete from bibrec_bibdoc: run_sql("DELETE FROM bibrec_bibdoc WHERE id_bibrec=%s", (recid,)) return def delete_bibdoc(id_bibrec): """Delete document from bibdoc which correspond to the bibrec id given in parameter""" query = """UPDATE bibdoc SET status='deleted' WHERE id IN (SELECT id_bibdoc FROM bibrec_bibdoc WHERE id_bibrec=%s)""" params = (id_bibrec,) try: run_sql(query, params) except Error, error: - write_message(" Error during the delete_bibdoc function : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during the delete_bibdoc function : %s " % error, verbose=1, stream=sys.stderr) def delete_bibrec_bibdoc(id_bibrec): """Delete the bibrec record from the table bibrec_bibdoc given in parameter""" # delete all the records with proper id_bibrec query = """DELETE FROM bibrec_bibdoc WHERE id_bibrec=%s""" params = (id_bibrec,) try: run_sql(query, params) except Error, error: - write_message(" Error during the delete_bibrec_bibdoc function : %s " % error, verbose=1, stream=sys.stderr) + write_message(" Error during the delete_bibrec_bibdoc function : %s " % error, verbose=1, stream=sys.stderr) def main(): """main entry point for bibupload""" global options ## parse command line: if len(sys.argv) == 2 and sys.argv[1].isdigit(): ## A - run the task task_id = int(sys.argv[1]) try: if not task_run(task_id): write_message("Error occurred. Exiting.", sys.stderr) except StandardError, erro: write_message("Unexpected error occurred: %s." % erro, sys.stderr) write_message("Traceback is:", sys.stderr) traceback.print_tb(sys.exc_info()[2]) write_message("Exiting.", sys.stderr) - task_update_status("ERROR") + task_update_status("ERROR") else: ## B - submit the task # set default values: - options["runtime"] = time.strftime("%Y-%m-%d %H:%M:%S") + options["runtime"] = time.strftime("%Y-%m-%d %H:%M:%S") options["sleeptime"] = "" # set user-defined options: error = parse_command() if error == 0: task_submit() else: sys.exit(1) return if __name__ == "__main__": main() diff --git a/modules/miscutil/bin/testsuite.in b/modules/miscutil/bin/testsuite.in index 3b707e0c3..ba155e098 100644 --- a/modules/miscutil/bin/testsuite.in +++ b/modules/miscutil/bin/testsuite.in @@ -1,112 +1,114 @@ #!@PYTHON@ ## -*- mode: python; coding: utf-8; -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """Run CDS Invenio test suite.""" __revision__ = "$Id$" import getopt import unittest import sys # we first import webinterface_tests to be sure to have the fake # Apache environment working: from invenio import webinterface_tests # now we import the rest: from invenio.config import version from invenio import search_engine_tests from invenio import bibindex_engine_tests from invenio import bibindex_engine_stemmer_tests from invenio import bibrecord_tests from invenio import bibrank_citation_indexer_tests from invenio import bibrank_citation_searcher_tests from invenio import bibrank_downloads_indexer_tests from invenio import bibrank_record_sorter_tests from invenio import bibrank_tag_based_indexer_tests from invenio import oai_repository_tests from invenio import bibconvert_tests from invenio import errorlib_tests from invenio import elmsubmit_tests from invenio import bibformat_engine_tests from invenio import websearch_external_collections_getter_tests from invenio import webuser_tests from invenio import webgroup_tests from invenio import dbquery_tests from invenio import dateutils_tests from invenio import htmlutils_tests +from invenio import access_control_firerole_tests def usage(): """Print usage info on standard error output.""" sys.stderr.write("Usage: %s [options]\n" % sys.argv[0]) sys.stderr.write("General options:\n") sys.stderr.write(" -h, --help \t\t Print this help.\n") sys.stderr.write(" -V, --version \t\t Print version information.\n") sys.stderr.write("Description: run CDS Invenio test suite.\n") return def create_all_test_suites(): """Return all tests suites for all CDS Invenio modules.""" return unittest.TestSuite((search_engine_tests.create_test_suite(), bibindex_engine_tests.create_test_suite(), bibindex_engine_stemmer_tests.create_test_suite(), bibrecord_tests.create_test_suite(), bibrank_citation_indexer_tests.create_test_suite(), bibrank_citation_searcher_tests.create_test_suite(), bibrank_downloads_indexer_tests.create_test_suite(), bibrank_record_sorter_tests.create_test_suite(), bibrank_tag_based_indexer_tests.create_test_suite(), oai_repository_tests.create_test_suite(), bibconvert_tests.create_test_suite(), errorlib_tests.create_test_suite(), elmsubmit_tests.create_test_suite(), webinterface_tests.create_test_suite(), bibformat_engine_tests.create_test_suite(), websearch_external_collections_getter_tests.create_test_suite(), webuser_tests.create_test_suite(), webgroup_tests.create_test_suite(), dbquery_tests.create_test_suite(), dateutils_tests.create_test_suite(), htmlutils_tests.create_test_suite(), + access_control_firerole_tests.create_test_suite(), )) def print_info_line(): """Prints info line about tests to be executed.""" info_line = """CDS Invenio v%s test suite results:""" % version sys.stderr.write(info_line + "\n") sys.stderr.write("=" * len(info_line) + "\n") if __name__ == "__main__": try: opts, args = getopt.getopt(sys.argv[1:], "hV", ["help", "version"]) except getopt.GetoptError: usage() sys.exit(2) for opt in opts: if opt[0] in ("-V","--version"): print __revision__ sys.exit(0) elif opt[0] in ("-h","--help"): usage() sys.exit(0) print_info_line() unittest.TextTestRunner(verbosity=2).run(create_all_test_suites()) diff --git a/modules/miscutil/lib/Makefile.am b/modules/miscutil/lib/Makefile.am index f71464409..3f65d792c 100644 --- a/modules/miscutil/lib/Makefile.am +++ b/modules/miscutil/lib/Makefile.am @@ -1,87 +1,88 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. pylibdir = $(libdir)/python/invenio pylib_DATA = __init__.py \ errorlib.py \ errorlib_tests.py \ errorlib_webinterface.py \ errorlib_regression_tests.py \ config.py \ + data_cacher.py \ dbquery.py \ dbquery_tests.py \ miscutil_config.py \ messages.py \ textutils.py \ dateutils.py \ dateutils_tests.py \ htmlutils.py \ htmlutils_tests.py \ testutils.py \ testutils_regression_tests.py \ urlutils.py noinst_DATA = testimport.py \ kwalitee.py phplibdir = $(libdir)/php/invenio/errors phplib_DATA = errorHandling.php EXTRA_DIST = __init__.py \ errorlib.py \ errorlib_tests.py \ errorlib_webinterface.py \ errorlib_regression_tests.py \ miscutil_config.py \ config.py.wml \ dbquery.py.wml \ dbquery_tests.py \ messages.py.wml \ errorHandling.php.wml \ textutils.py \ dateutils.py \ dateutils_tests.py \ htmlutils.py \ htmlutils_tests.py \ testutils.py \ testutils_regression_tests.py \ urlutils.py \ testimport.py \ kwalitee.py install-data-hook: $(PYTHON) $(srcdir)/testimport.py ${prefix} CLEANFILES = config.py dbquery.py messages.py $(phplib_DATA) *~ *.tmp *.pyc config.py: config.py.wml $(top_srcdir)/config/config.wml $(top_builddir)/config/configbis.wml \ $(top_srcdir)/config/cdswmllib.wml $(WML) -o $@ $< dbquery.py: dbquery.py.wml $(top_srcdir)/config/config.wml $(top_builddir)/config/configbis.wml \ $(top_srcdir)/config/cdswmllib.wml $(WML) -o $@ $< messages.py: messages.py.wml $(top_srcdir)/config/config.wml $(top_builddir)/config/configbis.wml \ $(top_srcdir)/config/cdswmllib.wml $(WML) -o $@ $< errorHandling.php: errorHandling.php.wml $(top_srcdir)/config/config.wml $(top_builddir)/config/configbis.wml \ $(top_srcdir)/config/cdswmllib.wml $(WML) -o $@ $< diff --git a/modules/miscutil/lib/config.py.wml b/modules/miscutil/lib/config.py.wml index ef6ee2bef..1abb42331 100644 --- a/modules/miscutil/lib/config.py.wml +++ b/modules/miscutil/lib/config.py.wml @@ -1,188 +1,189 @@ ## $Id$ ## CDS Invenio config file, to be read by all Python programs. ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. ## read config variables: #include "config.wml" #include "configbis.wml" ## -*- coding: utf-8 -*- ## $Id$ ## DO NOT EDIT THIS FILE! IT WAS AUTOMATICALLY GENERATED FROM CDS Invenio WML SOURCES. """CDS Invenio config file, to be read by all Python programs.""" __revision__ = "$Id$" ## fill all the generally-interesting config variables from WML: cdsname = "" cdslang = "" supportemail = "" adminemail = "" alertengineemail = "" CFG_PREFIX = "" webdir = "" weburl = "" sweburl = "" bindir = "" pylibdir = "/python" cachedir = "" logdir = "" tmpdir = "" etcdir = "" version = "" localedir = "" ## intl versions of CDSNAME of this installation: cdsnameintl = {} cdsnameintl['de'] = "" cdsnameintl['en'] = "" cdsnameintl['es'] = "" cdsnameintl['ca'] = "" cdsnameintl['pt'] = "" cdsnameintl['fr'] = "" cdsnameintl['hr'] = "" cdsnameintl['it'] = "" cdsnameintl['ru'] = "" cdsnameintl['sk'] = "" cdsnameintl['cs'] = "" cdsnameintl['no'] = "" cdsnameintl['sv'] = "" cdsnameintl['el'] = "" cdsnameintl['uk'] = "" cdsnameintl['ja'] = "" cdsnameintl['pl'] = "" cdsnameintl['bg'] = "" cdsnameintl['zh_CN'] = "" cdsnameintl['zh_TW'] = "" ## helper programs: CFG_PATH_PHP = "" CFG_PATH_PDFTOTEXT = "" CFG_PATH_PSTOTEXT = "" CFG_PATH_PSTOASCII = "" CFG_PATH_ANTIWORD = "" CFG_PATH_CATDOC = "" CFG_PATH_WVTEXT = "" CFG_PATH_PPTHTML = "" CFG_PATH_XLHTML = "" CFG_PATH_HTMLTOTEXT = "" CFG_PATH_GFILE = "" CFG_PATH_GZIP = "" CFG_PATH_TAR = "" CFG_PATH_GUNZIP = "" CFG_PATH_ACROREAD = "" CFG_PATH_DISTILLER = "" CFG_PATH_CONVERT = "" ## Apache password/group files: CFG_APACHE_PASSWORD_FILE = "" CFG_APACHE_GROUP_FILE = "" ## are we running CERN specifics? CFG_CERN_SITE = ## for websubmit: images = "/img" urlpath = "" accessurl = "/search" counters = "" storage = "" filedir = "" filedirsize = xmlmarc2textmarc = "/xmlmarc2textmarc" bibupload = "/bibupload" bibformat = "/bibformat" bibwords = "/bibwords" bibconvert = "/bibconvert" bibconvertconf = "/bibconvert/config" htdocsurl = "" ## for search engine: -CFG_MAX_RECID = +CFG_MAX_RECID = +CFG_MAX_CACHED_QUERIES = CFG_WEBSEARCH_INSTANT_BROWSE = -CFG_WEBSEARCH_AUTHOR_ET_AL_THRESHOLD = -CFG_WEBSEARCH_SEARCH_CACHE_SIZE = -CFG_WEBSEARCH_NB_RECORDS_TO_SORT = +CFG_WEBSEARCH_AUTHOR_ET_AL_THRESHOLD = +CFG_WEBSEARCH_SEARCH_CACHE_SIZE = +CFG_WEBSEARCH_NB_RECORDS_TO_SORT = CFG_WEBSEARCH_CALL_BIBFORMAT = -CFG_WEBSEARCH_USE_ALEPH_SYSNOS = +CFG_WEBSEARCH_USE_ALEPH_SYSNOS = CFG_WEBSEARCH_FIELDS_CONVERT = CFG_WEBSEARCH_SIMPLESEARCH_PATTERN_BOX_WIDTH = # FIXME: not used? -CFG_WEBSEARCH_ADVANCEDSEARCH_PATTERN_BOX_WIDTH = -CFG_WEBSEARCH_NARROW_SEARCH_SHOW_GRANDSONS = +CFG_WEBSEARCH_ADVANCEDSEARCH_PATTERN_BOX_WIDTH = +CFG_WEBSEARCH_NARROW_SEARCH_SHOW_GRANDSONS = CFG_WEBSEARCH_CREATE_SIMILARLY_NAMED_AUTHORS_LINK_BOX = ## for access control: CFG_ACCESS_CONTROL_LEVEL_SITE = CFG_ACCESS_CONTROL_LEVEL_GUESTS = CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS = CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN = "" CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS = CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT = CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION = CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION = ## for OAI repository: CFG_OAI_ID_PREFIX = "" CFG_OAI_SAMPLE_IDENTIFIER = "" CFG_OAI_IDENTIFY_DESCRIPTION = """""" CFG_OAI_ID_FIELD = "" CFG_OAI_SET_FIELD = "" CFG_OAI_DELETED_POLICY = "" CFG_OAI_EXPIRE = CFG_OAI_SLEEP = CFG_OAI_LOAD = ## for the indexer: CFG_BIBINDEX_FULLTEXT_INDEX_LOCAL_FILES_ONLY = CFG_BIBINDEX_STEMMER_DEFAULT_LANGUAGE = "" CFG_BIBINDEX_REMOVE_STOPWORDS = CFG_BIBINDEX_PATH_TO_STOPWORDS_FILE = "" CFG_BIBINDEX_CHARS_ALPHANUMERIC_SEPARATORS = r"[]" CFG_BIBINDEX_CHARS_PUNCTUATION = r"[]" CFG_BIBINDEX_REMOVE_HTML_MARKUP = CFG_BIBINDEX_MIN_WORD_LENGTH = CFG_BIBINDEX_URLOPENER_USERNAME = "" # FIXME: not found in modules subdir?! CFG_BIBINDEX_URLOPENER_PASSWORD = "" # FIXME: not found in modules subdir?! ## for ranking: CFG_BIBRANK_SHOW_DOWNLOAD_GRAPHS = 0 ## for commenting: CFG_WEBCOMMENT_ALLOW_COMMENTS = 1 CFG_WEBCOMMENT_ALLOW_REVIEWS = 1 CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN = 5 CFG_WEBCOMMENT_NB_COMMENTS_IN_DETAILED_VIEW = 1 CFG_WEBCOMMENT_NB_REVIEWS_IN_DETAILED_VIEW = 1 CFG_WEBCOMMENT_ADMIN_NOTIFICATION_LEVEL = 1 CFG_WEBCOMMENT_TIMELIMIT_PROCESSING_COMMENTS_IN_SECONDS = 20 CFG_WEBCOMMENT_TIMELIMIT_PROCESSING_REVIEWS_IN_SECONDS = 20 CFG_WEBCOMMENT_TIMELIMIT_VOTE_VALIDITY_IN_DAYS = 365 # FIXME: not found in modules subdir?! CFG_WEBCOMMENT_TIMELIMIT_REPORT_VALIDITY_IN_DAYS = 100 # FIXME: not found in modules subdir?! ## page and style elements: CFG_WEBSTYLE_TEMPLATE_SKIN = "" CFG_WEBSTYLE_CDSPAGEHEADER = """""" CFG_WEBSTYLE_CDSPAGEBOXLEFTTOP = """""" CFG_WEBSTYLE_CDSPAGEBOXLEFTBOTTOM = """""" CFG_WEBSTYLE_CDSPAGEBOXRIGHTTOP = """""" CFG_WEBSTYLE_CDSPAGEBOXRIGHTBOTTOM = """""" CFG_WEBSTYLE_CDSPAGEFOOTER = """""" # for task scheduler: CFG_BIBSCHED_REFRESHTIME = 5 diff --git a/modules/miscutil/lib/data_cacher.py b/modules/miscutil/lib/data_cacher.py new file mode 100644 index 000000000..038ba43c4 --- /dev/null +++ b/modules/miscutil/lib/data_cacher.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 + +"""Tool for caching important infos, which are slow to rebuild, but that rarely change""" + +from invenio.dbquery import run_sql, get_table_update_time +from invenio.config import cdslang, CFG_MAX_RECID +from invenio.access_control_admin import acc_getActionId +from invenio.access_control_config import VIEWRESTRCOLL +import time +import string +import Numeric +import zlib + +class CacherError(Exception): + """Error raised by data cacher""" + pass + +class DataCacher: + """ DataCacher is an abstract cacher system, for caching informations + that are slow to retrieve but that don't change too much during time.""" + def __init__(self, cache_filler, timestamp_getter): + """ @param cache_filler a function that receives the cache dictionary. + @param timestamp_getter a function that returns a timestamp for checking + if something has changed after cache creation. + """ + self.timestamp = 0 + self.cache = {} + if not callable(cache_filler): + raise CacherError, "cache_filler is not callable" + self.cache_filler = cache_filler + if not callable(timestamp_getter): + raise CacherError, "timestamp_getter is not callable" + self.timestamp_getter = timestamp_getter + self.is_ok_p = True + self.create_cache() + + def clear(self): + """ Clear the cache rebuilding it""" + self.cache = self.create_cache() + + def create_cache(self): + """Create cache. Called on startup and used later during the search time.""" + # populate field I18 name cache: + self.cache = self.cache_filler() + self.timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + + def get_cache(self): + """ Obtain an uptodate cache.""" + if self.timestamp_getter() > self.timestamp: + self.create_cache() + return self.cache + + + diff --git a/modules/miscutil/lib/dbquery.py.wml b/modules/miscutil/lib/dbquery.py.wml index 59f7d6e9d..3a44dac47 100644 --- a/modules/miscutil/lib/dbquery.py.wml +++ b/modules/miscutil/lib/dbquery.py.wml @@ -1,221 +1,263 @@ ## $Id$ ## CDS Invenio utility to run SQL queries. The core is taken from ## modpython FAQ and modified to suit our needs. The insert_id() is ## inspired by Erik Forsberg's mod_python slides. ## FIXME: note that this version of persistent connectivity to the ## database is not thread-safe; it works allright in the prefork model ## only (apache2-mpm-prefork). We should rather replace it with the ## connection pool technique when time permits. See: ## http://modpython.org/FAQ/faqw.py?req=show&file=faq03.003.htp ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. #include "configbis.wml" """CDS Invenio utility to run SQL queries.""" __revision__ = "$Id$" # dbquery clients can import these from here: # pylint: disable-msg=W0611 -from MySQLdb import escape_string +from MySQLdb import escape_string from MySQLdb import Warning, Error, InterfaceError, DataError, \ DatabaseError, OperationalError, IntegrityError, \ InternalError, NotSupportedError, \ ProgrammingError import string import datetime +import time from MySQLdb import connect -from invenio.config import CFG_ACCESS_CONTROL_LEVEL_SITE +from invenio.config import CFG_ACCESS_CONTROL_LEVEL_SITE, CFG_MAX_CACHED_QUERIES ## Configured MySQL credentials are read here and not in config.py in ## order to prevent them from appearing elsewhere, as no-one should ## know DB credentials but us. dbhost = "" dbname = "" dbuser = "" dbpass = "" def _db_login(relogin = 0): """Login to the database.""" global DB_CONN if relogin: DB_CONN = connect(host=dbhost, db=dbname, user=dbuser, passwd=dbpass) return DB_CONN else: try: d = DB_CONN return d except NameError: DB_CONN = connect(host=dbhost, db=dbname, user=dbuser, passwd=dbpass) return DB_CONN +try: + _db_cache +except NameError: + _db_cache = {} + _db_cache_last_timestamp = {} + +def run_sql_cached(sql, param=None, n=0, with_desc=0, affected_tables=[]): + """Caches whatever SQL command is passed by. + @param param: tuple of string params to insert in the query + (see notes below) + @param n: number of tuples in result (0 for unbounded) + @param with_desc: if true, will return a + DB API 7-tuple describing columns in query + @return the result as provided by run_sql + Note, it's useless and even wrong to use this function with SQL commands + different from SELECT + """ + global _db_cache, _db_cache_last_timestamp + key = repr((sql, param, n, with_desc, affected_tables)) + timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + _db_cache_last_timestamp[key] = timestamp + if len(_db_cache_last_timestamp) >= CFG_MAX_CACHED_QUERIES: + _run_sql_cached_gc() + if _db_cache.has_key(key): + result, last_timestamp = _db_cache[key] + if max([get_table_update_time(table) for table in affected_tables]) > last_timestamp: + result = run_sql(sql, param, n, with_desc) + _db_cache[key] = (result, timestamp) + else: + result = run_sql(sql, param, n, with_desc) + _db_cache[key] = (result, timestamp) + return result + +def _run_sql_cached_gc(): + global _db_cache, _db_cache_last_timestamp + key_rank = _db_cache_last_timestamp.keys() + key_rank.sort(lambda x, y:_db_cache_last_timestamp[x] < _db_cache_last_timestamp[y] and -1 or _db_cache_last_timestamp[x] > _db_cache_last_timestamp[y] and 1 or 0) + for i in range(0, len(key_rank)/2): + del _db_cache[key_rank[i]] + del _db_cache_last_timestamp[key_rank[i]] + def run_sql(sql, param=None, n=0, with_desc=0): """Run SQL on the server with PARAM and return result. @param param: tuple of string params to insert in the query (see notes below) @param n: number of tuples in result (0 for unbounded) @param with_desc: if true, will return a DB API 7-tuple describing columns in query @return: if SELECT, SHOW, DESCRIBE statements: tuples of data, followed by description if parameter provided if INSERT: last row id. else: SQL result as provided by database When the site is closed for maintenance (as governed by the config variable CFG_ACCESS_CONTROL_LEVEL_SITE), do not attempt to run any SQL queries but return empty list immediately. Useful to be able to have the website up while MySQL database is down for maintenance, hot copies, table repairs, etc. In case of problems, exceptions are returned according to the Python DB API 2.0. The client code can import them from this file and catch them. """ if CFG_ACCESS_CONTROL_LEVEL_SITE == 2: # do not connect to the database as the site is closed for maintenance: return [] ### log_sql_query(sql, param) ### UNCOMMENT ONLY IF you REALLY want to log all queries if param: param = tuple(param) try: - db = _db_login() + db = _db_login() cur = db.cursor() - rc = cur.execute(sql, param) + rc = cur.execute(sql, param) except OperationalError: # unexpected disconnect, bad malloc error, etc # FIXME: now reconnect is always forced, we may perhaps want to ping() first? try: - db = _db_login(relogin = 1) - cur = db.cursor() + db = _db_login(relogin = 1) + cur = db.cursor() rc = cur.execute(sql, param) except OperationalError: # again an unexpected disconnect, bad malloc error, etc - raise + raise if string.upper(string.split(sql)[0]) in ("SELECT", "SHOW", "DESC", "DESCRIBE"): if n: recset = cur.fetchmany(n) else: - recset = cur.fetchall() + recset = cur.fetchall() if with_desc: return recset, cur.description else: - return recset + return recset else: if string.upper(string.split(sql)[0]) == "INSERT": rc = cur.lastrowid return rc def blob_to_string(ablob): """Return string representation of ABLOB. Useful to treat MySQL BLOBs in the same way for both recent and old MySQLdb versions. - """ + """ if type(ablob) is str: # BLOB is already a string in MySQLdb 0.9.2 return ablob else: - # BLOB is array.array in MySQLdb 1.0.0 and later + # BLOB is array.array in MySQLdb 1.0.0 and later return ablob.tostring() def log_sql_query(sql, param=None): """Log SQL query into prefix/var/dbquery.log log file. In order to enable logging of all SQL queries, please uncomment one line in run_sql() above. Useful for fine-level debugging only! """ from invenio.config import logdir from invenio.dateutils import convert_datestruct_to_datetext import time from invenio.textutils import indent_text log_path = logdir + '/dbquery.log' date_of_log = convert_datestruct_to_datetext(time.localtime()) message = date_of_log + '-->\n' message += indent_text('Query:\n' + indent_text(str(sql), 2), 2) message += indent_text('Params:\n' + indent_text(str(param), 2), 2) message += '-----------------------------\n\n' try: log_file = open(log_path, 'a+') log_file.writelines(message) log_file.close() except: pass def get_table_update_time(tablename): """Return update time of TABLENAME. TABLENAME can contain wildcard `%' in which case we return the maximum update time value. """ # Note: in order to work with all of MySQL 4.0, 4.1, 5.0, this # function uses SHOW TABLE STATUS technique with a dirty column # position lookup to return the correct value. (Making use of # Index_Length column that is either of type long (when there are # some indexes defined) or of type None (when there are no indexes # defined, e.g. table is empty). When we shall use solely # MySQL-5.0, we can employ a much cleaner technique of using # SELECT UPDATE_TIME FROM INFORMATION_SCHEMA.TABLES WHERE # table_name='collection'. res = run_sql("SHOW TABLE STATUS LIKE '%s'" % tablename) update_times = [] # store all update times for row in res: if type(row[10]) is long or \ row[10] is None: # MySQL-4.1 and 5.0 have creation_time in 11th position, # so return next column: update_times.append(str(row[12])) else: # MySQL-4.0 has creation_time in 10th position, which is # of type datetime.datetime or str (depending on the # version of MySQLdb), so return next column: update_times.append(str(row[11])) return max(update_times) def get_table_status_info(tablename): """Return table status information on TABLENAME. Returned is a dict with keys like Name, Rows, Data_length, Max_data_length, etc. If TABLENAME does not exist, return empty dict. """ # Note: again a hack so that it works on all MySQL 4.0, 4.1, 5.0 res = run_sql("SHOW TABLE STATUS LIKE '%s'" % tablename) table_status_info = {} # store all update times for row in res: if type(row[10]) is long or \ row[10] is None: # MySQL-4.1 and 5.0 have creation time in 11th position: table_status_info['Name'] = row[0] table_status_info['Rows'] = row[4] table_status_info['Data_length'] = row[6] table_status_info['Max_data_length'] = row[8] table_status_info['Create_time'] = row[11] table_status_info['Update_time'] = row[12] else: # MySQL-4.0 has creation_time in 10th position, which is # of type datetime.datetime or str (depending on the # version of MySQLdb): table_status_info['Name'] = row[0] table_status_info['Rows'] = row[3] table_status_info['Data_length'] = row[5] table_status_info['Max_data_length'] = row[7] table_status_info['Create_time'] = row[10] table_status_info['Update_time'] = row[11] return table_status_info diff --git a/modules/miscutil/sql/tabcreate.sql b/modules/miscutil/sql/tabcreate.sql index d2e6471b2..1b946cd8f 100644 --- a/modules/miscutil/sql/tabcreate.sql +++ b/modules/miscutil/sql/tabcreate.sql @@ -1,3053 +1,3055 @@ -- $Id$ -- This file is part of CDS Invenio. -- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. -- tables for bibliographic records: CREATE TABLE IF NOT EXISTS bibrec ( id mediumint(8) unsigned NOT NULL auto_increment, creation_date datetime NOT NULL default '0000-00-00', modification_date datetime NOT NULL default '0000-00-00', PRIMARY KEY (id) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib00x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib01x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib02x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib03x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib04x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib05x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib06x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib07x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib08x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib09x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib10x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib11x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib12x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib13x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib14x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib15x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib16x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib17x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib18x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib19x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib20x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib21x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib22x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib23x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib24x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib25x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib26x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib27x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib28x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib29x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib30x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib31x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib32x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib33x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib34x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib35x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib36x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib37x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib38x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib39x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib40x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib41x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib42x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib43x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib44x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib45x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib46x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib47x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib48x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib49x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib50x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib51x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib52x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib53x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib54x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib55x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib56x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib57x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib58x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib59x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib60x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib61x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib62x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib63x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib64x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib65x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib66x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib67x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib68x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib69x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib70x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib71x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib72x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib73x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib74x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib75x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib76x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib77x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib78x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib79x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib80x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib81x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib82x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib83x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib84x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib85x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib86x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib87x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib88x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib89x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib90x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib91x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib92x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib93x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib94x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib95x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib96x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib97x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib98x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bib99x ( id mediumint(8) unsigned NOT NULL auto_increment, tag varchar(6) NOT NULL default '', value text NOT NULL, PRIMARY KEY (id), KEY kt (tag), KEY kv (value(35)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib00x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib01x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib02x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib03x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib04x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib05x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib06x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib07x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib08x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib09x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib10x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib11x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib12x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib13x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib14x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib15x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib16x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib17x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib18x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib19x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib20x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib21x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib22x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib23x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib24x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib25x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib26x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib27x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib28x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib29x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib30x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib31x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib32x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib33x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib34x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib35x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib36x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib37x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib38x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib39x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib40x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib41x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib42x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib43x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib44x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib45x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib46x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib47x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib48x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib49x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib50x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib51x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib52x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib53x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib54x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib55x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib56x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib57x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib58x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib59x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib60x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib61x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib62x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib63x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib64x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib65x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib66x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib67x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib68x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib69x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib70x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib71x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib72x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib73x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib74x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib75x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib76x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib77x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib78x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib79x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib80x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib81x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib82x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib83x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib84x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib85x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib86x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib87x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib88x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib89x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib90x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib91x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib92x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib93x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib94x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib95x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib96x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib97x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib98x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bib99x ( id_bibrec mediumint(8) unsigned NOT NULL default '0', id_bibxxx mediumint(8) unsigned NOT NULL default '0', field_number smallint(5) unsigned default NULL, KEY id_bibxxx (id_bibxxx), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; -- tables for bibliographic records formatted: CREATE TABLE IF NOT EXISTS bibfmt ( id mediumint(8) unsigned NOT NULL auto_increment, id_bibrec int(8) unsigned NOT NULL default '0', format varchar(10) NOT NULL default '', last_updated datetime NOT NULL default '0000-00-00', value longblob, PRIMARY KEY (id), KEY id_bibrec (id_bibrec), KEY format (format) ) TYPE=MyISAM; -- tables for index files: CREATE TABLE IF NOT EXISTS idxINDEX ( id mediumint(9) unsigned NOT NULL, name varchar(50) NOT NULL default '', description varchar(255) NOT NULL default '', last_updated datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (id), UNIQUE KEY name (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxINDEXNAME ( id_idxINDEX mediumint(9) unsigned NOT NULL, ln char(5) NOT NULL default '', type char(3) NOT NULL default 'sn', value varchar(255) NOT NULL, PRIMARY KEY (id_idxINDEX,ln,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxINDEX_field ( id_idxINDEX mediumint(9) unsigned NOT NULL, id_field mediumint(9) unsigned NOT NULL, regexp_punctuation varchar(255) NOT NULL default "[\.\,\:\;\?\!\"]", regexp_alphanumeric_separators varchar(255) NOT NULL default "[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]", PRIMARY KEY (id_idxINDEX,id_field) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD01F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD01R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD02F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD02R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD03F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD03R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD04F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD04R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD05F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD05R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD06F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD06R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD07F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD07R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD08F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD08R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD09F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD09R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD10F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxWORD10R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE01F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE01R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE02F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE02R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE03F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE03R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE04F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE04R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE05F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE05R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE06F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE06R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE07F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE07R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE08F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE08R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE09F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE09R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE10F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS idxPHRASE10R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; -- tables for ranking: CREATE TABLE IF NOT EXISTS rnkMETHOD ( id mediumint(9) unsigned NOT NULL auto_increment, name varchar(20) NOT NULL default '', last_updated datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (id), UNIQUE KEY name (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS rnkMETHODNAME ( id_rnkMETHOD mediumint(9) unsigned NOT NULL, ln char(5) NOT NULL default '', type char(3) NOT NULL default 'sn', value varchar(255) NOT NULL, PRIMARY KEY (id_rnkMETHOD,ln,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS rnkMETHODDATA ( id_rnkMETHOD mediumint(9) unsigned NOT NULL, relevance_data longblob, PRIMARY KEY (id_rnkMETHOD) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS collection_rnkMETHOD ( id_collection mediumint(9) unsigned NOT NULL, id_rnkMETHOD mediumint(9) unsigned NOT NULL, score tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (id_collection,id_rnkMETHOD) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS rnkWORD01F ( id mediumint(9) unsigned NOT NULL auto_increment, term varchar(50) default NULL, hitlist longblob, PRIMARY KEY (id), UNIQUE KEY term (term) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS rnkWORD01R ( id_bibrec mediumint(9) unsigned NOT NULL, termlist longblob, type enum('CURRENT','FUTURE','TEMPORARY') NOT NULL default 'CURRENT', PRIMARY KEY (id_bibrec,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS rnkPAGEVIEWS ( id_bibrec mediumint(8) unsigned default NULL, id_user int(15) unsigned default '0', client_host int(10) unsigned default NULL, view_time datetime default '0000-00-00 00:00:00', KEY view_time (view_time), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS rnkDOWNLOADS ( id_bibrec mediumint(8) unsigned default NULL, download_time datetime default '0000-00-00 00:00:00', client_host int(10) unsigned default NULL, id_user int(15) unsigned default NULL, id_bibdoc mediumint(8) unsigned default NULL, file_version smallint(2) unsigned default NULL, file_format text, KEY download_time (download_time), KEY id_bibrec (id_bibrec) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS rnkCITATIONDATA ( citation_data longblob, citation_data_reversed longblob ) TYPE=MyISAM; -- tables for collections and collection tree: CREATE TABLE IF NOT EXISTS collection ( id mediumint(9) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL, dbquery text, nbrecs int(10) unsigned default '0', reclist longblob, restricted varchar(255) default NULL, PRIMARY KEY (id), UNIQUE KEY name (name), KEY dbquery (dbquery(50)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS collectionname ( id_collection mediumint(9) unsigned NOT NULL, ln char(5) NOT NULL default '', type char(3) NOT NULL default 'sn', value varchar(255) NOT NULL, PRIMARY KEY (id_collection,ln,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS collection_collection ( id_dad mediumint(9) unsigned NOT NULL, id_son mediumint(9) unsigned NOT NULL, type char(1) NOT NULL default 'r', score tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (id_dad,id_son) ) TYPE=MyISAM; -- tables for OAI sets: CREATE TABLE IF NOT EXISTS oaiARCHIVE ( id mediumint(9) unsigned NOT NULL auto_increment, setName varchar(255) NOT NULL default '', setSpec varchar(255) NOT NULL default '', setCollection varchar(255) NOT NULL default '', setDescription text NOT NULL default '', setDefinition text NOT NULL default '', setRecList longblob, p1 text NOT NULL default '', f1 text NOT NULL default '', m1 text NOT NULL default '', p2 text NOT NULL default '', f2 text NOT NULL default '', m2 text NOT NULL default '', p3 text NOT NULL default '', f3 text NOT NULL default '', m3 text NOT NULL default '', PRIMARY KEY (id) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS oaiHARVEST ( id mediumint(9) unsigned NOT NULL auto_increment, baseurl varchar(255) NOT NULL default '', metadataprefix varchar(255) NOT NULL default 'oai_dc', arguments text, comment text, bibconvertcfgfile varchar(255), name varchar(255) NOT NULL, lastrun datetime, frequency mediumint(12) NOT NULL default '0', postprocess varchar(20) NOT NULL default 'h', bibfilterprogram varchar(255) NOT NULL default '', setspecs text NOT NULL default '', PRIMARY KEY (id) ) TYPE=MyISAM; -- tables for portal elements: CREATE TABLE IF NOT EXISTS collection_portalbox ( id_collection mediumint(9) unsigned NOT NULL, id_portalbox mediumint(9) unsigned NOT NULL, ln char(5) NOT NULL default '', position char(3) NOT NULL default 'top', score tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (id_collection,id_portalbox,ln) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS portalbox ( id mediumint(9) unsigned NOT NULL auto_increment, title text NOT NULL, body text NOT NULL, UNIQUE KEY id (id) ) TYPE=MyISAM; -- tables for search examples: CREATE TABLE IF NOT EXISTS collection_example ( id_collection mediumint(9) unsigned NOT NULL, id_example mediumint(9) unsigned NOT NULL, score tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (id_collection,id_example) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS example ( id mediumint(9) unsigned NOT NULL auto_increment, type text NOT NULL default '', body text NOT NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -- tables for collection formats: CREATE TABLE IF NOT EXISTS collection_format ( id_collection mediumint(9) unsigned NOT NULL, id_format mediumint(9) unsigned NOT NULL, score tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (id_collection,id_format) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS format ( id mediumint(9) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL, code varchar(6) NOT NULL, description varchar(255) default '', content_type varchar(255) default '', PRIMARY KEY (id), UNIQUE KEY code (code) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS formatname ( id_format mediumint(9) unsigned NOT NULL, ln char(5) NOT NULL default '', type char(3) NOT NULL default 'sn', value varchar(255) NOT NULL, PRIMARY KEY (id_format,ln,type) ) TYPE=MyISAM; -- tables for search options and MARC tags: CREATE TABLE IF NOT EXISTS collection_field_fieldvalue ( id_collection mediumint(9) unsigned NOT NULL, id_field mediumint(9) unsigned NOT NULL, id_fieldvalue mediumint(9) unsigned, type char(3) NOT NULL default 'src', score tinyint(4) unsigned NOT NULL default '0', score_fieldvalue tinyint(4) unsigned NOT NULL default '0', KEY id_collection (id_collection), KEY id_field (id_field), KEY id_fieldvalue (id_fieldvalue) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS field ( id mediumint(9) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL, code varchar(255) NOT NULL, PRIMARY KEY (id), UNIQUE KEY code (code) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS fieldname ( id_field mediumint(9) unsigned NOT NULL, ln char(5) NOT NULL default '', type char(3) NOT NULL default 'sn', value varchar(255) NOT NULL, PRIMARY KEY (id_field,ln,type) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS fieldvalue ( id mediumint(9) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL, value text NOT NULL, PRIMARY KEY (id) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS field_tag ( id_field mediumint(9) unsigned NOT NULL, id_tag mediumint(9) unsigned NOT NULL, score tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (id_field,id_tag) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS tag ( id mediumint(9) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL, value char(6) NOT NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -- tables for file management CREATE TABLE IF NOT EXISTS bibdoc ( id mediumint(9) unsigned NOT NULL auto_increment, status varchar(50) NOT NULL default '', docname varchar(250) NOT NULL default 'file', creation_date datetime NOT NULL default '0000-00-00', modification_date datetime NOT NULL default '0000-00-00', PRIMARY KEY (id) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibrec_bibdoc ( id_bibrec mediumint(9) unsigned NOT NULL default '0', id_bibdoc mediumint(9) unsigned NOT NULL default '0', type varchar(255), KEY (id_bibrec), KEY (id_bibdoc) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bibdoc_bibdoc ( id_bibdoc1 mediumint(9) unsigned NOT NULL, id_bibdoc2 mediumint(9) unsigned NOT NULL, type varchar(255), KEY (id_bibdoc1), KEY (id_bibdoc2) ) TYPE=MyISAM; -- tables for publication requests: CREATE TABLE IF NOT EXISTS publreq ( id int(11) NOT NULL auto_increment, host varchar(255) NOT NULL default '', date varchar(255) NOT NULL default '', name varchar(255) NOT NULL default '', email varchar(255) NOT NULL default '', address text NOT NULL, publication text NOT NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -- table for sessions and users: CREATE TABLE IF NOT EXISTS session ( session_key varchar(32) NOT NULL default '', session_expiry int(11) unsigned NOT NULL default '0', session_object blob, uid int(15) unsigned NOT NULL, UNIQUE KEY session_key (session_key), KEY uid (uid) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS user ( id int(15) unsigned NOT NULL auto_increment, email varchar(255) NOT NULL default '', password varchar(20) default NULL, note varchar(255) default NULL, settings blob default NULL, nickname varchar(255) NOT NULL default '', last_login datetime NOT NULL default '0000-00-00 00:00:00', UNIQUE KEY id (id), KEY email (email), KEY nickname (nickname) ) TYPE=MyISAM; -- tables for usergroups CREATE TABLE IF NOT EXISTS usergroup ( id int(15) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL default '', description text default '', join_policy char(2) NOT NULL default '', login_method varchar(255) NOT NULL default 'INTERNAL', PRIMARY KEY (id), UNIQUE KEY login_method_name (login_method(70), name), KEY name (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS user_usergroup ( id_user int(15) unsigned NOT NULL default '0', id_usergroup int(15) unsigned NOT NULL default '0', user_status char(1) NOT NULL default '', - user_status_date datetime NOT NULL default '0000-00-00 00:00:00', + user_status_date datetime NOT NULL default '0000-00-00 00:00:00', KEY id_user (id_user), KEY id_usergroup (id_usergroup) ) TYPE=MyISAM; -- tables for access control engine CREATE TABLE IF NOT EXISTS accROLE ( - id int(15) unsigned NOT NULL auto_increment, - name varchar(32), - description varchar(255), + id int(15) unsigned NOT NULL auto_increment, + name varchar(32), + description varchar(255), + firerole_def_ser tinyblob NULL, + firerole_def_src tinytext NULL, PRIMARY KEY (id), UNIQUE KEY name (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS user_accROLE ( id_user int(15) unsigned NOT NULL, id_accROLE int(15) unsigned NOT NULL, PRIMARY KEY (id_user, id_accROLE) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS accACTION ( id int(15) unsigned NOT NULL auto_increment, name varchar(32), description varchar(255), allowedkeywords varchar(255), optional ENUM ('yes', 'no') NOT NULL default 'no', - PRIMARY KEY (id), + PRIMARY KEY (id), UNIQUE KEY name (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS accARGUMENT ( id int(15) unsigned NOT NULL auto_increment, keyword varchar (32), value varchar(64), PRIMARY KEY (id), KEY KEYVAL (keyword, value) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS accROLE_accACTION_accARGUMENT ( id_accROLE int(15), id_accACTION int(15), id_accARGUMENT int(15), argumentlistid mediumint(8), KEY id_accROLE (id_accROLE), KEY id_accACTION (id_accACTION), KEY id_accARGUMENT (id_accARGUMENT) ) TYPE=MyISAM; -- tables for personal/collaborative features (baskets, alerts, searches, messages, usergroups): CREATE TABLE IF NOT EXISTS user_query ( id_user int(15) unsigned NOT NULL default '0', id_query int(15) unsigned NOT NULL default '0', hostname varchar(50) default 'unknown host', date datetime default NULL, KEY id_user (id_user,id_query) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS query ( id int(15) unsigned NOT NULL auto_increment, type char(1) NOT NULL default 'r', urlargs text NOT NULL, PRIMARY KEY (id), KEY urlargs (urlargs(100)) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS user_query_basket ( id_user int(15) unsigned NOT NULL default '0', id_query int(15) unsigned NOT NULL default '0', id_basket int(15) unsigned NOT NULL default '0', frequency varchar(5) NOT NULL default '', date_creation date default NULL, date_lastrun date default '0000-00-00', alert_name varchar(30) NOT NULL default '', notification char(1) NOT NULL default 'y', PRIMARY KEY (id_user,id_query,frequency,id_basket), KEY alert_name (alert_name) ) TYPE=MyISAM; -- baskets CREATE TABLE IF NOT EXISTS bskBASKET ( id int(15) unsigned NOT NULL auto_increment, id_owner int(15) unsigned NOT NULL default '0', name varchar(50) NOT NULL default '', date_modification datetime NOT NULL default '0000-00-00 00:00:00', nb_views int(15) NOT NULL default '0', PRIMARY KEY (id), KEY id_owner (id_owner), KEY name (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bskREC ( id_bibrec_or_bskEXTREC int(16) NOT NULL default '0', id_bskBASKET int(15) unsigned NOT NULL default '0', id_user_who_added_item int(15) NOT NULL default '0', score int(15) NOT NULL default '0', date_added datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (id_bibrec_or_bskEXTREC,id_bskBASKET), KEY id_bibrec_or_bskEXTREC (id_bibrec_or_bskEXTREC), KEY id_bskBASKET (id_bskBASKET), KEY score (score), KEY date_added (date_added) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bskEXTREC ( id int(15) unsigned NOT NULL default '0', creation_date datetime NOT NULL default '0000-00-00 00:00:00', modification_date datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (id) ) TYPE=MyISAM; -CREATE TABLE IF NOT EXISTS bskEXTFMT ( +CREATE TABLE IF NOT EXISTS bskEXTFMT ( id int(15) unsigned NOT NULL auto_increment, id_bskEXTREC int(15) unsigned NOT NULL default '0', format varchar(10) NOT NULL default '', last_updated datetime NOT NULL default '0000-00-00 00:00:00', value longblob, PRIMARY KEY (id), KEY id_bskEXTREC (id_bskEXTREC), KEY format (format) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS user_bskBASKET ( id_user int(15) unsigned NOT NULL default '0', id_bskBASKET int(15) unsigned NOT NULL default '0', topic varchar(50) NOT NULL default '', PRIMARY KEY (id_user,id_bskBASKET), KEY id_user (id_user), KEY id_bskBASKET (id_bskBASKET) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS usergroup_bskBASKET ( id_usergroup int(15) unsigned NOT NULL default '0', id_bskBASKET int(15) unsigned NOT NULL default '0', topic varchar(50) NOT NULL default '', date_shared datetime NOT NULL default '0000-00-00 00:00:00', share_level char(2) NOT NULL default '', PRIMARY KEY (id_usergroup,id_bskBASKET), KEY id_usergroup (id_usergroup), KEY id_bskBASKET (id_bskBASKET) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS bskRECORDCOMMENT ( id int(15) unsigned NOT NULL auto_increment, id_bibrec_or_bskEXTREC int(16) NOT NULL default '0', id_bskBASKET int(15) unsigned NOT NULL default '0', id_user int(15) unsigned NOT NULL default '0', title varchar(255) NOT NULL default '', body text NOT NULL, date_creation datetime NOT NULL default '0000-00-00 00:00:00', priority int(15) NOT NULL default '0', PRIMARY KEY (id), KEY id_bskBASKET (id_bskBASKET), KEY id_bibrec_or_bskEXTREC (id_bibrec_or_bskEXTREC), KEY date_creation (date_creation) ) TYPE=MyISAM; -- tables for messaging system CREATE TABLE IF NOT EXISTS msgMESSAGE ( id int(15) unsigned NOT NULL auto_increment, id_user_from int(15) unsigned NOT NULL default '0', sent_to_user_nicks text NOT NULL default '', sent_to_group_names text NOT NULL default '', subject text NOT NULL default '', body text default NULL, sent_date datetime NOT NULL default '0000-00-00 00:00:00', received_date datetime NULL default '0000-00-00 00:00:00', PRIMARY KEY id (id), KEY id_user_from (id_user_from) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS user_msgMESSAGE ( id_user_to int(15) unsigned NOT NULL default '0', id_msgMESSAGE int(15) unsigned NOT NULL default '0', status char(1) NOT NULL default 'N', PRIMARY KEY id (id_user_to, id_msgMESSAGE), KEY id_user_to (id_user_to), KEY id_msgMESSAGE (id_msgMESSAGE) ) TYPE=MyISAM; --tables for WebComment CREATE TABLE IF NOT EXISTS cmtRECORDCOMMENT ( id int(15) unsigned NOT NULL auto_increment, id_bibrec int(15) unsigned NOT NULL default '0', id_user int(15) unsigned NOT NULL default '0', title varchar(255) NOT NULL default '', body text NOT NULL default '', date_creation datetime NOT NULL default '0000-00-00 00:00:00', star_score tinyint(5) unsigned NOT NULL default '0', nb_votes_yes int(10) NOT NULL default '0', nb_votes_total int(10) unsigned NOT NULL default '0', nb_abuse_reports int(10) NOT NULL default '0', PRIMARY KEY (id), KEY id_bibrec (id_bibrec), KEY id_user (id_user) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS cmtACTIONHISTORY ( id_cmtRECORDCOMMENT int(15) unsigned NULL, id_bibrec int(15) unsigned NULL, id_user int(15) unsigned NULL default NULL, client_host int(10) unsigned NOT NULL, action_time datetime NOT NULL default '0000-00-00 00:00:00', action_code char(1) NOT NULL, KEY id_cmtRECORDCOMMENT (id_cmtRECORDCOMMENT), KEY client_host (client_host), KEY id_user (id_user), KEY action_code (action_code) ) TYPE=MyISAM; -- tables for BibFormat in Python CREATE TABLE IF NOT EXISTS fmtKNOWLEDGEBASES ( id mediumint(8) unsigned NOT NULL auto_increment, name varchar(255) default '', description text default '', PRIMARY KEY (id), UNIQUE KEY name (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS fmtKNOWLEDGEBASEMAPPINGS ( id mediumint(8) unsigned NOT NULL auto_increment, m_key varchar(255) NOT NULL default '', m_value text NOT NULL default '', id_fmtKNOWLEDGEBASES mediumint(8) NOT NULL default '0', PRIMARY KEY (id), KEY id_fmtKNOWLEDGEBASES (id_fmtKNOWLEDGEBASES) ) TYPE=MyISAM; -- tables for BibFormat, formely known as FlexElink: CREATE TABLE IF NOT EXISTS flxFORMATS ( name varchar(255) NOT NULL default '', value text, doc text, serialized longtext, PRIMARY KEY (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxKBS ( kb_name varchar(255) NOT NULL default '', kb_table varchar(255) NOT NULL default '', doc text, PRIMARY KEY (kb_name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxKBDBCOLLID2COLL ( vkey varchar(255) NOT NULL default '', value text, PRIMARY KEY (vkey) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxKBDBCOLLID2BIBTEX ( vkey varchar(255) NOT NULL default '', value text, PRIMARY KEY (vkey) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxKBEJOURNALS ( vkey varchar(255) NOT NULL default '', value text, PRIMARY KEY (vkey) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxLINKTYPES ( linktype varchar(255) NOT NULL default '', check_exists enum('Y','N') NOT NULL default 'N', solvingtype enum('INT','EXT') NOT NULL default 'EXT', base_file varchar(255) NOT NULL default '', base_url varchar(255) NOT NULL default '', PRIMARY KEY (linktype) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxLINKTYPECONDITIONS ( linktype varchar(255) NOT NULL default '', eval_order int(11) NOT NULL default '0', el_condition text NOT NULL, el_action text NOT NULL, solvingtype enum('INT','EXT') NOT NULL default 'EXT', base_file varchar(255) NOT NULL default '', base_url varchar(255) NOT NULL default '', PRIMARY KEY (linktype,eval_order) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxLINKTYPECONDITIONSACTIONS ( linktype varchar(255) NOT NULL default '', eval_order int(11) NOT NULL default '0', apply_order int(11) NOT NULL default '0', el_code text, PRIMARY KEY (linktype,eval_order,apply_order) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxLINKTYPECONDITIONSFILEFORMATS ( linktype varchar(255) NOT NULL default '', eval_order int(11) NOT NULL default '0', fname varchar(30) NOT NULL default '', PRIMARY KEY (linktype,eval_order,fname) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxFILEFORMATS ( name varchar(30) NOT NULL default '', text varchar(255) default '', extensions text, PRIMARY KEY (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxLINKTYPEPARAMS ( linktype varchar(255) NOT NULL default '', pname varchar(78) NOT NULL default '', ord tinyint(4) NOT NULL default '0', PRIMARY KEY (linktype,pname), UNIQUE KEY IDX_LINKTYPE_PARAMS_ORD (linktype,ord) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxXMLMARCEXTRULES ( type varchar(8) NOT NULL default '', varname varchar(50) NOT NULL default '', att_id varchar(150) default NULL, att_i1 varchar(150) default NULL, att_i2 varchar(150) default NULL, mvalues enum('S','N') NOT NULL default 'S', ftype enum("DATAFIELD", "CONTROLFIELD") not null, PRIMARY KEY (type,varname) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxXMLMARCEXTRULESUBFIELDS ( type varchar(8) NOT NULL default '', varname varchar(50) NOT NULL default '', sfname varchar(50) NOT NULL default '', att_label varchar(150) default NULL, PRIMARY KEY (type,varname,sfname) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxBEHAVIORCONDITIONSACTIONS ( otype varchar(40) NOT NULL default '', eval_order int(11) NOT NULL default '0', apply_order int(11) NOT NULL default '0', locator text, el_code text, PRIMARY KEY (otype,eval_order,apply_order) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxBEHAVIORCONDITIONS ( otype varchar(40) NOT NULL default '', eval_order int(11) NOT NULL default '0', el_condition text NOT NULL, PRIMARY KEY (otype,eval_order) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxBEHAVIORS ( name varchar(40) NOT NULL default '', type enum('NORMAL','IENRICH') NOT NULL default 'NORMAL', doc text, PRIMARY KEY (name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxUDFS ( fname varchar(100) NOT NULL default '', code text NOT NULL, rtype enum('STRING','BOOL') NOT NULL default 'STRING', doc text, PRIMARY KEY (fname) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxUDFPARAMS ( fname varchar(100) NOT NULL default '', pname varchar(100) NOT NULL default '', ord tinyint(4) NOT NULL default '0', PRIMARY KEY (fname,pname), UNIQUE KEY IDX_UDFS_PARAMS_ORD (fname,ord) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxUSERS ( id int(11) NOT NULL default '0', PRIMARY KEY (id) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS flxREFORMAT ( id int(10) unsigned NOT NULL auto_increment, user varchar(50) NOT NULL, date DATETIME NOT NULL, reg_select text, otypes varchar(40) not null, state varchar(20), PRIMARY KEY (id) ) TYPE=MyISAM; -- tables for webSubmit: CREATE TABLE IF NOT EXISTS sbmACTION ( lactname text, sactname char(3) NOT NULL default '', dir text, cd date default NULL, md date default NULL, actionbutton text, statustext text, PRIMARY KEY (sactname) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmALLFUNCDESCR ( function varchar(40) NOT NULL default '', description tinytext, PRIMARY KEY (function) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmAPPROVAL ( doctype varchar(10) NOT NULL default '', categ varchar(50) NOT NULL default '', rn varchar(50) NOT NULL default '', status varchar(10) NOT NULL default '', dFirstReq datetime NOT NULL default '0000-00-00 00:00:00', dLastReq datetime NOT NULL default '0000-00-00 00:00:00', dAction datetime NOT NULL default '0000-00-00 00:00:00', access varchar(20) NOT NULL default '0', PRIMARY KEY (rn) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmCOLLECTION ( id int(11) NOT NULL auto_increment, name varchar(100) NOT NULL default '', PRIMARY KEY (id) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS sbmCOLLECTION_sbmCOLLECTION ( id_father int(11) NOT NULL default '0', id_son int(11) NOT NULL default '0', catalogue_order int(11) NOT NULL default '0' ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS sbmCOLLECTION_sbmDOCTYPE ( id_father int(11) NOT NULL default '0', id_son char(10) NOT NULL default '0', catalogue_order int(11) NOT NULL default '0' ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS sbmCATEGORIES ( doctype varchar(10) NOT NULL default '', sname varchar(75) NOT NULL default '', lname varchar(75) NOT NULL default '', score tinyint unsigned NOT NULL default 0, PRIMARY KEY (doctype, sname), KEY doctype (doctype), KEY sname (sname) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmCHECKS ( chname varchar(15) NOT NULL default '', chdesc text, cd date default NULL, md date default NULL, chefi1 text, chefi2 text, PRIMARY KEY (chname) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmDOCTYPE ( ldocname text, sdocname varchar(10) default NULL, cd date default NULL, md date default NULL, description text ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmFIELD ( subname varchar(13) default NULL, pagenb int(11) default NULL, fieldnb int(11) default NULL, fidesc varchar(15) default NULL, fitext text, level char(1) default NULL, sdesc text, checkn text, cd date default NULL, md date default NULL, fiefi1 text, fiefi2 text ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmFIELDDESC ( name varchar(15) NOT NULL default '', alephcode varchar(50) default NULL, marccode varchar(50) NOT NULL default '', type char(1) default NULL, size int(11) default NULL, rows int(11) default NULL, cols int(11) default NULL, maxlength int(11) default NULL, val text, fidesc text, cd date default NULL, md date default NULL, modifytext text, fddfi2 text, cookie int(11) default '0', PRIMARY KEY (name) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmFORMATEXTENSION ( FILE_FORMAT text NOT NULL, FILE_EXTENSION text NOT NULL ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmFUNCTIONS ( action varchar(10) NOT NULL default '', doctype varchar(10) NOT NULL default '', function varchar(40) NOT NULL default '', score int(11) NOT NULL default '0', step tinyint(4) NOT NULL default '1' ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmFUNDESC ( function varchar(40) NOT NULL default '', param varchar(40) default NULL ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmGFILERESULT ( FORMAT text NOT NULL, RESULT text NOT NULL ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmIMPLEMENT ( docname varchar(10) default NULL, actname char(3) default NULL, displayed char(1) default NULL, subname varchar(13) default NULL, nbpg int(11) default NULL, cd date default NULL, md date default NULL, buttonorder int(11) default NULL, statustext text, level char(1) NOT NULL default '', score int(11) NOT NULL default '0', stpage int(11) NOT NULL default '0', endtxt varchar(100) NOT NULL default '' ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmPARAMETERS ( doctype varchar(10) NOT NULL default '', name varchar(20) NOT NULL default '', value varchar(200) NOT NULL default '', PRIMARY KEY (doctype,name) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS sbmPUBLICATION ( doctype varchar(10) NOT NULL default '', categ varchar(50) NOT NULL default '', rn varchar(50) NOT NULL default '', status varchar(10) NOT NULL default '', dFirstReq datetime NOT NULL default '0000-00-00 00:00:00', dLastReq datetime NOT NULL default '0000-00-00 00:00:00', dAction datetime NOT NULL default '0000-00-00 00:00:00', accessref varchar(20) NOT NULL default '', accessedi varchar(20) NOT NULL default '', access varchar(20) NOT NULL default '', referees varchar(50) NOT NULL default '', authoremail varchar(50) NOT NULL default '', dRefSelection datetime NOT NULL default '0000-00-00 00:00:00', dRefRec datetime NOT NULL default '0000-00-00 00:00:00', dEdiRec datetime NOT NULL default '0000-00-00 00:00:00', accessspo varchar(20) NOT NULL default '', journal varchar(100) default NULL, PRIMARY KEY (doctype,categ,rn) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmPUBLICATIONCOMM ( id int(11) NOT NULL auto_increment, id_parent int(11) default '0', rn varchar(100) NOT NULL default '', firstname varchar(100) default NULL, secondname varchar(100) default NULL, email varchar(100) default NULL, date varchar(40) NOT NULL default '', synopsis varchar(255) NOT NULL default '', commentfulltext text, PRIMARY KEY (id) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmPUBLICATIONDATA ( doctype varchar(10) NOT NULL default '', editoboard varchar(250) NOT NULL default '', base varchar(10) NOT NULL default '', logicalbase varchar(10) NOT NULL default '', spokesperson varchar(50) NOT NULL default '', PRIMARY KEY (doctype) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmREFEREES ( doctype varchar(10) NOT NULL default '', categ varchar(10) NOT NULL default '', name varchar(50) NOT NULL default '', address varchar(50) NOT NULL default '', rid int(11) NOT NULL auto_increment, PRIMARY KEY (rid) ) TYPE=MyISAM PACK_KEYS=1; CREATE TABLE IF NOT EXISTS sbmSUBMISSIONS ( email varchar(50) NOT NULL default '', doctype varchar(10) NOT NULL default '', action varchar(10) NOT NULL default '', status varchar(10) NOT NULL default '', id varchar(30) NOT NULL default '', reference varchar(40) NOT NULL default '', cd datetime NOT NULL default '0000-00-00 00:00:00', md datetime NOT NULL default '0000-00-00 00:00:00' ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS sbmCOOKIES ( id int(15) unsigned NOT NULL auto_increment, name varchar(100) NOT NULL, value text, uid int(15) NOT NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -- Scheduler tables CREATE TABLE IF NOT EXISTS schTASK ( id int(15) unsigned NOT NULL auto_increment, proc varchar(20) NOT NULL, host varchar(255) NOT NULL, user varchar(50) NOT NULL, runtime datetime NOT NULL, sleeptime varchar(20), arguments mediumblob, status varchar(50), progress varchar(255), PRIMARY KEY (id), KEY status (status), KEY runtime (runtime) ) TYPE=MyISAM; -- External collections CREATE TABLE IF NOT EXISTS collection_externalcollection ( id_collection mediumint(9) unsigned NOT NULL default '0', id_externalcollection mediumint(9) unsigned NOT NULL default '0', type tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (id_collection, id_externalcollection) ) TYPE=MyISAM; CREATE TABLE IF NOT EXISTS externalcollection ( id mediumint(9) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL default '', PRIMARY KEY (id), UNIQUE KEY name (name) ) TYPE=MyISAM; -- end of file diff --git a/modules/miscutil/sql/tabfill.sql.wml b/modules/miscutil/sql/tabfill.sql.wml index d415aeb1a..3e3f62dc5 100644 --- a/modules/miscutil/sql/tabfill.sql.wml +++ b/modules/miscutil/sql/tabfill.sql.wml @@ -1,1350 +1,1351 @@ ## -*- mode: sql; coding: utf-8; -*- ## $Id$ ## Fills configuration tables with defaults. ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. ## read config variables: #include "config.wml" #include "configbis.wml" ## local defaults, i.e. WML config variables are to be used: INSERT INTO collection VALUES (1,"",NULL,NULL,NULL,NULL); INSERT INTO collectionname VALUES (1,'en','ln',""); INSERT INTO collectionname VALUES (1,'fr','ln',""); INSERT INTO collectionname VALUES (1,'de','ln',""); INSERT INTO collectionname VALUES (1,'es','ln',""); INSERT INTO collectionname VALUES (1,'ca','ln',""); INSERT INTO collectionname VALUES (1,'pl','ln',""); INSERT INTO collectionname VALUES (1,'pt','ln',""); INSERT INTO collectionname VALUES (1,'it','ln',""); INSERT INTO collectionname VALUES (1,'ja','ln',""); INSERT INTO collectionname VALUES (1,'ru','ln',""); INSERT INTO collectionname VALUES (1,'sk','ln',""); INSERT INTO collectionname VALUES (1,'cs','ln',""); INSERT INTO collectionname VALUES (1,'no','ln',""); INSERT INTO collectionname VALUES (1,'sv','ln',""); INSERT INTO collectionname VALUES (1,'el','ln',""); INSERT INTO collectionname VALUES (1,'uk','ln',""); INSERT INTO collectionname VALUES (1,'bg','ln',""); INSERT INTO collectionname VALUES (1,'hr','ln',""); INSERT INTO collectionname VALUES (1,'zh_CN','ln',""); INSERT INTO collectionname VALUES (1,'zh_TW','ln',""); INSERT INTO user VALUES (1, "", '', 1, NULL, 'admin', ''); INSERT INTO flxLINKTYPES VALUES ('AUTHOR_SEARCH','N','EXT','',''); INSERT INTO flxLINKTYPES VALUES ('KEYWORD_SEARCH','N','EXT','',''); INSERT INTO flxLINKTYPECONDITIONS VALUES ('AUTHOR_SEARCH',0,' \"\"=\"\" ','\"/search?f=author&p=\" urlencode($author)','EXT','',''); INSERT INTO flxLINKTYPECONDITIONS VALUES ('KEYWORD_SEARCH',0,' \"\"=\"\" ','\"/search?f=keyword&p=\" urlencode($keyword)','EXT','',''); INSERT INTO flxLINKTYPECONDITIONSACTIONS VALUES ('AUTHOR_SEARCH',0,0,'\"/search?f=author&p=\" urlencode($author)'); INSERT INTO flxLINKTYPECONDITIONSACTIONS VALUES ('KEYWORD_SEARCH',0,0,'\"/search?f=keyword&p=\" urlencode($keyword)'); INSERT INTO flxLINKTYPEPARAMS VALUES ('AUTHOR_SEARCH','AUTHOR',0); INSERT INTO flxLINKTYPEPARAMS VALUES ('KEYWORD_SEARCH','KEYWORD',0); ## generally suitable defaults: INSERT INTO rnkMETHOD (id,name,last_updated) VALUES (1,'wrd','0000-00-00 00:00:00'); INSERT INTO collection_rnkMETHOD (id_collection,id_rnkMETHOD,score) VALUES (1,1,100); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'en','ln','word similarity'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'fr','ln','similarité de mots'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'de','ln','Wortähnlichkeit'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'es','ln','similitud de palabras'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'ca','ln','semblança de paraules'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'pl','ln','word similarity'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'pt','ln','similaridade por palavra'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'it','ln','word similarity'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'ja','ln','word similarity'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'ru','ln','похожые слова'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'sk','ln','podobnosť slov'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'cs','ln','podobnost slov'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'no','ln','ord-likhet'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'sv','ln','ord-likhet'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'el','ln','ομοιότητα λέξης'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'uk','ln','подібні слова'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'bg','ln','word similarity'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'hr','ln','sličnost riječi'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'zh_CN','ln','相似字词'); INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES (1,'zh_TW','ln','相似字詞'); INSERT INTO field VALUES (1,'any field','anyfield'); INSERT INTO field VALUES (2,'title','title'); INSERT INTO field VALUES (3,'author','author'); INSERT INTO field VALUES (4,'abstract','abstract'); INSERT INTO field VALUES (5,'keyword','keyword'); INSERT INTO field VALUES (6,'report number','reportnumber'); INSERT INTO field VALUES (7,'subject','subject'); INSERT INTO field VALUES (8,'reference','reference'); INSERT INTO field VALUES (9,'fulltext','fulltext'); INSERT INTO field VALUES (10,'collection','collection'); INSERT INTO field VALUES (11,'division','division'); INSERT INTO field VALUES (12,'year','year'); INSERT INTO field VALUES (13,'experiment','experiment'); INSERT INTO field VALUES (14,'record ID','recid'); INSERT INTO fieldname VALUES (1,'en','ln','any field'); INSERT INTO fieldname VALUES (1,'fr','ln','tous les champs'); INSERT INTO fieldname VALUES (1,'de','ln','alle Felder'); INSERT INTO fieldname VALUES (1,'es','ln','cualquier campo'); INSERT INTO fieldname VALUES (1,'ca','ln','qualsevol camp'); INSERT INTO fieldname VALUES (1,'pl','ln','dowolne pole'); INSERT INTO fieldname VALUES (1,'pt','ln','qualquer campo'); INSERT INTO fieldname VALUES (1,'it','ln','tutti i campi'); INSERT INTO fieldname VALUES (1,'ru','ln','любое поле'); INSERT INTO fieldname VALUES (1,'sk','ln','všetky polia'); INSERT INTO fieldname VALUES (1,'cs','ln','všechna pole'); INSERT INTO fieldname VALUES (1,'no','ln','alle felt'); INSERT INTO fieldname VALUES (1,'sv','ln','samtliga fält'); INSERT INTO fieldname VALUES (1,'el','ln','οποιοδήποτε πεδίο'); INSERT INTO fieldname VALUES (1,'uk','ln','всі поля'); INSERT INTO fieldname VALUES (1,'ja','ln','すべての分野'); INSERT INTO fieldname VALUES (1,'bg','ln','всички'); INSERT INTO fieldname VALUES (1,'hr','ln','bilo koje polje'); INSERT INTO fieldname VALUES (1,'zh_CN','ln','任何字段'); INSERT INTO fieldname VALUES (1,'zh_TW','ln','任何欄位'); INSERT INTO fieldname VALUES (2,'en','ln','title'); INSERT INTO fieldname VALUES (2,'fr','ln','titre'); INSERT INTO fieldname VALUES (2,'de','ln','Titel'); INSERT INTO fieldname VALUES (2,'es','ln','título'); INSERT INTO fieldname VALUES (2,'ca','ln','títol'); INSERT INTO fieldname VALUES (2,'pl','ln','tytuł'); INSERT INTO fieldname VALUES (2,'pt','ln','título'); INSERT INTO fieldname VALUES (2,'it','ln','titolo'); INSERT INTO fieldname VALUES (2,'ru','ln','название'); INSERT INTO fieldname VALUES (2,'sk','ln','názov'); INSERT INTO fieldname VALUES (2,'cs','ln','název'); INSERT INTO fieldname VALUES (2,'no','ln','tittel'); INSERT INTO fieldname VALUES (2,'sv','ln','titel'); INSERT INTO fieldname VALUES (2,'el','ln','τίτλος'); INSERT INTO fieldname VALUES (2,'uk','ln','назва'); INSERT INTO fieldname VALUES (2,'ja','ln','タイトル'); INSERT INTO fieldname VALUES (2,'bg','ln','заглавие'); INSERT INTO fieldname VALUES (2,'hr','ln','naslov'); INSERT INTO fieldname VALUES (2,'zh_CN','ln','标题'); INSERT INTO fieldname VALUES (2,'zh_TW','ln','標題'); INSERT INTO fieldname VALUES (3,'en','ln','author'); INSERT INTO fieldname VALUES (3,'fr','ln','auteur'); INSERT INTO fieldname VALUES (3,'de','ln','Autor'); INSERT INTO fieldname VALUES (3,'es','ln','autor'); INSERT INTO fieldname VALUES (3,'ca','ln','autor'); INSERT INTO fieldname VALUES (3,'pl','ln','autor'); INSERT INTO fieldname VALUES (3,'pt','ln','autor'); INSERT INTO fieldname VALUES (3,'it','ln','autore'); INSERT INTO fieldname VALUES (3,'ru','ln','автор'); INSERT INTO fieldname VALUES (3,'sk','ln','autor'); INSERT INTO fieldname VALUES (3,'cs','ln','autor'); INSERT INTO fieldname VALUES (3,'no','ln','forfatter'); INSERT INTO fieldname VALUES (3,'sv','ln','författare'); INSERT INTO fieldname VALUES (3,'el','ln','συγγραφέας'); INSERT INTO fieldname VALUES (3,'uk','ln','автор'); INSERT INTO fieldname VALUES (3,'ja','ln','著者'); INSERT INTO fieldname VALUES (3,'bg','ln','автор'); INSERT INTO fieldname VALUES (3,'hr','ln','autor'); INSERT INTO fieldname VALUES (3,'zh_CN','ln','作者'); INSERT INTO fieldname VALUES (3,'zh_TW','ln','作者'); INSERT INTO fieldname VALUES (4,'en','ln','abstract'); INSERT INTO fieldname VALUES (4,'fr','ln','abstract'); INSERT INTO fieldname VALUES (4,'de','ln','Abstrakt'); INSERT INTO fieldname VALUES (4,'es','ln','resumen'); INSERT INTO fieldname VALUES (4,'ca','ln','resum'); INSERT INTO fieldname VALUES (4,'pl','ln','abstrakt'); INSERT INTO fieldname VALUES (4,'pt','ln','resumo'); INSERT INTO fieldname VALUES (4,'it','ln','riassunto'); INSERT INTO fieldname VALUES (4,'ru','ln','абстракт'); INSERT INTO fieldname VALUES (4,'sk','ln','abstrakt'); INSERT INTO fieldname VALUES (4,'cs','ln','abstrakt'); INSERT INTO fieldname VALUES (4,'no','ln','sammendrag'); INSERT INTO fieldname VALUES (4,'sv','ln','sammanfattning'); INSERT INTO fieldname VALUES (4,'el','ln','περίληψη'); INSERT INTO fieldname VALUES (4,'uk','ln','резюме'); INSERT INTO fieldname VALUES (4,'ja','ln','概要'); INSERT INTO fieldname VALUES (4,'bg','ln','резюме'); INSERT INTO fieldname VALUES (4,'hr','ln','sažetak'); INSERT INTO fieldname VALUES (4,'zh_CN','ln','摘要'); INSERT INTO fieldname VALUES (4,'zh_TW','ln','摘要'); INSERT INTO fieldname VALUES (5,'en','ln','keyword'); INSERT INTO fieldname VALUES (5,'fr','ln','mot clé'); INSERT INTO fieldname VALUES (5,'de','ln','Kennwort'); INSERT INTO fieldname VALUES (5,'es','ln','palabra clave'); INSERT INTO fieldname VALUES (5,'ca','ln','paraula clau'); INSERT INTO fieldname VALUES (5,'pl','ln','słowo kluczowe'); INSERT INTO fieldname VALUES (5,'pt','ln','palavra chave'); INSERT INTO fieldname VALUES (5,'it','ln','parola chiave'); INSERT INTO fieldname VALUES (5,'ru','ln','ключевое слово'); INSERT INTO fieldname VALUES (5,'sk','ln','kľúčové slovo'); INSERT INTO fieldname VALUES (5,'cs','ln','klíčové slovo'); INSERT INTO fieldname VALUES (5,'no','ln','nøkkelord'); INSERT INTO fieldname VALUES (5,'sv','ln','nyckelord'); INSERT INTO fieldname VALUES (5,'el','ln','λέξη κλειδί'); INSERT INTO fieldname VALUES (5,'uk','ln','ключеве слово'); INSERT INTO fieldname VALUES (5,'ja','ln','キーワード'); INSERT INTO fieldname VALUES (5,'bg','ln','ключова дума'); INSERT INTO fieldname VALUES (5,'hr','ln','ključna riječ'); INSERT INTO fieldname VALUES (5,'zh_CN','ln','关键词'); INSERT INTO fieldname VALUES (5,'zh_TW','ln','關鍵詞'); INSERT INTO fieldname VALUES (6,'en','ln','report number'); INSERT INTO fieldname VALUES (6,'fr','ln','numéro de rapport'); INSERT INTO fieldname VALUES (6,'de','ln','Reportnummer'); INSERT INTO fieldname VALUES (6,'es','ln','número de reporte'); INSERT INTO fieldname VALUES (6,'ca','ln','número d\'informe'); INSERT INTO fieldname VALUES (6,'pl','ln','numer raportu'); INSERT INTO fieldname VALUES (6,'pt','ln','número de registro'); INSERT INTO fieldname VALUES (6,'it','ln','numero del rapporto'); INSERT INTO fieldname VALUES (6,'ru','ln','номер документа'); INSERT INTO fieldname VALUES (6,'sk','ln','číslo správy'); INSERT INTO fieldname VALUES (6,'cs','ln','číslo zprávy'); INSERT INTO fieldname VALUES (6,'no','ln','rapportnummer'); INSERT INTO fieldname VALUES (6,'sv','ln','rapportnummer'); INSERT INTO fieldname VALUES (6,'el','ln','αριθμός αναφοράς'); INSERT INTO fieldname VALUES (6,'uk','ln','номер документа'); INSERT INTO fieldname VALUES (6,'ja','ln','レポート数'); INSERT INTO fieldname VALUES (6,'bg','ln','номер на документа'); INSERT INTO fieldname VALUES (6,'hr','ln','broj izvještaja'); INSERT INTO fieldname VALUES (6,'zh_CN','ln','报告编号'); INSERT INTO fieldname VALUES (6,'zh_TW','ln','報告編號'); INSERT INTO fieldname VALUES (7,'en','ln','subject'); INSERT INTO fieldname VALUES (7,'fr','ln','sujet'); INSERT INTO fieldname VALUES (7,'de','ln','Thema'); INSERT INTO fieldname VALUES (7,'es','ln','materia'); INSERT INTO fieldname VALUES (7,'ca','ln','matèria'); INSERT INTO fieldname VALUES (7,'pl','ln','temat'); INSERT INTO fieldname VALUES (7,'pt','ln','assunto'); INSERT INTO fieldname VALUES (7,'it','ln','soggetto'); INSERT INTO fieldname VALUES (7,'ru','ln','предмет'); INSERT INTO fieldname VALUES (7,'sk','ln','predmet'); INSERT INTO fieldname VALUES (7,'cs','ln','předmět'); INSERT INTO fieldname VALUES (7,'no','ln','emne'); INSERT INTO fieldname VALUES (7,'sv','ln',''); INSERT INTO fieldname VALUES (7,'el','ln','θέμα'); INSERT INTO fieldname VALUES (7,'uk','ln','тема'); INSERT INTO fieldname VALUES (7,'ja','ln','ツ 主題'); INSERT INTO fieldname VALUES (7,'bg','ln','тема'); INSERT INTO fieldname VALUES (7,'hr','ln','predmetna odrednica'); INSERT INTO fieldname VALUES (7,'zh_CN','ln','主题'); INSERT INTO fieldname VALUES (7,'zh_TW','ln','主題'); INSERT INTO fieldname VALUES (8,'en','ln','reference'); INSERT INTO fieldname VALUES (8,'fr','ln','référence'); INSERT INTO fieldname VALUES (8,'de','ln','Referenz'); INSERT INTO fieldname VALUES (8,'es','ln','referencia'); INSERT INTO fieldname VALUES (8,'ca','ln','referència'); INSERT INTO fieldname VALUES (8,'pl','ln','odnośnik'); INSERT INTO fieldname VALUES (8,'pt','ln','referência'); INSERT INTO fieldname VALUES (8,'it','ln','referenza'); INSERT INTO fieldname VALUES (8,'ru','ln','ссылка'); INSERT INTO fieldname VALUES (8,'sk','ln','referencie'); INSERT INTO fieldname VALUES (8,'cs','ln','reference'); INSERT INTO fieldname VALUES (8,'no','ln','referanse'); INSERT INTO fieldname VALUES (8,'sv','ln','referens'); INSERT INTO fieldname VALUES (8,'el','ln','αναφορά'); INSERT INTO fieldname VALUES (8,'uk','ln','посилання'); INSERT INTO fieldname VALUES (8,'ja','ln','参照'); INSERT INTO fieldname VALUES (8,'bg','ln','препратка'); INSERT INTO fieldname VALUES (8,'hr','ln','referenca'); INSERT INTO fieldname VALUES (8,'zh_CN','ln','参考'); INSERT INTO fieldname VALUES (8,'zh_TW','ln','參考'); INSERT INTO fieldname VALUES (9,'en','ln','fulltext'); INSERT INTO fieldname VALUES (9,'fr','ln','fulltext'); INSERT INTO fieldname VALUES (9,'de','ln','Volltext'); INSERT INTO fieldname VALUES (9,'es','ln','texto completo'); INSERT INTO fieldname VALUES (9,'ca','ln','text complert'); INSERT INTO fieldname VALUES (9,'pl','ln','pełny tekst'); INSERT INTO fieldname VALUES (9,'pt','ln','texto completo'); INSERT INTO fieldname VALUES (9,'it','ln','testo completo'); INSERT INTO fieldname VALUES (9,'ru','ln','полный текст'); INSERT INTO fieldname VALUES (9,'sk','ln','plný text'); INSERT INTO fieldname VALUES (9,'cs','ln','plný text'); INSERT INTO fieldname VALUES (9,'no','ln','fulltekst'); INSERT INTO fieldname VALUES (9,'sv','ln','fulltext'); INSERT INTO fieldname VALUES (9,'el','ln','πλήρες κείμενο'); INSERT INTO fieldname VALUES (9,'uk','ln','повний текст'); INSERT INTO fieldname VALUES (9,'ja','ln','フルテキスト'); INSERT INTO fieldname VALUES (9,'bg','ln','пълен текст'); INSERT INTO fieldname VALUES (9,'hr','ln','cjeloviti tekst'); INSERT INTO fieldname VALUES (9,'zh_CN','ln','全文'); INSERT INTO fieldname VALUES (9,'zh_TW','ln','全文'); INSERT INTO fieldname VALUES (10,'en','ln','collection'); INSERT INTO fieldname VALUES (10,'fr','ln','collection'); INSERT INTO fieldname VALUES (10,'de','ln','Sammlung'); INSERT INTO fieldname VALUES (10,'es','ln','colección'); INSERT INTO fieldname VALUES (10,'ca','ln','col·lecció'); INSERT INTO fieldname VALUES (10,'pl','ln','zbiór'); INSERT INTO fieldname VALUES (10,'pt','ln','coleção'); INSERT INTO fieldname VALUES (10,'it','ln','collezione'); INSERT INTO fieldname VALUES (10,'ru','ln','набор'); INSERT INTO fieldname VALUES (10,'sk','ln','kolekcia'); INSERT INTO fieldname VALUES (10,'cs','ln','kolekce'); INSERT INTO fieldname VALUES (10,'no','ln','samling'); INSERT INTO fieldname VALUES (10,'sv','ln','samlingen'); INSERT INTO fieldname VALUES (10,'el','ln','συλλογή'); INSERT INTO fieldname VALUES (10,'uk','ln','розділ'); INSERT INTO fieldname VALUES (10,'ja','ln','コレクション'); INSERT INTO fieldname VALUES (10,'bg','ln','колекция'); INSERT INTO fieldname VALUES (10,'hr','ln','kolekcija'); INSERT INTO fieldname VALUES (10,'zh_CN','ln','汇集'); INSERT INTO fieldname VALUES (10,'zh_TW','ln','彙集'); INSERT INTO fieldname VALUES (11,'en','ln','division'); INSERT INTO fieldname VALUES (11,'fr','ln','division'); INSERT INTO fieldname VALUES (11,'de','ln','Abteilung'); INSERT INTO fieldname VALUES (11,'es','ln','división'); INSERT INTO fieldname VALUES (11,'ca','ln','divisió'); INSERT INTO fieldname VALUES (11,'pl','ln','podział'); INSERT INTO fieldname VALUES (11,'pt','ln','divisão'); INSERT INTO fieldname VALUES (11,'it','ln','divisione'); INSERT INTO fieldname VALUES (11,'ru','ln','разделение'); INSERT INTO fieldname VALUES (11,'sk','ln','oddelenie'); INSERT INTO fieldname VALUES (11,'cs','ln','oddělení'); INSERT INTO fieldname VALUES (11,'no','ln','divisjon'); INSERT INTO fieldname VALUES (11,'sv','ln',''); INSERT INTO fieldname VALUES (11,'el','ln','τμήμα'); INSERT INTO fieldname VALUES (11,'uk','ln','підрозділ'); INSERT INTO fieldname VALUES (11,'ja','ln','部'); INSERT INTO fieldname VALUES (11,'bg','ln','отдел'); INSERT INTO fieldname VALUES (11,'hr','ln','odjel'); INSERT INTO fieldname VALUES (11,'zh_CN','ln','分类'); INSERT INTO fieldname VALUES (11,'zh_TW','ln','分類'); INSERT INTO fieldname VALUES (12,'en','ln','year'); INSERT INTO fieldname VALUES (12,'fr','ln','année'); INSERT INTO fieldname VALUES (12,'de','ln','Jahr'); INSERT INTO fieldname VALUES (12,'es','ln','año'); INSERT INTO fieldname VALUES (12,'ca','ln','any'); INSERT INTO fieldname VALUES (12,'pl','ln','rok'); INSERT INTO fieldname VALUES (12,'pt','ln','ano'); INSERT INTO fieldname VALUES (12,'it','ln','anno'); INSERT INTO fieldname VALUES (12,'ru','ln','год'); INSERT INTO fieldname VALUES (12,'sk','ln','rok'); INSERT INTO fieldname VALUES (12,'cs','ln','rok'); INSERT INTO fieldname VALUES (12,'no','ln','år'); INSERT INTO fieldname VALUES (12,'sv','ln','år'); INSERT INTO fieldname VALUES (12,'el','ln','έτος'); INSERT INTO fieldname VALUES (12,'uk','ln','рік'); INSERT INTO fieldname VALUES (12,'ja','ln','年'); INSERT INTO fieldname VALUES (12,'bg','ln','година'); INSERT INTO fieldname VALUES (12,'hr','ln','godina'); INSERT INTO fieldname VALUES (12,'zh_CN','ln','年份'); INSERT INTO fieldname VALUES (12,'zh_TW','ln','年份'); INSERT INTO fieldname VALUES (13,'en','ln','experiment'); INSERT INTO fieldname VALUES (13,'fr','ln','expérience'); INSERT INTO fieldname VALUES (13,'de','ln','Experiment'); INSERT INTO fieldname VALUES (13,'es','ln','experimento'); INSERT INTO fieldname VALUES (13,'ca','ln','experiment'); INSERT INTO fieldname VALUES (13,'pl','ln','eksperyment'); INSERT INTO fieldname VALUES (13,'pt','ln','experimento'); INSERT INTO fieldname VALUES (13,'it','ln','esperimento'); INSERT INTO fieldname VALUES (13,'ru','ln','эксперимент'); INSERT INTO fieldname VALUES (13,'sk','ln','experiment'); INSERT INTO fieldname VALUES (13,'cs','ln','experiment'); INSERT INTO fieldname VALUES (13,'no','ln','eksperiment'); INSERT INTO fieldname VALUES (13,'sv','ln',''); INSERT INTO fieldname VALUES (13,'el','ln','πείραμα'); INSERT INTO fieldname VALUES (13,'uk','ln','експеримент'); INSERT INTO fieldname VALUES (13,'ja','ln','実験'); INSERT INTO fieldname VALUES (13,'bg','ln','експеримент'); INSERT INTO fieldname VALUES (13,'hr','ln','eksperiment'); INSERT INTO fieldname VALUES (13,'zh_CN','ln','实验'); INSERT INTO fieldname VALUES (13,'zh_TW','ln','實驗'); INSERT INTO fieldname VALUES (14,'en','ln','record ID'); INSERT INTO fieldname VALUES (14,'fr','ln','identificateur de notice'); INSERT INTO fieldname VALUES (14,'de','ln','Datensatz-ID'); INSERT INTO fieldname VALUES (14,'es','ln','registro núm.'); INSERT INTO fieldname VALUES (14,'ca','ln','registre núm.'); INSERT INTO fieldname VALUES (14,'pl','ln','ID rekordu'); INSERT INTO fieldname VALUES (14,'pt','ln','ID do registro'); INSERT INTO fieldname VALUES (14,'it','ln','ID della notizia'); INSERT INTO fieldname VALUES (14,'ru','ln','номер записи'); INSERT INTO fieldname VALUES (14,'sk','ln','ID záznamu'); INSERT INTO fieldname VALUES (14,'cs','ln','ID záznamu'); INSERT INTO fieldname VALUES (14,'no','ln','post ID'); INSERT INTO fieldname VALUES (14,'sv','ln',''); INSERT INTO fieldname VALUES (14,'el','ln','record ID'); INSERT INTO fieldname VALUES (14,'uk','ln','номер запису'); INSERT INTO fieldname VALUES (14,'ja','ln','記録的なID'); INSERT INTO fieldname VALUES (14,'bg','ln','ID на записа'); INSERT INTO fieldname VALUES (14,'hr','ln','ID unosa'); INSERT INTO fieldname VALUES (14,'zh_CN','ln','记录号'); INSERT INTO fieldname VALUES (14,'zh_TW','ln','記錄號'); INSERT INTO field_tag VALUES (1,100,10); INSERT INTO field_tag VALUES (1,101,10); INSERT INTO field_tag VALUES (1,102,10); INSERT INTO field_tag VALUES (1,103,10); INSERT INTO field_tag VALUES (1,104,10); INSERT INTO field_tag VALUES (1,105,10); INSERT INTO field_tag VALUES (1,106,10); INSERT INTO field_tag VALUES (1,107,10); INSERT INTO field_tag VALUES (1,108,10); INSERT INTO field_tag VALUES (1,109,10); INSERT INTO field_tag VALUES (1,110,10); INSERT INTO field_tag VALUES (1,111,10); INSERT INTO field_tag VALUES (1,112,10); INSERT INTO field_tag VALUES (1,113,10); INSERT INTO field_tag VALUES (1,114,10); INSERT INTO field_tag VALUES (1,16,10); INSERT INTO field_tag VALUES (1,17,10); INSERT INTO field_tag VALUES (1,18,10); INSERT INTO field_tag VALUES (1,19,10); INSERT INTO field_tag VALUES (1,20,10); INSERT INTO field_tag VALUES (1,21,10); INSERT INTO field_tag VALUES (1,22,10); INSERT INTO field_tag VALUES (1,23,10); INSERT INTO field_tag VALUES (1,24,10); INSERT INTO field_tag VALUES (1,25,10); INSERT INTO field_tag VALUES (1,26,10); INSERT INTO field_tag VALUES (1,27,10); INSERT INTO field_tag VALUES (1,28,10); INSERT INTO field_tag VALUES (1,29,10); INSERT INTO field_tag VALUES (1,30,10); INSERT INTO field_tag VALUES (1,31,10); INSERT INTO field_tag VALUES (1,32,10); INSERT INTO field_tag VALUES (1,33,10); INSERT INTO field_tag VALUES (1,34,10); INSERT INTO field_tag VALUES (1,35,10); INSERT INTO field_tag VALUES (1,36,10); INSERT INTO field_tag VALUES (1,37,10); INSERT INTO field_tag VALUES (1,38,10); INSERT INTO field_tag VALUES (1,39,10); INSERT INTO field_tag VALUES (1,40,10); INSERT INTO field_tag VALUES (1,41,10); INSERT INTO field_tag VALUES (1,42,10); INSERT INTO field_tag VALUES (1,43,10); INSERT INTO field_tag VALUES (1,44,10); INSERT INTO field_tag VALUES (1,45,10); INSERT INTO field_tag VALUES (1,46,10); INSERT INTO field_tag VALUES (1,47,10); INSERT INTO field_tag VALUES (1,48,10); INSERT INTO field_tag VALUES (1,49,10); INSERT INTO field_tag VALUES (1,50,10); INSERT INTO field_tag VALUES (1,51,10); INSERT INTO field_tag VALUES (1,52,10); INSERT INTO field_tag VALUES (1,53,10); INSERT INTO field_tag VALUES (1,54,10); INSERT INTO field_tag VALUES (1,55,10); INSERT INTO field_tag VALUES (1,56,10); INSERT INTO field_tag VALUES (1,57,10); INSERT INTO field_tag VALUES (1,58,10); INSERT INTO field_tag VALUES (1,59,10); INSERT INTO field_tag VALUES (1,60,10); INSERT INTO field_tag VALUES (1,61,10); INSERT INTO field_tag VALUES (1,62,10); INSERT INTO field_tag VALUES (1,63,10); INSERT INTO field_tag VALUES (1,64,10); INSERT INTO field_tag VALUES (1,65,10); INSERT INTO field_tag VALUES (1,66,10); INSERT INTO field_tag VALUES (1,67,10); INSERT INTO field_tag VALUES (1,68,10); INSERT INTO field_tag VALUES (1,69,10); INSERT INTO field_tag VALUES (1,70,10); INSERT INTO field_tag VALUES (1,71,10); INSERT INTO field_tag VALUES (1,72,10); INSERT INTO field_tag VALUES (1,73,10); INSERT INTO field_tag VALUES (1,74,10); INSERT INTO field_tag VALUES (1,75,10); INSERT INTO field_tag VALUES (1,76,10); INSERT INTO field_tag VALUES (1,77,10); INSERT INTO field_tag VALUES (1,78,10); INSERT INTO field_tag VALUES (1,79,10); INSERT INTO field_tag VALUES (1,80,10); INSERT INTO field_tag VALUES (1,81,10); INSERT INTO field_tag VALUES (1,82,10); INSERT INTO field_tag VALUES (1,83,10); INSERT INTO field_tag VALUES (1,84,10); INSERT INTO field_tag VALUES (1,85,10); INSERT INTO field_tag VALUES (1,86,10); INSERT INTO field_tag VALUES (1,87,10); INSERT INTO field_tag VALUES (1,88,10); INSERT INTO field_tag VALUES (1,89,10); INSERT INTO field_tag VALUES (1,90,10); INSERT INTO field_tag VALUES (1,91,10); INSERT INTO field_tag VALUES (1,92,10); INSERT INTO field_tag VALUES (1,93,10); INSERT INTO field_tag VALUES (1,94,10); INSERT INTO field_tag VALUES (1,95,10); INSERT INTO field_tag VALUES (1,96,10); INSERT INTO field_tag VALUES (1,97,10); INSERT INTO field_tag VALUES (1,98,10); INSERT INTO field_tag VALUES (1,99,10); INSERT INTO field_tag VALUES (10,11,100); INSERT INTO field_tag VALUES (11,14,100); INSERT INTO field_tag VALUES (12,15,10); INSERT INTO field_tag VALUES (13,116,10); INSERT INTO field_tag VALUES (2,3,100); INSERT INTO field_tag VALUES (2,4,90); INSERT INTO field_tag VALUES (3,1,100); INSERT INTO field_tag VALUES (3,2,90); INSERT INTO field_tag VALUES (4,5,100); INSERT INTO field_tag VALUES (5,6,100); INSERT INTO field_tag VALUES (6,7,30); INSERT INTO field_tag VALUES (6,8,10); INSERT INTO field_tag VALUES (6,9,20); INSERT INTO field_tag VALUES (7,12,100); INSERT INTO field_tag VALUES (7,13,90); INSERT INTO field_tag VALUES (8,10,100); INSERT INTO field_tag VALUES (9,115,100); INSERT INTO field_tag VALUES (14,117,100); INSERT INTO format VALUES (1,'HTML brief','hb', 'HTML brief output format, used for search results pages.', 'text/html'); INSERT INTO format VALUES (2,'HTML detailed','hd', 'HTML detailed output format, used for Detailed record pages.', 'text/html'); INSERT INTO format VALUES (6,'portfolio','hp', 'HTML portfolio-style output format for photos.', 'text/html'); INSERT INTO format VALUES (7,'photo captions only','hc', 'HTML caption-only output format for photos.', 'text/html'); INSERT INTO format VALUES (8,'BibTeX','hx', 'BibTeX.', 'text/html'); INSERT INTO format VALUES (4,'Dublin Core','xd', 'XML Dublin Core.', 'text/xml'); INSERT INTO format VALUES (3,'MARC','hm', 'HTML MARC.', 'text/html'); INSERT INTO format VALUES (5,'MARCXML','xm', 'XML MARC.', 'text/xml'); INSERT INTO format VALUES (9,'EndNote','xe', 'XML EndNote.', 'text/xml'); INSERT INTO format VALUES (10,'NLM','xn', 'XML NLM.', 'text/xml'); INSERT INTO tag VALUES (1,'first author','100__%'); INSERT INTO tag VALUES (2,'additional author','700__%'); INSERT INTO tag VALUES (3,'main title','245__%'); INSERT INTO tag VALUES (4,'additional title','246__%'); INSERT INTO tag VALUES (5,'abstract','520__%'); INSERT INTO tag VALUES (6,'keyword','6531_a'); INSERT INTO tag VALUES (7,'primary report number','037__a'); INSERT INTO tag VALUES (8,'additional report number','088__a'); INSERT INTO tag VALUES (9,'added report number','909C0r'); INSERT INTO tag VALUES (10,'reference','999C5%'); INSERT INTO tag VALUES (11,'collection identifier','980__%'); INSERT INTO tag VALUES (12,'main subject','65017a'); INSERT INTO tag VALUES (13,'additional subject','65027a'); INSERT INTO tag VALUES (14,'division','909C0p'); INSERT INTO tag VALUES (15,'year','909C0y'); INSERT INTO tag VALUES (16,'00x','00%'); INSERT INTO tag VALUES (17,'01x','01%'); INSERT INTO tag VALUES (18,'02x','02%'); INSERT INTO tag VALUES (19,'03x','03%'); INSERT INTO tag VALUES (20,'04x','04%'); INSERT INTO tag VALUES (21,'05x','05%'); INSERT INTO tag VALUES (22,'06x','06%'); INSERT INTO tag VALUES (23,'07x','07%'); INSERT INTO tag VALUES (24,'08x','08%'); INSERT INTO tag VALUES (25,'09x','09%'); INSERT INTO tag VALUES (26,'10x','10%'); INSERT INTO tag VALUES (27,'11x','11%'); INSERT INTO tag VALUES (28,'12x','12%'); INSERT INTO tag VALUES (29,'13x','13%'); INSERT INTO tag VALUES (30,'14x','14%'); INSERT INTO tag VALUES (31,'15x','15%'); INSERT INTO tag VALUES (32,'16x','16%'); INSERT INTO tag VALUES (33,'17x','17%'); INSERT INTO tag VALUES (34,'18x','18%'); INSERT INTO tag VALUES (35,'19x','19%'); INSERT INTO tag VALUES (36,'20x','20%'); INSERT INTO tag VALUES (37,'21x','21%'); INSERT INTO tag VALUES (38,'22x','22%'); INSERT INTO tag VALUES (39,'23x','23%'); INSERT INTO tag VALUES (40,'24x','24%'); INSERT INTO tag VALUES (41,'25x','25%'); INSERT INTO tag VALUES (42,'26x','26%'); INSERT INTO tag VALUES (43,'27x','27%'); INSERT INTO tag VALUES (44,'28x','28%'); INSERT INTO tag VALUES (45,'29x','29%'); INSERT INTO tag VALUES (46,'30x','30%'); INSERT INTO tag VALUES (47,'31x','31%'); INSERT INTO tag VALUES (48,'32x','32%'); INSERT INTO tag VALUES (49,'33x','33%'); INSERT INTO tag VALUES (50,'34x','34%'); INSERT INTO tag VALUES (51,'35x','35%'); INSERT INTO tag VALUES (52,'36x','36%'); INSERT INTO tag VALUES (53,'37x','37%'); INSERT INTO tag VALUES (54,'38x','38%'); INSERT INTO tag VALUES (55,'39x','39%'); INSERT INTO tag VALUES (56,'40x','40%'); INSERT INTO tag VALUES (57,'41x','41%'); INSERT INTO tag VALUES (58,'42x','42%'); INSERT INTO tag VALUES (59,'43x','43%'); INSERT INTO tag VALUES (60,'44x','44%'); INSERT INTO tag VALUES (61,'45x','45%'); INSERT INTO tag VALUES (62,'46x','46%'); INSERT INTO tag VALUES (63,'47x','47%'); INSERT INTO tag VALUES (64,'48x','48%'); INSERT INTO tag VALUES (65,'49x','49%'); INSERT INTO tag VALUES (66,'50x','50%'); INSERT INTO tag VALUES (67,'51x','51%'); INSERT INTO tag VALUES (68,'52x','52%'); INSERT INTO tag VALUES (69,'53x','53%'); INSERT INTO tag VALUES (70,'54x','54%'); INSERT INTO tag VALUES (71,'55x','55%'); INSERT INTO tag VALUES (72,'56x','56%'); INSERT INTO tag VALUES (73,'57x','57%'); INSERT INTO tag VALUES (74,'58x','58%'); INSERT INTO tag VALUES (75,'59x','59%'); INSERT INTO tag VALUES (76,'60x','60%'); INSERT INTO tag VALUES (77,'61x','61%'); INSERT INTO tag VALUES (78,'62x','62%'); INSERT INTO tag VALUES (79,'63x','63%'); INSERT INTO tag VALUES (80,'64x','64%'); INSERT INTO tag VALUES (81,'65x','65%'); INSERT INTO tag VALUES (82,'66x','66%'); INSERT INTO tag VALUES (83,'67x','67%'); INSERT INTO tag VALUES (84,'68x','68%'); INSERT INTO tag VALUES (85,'69x','69%'); INSERT INTO tag VALUES (86,'70x','70%'); INSERT INTO tag VALUES (87,'71x','71%'); INSERT INTO tag VALUES (88,'72x','72%'); INSERT INTO tag VALUES (89,'73x','73%'); INSERT INTO tag VALUES (90,'74x','74%'); INSERT INTO tag VALUES (91,'75x','75%'); INSERT INTO tag VALUES (92,'76x','76%'); INSERT INTO tag VALUES (93,'77x','77%'); INSERT INTO tag VALUES (94,'78x','78%'); INSERT INTO tag VALUES (95,'79x','79%'); INSERT INTO tag VALUES (96,'80x','80%'); INSERT INTO tag VALUES (97,'81x','81%'); INSERT INTO tag VALUES (98,'82x','82%'); INSERT INTO tag VALUES (99,'83x','83%'); INSERT INTO tag VALUES (100,'84x','84%'); INSERT INTO tag VALUES (101,'85x','85%'); INSERT INTO tag VALUES (102,'86x','86%'); INSERT INTO tag VALUES (103,'87x','87%'); INSERT INTO tag VALUES (104,'88x','88%'); INSERT INTO tag VALUES (105,'89x','89%'); INSERT INTO tag VALUES (106,'90x','90%'); INSERT INTO tag VALUES (107,'91x','91%'); INSERT INTO tag VALUES (108,'92x','92%'); INSERT INTO tag VALUES (109,'93x','93%'); INSERT INTO tag VALUES (110,'94x','94%'); INSERT INTO tag VALUES (111,'95x','95%'); INSERT INTO tag VALUES (112,'96x','96%'); INSERT INTO tag VALUES (113,'97x','97%'); INSERT INTO tag VALUES (114,'98x','98%'); INSERT INTO tag VALUES (115,'url','8564_u'); INSERT INTO tag VALUES (116,'experiment','909C0e'); INSERT INTO tag VALUES (117,'record ID','001'); INSERT INTO idxINDEX VALUES (1,'global','This index contains words/phrases from global fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (2,'collection','This index contains words/phrases from collection identifiers fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (3,'abstract','This index contains words/phrases from abstract fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (4,'author','This index contains words/phrases from author fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (5,'keyword','This index contains words/phrases from keyword fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (6,'reference','This index contains words/phrases from references fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (7,'reportnumber','This index contains words/phrases from report numbers fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (8,'title','This index contains words/phrases from title fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (9,'fulltext','This index contains words/phrases from fulltext fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX VALUES (10,'year','This index contains words/phrases from year fields.','0000-00-00 00:00:00'); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (1,1); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (2,10); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (3,4); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (4,3); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (5,5); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (6,8); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (7,6); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (8,2); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (9,9); INSERT INTO idxINDEX_field (id_idxINDEX, id_field) VALUES (10,12); INSERT INTO flxFORMATS VALUES ('DEFAULT_HTML_BRIEF','\"\" format(\"_DEFAULT_TITLE\") \" \"\r\nif(count($100.a)!=\"0\" || count($700.a)!=\"0\")\r\n{\r\n \" / \" format(\"_DEFAULT_AUTHORS\") \" \"\r\n}\r\nforall($088.a)\r\n{ \" [\" $088.a \"] \" }\r\nforall($037.a)\r\n{ \" [\" $037.a \"] \" }\r\nforall($520.a)\r\n{ \"
\" format(\"_DEFAULT_ABSTRACT_FIRST_SENTENCE\") \"\" }\r\nforall($8564.u)\r\n{ \"
\" format(\"_DEFAULT_URL\") \"\" }','This is the default brief HTML format.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:8:\"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"_DEFAULT_TITLE\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\" / \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:16:\"_DEFAULT_AUTHORS\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:26:\" [\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"] \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:26:\" [\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"] \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:32:\"_DEFAULT_ABSTRACT_FIRST_SENTENCE\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:8:\"\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"_DEFAULT_URL\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:8:\"\";s:4:\"sons\";a:0:{}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_DEFAULT_AUTHORS',' if(gt(sum( count($700.a), count($100.a) ),\"4\")!=\"\") \r\n{ \r\n if(count($100.a)!=\"0\") \r\n { \r\n link(\"author_search\", $100.a)\r\n {\r\n \"\" $100.a \"\"\r\n if($100.e!=\"\") { \" (\" $100.e \")\" }\r\n \" et al \" \r\n } \r\n } \r\n else \r\n { \r\n if(count($700.a)!=\"0\") \r\n { \r\n link(\"author_search\", $700.a)\r\n { \r\n \"\" $700.a \"\"\r\n if($700.e!=\"\") { \" (\" $700.e \")\" }\r\n \" et al.\" \r\n } \r\n } \r\n } \r\n} \r\nelse \r\n{ \r\n forall($100) \r\n { \r\n if($100.a!=\"\") \r\n { \r\n link(\"author_search\", $100.a){\"\" $100.a \"\" } \r\n separator(\"; \") \r\n } \r\n } \r\n if(count($100.a)!=\"0\") \r\n { \r\n if(count($700.a)!=\"0\") \r\n { \"; \" } \r\n } \r\n forall($700) \r\n { \r\n if($700.a!=\"\") \r\n { \r\n link(\"author_search\", $700.a){\"\" $700.a \"\" } \r\n separator(\"; \") \r\n } \r\n } \r\n} ','This is the default subformat to format author lists.','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:2:\"GT\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:3:\"SUM\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"4\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"author_search\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\")\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:17:\" et al \";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"author_search\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\")\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\" et al.\";s:4:\"sons\";a:0:{}}}}}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"author_search\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"author_search\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_DEFAULT_TITLE','$245.a \r\nif($245.b!=\"\"){ \" : \" $245.b } \r\nif($250.a!=\"\"){ \" ; \" $250.a } ','HTML for displaying the title in brief formats','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\" : \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"250\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\" ; \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"250\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_DEFAULT_ABSTRACT_FIRST_SENTENCE','limw_l($520.a, \".\") \". [...]\"','This is the default subformat to yield the first sentence of the abstract.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:6:\"LIMW_L\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\".\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\". [...]\";s:4:\"sons\";a:0:{}}}}'); INSERT INTO flxFORMATS VALUES ('DEFAULT_HTML_DETAILED','format(\"_full_topbanner\") \r\nformat(\"_full_title\") \r\n\"

\" \r\nformat(\"_full_author\")\r\nformat(\"_full_affiliation\")\r\nformat(\"_full_datedoc\") \"
\"\r\nformat(\"_full_imprint\")\r\n\"
\"\r\n\r\n\"

\"\r\n\r\nformat(\"_full_abstract\")\r\nformat(\"_full_daterec\")\r\n\r\nformat(\"_full_keyword\")\r\n\r\nformat(\"_full_note\") \r\nformat(\"_full_publiinfo\")\r\n\"
\"\r\nformat(\"_full_url\")\r\nformat(\"_full_citedby\")\r\n\"

\" \r\nformat(\"_full_references\")\r\n','This is the default HTML detailed format.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"_full_topbanner\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"_full_title\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"

\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"_full_author\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:17:\"_full_affiliation\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"_full_datedoc\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"_full_imprint\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:40:\"

\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"_full_abstract\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"_full_daterec\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"_full_keyword\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"_full_note\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"_full_publiinfo\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"_full_url\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"_full_citedby\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"

\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:16:\"_full_references\";s:4:\"sons\";a:0:{}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_ABSTRACT','if($520.a!=\"\"||$520.b!=\"\"){\r\n \"\r\n Abstract: \"\r\n $520.a\"
\"$520.b\" \"\r\n \"

\r\n \"\r\n} \r\nif($590.a!=\"\"||$590.b!=\"\"){\r\n \"\r\n Texte: \"\r\n $590.a\"
\"$590.b\r\n \"

\r\n \"\r\n} ','HTML Abstract display','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:37:\"\r\n Abstract: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"

\r\n \";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"590\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"590\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:34:\"\r\n Texte: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"590\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"590\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"

\r\n \";s:4:\"sons\";a:0:{}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_TITLE','if($245.a!=\"\"){\r\n \"

\"\r\n $245.a\r\n if($245.b!=\"\"){ \": \" $245.b }\r\n \"
\"\r\n}\r\n\r\nif($0248.a!=\"\"){\r\n \"
\"\r\n $0248.a\r\n \"
\"\r\n}\r\n\r\nif($246.a!=\"\"){\r\n \"
\"\r\n $246.a\r\n \"
\"\r\n}\r\n\r\nif($246_1.a!=\"\"){\r\n \"
\"\r\n $246_1.a\r\n \"
\"\r\n}\r\n\r\nif($210.a!=\"\"){\r\n \"(\"\r\n $210.a\r\n \") \"\r\n}\r\n','HTML Title display ','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:26:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\": \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:30:\"
\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"0248\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:30:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"0248\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:30:\"
\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"246\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:30:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"246\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:30:\"
\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"246_1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:33:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"246_1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:34:\"
\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"210\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:8:\"(\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"210\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\") \";s:4:\"sons\";a:0:{}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('PICTURE_HTML_DETAILED','format(\"_full_topbanner\")\r\nformat(\"_full_title\")\r\n\r\nformat(\"_full_note\")\r\nif($260.c!=\"\"){\"
\" $260.c \"
\"}\r\nformat(\"_full_contact\")\r\nif($100.a!=\"\"){\r\n \"
Photographer: \"\r\n format(\"_full_author\")\r\n \"
\"\r\n}\r\n\r\n\"
\"\r\n\r\nformat(\"_full_keyword\")\r\n\r\n\r\n\r\n\"\r\n\r\n\"\r\n\r\n\"\" \r\n\r\n\"\r\n\r\n\r\n\r\n\r\n
\" \r\nif($909CP.s!=\"\"){\"
Original ref.: \"$909CP.s\" \"}\r\nif($909CP.t!=\"\"){\"
Available pictures: \"$909CP.t\" \"}\r\n\r\nif ($520.a!=\"\"){\r\n \"

\r\n Caption
\" \r\n \"\" \r\n $520.a\r\n \"

\"\r\n}\r\nif ($590.a!=\"\"){\r\n \"

\r\n Légende
\" \r\n \"\" \r\n $590.a\r\n \"

\"\r\n}\r\n\r\nif ($909C4!=\"\"){\r\n \"

See also:
\" \r\n}\r\nforall ($909C4){\r\n \"\" $909C4.p \"
\"\r\n}\r\n\r\n\"
\" \r\nformat(\"_full_photo_resources\")\r\n\"
\r\n © CERN Geneva: \r\nThe use of photos requires prior authorization (from CERN copyright). \r\nThe words CERN Photo must be quoted for each use. \r\n
\r\n

\"','The detailed HTML format suitable for displaying pictures.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"_full_topbanner\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"_full_title\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"_full_note\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:8:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"
\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"_full_contact\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:29:\"
Photographer: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"_full_author\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:17:\"
\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"_full_keyword\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:46:\"\r\n\r\n\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:17:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:310:\"\r\n\r\n\r\n\r\n\r\n
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"S\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:37:\"
Original ref.: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"S\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:41:\"
Available pictures: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:67:\"

\r\n Caption
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"

\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"590\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:68:\"

\r\n Légende
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"590\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"

\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:64:\"

See also:
\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:16:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:16:\"
\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:21:\"_full_photo_resources\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\r\n © CERN Geneva: \r\nThe use of photos requires prior authorization (from CERN copyright). \r\nThe words CERN Photo must be quoted for each use. \r\n
\r\n

\";s:4:\"sons\";a:0:{}}}}'); INSERT INTO `flxFORMATS` VALUES ('PICTURE_HTML_BRIEF',' \"
\r\n \r\n \r\n \r\n
\"\r\n\"\" format(\"_DEFAULT_TITLE\") \"\"\r\nforall($246_1.a)\r\n{ \"
\" $246_1.a\" \" } \r\nforall($260.c)\r\n{ \"
\" $260.c }\r\nforall($520.a) {\r\n rep_prefix(\"

Abstract: \")\r\n format(\"_DEFAULT_ABSTRACT_FIRST_SENTENCE\")\r\n \"

\"\r\n}\r\nforall($6531.a)\r\n{ \r\n rep_prefix(\"
Keyword: \") \r\n link(\"KEYWORD_SEARCH\", $6531.a)\r\n { \"\" $6531.a \"\" } separator(\", \")\r\n}\r\nforall($037.a)\r\n{\"
Picture number: \" $037.a }\r\nforall($909CP.t)\r\n{ rep_prefix(\"
Available picture(s):\") xml_text($909CP.t) }\r\n\r\n\"

\"\r\nforall($8564)\r\n{ if(($8564.x=\"icon\")&&($8564.u=\"\"))\r\n { \"

\" }\r\n}\r\n\r\n\"
© CERN Geneva\" \r\n\"
\" link(\"EXT\", $8564.u, $8564.z){ $link }\r\n\"

\"','The brief HTML format suitable for displaying pictures.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:69:\"
\r\n \r\n \r\n \r\n
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"_DEFAULT_TITLE\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:5:\"246_1\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"246_1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\" \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"520\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"REP_PREFIX\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:20:\"

Abstract: \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:32:\"_DEFAULT_ABSTRACT_FIRST_SENTENCE\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"

\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:4:\"6531\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"REP_PREFIX\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:21:\"
Keyword: \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"KEYWORD_SEARCH\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"6531\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"6531\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\", \";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:27:\"
Picture number: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"REP_PREFIX\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:32:\"
Available picture(s):\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"XML_TEXT\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:38:\"

\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:6;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"X\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"icon\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:20:\"

\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:56:\"
© CERN Geneva\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"EXT\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Z\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"LINK\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:29:\"

\";s:4:\"sons\";a:0:{}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_AUTHOR','if($700.a!=\"\"||$100.a!=\"\"||$270.p!=\"\"){\r\n\r\n forall($100){\r\n LINK(\"AUTHOR_SEARCH\",$100.a){\r\n \"\"$100.a\" \"\r\n if ($100.e!=\"\"){\" (\"$100.e\")\"}\r\n separator(\"; \")\r\n }\r\n }\r\n if(count($100.a)!=\"0\") \r\n { \r\n if(count($700.a)!=\"0\") \r\n { \"; \" } \r\n } \r\n forall($700){\r\n LINK(\"AUTHOR_SEARCH\",$700.a){\r\n \" \"$700.a\" \"\r\n if ($700.e!=\"\"){\" (\"$700.e\")\"}\r\n separator(\"; \")\r\n }\r\n } \r\n \r\n forall($270){\r\n LINK(\"AUTHOR_SEARCH\",$270.p){\r\n \" \"$270.p\" \"\r\n if ($270.g!=\"\"){\r\n \" (\"\r\n $270.g\r\n \")\"\r\n }\r\n separator(\"; \")\r\n }\r\n }\r\n \r\n} ','HTML linked author display','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"270\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"AUTHOR_SEARCH\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\")\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:17;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"AUTHOR_SEARCH\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\")\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"270\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"AUTHOR_SEARCH\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"270\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"270\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"270\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"G\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"270\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"G\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\")\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_AFFILIATION','if($909C1.u!=\"\"){\r\n \"
\"\r\n forall($909C1){\r\n $909C1.u\" \"\r\n }\r\n} \r\n','HTML Affiliation display','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:5:\"909C1\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\" \";s:4:\"sons\";a:0:{}}}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_DATEDOC','if($260.c!=\"\"){\r\n \"
\"\r\n $260.c\" \r\n \"\r\n} \r\n','HTML Imprint date','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\" \r\n \";s:4:\"sons\";a:0:{}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_IMPRINT','if($260.b!=\"\"){\r\n if($260.b!=\"sine nomine\"){\r\n \"\"\r\n $260.b\r\n if($260.a!=\"\"){\r\n if($260.a!=\"sine loco\"){\": \"$260.a}\r\n }\r\n \" \"\r\n }\r\n}\r\n','HTML Imprint display (not the date)','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"sine nomine\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"sine loco\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\": \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\" \";s:4:\"sons\";a:0:{}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_DATEREC','if($909C1.c!=\"\"){\r\n \"
Arrived: \"\r\n $909C1.c\" \"\r\n}\r\n','',NULL); INSERT INTO flxFORMATS VALUES ('_FULL_KEYWORD','forall($6531.a){\r\n REP_PREFIX(\"
Keyword(s): \")\r\n \"\"\r\n LINK(\"KEYWORD_SEARCH\",$6531.a){ \r\n \"\"$6531.a\" \"\r\n separator(\";\")\r\n }\r\n \"\r\n \"\r\n} \r\n','HTML keyword display with search link','O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:4:\"6531\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"REP_PREFIX\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:48:\"
Keyword(s): \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"KEYWORD_SEARCH\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"6531\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"6531\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\";\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"\r\n \";s:4:\"sons\";a:0:{}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_NOTE','if($594.p!=\"\"){\r\n \"
Note: \"\r\n xml_text($594.p)\" \"\r\n}\r\nif($500.a!=\"\"){\r\n \"
Note: \"\r\n forall($500){xml_text($500.a)\"; \"}\r\n \"\"\r\n} \r\nif($502.a!=\"\"||$909CC.r!=\"\"||$909CP.n!=\"\"||$711.a!=\"\"){\r\n \"
Note: \"\r\n $502.a\" \"\r\n $909CC.r\" \"\r\n $909CC.d\" \"\r\n $909CP.n\" \"\r\n $711.a \" \"\r\n} \r\nif($596.a!=\"\"){\r\n \"
Notes: \"\r\n $596.a \" \"\r\n} \r\n\r\n','HTML note display (various note fields)','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"594\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:34:\"
Note: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"XML_TEXT\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"594\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\" \";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"500\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:34:\"
Note: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"500\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"XML_TEXT\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"500\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"; \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:8:\"\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CC\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"R\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"711\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:34:\"
Note: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CC\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"R\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CC\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"D\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909CP\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"711\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\" \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"596\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:35:\"
Notes: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"596\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\" \";s:4:\"sons\";a:0:{}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_PUBLIINFO','if($909C4.p!=\"\"){ \r\n \"

Published in: \"\r\n if (KB($909C4.p,\"ejournals\")!=\"\") {\r\n if ($909C4.v!=\"\") { \r\n \"\"$909C4.p\": \"\r\n $909C4.v \" (\"$909C4.y\") \"$909C4.c \r\n \" \" \r\n } else {\r\n $909C4.p\": \"\r\n if($909C4.y!=\"\"){\" (\"$909C4.y\") \"}\r\n if($909C4.n!=\"\"){\"no. \"$909C4.n\", \"}\r\n if($909C4.c!=\"\"){\"pp.\"$909C4.c }\r\n }\r\n } else {\r\n $909C4.p \": \"\r\n if($909C4.v!=\"\"){ $909C4.v }\r\n if($909C4.y!=\"\"){\" (\"$909C4.y\") \"}\r\n if($909C4.n!=\"\"){\"no. \"$909C4.n\", \"}\r\n if($909C4.c!=\"\"){\"pp.\"$909C4.c } \r\n }\r\n}\r\n','HTML publication information display possibly with link to ejournal','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:39:\"

Published in: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"ejournals\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:61:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\": \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\") \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\": \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\") \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"no. \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\", \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"pp.\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\": \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\") \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"no. \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\", \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"pp.\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}}}}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_YEAR','if ($909C0.y!=\"\"){\"
Year: \"\r\n $909C0.y\r\n}','HTML Year display','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C0\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:27:\"
Year: \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C0\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_TOPBANNER','\" \r\n\" \r\nforall($088){\"\"} \r\nif($037.a!=\"\"){\"\"} \r\n\"
\"KB($980.a,\"dbcollid2coll\")\" \"\r\nif($65017.a!=\"XX\"){\r\n \" / \" $65017.a\r\n}\r\n\" \"$65027.a\r\n\"\"$088.a\" \"$037.a\"

\" ','HTML top page banner containing category, rep. number, etc','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:74:\" \r\n\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:19:\"\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:26:\"\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:17:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"dbcollid2coll\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"65017\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"XX\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\" / \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"65017\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"65027\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:23:\" \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"

\";s:4:\"sons\";a:0:{}}}}'); INSERT INTO flxFORMATS VALUES ('_DEFAULT_URL','\"\" $8564.u \"\"','This is the default format for formatting URLs.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_URL','forall($8564)\r\n{\r\n\"
\" $8564.z \" : \" $8564.u \"\"\r\n}','HTML URL display','O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Z\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:29:\" : \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"\";s:4:\"sons\";a:0:{}}}}}}'); INSERT INTO flxFORMATS VALUES ('DEFAULT_HTML_CAPTIONS','format(\"_default_title\")','HTML \"captions only\" format','O:7:\"aelnode\":3:{s:3:\"cat\";i:13;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"_default_title\";s:4:\"sons\";a:0:{}}}}'); INSERT INTO `flxFORMATS` VALUES ('DEFAULT_HTML_PORTFOLIO','forall($8564)\r\n{ if(($8564.x=\"icon\")&&($8564.u=\"\"))\r\n { \"

\" }\r\n} ','HTML \"portfolio\" format','O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:6;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"X\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"icon\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:20:\"

\";s:4:\"sons\";a:0:{}}}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_PHOTO_RESOURCES','\"
Resources
\"\r\n\r\nforall($8564)\r\n{ \r\n if(($8564.x=\"icon\")&&($8564.u=\"\")) { \r\n \"

\" \r\n }\r\n if($8564.x=\"1\") {\r\n \"
High resolution: \" $8564.q \"\"\r\n }\r\n \r\n}\r\n\r\n\"
© CERN Geneva\" \r\n\"
\" link(\"EXT\", $8564.u, $8564.z){ $link } \r\n','Prints image and link to photo resources.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:60:\"
Resources
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:6;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"X\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"icon\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"

\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"X\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"1\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:42:\"
High resolution: \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Q\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:47:\"
© CERN Geneva\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:14;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"EXT\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:15;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"U\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"8564\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Z\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:4:\"LINK\";s:4:\"sons\";a:0:{}}}}}}'); INSERT INTO `flxFORMATS` VALUES ('_FULL_CITEDBY','if($037.a!=\"\" || $088.a!=\"\") {\r\n \"

Cited by: try citation search for \"\r\n forall($037.a) {\r\n \"\" $037.a \"\"\r\n separator(\";\")\r\n }\r\n if($037.a!=\"\" && $088.a!=\"\") {\r\n \" ; \"\r\n }\r\n forall($088.a) {\r\n \"\" $088.a \"\"\r\n separator(\";\")\r\n }\r\n}','HTML \"cited by\" link creation, based on report numbers.','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:59:\"

Cited by: try citation search for \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:33:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\";\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:6;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\" ; \";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:33:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"SEPARATOR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\";\";s:4:\"sons\";a:0:{}}}}}}}}}}}}'); INSERT INTO `flxFORMATS` VALUES ('_FULL_REFERENCES','if ($999C5!=\"\") {\r\n\"

\"\r\n\"References:\"\r\n\"
    \" \r\nforall($999C5){ \r\n\r\nif($999C5.o!=\"\")\r\n {\"
  • \"$999C5.o \" \"} \r\n\r\nif ($999C5.m!=\"\")\r\n {\" \" $999C5.m \" \"}\r\n\r\nif ($999C5.r!=\"\")\r\n {\" [\"$999C5.r\"]
    \"} \r\n\r\nif ($999C5.t!=\"\")\r\n {if (KB($999C5.t,\"ejournals\")!=\"\")\r\n { \r\n \" \"$999C5.t\": \"$999C5.v\" (\"$999C5.y\") \"$999C5.p \r\n \"
    \"\r\n } \r\n else\r\n {\" \" $999C5.t\" \"$999C5.v\" \"$999C5.y\" \"$999C5.p \"
    \"\r\n }\r\n }\r\n\r\n} \r\n\"
\"\r\n\r\n\"

Warning: references are automatically extracted and standardized from the PDF document and may therefore contain errors. If you think they are incorrect or incomplete, look at the fulltext document itself.
\"\r\n\"

\"\r\n}','HTML references','O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:28:\"References:\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"
    \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"O\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:12:\"
  • \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"O\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\" \";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"M\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\" \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"M\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\" \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"R\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:46:\" [\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"R\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:20:\"]
    \";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"ejournals\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:70:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\": \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\" (\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\") \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:18:\"
    \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\" \";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"T\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\" \";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"999C5\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:14:\"
    \";s:4:\"sons\";a:0:{}}}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:241:\"

Warning: references are automatically extracted and standardized from the PDF document and may therefore contain errors. If you think they are incorrect or incomplete, look at the fulltext document itself.
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"

\";s:4:\"sons\";a:0:{}}}}}}'); INSERT INTO flxFORMATS VALUES ('_FULL_BIBTEX','\"
\"\r\n\"@\" \r\n\r\nif (kb($980.a, \"DBCOLLID2BIBTEX\") = \"\"){\r\n    \"article\"\r\n}else{\r\n    kb($980.a, \"DBCOLLID2BIBTEX\")\r\n}\r\n\r\n\"{\"\r\n\r\nif($100.a != \"\"){\r\n    GET_NAME($100.a) \":\" $001 \",
\"\r\n}else{\r\n if($700.a != \"\"){\r\n GET_NAME($700.a) \":\" $001 \",
\"\r\n }else{\r\n if($037.a != \"\"){\r\n $037.a \",
\"\r\n }else{\r\n if($088.a != \"\"){\r\n $088.a \",
\"\r\n }else{\r\n if($245.a != \"\"){\r\n GET_NAME($245.a) \":\" $001 \",
\"\r\n }else{\r\n $001 \",
\"\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n\r\n\r\n\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"article\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"book\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"inproceedings\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"misc\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"phdthesis\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"techreport\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"unpublished\"){\r\n if ($100.a != \"\" || $700.a != \"\" || $110.b != \"\" || $110.a != \"\" || $710.a != \"\"){\r\n STR_BUFFER(\"add\",\" author = \\\"\", \"0\", \"0\")\r\n\r\n if($100.a != \"\"){\r\n STR_BUFFER(\"add\", $100.a \" and \", \"0\", \"0\")\r\n }\r\n\r\n forall($700.a){\r\n if ($700.e != \"ed.\"){\r\n STR_BUFFER(\"add\", $700.a \" and \", \"0\", \"0\")\r\n }\r\n }\r\n\r\n forall($110.b){\r\n STR_BUFFER(\"add\", $110.b \" and \", \"0\", \"0\")\r\n }\r\n\r\n forall($110.a){\r\n STR_BUFFER(\"add\", $110.a \" and \", \"0\", \"0\")\r\n }\r\n\r\n forall($710.a){\r\n STR_BUFFER(\"add\", $710.a \" and \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"5\", \"22\"), \"72\", \"22\")\r\n }else{\r\n SPLIT_LINE(\" key = \\\"\" $001 \"\\\",
\", \"72\", \"22\")\r\n }\r\n}\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"inproceedings\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"proceedings\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"phdthesis\"){\r\n if ($700.a != \"\"){\r\n STR_BUFFER(\"add\", \" editor = \\\"\", \"0\", \"0\")\r\n\r\n forall($700){\r\n if ($700.e = \"ed.\"){\r\n STR_BUFFER(\"add\", $700.a \" and \", \"0\", \"0\")\r\n }\r\n }\r\n \r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"5\", \"22\"), \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\nif ($245.a != \"\" || $245.b != \"\" || $246.a != \"\" || $246_1.a != \"\"){\r\n\r\n STR_BUFFER(\"add\", \" title = \\\"\", \"0\", \"0\")\r\n\r\n if($245.a != \"\"){\r\n STR_BUFFER(\"add\", $245.a \". \", \"0\", \"0\")\r\n }\r\n\r\n if($245.b != \"\"){\r\n STR_BUFFER(\"add\", $245.b \". \", \"0\", \"0\")\r\n }\r\n\r\n if($246.a != \"\"){\r\n STR_BUFFER(\"add\", $246.a \". \", \"0\", \"0\")\r\n }\r\n\r\n if($246_1.a != \"\"){\r\n STR_BUFFER(\"add\", $246_1.a \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n}\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"techreport\"){\r\n if ($269.b != \"\"){\r\n SPLIT_LINE(\" institution = \\\"\" $269.b \"\\\",
\", \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"inproceedings\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"proceedings\"){\r\n if ($260.b != \"\" || $269.b != \"\"){\r\n\r\n STR_BUFFER(\"add\", \" organization = \\\"\", \"0\", \"0\")\r\n\r\n if($260.b != \"\"){\r\n STR_BUFFER(\"add\", $260.b \". \", \"0\", \"0\")\r\n }\r\n\r\n if($269.b != \"\"){\r\n STR_BUFFER(\"add\", $269.b \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n }\r\n}\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"book\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"inproceedings\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"proceedings\"){\r\n if ($260.b != \"\" || $269.b != \"\" || $933.b != \"\" || $934.b != \"\"){\r\n\r\n STR_BUFFER(\"add\", \" publisher = \\\"\", \"0\", \"0\")\r\n\r\n if($260.b != \"\"){\r\n STR_BUFFER(\"add\", $260.b \". \", \"0\", \"0\")\r\n }\r\n\r\n if($269.b != \"\"){\r\n STR_BUFFER(\"add\", $269.b \". \", \"0\", \"0\")\r\n }\r\n\r\n if($933.b != \"\"){\r\n STR_BUFFER(\"add\", $933.b \". \", \"0\", \"0\")\r\n }\r\n\r\n if($934.b != \"\"){\r\n STR_BUFFER(\"add\", $934.b \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n }\r\n}\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"article\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"\"){\r\n if ($773.p != \"\" || $909C4.p != \"\"){\r\n STR_BUFFER(\"add\", \" journal = \\\"\", \"0\", \"0\")\r\n\r\n if($909C4.p != \"\"){\r\n STR_BUFFER(\"add\", $909C4.p \". \", \"0\", \"0\")\r\n }\r\n\r\n if($773.p != \"\"){\r\n STR_BUFFER(\"add\", $773.p \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n\r\n }\r\n}\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"phdthesis\"){\r\n if ($502.b != \"\"){\r\n SPLIT_LINE(\" school = \\\"\" $502.b \"\\\",
\", \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"book\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"inproceedings\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"proceedings\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"phdthesis\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"techreport\"){\r\n if ($260.a != \"\" || $269.a != \"\" || $933.a != \"\" || $934.a != \"\"){\r\n STR_BUFFER(\"add\", \" address = \\\"\", \"0\", \"0\")\r\n\r\n if($260.a != \"\"){\r\n STR_BUFFER(\"add\", $260.a \". \", \"0\", \"0\")\r\n }\r\n\r\n forall($269.a){\r\n STR_BUFFER(\"add\", $269.a \". \", \"0\", \"0\")\r\n }\r\n\r\n forall($933.a){\r\n STR_BUFFER(\"add\", $933.a \". \", \"0\", \"0\")\r\n }\r\n\r\n forall($934.a){\r\n STR_BUFFER(\"add\", $934.a \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"article\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"techreport\"){\r\n if ($037.a != \"\" || $088.a != \"\" || $773.n != \"\" || $909C4.n){\r\n\r\n STR_BUFFER(\"add\", \" number = \\\"\", \"0\", \"0\")\r\n\r\n if($037.a != \"\"){\r\n STR_BUFFER(\"add\", $037.a \". \", \"0\", \"0\")\r\n }\r\n\r\n forall($088.a) {\r\n if($088.a != \"\"){\r\n STR_BUFFER(\"add\", $088.a \". \", \"0\", \"0\")\r\n }\r\n }\r\n\r\n if($773.n != \"\"){\r\n STR_BUFFER(\"add\", $773.n \". \", \"0\", \"0\")\r\n }\r\n\r\n if($909C4.n != \"\"){\r\n STR_BUFFER(\"add\", $909C4.n \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"article\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"book\"){\r\n if ($773.v != \"\" || $909C4.v != \"\"){\r\n\r\n STR_BUFFER(\"add\",\" volume = \\\"\", \"0\", \"0\")\r\n\r\n if($909C4.v != \"\"){\r\n STR_BUFFER(\"add\", $909C4.v \". \", \"0\", \"0\")\r\n }\r\n\r\n if($773.v != \"\"){\r\n STR_BUFFER(\"add\", $773.v \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"book\"){\r\n if ($490.a != \"\"){\r\n SPLIT_LINE(\" series = \\\"\" $490.a \"\\\",
\", \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\nif (KB($980.a, \"DBCOLLID2BIBTEX\") = \"article\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"\" || KB($980.a, \"DBCOLLID2BIBTEX\") = \"inproceedings\"){\r\n if ($773.c != \"\" || $909C4.c != \"\" || $300.a != \"\"){\r\n\r\n STR_BUFFER(\"add\", \" pages = \\\"\", \"0\", \"0\")\r\n\r\n if($773.c != \"\"){\r\n STR_BUFFER(\"add\", $773.c \". \", \"0\", \"0\")\r\n }\r\n\r\n if($909C4.c != \"\"){\r\n STR_BUFFER(\"add\", $909C4.c \". \", \"0\", \"0\")\r\n }\r\n\r\n if($300.a != \"\"){\r\n STR_BUFFER(\"add\", $300.a \". \", \"0\", \"0\")\r\n }\r\n\r\n SPLIT_LINE(STR_BUFFER(\"print\", \"\\\",
\", \"2\", \"22\"), \"72\", \"22\")\r\n }\r\n}\r\n\r\n\r\n\r\nSTR_BUFFER(\"add\", \" month = \\\"\", \"0\", \"0\")\r\nif($269.c != \"\"){\r\n STR_BUFFER(\"add\", GET_MONTH($269.c), \"0\", \"0\")\r\n}else{\r\n if($260.c != \"\"){\r\n STR_BUFFER(\"add\", GET_MONTH($260.c), \"0\", \"0\")\r\n }else{\r\n if($502.c != \"\"){\r\n STR_BUFFER(\"add\", GET_MONTH($502.c), \"0\", \"0\")\r\n }\r\n }\r\n}\r\nSTR_BUFFER(\"print\", \"\\\",
\", \"0\", \"22\")\r\n\r\n\r\nSTR_BUFFER(\"add\", \" year = \\\"\", \"0\", \"0\")\r\nif($269.c != \"\"){\r\n STR_BUFFER(\"add\", GET_YEAR($269.c), \"0\", \"0\")\r\n}else{\r\n if($260.c != \"\"){\r\n STR_BUFFER(\"add\", GET_YEAR($260.c), \"0\", \"0\")\r\n }else{\r\n if($502.c != \"\"){\r\n STR_BUFFER(\"add\", GET_YEAR($502.c), \"0\", \"0\")\r\n }else{\r\n if($909C0.y != \"\"){\r\n STR_BUFFER(\"add\", GET_YEAR($909C0.y), \"0\", \"0\") \r\n }\r\n }\r\n }\r\n}\r\nSTR_BUFFER(\"print\", \"\\\",
\", \"0\", \"22\")\r\n\r\n\r\n\r\nif ($500.a != \"\"){\r\n SPLIT_LINE(\" note = \\\"\" $500.a \"\\\",
\", \"72\", \"22\")\r\n}\r\n\r\n\"}\"\r\n\"
\"','Creates BibTeX format for a record.','O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"
\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"@\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"article\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"{\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"GET_NAME\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\":\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"001\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\",
\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"GET_NAME\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\":\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"001\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\",
\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\",
\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\",
\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"GET_NAME\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\":\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"001\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\",
\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"001\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\",
\";s:4:\"sons\";a:0:{}}}}}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"article\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"book\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"inproceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"misc\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"phdthesis\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"techreport\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"unpublished\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"110\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"110\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"710\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" author = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"100\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" and \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"ed.\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" and \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"110\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"110\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" and \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"110\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"110\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" and \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"710\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"710\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" and \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"5\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" key = \"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"001\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"inproceedings\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"proceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"phdthesis\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" editor = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:3:{i:0;N;i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"E\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"ed.\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"700\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\" and \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"5\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"246\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"246_1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" title = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"245\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"246\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"246\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"246_1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"246_1\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"techreport\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" institution = \"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"inproceedings\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"proceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" organization = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"book\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"inproceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"proceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"933\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"934\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" publisher = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"933\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"933\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"934\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"934\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"article\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" journal = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"P\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"phdthesis\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" school = \"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"B\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"book\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"inproceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:11:\"proceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:9:\"phdthesis\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"techreport\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"933\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"934\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" address = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"933\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"933\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"934\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"934\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"article\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:10:\"techreport\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" number = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"037\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:3;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}i:1;N;i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"088\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"N\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"article\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"book\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" volume = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"V\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:4:\"book\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"490\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" series = \"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"490\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:7:\"article\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:7;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:16;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:15:\"DBCOLLID2BIBTEX\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"980\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:13:\"inproceedings\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:5;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"300\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" pages = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"773\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C4\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"300\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"300\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\". \";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"2\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" month = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"GET_MONTH\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"GET_MONTH\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:9:\"GET_MONTH\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" year = \"\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"GET_YEAR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"269\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"GET_YEAR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"260\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"GET_YEAR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"502\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"C\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C0\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:3:\"add\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:8:\"GET_YEAR\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:5:\"909C0\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"Y\";s:4:\"sons\";a:0:{}}}}}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}}}}}}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"STR_BUFFER\";s:4:\"sons\";a:4:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:5:\"print\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"0\";s:4:\"sons\";a:0:{}}i:3;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:4;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:8;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"500\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:2;s:3:\"lex\";s:10:\"SPLIT_LINE\";s:4:\"sons\";a:3:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:11;s:3:\"lex\";s:0:\"\";s:4:\"sons\";a:2:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:22:\" note = \"\";s:4:\"sons\";a:0:{}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:0;s:3:\"lex\";s:3:\"500\";s:4:\"sons\";a:1:{i:0;O:7:\"aelnode\":3:{s:3:\"cat\";i:12;s:3:\"lex\";s:1:\"A\";s:4:\"sons\";a:0:{}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"\",
\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"72\";s:4:\"sons\";a:0:{}}i:2;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:2:\"22\";s:4:\"sons\";a:0:{}}}}}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:1:\"}\";s:4:\"sons\";a:0:{}}}}i:1;O:7:\"aelnode\":3:{s:3:\"cat\";i:1;s:3:\"lex\";s:6:\"
\";s:4:\"sons\";a:0:{}}}}'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CD','909','C','D','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','520','520','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','590','590','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909C0','909','C','0','N','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','110','110','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','583','583','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','270','270','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909C1','909','C','1','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CL','909','C','L','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','700','700','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','100','100','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','506','506','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CE','909','C','E','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CI','909','C','I','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','710','710','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','030','030','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CZ','909','C','Z','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CA','909','C','A','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','111','111','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','711','711','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','524','524','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909C4','909','C','4','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CP','909','C','P','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CM','909','C','M','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','8560','856','0','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','037','037','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','8564','856','4','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','866','866','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','260','260','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','300','300','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','690C','690','C','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','020','020','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','022','022','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','654','654','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','6531','653','1','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','6532','653','2','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CK','909','C','K','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','041','041','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','852','852','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','340','340','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','600','600','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','595','595','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','500','500','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','502','502','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CC','909','C','C','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','596','596','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','591','591','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CO','909','C','O','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','594','594','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','856','856','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','598','598','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CR','909','C','R','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CH','909','C','H','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CF','909','C','F','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','088','088','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','246','246','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','770','770','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','772','772','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','780','780','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','785','785','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','787','787','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','541','541','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','0248','024','8','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','490','490','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','65017','650','1','7','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','65027','650','2','7','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909CS','909','C','S','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','044','044','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','310','310','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','909C2','909','C','2','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','655','655','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','245','245','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','250','250','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','130','130','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','246_1','246','','1','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','246_3','246','','3','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','210','210','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','85642','856','4','2','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','080','080','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','999C5','999','C','5','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','040','040','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','980','980','','','S','DATAFIELD'); INSERT INTO flxXMLMARCEXTRULES VALUES ('DEFAULT','001','001','','','S','CONTROLFIELD'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','','',''); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','z','z'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','520','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','520','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','590','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','590','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','110','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','583','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C1','u','u'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','700','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','700','e','e'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','700','u','u'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','100','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','100','e','e'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','506','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','506','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','m','m'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CE','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','l','l'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','m','m'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','710','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','110','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C1','o','o'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C1','l','l'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C1','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C1','m','m'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','030','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CZ','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CZ','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CZ','m','m'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CZ','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CZ','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CZ','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909Cz','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','111','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','111','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','111','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','111','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','111','9','9'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','111','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','111','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','711','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','711','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','711','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','711','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','711','9','9'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','711','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','711','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','524','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','v','v'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','y','y'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','710','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','P','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CP','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','l','l'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','k','k'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','z','z'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','583','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CM','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','110','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CM','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','e','e'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','8560','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','8560','x','x'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','037','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','e','e'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','8564','z','z'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','8564','u','u'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','8564','q','q'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','8564','x','x'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CM','h','h'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','866','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','866','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','866','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','866','z','z'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','866','x','x'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','866','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CM','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','260','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','300','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','260','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','260','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','260','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','V','v'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','690C','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','020','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','022','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','654','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','6531','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','6532','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C','$','$'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CK','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CK','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CK','k','k'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CK','l','l'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CK','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','041','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','852','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','852','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','m','m'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','8564','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','340','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','600','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','595','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','500','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','502','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CP','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CC','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CC','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CC','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CC','h','h'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CC','l','l'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','596','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','591','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','o','o'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','o','o'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CO','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CP','s','s'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CO','s','s'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CP','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','594','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','594','c','c'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','594','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','856','k','k'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','u','u'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','598','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CR','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CR','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CR','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CR','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CR','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CR','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CP','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CH','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CH','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CF','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CH','e','e'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CH','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CF','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CH','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CH','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CH','s','s'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CF','g','g'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CF','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CF','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','088','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','246','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','770','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','772','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','780','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','785','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','787','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CA','q','q'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','246','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','770','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','772','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','780','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','785','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','787','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','s','s'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','541','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','541','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','541','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','0248','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','e','e'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CI','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CE','m','m'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','490','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','490','v','v'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CE','s','s'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CE','d','d'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','65017','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','65017','2','2'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','6502','$','$'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','65027','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CS','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','044','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','310','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C2','i','i'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C2','f','f'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C2','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CS','s','s'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CS','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CS','y','y'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','o','o'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','655','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','245','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','250','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','245','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','130','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','130','s','s'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','130','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','246','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','246_1','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','246_3','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','210','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CP','t','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','85642','r','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','85642','z','z'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','85642','u','u'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','b','b'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','270','e','e'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','v','v'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CD','x','x'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','080','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','u','u'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','245','n','n'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','245','p','p'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CM','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CM','l','l'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909CL','x','x'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C1','y','y'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C0','y','y'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','T','t'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','040','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','770','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','772','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','780','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','785','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','787','w','w'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','M','m'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','Y','y'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','R','r'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','U','u'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','Z','z'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','999C5','O','o'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','980','a','a'); INSERT INTO flxXMLMARCEXTRULESUBFIELDS VALUES ('DEFAULT','909C4','D','d'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('DEFAULT',100,0,'record','\" \r\n hb \r\n \" \r\nxml_text(format(\"DEFAULT_HTML_BRIEF\"))\r\n\" \r\n \r\n \r\n hd \r\n \" \r\nxml_text(format(\"DEFAULT_HTML_DETAILED\"))\r\n\" \r\n \r\n\"'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('HB',100,0,'','\"\r\n \" $001 \"\r\n \r\n hb \r\n \" \r\nxml_text(format(\"DEFAULT_HTML_BRIEF\"))\r\n\" \r\n \r\n\"'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('HP',0,0,'','\"\r\n \" $001 \"\r\n \r\n hp \r\n \" \r\nxml_text(format(\"DEFAULT_HTML_PORTFOLIO\"))\r\n\" \r\n \r\n\"'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('HC',0,0,'','\"\r\n \" $001 \"\r\n \r\n hc \r\n \" \r\nxml_text(format(\"DEFAULT_HTML_CAPTIONS\"))\r\n\" \r\n \r\n\"'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('HD',100,100,'','\"\r\n \" $001 \"\r\n \r\n hd \r\n \" \r\nxml_text(format(\"DEFAULT_HTML_DETAILED\"))\r\n\" \r\n \r\n\"'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('HB',0,0,'','\"\r\n \" $001 \"\r\n \r\n hb \r\n \" \r\nxml_text(format(\"PICTURE_HTML_BRIEF\"))\r\n\" \r\n \r\n\"'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('HD',90,0,'','\"\r\n \" $001 \"\r\n \r\n hd \r\n \" \r\nxml_text(format(\"PICTURE_HTML_DETAILED\"))\r\n\" \r\n \r\n\"'); INSERT INTO flxBEHAVIORCONDITIONSACTIONS VALUES ('HX',0,0,'','format(\"_FULL_BIBTEX\")'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('DEFAULT',100,'\"\"=\"\"'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('HB',0,'$980.a=\"PICTURE\"'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('HB',100,'\"\"=\"\"'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('HP',0,'\"\"=\"\"'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('HC',0,'\"\"=\"\"'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('HD',100,'\"\"=\"\"'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('HD',90,'$980.a=\"PICTURE\"'); INSERT INTO flxBEHAVIORCONDITIONS VALUES ('HX',0,'\"\"=\"\"'); INSERT INTO flxBEHAVIORS VALUES ('DEFAULT','IENRICH','Creates DEFAULT formats and includes them in the input XML OAI MARC record in the \"FMT\" element'); INSERT INTO flxBEHAVIORS VALUES ('HB','NORMAL','Produces HTML brief format. Useful for reformatting records existing in the database.'); INSERT INTO flxBEHAVIORS VALUES ('HP','NORMAL','PRODUCES HTML PORTFOLIO FORMAT. USEFUL FOR REFORMATTING RECORDS EXISTING IN THE DATABASE.'); INSERT INTO flxBEHAVIORS VALUES ('HC','NORMAL','PRODUCES HTML CAPTIONS FORMAT. USEFUL FOR REFORMATTING RECORDS\r\nEXISTING IN THE DATABASE.'); INSERT INTO flxBEHAVIORS VALUES ('HD','NORMAL','PRODUCES HTML DETAILED FORMAT. USEFUL FOR REFORMATTING RECORDS EXISTING IN THE DATABASE.'); INSERT INTO flxBEHAVIORS VALUES ('HX','NORMAL','PRODUCES HTML BibTeX format.'); INSERT INTO flxUDFS VALUES ('URLENCODE','return urlencode($url);','STRING',NULL); INSERT INTO flxUDFS VALUES ('UPPER','return strtoupper($s);','STRING','Purpose: Returns characters of string s into uppercase characters\r\nExample: upper(\"test12\") gives as result \"TEST12\"'); INSERT INTO flxUDFS VALUES ('SUBSTR','return substr($s, $start, $end-$start+1);','STRING','Purpose: Returns substring between position start and end from the string s\r\nExample: substr(\"test\", 2, 3) gives as result \"st\"'); INSERT INTO flxUDFS VALUES ('ADD','if($prefix!=\"\")\r\n $value=$prefix.$value;\r\nif($postfix!=\"\")\r\n $value=$value.$postfix;\r\nreturn $value;\r\n','STRING','Purpose: This function adds prefix at the begining and postfix at the end, of value\r\nExample: add(\"test\",\"pre\",\"post\") gives as result \"pretestpost\"\r\nNote: Defined to keep compatibility with uploader\'s languaje'); INSERT INTO flxUDFS VALUES ('MINFO','return \"More Info\";','STRING',''); INSERT INTO flxUDFS VALUES ('RNETC','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('EXT','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('MARK','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('SEPARATOR','if(!$LAST_ITERATION)\r\n return $str;\r\nreturn \"\";','STRING',NULL); INSERT INTO flxUDFS VALUES ('TIONE','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('BRBER','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('MINFA','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('INDIS','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('INHLD','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('LKR','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('NIUCO','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('HOL','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('SNLNK','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('AUFU','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('LKRFU','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('SP','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('HO','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('SREF','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('QUOT','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('MARKF','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('LATEX','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('DI','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('REP_PREFIX','if($FIRST_ITERATION) return $str; return \"\";','STRING',NULL); INSERT INTO flxUDFS VALUES ('XML_TEXT','return htmlspecialchars($str,ENT_QUOTES); \r\n\r\n','STRING',''); INSERT INTO flxUDFS VALUES ('REP','return str_replace($search, $replacement, $str); \r\n\r\n','STRING','Purpose: Replaces any occurence of string search inside string str by the \r\nreplacement one.\r\nExample: rep(\"test12test\", \"12\", \"-\") gives as result \"test-test\"'); INSERT INTO flxUDFS VALUES ('SAVETOFILE','$fh=fopen($filename, \"w\"); if(!$fh) return \"ERROR OPENING FILE \'$filename\'\"; fwrite($fh, $code); fclose($fh); return \"\"; ','STRING',NULL); INSERT INTO flxUDFS VALUES ('FORMAT_EXIST','$format_name=strtoupper(trim($format_name)); \r\n$res=\"\"; \r\n$db=mysql_pconnect(\"cdsdb.cern.ch\", \"flexelink\", \"2flexible\"); \r\nmysql_selectdb(\"flexelink\"); \r\n$qry=\"select name from FORMATS where name=\'$format_name\'\"; \r\n$qh=mysql_query($qry); \r\nif(mysql_num_rows($qh)==1) \r\n $res=\"Y\"; \r\nreturn $res; ','STRING','Purpose: Tells if a format exists in the FlexElink formats database. Returns non-empty string when a format called format_name doesn\'t exist in the format db, empty string in\r\n other case\r\nNote: To be migrated to FlexElink EL internal fuction'); INSERT INTO flxUDFS VALUES ('TOC','return \"\";','STRING','Temporary defined for \"automatic format migration\" compatibility. Gives empty string.'); INSERT INTO flxUDFS VALUES ('DATE','return date(\"j M Y H:i:s\");','STRING','Purpose: Gives the current date in the following format \"day month_name year2k hh:mm:ss\"'); INSERT INTO flxUDFS VALUES ('FILTER_PAGENR','$temp=explode(\"-\", $str);\r\nreturn $temp[0];','STRING',''); INSERT INTO flxUDFS VALUES ('LOWER','return strtolower($str);','STRING','Purpose: Returns characters of string s into lowercase characters \r\nExample: lower(\"TEsT12\") gives as result \"test12\"'); INSERT INTO flxUDFS VALUES ('SUBSTR_END','return substr($str, $start);','STRING','Purpose: Returns a substring from the string s, from position start to the end of the string. \r\nNote that characters into a string are always numerated starting in 0\r\nExample: substr(\"test\", 2) gives as result \"st\"'); INSERT INTO flxUDFS VALUES ('LIMW_L','$temp=explode($token, $str, 2);\r\nreturn $temp[0];','STRING','Purpose: Returns a substring from the string str, containing all characters found in it\r\nbefore the first occurrence of string token.\r\nExample: substr_bef_token(\"test1@test2@test3\", \"@\") gives as result \"test1\"'); INSERT INTO flxUDFS VALUES ('LIMW_R','$temp=explode($token, $str, 2); \r\nreturn $temp[1];','STRING','Purpose: Returns a substring from the string str, containing all characters found in it\r\nafter the first acourrence of string token.\r\nExample: substr_bef_token(\"test1@test2@test3\", \"@\") gives as result \"test2@test3\"'); INSERT INTO flxUDFS VALUES ('FILE_EXISTS','$fh=@fopen($url, \"r\");\r\n$res=\"\";\r\nif($fh)\r\n $res=$url;\r\nreturn $res;','STRING','Purpose: Checks if the given url exists. If so it returns the url, if not it gives back an empty string.\r\nExample: file_exists(\"/not/exists\") gives \"\" as far as file \"/not/exists\" doesn\'t exist'); INSERT INTO flxUDFS VALUES ('CUT_FILE','$fh=@fopen($url, \"r\");\r\n$res=\"\";\r\nif($fh)\r\n{\r\n $found=false;\r\n if($start_token==\"\")\r\n {\r\n $found=true;\r\n }\r\n while(!feof($fh))\r\n {\r\n if(!$found)\r\n {\r\n $line=fgets($fh, 4096);\r\n $pos=strpos($line, $start_token);\r\n if($pos === false)\r\n continue;\r\n $res=substr($line, $pos, strlen($start_tag));\r\n $line=substr($line, $pos+strlen($start_tag));\r\n $found=true;\r\n }\r\n else\r\n {\r\n $pos=strpos($line, $end_token);\r\n if($pos === false)\r\n {\r\n $res.=$line;\r\n $line=fgets($fh, 4096);\r\n }\r\n else\r\n {\r\n $res.=substr($line, 0, $pos+strlen($end_token));\r\n break;\r\n }\r\n }\r\n }\r\n fclose($fh);\r\n}\r\n\r\nreturn $res;','STRING','Purpose: This function opens the file pointed by the URL url. If it\'s accessible, it parses it and \r\nreturns all characters between first occurence of string start_token and first occurrence of \r\nstring end_token.\r\nExample: cut_file(\"/local/pp.txt\", \"PEPE\", \"JOSE\") and \"/local/pp.txt\" file contains the\r\n following text \r\n\"In spanish PEPE means JOSE and PACO means FRANCISCO\", \r\nwould give as result \"PEPE means JOSE\"'); INSERT INTO flxUDFS VALUES ('STRPOS','$pos=strpos($str, $substr);\r\nif($pos === false)\r\n{\r\n return \"\";\r\n}\r\nelse\r\n{\r\n return \"$pos\";\r\n}','STRING',''); INSERT INTO flxUDFS VALUES ('GET_FROM_SETLINKURL','$url=parse_url( $url );\r\n$res=\"\";\r\nif(trim($url[query])!=\"\")\r\n{\r\n $params=explode(\"&\", $url[query]);\r\n foreach($params as $param)\r\n {\r\n $param=explode(\"=\", $param);\r\n if(trim($param[0])==$field)\r\n {\r\n $res=trim($param[1]);\r\n break;\r\n }\r\n } \r\n}\r\nreturn $res;','STRING',''); INSERT INTO flxUDFS VALUES ('FILTER_CDS_ID','$temp=explode(\"-\", $str, 2); \r\nreturn $temp[0];','STRING',''); INSERT INTO flxUDFS VALUES ('COPY','return substr($str, $start, $length);','STRING','Purpose: Returns a substring from string str, that starts in position start\r\n and that is length characters long from there\r\nExample: copy(\"test\", \"1\", \"2\") gives as result \"es\"'); INSERT INTO flxUDFS VALUES ('TERMINATOR','if($LAST_ITERATION)\r\n return $str;','STRING',''); INSERT INTO flxUDFS VALUES ('SUM','return $v1+$v2;','STRING','Purpose: Gives the result of adding v1 to v2 (v1+v2)\r\nExample: add(\"3\", \"4\") gives as result \"7\"'); INSERT INTO flxUDFS VALUES ('GT','if($v1>$v2)\r\n return \"1\";\r\nreturn \"\";','STRING','Purpose: \"Greater than\" function; returns \"1\" if v1>v2, \"\" in other case\r\nExample: gt(\"3\", \"4\") gives as result \"\"'); INSERT INTO flxUDFS VALUES ('EXTRACT_EMAIL','if(ereg(\"([^ <\\t\\n]+@[^ >\\t\\n]+)\", $str, $res))\r\n{\r\n return $res[1];\r\n}\r\nelse\r\n return \"\";\r\n','STRING','Purpose: Returns the first valid (filtered) email address found in string str. \r\nIf there\'s no valid email address in it, it returns \"\"\r\nExample: extract_email(\"Hector Sanchez \") gives \"Hector.Sanchez@cern.ch\".'); INSERT INTO flxUDFS VALUES ('GE','if($v1>=$v2)\r\n return \"1\";\r\nreturn \"\";','STRING','Purpose: \"Greater or equal than\" function; returns \"1\" if v1>=v2, \"\" in other case\r\nExample: ge(\"3\", \"4\") gives as result \"\"'); INSERT INTO flxUDFS VALUES ('LE','if($v1<=$v2)\r\n return \"1\";\r\nreturn \"\";','STRING','Purpose: \"Lower or equal than\" function; returns \"1\" if v1<=v2, \"\" in other case\r\nExample: ge(\"3\", \"4\") gives as result \"\"'); INSERT INTO flxUDFS VALUES ('ISO_NUM','$iso=substr($str, strlen($str_iso));\r\n$temp=explode(\"-\", $iso, 2);\r\n$isonum=$temp[0]; \r\nreturn $isonum;\r\n','STRING',''); INSERT INTO flxUDFS VALUES ('ISO_PART','$iso=substr($str, strlen($str_iso)); \r\n$temp=explode(\"-\", $iso, 2); \r\n$isopart=\"\";\r\nif(count($temp)>1)\r\n{\r\n $isopart=$temp[1]; \r\n}\r\nreturn $isopart; \r\n','STRING',''); INSERT INTO flxUDFS VALUES ('ISO_NUMPART_LINK','$iso=substr($str, strlen($str_iso));\r\n$temp=explode(\"-\", $iso, 2);\r\n$isolink=$temp[0]; \r\nif(count($temp)>1)\r\n{\r\n if(strlen($temp[1])>0)\r\n {\r\n $isolink.=\"&part=\";\r\n $isolink.=str_replace(\"-\", \"&se=\", $temp[1]);\r\n }\r\n}\r\nreturn $isolink;\r\n','STRING',''); INSERT INTO flxUDFS VALUES ('STRIP_SPACES','return str_replace(\" \", \"\", $str);','STRING',''); INSERT INTO flxUDFS VALUES ('LFILL','if(strlen($char)==0) return $str;\r\nif(strlen($str)>$digits) \r\n $str=substr($str, strlen($str)-$digits);\r\nelse\r\n $str=sprintf(\"%0\".$digits.\"u\", $str);\r\nreturn $str;','STRING','Purpose: Returns a string consisting in the string str with the character char \r\nadded to its left the numer of times needed until the lenght digits is reached. If the length\r\nof str is bigger than digits, a left truncated string to length digit is returned.\r\nExample: lfill(\"12\", \"0\", \"5\") gives as result \"00012\", while lfill(\"12345\", \"0\", \"3\") gives as result \"345\", while'); INSERT INTO flxUDFS VALUES ('STR_BUFFER','return add_text($action, $str_to_add, $remove_end_before_print, $min_length_for_print);\r\n\r\nfunction add_text($action, $str_to_add, $remove_end_before_print, $min_length_for_print) {\r\n static $whole_str_buffer = \'\';\r\n\r\n if($action === \'print\') {\r\n if (strlen($whole_str_buffer) > $min_length_for_print){ \r\n $retrn_val = substr($whole_str_buffer, 0, strlen($whole_str_buffer) - $remove_end_before_print) . $str_to_add;\r\n $whole_str_buffer = \'\';\r\n \r\n return $retrn_val;\r\n }\r\n $whole_str_buffer = \'\';\r\n return \'\';\r\n }elseif($action === \'add\'){\r\n $whole_str_buffer .= $str_to_add;\r\n return \'\';\r\n }elseif($action ===\'reset\'){\r\n $whole_str_buffer = \'\';\r\n return \'\';\r\n }else{\r\n return \'\';\r\n }\r\n}','','Purpose:Concatenates strings into static buffer without printing it out before you say so.\r\nParameters:\r\naction: If action is \"add\", then it adds the string to the buffer, if the action is \"print\", then it first removes the end of the string, then adds str_to_add, then prints out. If action is \"reset\", then it resets the buffer to \"\". When you do a \"print\", it also resets the buffer.\r\nstr_to_add: The string you want to add to the already stored string. If action is \"print\" then this part will be added after the function has taken away the end of the string.\r\nremove_end_before_print: Only works when action is \"print\", then it removes the number of chars you have specified before adding the rest of the string, and prints out.\r\nmin_length_for_print: If string is shorter then this when action is \"print\", then it will return \"\". This parameter is only in use when action is \"print\".\r\nExample:\r\nSTR_BUFFER(\"add\", \"\\\"Øyvind and \", \"0\", \"0\");\r\nSTR_BUFFER(\"print\", \"\\\"\", \"5\", \"3\");\r\noutputs: \"Øyvind\"'); INSERT INTO flxUDFS VALUES ('GET_NAME','$pos=strpos($names, \',\');\r\n\r\nif($pos === false){\r\n $name_ar = preg_split(\"/[\\s+]+/\", $names);\r\n $names = \"\";\r\n\r\n for($i = 0; $i < count($name_ar); $i++){\r\n if(strlen($name_ar[$i]) >= strlen($names)){\r\n $names = $name_ar[$i];\r\n }\r\n }\r\n return $names;\r\n}\r\n\r\n$newname = substr($names, 0, $pos);\r\n\r\nreturn str_replace(\" \", \"\", $newname);','','Purpose: Tryes to find the last name in a string, and returns it.\r\nExample: GET_NAME(\"Østlund, Øyvind B\"); returns \"Østlund\".'); INSERT INTO flxUDFS VALUES ('SPLIT_LINE','$start_index = 0;\r\n$result_string;\r\n$done = false;\r\n$firstline = true;\r\n\r\nwhile (!$done){\r\n\r\n if($start_index + $str_len >= strlen($split_str)){\r\n $done = true;\r\n $split = strlen($split_str) - $start_index;\r\n $result_string .= substr($split_str, $start_index);\r\n }else{\r\n $found = false;\r\n\r\n if($firstline == true){\r\n $split = $str_len + $indentation;\r\n $firstline = false;\r\n }else{\r\n $split = $str_len;\r\n }\r\n\r\n while ($split > 0 && $found == false){\r\n if($split_str[$start_index + $split] == \' \'){\r\n $found = true;\r\n }else{\r\n $split --;\r\n }\r\n }\r\n\r\n $result_string .= substr($split_str, $start_index, $split) . \'
\' . str_repeat(\' \', $indentation);\r\n $start_index += $split + 1;\r\n }\r\n}\r\n\r\n\r\nreturn $result_string;\r\n\r\n\r\n\r\n','','Purpose: Splits a line after a certain amount of letters. Does not split a word in two, but finds the nearest word break. \r\nNotice: Indentation is only for line 2->n, not line 1.\r\nNotice: First line will be the length of str_len + indentation.\r\nNotice: If there is HTML tags in the string, they will be counted too.\r\nExample: SPLIT_LINE(\"title = Nuclear matter with off-shell propagation\", \"35\", \"15\");\r\nReturns:
title        = Nuclear matter with\r\n               off-shell propagation
'); INSERT INTO flxUDFS VALUES ('GET_MONTH','if(eregi(\'jan\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'feb\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'mar\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'apr\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'may\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'jun\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'jul\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'aug\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'sep\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'oct\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'nov\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(eregi(\'dec\', $date, $res)){\r\n return ucfirst(strtolower($res[0]));\r\n}elseif(preg_match(\'/(?<=[-\\/])\\n\\n(?=[-\\/])/i\', $date, $res)){\r\n if($res[0] === \'01\' || $res[0] === \'1\'){\r\n return \'Jan\';\r\n }elseif($res[0] === \'02\' || $res[0] === \'2\'){\r\n return \'Feb\';\r\n }elseif($res[0] === \'03\' || $res[0] === \'3\'){\r\n return \'Mar\';\r\n }elseif($res[0] === \'04\' || $res[0] === \'4\'){\r\n return \'Apr\';\r\n }elseif($res[0] === \'05\' || $res[0] === \'5\'){\r\n return \'May\';\r\n }elseif($res[0] === \'06\' || $res[0] === \'6\'){\r\n return \'Jun\';\r\n }elseif($res[0] === \'07\' || $res[0] === \'7\'){\r\n return \'Jul\';\r\n }elseif($res[0] === \'08\' || $res[0] === \'8\'){\r\n return \'Aug\';\r\n }elseif($res[0] === \'09\' || $res[0] === \'9\'){\r\n return \'Sep\';\r\n }elseif($res[0] === \'10\'){\r\n return \'Oct\';\r\n }elseif($res[0] === \'11\'){\r\n return \'Nov\';\r\n }elseif($res[0] === \'12\'){\r\n return \'Dec\';\r\n }\r\n}\r\n\r\nreturn \"\";','','Purpose: Takes a string as input, and returns a 3 letter abrivation of the month if the string contains it.\r\nExample: Accepted string format is e.g. 17 February 2004, 2004/02/17, 17-Feb-2004, etc. (Almost any English date format!)'); INSERT INTO flxUDFS VALUES ('GET_YEAR','if(ereg(\'[[:digit:]][[:digit:]][[:digit:]][[:digit:]]\', $date, $res)){\r\n return $res[0];\r\n}elseif(ereg(\'[[:digit:]][[:digit:]][[:digit:]][[:digit:]]\', $date, $res)){\r\n return $res[0];\r\n}','','Purpose: Takes a string as input, and returns a 4 digit year if the string contains it.'); INSERT INTO flxUDFPARAMS VALUES ('URLENCODE','url',0); INSERT INTO flxUDFPARAMS VALUES ('ADD','postfix',2); INSERT INTO flxUDFPARAMS VALUES ('SUBSTR','end',2); INSERT INTO flxUDFPARAMS VALUES ('UPPER','s',0); INSERT INTO flxUDFPARAMS VALUES ('SUBSTR','s',0); INSERT INTO flxUDFPARAMS VALUES ('SUBSTR','start',1); INSERT INTO flxUDFPARAMS VALUES ('MINFO','sysno',0); INSERT INTO flxUDFPARAMS VALUES ('SEPARATOR','str',0); INSERT INTO flxUDFPARAMS VALUES ('REP_PREFIX','str',0); INSERT INTO flxUDFPARAMS VALUES ('XML_TEXT','str',0); INSERT INTO flxUDFPARAMS VALUES ('REP','search',1); INSERT INTO flxUDFPARAMS VALUES ('REP','str',0); INSERT INTO flxUDFPARAMS VALUES ('SAVETOFILE','filename',0); INSERT INTO flxUDFPARAMS VALUES ('SAVETOFILE','code',1); INSERT INTO flxUDFPARAMS VALUES ('REP','replacement',2); INSERT INTO flxUDFPARAMS VALUES ('FORMAT_EXIST','format_name',0); INSERT INTO flxUDFPARAMS VALUES ('FILTER_PAGENR','str',0); INSERT INTO flxUDFPARAMS VALUES ('LOWER','str',0); INSERT INTO flxUDFPARAMS VALUES ('ADD','value',0); INSERT INTO flxUDFPARAMS VALUES ('ADD','prefix',1); INSERT INTO flxUDFPARAMS VALUES ('STRPOS','substr',1); INSERT INTO flxUDFPARAMS VALUES ('STRPOS','str',0); INSERT INTO flxUDFPARAMS VALUES ('CUT_FILE','end_token',2); INSERT INTO flxUDFPARAMS VALUES ('CUT_FILE','start_token',1); INSERT INTO flxUDFPARAMS VALUES ('CUT_FILE','url',0); INSERT INTO flxUDFPARAMS VALUES ('FILE_EXISTS','url',0); INSERT INTO flxUDFPARAMS VALUES ('SUBSTR_END','str',0); INSERT INTO flxUDFPARAMS VALUES ('SUBSTR_END','start',1); INSERT INTO flxUDFPARAMS VALUES ('LIMW_R','str',0); INSERT INTO flxUDFPARAMS VALUES ('LIMW_L','str',0); INSERT INTO flxUDFPARAMS VALUES ('LIMW_L','token',1); INSERT INTO flxUDFPARAMS VALUES ('LIMW_R','token',1); INSERT INTO flxUDFPARAMS VALUES ('GET_FROM_SETLINKURL','url',0); INSERT INTO flxUDFPARAMS VALUES ('GET_FROM_SETLINKURL','field',1); INSERT INTO flxUDFPARAMS VALUES ('FILTER_CDS_ID','str',0); INSERT INTO flxUDFPARAMS VALUES ('COPY','str',0); INSERT INTO flxUDFPARAMS VALUES ('COPY','start',1); INSERT INTO flxUDFPARAMS VALUES ('TERMINATOR','str',0); INSERT INTO flxUDFPARAMS VALUES ('SUM','v1',0); INSERT INTO flxUDFPARAMS VALUES ('GT','v1',0); INSERT INTO flxUDFPARAMS VALUES ('SUM','v2',1); INSERT INTO flxUDFPARAMS VALUES ('EXTRACT_EMAIL','str',0); INSERT INTO flxUDFPARAMS VALUES ('GT','v2',1); INSERT INTO flxUDFPARAMS VALUES ('GE','v2',1); INSERT INTO flxUDFPARAMS VALUES ('GE','v1',0); INSERT INTO flxUDFPARAMS VALUES ('LE','v1',0); INSERT INTO flxUDFPARAMS VALUES ('LE','v2',1); INSERT INTO flxUDFPARAMS VALUES ('ISO_NUM','str_iso',0); INSERT INTO flxUDFPARAMS VALUES ('ISO_NUM','str',1); INSERT INTO flxUDFPARAMS VALUES ('ISO_PART','str_iso',0); INSERT INTO flxUDFPARAMS VALUES ('ISO_PART','str',1); INSERT INTO flxUDFPARAMS VALUES ('ISO_NUMPART_LINK','str_iso',0); INSERT INTO flxUDFPARAMS VALUES ('ISO_NUMPART_LINK','str',1); INSERT INTO flxUDFPARAMS VALUES ('STRIP_SPACES','str',0); INSERT INTO flxUDFPARAMS VALUES ('LFILL','digits',2); INSERT INTO flxUDFPARAMS VALUES ('LFILL','char',1); INSERT INTO flxUDFPARAMS VALUES ('LFILL','str',0); INSERT INTO flxUDFPARAMS VALUES ('COPY','length',2); INSERT INTO flxUDFPARAMS VALUES ('STR_BUFFER','action',0); INSERT INTO flxUDFPARAMS VALUES ('STR_BUFFER','str_to_add',1); INSERT INTO flxUDFPARAMS VALUES ('STR_BUFFER','min_length_for_print',3); INSERT INTO flxUDFPARAMS VALUES ('STR_BUFFER','remove_end_before_print',2); INSERT INTO flxUDFPARAMS VALUES ('GET_YEAR','date',0); INSERT INTO flxUDFPARAMS VALUES ('GET_MONTH','date',0); INSERT INTO flxUDFPARAMS VALUES ('GET_NAME','names',0); INSERT INTO flxUDFPARAMS VALUES ('SPLIT_LINE','indentation',2); INSERT INTO flxUDFPARAMS VALUES ('SPLIT_LINE','split_str',0); INSERT INTO flxUDFPARAMS VALUES ('SPLIT_LINE','str_len',1); INSERT INTO flxUSERS VALUES (1); INSERT INTO oaiARCHIVE VALUES (1,'','global','','','',NULL,'','','','','','','','',''); INSERT INTO sbmACTION VALUES ('Submit New Record','SBI','running','1998-08-17','2001-08-08','','Submit New Record'); INSERT INTO sbmACTION VALUES ('Modify Record','MBI','modify','1998-08-17','2001-11-07','','Modify Record'); INSERT INTO sbmACTION VALUES ('Submit New File','SRV','revise','0000-00-00','2001-11-07','','Submit New File'); INSERT INTO sbmACTION VALUES ('Approve Record','APP','approve','2001-11-08','2002-06-11','','Approve Record'); INSERT INTO sbmALLFUNCDESCR VALUES ('CaseEDS',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Create_Modify_Interface',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Create_Recid',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Finish_Submission',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Get_Info',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Get_Recid', 'This function gets the recid for a document with a given report-number (as stored in the global variable rn).'); INSERT INTO sbmALLFUNCDESCR VALUES ('Get_Report_Number',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Get_Sysno',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Insert_Modify_Record',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Insert_Record',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Is_Original_Submitter',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Is_Referee','This function checks whether the logged user is a referee for the current document'); INSERT INTO sbmALLFUNCDESCR VALUES ('Mail_Submitter',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Make_Modify_Record',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Make_Record',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Move_From_Pending',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Move_to_Done',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Move_to_Pending',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Print_Success',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Print_Success_APP',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Print_Success_MBI',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Print_Success_SRV',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Report_Number_Generation',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Send_Approval_Request',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Send_APP_Mail',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Send_Modify_Mail',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Send_SRV_Mail',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Test_Status',''); INSERT INTO sbmALLFUNCDESCR VALUES ('Update_Approval_DB',NULL); INSERT INTO sbmALLFUNCDESCR VALUES ('Upload_Files',''); INSERT INTO sbmCHECKS VALUES ('AUCheck','function AUCheck(txt) {\r\n var res=1;\r\n tmp=txt.indexOf(\"\\015\");\r\n while (tmp != -1) {\r\n left=txt.substring(0,tmp);\r\n right=txt.substring(tmp+2,txt.length);\r\n txt=left + \"\\012\" + right;\r\n tmp=txt.indexOf(\"\\015\");\r\n }\r\n tmp=txt.indexOf(\"\\012\");\r\n if (tmp==-1){\r\n line=txt;\r\n txt=\'\';}\r\n else{\r\n line=txt.substring(0,tmp);\r\n txt=txt.substring(tmp+1,txt.length);}\r\n while (line != \"\"){\r\n coma=line.indexOf(\",\");\r\n left=line.substring(0,coma);\r\n right=line.substring(coma+1,line.length);\r\n coma2=right.indexOf(\",\");\r\n space=right.indexOf(\" \");\r\n if ((coma==-1)||(left==\"\")||(right==\"\")||(space!=0)||(coma2!=-1)){\r\n res=0;\r\n error_log=line;\r\n }\r\n tmp=txt.indexOf(\"\\012\");\r\n if (tmp==-1){\r\n line=txt;\r\n txt=\'\';}\r\n else{\r\n line=txt.substring(0,tmp-1);\r\n txt=txt.substring(tmp+1,txt.length);}\r\n }\r\n if (res == 0){\r\n alert(\"This author name cannot be managed \\: \\012\\012\" + error_log + \" \\012\\012It is not in the required format!\\012Put one author per line and a comma (,) between the name and the firstname initial letters. \\012The name is going first, followed by the firstname initial letters.\\012Don\'t forget the whitespace after the comma!!!\\012\\012Example \\: Put\\012\\012Le Meur, J Y \\012Baron, T \\012\\012for\\012\\012Le Meur Jean-Yves & Baron Thomas.\");\r\n return 0;\r\n } \r\n return 1; \r\n}','1998-08-18','0000-00-00','',''); INSERT INTO sbmCHECKS VALUES ('DatCheckNew','function DatCheckNew(txt) {\r\n var res=1;\r\n if (txt.length != 10){res=0;}\r\n if (txt.indexOf(\"/\") != 2){res=0;}\r\n if (txt.lastIndexOf(\"/\") != 5){res=0;}\r\n tmp=parseInt(txt.substring(0,2),10);\r\n if ((tmp > 31)||(tmp < 1)||(isNaN(tmp))){res=0;}\r\n tmp=parseInt(txt.substring(3,5),10);\r\n if ((tmp > 12)||(tmp < 1)||(isNaN(tmp))){res=0;}\r\n tmp=parseInt(txt.substring(6,10),10);\r\n if ((tmp < 1)||(isNaN(tmp))){res=0;}\r\n if (txt.length == 0){res=1;}\r\n if (res == 0){\r\n alert(\"Please enter a correct Date \\012Format: dd/mm/yyyy\");\r\n return 0;\r\n }\r\n return 1; \r\n}','0000-00-00','0000-00-00','',''); INSERT INTO sbmFORMATEXTENSION VALUES ('WORD','.doc'); INSERT INTO sbmFORMATEXTENSION VALUES ('PostScript','.ps'); INSERT INTO sbmFORMATEXTENSION VALUES ('PDF','.pdf'); INSERT INTO sbmFORMATEXTENSION VALUES ('JPEG','.jpg'); INSERT INTO sbmFORMATEXTENSION VALUES ('JPEG','.jpeg'); INSERT INTO sbmFORMATEXTENSION VALUES ('GIF','.gif'); INSERT INTO sbmFORMATEXTENSION VALUES ('PPT','.ppt'); INSERT INTO sbmFORMATEXTENSION VALUES ('HTML','.htm'); INSERT INTO sbmFORMATEXTENSION VALUES ('HTML','.html'); INSERT INTO sbmFORMATEXTENSION VALUES ('Latex','.tex'); INSERT INTO sbmFORMATEXTENSION VALUES ('Compressed PostScript','.ps.gz'); INSERT INTO sbmFORMATEXTENSION VALUES ('Tarred Tex (.tar)','.tar'); INSERT INTO sbmFORMATEXTENSION VALUES ('Text','.txt'); INSERT INTO sbmFUNDESC VALUES ('Get_Report_Number','edsrn'); INSERT INTO sbmFUNDESC VALUES ('Send_Modify_Mail','addressesMBI'); INSERT INTO sbmFUNDESC VALUES ('Send_Modify_Mail','sourceDoc'); INSERT INTO sbmFUNDESC VALUES ('Report_Number_Generation','edsrn'); INSERT INTO sbmFUNDESC VALUES ('Report_Number_Generation','autorngen'); INSERT INTO sbmFUNDESC VALUES ('Report_Number_Generation','rnin'); INSERT INTO sbmFUNDESC VALUES ('Report_Number_Generation','counterpath'); INSERT INTO sbmFUNDESC VALUES ('Report_Number_Generation','rnformat'); INSERT INTO sbmFUNDESC VALUES ('Report_Number_Generation','yeargen'); INSERT INTO sbmFUNDESC VALUES ('Mail_Submitter','authorfile'); INSERT INTO sbmFUNDESC VALUES ('Mail_Submitter','status'); INSERT INTO sbmFUNDESC VALUES ('Send_Approval_Request','authorfile'); INSERT INTO sbmFUNDESC VALUES ('Create_Modify_Interface','fieldnameMBI'); INSERT INTO sbmFUNDESC VALUES ('Send_Modify_Mail','fieldnameMBI'); INSERT INTO sbmFUNDESC VALUES ('Update_Approval_DB','categformatDAM'); INSERT INTO sbmFUNDESC VALUES ('Send_SRV_Mail','categformatDAM'); INSERT INTO sbmFUNDESC VALUES ('Send_SRV_Mail','addressesSRV'); INSERT INTO sbmFUNDESC VALUES ('Send_Approval_Request','directory'); INSERT INTO sbmFUNDESC VALUES ('Send_Approval_Request','categformatDAM'); INSERT INTO sbmFUNDESC VALUES ('Send_Approval_Request','addressesDAM'); INSERT INTO sbmFUNDESC VALUES ('Send_Approval_Request','titleFile'); INSERT INTO sbmFUNDESC VALUES ('Send_APP_Mail','edsrn'); INSERT INTO sbmFUNDESC VALUES ('Mail_Submitter','titleFile'); INSERT INTO sbmFUNDESC VALUES ('Send_Modify_Mail','emailFile'); INSERT INTO sbmFUNDESC VALUES ('Get_Info','authorFile'); INSERT INTO sbmFUNDESC VALUES ('Get_Info','emailFile'); INSERT INTO sbmFUNDESC VALUES ('Get_Info','titleFile'); INSERT INTO sbmFUNDESC VALUES ('Make_Modify_Record','modifyTemplate'); INSERT INTO sbmFUNDESC VALUES ('Send_APP_Mail','addressesAPP'); INSERT INTO sbmFUNDESC VALUES ('Send_APP_Mail','categformatAPP'); INSERT INTO sbmFUNDESC VALUES ('Send_APP_Mail','newrnin'); INSERT INTO sbmFUNDESC VALUES ('CaseEDS','casevariable'); INSERT INTO sbmFUNDESC VALUES ('CaseEDS','casevalues'); INSERT INTO sbmFUNDESC VALUES ('CaseEDS','casesteps'); INSERT INTO sbmFUNDESC VALUES ('CaseEDS','casedefault'); INSERT INTO sbmFUNDESC VALUES ('Send_SRV_Mail','noteFile'); INSERT INTO sbmFUNDESC VALUES ('Send_SRV_Mail','emailFile'); INSERT INTO sbmFUNDESC VALUES ('Mail_Submitter','emailFile'); INSERT INTO sbmFUNDESC VALUES ('Mail_Submitter','edsrn'); INSERT INTO sbmFUNDESC VALUES ('Mail_Submitter','newrnin'); INSERT INTO sbmFUNDESC VALUES ('Upload_Files','maxsize'); INSERT INTO sbmFUNDESC VALUES ('Upload_Files','minsize'); INSERT INTO sbmFUNDESC VALUES ('Upload_Files','iconsize'); INSERT INTO sbmFUNDESC VALUES ('Upload_Files','type'); INSERT INTO sbmFUNDESC VALUES ('Make_Record','sourceTemplate'); INSERT INTO sbmFUNDESC VALUES ('Make_Record','createTemplate'); INSERT INTO sbmFUNDESC VALUES ('Print_Success','edsrn'); INSERT INTO sbmFUNDESC VALUES ('Print_Success','newrnin'); INSERT INTO sbmFUNDESC VALUES ('Print_Success','status'); INSERT INTO sbmFUNDESC VALUES ('Make_Modify_Record','sourceTemplate'); INSERT INTO sbmGFILERESULT VALUES ('HTML','HTML document'); INSERT INTO sbmGFILERESULT VALUES ('WORD','data'); INSERT INTO sbmGFILERESULT VALUES ('PDF','PDF document'); INSERT INTO sbmGFILERESULT VALUES ('PostScript','PostScript document'); INSERT INTO sbmGFILERESULT VALUES ('PostScript','data '); INSERT INTO sbmGFILERESULT VALUES ('PostScript','HP Printer Job Language data'); INSERT INTO sbmGFILERESULT VALUES ('jpg','JPEG image'); INSERT INTO sbmGFILERESULT VALUES ('Compressed PostScript','gzip compressed data'); INSERT INTO sbmGFILERESULT VALUES ('Tarred Tex (.tar)','tar archive'); INSERT INTO sbmGFILERESULT VALUES ('JPEG','JPEG image'); INSERT INTO sbmGFILERESULT VALUES ('GIF','GIF'); -INSERT INTO accROLE VALUES (1,'superadmin','superuser with all rights'); -INSERT INTO accROLE VALUES (2,'photoadmin','Photo collection administrator'); -INSERT INTO accROLE VALUES (3,'webaccessadmin','WebAccess administrator'); +INSERT INTO accROLE VALUES (1,'superadmin','superuser with all rights', NULL, NULL); +INSERT INTO accROLE VALUES (2,'photoadmin','Photo collection administrator', NULL, NULL); +INSERT INTO accROLE VALUES (3,'webaccessadmin','WebAccess administrator', NULL, NULL); INSERT INTO user_accROLE VALUES (1,1); INSERT INTO user_accROLE VALUES (1,3); INSERT INTO accACTION VALUES (1,'cfgwebsearch','configure WebSearch','','no'); INSERT INTO accACTION VALUES (2,'cfgbibformat','configure BibFormat','','no'); INSERT INTO accACTION VALUES (3,'runbibindex','run BibIndex','','no'); INSERT INTO accACTION VALUES (4,'runbibupload','run BibUpload','','no'); INSERT INTO accACTION VALUES (5,'runwebcoll','run webcoll','collection','yes'); INSERT INTO accACTION VALUES (6,'runbibformat','run BibFormat','format','yes'); INSERT INTO accACTION VALUES (7,'cfgwebaccess','configure WebAccess','','no'); INSERT INTO accACTION VALUES (8,'accdelegaterole','delegate subroles inside WebAccess','role','no'); INSERT INTO accACTION VALUES (9,'runbibtaskex','run BibTaskEx example', '','no'); INSERT INTO accACTION VALUES (11,'submit','use webSubmit','doctype,act','no'); INSERT INTO accACTION VALUES (12,'cfgwebsubmit','configure webSubmit','','no'); INSERT INTO accACTION VALUES (13,'referee','referee document type doctype','doctype,categ','yes'); INSERT INTO accACTION VALUES (14,'runbibrank','run BibRank','','no'); INSERT INTO accACTION VALUES (15,'cfgbibrank','configure BibRank','','no'); INSERT INTO accACTION VALUES (16,'cfgbibindex','configure BibIndex','','no'); INSERT INTO accACTION VALUES (17,'cfgbibharvest','configure BibHarvest','','no'); INSERT INTO accACTION VALUES (18,'runoaiharvest','run BibHarvest oaiharvest','','no'); INSERT INTO accACTION VALUES (19,'cfgwebcomment','configure WebComment','','no'); INSERT INTO accACTION VALUES (20,'runoaiarchive','run BibHarvest oaiarchive','','no'); INSERT INTO accACTION VALUES (21,'runbibedit','run BibEdit','','no'); +INSERT INTO accACTION VALUES (22,'accrestrcoll','view restricted collection','collection','no'); INSERT INTO accARGUMENT VALUES (1,'collection','Pictures'); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (1,1, 0, 0); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (1,2, 0, 0); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (1,3, 0, 0); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (1,4, 0, 0); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (1,6,-1,-1); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (1,7, 0, 0); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (2,5, 1, 1); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (3,7, 0, 0); INSERT INTO accROLE_accACTION_accARGUMENT VALUES (1,9, 0, 0);
diff --git a/modules/webaccess/bin/Makefile.am b/modules/webaccess/bin/Makefile.am index cfd5c6659..4b57b37d3 100644 --- a/modules/webaccess/bin/Makefile.am +++ b/modules/webaccess/bin/Makefile.am @@ -1,24 +1,27 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. bin_SCRIPTS = authaction webaccessadmin EXTRA_DIST = authaction.in webaccessadmin.in CLEANFILES = *~ *.tmp authactionc + +all: + chmod u+x ./webaccessadmin diff --git a/modules/webaccess/bin/webaccessadmin.in b/modules/webaccess/bin/webaccessadmin.in index ee097aa92..b472342ed 100644 --- a/modules/webaccess/bin/webaccessadmin.in +++ b/modules/webaccess/bin/webaccessadmin.in @@ -1,106 +1,159 @@ #!@PYTHON@ ## -*- mode: python; coding: utf-8; -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """WebAccess Admin -- reset or add default authorization settings""" __revision__ = "$Id$" try: import getpass import sys from invenio.config import supportemail from invenio.access_control_admin import acc_reset_default_settings from invenio.access_control_admin import acc_add_default_settings + from invenio.access_control_firerole import repair_role_definitions + from invenio.access_control_engine import acc_authorize_action from invenio.dbquery import run_sql except ImportError, e: print "Error: %s" % e import sys sys.exit(1) def usage(code, msg=''): """Print usage info.""" if msg: sys.stderr.write("Error: %s.\n" % msg) sys.stderr.write("WebAccess Admin -- reset or add default authorization settings\n") sys.stderr.write("Usage: %s [options] \n" % sys.argv[0]) sys.stderr.write("Command options:\n") sys.stderr.write(" = reset-default-settings\n") sys.stderr.write(" = add-default-settings\n") + sys.stderr.write(" = compile-role-definitions\n") sys.stderr.write("General options:\n") sys.stderr.write(" -h, --help \t\t Print this help.\n") sys.stderr.write(" -V, --version \t\t Print version information.\n") + sys.stderr.write(" -u, --user username\t Set the user name.\n") sys.exit(code) +def authenticate(user, header="WebAccess Administration", action="cfgwebaccess"): + """Authenticate the user against the user database. + Check for its password, if it exists. + Check for action access rights. + Return user name upon authorization success, + do system exit upon authorization failure. + """ + print header + print "=" * len(header) + if user == "": + print >> sys.stdout, "\rUsername: ", + user = string.strip(string.lower(sys.stdin.readline())) + else: + print >> sys.stdout, "\rUsername:", user + ## first check user pw: + res = run_sql("select id,password from user where email=%s", (user,), 1) + \ + run_sql("select id,password from user where nickname=%s", (user,), 1) + if not res: + print "Sorry, %s does not exist." % user + sys.exit(1) + else: + (uid_db, password_db) = res[0] + if password_db: + password_entered = getpass.getpass() + if password_db == password_entered: + pass + else: + print "Sorry, wrong credentials for %s." % user + sys.exit(1) + ## secondly check authorization for the action: + (auth_code, auth_message) = acc_authorize_action(uid_db, action) + if auth_code != 0: + print auth_message + sys.exit(1) + return user + + def main(): """CLI to acc_authorize_action. The function finds the needed arguments in sys.argv. If the number of arguments is wrong it prints help. Return 1 on success, 0 on failure. """ - + alen = len(sys.argv) action = '' # print help if wrong arguments if alen > 1 and sys.argv[1] in ["-h", "--help"]: usage(0) elif alen > 1 and sys.argv[1] in ["-V", "--version"]: print __revision__ - sys.exit(0) - if alen != 2 or sys.argv[1] not in ['reset-default-settings', 'add-default-settings']: - usage(1) + sys.exit(0) - # getting input from user - print 'User: ', - user = raw_input() - password = getpass.getpass() + isUser = -1 + try: + isUser = sys.argv.index('-u') + sys.argv.remove('-u') + except ValueError: + try: + isUser = sys.argv.index('--user') + sys.argv.remove('--user') + except ValueError: + pass - # validating input - perform = 0 + if isUser > 0 and isUser < alen: + username = sys.argv[isUser] + sys.argv.remove(username) + elif isUser > 0: + usage(0) + else: + username = '' - # check password - if user == supportemail: - perform = run_sql("""select * from user where email = '%s' and password = '%s' """ % (supportemail, password)) and 1 or 0 + alen = len(sys.argv) - if not perform: - # wrong password or user not recognized - print 'User not authorized' - return perform + if alen != 2 or sys.argv[1] not in ['reset-default-settings', 'add-default-settings', 'compile-role-definitions']: + usage(1) + + user = authenticate(username) + + perform = 0 # perform chosen action, add all users above as superusers if sys.argv[1] == 'reset-default-settings': action = 'reset' acc_reset_default_settings([supportemail]) elif sys.argv[1] == 'add-default-settings': action = 'added' acc_add_default_settings([supportemail]) + elif sys.argv[1] == 'compile-role-definitions': + action = 'compiled' + repair_role_definitions() # notify of success - if action: + if action: print '\nOkay, the default authorization settings have been __%s__.' % (action, ) else: print 'Requested action failed.' return perform if __name__ == '__main__': - main() + main() diff --git a/modules/webaccess/doc/admin/Makefile.am b/modules/webaccess/doc/admin/Makefile.am index ad3c27bc3..b20ee7059 100644 --- a/modules/webaccess/doc/admin/Makefile.am +++ b/modules/webaccess/doc/admin/Makefile.am @@ -1,31 +1,31 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. docdir = $(localstatedir)/www/admin/webaccess -doc_DATA = index.html guide.html +doc_DATA = index.html guide.html firerole.html FILESWML = $(wildcard $(srcdir)/*.wml) EXTRA_DIST = $(FILESWML:$(srcdir)/%=%) CLEANFILES = $(doc_DATA) *~ *.tmp %.html: %.html.wml $(top_srcdir)/config/config.wml $(top_builddir)/config/configbis.wml $(top_srcdir)/config/cdsnavbar.wml $(WML) -o\(ALL-LANG_*\)+LANG_EN:$@ $< $(PYTHON) $(top_srcdir)/po/i18n_update_wml_target.py en $@ \ No newline at end of file diff --git a/modules/webaccess/doc/admin/firerole.html.wml b/modules/webaccess/doc/admin/firerole.html.wml new file mode 100644 index 000000000..1d112a80f --- /dev/null +++ b/modules/webaccess/doc/admin/firerole.html.wml @@ -0,0 +1,116 @@ +## $Id$ +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. + +#include "cdspage.wml" \ +title="FireRole language description" \ +navtrail_previous_links="/admin/>Admin Area > /admin/webaccess/>WebAccess Admin " \ +navbar_name="admin" \ +navbar_select="webaccess-admin-guide" + +

Version <: print generate_pretty_revision_date_string('$Id$'); :> + +

The FireRole language description

+ +
+    In the WebAccess RBAC system, roles are built up from their names,
+    description and definition.
+
+    A definition is the way to formally implicitly define which users belong
+    to which roles.
+
+    A definition is expressed in a firewall like rules language. It's built up
+    by rows which are matched from top to bottom, in order to decide if the
+    current user (wethever he/she is logged in or not) may belong to a role.
+
+    Any row has this syntax:
+
+        ALLOW/DENY ANY
+
+        or
+
+        ALLOW/DENY [NOT] field {one or more values}
+
+    The rows are parsed from top to bottom. If a row matches the user than the
+    user belongs to the role if the rule is an ALLOW rule, otherwise, if the
+    rule is a DENY one, the user doesn't belong to the role.
+
+    A rule of the kind ALLOW|DENY ANY always matches, regardless of the user.
+
+    The second type of rule is interpreted as follows: given a dictionary
+    of keys:values describing a user (we will cover this below), the rule
+    considers the value associated with the key named in field, and checks
+    if it corresponds to at least one of the values in the "one or more values" list.
+    This is a list of comma separated strings, which can be literal
+    (double-)quoted strings or regexps (marked by `/' ... `/' signs). If at
+    least a value matches (literally or through the regexp language), the
+    whole rule is considered to match.
+    If the optional NOT keyword is specified than if at least a value of the
+    rule matches the rule is skipped, otherwise if all the value of the rules
+    don't match the whole rule matches.
+
+    A DENY ANY rule is implicitly added at the end of every definition.
+
+    Any field is valid, but only rules concerning fields which currently
+    exist in the user describing dictionary are checked. All the rules
+    with non existant fields are skipped.
+
+    The user describing dictionary is built at runtime with all the informations
+    that can be gathered about the current user (and its session).
+    Currently valid fields are: uid, email, nickname, apache_user, remote_ip,
+    remote_host, groups, apache_groups and all the external settings provided
+    by the external authentication systems (e.g. CERN SSO provides:
+    external_authmethod, external_building, external_department, external_email,
+    external_external, external_firstname, external_fullname, external_homdir,
+    external_homeinstitute, external_lastname, external_login, external_mobilenumber,
+    external_phonenumber).
+
+    Among those fields there are some special cases, which are remote_ip and
+    (apache_)groups. Rules can refer to remote_ip either using a literal
+    expression for specifing list of single ips, or a usual regexp (or list
+    of regexps), or, also, using the common network group/mask notation
+    (e.g. "127.0.0.0/24") as a literal string, which is a mix between literal
+    expressions and regexps. (apache_)groups are related to group memberships.
+    Since a user will probably belong to more than a group, than the rule
+    matches if there's at least one group to which the user belong, that matches
+    at least one of the expressions (NOT rules behave as you can imagine).
+
+    The dictionary is built using the current user session. If the user is
+    authenticated in some way (apache, locally, externally, SSO...) than more
+    infos could be provided to the firerole system in order to decide if the
+    user should belong to a role or not.
+
+    Every rule is case-insensitive (apart values which must match literally
+    and regexp values which don't explicitly specify case-insesitiveness matches).
+
+    Every rule may contain comments preceded by the '#' character. Any comment
+    is discarded.
+
+    When you set a definition for a role, it is actually compiled and stored
+    in a binary compressed form inside the database. If the syntax isn't correct
+    this will be stated and the definition won't be set or updated.
+
+    Example of role definition:
+        allow not email /.*@gmail.com/,/.*@hotmail.com/
+        deny group badguys
+        allow remote_ip "127.0.0.0/24"
+        deny all
+
+    This definition would match all users whose emails don't end with @gmail.com and
+    @hotmail.com, or who don't belong to the group badguys and have remote_ip
+    in the 24bit mask network of 127.0.0.0. All the the other users don't belong
+    to the role which is being defined.
\ No newline at end of file
diff --git a/modules/webaccess/doc/admin/guide.html.wml b/modules/webaccess/doc/admin/guide.html.wml
index b360894f7..9cd5e4738 100644
--- a/modules/webaccess/doc/admin/guide.html.wml
+++ b/modules/webaccess/doc/admin/guide.html.wml
@@ -1,1013 +1,986 @@
 ## $Id$
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
 
 #include "cdspage.wml" \
     title="WebAccess Admin Guide" \
     navtrail_previous_links="/admin/>Admin Area  > /admin/webaccess/>WebAccess Admin " \
     navbar_name="admin" \
     navbar_select="webaccess-admin-guide"
 
 

Version <: print generate_pretty_revision_date_string('$Id$'); :>

Contents

1. Introduction, using roles
2. WebAccess admin interface
3. Example pages, illustrating snapshots
4. Managing accounts / Access policy
5. Managing login methods

1. INTRODUCTION, USING ROLES

   WebAccess is a common RBAC, role based access control, for all of
   CDS Invenio. This means that users are connected to roles that cover
   different areas of access. I.e administrator of the photo
   collection or system librarian. Users can be active in
   different areas and of course connected to as many roles as needed.
 
   The roles are connected to actions. An action identifies a task you
   can perform in CDS Invenio. It can be defined to take any number of
   arguments in order to more clearly describe what you are allowing
   connected users to do.
 
   For example the system librarian can be allowed to run bibwords on
   the different indexes. To allow system librarians to run the
   bibwords indexing on the field author we connect role system
   librarian with action runbibwords using the argument
   index='author'.
 
+  Additionally, roles could have definitions. A definition is a formal
+  description of which users are entitled to belong to the role. So you
+  have two ways for connecting users to roles. Either linking explicitly
+  a user with the role or describing the characteristics that makes users
+  belong to the role.
+
   WebAccess is based on allowing users to perform actions. This means
   that only allowed actions are stored in the access control engine's
   database.
 

2. WEBACCESS ADMIN INTERFACE

 All the WebAccess Administration web pages have certain
 features/design choices in common
 
 - Divided into steps
 
   The process of adding new authorizations/information is
   stepwise. The subtitle contains information about wich step you are
   on and what you are supposed to do.
 
 - Restart from any wanted step
 
   You can always start from an earlier step by simply clicking the
   wanted button. This is not a way to undo changes! No information
   about previous database is kept, so all changes are definite.
 
 - Change or new entry must confirmed
 
   On all the pages you will be asked to confirm the change, with
   information about what kind of change you are about to perform.
 
 - Links to other relevant admin areas on the right side
 
   To make it easier to perform your administration tasks, we have
   added a menu area on the right hand side of these pages. The menu
   contain links to other relevant admin pages and change according to
   the page you are on and the information you have selected.
 

3. EXAMPLE PAGES

 I. Role area
 II. Example - connecting role and user
 
 
 I. Role area
 
   Administration tasks starts in one of the administration areas. The
   role area is the main area from where you can perform all your
   managing tasks. The other admin areas are just other ways of
   entering.
 
 
-
- -
- + - - + - -
- -
- - - - -
- -

Role Administration

- - - - - - - - - - - - -
administration with roles as access point
-
-
Users:
-
add or remove users from the access to a role and its priviliges.
-
Authorizations/Actions:
-
these terms means almost the same, but an authorization is a
- connection between a role and an action (possibly) containing arguments.
-
Roles:
-
see all the information attached to a role and decide if you want to
delete it.
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
idnamedescriptionusersauthorizations / actionsrole
2photoadminadministrator of the photo col... - add / - remove - - add / - modify / - remove - deleteshow details - -
9submitter - add / - remove - add / - modify / - remove - deleteshow details
1superadminall rightsadd / removeadd / - modify / - remove - deleteshow details
4systemlibrariansystem librarian - add / - remove - add / - modify / - remove - deleteshow details
3webaccessadminaccess to web administrator in... - add / - remove - add / - modify / - remove - deleteshow details
-
-
-
Create new role
-
go here to add a new role.
-
Create new action
-
go here to add a new action.
-
-
-
-
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +

Role Administration

+ + + + + + + + + + + + + + + + + +
administration with roles as access point
+ +
+
Users:
+
add or remove users from the access to a role and its priviliges.
+
Authorizations/Actions:
+
these terms means almost the same, but an authorization is a
+ connection between a role and an action (possibly) containing arguments.
+
Roles:
+
see all the information attached to a role and decide if you want to
delete it.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idnamedescriptiondefinitionusersauthorizations / actionsrole
2photoadminPhoto collection administratorNoneadd / deleteadd / modify / removemodify / deleteshow details + +
1superadminsuperuser with all rightsallow email /.*@cern.ch/add / deleteadd / modify / removemodify / deleteshow details
3webaccessadminWebAccess administratorallow apache_user 'jekyll' + de...add / deleteadd / modify / removemodify / deleteshow details
+ +
+ +
+
Create new role
+
go here to add a new role.
+
Create new action
+
go here to add a new action.
+
+ +
+ +
+
+
 
 II. Example - connecting role and user
 
   One of the important tasks that can be handled via the WebAccess Admin Web Interface
   is the delegation of access rights to users. This is done by connecting them to the
   different roles offered.
 
   The task is divided into 5 simple and comprehensive steps. Below follows the pages from
   the different steps with comments on the ongoing procedure.
 
 - step 1 - select a role
 
   You must first select the role you want to connect users to. All the available roles are
   listed alfabetically in a select box. Just find the wanted role and select it. Then click on
   the button saying "select role".
 
   If you start from the Role Area, this step is already done, and you start directly on step 2.
 
 

Connect user to role

step 1 - select a role
1. select role
Create new role
go here to add a new role.
 
 - step 2 - search for users
 
   As you can see, the subtitle of the page has now changed. The subtitle always tells you
   which step you are on and what your current task is.
 
   There can be possibly thousands of users using your online library, therefore it is important
   to make it easier to identify the user you are looking for. Give part of, or the entire search
   string and all users with partly matching e-mails will be listed on the next step.
 
   You can also see that the right hand menu has changed. This area is always updated with links
   to related admin areas.
 
 

Connect user to role

step 2 - search for users
1. select role
2. search pattern
Create new role
go here to add a new role.
Remove users
remove users from role superadmin.
Connected users
show all users connected to role superadmin.
Add authorization
start adding new authorizations to role superadmin.
 
 - step 3 - select a user.
 
   The select box contains all users with partly matching e-mail addresses. Select the one
   you want to connect to the role and continue.
 
   Notice the navigation trail that tells you were on the Administrator pages you are currently
   working.
 
 

Connect user to role

step 3 - select a user
1. select role
2. search pattern
3. select user
Create new role
go here to add a new role.
Remove users
remove users from role superadmin.
Connected users
show all users connected to role superadmin.
Add authorization
start adding new authorizations to role superadmin.
 
 - step 4 - confirm to add user
 
   All WebAccess Administrator web pages display the action you are about to peform, this
   means explaining what kind of addition, change or update will be done to your access control
   data.
 
   If you are happy with your decision, simply confirm it.
 
 

Connect user to role

step 4 - confirm to add user
1. select role
2. search pattern
3. select user
add user mikael.vik@cern.ch to role superadmin?
Create new role
go here to add a new role.
Remove users
remove users from role superadmin.
Connected users
show all users connected to role superadmin.
Add authorization
start adding new authorizations to role superadmin.
 
 - step 5 - confirm user added.
 
   The user has now been added to this role. You can easily continue adding more users to this
   role be restarting from step 2 or 3. You can also go directly to another area and keep working
   on the same role.
 
 

Connect user to role

step 5 - confirm user added
1. select role
2. search pattern
3. select user
add user mikael.vik@cern.ch to role superadmin?

confirm: user mikael.vik@cern.ch added to role superadmin.

Create new role
go here to add a new role.
Remove users
remove users from role superadmin.
Connected users
show all users connected to role superadmin.
Add authorization
start adding new authorizations to role superadmin.
 
 - we are done
 
   This example is very similar to all the other pages where you administrate WebAccess. The pages
   are an easy gateway to maintaing access control rights and share a lot of features.
   - divided into steps
   - restart from any wanted step (not undo)
   - changes must be confirmed
   - link to other relevant areas
   - prevent unwanted input
 
   As an administrator with access to these pages you are free to manage the rights any way you want.
 

IV. Managing accounts and access policy

   Here you can administrate the accounts and the access policy for your CDS Invenio installation.
 
   - Access policy:
 
     To change the access policy, the general config file (or
     access_control_config.py) must be edited manually in a text
     editor. The site can there be defined as opened or closed, you can
     edit the access policy level for guest accounts, registered
     accounts and decide when to warn the owner of the account when
     something happens with it, either when it is created, deleted or
     approved.  The Apache server must be restarted after modifying
     these settings.
 
     The two levels for guest account, are:
        0 - Allow guest accounts
        1 - Do not allow guest accounts
     The five levels for normal accounts, are:
        0 - Allow user to create account, automatically activate new accounts
        1 - Allow user to create account, administrator must activate account
        2 - Only administrators can create account. User cannot edit the email address.
        3 - Users cannot register or update account information (email/password)
        4 - User cannot change default login method
     You can configure CDS Invenio to send an email:
        1. To an admin email-address when an account is created
        2. To the owner of an account when it is created
        3. To the owner of an account when it is activated
        4. To the owner of an account when it is deleted
 
     Define how open the site is:
       0 = normal operation of the site
       1 = read-only site, all write operations temporarily closed
       2 = site fully closed
       CFG_ACCESS_CONTROL_LEVEL_SITE = 0
     Access policy for guests:
       0 = Allow guests to search,
       1 = Guests cannot search (all users must login)
       CFG_ACCESS_CONTROL_LEVEL_GUESTS = 0
     Access policy for accounts:
       0 = Users can register, automatically acticate accounts
       1 = Users can register, but admin must activate the accounts
       2 = Users cannot register or change email address, only admin can register accounts.
       3 = Users cannot register or update email address or password, only admin can register accounts.
       4 = Same as 3, but user cannot change login method.
       CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS = 0
 
     Limit email addresses available to use when register a new account (example: cern.ch):
       CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN = ""
 
     Send an email when a new account is created by an user:
       CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS = 0
 
     Send an email to the user notifying when the account is created:
       CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT = 0
 
     Send an email to the user notifying when the account is activated:
       CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION = 0
 
     Send an email to the user notifying when the account is deleted/rejected:
       CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION = 0
 
   - Account overview:
     Here you find an overview of the number of guest accounts, registered accounts and accounts
     awaiting activation, with a link to the activation page.
 
   - Create account:
     For creating new accounts, the email address must be unique. If configured to do so, an email
     will be sent to the given address when an account is created.
 
   - Edit accounts:
     For activating or rejecting accounts in addition to modifying them. An activated account can be
     inactivated for a short period of time, but this will not warn the account owner. To find accounts
     enter a part of the email address of the account and then search. This may take some time. If there
     are more than the selected number of accounts per page, you can use the next/prev links to switch
     pages. The accounts to search in can also be limited to only activated or not activated accounts.
 
   - Edit account:
     When editing one account, you can change the email address, password, delete the account, or modify
     the baskets or alerts belonging to one account. Which login method should be the default for this
     account can also be selected. To modify baskets or alerts, you need to login as the user, and
     modify the desired data as a normal user. Remember to log out as the user when you are finished
     editing.
 
 

V. Managing login methods

    CDS Invenio supports using external login systems to authenticate users.
 
    When a user wants to login, the username and password given by the user is checked against the selected
    system, if the user is authenticated by the external system, a valid email-address is returned to
    CDS Invenio and used to recognize the user within CDS Invenio.
 
    If a new user is trying to login without having an account, using an external login system, an account
    is automatically created in CDS Invenio to recognize and store the users settings. The password for the
    local account is randomly generated.
 
    If you want the user to be unable to change login method and account username / password, forcing use
    of certain external systems, set CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS to 4 as mentioned in the last paragraph.
 
    If a user is changing login method from an external one to the internal, he also need to either change the
    password before logging out, or ask to get the password sent by email, since the password is randomly
    generated for the local account when using an external login method.
 
    If a external login system is used, you may want to protect the users username / password using HTTPS.
 
    To add new system, two changes must be made (for the time being):
    - The name of the method, if it is default or not, and the classname must be added to the variable
      CFG_EXTERNAL_AUTHENTICATION in access_control_config.py. Atleast one method must be marked as the
      default one. The internal login method should be given with None as classname.
 
      Example:
       CFG_EXTERNAL_AUTHENTICATION = {"%s (internal)" % cdsname: (None, True), "CERN NICE (external)":
                                                         (AuthCernWrapper(), False)}
 
    - A class must be created derived from the class external_authentication inside file
      external_authentication.py. This class must include at least the
      function auth_user. This function returns a valid email-address in CDS Invenio if the user
      is authenticated, not necessarily the same entered by the user as username. If the user
      is not authenticated, return None.
      The class could also provide five more methods: fetch_user_preferences, user_exists,
      fetch_user_groups_membership and fetch_all_users_groups_membership.
      The first should take an email and eventually a password and should return a dictionary of keys
      and value representing external preferences, infos or settings. If, for some reasons, you like
      to force some kind of hiding for some particular field you should export the related key
      prefixed by "HIDDEN_". Those fields won't be displayed in tables and pages regarding external
      settings.
      The second method should check through the external system if a particular email exists. If you
      provide such a method then a user will be able to switch from and to this authorization method.
      The third method should take an email and (if necessary) a password
      and should return a dictionary of external_groups_names toghether with their description, for which
      the user has a membership. Those groups will be merged into the groups system.
      The user will be a member of those groups and will be able to use them in any place
      where groups are useful, but won't be able to unsubscribe or to administrate them.
      The fourth method should just return a dictionary of external groups as keys and touples containing
      a group description and a list of email of users belonging to each groups. Those memberships
      will be merged into the database in the way done by the previous method, but could
      provide batch synchronization of groups.
      The fifth method should just return the nickname as is known by the external authentication
      system, given the usual email/username and the password.
      Note: if your system has more than one external login methods then incoherence in the groups
      memberships could happen when a user switch his login method. This will be fixed some times in the
      future.
      Note every method will receive as last parameter the mod_python request object, that could
      be used for particular purposes.
 
      Example template:
      from invenio.external_authentication import ExternalAuth, WebAccessExternalAuthError
 
      class ExternalAuthFoo(ExternalAuth):
          """External authentication template example."""
 
          def __init__ (self):
              """Initialize stuff here."""
              self.name = None
              pass
 
          def auth_user(self, username, password, req=None):
              """Authenticate user-supplied USERNAME and PASSWORD.
              Return None if authentication failed, or the email address of the
              person if the authentication was successful.  In order to do
              this you may perhaps have to keep a translation table between
              usernames and email addresses.
              Raise WebAccessExternalAuthError in case of external troubles.
              """
              raise NotImplementedError
              #return None
 
          def user_exists(self, email, req=None):
              """Checks against external_authentication for existance of email.
              @return True if the user exists, False otherwise
              """
              raise NotImplementedError
 
          def fetch_user_groups_membership(self, username, password=None, req=None):
              """Given a username, returns a dictionary of groups
              and their description to which the user is subscribed.
              Raise WebAccessExternalAuthError in case of troubles.
              """
              raise NotImplementedError
              #return {}
 
          def fetch_user_preferences(self, username, password=None, req=None):
              """Given a username and a password, returns a dictionary of keys and
              values, corresponding to external infos and settings.
 
              userprefs = {"telephone": "2392489",
              "address": "10th Downing Street"}
              """
              raise NotImplementedError
             #return {}
 
          def fetch_all_users_groups_membership(self, req=None):
              """Fetch all the groups with a description, and users who belong to
              each groups.
              @return {'mygroup': ('description', ['email1', 'email2', ...]), ...}
              """
              raise NotImplementedError
 
          def fetch_user_nickname(self, username, password, req=None):
              """Given a username and a password, returns the right nickname belonging
              to that user (username could be an email).
              """
              raise NotImplementedError
              #return Nickname
 
 - end of file -
 
diff --git a/modules/webaccess/doc/hacking/admin-internals.html.wml b/modules/webaccess/doc/hacking/admin-internals.html.wml index 836c39199..b9746fc1b 100644 --- a/modules/webaccess/doc/hacking/admin-internals.html.wml +++ b/modules/webaccess/doc/hacking/admin-internals.html.wml @@ -1,157 +1,161 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. #include "cdspage.wml" \ title="Access Control Admin Internals" \ navbar_name="hacking-webaccess" \ navtrail_previous_links="/hacking/>Hacking CDS Invenio > /hacking/webaccess/index.html>WebAccess Internals " \ - navbar_select="hacking-webaccess-admin-internals" + navbar_select="hacking-webaccess-admin-internals"

Version <: print generate_pretty_revision_date_string('$Id$'); :>

 These are the functions called by the WebAccess Web Admin Interface to administrate
-the wanted authorizations. This listing is of the most important functions. 
+the wanted authorizations. This listing is of the most important functions.
 
 For more information look in the source code or at the signatures.
 
 CONTENTS
  1. Adding Information
  2. Finding Information
  3. Deleting Information
 
 1. Adding Information
 
 acc_addAction(name_action='', description='', optional='no', *allowedkeywords)
     function to create new entry in accACTION for an action
 
     name_action     - name of the new action, must be unique
 
       keyvalstr     - string with allowed keywords
 
     allowedkeywords - a list of allowedkeywords
 
     keyvalstr and allowedkeywordsdict can not be in use simultanously
 
     success -> return id_action, name_action, description and allowedkeywords
     failure -> return 0
 
 
 
-acc_addRole(name_role, description)
+acc_addRole(name_role, description, definition, definition_src)
     add a new role to accROLE in the database.
 
       name_role - name of the role, must be unique
 
     description - text to describe the role
 
+    definition - precompiled serialized firewall like role definition (firerole)
+
+    definition_src - definition text source for repairing after Python upgrades
+
 
 
 acc_addUserRole(id_user=0, id_role=0, email='', name_role='')
      this function adds a new entry to table user_accROLE and returns it
 
       id_user, id_role - self explanatory
 
         email - email of the user
 
     name_role - name of the role, to be used instead of id.
 
 
 
 acc_addRoleActionArguments_names(name_role='', name_action='', arglistid=-1, optional=0, verbose=0, **keyval)
      this function makes it possible to pass names when creating new entries instead of ids.
     get ids for all the names,
     create entries in accARGUMENT that does not exist,
     pass on to id based function.
 
     name_role, name_action - self explanatory
 
     arglistid - add entries to or create group with arglistid, default -1 create new.
 
      optional - create entry with optional keywords, **keyval is ignored, but should be empty
 
       verbose - used to print extra information
 
      **keyval - dictionary of keyword=value pairs, used to find ids.
 
 
 
 2. Finding Information
 
 acc_findPossibleActions(id_role, id_action)
     Role based function to find all action combinations for a
     give role and action.
 
       id_role - id of role in the database
 
     id_action - id of the action in the database
 
     returns a list with all the combinations.
     first row is used for header.
 
 
 
 3. Deleting Information
 
 acc_deleteAction(id_action=0, name_action=0)
     delete action in accACTION according to id, or secondly name.
     entries in accROLE_accACTION_accARGUMENT will also be removed.
 
       id_action - id of action to be deleted, prefered variable
 
     name_action - this is used if id_action is not given
 
     if the name or id is wrong, the function does nothing
 
 
 
 acc_deleteRole(id_role=0, name_role=0)
      delete role entry in table accROLE and all references from other tables.
 
       id_role - id of role to be deleted, prefered variable
 
     name_role - this is used if id_role is not given
 
 
 
 acc_deleteUserRole(id_user, id_role=0, name_role=0)
      function deletes entry from user_accROLE and reports the success.
 
       id_user - user in database
 
       id_role - role in the database, prefered parameter
 
     name_role - can also delete role on background of role name.
 
 
 
 acc_deleteRoleActionArguments_names(name_role='', name_action='', arglistid=1, **keyval)
     utilize the function on ids by first finding all ids and redirecting the function call.
     break of and return 0 if any of the ids can't be found.
 
     name_role = name of the role
 
     name_action - name of the action
 
     arglistid - the argumentlistid, all keyword=value pairs must be in this same group.
 
     **keyval - dictionary of keyword=value pairs for the arguments.
 
 
 
 
diff --git a/modules/webaccess/doc/hacking/api.html.wml b/modules/webaccess/doc/hacking/api.html.wml index 9cddeaf32..7f0ebdbb7 100644 --- a/modules/webaccess/doc/hacking/api.html.wml +++ b/modules/webaccess/doc/hacking/api.html.wml @@ -1,169 +1,175 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. #include "cdspage.wml" \ title="Access Control Engine API" \ navbar_name="hacking-webaccess" \ navtrail_previous_links="/hacking/>Hacking CDS Invenio > /hacking/webaccess/index.html>WebAccess Internals " \ - navbar_select="hacking-webaccess-engine-api" + navbar_select="hacking-webaccess-engine-api"

Version <: print generate_pretty_revision_date_string('$Id$'); :>

 CDS Invenio Access Control Engine can be called from within your Python programs
 via both a regular Python API and CLI.
 In addition the you get an explanation of the program flow.
 
 Contents:
  1. Regular API
  2. Command Line Interface
  3. Program Flow
  4. External login methods
 
 1. Regular API
 
    Description:
 
       There is not very much information in the database at the moment.
       More can be added on demand.
 
       Information on these will be added when time allows it.
 
    Signature:
 
-      def acc_authorize_action(id_user, name_action, dict={}, **arguments):
+      def acc_authorize_action(req, name_action, dict={}, **arguments):
           """ Check if user is allowed to perform action
 	  with given list of arguments.
 	  Return (0, message) if authentication succeeds, (error_code, error_message) if it fails.
 
 	  The arguments are as follows:
-    
-                  id_user - id of the user to be authorized in the database
-                            
+
+                  req - could be either one of these three things:
+                        id_user of the current user
+                        user_info dictionary built against the user details
+                        req mod_python request object
+
               name_action - the name of the action
 
                 arguments - dictionary with keyword=value pairs created automatically
                             by python on the extra arguments. these depend on the
                             given action. """
 
    Examples:
 
 >>> # import the functions from module
 >>> # change this to your local settings...
 >>> from invenio.access_control_engine import *
 >>> # authorize user 109 for action WebSearch_search with collection="LHC"
 >>> acc_authorize_action(109, 'cfgwebsearch', collection="LHC")
       (0, "User authorized")
 >>> # authorize user 109 for action WebSearch_search with collection="fail this"
 >>> acc_authorize_action(109, 'cfgwebsearch', collection="fail this")
       (8, "Error (8): Incorrect keyword given for specified action.")
 >>> # authorize user 109 for action BibFormat_modify with format="htmlbrief"
 >>> acc_authorize_action(109, 'cfgbibformat', format="htmlbrief")
       (0, "User authorized")
+>>> # authorize user foo.bar@cern.ch for action BibFormat_modify with format="htmlbrief"
+>>> acc_authorize_action({'uid':109, 'email':'foo.bar@cern.ch'}, 'cfgbibformat', format="htmlbrief")
+    (0, "User authorized")
 
 2. Command Line Interface
 
    Description:
 
       The Command Line Interface uses the regular API of acc_authorize_action.
-      
+
    Signature:
 
       authaction id_user name_action keyword1 value1 keyword2 value2 ...
           """ See description from function acc_authorize_action.
                   id_user - id of user to be authorized
- 
+
 	      name_action - name of the action
- 
+
 	         keyword1 - first keyword like in the keyword=value pairs,
                             same rules for the following ones.
 			    always one word.
- 
+
 	           value1 - value that belongs in a pair with the corresponding keyword,
                             same rules for the following ones.
 			    add quotes if it is more that one word.
- 
+
               the keyword=value pairs are collected in a dictionary
           """
-   
+
    Examples:
 
       These are the same ones as for the regular API:
       $ authaction 109 cfgwebsearch collection LHC
         0 - User authorized
       $ authaction 109 cfgwebsearch collection 'fail this'
         8 - Error (8): Incorrect keyword given for specified action.
       $ authaction 109 cfgbibformat format htmlbrief
         0 - User authorized
 
 
 3. Program Flow
 
    this is a quick explanation of the different tasks
    performed by the authorization engine.
-   
+
    I. find information for the action
-     use admin API to find info. 
-   
+     use admin API to find info.
+
    II. see if user is a superadmin
      query the database for connection between user and role superadmin.
      -> authorize if yes
-   
+
    III. check if the user exists and find all of the users roles and create string with the ids
      query the database and build string of ids
      -> don't authorize if no roles
-   
+
    IV. try to authorize without arguments
      action without arguments: query database
      -> authorize if yes
      action with optional arguments
      -> authorize if yes
-   
+
    V. create list of keyword=value pairs to query the database
      run through dictionary and create string for adding to database query
-   
+
    VI. find all table entries from the database
      query the database for table entries
      create list of the tuples and sort it
      -> don't authorize if no entries
      -> authorize if only 1 argument and result
-   
+
    VII. combine entries and try to satisfy authorization
      dictionary with the arguments as keys, all values 0
      run throught the list created in VI
        if moving on to new authorization
          check dictionary values
          -> authorize if combination found
          reset values to 0 if not found
        set dictionary[keyword] to 1.
        (countinue loop)
 
    VIII. all the above failed
-     -> authorization failed   
+     -> authorization failed
 
 4. External login methods
 
    If you want to call defined external loginmethods, it can be done by:
-   
+
    import invenio.external_authentication
    example_method = invenio.external_authentication.example()
    example_method.auth_user("testuser", "testpassword")
 
    Example is here a class used as an example, which must contain the method
    auth_user.
 
diff --git a/modules/webaccess/doc/hacking/table-structure.html.wml b/modules/webaccess/doc/hacking/table-structure.html.wml index 36b048209..0e2f21cff 100644 --- a/modules/webaccess/doc/hacking/table-structure.html.wml +++ b/modules/webaccess/doc/hacking/table-structure.html.wml @@ -1,105 +1,109 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. #include "cdspage.wml" \ title="WebAccess Table Structure" \ navbar_name="hacking-webaccess" \ navtrail_previous_links="/hacking/>Hacking CDS Invenio > /hacking/webaccess/index.html>WebAccess Internals " \ - navbar_select="hacking-webaccess-tabfill" + navbar_select="hacking-webaccess-tabfill"

Version <: print generate_pretty_revision_date_string('$Id$'); :>

 Explanation of the WebAccess table structure and how to create authorizations.
 
--- accROLE -- 
+-- accROLE --
 
 roles are collections of authorizations within specified areas. these should
 have a clear connection, for example within a module or for a special type of
 person, e.g a library administator.
 
-         id - specify the id of the role
+            id - specify the id of the role
 
-       name - unique name for the role
+          name - unique name for the role
 
-description - describe the authorization tasks the role will cover
+   description - describe the authorization tasks the role will cover
 
+    definition - precompiled serialized firewall like role definition (firerole)
 
--- user_accROLE -- 
+definition_src - definition text source for repairing after Python upgrades
+
+
+-- user_accROLE --
 
 give users access to the authorizations/actions provided by the given role.
 
    id_user - id of user in the database, usually just the supportemail and/or adminemail
 
 id_accROLE - id of role from accROLE
 
 
--- accACTION -- 
+-- accACTION --
 
 the actions specify what information is needed to create an authorization.
 an action can take any number of arguments, and you also have the possibility to
 make these arguments optional.
 
              id - specify the id of the action
 
            name - unique name for the action
 
     description - describe authorization area
 
 allowedkeywords - the keywords for the wanted arguments
 
        optional - enum to define wether arguments can be optional
                   value: ['yes', 'no']
 
                   'no'  - action without arguments or not optional arguments
                   'yes' - only actions with arguments
-           
 
--- accARGUMENT -- 
 
-arguments for the authorizations. one entry might be shared by several authorizations, 
+-- accARGUMENT --
+
+arguments for the authorizations. one entry might be shared by several authorizations,
 so it is important to not change these but simply add new ones when a change is needed.
 
      id - id of the argument
 
 keyword - the one listed in an action's allowedkeywords
 
   value - the value connected to the keyword in an keyword=value argument pair
 
 
--- accROLE_accACTION_accARGUMENT -- 
+-- accROLE_accACTION_accARGUMENT --
 
-ternary connection to create authorizations. when an authorization has more than 
-one argument they need to be connected somehow. the same id for role, action and 
+ternary connection to create authorizations. when an authorization has more than
+one argument they need to be connected somehow. the same id for role, action and
 argumentlist does this. there must be at least as many entries as allowedkeywords
 for the action. with more entries all authorizations are found using a cross product.
 
 id_accARGUMENT and argumentlistid are both set to 0 when the action have no arguments.
 with optional arguments they are both set to -1.
 
     id_accROLE - reference to argument in table accROLE
 
   id_accACTION - reference to argument in table accACTION
 
 id_accARGUMENT - reference to argument in table accARGUMENT
 
-argumentlistid - glue to bind entries into authorizations. 
+argumentlistid - glue to bind entries into authorizations.
 
 
 
diff --git a/modules/webaccess/lib/Makefile.am b/modules/webaccess/lib/Makefile.am index e33a9cbf6..4a5679499 100644 --- a/modules/webaccess/lib/Makefile.am +++ b/modules/webaccess/lib/Makefile.am @@ -1,36 +1,37 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. pylibdir = $(libdir)/python/invenio pylib_DATA = access_control_engine.py \ access_control_config.py \ access_control_admin.py \ + access_control_firerole.py \ + access_control_firerole_tests.py \ webaccessadmin_lib.py \ external_authentication_cern.py \ external_authentication.py \ external_authentication_cern_wrapper.py \ external_authentication_cern_tests.py \ external_authentication_sso.py \ - firewall.py \ webaccess_regression_tests.py EXTRA_DIST = $(pylib_DATA) CLEANFILES = *~ *.tmp *.pyc diff --git a/modules/webaccess/lib/access_control_admin.py b/modules/webaccess/lib/access_control_admin.py index ee4231eb9..1ec27540a 100644 --- a/modules/webaccess/lib/access_control_admin.py +++ b/modules/webaccess/lib/access_control_admin.py @@ -1,1588 +1,1623 @@ # $Id$ ## CDS Invenio Access Control Engine in mod_python. ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio Access Control Admin.""" __revision__ = "$Id$" # check this: def acc_addUserRole(id_user, id_role=0, name_role=0): ## import interesting modules: import sys import time from invenio.config import \ supportemail, \ version from invenio.access_control_config import * -from invenio.access_control_engine import acc_authorize_action from invenio.dbquery import run_sql, ProgrammingError +from invenio.access_control_firerole import compile_role_definition, acc_firerole_check_user, deserialize +from sets import Set # ACTIONS def acc_addAction(name_action='', description='', optional='no', *allowedkeywords): """function to create new entry in accACTION for an action - + name_action - name of the new action, must be unique - - keyvalstr - string with allowed keywords + + keyvalstr - string with allowed keywords allowedkeywords - a list of allowedkeywords - + keyvalstr and allowedkeywordsdict can not be in use simultanously - + success -> return id_action, name_action, description and allowedkeywords failure -> return 0 """ keystr = '' # action with this name all ready exists, return 0 if run_sql("""SELECT * FROM accACTION WHERE name = '%s'""" % (name_action, )): return 0 # create keyword string for value in allowedkeywords: if keystr: keystr += ',' keystr += value if not allowedkeywords: optional = 'no' - + # insert the new entry try: res = run_sql("""INSERT INTO accACTION (name, description, allowedkeywords, optional) VALUES ('%s', '%s', '%s', '%s')""" % (name_action, description, keystr, optional)) except ProgrammingError: return 0 - + if res: return res, name_action, description, keystr, optional return 0 def acc_deleteAction(id_action=0, name_action=0): """delete action in accACTION according to id, or secondly name. entries in accROLE_accACTION_accARGUMENT will also be removed. id_action - id of action to be deleted, prefered variable name_action - this is used if id_action is not given if the name or id is wrong, the function does nothing """ if id_action and name_action: return 0 # delete the action if run_sql("""DELETE FROM accACTION WHERE id = %s OR name = '%s'""" % (id_action, name_action)): # delete all entries related return 1 + run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accACTION = %s """ % (id_action, )) else: return 0 def acc_verifyAction(name_action='', description='', allowedkeywords='', optional=''): """check if all the values of a given action are the same as those in accACTION in the database. self explanatory parameters. return id if identical, 0 if not. """ id_action = acc_getActionId(name_action=name_action) if not id_action: return 0 res_desc = acc_getActionDescription(id_action=id_action) res_keys = acc_getActionKeywordsString(id_action=id_action) bool_desc = res_desc == description and 1 or 0 bool_keys = res_keys == allowedkeywords and 1 or 0 bool_opti = acc_getActionIsOptional(id_action=id_action) return bool_desc and bool_keys and bool_opti and id_action or 0 def acc_updateAction(id_action=0, name_action='', verbose=0, **update): """try to change the values of given action details. if there is no change nothing is done. some changes require to update other parts of the database. id_action - id of the action to change name_action - if no id_action is given try to find it using this name **update - dictionary containg keywords: description, allowedkeywords and/or optional other keywords are ignored """ - + id_action = id_action or acc_getActionId(name_action=name_action) if not id_action: return 0 - try: + try: if update.has_key('description'): # change the description, no other effects if verbose: print 'desc' run_sql("""UPDATE accACTION SET description = '%s' WHERE id = %s""" % (update['description'], id_action)) - + if update.has_key('allowedkeywords'): # change allowedkeywords if verbose: print 'keys' # check if changing allowedkeywords or not if run_sql("""SELECT * FROM accACTION WHERE id = %s AND allowedkeywords != '%s' """ % (id_action, update['allowedkeywords'])): # change allowedkeywords if verbose: print ' changing' run_sql("""UPDATE accACTION SET allowedkeywords = '%s' WHERE id = %s""" % (update['allowedkeywords'], id_action)) # delete entries, but keep optional authorizations if there still is keywords if verbose: print ' deleting auths' run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accACTION = %s %s """ % (id_action, update['allowedkeywords'] and 'AND id_accARGUMENT != -1' or '')) - + if update.has_key('optional'): # check if there changing optional or not if verbose: print 'optional' if run_sql("""SELECT * FROM accACTION WHERE id = %s AND optional != '%s' """ % (id_action, update['optional'])): # change optional if verbose: print ' changing' run_sql("""UPDATE accACTION SET optional = '%s' WHERE id = %s""" % (update['optional'], id_action)) # setting it to no, delete authorizations with optional arguments if update['optional'] == 'no': if verbose: print ' deleting optional' run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accACTION = %s AND id_accARGUMENT = -1 AND argumentlistid = -1 """ % (id_action, )) - + except ProgrammingError: return 0 return 1 - + # ROLES -def acc_addRole(name_role, description): +def acc_addRole(name_role, description, firerole_def_ser, firerole_def_src): """add a new role to accROLE in the database. - name_role - name of the role, must be unique + name_role - name of the role, must be unique - description - text to describe the role""" + description - text to describe the role + + firerole_def_ser - compiled firerole like definition + + firerole_def_src - firerole like definition sources + """ if not run_sql("""SELECT * FROM accROLE WHERE name = '%s'""" % (name_role, )): - res = run_sql("""INSERT INTO accROLE (name, description) VALUES ('%s', '%s') """ % (name_role, description)) - return res, name_role, description + res = run_sql("""INSERT INTO accROLE (name, description, firerole_def_ser, firerole_def_src) VALUES (%s, %s, %s, %s)""", (name_role, description, firerole_def_ser, firerole_def_src)) + return res, name_role, description, firerole_def_src return 0 def acc_isRole(name_action,**arguments): """ check whether the role which allows action name_action on arguments exists - + action_name - name of the action - + arguments - arguments for authorization""" - + # first check if an action exists with this name query1 = """select a.id, a.allowedkeywords, a.optional from accACTION a where a.name = '%s'""" % (name_action) try: id_action, aallowedkeywords, optional = run_sql(query1)[0] except (ProgrammingError, IndexError): return 0 defkeys = aallowedkeywords.split(',') for key in arguments.keys(): if key not in defkeys: return 0 - + # then check if a role giving this authorization exists # create dictionary with default values and replace entries from input arguments defdict = {} for key in defkeys: try: defdict[key] = arguments[key] except KeyError: return 0 # all keywords must be present # except KeyError: defdict[key] = 'x' # default value, this is not in use... # create or-string from arguments str_args = '' for key in defkeys: if str_args: str_args += ' OR ' str_args += """(arg.keyword = '%s' AND arg.value = '%s')""" % (key, defdict[key]) query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid, raa.id_accARGUMENT, arg.keyword, arg.value FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT arg WHERE raa.id_accACTION = %s AND (%s) AND - raa.id_accARGUMENT = arg.id """ % (id_action, str_args) + raa.id_accARGUMENT = arg.id """ % (id_action, str_args) try: res4 = run_sql(query4) except ProgrammingError: return 0 - + if not res4: return 0 # no entries at all res5 = [] for res in res4: res5.append(res) res5.sort() if len(defdict) == 1: return 1 cur_role = cur_action = cur_arglistid = 0 - + booldict = {} for key in defkeys: booldict[key] = 0 # run through the results for (role, action, arglistid, arg, keyword, val) in res5 + [(-1, -1, -1, -1, -1, -1)]: # not the same role or argumentlist (authorization group), i.e. check if thing are satisfied # if cur_arglistid != arglistid or cur_role != role or cur_action != action: if (cur_arglistid, cur_role, cur_action) != (arglistid, role, action): # test if all keywords are satisfied for value in booldict.values(): if not value: break else: return 1 # USER AUTHENTICATED TO PERFORM ACTION # assign the values for the current tuple from the query cur_arglistid, cur_role, cur_action = arglistid, role, action for key in booldict.keys(): booldict[key] = 0 # set keyword qualified for the action, (whatever result of the test) booldict[keyword] = 1 # matching failed return 0 - + def acc_deleteRole(id_role=0, name_role=0): """ delete role entry in table accROLE and all references from other tables. - + id_role - id of role to be deleted, prefered variable - + name_role - this is used if id_role is not given """ count = 0 id_role = id_role or acc_getRoleId(name_role=name_role) # try to delete if run_sql("""DELETE FROM accROLE WHERE id = %s """ % (id_role, )): # delete everything related # authorization entries count += 1 + run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s""" % (id_role, )) # connected users count += run_sql("""DELETE FROM user_accROLE WHERE id_accROLE = %s """ % (id_role, )) # delegated rights over the role rolenames = run_sql("""SELECT name FROM accROLE""") # string of rolenames roles_str = '' for (name, ) in rolenames: roles_str += (roles_str and ',' or '') + '"%s"' % (name, ) # arguments with non existing rolenames not_valid = run_sql("""SELECT ar.id FROM accARGUMENT ar WHERE keyword = 'role' AND value NOT IN (%s)""" % (roles_str, )) if not_valid: nv_str = '' for (id, ) in not_valid: nv_str += (nv_str and ',' or '') + '%s' % (id, ) # delete entries count += run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accACTION = %s AND id_accARGUMENT IN (%s) """ % (acc_getActionId(name_action=DELEGATEADDUSERROLE), nv_str)) # return number of deletes return count -def acc_updateRole(id_role=0, name_role='', verbose=0, description=''): +def acc_updateRole(id_role=0, name_role='', verbose=0, description='', \ + firerole_def_ser=CFG_ACC_EMPTY_ROLE_DEFINITION_SER, \ + firerole_def_src=CFG_ACC_EMPTY_ROLE_DEFINITION_SRC): """try to change the description. id_role - id of the role to change name_role - use this to find id if not present verbose - extra output - description - new description """ + description - new description + + firerole_def_ser - compiled firerole like definition + + firerole_def_src - firerole like definition + """ id_role = id_role or acc_getRoleId(name_role=name_role) if not id_role: return 0 - return run_sql("""UPDATE accROLE SET description = '%s' - WHERE id = %s AND - description != '%s' """ - % (description, id_role, description)) + return run_sql("""UPDATE accROLE SET description = %s, firerole_def_ser = %s, firerole_def_src = %s + WHERE id = %s""", (description, firerole_def_ser, firerole_def_src, id_role)) # CONNECTIONS BETWEEN USER AND ROLE def acc_addUserRole(id_user=0, id_role=0, email='', name_role=''): """ this function adds a new entry to table user_accROLE and returns it id_user, id_role - self explanatory email - email of the user name_role - name of the role, to be used instead of id. """ id_user = id_user or acc_getUserId(email=email) id_role = id_role or acc_getRoleId(name_role=name_role) # check if the id_role exists if id_role and not acc_getRoleName(id_role=id_role): return 0 - + # check that the user actually exist if not acc_getUserEmail(id_user=id_user): return 0 # control if existing entry if run_sql("""SELECT * FROM user_accROLE WHERE id_user = %s AND id_accROLE = %s""" % (id_user, id_role)): return id_user, id_role, 0 else: run_sql("""INSERT INTO user_accROLE (id_user, id_accROLE) VALUES (%s, %s) """ % (id_user, id_role)) return id_user, id_role, 1 def acc_deleteUserRole(id_user, id_role=0, name_role=0): """ function deletes entry from user_accROLE and reports the success. - + id_user - user in database id_role - role in the database, prefered parameter name_role - can also delete role on background of role name. """ # need to find id of the role id_role = id_role or acc_getRoleId(name_role=name_role) - + # number of deleted entries will be returned (0 or 1) return run_sql("""DELETE FROM user_accROLE WHERE id_user = %s AND id_accROLE = %s """ % (id_user, id_role)) # ARGUMENTS def acc_addArgument(keyword='', value=''): """ function to insert an argument into table accARGUMENT. if it exists the old id is returned, if it does not the entry is created and the new id is returned. keyword - inserted in keyword column value - inserted in value column. """ - + # if one of the values are missing, return 0 if not keyword or not value: return 0 # try to return id of existing argument try: return run_sql("""SELECT id from accARGUMENT where keyword = '%s' and value = '%s'""" % (keyword, value))[0][0] # return id of newly added argument except IndexError: return run_sql("""INSERT INTO accARGUMENT (keyword, value) values ('%s', '%s') """ % (keyword, value)) def acc_deleteArgument(id_argument): """ functions deletes one entry in table accARGUMENT. the success of the operation is returned. id_argument - id of the argument to be deleted""" # return number of deleted entries, 1 or 0 return run_sql("""DELETE FROM accARGUMENT WHERE id = %s """ % (id_argument, )) def acc_deleteArgument_names(keyword='', value=''): """delete argument according to keyword and value, send call to another function...""" # one of the values is missing if not keyword or not value: return 0 # find id of the entry try: return run_sql("""SELECT id from accARGUMENT where keyword = '%s' and value = '%s'""" % (keyword, value))[0][0] except IndexError: return 0 # AUTHORIZATIONS # ADD WITH names and keyval list -def acc_addAuthorization(name_role='', name_action='', optional=0, **keyval): +def acc_addAuthorization(name_role='', name_action='', optional=0, **keyval): """ function inserts entries in accROLE_accACTION_accARGUMENT if all references are valid. this function is made specially for the webaccessadmin web interface. - always inserting only one authorization. + always inserting only one authorization. id_role, id_action - self explanatory, preferably used name_role, name_action - self explanatory, used if id not given optional - if this is set to 1, check that function can have optional - arguments and add with arglistid -1 and id_argument -1 - + arguments and add with arglistid -1 and id_argument -1 + **keyval - dictionary of keyword=value pairs, used to find ids. """ - + inserted = [] # check that role and action exist id_role = run_sql("""SELECT id FROM accROLE where name = '%s'""" % (name_role, )) action_details = run_sql("""SELECT * from accACTION where name = '%s' """ % (name_action, )) if not id_role or not action_details: return [] # get role id and action id and details id_role, id_action = id_role[0][0], action_details[0][0] allowedkeywords_str = action_details[0][3] allowedkeywords_lst = acc_getActionKeywords(id_action=id_action) optional_action = action_details[0][4] == 'yes' and 1 or 0 optional = int(optional) # this action does not take arguments if not optional and not keyval: # can not add if user is doing a mistake if allowedkeywords_str: return [] # check if entry exists if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND argumentlistid = %s AND id_accARGUMENT = %s""" % (id_role, id_action, 0, 0)): # insert new authorization run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values (%s, %s, %s, %s)""" % (id_role, id_action, 0, 0)) return [[id_role, id_action, 0, 0], ] return [] # try to add authorization without the optional arguments elif optional: # optional not allowed for this action if not optional_action: return [] # check if authorization already exists if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = -1 AND argumentlistid = -1""" % (id_role, id_action, )): # insert new authorization run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid) VALUES (%s, %s, -1, -1) """ % (id_role, id_action)) return [[id_role, id_action, -1, -1], ] - return [] + return [] else: # regular authorization - + # get list of ids, if they don't exist, create arguments id_arguments = [] argstr = '' for key in keyval.keys(): if key not in allowedkeywords_lst: return [] id_argument = (acc_getArgumentId(key, keyval[key]) or run_sql("""INSERT INTO accARGUMENT (keyword, value) values ('%s', '%s') """ % (key, keyval[key]))) id_arguments.append(id_argument) argstr += (argstr and ',' or '') + str(id_argument) - + # check if equal authorization exists for (id_trav, ) in run_sql("""SELECT DISTINCT argumentlistid FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' """% (id_role, id_action)): listlength = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND id_accARGUMENT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0] notlist = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND id_accARGUMENT NOT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0] # this means that a duplicate already exists if not notlist and listlength == len(id_arguments): return [] - + # find new arglistid, highest + 1 try: arglistid = 1 + run_sql("""SELECT MAX(argumentlistid) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s """ % (id_role, id_action))[0][0] except (IndexError, TypeError): arglistid = 1 if arglistid <= 0: arglistid = 1 - + # insert for id_argument in id_arguments: run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values (%s, %s, %s, %s) """ % (id_role, id_action, id_argument, arglistid)) inserted.append([id_role, id_action, id_argument, arglistid]) - + return inserted -def acc_addRoleActionArguments(id_role=0, id_action=0, arglistid=-1, optional=0, verbose=0, id_arguments=[]): +def acc_addRoleActionArguments(id_role=0, id_action=0, arglistid=-1, optional=0, verbose=0, id_arguments=[]): """ function inserts entries in accROLE_accACTION_accARGUMENT if all references are valid. id_role, id_action - self explanatory - + arglistid - argumentlistid for the inserted entries if -1: create new group other values: add to this group, if it exists or not optional - if this is set to 1, check that function can have optional arguments and add with arglistid -1 and - id_argument -1 - + id_argument -1 + verbose - extra output id_arguments - list of arguments to add to group.""" inserted = [] if verbose: print 'ids: starting' if verbose: print 'ids: checking ids' # check that all the ids are valid and reference something... if not run_sql("""SELECT * FROM accROLE WHERE id = %s""" % (id_role, )): return 0 if verbose: print 'ids: get allowed keywords' # check action exist and get allowed keywords try: allowedkeys = acc_getActionKeywords(id_action=id_action) # allowedkeys = run_sql("""SELECT * FROM accACTION WHERE id = %s""" % (id_action, ))[0][3].split(',') except (IndexError, AttributeError): return 0 if verbose: print 'ids: is it optional' # action with optional arguments if optional: if verbose: print 'ids: yes - optional' if not acc_getActionIsOptional(id_action=id_action): return [] - + if verbose: print 'ids: run query to check if exists' if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = -1 AND argumentlistid = -1""" % (id_role, id_action, )): if verbose: print 'ids: does not exist' run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid) VALUES (%s, %s, -1, -1) """ % (id_role, id_action)) return ((id_role, id_action, -1, -1), ) if verbose: print 'ids: exists' - return [] + return [] if verbose: print 'ids: check if not arguments' # action without arguments if not allowedkeys: if verbose: print 'ids: not arguments' if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND argumentlistid = %s AND id_accARGUMENT = %s""" % (id_role, id_action, 0, 0)): if verbose: print 'ids: try to insert' result = run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values (%s, %s, %s, %s)""" % (id_role, id_action, 0, 0)) return ((id_role, id_action, 0, 0), ) else: if verbose: print 'ids: already existed' return 0 else: if verbose: print 'ids: arguments exist' argstr = '' # check that the argument exists, and that it is a valid key if verbose: print 'ids: checking all the arguments' for id_argument in id_arguments: res_arg = run_sql("""SELECT * FROM accARGUMENT WHERE id = %s""" % (id_argument, )) if not res_arg or res_arg[0][1] not in allowedkeys: return 0 else: if argstr: argstr += ',' argstr += '%s' % (id_argument, ) # arglistid = -1 means that the user wants a new group if verbose: print 'ids: find arglistid' if arglistid < 0: # check if such single group already exists for (id_trav, ) in run_sql("""SELECT DISTINCT argumentlistid FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' """ % (id_role, id_action)): listlength = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND id_accARGUMENT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0] notlist = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND id_accARGUMENT NOT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0] # this means that a duplicate already exists if not notlist and listlength == len(id_arguments): return 0 # find new arglistid try: arglistid = run_sql("""SELECT MAX(argumentlistid) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s """ % (id_role, id_action))[0][0] + 1 except ProgrammingError: return 0 except (IndexError, TypeError): arglistid = 1 - + if arglistid <= 0: arglistid = 1 - + if verbose: print 'ids: insert all the entries' # all references are valid, insert: one entry in raa for each argument for id_argument in id_arguments: if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = %s AND argumentlistid = %s""" % (id_role, id_action, id_argument, arglistid)): run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid) VALUES (%s, %s, %s, %s) """ % (id_role, id_action, id_argument, arglistid)) - inserted.append((id_role, id_action, id_argument, arglistid)) + inserted.append((id_role, id_action, id_argument, arglistid)) # [(r, ac, ar1, aid), (r, ac, ar2, aid)] - if verbose: + if verbose: print 'ids: inside add function' for r in acc_findPossibleActions(id_role=id_role, id_action=id_action): print 'ids: ', r - + return inserted def acc_addRoleActionArguments_names(name_role='', name_action='', arglistid=-1, optional=0, verbose=0, **keyval): """ this function makes it possible to pass names when creating new entries instead of ids. get ids for all the names, create entries in accARGUMENT that does not exist, pass on to id based function. name_role, name_action - self explanatory arglistid - add entries to or create group with arglistid, default -1 create new. optional - create entry with optional keywords, **keyval is ignored, but should be empty verbose - used to print extra information **keyval - dictionary of keyword=value pairs, used to find ids. """ - + if verbose: print 'names: starting' if verbose: print 'names: checking ids' # find id of the role, return 0 if it doesn't exist id_role = run_sql("""SELECT id FROM accROLE where name = '%s'""" % (name_role, )) if id_role: id_role = id_role[0][0] else: return 0 # find id of the action, return 0 if it doesn't exist res = run_sql("""SELECT * from accACTION where name = '%s'""" % (name_action, )) if res: id_action = res[0][0] else: return 0 if verbose: print 'names: checking arguments' - + id_arguments = [] if not optional: if verbose: print 'names: not optional' # place to keep ids of arguments and list of allowed keywords allowedkeys = acc_getActionKeywords(id_action=id_action) # res[0][3].split(',') - + # find all the id_arguments and create those that does not exist for key in keyval.keys(): # this key does not exist if key not in allowedkeys: return 0 - + id_argument = acc_getArgumentId(key, keyval[key]) id_argument = id_argument or run_sql("""INSERT INTO accARGUMENT (keyword, value) values ('%s', '%s') """ % (key, keyval[key])) - + id_arguments.append(id_argument) # append the id to the list else: if verbose: print 'names: optional' # use the other function return acc_addRoleActionArguments(id_role=id_role, id_action=id_action, arglistid=arglistid, optional=optional, verbose=verbose, id_arguments=id_arguments) # DELETE WITH ID OR NAMES def acc_deleteRoleActionArguments(id_role, id_action, arglistid=1, auths=[[]]): """delete all entries in accROLE_accACTION_accARGUMENT that satisfy the parameters. return number of actual deletes. this function relies on the id-lists in auths to have the same order has the possible actions... - + id_role, id_action - self explanatory arglistid - group to delete from. if more entries than deletes, split the group before delete. id_arguments - list of ids to delete.""" - + keepauths = [] # these will be kept # find all possible actions pas = acc_findPossibleActions_ids(id_role, id_action) header = pas[0] # decide which to keep or throw away - + for pa in pas[1:]: if pa[0] == arglistid and pa[1:] not in auths: keepauths.append(pa[1:]) # delete everything run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND argumentlistid = %s """ % (id_role, id_action, arglistid)) - + # insert those to be kept for auth in keepauths: acc_addRoleActionArguments(id_role=id_role, id_action=id_action, arglistid=-1, id_arguments=auth) - + return 1 def acc_deleteRoleActionArguments_names(name_role='', name_action='', arglistid=1, **keyval): """utilize the function on ids by first finding all ids and redirecting the function call. break of and return 0 if any of the ids can't be found. name_role = name of the role name_action - name of the action arglistid - the argumentlistid, all keyword=value pairs must be in this same group. **keyval - dictionary of keyword=value pairs for the arguments.""" - + # find ids for role and action id_role = acc_getRoleId(name_role=name_role) id_action = acc_getActionId(name_action=name_action) # create string with the ids idstr = '' idlist = [] for key in keyval.keys(): id = acc_getArgumentId(key, keyval[key]) if not id: return 0 if idstr: idstr += ',' idstr += '%s' % id idlist.append(id) # control that a fitting group exists try: count = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND argumentlistid = %s AND id_accARGUMENT IN (%s)""" % (id_role, id_action, arglistid, idstr))[0][0] except IndexError: return 0 if count < len(keyval): return 0 # call id based function return acc_deleteRoleActionArguments(id_role, id_action, arglistid, [idlist]) def acc_deleteRoleActionArguments_group(id_role=0, id_action=0, arglistid=0): """delete entire group of arguments for connection between role and action.""" if not id_role or not id_action: return [] return run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND argumentlistid = %s """ % (id_role, id_action, arglistid)) def acc_deletePossibleActions(id_role=0, id_action=0, authids=[]): """delete authorizations in selected rows. utilization of the delete function. id_role - id of role to be connected to action. id_action - id of action to be connected to role authids - list of row indexes to be removed. """ - + # find all authorizations pas = acc_findPossibleActions(id_role=id_role, id_action=id_action) - + # get the keys keys = pas[0][1:] - + # create dictionary for all the argumentlistids ald = {} for authid in authids: if authid > len(pas): return authid, len(pas) - + # get info from possible action - id = pas[authid][0] + id = pas[authid][0] values = pas[authid][1:] # create list of authids for each authorization auth = [acc_getArgumentId(keys[0], values[0])] for i in range(1, len(keys)): auth.append(acc_getArgumentId(keys[i], values[i])) - + # create entries in the dictionary for each argumentlistid try: ald[id].append(auth) except KeyError: ald[id] = [auth] # do the deletes result = 1 for key in ald.keys(): result = 1 and acc_deleteRoleActionArguments(id_role=id_role, id_action=id_action, arglistid=key, auths=ald[key]) return result def acc_deleteRoleAction(id_role=0, id_action=0): """delete all connections between a role and an action. """ - + count = run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' """ % (id_role, id_action)) - + return count # GET FUNCTIONS # ACTION RELATED def acc_getActionId(name_action): """get id of action when name is given name_action - name of the wanted action""" - + try: return run_sql("""SELECT id FROM accACTION WHERE name = '%s'""" % (name_action, ))[0][0] except IndexError: return 0 def acc_getActionName(id_action): """get name of action when id is given. """ - + try: return run_sql("""SELECT name FROM accACTION WHERE id = %s""" % (id_action, ))[0][0] except (ProgrammingError, IndexError): return '' def acc_getActionDescription(id_action): """get description of action when id is given. """ - + try: return run_sql("""SELECT description FROM accACTION WHERE id = %s""" % (id_action, ))[0][0] except (ProgrammingError, IndexError): return '' def acc_getActionKeywords(id_action=0, name_action=''): """get list of keywords for action when id is given. empty list if no keywords.""" - + result = acc_getActionKeywordsString(id_action=id_action, name_action=name_action) - + if result: return result.split(',') else: return [] - + def acc_getActionKeywordsString(id_action=0, name_action=''): """get keywordstring when id is given. """ - + id_action = id_action or acc_getActionId(name_action) try: result = run_sql("""SELECT allowedkeywords from accACTION where id = %s """ % (id_action, ))[0][0] except IndexError: return '' - + return result def acc_getActionIsOptional(id_action=0): """get if the action arguments are optional or not. return 1 if yes, 0 if no.""" - + result = acc_getActionOptional(id_action=id_action) return result == 'yes' and 1 or 0 def acc_getActionOptional(id_action=0): """get if the action arguments are optional or not. return result, but 0 if action does not exist. """ - + try: result = run_sql("""SELECT optional from accACTION where id = %s """ % (id_action, ))[0][0] except IndexError: return 0 - + return result def acc_getActionDetails(id_action=0): """get all the fields for an action.""" - + details = [] try: result = run_sql("""SELECT * FROM accACTION WHERE id = %s """ % (id_action, ))[0] except IndexError: return details - + if result: for r in result: details.append(r) return details - + def acc_getAllActions(): """returns all entries in accACTION.""" return run_sql("""SELECT a.id, a.name, a.description FROM accACTION a ORDER BY a.name""") def acc_getActionRoles(id_action): return run_sql("""SELECT DISTINCT(r.id), r.name, r.description FROM accROLE_accACTION_accARGUMENT raa LEFT JOIN accROLE r ON raa.id_accROLE = r.id WHERE raa.id_accACTION = %s ORDER BY r.name """ % (id_action, )) # ROLE RELATED def acc_getRoleId(name_role): """get id of role, name given. """ try: return run_sql("""SELECT id FROM accROLE WHERE name = %s""", (name_role, ))[0][0] except IndexError: return 0 def acc_getRoleName(id_role): """get name of role, id given. """ - + try: return run_sql("""SELECT name FROM accROLE WHERE id = %s""", (id_role, ))[0][0] except IndexError: return '' +def acc_getRoleDefinition(id_role=0): + """get definition object for a role.""" + + try: return run_sql("""SELECT firerole_def_ser FROM accROLE WHERE id = %s""", (id_role, ))[0][0] + except IndexError: return '' + def acc_getRoleDetails(id_role=0): """get all the fields for an action.""" - + details = [] - try: result = run_sql("""SELECT * FROM accROLE WHERE id = %s """, (id_role, ))[0] + try: result = run_sql("""SELECT id, name, description, firerole_def_src FROM accROLE WHERE id = %s """, (id_role, ))[0] except IndexError: return details - + if result: for r in result: details.append(r) return details - + def acc_getAllRoles(): """get all entries in accROLE.""" - - return run_sql("""SELECT r.id, r.name, r.description FROM accROLE r ORDER BY r.name""") + + return run_sql("""SELECT r.id, r.name, r.description, r.firerole_def_ser, r.firerole_def_src FROM accROLE r ORDER BY r.name""") def acc_getRoleActions(id_role): """get all actions connected to a role. """ - + return run_sql("""SELECT DISTINCT(a.id), a.name, a.description FROM accROLE_accACTION_accARGUMENT raa, accACTION a WHERE raa.id_accROLE = %s and raa.id_accACTION = a.id ORDER BY a.name """, (id_role, )) def acc_getRoleUsers(id_role): """get all users that have access to a role. """ - + return run_sql("""SELECT DISTINCT(u.id), u.email, u.settings FROM user_accROLE ur, user u WHERE ur.id_accROLE = %s AND u.id = ur.id_user ORDER BY u.email""", (id_role, )) # ARGUMENT RELATED def acc_getArgumentId(keyword, value): """get id of argument, keyword=value pair given. value = 'optional value' is replaced for id_accARGUMENT = -1.""" - + try: return run_sql("""SELECT DISTINCT id FROM accARGUMENT WHERE keyword = %s and value = %s""", (keyword, value))[0][0] except IndexError: if value == 'optional value': return -1 return 0 # USER RELATED def acc_getUserEmail(id_user=0): """get email of user, id given.""" - + try: return run_sql("""SELECT email FROM user WHERE id = %s """, (id_user, ))[0][0] except IndexError: return '' - + def acc_getUserId(email=''): """get id of user, email given.""" - + try: return run_sql("""SELECT id FROM user WHERE email = %s """, (email, ))[0][0] except IndexError: return 0 - + def acc_getUserRoles(id_user=0): """get all roles a user is connected to.""" - + res = run_sql("""SELECT ur.id_accROLE FROM user_accROLE ur WHERE ur.id_user = %s ORDER BY ur.id_accROLE""", (id_user, )) return res def acc_findUserInfoIds(id_user=0): """find all authorization entries for all the roles a user is connected to.""" - + res1 = run_sql("""SELECT ur.id_user, raa.* FROM user_accROLE ur LEFT JOIN accROLE_accACTION_accARGUMENT raa ON ur.id_accROLE = raa.id_accROLE WHERE ur.id_user = %s """, (id_user, )) res2 = [] for res in res1: res2.append(res) res2.sort() return res2 def acc_findUserInfoNames(id_user=0): query = """ SELECT ur.id_user, r.name, ac.name, raa.argumentlistid, ar.keyword, ar.value FROM accROLE_accACTION_accARGUMENT raa, user_accROLE ur, accROLE r, accACTION ac, accARGUMENT ar WHERE ur.id_user = %s and ur.id_accROLE = raa.id_accROLE and raa.id_accROLE = r.id and raa.id_accACTION = ac.id and raa.id_accARGUMENT = ar.id """ % (id_user, ) - + res1 = run_sql(query) - + res2 = [] for res in res1: res2.append(res) res2.sort() - + return res2 def acc_findUserRoleActions(id_user=0): """find name of all roles and actions connected to user, id given.""" - + query = """SELECT DISTINCT r.name, a.name FROM user_accROLE ur, accROLE_accACTION_accARGUMENT raa, accACTION a, accROLE r WHERE ur.id_user = %s and ur.id_accROLE = raa.id_accROLE and raa.id_accACTION = a.id and raa.id_accROLE = r.id """ % (id_user, ) - + res1 = run_sql(query) - + res2 = [] for res in res1: res2.append(res) res2.sort() - + return res2 +def acc_findUserRoleActions_user_info(user_info): + """find name of all roles and actions connected to user_info, id given.""" + query = """SELECT DISTINCT r.name, a.name, r.firerole_def_ser + FROM accROLE_accACTION_accARGUMENT raa, accACTION a, accROLE r + WHERE raa.id_accACTION = a.id and + raa.id_accROLE = r.id """ + + res1 = run_sql(query) + res2 = [] + for role_name, action_name, role_definition in res1: + if acc_firerole_check_user(user_info, deserialize(role_definition)): + res2.append((role_name, action_name)) + + # Collect also traditional explicit id_user authorization + res3 = acc_findUserRoleActions(user_info['uid']) + + return list(Set(res2) or Set(res3)) + # POSSIBLE ACTIONS / AUTHORIZATIONS def acc_findPossibleActionsAll(id_role): """find all the possible actions for a role. the function utilizes acc_findPossibleActions to find all the entries from each of the actions under the given role id_role - role to find all actions for returns a list with headers""" - + query = """SELECT DISTINCT(aar.id_accACTION) FROM accROLE_accACTION_accARGUMENT aar WHERE aar.id_accROLE = %s ORDER BY aar.id_accACTION""" % (id_role, ) res = [] for (id_action, ) in run_sql(query): hlp = acc_findPossibleActions(id_role, id_action) if hlp: res.append(['role', 'action'] + hlp[0]) for row in hlp[1:]: res.append([id_role, id_action] + row) return res def acc_findPossibleActionsArgumentlistid(id_role, id_action, arglistid): """find all possible actions with the given arglistid only.""" - + # get all, independent of argumentlistid res1 = acc_findPossibleActions_ids(id_role, id_action) # create list with only those with the right arglistid res2 = [] for row in res1[1:]: if row[0] == arglistid: res2.append(row) # return this list return res2 def acc_findPossibleActionsUser(id_user, id_action): """user based function to find all action combination for a given user and action. find all the roles and utilize findPossibleActions for all these. id_user - user id, used to find roles id_action - action id. """ - + res = [] - for (id_role, ) in acc_getUserRoles(id_user): + for (id_role, ) in acc_getUserRoles(id_user): hlp = acc_findPossibleActions(id_role, id_action) if hlp and not res: res.append(['role'] + hlp[0]) for row in hlp[1:]: res.append([id_role] + row) - + return res def acc_findPossibleActions_ids(id_role, id_action): """finds the ids of the possible actions. utilization of acc_getArgumentId and acc_findPossibleActions. """ - + pas = acc_findPossibleActions(id_role, id_action) if not pas: return [] keys = pas[0] pas_ids = [pas[0:1]] for pa in pas[1:]: auth = [pa[0]] for i in range(1, len(pa)): auth.append(acc_getArgumentId(keys[i], pa[i])) pas_ids.append(auth) return pas_ids - + def acc_findPossibleActions(id_role, id_action): """Role based function to find all action combinations for a give role and action. - + id_role - id of role in the database id_action - id of the action in the database returns a list with all the combinations. first row is used for header.""" - + # query to find all entries for user and action res1 = run_sql(""" SELECT raa.argumentlistid, ar.keyword, ar.value FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT ar - WHERE raa.id_accROLE = %s and + WHERE raa.id_accROLE = %s and raa.id_accACTION = %s and raa.id_accARGUMENT = ar.id """, (id_role, id_action)) - + # find needed keywords, create header keywords = acc_getActionKeywords(id_action=id_action) keywords.sort() if not keywords: # action without arguments if run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = 0 AND argumentlistid = 0""", (id_role, id_action)): return [['#', 'argument keyword'], ['0', 'action without arguments']] - + # tuples into lists res2, arglistids = [], {} for res in res1: res2.append([]) for r in res: res2[-1].append(r) res2.sort() - + # create multilevel dictionary for res in res2: a, kw, value = res # rolekey, argumentlistid, keyword, value if kw not in keywords: continue if not arglistids.has_key(a): arglistids[a] = {} # fill dictionary if not arglistids[a].has_key(kw): arglistids[a][kw] = [value] elif not value in arglistids[a][kw]: arglistids[a][kw] = arglistids[a][kw] + [value] - + # fill list with all possible combinations res3 = [] # rolekeys = roles2.keys(); rolekeys.sort() for a in arglistids.keys(): # argumentlistids # fill a list with the new entries, shortcut and copying first keyword list next_arglistid = [] for row in arglistids[a][keywords[0]]: next_arglistid.append([a, row[:] ]) # run through the rest of the keywords for kw in keywords[1:]: if not arglistids[a].has_key(kw): arglistids[a][kw] = ['optional value'] - + new_list = arglistids[a][kw][:] new_len = len(new_list) # duplicate the list temp_list = [] for row in next_arglistid: for i in range(new_len): temp_list.append(row[:]) # append new values for i in range(len(temp_list)): new_item = new_list[i % new_len][:] temp_list[i].append( new_item ) next_arglistid = temp_list[:] - + res3.extend(next_arglistid) - + res3.sort() # if optional allowed, put on top opt = run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = -1 AND argumentlistid = -1""" % (id_role, id_action)) if opt: res3.insert(0, [-1] + ['optional value'] * len(keywords)) # put header on top if res3: res3.insert(0, ['#'] + keywords) - + return res3 def acc_splitArgumentGroup(id_role=0, id_action=0, arglistid=0): """collect the arguments, find all combinations, delete original entries and insert the new ones with different argumentlistids for each group - + id_role - id of the role id_action - id of the action arglistid - argumentlistid to be splittetd""" if not id_role or not id_action or not arglistid: return [] # don't split if none or one possible actions res = acc_findPossibleActionsArgumentlistid(id_role, id_action, arglistid) if not res or len(res) <= 1: return 0 # delete the existing group delete = acc_deleteRoleActionArguments_group(id_role, id_action, arglistid) # add all authorizations with new and different argumentlistid addlist = [] for row in res: argids = row[1:] addlist.append(acc_addRoleActionArguments(id_role=id_role, id_action=id_action, arglistid=-1, id_arguments=argids)) # return list of added authorizations return addlist def acc_mergeArgumentGroups(id_role=0, id_action=0, arglistids=[]): """merge the authorizations from groups with different argumentlistids into one single group. this can both save entries in the database and create extra authorizations. id_role - id of the role id_action - role of the action arglistids - list of groups to be merged together into one.""" - + if len(arglistids) < 2: return [] argstr = '' for id in arglistids: argstr += 'raa.argumentlistid = %s or ' % (id, ) argstr = '(%s)' % (argstr[:-4], ) # query to find all entries that will be merged query = """ SELECT ar.keyword, ar.value, raa.id_accARGUMENT FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT ar - WHERE raa.id_accROLE = %s and + WHERE raa.id_accROLE = %s and raa.id_accACTION = %s and %s and raa.id_accARGUMENT = ar.id """ % (id_role, id_action, argstr) q_del = """DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s and id_accACTION = %s and %s """ % (id_role, id_action, argstr.replace('raa.', '')) res = run_sql(query) if not res: return [] run_sql(q_del) # list of entire entries old = [] # list of only the ids ids = [] for (k, v, id) in res: if [k, v, id] not in old: old.append([k, v, id]) ids.append(id) # for (k, v, id) in res: if id not in ids: ids.append(id) return acc_addRoleActionArguments(id_role=id_role, id_action=id_action, arglistid=-1, id_arguments=ids) def acc_reset_default_settings(superusers=[]): """reset to default by deleting everything and adding default. superusers - list of superuser emails """ - + remove = acc_delete_all_settings() add = acc_add_default_settings(superusers=superusers) return remove, add def acc_delete_all_settings(): """simply remove all data affiliated with webaccess by truncating tables accROLE, accACTION, accARGUMENT and those connected. """ - + run_sql("""TRUNCATE accROLE""") run_sql("""TRUNCATE accACTION""") run_sql("""TRUNCATE accARGUMENT""") run_sql("""TRUNCATE user_accROLE""") run_sql("""TRUNCATE accROLE_accACTION_accARGUMENT""") - + return 1 def acc_add_default_settings(superusers=[]): """add the default settings if they don't exist. superusers - list of superuser emails """ # imported from config global supportemail # imported from access_control_config global DEF_ROLES global DEF_USERS global DEF_ACTIONS global DEF_AUTHS - + # from superusers: allow input formats ['email1', 'email2'] and [['email1'], ['email2']] and [['email1', id], ['email2', id]] for user in superusers: if type(user) is str: user = [user] DEF_USERS.append(user[0]) if supportemail not in DEF_USERS: DEF_USERS.append(supportemail) # add data - + # add roles insroles = [] - for (name, description) in DEF_ROLES: + for (name, description, firerole_def_src) in DEF_ROLES: # try to add, don't care if description is different id = acc_addRole(name_role=name, - description=description) + description=description, firerole_def_ser=compile_role_definition(firerole_def_src), firerole_def_src=firerole_def_src) if not id: id = acc_getRoleId(name_role=name) - acc_updateRole(id_role=id, description=description) - insroles.append([id, name, description]) + acc_updateRole(id_role=id, description=description, firerole_def_ser=compile_role_definition(firerole_def_src), firerole_def_src=firerole_def_src) + insroles.append([id, name, description, firerole_def_src]) # add users to superadmin insuserroles = [] for user in DEF_USERS: insuserroles.append(acc_addUserRole(email=user, name_role=SUPERADMINROLE)) # add actions insactions = [] for (name, description, allkeys, optional) in DEF_ACTIONS: # try to add action as new id = acc_addAction(name, description, optional, allkeys) # action with the name exist if not id: id = acc_getActionId(name_action=name) # update the action, necessary updates to the database will also be done acc_updateAction(id_action=id, optional=optional, allowedkeywords=allkeys) # keep track of inserted actions insactions.append([id, name, description, allkeys]) # add authorizations insauths = [] for (name_role, name_action, arglistid, optional, args) in DEF_AUTHS: # add the authorization acc_addRoleActionArguments_names(name_role=name_role, name_action=name_action, arglistid=arglistid, - optional=optional, + optional=optional, **args) # keep track of inserted authorizations insauths.append([name_role, name_action, arglistid, optional, args]) - + return insroles, insactions, insuserroles, insauths def acc_find_delegated_roles(id_role_admin=0): """find all the roles the admin role has delegation rights over. return tuple of all the roles. id_role_admin - id of the admin role """ id_action_delegate = acc_getActionId(name_action=DELEGATEADDUSERROLE) rolenames = run_sql("""SELECT DISTINCT(ar.value) FROM accROLE_accACTION_accARGUMENT raa LEFT JOIN accARGUMENT ar ON raa.id_accARGUMENT = ar.id WHERE raa.id_accROLE = '%s' AND raa.id_accACTION = '%s' """ % (id_role_admin, id_action_delegate)) result = [] for (name_role, ) in rolenames: roledetails = run_sql("""SELECT * FROM accROLE WHERE name = %s """, (name_role, )) if roledetails: result.append(roledetails) return result def acc_cleanupArguments(): """function deletes all accARGUMENTs that are not referenced by accROLE_accACTION_accARGUMENT. returns how many arguments where deleted and a list of the deleted id_arguments""" # find unreferenced arguments ids1 = run_sql("""SELECT DISTINCT ar.id FROM accARGUMENT ar LEFT JOIN accROLE_accACTION_accARGUMENT raa ON ar.id = raa.id_accARGUMENT WHERE raa.id_accARGUMENT IS NULL """) # it is clean if not ids1: return 1 # create list and string of the ids ids2 = [] idstr = '' for (id, ) in ids1: ids2.append(id) if idstr: idstr += ',' idstr += '%s' % id # delete unreferenced arguments count = run_sql("""DELETE FROM accARGUMENT WHERE id in (%s)""" % (idstr, )) - + # return count and ids of deleted arguments return (count, ids2) def acc_cleanupUserRoles(): """remove all entries in user_accROLE referencing non-existing roles. return number of deletes and the ids. FIXME: THIS FUNCTION HAS NOT BEEN TESTED """ # find unreferenced arguments ids1 = run_sql("""SELECT DISTINCT ur.id_accROLE FROM accROLE ur LEFT JOIN accROLE r ON ur.id_accROLE = r.id - WHERE r.id IS NULL""") + WHERE r.id IS NULL""") # it is clean if not ids1: return 1 # create list and string of the ids ids2 = [] idstr = '' for (id, ) in ids1: ids2.append(id) if idstr: idstr += ',' idstr += '%s' % id # delete unreferenced arguments count = run_sql("""DELETE FROM user_accROLE WHERE id_accROLE in (%s)""" % (idstr, )) - + # return count and ids of deleted arguments return (count, ids2) def acc_garbage_collector(verbose=0): """clean the entire database for unused data""" # keep track of all deleted entries del_entries = [] # user_accROLEs without existing role or user count = 0 # roles have been deleted id_roles = run_sql("""SELECT DISTINCT r.id FROM accROLE r""") idrolesstr = '' for (id, ) in id_roles: idrolesstr += (idrolesstr and ',' or '') + '%s' % id - if idrolesstr: + if idrolesstr: count += run_sql("""DELETE FROM user_accROLE WHERE id_accROLE NOT IN (%s)""" % (idrolesstr, )) - # users have been deleted + # users have been deleted id_users = run_sql("""SELECT DISTINCT u.id FROM user u WHERE email != ''""") idusersstr = '' for (id, ) in id_users: idusersstr += (idusersstr and ',' or '') + '%s' % id - if idusersstr: + if idusersstr: count += run_sql("""DELETE FROM user_accROLE WHERE id_user NOT IN (%s) """ % (idusersstr, )) - del_entries.append([count]) + del_entries.append([count]) # accROLE_accACTION_accARGUMENT where role is deleted count = 0 if idrolesstr: count += run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE NOT IN (%s)""" % (idrolesstr, )) # accROLE_accACTION_accARGUMENT where action is deleted id_actions = run_sql("""SELECT DISTINCT a.id FROM accACTION a""") idactionsstr = '' for (id, ) in id_actions: idactionsstr += (idactionsstr and ',' or '') + '%s' % id # FIXME: here was a syntactic bug, so check the code! if idactionsstr: count += run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accACTION NOT IN (%s)""" % (idactionsstr, )) del_entries.append([count]) # delegated roles that does not exist nameroles = run_sql("""SELECT DISTINCT r.name FROM accROLE r""") namestr = '' for (name, ) in nameroles: namestr += (namestr and ',' or '') + '"%s"' % name if namestr: idargs = run_sql("""SELECT ar.id FROM accARGUMENT WHERE keyword = 'role' AND value NOT IN (%s) """ % (namestr, )) idstr = '' for (id, ) in idargs: idstr += (idstr and ',' or '') + '%s' % id - + if namestr and idstr: count = run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accARGUMENT IN (%s) """ % (idstr, )) else: count = 0 - del_entries.append([0]) - + del_entries.append([0]) + # delete unreferenced arguments unused_args = run_sql("""SELECT DISTINCT ar.id FROM accARGUMENT ar LEFT JOIN accROLE_accACTION_accARGUMENT raa ON ar.id = raa.id_accARGUMENT WHERE raa.id_accARGUMENT IS NULL """) args = [] idstr = '' for (id, ) in unused_args: args.append(id) idstr += (idstr and ',' or '') + '%s' % id count = run_sql("""DELETE FROM accARGUMENT WHERE id in (%s)""" % (idstr, )) - + del_entries.append([count, args]) # return statistics return del_entries diff --git a/modules/webaccess/lib/access_control_config.py b/modules/webaccess/lib/access_control_config.py index 1cea5803b..4f4cb3528 100644 --- a/modules/webaccess/lib/access_control_config.py +++ b/modules/webaccess/lib/access_control_config.py @@ -1,166 +1,189 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio Access Control Config. """ __revision__ = \ "$Id$" # pylint: disable-msg=C0301 -#import external_authentication_sso -#import external_authentication_cern -from invenio.config import cdsname, sweburl, supportemail +from invenio.config import cdsname, sweburl, supportemail, CFG_CERN_SITE +import cPickle +from zlib import compress + +class WebAccessFireroleError(Exception): + """Just an Exception to discover if it's a FireRole problem""" + pass # VALUES TO BE EXPORTED # CURRENTLY USED BY THE FILES access_control_engine.py access_control_admin.py webaccessadmin_lib.py # name of the role giving superadmin rights SUPERADMINROLE = 'superadmin' # name of the webaccess webadmin role WEBACCESSADMINROLE = 'webaccessadmin' # name of the action allowing roles to access the web administrator interface WEBACCESSACTION = 'cfgwebaccess' +# name of the action allowing roles to access the web administrator interface +VIEWRESTRCOLL = 'accrestrcoll' + + # name of the action allowing roles to delegate the rights to other roles # ex: libraryadmin to delegate libraryworker DELEGATEADDUSERROLE = 'accdelegaterole' # max number of users to display in the drop down selects MAXSELECTUSERS = 25 # max number of users to display in a page (mainly for user area) MAXPAGEUSERS = 25 -# Default behaviour when a definition is parsed to the end without having decided -# if the user should belong to it or not -CFG_FIREWALL_DEFAULT_ALLOW = True +""" Serialized compiled default role definition""" +CFG_ACC_EMPTY_ROLE_DEFINITION_SER=compress(cPickle.dumps((False, ()), -1)) + +""" Source of the default role definition""" +CFG_ACC_EMPTY_ROLE_DEFINITION_SRC='deny any' -# To be set in order to change the login Behaviour into Invenio -CFG_EXTERNAL_AUTH_USING_SSO = False -# Link to reach in order to logout from SSO -#CFG_EXTERNAL_AUTH_LOGOUT_SSO = 'https://login.cern.ch/adfs/ls/?wa=wsignout1.0' -CFG_EXTERNAL_AUTH_LOGOUT_SSO = None # Use external source for access control? # Atleast one must be added # Adviced not to change the name, since it is used to identify the account # Format is: System name: (System class, Default True/Flase), atleast one # must be default CFG_EXTERNAL_AUTHENTICATION = {"Local": (None, True)} -#CFG_EXTERNAL_AUTHENTICATION = {"SSO" : (external_authentication_sso.ExternalAuthSSO(), True)} -#CFG_EXTERNAL_AUTHENTICATION = {"Local": (None, True), \ -# "CERN": (external_authentication_cern.ExternalAuthCern(), False)} + +# Variables to set if using SSO +CFG_EXTERNAL_AUTH_USING_SSO = False +CFG_EXTERNAL_AUTH_LOGOUT_SSO = None + +if CFG_CERN_SITE: + if False: #FIXME set this to True when we deploy SSO at CERN + import external_authentication_sso as ea_sso + CFG_EXTERNAL_AUTH_USING_SSO = True + # Link to reach in order to logout from SSO + CFG_EXTERNAL_AUTH_LOGOUT_SSO = 'https://login.cern.ch/adfs/ls/?wa=wsignout1.0' + CFG_EXTERNAL_AUTHENTICATION = {"SSO" : (ea_sso.ExternalAuthSSO(), True)} + else: + import external_authentication_cern as ea_cern + CFG_EXTERNAL_AUTHENTICATION = {"Local": (None, True), \ + "CERN": (ea_cern.ExternalAuthCern(), False)} -# default data for the add_default_settings function + + +# default data for the add_default_settings function +# Note: by default the definition is set to deny any. This won't be a problem +# because userid directly connected with roles will still be allowed. # roles -# name description -DEF_ROLES = ((SUPERADMINROLE, 'superuser with all rights'), - ('photoadmin', 'Photo collection administrator'), - (WEBACCESSADMINROLE, 'WebAccess administrator')) +# name description definition +DEF_ROLES = ((SUPERADMINROLE, 'superuser with all rights', 'deny any'), + ('photoadmin', 'Photo collection administrator', 'deny any'), + (WEBACCESSADMINROLE, 'WebAccess administrator', 'deny any')) # users # list of e-mail addresses DEF_USERS = [] # actions # name desc allowedkeywords optional DEF_ACTIONS = ( ('cfgwebsearch', 'configure WebSearch', '', 'no'), ('cfgbibformat', 'configure BibFormat', '', 'no'), ('cfgwebsubmit', 'configure WebSubmit', '', 'no'), ('runbibindex', 'run BibIndex', '', 'no'), ('runbibupload', 'run BibUpload', '', 'no'), ('runwebcoll', 'run webcoll', 'collection', 'yes'), ('runbibformat', 'run BibFormat', 'format', 'yes'), (WEBACCESSACTION, 'configure WebAccess', '', 'no'), (DELEGATEADDUSERROLE, 'delegate subroles inside WebAccess', 'role', 'no'), + (VIEWRESTRCOLL, 'view restricted collection', 'collection', 'no'), ('runbibtaskex', 'run BibTaskEx example', '', 'no'), ('referee', 'referee document type doctype/category categ', 'doctype,categ', 'yes'), ('submit', 'use webSubmit', 'doctype,act', 'yes'), ('runbibrank', 'run BibRank', '', 'no'), ('cfgbibrank', 'configure BibRank', '', 'no'), ('cfgbibharvest', 'configure BibHarvest', '', 'no'), ('runoaiharvest', 'run oaiharvest task', '', 'no'), ('cfgwebcomment', 'configure WebComment', '', 'no'), ('runoaiarchive', 'run oaiarchive task', '', 'no'), ('runbibedit', 'run BibEdit', '', 'no'), ) # authorizations # role action arglistid optional arguments DEF_AUTHS = ( (SUPERADMINROLE, 'cfgwebsearch', -1, 0, {}), (SUPERADMINROLE, 'cfgbibformat', -1, 0, {}), (SUPERADMINROLE, 'cfgwebsubmit', -1, 0, {}), (SUPERADMINROLE, 'runbibindex', -1, 0, {}), (SUPERADMINROLE, 'runbibupload', -1, 0, {}), (SUPERADMINROLE, 'runbibformat', -1, 1, {}), (SUPERADMINROLE, WEBACCESSACTION, -1, 0, {}), ('photoadmin', 'runwebcoll', -1, 0, {'collection': 'Pictures'}), (WEBACCESSADMINROLE,WEBACCESSACTION, -1, 0, {}), (SUPERADMINROLE, 'runtaskex', -1, 0, {}), (SUPERADMINROLE, 'referee', -1, 1, {}), (SUPERADMINROLE, 'submit', -1, 1, {}), (SUPERADMINROLE, 'runbibrank', -1, 0, {}), (SUPERADMINROLE, 'cfgbibrank', -1, 0, {}), (SUPERADMINROLE, 'cfgbibharvest', -1, 0, {}), (SUPERADMINROLE, 'runoaiharvest', -1, 0, {}), (SUPERADMINROLE, 'cfgwebcomment', -1, 0, {}), (SUPERADMINROLE, 'runoaiarchive', -1, 0, {}), (SUPERADMINROLE, 'runbibedit', -1, 0, {}), ) CFG_WEBACCESS_MSGS = { 0: 'Try to login with another account.' % (sweburl, sweburl, "%s"), 1: '
If you think this is not correct, please contact: %s' % (supportemail, supportemail), 2: '
If you have any questions, please write to %s' % (supportemail, supportemail), 3: 'Guest users are not allowed, please login.' % sweburl, 4: 'The site is temporarily closed for maintenance. Please come back soon.', 5: 'Authorization failure', 6: '%s temporarily closed' % cdsname, 7: 'This functionality is temporarily closed due to server maintenance. Please use only the search engine in the meantime.', 8: 'Functionality temporarily closed' } CFG_WEBACCESS_WARNING_MSGS = { 0: 'Authorization granted', 1: 'Error(1): You are not authorized to perform this action.', 2: 'Error(2): You are not authorized to perform any action.', 3: 'Error(3): The action %s does not exist.', 4: 'Error(4): Unexpected error occurred.', 5: 'Error(5): Missing mandatory keyword argument(s) for this action.', 6: 'Error(6): Guest accounts are not authorized to perform this action.', 7: 'Error(7): Not enough arguments, user ID and action name required.', 8: 'Error(8): Incorrect keyword argument(s) for this action.', 9: """Error(9): Account '%s' is not yet activated.""", 10: """Error(10): You were not authorized by the authentication method '%s'.""", 11: """Error(11): The selected login method '%s' is not the default method for this account, please try another one.""", 12: """Error(12): Selected login method '%s' does not exist.""", 13: """Error(13): Could not register '%s' account.""", 14: """Error(14): Could not login using '%s', because this user is unknown.""", 15: """Error(15): Could not login using your '%s' account, because you have introduced a wrong password.""", 16: """Error(16): External authentication troubles using '%s' (maybe temporary network problems).""", } diff --git a/modules/webaccess/lib/access_control_engine.py b/modules/webaccess/lib/access_control_engine.py index 3bbe505f6..60a03ce2e 100644 --- a/modules/webaccess/lib/access_control_engine.py +++ b/modules/webaccess/lib/access_control_engine.py @@ -1,419 +1,312 @@ ## $Id$ ## CDS Invenio Access Control Engine in mod_python. ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio Access Control Engine in mod_python.""" __revision__ = "$Id$" from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \ version from invenio.dbquery import run_sql, ProgrammingError +import invenio.access_control_admin as aca from invenio.access_control_config import SUPERADMINROLE, CFG_WEBACCESS_WARNING_MSGS, CFG_WEBACCESS_MSGS +import invenio.webuser as wu +import invenio.access_control_firerole as fw + called_from = 1 #1=web,0=cli try: import _apache except ImportError, e: called_from = 0 ## access controle engine function -def acc_authorize_action(id_user, name_action, verbose=0, **arguments): +def acc_authorize_action(req, name_action, verbose=0, **arguments): """Check if user is allowed to perform action with given list of arguments. Return (0, message) if authentication succeeds, (error code, error message) if it fails. The arguments are as follows: - id_user - id of the user in the database + req - mod_python req necessary to discover info on the user + or uid of the user + or dictionary produces by collect_user_info name_action - the name of the action arguments - dictionary with keyword=value pairs created automatically by python on the extra arguments. these depend on the given action. """ #TASK -1: Checking external source if user is authorized: #if CFG_: # em_pw = run_sql("SELECT email, password FROM user WHERE id=%s", (id_user,)) # if em_pw: # if not CFG_EXTERNAL_ACCESS_CONTROL.loginUser(em_pw[0][0], em_pw[0][1]): # return (10, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[10], (called_from and CFG_WEBACCESS_MSGS[1] or ""))) # TASK 0: find id and allowedkeywords of action + + id_user = req # We initially suppose req contain the id_user + have_uid_p = type(id_user) in [type(1), type(1L)] + if not have_uid_p: # Does req contains more infos? + if type(req) == type({}): # we suppose it's a dict by collect_user_info + user_info = req + else: # otherwise it is a mod_python request object + user_info = wu.collect_user_info(req) + + if user_info.has_key('uid'): + id_user = user_info['uid'] + else: + return (4, CFG_WEBACCESS_WARNING_MSGS[4]) + + # Check if just the userid is enough to execute this action + (ret, msg) = acc_authorize_action(id_user, name_action, verbose, **arguments) + if ret == 0: + return (ret, msg) + + if verbose: print 'task 0 - get action info' query1 = """select a.id, a.allowedkeywords, a.optional from accACTION a where a.name = '%s'""" % (name_action) try: id_action, aallowedkeywords, optional = run_sql(query1)[0] except (ProgrammingError, IndexError): return (3, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[3] % name_action, (called_from and CFG_WEBACCESS_MSGS[1] or ""))) defkeys = aallowedkeywords.split(',') for key in arguments.keys(): if key not in defkeys: return (8, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[8], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) #incorrect arguments? # ------------------------------------------- # TASK 1: check if user is a superadmin # we know the action exists. no connection with role is necessary # passed arguments must have allowed keywords # no check to see if the argument exists if verbose: print 'task 1 - is user %s' % (SUPERADMINROLE, ) - if run_sql("""SELECT * - FROM accROLE r LEFT JOIN user_accROLE ur - ON r.id = ur.id_accROLE - WHERE r.name = '%s' AND - ur.id_user = '%s' """ % (SUPERADMINROLE, id_user)): - return (0, CFG_WEBACCESS_WARNING_MSGS[0]) - # ------------------------------------------ + if have_uid_p: + if run_sql("""SELECT * + FROM accROLE r LEFT JOIN user_accROLE ur + ON r.id = ur.id_accROLE + WHERE r.name = '%s' AND + ur.id_user = '%s' """ % (SUPERADMINROLE, id_user)): + return (0, CFG_WEBACCESS_WARNING_MSGS[0]) + else: + if fw.acc_firerole_check_user(user_info, fw.load_role_definition(aca.acc_getRoleId(SUPERADMINROLE))): + return (0, CFG_WEBACCESS_WARNING_MSGS[0]) # TASK 2: check if user exists and find all the user's roles and create or-string if verbose: print 'task 2 - find user and userroles' try: query2 = """SELECT email, note from user where id=%s""" % id_user res2 = run_sql(query2) - if not res2: - raise Exception - if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1 and res2[0][1] not in [1, "1"]: - if res2[0][0]: - return (9, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[9] % res2[0][0], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) - else: + if have_uid_p: + if not res2: raise Exception - query2 = """SELECT ur.id_accROLE FROM user_accROLE ur WHERE ur.id_user=%s ORDER BY ur.id_accROLE """ % id_user - res2 = run_sql(query2) + if res2: + if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1 and res2[0][1] not in [1, "1"]: + if res2[0][0]: + return (9, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[9] % res2[0][0], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) + else: + raise Exception + if have_uid_p: + query2 = """SELECT ur.id_accROLE FROM user_accROLE ur WHERE ur.id_user=%s ORDER BY ur.id_accROLE """ % id_user + res2 = run_sql(query2) except Exception: return (6, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[6], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) - if not res2: return (2, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[2], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) #user has no roles - # ------------------------------------------- + if have_uid_p: + if not res2: + return (2, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[2], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) #user has no roles + # ------------------------------------------- - # create role string (add default value? roles='(raa.id_accROLE='def' or ') - str_roles = '' - for (role, ) in res2: - if str_roles: str_roles += ',' - str_roles += '%s' % (role, ) + # create role string (add default value? roles='(raa.id_accROLE='def' or ') + str_roles = '' + for (role, ) in res2: + if str_roles: str_roles += ',' + str_roles += '%s' % (role, ) # TASK 3: authorizations with no arguments given if verbose: print 'task 3 - checks with no arguments' if not arguments: # 3.1 if optional == 'no': if verbose: print ' - action with zero arguments' - connection = run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT - WHERE id_accROLE IN (%s) AND - id_accACTION = %s AND - argumentlistid = 0 AND - id_accARGUMENT = 0 """ % (str_roles, id_action)) - - if connection and 1: - return (0, CFG_WEBACCESS_WARNING_MSGS[0]) + if have_uid_p: + connection = run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT + WHERE id_accROLE IN (%s) AND + id_accACTION = %s AND + argumentlistid = 0 AND + id_accARGUMENT = 0 """ % (str_roles, id_action)) + + if connection and 1: + return (0, CFG_WEBACCESS_WARNING_MSGS[0]) + else: + return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) else: + connection = run_sql("""SELECT id_accROLE FROM + accROLE_accACTION_accARGUMENT + WHERE id_accACTION = %s AND + argumentlistid = 0 AND + id_accARGUMENT = 0 """ % id_action) + + for id_accROLE in connection: + if fw.acc_firerole_check_user(user_info, fw.load_role_definition(id_accROLE[0])): + return (0, CFG_WEBACCESS_WARNING_MSGS[0]) + return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) # 3.2 if optional == 'yes': if verbose: print ' - action with optional arguments' - connection = run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT - WHERE id_accROLE IN (%s) AND - id_accACTION = %s AND - id_accARGUMENT = -1 AND - argumentlistid = -1 """ % (str_roles, id_action)) - - if connection and 1: - return (0, CFG_WEBACCESS_WARNING_MSGS[0]) + if have_uid_p: + connection = run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT + WHERE id_accROLE IN (%s) AND + id_accACTION = %s AND + id_accARGUMENT = -1 AND + argumentlistid = -1 """ % (str_roles, id_action)) + + if connection and 1: + return (0, CFG_WEBACCESS_WARNING_MSGS[0]) + else: + return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) else: + connection = run_sql("""SELECT id_accROLE FROM + accROLE_accACTION_accARGUMENT + WHERE id_accACTION = %s AND + id_accARGUMENT = -1 AND + argumentlistid = -1 """ % id_action) + + for id_accROLE in connection: + if fw.acc_firerole_check_user(user_info, fw.load_role_definition(id_accROLE[0])): + return (0, CFG_WEBACCESS_WARNING_MSGS[0]) return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) # none of the zeroargs tests succeded if verbose: print ' - not authorization without arguments' return (5, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[5], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) # TASK 4: create list of keyword and values that satisfy part of the authentication and create or-string if verbose: print 'task 4 - create keyword=value pairs' # create dictionary with default values and replace entries from input arguments defdict = {} for key in defkeys: try: defdict[key] = arguments[key] except KeyError: return (5, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[5], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) # all keywords must be present # except KeyError: defdict[key] = 'x' # default value, this is not in use... # create or-string from arguments str_args = '' for key in defkeys: if str_args: str_args += ' OR ' str_args += """(arg.keyword = '%s' AND arg.value = '%s')""" % (key, defdict[key]) # TASK 5: find all the table entries that partially authorize the action in question if verbose: print 'task 5 - find table entries that are part of the result' - query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid, - raa.id_accARGUMENT, arg.keyword, arg.value - FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT arg - WHERE raa.id_accACTION = %s AND - raa.id_accROLE IN (%s) AND - (%s) AND - raa.id_accARGUMENT = arg.id """ % (id_action, str_roles, str_args) + if have_uid_p: + query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid, + raa.id_accARGUMENT, arg.keyword, arg.value + FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT arg + WHERE raa.id_accACTION = %s AND + raa.id_accROLE IN (%s) AND + (%s) AND + raa.id_accARGUMENT = arg.id """ % (id_action, str_roles, str_args) + else: + query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid, + raa.id_accARGUMENT, arg.keyword, arg.value, ar.firerole_def_ser + FROM accROLE_accACTION_accARGUMENT raa INNER JOIN accROLE ar ON + raa.id_accROLE = ar.id, accARGUMENT arg + WHERE raa.id_accACTION = %s AND + (%s) AND + raa.id_accARGUMENT = arg.id """ % (id_action, str_args) try: res4 = run_sql(query4) - except ProgrammingError: return (3, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[3], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) - - if not res4: return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) # no entries at all + except ProgrammingError: + raise query4 + return (3, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[3] % id_action, (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) res5 = [] - for res in res4: - res5.append(res) - res5.sort() - - # USER AUTHENTICATED TO PERFORM ACTION WITH ONE ARGUMENT - if len(defdict) == 1: return (0, CFG_WEBACCESS_WARNING_MSGS[0]) - - - # CHECK WITH MORE THAN 1 ARGUMENT - - # TASK 6: run through the result and try to satisfy authentication - if verbose: print 'task 6 - combine results and try to satisfy' - - cur_role = cur_action = cur_arglistid = 0 - - booldict = {} - for key in defkeys: booldict[key] = 0 - - # run through the results - - for (role, action, arglistid, arg, keyword, val) in res5 + [(-1, -1, -1, -1, -1, -1)]: - # not the same role or argumentlist (authorization group), i.e. check if thing are satisfied - # if cur_arglistid != arglistid or cur_role != role or cur_action != action: - if (cur_arglistid, cur_role, cur_action) != (arglistid, role, action): - if verbose: print ' : checking new combination', - - # test if all keywords are satisfied - for value in booldict.values(): - if not value: break - else: - if verbose: print '-> found satisfying combination' - return (0, CFG_WEBACCESS_WARNING_MSGS[0]) # USER AUTHENTICATED TO PERFORM ACTION - - if verbose: print '-> not this one' - - # assign the values for the current tuple from the query - cur_arglistid, cur_role, cur_action = arglistid, role, action - - for key in booldict.keys(): - booldict[key] = 0 - - # set keyword qualified for the action, (whatever result of the test) - booldict[keyword] = 1 - - if verbose: print 'finished' - # authentication failed - return (4, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[4], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) - - -## access controle engine function -def acc_authorize_action_req(req, name_action, verbose=0, **arguments): - """Check if user is allowed to perform action - with given list of arguments. - Return (0, message) if authentication succeeds, (error code, error message) if it fails. - - The arguments are as follows: - - req - mod_python req necessary to discover info on the user - - name_action - the name of the action - - arguments - dictionary with keyword=value pairs created automatically - by python on the extra arguments. these depend on the - given action. - """ - - #TASK -1: Checking external source if user is authorized: - #if CFG_: - # em_pw = run_sql("SELECT email, password FROM user WHERE id=%s", (id_user,)) - # if em_pw: - # if not CFG_EXTERNAL_ACCESS_CONTROL.loginUser(em_pw[0][0], em_pw[0][1]): - # return (10, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[10], (called_from and CFG_WEBACCESS_MSGS[1] or ""))) - # TASK 0: find id and allowedkeywords of action - from invenio.firewall import load_role_definition, firewall - if type(req) in [type(1), type(1L)]: - return acc_authorize_action(req, name_action, verbose, **arguments) - if verbose: print 'task 0 - get action info' - query1 = """select a.id, a.allowedkeywords, a.optional - from accACTION a - where a.name = '%s'""" % (name_action) - - try: id_action, aallowedkeywords, optional = run_sql(query1)[0] - except (ProgrammingError, IndexError): return (3, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[3] % name_action, (called_from and CFG_WEBACCESS_MSGS[1] or ""))) - - defkeys = aallowedkeywords.split(',') - for key in arguments.keys(): - if key not in defkeys: return (8, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[8], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) #incorrect arguments? - # ------------------------------------------- + if have_uid_p: + if not res4: return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) # no entries at all + res5 = [] + for res in res4: + res5.append(res) - # TASK 1: check if user is a superadmin - # we know the action exists. no connection with role is necessary - # passed arguments must have allowed keywords - # no check to see if the argument exists - if verbose: print 'task 1 - is user %s' % (SUPERADMINROLE, ) - - from webuser import extract_user_info - user_info = extract_user_info(req) - - if firewall(user_info, load_role_definition(SUPERADMINROLE)): - return (0, CFG_WEBACCESS_WARNING_MSGS[0]) - # ------------------------------------------ - - - # TASK 2: check if user exists - if verbose: print 'task 2 - find user' - - query2 = """SELECT email, note from user where id=%s""" % id_user - res2 = run_sql(query2) - if res2: - if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1 and res2[0][1] not in [1, "1"]: - if res2[0][0]: - return (9, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[9] % res2[0][0], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) - else: - raise Exception - - # TASK 3: authorizations with no arguments given - if verbose: print 'task 3 - checks with no arguments' - if not arguments: - # 3.1 - if optional == 'no': - if verbose: print ' - action with zero arguments' - connection = run_sql("""SELECT id_accROLE FROM accROLE_accACTION_accARGUMENT - WHERE id_accACTION = %s AND - argumentlistid = 0 AND - id_accARGUMENT = 0 """ % id_action) + else: + for row in res4: + if fw.acc_firerole_check_user(user_info, fw.load_role_definition(row[0])): + res5.append(row) + if not res5: + return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) # no entries at all - for id_accROLE in connection: - if firewall(user_info, load_role_definition(id_accROLE[0])): - return (0, CFG_WEBACCESS_WARNING_MSGS[0]) - - return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) - - # 3.2 - if optional == 'yes': - if verbose: print ' - action with optional arguments' - connection = run_sql("""SELECT id_accROLE FROM accROLE_accACTION_accARGUMENT - WHERE id_accACTION = %s AND - id_accARGUMENT = -1 AND - argumentlistid = -1 """ % id_action) - - for id_accROLE in connection: - if firewall(user_info, load_role_definition(id_accROLE[0])): - return (0, CFG_WEBACCESS_WARNING_MSGS[0]) - return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) - - # none of the zeroargs tests succeded - if verbose: print ' - not authorization without arguments' - return (5, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[5], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) - - # TASK 4: create list of keyword and values that satisfy part of the authentication and create or-string - if verbose: print 'task 4 - create keyword=value pairs' - - # create dictionary with default values and replace entries from input arguments - defdict = {} - - for key in defkeys: - try: defdict[key] = arguments[key] - except KeyError: return (5, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[5], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) # all keywords must be present - # except KeyError: defdict[key] = 'x' # default value, this is not in use... - - # create or-string from arguments - str_args = '' - for key in defkeys: - if str_args: str_args += ' OR ' - str_args += """(arg.keyword = '%s' AND arg.value = '%s')""" % (key, defdict[key]) - - - # TASK 5: find all the table entries that partially authorize the action in question - if verbose: print 'task 5 - find table entries that are part of the result' - - query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid, - raa.id_accARGUMENT, arg.keyword, arg.value, ar.definition - FROM accROLE_accACTION_accARGUMENT raa INNER JOIN accRole ar ON raa.id_accROLE = ar.id, accARGUMENT arg - WHERE raa.id_accACTION = %s AND - (%s) AND - raa.id_accARGUMENT = arg.id """ % (id_action, str_args) - - try: res4 = run_sql(query4) - except ProgrammingError: return (3, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[3], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) - - res5 = [] - for row in res4: - if firewall(user_info, load_role_definition(row[0])): - res5.append(row) - if not res5: - return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) # no entries at all res5.sort() # USER AUTHENTICATED TO PERFORM ACTION WITH ONE ARGUMENT if len(defdict) == 1: return (0, CFG_WEBACCESS_WARNING_MSGS[0]) # CHECK WITH MORE THAN 1 ARGUMENT # TASK 6: run through the result and try to satisfy authentication if verbose: print 'task 6 - combine results and try to satisfy' cur_role = cur_action = cur_arglistid = 0 booldict = {} for key in defkeys: booldict[key] = 0 # run through the results for (role, action, arglistid, arg, keyword, val) in res5 + [(-1, -1, -1, -1, -1, -1)]: # not the same role or argumentlist (authorization group), i.e. check if thing are satisfied # if cur_arglistid != arglistid or cur_role != role or cur_action != action: if (cur_arglistid, cur_role, cur_action) != (arglistid, role, action): if verbose: print ' : checking new combination', # test if all keywords are satisfied for value in booldict.values(): if not value: break else: if verbose: print '-> found satisfying combination' return (0, CFG_WEBACCESS_WARNING_MSGS[0]) # USER AUTHENTICATED TO PERFORM ACTION if verbose: print '-> not this one' # assign the values for the current tuple from the query cur_arglistid, cur_role, cur_action = arglistid, role, action for key in booldict.keys(): booldict[key] = 0 # set keyword qualified for the action, (whatever result of the test) booldict[keyword] = 1 if verbose: print 'finished' # authentication failed return (4, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[4], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) - - diff --git a/modules/webaccess/lib/access_control_firerole.py b/modules/webaccess/lib/access_control_firerole.py new file mode 100644 index 000000000..cf4c06da9 --- /dev/null +++ b/modules/webaccess/lib/access_control_firerole.py @@ -0,0 +1,253 @@ + ## $Id$ +## Administrator interface for WebAccess + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. + +"""CDS Invenio Access Control FireRole.""" + +__revision__ = "$Id$" + +__lastupdated__ = """$Date$""" + +"""These functions are for realizing a firewall like role definition for extending +webaccess to connect user to roles using every infos about users. +""" + +from invenio.webgroup_dblayer import get_groups +from invenio.webinterface_handler import http_get_credentials +from invenio.access_control_config import WebAccessFireroleError +from invenio.dbquery import run_sql +from invenio.access_control_config import CFG_ACC_EMPTY_ROLE_DEFINITION_SRC, \ + CFG_ACC_EMPTY_ROLE_DEFINITION_SER +from socket import gethostbyname +import re +import cPickle +from zlib import compress, decompress + + +# INTERFACE + +def compile_role_definition(firerole_def_src): + """ Given a text in which every row contains a rule it returns the compiled + object definition. + Rules have the following syntax: + allow|deny [not] field {list of one or more (double)quoted string or regexp} + or allow|deny any + Every row may contain a # sign followed by a comment which are discarded. + Field could be any key contained in a user_info dictionary. If the key does + not exist in the dictionary, the rule is skipped. + The first rule which matches return. + """ + line = 0 + ret = [] + default_allow_p = False + if not firerole_def_src or not firerole_def_src.strip(): + firerole_def_src = CFG_ACC_EMPTY_ROLE_DEFINITION_SRC + for row in firerole_def_src.split('\n'): + line += 1 + row = row.strip() + if not row: + continue + clean_row = _no_comment_re.sub('', row) + if clean_row: + g = _any_rule_re.match(clean_row) + if g: + default_allow_p = g.group('command').lower() == 'allow' + break + g = _rule_re.match(clean_row) + if g: + allow_p = g.group('command').lower() == 'allow' + not_p = g.group('not') != None + field = g.group('field').lower() + # Renaming groups to group and apache_groups to apache_group + for alias_item in _aliasTable: + if field in alias_item: + field = alias_item[0] + break + expressions = g.group('expression')+g.group('more_expressions') + expressions_list = [] + for expr in _expressions_re.finditer(expressions): + expr = expr.group() + if expr[0] == '/': + try: + expressions_list.append((True, re.compile(expr[1:-1], re.I))) + except Exception, msg: + raise WebAccessFireroleError, "Syntax error while compiling rule %s (line %s): %s is not a valid re because %s!" % (row, line, expr, msg) + else: + if field == 'remote_ip' and '/' in expr[1:-1]: + try: + expressions_list.append((False, _ip_matcher_builder(expr[1:-1]))) + except Exception, msg: + raise WebAccessFireroleError, "Syntax error while compiling rule %s (line %s): %s is not a valid ip group because %s!" % (row, line, expr, msg) + else: + expressions_list.append((False, expr[1:-1])) + expressions_list = tuple(expressions_list) + ret.append((allow_p, not_p, field, expressions_list)) + else: + raise WebAccessFireroleError, "Syntax error while compiling rule %s (line %s): not a valid rule!" % (row, line) + return (compress(cPickle.dumps((default_allow_p, tuple(ret)), -1))) + + +def repair_role_definitions(): + """ Try to rebuild compiled serialized definitions from their respectives + sources. This is needed in case Python break back compatibility. + """ + definitions = run_sql("SELECT id, firerole_def_src FROM accROLE""") + for role_id, firerole_def_src in definitions: + run_sql("UPDATE accROLE SET firerole_def_ser=%s WHERE id=%s", (compile_role_definition(firerole_def_src), role_id)) + +def store_role_definition(role_id, firerole_def_ser, firerole_def_src): + """ Store a compiled serialized definition and its source in the database + alongside the role to which it belong. + @param role_id the role_id + @param firerole_def_ser the serialized compiled definition + @param firerole_def_src the sources from which the definition was taken + """ + run_sql("UPDATE accROLE SET firerole_def_ser=%s, firerole_def_src=%s WHERE id=%s", (firerole_def_ser, firerole_def_src, role_id)) + +def load_role_definition(role_id): + """ Load the definition corresponding to a role. If the compiled definition + is corrupted it try to repairs definitions from their sources and try again + to return the definition. + @param the role_id + @return a deserialized compiled role definition + """ + res = run_sql("SELECT firerole_def_ser FROM accROLE WHERE id=%s", (role_id, ), 1) + if res: + try: + return cPickle.loads(decompress(res[0][0])) + except Exception: + repair_role_definitions() + res = run_sql("SELECT firerole_def_ser FROM accROLE WHERE id=%s", (role_id, ), 1) + if res: + return cPickle.loads(decompress(res[0][0])) + else: + return (False, ()) + else: + return (False, ()) + +def acc_firerole_check_user(user_info, firerole_def_obj): + """ Given a user_info dictionary, it matches the rules inside the deserializez + compiled definition in order to discover if the current user match the roles + corresponding to this definition. + @param user_info a dict produced by collect_user_info which contains every + info about a user + @param definition a compiled deserialized definition produced by compile_role_defintion + @return True if the user match the definition, False otherwise. + """ + try: + default_allow_p, rules = firerole_def_obj + for (allow_p, not_p, field, expressions_list) in rules: # for every rule + group_p = field in ['group', 'apache_group'] # Is it related to group? + ip_p = field == 'remote_ip' # Is it related to Ips? + next_rule_p = False # Silly flag to break 2 for cycle + if not user_info.has_key(field): + continue + for reg_p, expr in expressions_list: # For every element in the rule + if group_p: # Special case: groups + if reg_p: # When it is a regexp + for group in user_info[field]: # iterate over every group + if expr.match(group): # if it matches + if not_p: # if must not match + next_rule_p = True # let's skip to next rule + break + else: # Ok! + return allow_p + if next_rule_p: + break # I said: let's skip to next rule ;-) + elif expr.lower() in [group.lower() for group in user_info[field]]: # Simple expression then just check for expr in groups + if not_p: # If expr is in groups then if must not match + break # let's skip to next rule + else: # Ok! + return allow_p + elif reg_p: # Not a group, then easier. If it's a regexp + if expr.match(user_info[field]): # if it matches + if not_p: # If must not match + break # Let's skip to next rule + else: + return allow_p # Ok! + elif ip_p and type(expr) == type(()): # If it's just a simple expression but an IP! + if _ipmatch(user_info['remote_ip'], expr): # Then if Ip matches + if not_p: # If must not match + break # let's skip to next rule + else: + return allow_p # ok! + elif expr.lower() == user_info[field].lower(): # Finally the easiest one!! + if not_p: # ... + break + else: # ... + return allow_p # ... + if not_p and not next_rule_p: # Nothing has matched and we got not + return allow_p # Then the whole rule matched! + except Exception, msg: + raise WebAccessFireroleError, msg + return default_allow_p # By default we allow ;-) it'an OpenSource project + +def deserialize(firerole_def_ser): + """ Deserialize and decompress a definition.""" + if firerole_def_ser: + return cPickle.loads(decompress(firerole_def_ser)) + else: + return cPickle.loads(decompress(CFG_ACC_EMPTY_ROLE_DEFINITION_SER)) + +# IMPLEMENTATION + +# Comment finder +_no_comment_re = re.compile(r'[\s]*(?allow|deny)[\s]+(?:(?Pnot)[\s]+)?(?P[\w]+)[\s]+(?P(?([\s]*,[\s]*((?allow|deny)[\s]+any[\s]*', re.I) + +# Sub expression finder +_expressions_re = re.compile(r'(?allow|deny)[\s]+(?:(?Pnot)[\s]+)?(?P[\w]+)[\s]+(?P(?([\s]*,[\s]*((?allow|deny)[\s]+any[\s]*', re.I) - -# Sub expression finder -expressions_re = re.compile(r'(?Admin Area > WebAccess Admin """ % (weburl, weburl) - + if body: if adminarea == 1: navtrail_previous_links += '> Delegate Rights ' % (weburl, ) if adminarea >= 2 and adminarea < 7: navtrail_previous_links += '> Manage WebAccess ' % (weburl, ) if adminarea == 3: navtrail_previous_links += '> Role Administration ' % (weburl, ) elif adminarea == 4: navtrail_previous_links += '> Action Administration ' % (weburl, ) elif adminarea == 5: navtrail_previous_links += '> User Administration ' % (weburl, ) elif adminarea == 6: navtrail_previous_links += '> Reset Authorizations ' % (weburl, ) elif adminarea == 7: navtrail_previous_links += '> Manage Accounts ' % (weburl, ) - + id_user = getUid(req) (auth_code, auth_message) = is_adminuser(req) if not authorized and auth_code != 0: return mustloginpage(req, auth_message) elif not body: title = 'Manage WebAccess' body = startpage() elif type(body) != str: body = addadminbox(subtitle, datalist=body) return page(title=title, uid=id_user, req=req, body=body, navtrail=navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) def mustloginpage(req, message): """show a page asking the user to login.""" - + navtrail_previous_links = """Admin Area > WebAccess Admin """ % (weburl, weburl) return page_not_authorized(req=req, text=message, navtrail=navtrail_previous_links) - + def is_adminuser(req): """check if user is a registered administrator. """ - id_user = getUid(req) - return acce.acc_authorize_action(id_user, WEBACCESSACTION) + return acce.acc_authorize_action(req, WEBACCESSACTION) def perform_rolearea(req): """create the role area menu page.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) - header = ['id', 'name', 'description', 'users', 'authorizations / actions', 'role', ''] + header = ['id', 'name', 'description', 'definition', 'users', 'authorizations / actions', 'role', ''] roles = acca.acc_getAllRoles() roles2 = [] - for (id, name, desc) in roles: + for (id, name, desc, dontcare, firerole_def_src) in roles: if len(desc) > 30: desc = desc[:30] + '...' - roles2.append([id, name, desc]) + if firerole_def_src and len(firerole_def_src) > 30: firerole_def_src = firerole_def_src[:30] + '...' + roles2.append([id, name, desc, firerole_def_src]) for col in [(('add', 'adduserrole'), - ('remove', 'deleteuserrole')), + ('delete', 'deleteuserrole'),), (('add', 'addauthorization'), ('modify', 'modifyauthorizations'), ('remove', 'deleteroleaction')), - (('delete', 'deleterole'), ), + (('modify', 'modifyrole'), + ('delete', 'deleterole')), (('show details', 'showroledetails'), )]: roles2[-1].append('%s' % (col[0][1], id, col[0][0])) for (str, function) in col[1:]: roles2[-1][-1] += ' / %s' % (function, id, str) output = """
Users:
add or remove users from the access to a role and its priviliges.
Authorizations/Actions:
these terms means almost the same, but an authorization is a
connection between a role and an action (possibly) containing arguments.
Roles:
see all the information attached to a role and decide if you want to
delete it.
""" - + output += tupletotable(header=header, tuple=roles2) extra = """
Create new role
go here to add a new role.
Create new action
go here to add a new action.
""" return index(req=req, title='Role Administration', subtitle='administration with roles as access point', body=[output, extra], adminarea=2) def perform_actionarea(req): """create the action area menu page.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) header = ['id', 'name', 'authorizations/roles', 'action', ''] actions = acca.acc_getAllActions() actions2 = [] roles2 = [] for (id, name, dontcare) in actions: actions2.append([id, name]) for col in [(('add', 'addauthorization'), ('modify', 'modifyauthorizations'), ('remove', 'deleteroleaction')), (('delete', 'deleteaction'), ), (('show details', 'showactiondetails'), )]: actions2[-1].append('%s' % (col[0][1], id, col[0][0])) for (str, function) in col[1:]: actions2[-1][-1] += ' / %s' % (function, id, str) output = """
Authorizations/Roles:
these terms means almost the same, but an authorization is a
connection between a role and an action (possibly) containing arguments.
Actions:
see all the information attached to an action and decide if you want to
delete it.
""" - + output += tupletotable(header=header, tuple=actions2) extra = """
Create new role
go here to add a new role.
Create new action
go here to add a new action.
""" return index(req=req, title='Action Administration', subtitle='administration with actions as access point', body=[output, extra], adminarea=2) def perform_userarea(req, email_user_pattern=''): """create area to show info about users. """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = 'step 1 - search for users' output = """

- search for users to display. + search for users to display.

""" # remove letters not allowed in an email email_user_pattern = cleanstring_email(email_user_pattern) - + text = ' 1. search for user\n' text += ' \n' % (email_user_pattern, ) output += createhiddenform(action="userarea", text=text, button="search for users") if email_user_pattern: users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email LIMIT %s""" % (email_user_pattern, MAXPAGEUSERS+1)) if not users1: output += '

no matching users

' - else: + else: subtitle = 'step 2 - select what to do with user' users = [] for (id, email) in users1[:MAXPAGEUSERS]: users.append([id, email]) for col in [(('add', 'addroleuser'), ('remove', 'deleteuserrole')), (('show details', 'showuserdetails'), )]: users[-1].append('%s' % (col[0][1], email_user_pattern, id, col[0][0])) for (str, function) in col[1:]: users[-1][-1] += ' / %s' % (function, email_user_pattern, id, str) - + output += '

found %s matching users:

' % (len(users1), ) output += tupletotable(header=['id', 'email', 'roles', ''], tuple=users) if len(users1) > MAXPAGEUSERS: output += '

only showing the first %s users, narrow your search...

' % (MAXPAGEUSERS, ) return index(req=req, title='User Administration', subtitle=subtitle, body=[output], adminarea=2) def perform_resetarea(req): """create the reset area menu page.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) output = """
Reset to Default Authorizations
remove all changes that has been done to the roles and
add only the default authorization settings.
Add Default Authorizations
keep all changes and add the default authorization settings.
""" return index(req=req, title='Reset Authorizations', subtitle='reseting to or adding default authorizations', body=[output], adminarea=2) def perform_resetdefaultsettings(req, superusers=[], confirm=0): """delete all roles, actions and authorizations presently in the database and add only the default roles. only selected users will be added to superadmin, rest is blank """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) # cleaning input if type(superusers) == str: superusers = [superusers] # remove not valid e-mails for email in superusers: if not check_email(email): superusers.remove(email) - + # instructions output = """

before you reset the settings, we need some users
to connect to %s.
enter as many e-mail addresses you want and press reset.
confirm reset settings when you have added enough e-mails.
%s is added as default.

""" % (SUPERADMINROLE, supportemail) # add more superusers output += """

enter user e-mail addresses:

""" for email in superusers: output += ' ' % (email, ) output += """ e-mail
""" if superusers: # remove emails output += """
- have you entered wrong data? + have you entered wrong data?
""" - + # superusers confirm table start = '
' - + extra = ' ' for email in superusers: extra += '' % (email, ) extra += ' ' - + end = '
' - + output += '

reset default settings with the users below?

' output += tupletotable(header=['e-mail address'], tuple=superusers, start=start, extracolumn=extra, end=end) - + if confirm in [1, "1"]: res = acca.acc_reset_default_settings(superusers) if res: output += '

successfully reset default settings

' else: output += '

sorry, could not reset default settings

' - + return index(req=req, title='Reset Default Settings', subtitle='reset settings', body=[output], adminarea=6) def perform_adddefaultsettings(req, superusers=[], confirm=0): """add the default settings, and keep everything else. probably nothing will be deleted, except if there has been made changes to the defaults.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) # cleaning input if type(superusers) == str: superusers = [superusers] - + # remove not valid e-mails for email in superusers: if not check_email(email): superusers.remove(email) - + # instructions output = """

before you add the settings, we need some users
to connect to %s.
enter as many e-mail addresses you want and press add.
confirm add settings when you have added enough e-mails.
%s is added as default.

""" % (SUPERADMINROLE, supportemail) # add more superusers output += """

enter user e-mail addresses:

""" for email in superusers: output += ' ' % (email, ) output += """ e-mail
""" if superusers: # remove emails output += """
- have you entered wrong data? + have you entered wrong data?
""" - + # superusers confirm table start = '
' - + extra = ' ' for email in superusers: extra += '' % (email, ) extra += ' ' - + end = '
' - + output += '

add default settings with the users below?

' output += tupletotable(header=['e-mail address'], tuple=superusers, start=start, extracolumn=extra, end=end) if confirm in [1, "1"]: res = acca.acc_add_default_settings(superusers) if res: output += '

successfully added default settings

' else: output += '

sorry, could not add default settings

' - + return index(req=req, title='Add Default Settings', subtitle='add settings', body=[output], adminarea=6) def perform_manageaccounts(req, mtype='', content='', confirm=0): """start area for managing accounts.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = 'Overview' fin_output = '' fin_output += """
Menu
0. Show all 1. Access policy 2. Account overview 3. Create account 4. Edit accounts
""" % (weburl, weburl, weburl, weburl, weburl) if mtype == "perform_accesspolicy" and content: fin_output += content elif mtype == "perform_accesspolicy" or mtype == "perform_showall": fin_output += perform_accesspolicy(req, callback='') fin_output += "
" if mtype == "perform_accountoverview" and content: fin_output += content elif mtype == "perform_accountoverview" or mtype == "perform_showall": fin_output += perform_accountoverview(req, callback='') fin_output += "
" if mtype == "perform_createaccount" and content: fin_output += content elif mtype == "perform_createaccount" or mtype == "perform_showall": fin_output += perform_createaccount(req, callback='') fin_output += "
" if mtype == "perform_modifyaccounts" and content: fin_output += content elif mtype == "perform_modifyaccounts" or mtype == "perform_showall": fin_output += perform_modifyaccounts(req, callback='') fin_output += "
" return index(req=req, title='Manage Accounts', - subtitle=subtitle, + subtitle=subtitle, body=[fin_output], adminarea=0, authorized=1) def perform_accesspolicy(req, callback='yes', confirm=0): """Modify default behaviour of a guest user or if new accounts should automatically/manually be modified.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """1. Access policy.   [?]""" % weburl account_policy = {} - account_policy[0] = "Users can register new accounts. New accounts automatically activated." + account_policy[0] = "Users can register new accounts. New accounts automatically activated." account_policy[1] = "Users can register new accounts. Admin users must activate the accounts." account_policy[2] = "Only admin can register new accounts. User cannot edit email address." account_policy[3] = "Only admin can register new accounts. User cannot edit email address or password." account_policy[4] = "Only admin can register new accounts. User cannot edit email address,password or login method." site_policy = {} site_policy[0] = "Normal operation of the site." site_policy[1] = "Read-only site, all write operations temporarily closed." site_policy[2] = "Site fully closed." output = "(Modifications must be done in access_control_config.py)
" output += "
Current settings:
" output += "Site status: %s
" % (site_policy[CFG_ACCESS_CONTROL_LEVEL_SITE]) output += "Guest accounts allowed: %s
" % (CFG_ACCESS_CONTROL_LEVEL_GUESTS == 0 and "Yes" or "No") output += "Account policy: %s
" % (account_policy[CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS]) output += "Allowed email addresses limited: %s
" % (CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN and CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN or "Not limited") output += "Send email to admin when new account: %s
" % (CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS == 1 and "Yes" or "No") output += "Send email to user after creating new account: %s
" % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1 and "Yes" or "No") output += "Send email to user when account is activated: %s
" % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION == 1 and "Yes" or "No") output += "Send email to user when account is deleted/rejected: %s
" % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1 and "Yes" or "No") output += "
" output += "Available 'login via' methods:
" methods = CFG_EXTERNAL_AUTHENTICATION.keys() methods.sort() for system in methods: output += """%s %s
""" % (system, (CFG_EXTERNAL_AUTHENTICATION[system][1] and "(Default)" or "")) - + output += "
Changing the settings:
" output += "Currently, all changes must be done using your favourite editor, and the webserver restarted for changes to take effect. For the settings to change, either look in the guide or in access_control_config.py ." body = [output] if callback: return perform_manageaccounts(req, "perform_accesspolicy", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_accountoverview(req, callback='yes', confirm=0): """Modify default behaviour of a guest user or if new accounts should automatically/manually be modified.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """2. Account overview.   [?]""" % weburl output = "" res = run_sql("SELECT COUNT(*) FROM user WHERE email=''") output += "Guest accounts: %s
" % res[0][0] res = run_sql("SELECT COUNT(*) FROM user WHERE email!=''") output += "Registered accounts: %s
" % res[0][0] res = run_sql("SELECT COUNT(*) FROM user WHERE email!='' AND note='0' OR note IS NULL") output += "Inactive accounts: %s " % res[0][0] if res[0][0] > 0: output += ' [Activate/Reject accounts]' res = run_sql("SELECT COUNT(*) FROM user") output += "
Total nr of accounts: %s
" % res[0][0] body = [output] if callback: return perform_manageaccounts(req, "perform_accountoverview", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_createaccount(req, email='', password='', callback='yes', confirm=0): """Modify default behaviour of a guest user or if new accounts should automatically/manually be modified.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """3. Create account.   [?]""" % weburl output = "" text = ' Email:\n' text += '
' % (email, ) text += ' Password:\n' text += '
' % (password, ) output += createhiddenform(action="createaccount", - text=text, + text=text, confirm=1, button="Create") if confirm in [1, "1"] and email and email_valid_p(email): res = run_sql("SELECT * FROM user WHERE email='%s'" % escape_string(email)) if not res: res = run_sql("INSERT INTO user (email,password, note) values('%s','%s', '1')" % (escape_string(email), escape_string(password))) if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1: emailsent = sendNewUserAccountWarning(email, email, password) if password: - output += 'Account created with password and activated.' - else: - output += 'Account created without password and activated.' + output += 'Account created with password and activated.' + else: + output += 'Account created without password and activated.' if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1: if emailsent: - output += '
An email has been sent to the owner of the account.' + output += '
An email has been sent to the owner of the account.' else: - output += '
Could not send an email to the owner of the account.' - + output += '
Could not send an email to the owner of the account.' + else: - output += 'An account with the same email already exists.' - + output += 'An account with the same email already exists.' + elif confirm in [1, "1"]: output += 'Please specify an valid email-address.' - + body = [output] if callback: return perform_manageaccounts(req, "perform_createaccount", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_modifyaccountstatus(req, userID, email_user_pattern, limit_to, maxpage, page, callback='yes', confirm=0): """set a disabled account to enabled and opposite""" - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) res = run_sql("SELECT id, email, note, password FROM user WHERE id=%s" % userID) subtitle = "" output = "" if res: if res[0][2] in [0, "0", None]: res2 = run_sql("UPDATE user SET note=1 WHERE id=%s" % userID) output += """The account '%s' has been activated.""" % res[0][1] if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION == 1: emailsent = sendAccountActivatedMessage(res[0][1], res[0][1], res[0][3]) - if emailsent: + if emailsent: output += """
An email has been sent to the owner of the account.""" else: output += """
Could not send an email to the owner of the account.""" - + elif res[0][2] in [1, "1"]: res2 = run_sql("UPDATE user SET note=0 WHERE id=%s" % userID) output += """The account '%s' has been set inactive.""" % res[0][1] else: output += 'The account id given does not exist.' - + body = [output] if callback: return perform_modifyaccounts(req, email_user_pattern, limit_to, maxpage, page, content=output, callback='yes') else: return addadminbox(subtitle, body) def perform_editaccount(req, userID, mtype='', content='', callback='yes', confirm=-1): """form to modify an account. this method is calling other methods which again is calling this and sending back the output of the method. if callback, the method will call perform_editcollection, if not, it will just return its output. userID - id of the user mtype - the method that called this method. content - the output from that method.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) res = run_sql("SELECT id, email FROM user WHERE id=%s" % userID) if not res: if mtype == "perform_deleteaccount": text = """The selected account has been deleted, to continue editing, go back to 'Manage Accounts'.""" if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1: text += """
An email has been sent to the owner of the account.""" else: text = """The selected accounts does not exist, please go back and select an account to edit.""" - - return index(req=req, + + return index(req=req, title='Edit Account', - subtitle="Edit account", + subtitle="Edit account", body=[text], adminarea=7, authorized=1) - + fin_output = """
Menu
0. Show all 1. Modify login-data 2. Modify baskets 3. Modify alerts 4. Modify preferences
5. Delete account
""" % (weburl, userID, weburl, userID, weburl, userID, weburl, userID, weburl, userID, weburl, userID) if mtype == "perform_modifylogindata" and content: fin_output += content elif mtype == "perform_modifylogindata" or not mtype: fin_output += perform_modifylogindata(req, userID, callback='') if mtype == "perform_modifybasket" and content: fin_output += content elif mtype == "perform_modifybasket" or not mtype: fin_output += perform_modifybasket(req, userID, callback='') if mtype == "perform_modifypreferences" and content: fin_output += content elif mtype == "perform_modifypreferences" or not mtype: fin_output += perform_modifypreferences(req, userID, callback='') if mtype == "perform_modifyalerts" and content: fin_output += content elif mtype == "perform_modifyalerts" or not mtype: fin_output += perform_modifyalerts(req, userID, callback='') if mtype == "perform_deleteaccount" and content: fin_output += content elif mtype == "perform_deleteaccount" or not mtype: fin_output += perform_deleteaccount(req, userID, callback='') - + return index(req=req, title='Edit Account', - subtitle="Edit account '%s'" % res[0][1], + subtitle="Edit account '%s'" % res[0][1], body=[fin_output], adminarea=7, authorized=1) def perform_modifybasket(req, userID, callback='yes', confirm=0): """modify email and password of an account""" - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """2. Modify baskets.   [?]""" % weburl res = run_sql("SELECT id, email, password FROM user WHERE id=%s" % userID) output = "" if res: text = """To modify the baskets for this account, you have to login as the user.""" output += createhiddenform(action="%s/youraccount/login?" % sweburl, text=text, p_email=res[0][1], p_pw=res[0][2], referer="%s/yourbaskets/display" % weburl, button="Login") output += "Remember that you will be logged out as the current user." #baskets = run_sql("SELECT basket.id, basket.name, basket.public FROM basket, user_basket WHERE id_user=%s and user_basket.id_basket=basket.id" % userID) #output += "" #for (id, name, public) in baskets: # output += "" % (name, (public=="y" and "Yes" or "No")) # basket_records = run_sql("SELECT id_record, nb_order FROM basket_record WHERE id_basket=%s" % id) # for (id_record, nb_order) in basket_records: # output += "" - # + # #output += "
%s
Public: %s
" # output += print_record(id_record) # output += "
" else: output += 'The account id given does not exist.' - + body = [output] if callback: return perform_editaccount(req, userID, mtype='perform_modifybasket', content=addadminbox(subtitle, body), callback='yes') else: return addadminbox(subtitle, body) def perform_modifylogindata(req, userID, email='', password='', callback='yes', confirm=0): """modify email and password of an account""" - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """1. Edit login-data.   [?]""" % weburl res = run_sql("SELECT id, email, password FROM user WHERE id=%s" % userID) output = "" if res: if not email and not password: email = res[0][1] password = res[0][2] text = ' Account id:%s
\n' % userID text += ' Email:\n' text += '
' % (email, ) text += ' Password:\n' text += '
' % (password, ) output += createhiddenform(action="modifylogindata", text=text, - userID=userID, + userID=userID, confirm=1, button="Modify") if confirm in [1, "1"] and email and email_valid_p(email): res = run_sql("UPDATE user SET email='%s' WHERE id=%s" % (escape_string(email), userID)) res = run_sql("UPDATE user SET password='%s' WHERE id=%s" % (escape_string(password), userID)) output += 'Email and/or password modified.' elif confirm in [1, "1"]: output += 'Please specify an valid email-address.' else: output += 'The account id given does not exist.' - + body = [output] if callback: return perform_editaccount(req, userID, mtype='perform_modifylogindata', content=addadminbox(subtitle, body), callback='yes') else: return addadminbox(subtitle, body) def perform_modifyalerts(req, userID, callback='yes', confirm=0): """modify email and password of an account""" - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """3. Modify alerts.   [?]""" % weburl res = run_sql("SELECT id, email, password FROM user WHERE id=%s" % userID) output = "" if res: text = """To modify the alerts for this account, you have to login as the user.""" output += createhiddenform(action="%s/youraccount/login?" % sweburl, text=text, p_email=res[0][1], p_pw=res[0][2], referer="%s/youralerts/display" % weburl, button="Login") output += "Remember that you will be logged out as the current user." - res= """ SELECT q.id, q.urlargs, a.id_basket, - a.alert_name, a.frequency, a.notification, - DATE_FORMAT(a.date_creation,'%%d %%b %%Y'), + res = """ SELECT q.id, q.urlargs, a.id_basket, + a.alert_name, a.frequency, a.notification, + DATE_FORMAT(a.date_creation,'%%d %%b %%Y'), DATE_FORMAT(a.date_lastrun,'%%d %%b %%Y') FROM query q, user_query_basket a WHERE a.id_user='%s' AND a.id_query=q.id ORDER BY a.alert_name ASC """ % userID #res = run_sql(res) #for (qID, qurlargs, id_basket, alertname, frequency, notification, date_creation, date_lastrun) in res: # output += "%s - %s - %s - %s - %s - %s - %s
" % (qID, id_basket, alertname, frequency, notification, date_creation, date_lastrun) else: output += 'The account id given does not exist.' - + body = [output] if callback: return perform_editaccount(req, userID, mtype='perform_modifyalerts', content=addadminbox(subtitle, body), callback='yes') else: return addadminbox(subtitle, body) def perform_modifypreferences(req, userID, login_method='', callback='yes', confirm=0): """modify email and password of an account""" - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """4. Modify preferences.   [?]""" % weburl res = run_sql("SELECT id, email, password FROM user WHERE id=%s" % userID) output = "" if res: user_pref = get_user_preferences(userID) if confirm in [1, "1"]: if login_method: - user_pref['login_method'] = login_method + user_pref['login_method'] = login_method set_user_preferences(userID, user_pref) output += "Select default login method:
" text = "" methods = CFG_EXTERNAL_AUTHENTICATION.keys() methods.sort() for system in methods: text += """%s
""" % (system, (user_pref['login_method'] == system and "checked" or ""), system) output += createhiddenform(action="modifypreferences", text=text, confirm=1, userID=userID, button="Select") if confirm in [1, "1"]: if login_method: output += """The login method has been changed""" else: output += """Nothing to update""" else: output += 'The account id given does not exist.' - + body = [output] if callback: return perform_editaccount(req, userID, mtype='perform_modifypreferences', content=addadminbox(subtitle, body), callback='yes') else: return addadminbox(subtitle, body) def perform_deleteaccount(req, userID, callback='yes', confirm=0): """delete account""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) - + subtitle = """5. Delete account.   [?]""" % weburl res = run_sql("SELECT id, email, password FROM user WHERE id=%s" % userID) output = "" if res: if confirm in [0, "0"]: text = 'Are you sure you want to delete the account with email: "%s"?' % res[0][1] output += createhiddenform(action="deleteaccount", text=text, - userID=userID, + userID=userID, confirm=1, button="Delete") - + elif confirm in [1, "1"]: res2 = run_sql("DELETE FROM user WHERE id=%s" % userID) output += 'Account deleted.' if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1: emailsent = sendAccountDeletedMessage(res[0][1], res[0][1]) else: output += 'The account id given does not exist.' - + body = [output] if callback: return perform_editaccount(req, userID, mtype='perform_deleteaccount', content=addadminbox(subtitle, body), callback='yes') else: return addadminbox(subtitle, body) def perform_rejectaccount(req, userID, email_user_pattern, limit_to, maxpage, page, callback='yes', confirm=0): """Delete account and send an email to the owner.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) - + res = run_sql("SELECT id, email, password, note FROM user WHERE id=%s" % userID) output = "" subtitle = "" if res: res2 = run_sql("DELETE FROM user WHERE id=%s" % userID) output += 'Account rejected and deleted.' if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1: if not res[0][3] or res[0][3] == "0": emailsent = sendAccountRejectedMessage(res[0][1], res[0][1]) elif res[0][3] == "1": emailsent = sendAccountDeletedMessage(res[0][1], res[0][1]) - if emailsent: + if emailsent: output += """
An email has been sent to the owner of the account.""" else: output += """
Could not send an email to the owner of the account.""" else: output += 'The account id given does not exist.' body = [output] if callback: return perform_modifyaccounts(req, email_user_pattern, limit_to, maxpage, page, content=output, callback='yes') else: return addadminbox(subtitle, body) - + def perform_modifyaccounts(req, email_user_pattern='', limit_to=-1, maxpage=MAXPAGEUSERS, page=1, content='', callback='yes', confirm=0): """Modify default behaviour of a guest user or if new accounts should automatically/manually be modified.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = """4. Edit accounts.   [?]""" % weburl output = "" # remove letters not allowed in an email email_user_pattern = cleanstring_email(email_user_pattern) try: maxpage = int(maxpage) except: maxpage = MAXPAGEUSERS try: page = int(page) if page < 1: page = 1 except: page = 1 - + text = ' Email (part of):\n' text += '
' % (email_user_pattern, ) - + text += """Limit to:
""" % ((limit_to=="all" and "selected" or ""), (limit_to=="enabled" and "selected" or ""), (limit_to=="disabled" and "selected" or "")) text += """Accounts per page:
""" % ((maxpage==25 and "selected" or ""), (maxpage==50 and "selected" or ""), (maxpage==100 and "selected" or ""), (maxpage==250 and "selected" or ""), (maxpage==500 and "selected" or ""), (maxpage==1000 and "selected" or "")) output += createhiddenform(action="modifyaccounts", text=text, button="search for accounts") if limit_to not in [-1, "-1"] and maxpage: users1 = "SELECT id,email,note FROM user WHERE " if limit_to == "enabled": users1 += " email!='' AND note=1" elif limit_to == "disabled": users1 += " email!='' AND note=0 OR note IS NULL" elif limit_to == "guest": users1 += " email=''" else: users1 += " email!=''" if email_user_pattern: users1 += " AND email RLIKE '%s'" % (email_user_pattern) users1 += " ORDER BY email LIMIT %s" % (maxpage * page + 1) users1 = run_sql(users1) if not users1: output += 'There are no accounts matching the email given.' - else: + else: users = [] if maxpage * (page - 1) > len(users1): - page = len(users1) / maxpage + 1 + page = len(users1) / maxpage + 1 for (id, email, note) in users1[maxpage * (page - 1):(maxpage * page)]: users.append(['', id, email, (note=="1" and 'Active' or 'Inactive')]) - for col in [(((note=="1" and 'Inactivate' or 'Activate'), 'modifyaccountstatus'), ((note == "0" and 'Reject' or 'Delete'), 'rejectaccount'), ), + for col in [(((note=="1" and 'Inactivate' or 'Activate'), 'modifyaccountstatus'), ((note == "0" and 'Reject' or 'Delete'), 'rejectaccount'), ), (('Edit account', 'editaccount'), ),]: - users[-1].append('%s' % (col[0][1], id, email_user_pattern, limit_to, maxpage, page, random.randint(0,1000), col[0][0])) + users[-1].append('%s' % (col[0][1], id, email_user_pattern, limit_to, maxpage, page, random.randint(0, 1000), col[0][0])) for (str, function) in col[1:]: - users[-1][-1] += ' / %s' % (function, id, email_user_pattern, limit_to, maxpage, page, random.randint(0,1000), str) - + users[-1][-1] += ' / %s' % (function, id, email_user_pattern, limit_to, maxpage, page, random.randint(0, 1000), str) + last = "" next = "" if len(users1) > maxpage: if page > 1: last += 'Last Page' % (email_user_pattern, limit_to, maxpage, (page - 1)) if len(users1[maxpage * (page - 1):(maxpage * page)]) == maxpage: next += 'Next page' % (email_user_pattern, limit_to, maxpage, (page + 1)) output += 'Showing accounts %s-%s:' % (1 + maxpage * (page - 1), maxpage * page) else: output += '%s matching account(s):' % len(users1) - output += tupletotable(header=[last, 'id', 'email', 'Status', '', '',next], tuple=users) + output += tupletotable(header=[last, 'id', 'email', 'Status', '', '', next], tuple=users) else: output += 'Please select which accounts to find and how many to show per page.' - + if content: output += "
%s" % content - + body = [output] if callback: return perform_manageaccounts(req, "perform_modifyaccounts", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_delegate_startarea(req): """start area for lower level delegation of rights.""" # refuse access to guest users: uid = getUid(req) if isGuestUser(uid): return index(req=req, title='Delegate Rights', adminarea=0, authorized=0) subtitle = 'select what to do' output = '' - + if is_adminuser(req)[0] == 0: output += """

You are also allowed to be in the Main Admin Area which gives you
the access to the full functionality of WebAccess.

""" output += """
Connect users to roles
add users to the roles you have delegation rights to.
Remove users from roles
remove users from the roles you have delegation rights to.
Set up delegation rights
specialized area to set up the delegation rights used in the areas above.
you need to be a web administrator to access the area.
""" - + return index(req=req, title='Delegate Rights', - subtitle=subtitle, + subtitle=subtitle, body=[output], adminarea=0, authorized=1) def perform_delegate_adminsetup(req, id_role_admin=0, id_role_delegate=0, confirm=0): """lets the webadmins set up the delegation rights for the other roles id_role_admin - the role to be given delegation rights id_role_delegate - the role over which the delegation rights are given confirm - make the connection happen """ subtitle = 'step 1 - select admin role' admin_roles = acca.acc_getAllRoles() output = """

This is a specialized area to handle a task that also can be handled
from the "add authorization" interface.

By handling the delegation rights here you get the advantage of
not having to select the correct action (%s) or
remembering the names of available roles.

""" % (DELEGATEADDUSERROLE, ) - + output += createroleselect(id_role=id_role_admin, step=1, button='select admin role', name='id_role_admin', action='delegate_adminsetup', roles=admin_roles) if str(id_role_admin) != '0': subtitle = 'step 2 - select delegate role' name_role_admin = acca.acc_getRoleName(id_role=id_role_admin) delegate_roles_old = acca.acc_find_delegated_roles(id_role_admin=id_role_admin) - + delegate_roles = [] delegate_roles_old_names = [] for role in admin_roles: if (role,) not in delegate_roles_old: delegate_roles.append(role) else: delegate_roles_old_names.append(role[1]) if delegate_roles_old_names: delegate_roles_old_names.sort() names_str = '' for name in delegate_roles_old_names: if names_str: names_str += ', ' names_str += name output += '

previously selected roles: %s.

' % (names_str, ) extra = """
Remove delegated roles
use the standard administration area to remove delegation rights you no longer want to be available.
""" % (id_role_admin, acca.acc_getActionId(name_action=DELEGATEADDUSERROLE)) else: output += '

no previously selected roles.

' output += createroleselect(id_role=id_role_delegate, step=2, button='select delegate role', name='id_role_delegate', action='delegate_adminsetup', roles=delegate_roles, id_role_admin=id_role_admin) if str(id_role_delegate) != '0': subtitle = 'step 3 - confirm to add delegation right' - + name_role_delegate = acca.acc_getRoleName(id_role=id_role_delegate) output += """

Warning: don't hand out delegation rights that can harm the system (e.g. delegating superrole).

""" output += createhiddenform(action="delegate_adminsetup", text='let role %s delegate rights over role %s?' % (name_role_admin, name_role_delegate), id_role_admin=id_role_admin, id_role_delegate=id_role_delegate, confirm=1) if int(confirm): subtitle = 'step 4 - confirm delegation right added' # res1 = acca.acc_addRoleActionArguments_names(name_role=name_role_admin, # name_action=DELEGATEADDUSERROLE, # arglistid=-1, # optional=0, # role=name_role_delegate) res1 = acca.acc_addAuthorization(name_role=name_role_admin, name_action=DELEGATEADDUSERROLE, optional=0, role=name_role_delegate) if res1: output += '

confirm: role %s delegates role %s.' % (name_role_admin, name_role_delegate) - + else: output += '

sorry, delegation right could not be added,
it probably already exists.

' # see if right hand menu is available try: body = [output, extra] except NameError: body = [output] - + return index(req=req, title='Delegate Rights', - subtitle=subtitle, + subtitle=subtitle, body=body, adminarea=1) def perform_delegate_adduserrole(req, id_role=0, email_user_pattern='', id_user=0, confirm=0): """let a lower level web admin add users to a limited set of roles. id_role - the role to connect to a user id_user - the user to connect to a role confirm - make the connection happen """ # finding the allowed roles for this user id_admin = getUid(req) - id_action = acca.acc_getActionId(name_action=DELEGATEADDUSERROLE) + id_action = acca.acc_getActionId(name_action=DELEGATEADDUSERROLE) actions = acca.acc_findPossibleActionsUser(id_user=id_admin, id_action=id_action) allowed_roles = [] allowed_id_roles = [] for (id, arglistid, name_role_help) in actions[1:]: id_role_help = acca.acc_getRoleId(name_role=name_role_help) if id_role_help and [id_role_help, name_role_help, ''] not in allowed_roles: allowed_roles.append([id_role_help, name_role_help, '']) allowed_id_roles.append(str(id_role_help)) - + output = '' if not allowed_roles: subtitle = 'no delegation rights' output += """

You do not have the delegation rights over any roles.
If you think you should have such rights, contact a WebAccess Administrator.

""" extra = '' else: subtitle = 'step 1 - select role' output += """

Lower level delegation of access rights to roles.
An administrator with all rights have to give you these rights.

""" email_out = acca.acc_getUserEmail(id_user=id_user) name_role = acca.acc_getRoleName(id_role=id_role) output += createroleselect(id_role=id_role, step=1, name='id_role', action='delegate_adduserrole', roles=allowed_roles) if str(id_role) != '0' and str(id_role) in allowed_id_roles: subtitle = 'step 2 - search for users' # remove letters not allowed in an email email_user_pattern = cleanstring_email(email_user_pattern) - + text = ' 2. search for user \n' text += ' \n' % (email_user_pattern, ) - + output += createhiddenform(action="delegate_adduserrole", text=text, button="search for users", id_role=id_role) - + # pattern is entered if email_user_pattern: # users with matching email-address users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email """ % (email_user_pattern, )) # users that are connected users2 = run_sql("""SELECT DISTINCT u.id, u.email FROM user u LEFT JOIN user_accROLE ur ON u.id = ur.id_user WHERE ur.id_accROLE = '%s' AND u.email RLIKE '%s' ORDER BY u.email """ % (id_role, email_user_pattern)) - + # no users that match the pattern if not (users1 or users2): output += '

no qualified users, try new search.

' # too many matching users elif len(users1) > MAXSELECTUSERS: output += '

%s hits, too many qualified users, specify more narrow search. (limit %s)

' % (len(users1), MAXSELECTUSERS) # show matching users else: subtitle = 'step 3 - select a user' - + users = [] extrausers = [] for (id, email) in users1: if (id, email) not in users2: users.append([id,email,'']) for (id, email) in users2: extrausers.append([-id, email,'']) output += createuserselect(id_user=id_user, action="delegate_adduserrole", step=3, users=users, extrausers=extrausers, button="add this user", id_role=id_role, email_user_pattern=email_user_pattern) - + try: id_user = int(id_user) except ValueError: pass # user selected already connected to role if id_user < 0: output += '

users in brackets are already attached to the role, try another one...

' # a user is selected elif email_out: subtitle = "step 4 - confirm to add user" - + output += createhiddenform(action="delegate_adduserrole", text='add user %s to role %s?' % (email_out, name_role), id_role=id_role, email_user_pattern=email_user_pattern, id_user=id_user, confirm=1) - + # it is confirmed that this user should be added if confirm: # add user result = acca.acc_addUserRole(id_user=id_user, id_role=id_role) - - if result and result[2]: + + if result and result[2]: subtitle = 'step 5 - confirm user added' output += '

confirm: user %s added to role %s.

' % (email_out, name_role) else: subtitle = 'step 5 - user could not be added' output += '

sorry, but user could not be added.

' extra = """
Remove users from role
remove users from the roles you have delegating rights to.
""" % (id_role, ) return index(req=req, title='Connect users to roles', - subtitle=subtitle, + subtitle=subtitle, body=[output, extra], adminarea=1, authorized=1) def perform_delegate_deleteuserrole(req, id_role=0, id_user=0, confirm=0): """let a lower level web admin remove users from a limited set of roles. id_role - the role to connect to a user id_user - the user to connect to a role confirm - make the connection happen """ subtitle = 'in progress...' output = '

in progress...

' # finding the allowed roles for this user id_admin = getUid(req) id_action = acca.acc_getActionId(name_action=DELEGATEADDUSERROLE) actions = acca.acc_findPossibleActionsUser(id_user=id_admin, id_action=id_action) output = '' if not actions: subtitle = 'no delegation rights' output += """

You do not have the delegation rights over any roles.
If you think you should have such rights, contact a WebAccess Administrator.

""" extra = '' else: subtitle = 'step 1 - select role' output += """

Lower level delegation of access rights to roles.
An administrator with all rights have to give you these rights.

""" email_out = acca.acc_getUserEmail(id_user=id_user) name_role = acca.acc_getRoleName(id_role=id_role) # create list of allowed roles allowed_roles = [] allowed_id_roles = [] for (id, arglistid, name_role_help) in actions[1:]: id_role_help = acca.acc_getRoleId(name_role=name_role_help) if id_role_help and [id_role_help, name_role_help, ''] not in allowed_roles: allowed_roles.append([id_role_help, name_role_help, '']) allowed_id_roles.append(str(id_role_help)) - + output += createroleselect(id_role=id_role, step=1, action='delegate_deleteuserrole', roles=allowed_roles) if str(id_role) != '0' and str(id_role) in allowed_id_roles: subtitle = 'step 2 - select user' users = acca.acc_getRoleUsers(id_role) output += createuserselect(id_user=id_user, step=2, action='delegate_deleteuserrole', users=users, id_role=id_role) if str(id_user) != '0': subtitle = 'step 3 - confirm delete of user' email_user = acca.acc_getUserEmail(id_user=id_user) - + output += createhiddenform(action="delegate_deleteuserrole", text='delete user %s from %s?' % (headerstrong(user=id_user), headerstrong(role=id_role)), id_role=id_role, id_user=id_user, confirm=1) - + if confirm: res = acca.acc_deleteUserRole(id_user=id_user, id_role=id_role) if res: subtitle = 'step 4 - confirm user deleted from role' output += '

confirm: deleted user %s from role %s.

' % (email_user, name_role) else: subtitle = 'step 4 - user could not be deleted' output += 'sorry, but user could not be deleted
user is probably already deleted.' extra = """
Connect users to role
add users to the roles you have delegating rights to.
""" % (id_role, ) return index(req=req, title='Remove users from roles', - subtitle=subtitle, + subtitle=subtitle, body=[output, extra], adminarea=1, authorized=1) def perform_addaction(req, name_action='', arguments='', optional='no', description='put description here.', confirm=0): """form to add a new action with these values: name_action - name of the new action arguments - allowedkeywords, separated by whitespace description - optional description of the action""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) name_action = cleanstring(name_action) arguments = cleanstring(arguments, comma=1) title = 'Add Action' subtitle = 'step 1 - give values to the requested fields' output = """
action name -
+
arguments - + keywords for arguments, separate with comma, no whitespace.
optional arguments
description - +
""" % (name_action, arguments, optional == 'yes' and 'selected="selected"' or '', description) if name_action: # description must be changed before it is submitted if description == 'put description here.': internaldesc = '' else: internaldesc = description - + if arguments: subtitle = 'step 2 - confirm to add action with %s arguments' % (optional == 'yes' and 'optional' or '', ) arguments = arguments.replace(' ', '') text = 'add action with:
\n' text += 'name: %s
\n' % (name_action, ) if internaldesc: text += 'description: %s
\n' % (description, ) text += '%sarguments: %s
' % (optional == 'yes' and 'optional ' or '', arguments) text += 'optional: %s?' % (optional, ) - + else: optional = 'no' subtitle = 'step 2 - confirm to add action without arguments' text = 'add action %s without arguments' % (name_action, ) if internaldesc: text += '
\nand description: %s?\n' % (description, ) else: text += '?\n' - + output += createhiddenform(action="addaction", text=text, name_action=name_action, arguments=arguments, - optional=optional, + optional=optional, description=description, confirm=1) if confirm not in ["0", 0]: arguments = arguments.split(',') result = acca.acc_addAction(name_action, internaldesc, optional, *arguments) if result: subtitle = 'step 3 - action added' output += '

action added:

' output += tupletotable(header=['id', 'action name', 'description', 'allowedkeywords', 'optional'], tuple=[result]) else: subtitle = 'step 3 - action could not be added' output += '

sorry, could not add action,
action with the same name probably exists.

' - + extra = """
Add authorization
start adding new authorizations to action %s.
""" % (acca.acc_getActionId(name_action=name_action), name_action) try: body = [output, extra] except NameError: body = [output] return index(req=req, title=title, body=body, subtitle=subtitle, adminarea=4) def perform_deleteaction(req, id_action="0", confirm=0): """show all roles connected, and ask for confirmation. id_action - id of action to delete """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) title='Delete action' subtitle='step 1 - select action to delete' name_action = acca.acc_getActionName(id_action=id_action) output = createactionselect(id_action=id_action, action="deleteaction", step=1, actions=acca.acc_getAllActions(), button="delete action") if id_action != "0" and name_action: subtitle = 'step 2 - confirm the delete' output += actiondetails(id_action=id_action) if acca.acc_getActionRoles(id_action=id_action): output += createhiddenform(action="deleteroleaction", text="""rather delete only connection between action %s and a selected role?""" % (name_action, ), id_action=id_action, reverse=1, button='go there') - + output += createhiddenform(action="deleteaction", text=' delete action %s and all connections?' % (name_action, ), confirm=1, id_action=id_action) - + if confirm: subtitle = 'step 3 - confirm delete of action' res = acca.acc_deleteAction(id_action=id_action) if res: output += '

confirm: action %s deleted.
\n' % (name_action, ) output += '%s entries deleted all in all.

\n' % (res, ) else: output += '

sorry, action could not be deleted.

\n' elif id_action != "0": output += '

the action has been deleted...

' - + return index(req=req, title=title, subtitle=subtitle, body=[output], adminarea=4) def perform_showactiondetails(req, id_action): """show the details of an action. """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) output = createactionselect(id_action=id_action, action="showactiondetails", step=1, actions=acca.acc_getAllActions(), button="select action") if id_action not in [0, '0']: output += actiondetails(id_action=id_action) extra = """
Add new authorization
add an authorization.
Modify authorizations
modify existing authorizations.
Remove role
remove all authorizations from action and a role.
""" % (id_action, id_action, id_action) body = [output, extra] - + else: output += '

no details to show

' body = [output] return index(req=req, title='Show Action Details', subtitle='show action details', body=body, adminarea=4) def actiondetails(id_action=0): """show details of given action. """ output = '' if id_action not in [0, '0']: name_action = acca.acc_getActionName(id_action=id_action) output += '

action details:

' output += tupletotable(header=['id', 'name', 'description', 'allowedkeywords', 'optional'], tuple=[acca.acc_getActionDetails(id_action=id_action)]) - + roleshlp = acca.acc_getActionRoles(id_action=id_action) - if roleshlp: + if roleshlp: roles = [] for (id, name, dontcare) in roleshlp: roles.append([id, name, 'show authorization details' % (id, id_action), 'show connected users' % (id, )]) roletable = tupletotable(header=['id', 'name', '', ''], tuple=roles) - + output += '

roles connected to %s:

\n' % (headerstrong(action=name_action, query=0), ) output += roletable - + else: output += '

no roles connected to %s.

\n' % (headerstrong(action=name_action, query=0), ) else: output += '

no details to show

' - + return output -def perform_addrole(req, name_role='', description='put description here.', confirm=0): +def perform_addrole(req, id_role=0, name_role='', description='put description here.', firerole_def_src=CFG_ACC_EMPTY_ROLE_DEFINITION_SRC, confirm=0): """form to add a new role with these values: - + name_role - name of the new role description - optional description of the role """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) name_role = cleanstring(name_role) title='Add Role' subtitle = 'step 1 - give values to the requested fields' output = """
role name -
+
description - +
+ firewall like role definition +
+ For a help on writing definition, please, see the help page.
- """ % (name_role, description) - + """ % (escape(name_role, '"'), escape(description), escape(firerole_def_src)) + if name_role: # description must be changed before submitting subtitle = 'step 2 - confirm to add role' internaldesc = '' if description != 'put description here.': internaldesc = description - - text = """ - add role with:
\n - name: %s
""" % (name_role, ) - if internaldesc: - text += 'description: %s?\n' % (description, ) - - output += createhiddenform(action="addrole", - text=text, - name_role=name_role, - description=description, - confirm=1) - - if confirm not in ["0", 0]: - result = acca.acc_addRole(name_role=name_role, - description=internaldesc) - - if result: - subtitle = 'step 3 - role added' - output += '

role added:

' - output += tupletotable(header=['id', 'action name', 'description', 'allowedkeywords'], - tuple=[result]) - else: - subtitle = 'step 3 - role could not be added' - output += '

sorry, could not add role,
role with the same name probably exists.

' - id_role = acca.acc_getRoleId(name_role=name_role) - extra = """ -
-
Add authorization
-
start adding new authorizations to role %s.
-
-
Connect user
-
connect a user to role %s.
-
-
""" % (id_role, name_role, id_role, name_role) + try: + firerole_def_ser = compile_role_definition(firerole_def_src) + except WebAccessFireroleError, msg: + output += "%s" % msg + else: + text = """ + add role with:
\n + name: %s
""" % (name_role, ) + if internaldesc: + text += 'description: %s?\n' % (description, ) + + output += createhiddenform(action="addrole", + text=text, + name_role=escape(name_role, '"'), + description=escape(description, '"'), + firerole_def_src=escape(firerole_def_src, '"'), + confirm=1) + + if confirm not in ["0", 0]: + result = acca.acc_addRole(name_role=name_role, + description=internaldesc, + firerole_def_ser=firerole_def_ser, + firerole_def_src=firerole_def_src) + + if result: + subtitle = 'step 3 - role added' + output += '

role added:

' + output += tupletotable(header=['id', 'role name', 'description', 'firewall like role definition'], + tuple=result) + else: + subtitle = 'step 3 - role could not be added' + output += '

sorry, could not add role,
role with the same name probably exists.

' + + id_role = acca.acc_getRoleId(name_role=name_role) + extra = """ +
+
Add authorization
+
start adding new authorizations to role %s.
+
+
Connect user
+
connect a user to role %s.
+
+
""" % (id_role, name_role, id_role, name_role) try: body = [output, extra] except NameError: body = [output] return index(req=req, title=title, body=body, subtitle=subtitle, adminarea=3) +def perform_modifyrole(req, id_role='0', name_role='', description='put description here.', firerole_def_src='', modified='0', confirm=0): + """form to add a new role with these values: + + name_role - name of the role to be changed + + description - optional description of the role + + firerole_def_src - optional firerole like definition of the role + """ + + (auth_code, auth_message) = is_adminuser(req) + if auth_code != 0: return mustloginpage(req, auth_message) + + ret = acca.acc_getRoleDetails(id_role) + if ret and modified =='0': + name_role = ret[1] + description = ret[2] + firerole_def_src = ret[3] + + name_role = cleanstring(name_role) + + title='Modify Role' + subtitle = 'step 1 - give values to the requested fields and confirm to modify role' + + output = """ +
+ + role name +
+ description +
+ firewall like role definition +
+ For a help on writing definition, please, see the help page.
+ + +
+ """ % (id_role, escape(name_role), description, firerole_def_src) + + if modified in [1, '1']: + # description must be changed before submitting + internaldesc = '' + if description != 'put description here.': + internaldesc = description + + text = """ + modify role with:
\n + name: %s
""" % (name_role, ) + if internaldesc: + text += 'description: %s?
' % (description, ) + text += 'firewall like role definition: %s' % firerole_def_src.replace('\n', '
') + + try: + firerole_def_ser = compile_role_definition(firerole_def_src) + except WebAccessFireroleError, msg: + subtitle = 'step 2 - role could not be modified' + output += '

sorry, could not modify role because of troubles with its definition:
%s

' % msg + else: + output += createhiddenform(action="modifyrole", + text=text, + id_role = id_role, + name_role=escape(name_role), + description=escape(description), + firerole_def_src=escape(firerole_def_src), + modified=1, + confirm=1) + if confirm not in ["0", 0]: + result = acca.acc_updateRole(id_role, name_role=name_role, + description=internaldesc, firerole_def_ser=firerole_def_ser, firerole_def_src=firerole_def_src) + + if result: + subtitle = 'step 2 - role modified' + output += '

role modified:

' + output += tupletotable(header=['id', 'role name', + 'description', 'firewall like role definition'], + tuple=((id_role, name_role, description, firerole_def_src))) + else: + subtitle = 'step 2 - role could not be modified' + output += '

sorry, could not modify role,
please contact the administrator.

' + + + body = [output] + + return index(req=req, + title=title, + body=body, + subtitle=subtitle, + adminarea=3) + + def perform_deleterole(req, id_role="0", confirm=0): """select a role and show all connected information, users - users that can access the role. actions - actions with possible authorizations.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) title = 'Delete role' subtitle = 'step 1 - select role to delete' name_role = acca.acc_getRoleName(id_role=id_role) output = createroleselect(id_role=id_role, action="deleterole", step=1, roles=acca.acc_getAllRoles(), button="delete role") if id_role != "0" and name_role: subtitle = 'step 2 - confirm delete of role' output += roledetails(id_role=id_role) output += createhiddenform(action="deleterole", text='delete role %s and all connections?' % (name_role, ), id_role=id_role, confirm=1) if confirm: res = acca.acc_deleteRole(id_role=id_role) subtitle = 'step 3 - confirm role deleted' if res: output += "

confirm: role %s deleted.
" % (name_role, ) output += "%s entries were removed.

" % (res, ) else: output += "

sorry, the role could not be deleted.

" elif id_role != "0": output += '

the role has been deleted...

' return index(req=req, title=title, - subtitle=subtitle, + subtitle=subtitle, body=[output], adminarea=3) def perform_showroledetails(req, id_role): """show the details of a role.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) output = createroleselect(id_role=id_role, action="showroledetails", step=1, roles=acca.acc_getAllRoles(), button="select role") if id_role not in [0, '0']: name_role = acca.acc_getRoleName(id_role=id_role) - + output += roledetails(id_role=id_role) - + extra = """
+
Modify role
+
modify the role you are seeing
Add new authorization
add an authorization.
Modify authorizations
modify existing authorizations.
Connect user
connect a user to role %s.
Remove user
remove a user from role %s.
- """ % (id_role, id_role, id_role, name_role, id_role, name_role) + """ % (id_role, id_role, id_role, id_role, name_role, id_role, name_role) body = [output, extra] - + else: output += '

no details to show

' body = [output] - + return index(req=req, title='Show Role Details', subtitle='show role details', body=body, adminarea=3) def roledetails(id_role=0): """create the string to show details about a role. """ name_role = acca.acc_getRoleName(id_role=id_role) usershlp = acca.acc_getRoleUsers(id_role) users = [] for (id, email, dontcare) in usershlp: users.append([id, email, 'show user details' % (id, )]) usertable = tupletotable(header=['id', 'email'], tuple=users) - + actionshlp = acca.acc_getRoleActions(id_role) actions = [] for (id, name, dontcare) in actionshlp: actions.append([id, name, 'show action details' % (id_role, id), 'show authorization details' % (id_role, id)]) - + actiontable = tupletotable(header=['id', 'name', '', ''], tuple=actions) # show role details details = '

role details:

' - details += tupletotable(header=['id', 'name', 'description'], + details += tupletotable(header=['id', 'name', 'description', 'firewall like role definition'], tuple=[acca.acc_getRoleDetails(id_role=id_role)]) # show connected users details += '

users connected to %s:

' % (headerstrong(role=name_role, query=0), ) - if users: + if users: details += usertable else: details += '

no users connected.

' # show connected authorizations details += '

authorizations for %s:

' % (headerstrong(role=name_role, query=0), ) - if actions: + if actions: details += actiontable else: details += '

no authorizations connected

' - return details + return details def perform_adduserrole(req, id_role='0', email_user_pattern='', id_user='0', confirm=0): """create connection between user and role. id_role - id of the role to add user to email_user_pattern - search for users using this pattern id_user - id of user to add to the role. """ - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) email_out = acca.acc_getUserEmail(id_user=id_user) name_role = acca.acc_getRoleName(id_role=id_role) - + title = 'Connect user to role ' subtitle = 'step 1 - select a role' output = createroleselect(id_role=id_role, action="adduserrole", step=1, roles=acca.acc_getAllRoles()) # role is selected if id_role != "0": title += name_role - + subtitle = 'step 2 - search for users' # remove letters not allowed in an email email_user_pattern = cleanstring_email(email_user_pattern) - + text = ' 2. search for user \n' text += ' \n' % (email_user_pattern, ) output += createhiddenform(action="adduserrole", text=text, button="search for users", id_role=id_role) # pattern is entered if email_user_pattern: # users with matching email-address users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email """ % (email_user_pattern, )) # users that are connected users2 = run_sql("""SELECT DISTINCT u.id, u.email FROM user u LEFT JOIN user_accROLE ur ON u.id = ur.id_user WHERE ur.id_accROLE = '%s' AND u.email RLIKE '%s' ORDER BY u.email """ % (id_role, email_user_pattern)) # no users that match the pattern if not (users1 or users2): output += '

no qualified users, try new search.

' elif len(users1) > MAXSELECTUSERS: output += '

%s hits, too many qualified users, specify more narrow search. (limit %s)

' % (len(users1), MAXSELECTUSERS) - + # show matching users else: subtitle = 'step 3 - select a user' - + users = [] extrausers = [] for (id, email) in users1: if (id, email) not in users2: users.append([id,email,'']) for (id, email) in users2: extrausers.append([-id, email,'']) output += createuserselect(id_user=id_user, action="adduserrole", step=3, users=users, extrausers=extrausers, button="add this user", id_role=id_role, email_user_pattern=email_user_pattern) try: id_user = int(id_user) except ValueError: pass # user selected already connected to role if id_user < 0: output += '

users in brackets are already attached to the role, try another one...

' # a user is selected elif email_out: subtitle = "step 4 - confirm to add user" output += createhiddenform(action="adduserrole", text='add user %s to role %s?' % (email_out, name_role), id_role=id_role, email_user_pattern=email_user_pattern, id_user=id_user, confirm=1) # it is confirmed that this user should be added if confirm: # add user result = acca.acc_addUserRole(id_user=id_user, id_role=id_role) - - if result and result[2]: + + if result and result[2]: subtitle = 'step 5 - confirm user added' output += '

confirm: user %s added to role %s.

' % (email_out, name_role) else: subtitle = 'step 5 - user could not be added' output += '

sorry, but user could not be added.

' - + extra = """
Create new role
go here to add a new role.
""" if str(id_role) != "0": extra += """
Remove users
remove users from role %s.
Connected users
show all users connected to role %s.
Add authorization
start adding new authorizations to role %s.
""" % (id_role, name_role, id_role, name_role, id_role, name_role) return index(req=req, title=title, subtitle=subtitle, body=[output, extra], adminarea=3) def perform_addroleuser(req, email_user_pattern='', id_user='0', id_role='0', confirm=0): """delete connection between role and user. id_role - id of role to disconnect id_user - id of user to disconnect. """ - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) email_out = acca.acc_getUserEmail(id_user=id_user) name_role = acca.acc_getRoleName(id_role=id_role) # used to sort roles, and also to determine right side links con_roles = [] not_roles = [] title = 'Connect user to roles' subtitle = 'step 1 - search for users' # clean email search string email_user_pattern = cleanstring_email(email_user_pattern) - + text = ' 1. search for user \n' text += ' \n' % (email_user_pattern, ) output = createhiddenform(action='addroleuser', text=text, button='search for users', id_role=id_role) - + if email_user_pattern: subtitle = 'step 2 - select user' users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email """ % (email_user_pattern, )) users = [] for (id, email) in users1: users.append([id, email, '']) - # no users + # no users if not users: output += '

no qualified users, try new search.

' # too many users elif len(users) > MAXSELECTUSERS: output += '

%s hits, too many qualified users, specify more narrow search. (limit %s)

' % (len(users), MAXSELECTUSERS) # ok number of users else: output += createuserselect(id_user=id_user, action='addroleuser', step=2, users=users, button='select user', email_user_pattern=email_user_pattern) if int(id_user): subtitle = 'step 3 - select role' # roles the user is connected to role_ids = acca.acc_getUserRoles(id_user=id_user) # all the roles, lists are sorted on the background of these... all_roles = acca.acc_getAllRoles() # sort the roles in connected and not connected roles for (id, name, description) in all_roles: if (id, ) in role_ids: con_roles.append([-id, name, description]) else: not_roles.append([id, name, description]) # create roleselect output += createroleselect(id_role=id_role, action='addroleuser', step=3, roles=not_roles, extraroles=con_roles, - extrastamp='(connected)', + extrastamp='(connected)', button='add this role', email_user_pattern=email_user_pattern, id_user=id_user) if int(id_role) < 0: name_role = acca.acc_getRoleName(id_role=-int(id_role)) output += '

role %s already connected to the user, try another one...

' % (name_role, ) elif int(id_role): subtitle = 'step 4 - confirm to add role to user' output += createhiddenform(action='addroleuser', text='add role %s to user %s?' % (name_role, email_out), email_user_pattern=email_user_pattern, id_user=id_user, id_role=id_role, confirm=1) if confirm: # add role result = acca.acc_addUserRole(id_user=id_user, id_role=id_role) if result and result[2]: subtitle = 'step 5 - confirm role added' output += '

confirm: role %s added to user %s.

' % (name_role, email_out) else: subtitle = 'step 5 - role could not be added' output += '

sorry, but role could not be added

' extra = """
Create new role
go here to add a new role.
""" if int(id_user) and con_roles: extra += """
Remove roles
disconnect roles from user %s.
""" % (id_user, email_out) if int(id_role): if int(id_role) < 0: id_role = -int(id_role) extra += """
Remove users
disconnect users from role %s.
""" % (id_role, name_role) - + return index(req=req, title=title, subtitle=subtitle, body=[output, extra], adminarea=5) def perform_deleteuserrole(req, id_role='0', id_user='0', reverse=0, confirm=0): """delete connection between role and user. id_role - id of role to disconnect id_user - id of user to disconnect. """ - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) title = 'Remove user from role' email_user = acca.acc_getUserEmail(id_user=id_user) name_role = acca.acc_getRoleName(id_role=id_role) output = '' if reverse in [0, '0']: adminarea = 3 subtitle = 'step 1 - select the role' output += createroleselect(id_role=id_role, action="deleteuserrole", step=1, roles=acca.acc_getAllRoles()) - + if id_role != "0": subtitle = 'step 2 - select the user' output += createuserselect(id_user=id_user, action="deleteuserrole", step=2, users=acca.acc_getRoleUsers(id_role=id_role), id_role=id_role) else: adminarea = 5 # show only if user is connected to a role, get users connected to roles users = run_sql("""SELECT DISTINCT(u.id), u.email, u.note FROM user u LEFT JOIN user_accROLE ur ON u.id = ur.id_user WHERE ur.id_accROLE != 'NULL' AND u.email != '' ORDER BY u.email """) has_roles = 1 - + # check if the user is connected to any roles for (id, email, note) in users: if str(id) == str(id_user): break # user not connected to a role else: subtitle = 'step 1 - user not connected' output += '

no need to remove roles from user %s,
user is not connected to any roles.

' % (email_user, ) has_roles, id_user = 0, '0' # stop the rest of the output below... - + # user connected to roles if has_roles: output += createuserselect(id_user=id_user, action="deleteuserrole", step=1, users=users, reverse=reverse) - + if id_user != "0": subtitle = 'step 2 - select the role' - + role_ids = acca.acc_getUserRoles(id_user=id_user) all_roles = acca.acc_getAllRoles() roles = [] for (id, name, desc) in all_roles: if (id, ) in role_ids: roles.append([id, name, desc]) - + output += createroleselect(id_role=id_role, action="deleteuserrole", step=2, roles=roles, id_user=id_user, reverse=reverse) - + if id_role != '0' and id_user != '0': subtitle = 'step 3 - confirm delete of user' output += createhiddenform(action="deleteuserrole", text='delete user %s from %s?' % (headerstrong(user=id_user), headerstrong(role=id_role)), id_role=id_role, id_user=id_user, reverse=reverse, confirm=1) if confirm: res = acca.acc_deleteUserRole(id_user=id_user, id_role=id_role) if res: subtitle = 'step 4 - confirm delete of user' output += '

confirm: deleted user %s from role %s.

' % (email_user, name_role) else: subtitle = 'step 4 - user could not be deleted' output += 'sorry, but user could not be deleted
user is probably already deleted.' extra = '' if str(id_role) != "0": extra += """
Connect user
add users to role %s.
""" % (id_role, name_role) if int(reverse): extra += """
Remove user
remove users from role %s.
""" % (id_role, name_role) extra += '
' if str(id_user) != "0": extra += """
Connect role
add roles to user %s.
""" % (email_user, id_user, email_user) if not int(reverse): extra += """
Remove role
remove roles from user %s.
""" % (id_user, email_user, email_user) extra += '
' if extra: body = [output, extra] else: body = [output] return index(req=req, title=title, subtitle=subtitle, body=body, adminarea=adminarea) def perform_showuserdetails(req, id_user=0): """show the details of a user. """ - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) if id_user not in [0, '0']: output = userdetails(id_user=id_user) email_user = acca.acc_getUserEmail(id_user=id_user) extra = """
Connect role
connect a role to user %s.
Remove role
remove a role from user %s.
""" % (id_user, email_user, email_user, id_user, email_user) body = [output, extra] else: body = ['

no details to show

'] return index(req=req, title='Show User Details', subtitle='show user details', body=body, adminarea=5) def userdetails(id_user=0): """create the string to show details about a user. """ # find necessary details email_user = acca.acc_getUserEmail(id_user=id_user) userroles = acca.acc_getUserRoles(id_user=id_user) conn_roles = [] # find connected roles - for (id, name, desc) in acca.acc_getAllRoles(): + for (id, name, desc, dontcare, dontcare2) in acca.acc_getAllRoles(): if (id, ) in userroles: conn_roles.append([id, name, desc]) conn_roles[-1].append('show details' % (id, )) - if conn_roles: + if conn_roles: # print details details = '

roles connected to user %s

' % (email_user, ) details += tupletotable(header=['id', 'name', 'description', ''], tuple=conn_roles) else: details = '

no roles connected to user %s.

' % (email_user, ) return details def perform_addauthorization(req, id_role="0", id_action="0", optional=0, reverse="0", confirm=0, **keywords): """ form to add new connection between user and role: - id_role - role to connect + id_role - role to connect id_action - action to connect reverse - role or action first? """ - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) # values that might get used name_role = acca.acc_getRoleName(id_role=id_role) or id_role name_action = acca.acc_getActionName(id_action=id_action) or id_action optional = optional == 'on' and 1 or int(optional) - + extra = """
Create new role
go here to add a new role.
Create new action
go here to add a new action.
""" # create the page according to which step the user is on # role -> action -> arguments if reverse in ["0", 0]: adminarea = 3 subtitle = 'step 1 - select role' output = createroleselect(id_role=id_role, action="addauthorization", step=1, roles=acca.acc_getAllRoles(), reverse=reverse) if str(id_role) != "0": subtitle = 'step 2 - select action' rolacts = acca.acc_getRoleActions(id_role) allhelp = acca.acc_getAllActions() allacts = [] for r in allhelp: if r not in rolacts: allacts.append(r) output += createactionselect(id_action=id_action, action="addauthorization", step=2, actions=rolacts, extraactions=allacts, id_role=id_role, reverse=reverse) - + # action -> role -> arguments else: adminarea = 4 subtitle = 'step 1 - select action' output = createactionselect(id_action=id_action, action="addauthorization", step=1, actions=acca.acc_getAllActions(), reverse=reverse) if str(id_action) != "0": subtitle = 'step 2 - select role' actroles = acca.acc_getActionRoles(id_action) allhelp = acca.acc_getAllRoles() allroles = [] for r in allhelp: if r not in actroles: allroles.append(r) output += createroleselect(id_role=id_role, action="addauthorization", step=2, roles=actroles, extraroles=allroles, id_action=id_action, reverse=reverse) # ready for step 3 no matter which direction we took to get here if id_action != "0" and id_role != "0": # links to adding authorizations in the other direction if str(reverse) == "0": extra += """
Add authorization
add authorizations to action %s.
""" % (id_action, name_action) else: extra += """
Add authorization
add authorizations to role %s.
""" % (id_role, name_role) subtitle = 'step 3 - enter values for the keywords\n' output += """
""" % (id_role, id_action, reverse) # the actions argument keywords res_keys = acca.acc_getActionKeywords(id_action=id_action) - + # res used to display existing authorizations # res used to determine if showing "create connection without arguments" res_auths = acca.acc_findPossibleActions(id_role, id_action) - + if not res_keys: # action without arguments if not res_auths: output += """ create connection between %s?
""" % (headerstrong(role=name_role, action=name_action, query=0), ) else: output += '

connection without arguments is already created.

' - + else: # action with arguments optionalargs = acca.acc_getActionIsOptional(id_action=id_action) output += '3. authorized arguments
' if optionalargs: # optional arguments output += """

connect %s to %s for any arguments
connect %s to %s for only these argument cases:

""" % (optional and 'checked="checked"' or '', name_role, name_action, not optional and 'checked="checked"' or '', name_role, name_action) # list the arguments allkeys = 1 for key in res_keys: output += '%s \n \n' output += '\n' # ask for confirmation if str(allkeys) != "0" or optional: keys = keywords.keys() keys.reverse() subtitle = 'step 4 - confirm add of authorization\n' text = """ create connection between
%s
""" % (headerstrong(role=name_role, action=name_action, query=0), ) if optional: text += 'withouth arguments' keywords = {} else: for key in keys: text += '%s: %s \n' % (key, keywords[key]) - + output += createhiddenform(action="addauthorization", text=text, id_role=id_role, id_action=id_action, reverse=reverse, confirm=1, optional=optional, **keywords) # show existing authorizations, found authorizations further up in the code... # res_auths = acca.acc_findPossibleActions(id_role, id_action) output += '

existing authorizations:

' if res_auths: output += tupletotable(header=res_auths[0], tuple=res_auths[1:]) # shortcut to modifying authorizations extra += """
Modify authorizations
modify the existing authorizations.
""" % (id_role, id_action, reverse) else: output += '

no details to show

' # user confirmed to add entries - if confirm: + if confirm: subtitle = 'step 5 - confirm authorization added' res1 = acca.acc_addAuthorization(name_role=name_role, name_action=name_action, optional=optional, **keywords) if res1: res2 = acca.acc_findPossibleActions(id_role, id_action) arg = res1[0][3] # the arglistid new = [res2[0]] for row in res2[1:]: if int(row[0]) == int(arg): new.append(row) - + newauths = tupletotable(header=new[0], tuple=new[1:]) newentries = tupletotable(header=['role id', 'action id', 'argument id', '#'], tuple=res1) st = 'style="vertical-align: top"' output += """

new authorization and entries:

%s %s
""" % (st, newauths, st, newentries) else: output += '

sorry, authorization could not be added,
it probably already exists

' # trying to put extra link on the right side try: body = [output, extra] except NameError: body = [output] return index(req=req, title = 'Create entry for new authorization', subtitle=subtitle, body=body, adminarea=adminarea) def perform_deleteroleaction(req, id_role="0", id_action="0", reverse=0, confirm=0): """delete all connections between a role and an action. id_role - id of the role id_action - id of the action reverse - 0: ask for role first 1: ask for action first""" - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) title = 'Remove action from role ' - + if reverse in ["0", 0]: # select role -> action adminarea = 3 subtitle = 'step 1 - select a role' output = createroleselect(id_role=id_role, action="deleteroleaction", step=1, roles=acca.acc_getAllRoles(), reverse=reverse) - + if id_role != "0": rolacts = acca.acc_getRoleActions(id_role=id_role) subtitle = 'step 2 - select the action' output += createactionselect(id_action=id_action, action="deleteroleaction", step=2, actions=rolacts, reverse=reverse, id_role=id_role, button="remove connection and all authorizations") else: # select action -> role adminarea = 4 subtitle = 'step 1 - select an action' output = createactionselect(id_action=id_action, action="deleteroleaction", step=1, actions=acca.acc_getAllActions(), reverse=reverse) - + if id_action != "0": actroles = acca.acc_getActionRoles(id_action=id_action) subtitle = 'step 2 - select the role' output += createroleselect(id_role=id_role, action="deleteroleaction", step=2, roles=actroles, - button="remove connection and all authorizations", + button="remove connection and all authorizations", id_action=id_action, reverse=reverse) if id_action != "0" and id_role != "0": subtitle = 'step 3 - confirm to remove authorizations' # ask for confirmation res = acca.acc_findPossibleActions(id_role, id_action) if res: output += '

authorizations that will be deleted:

' output += tupletotable(header=res[0], tuple=res[1:]) output += createhiddenform(action="deleteroleaction", text='remove %s from %s' % (headerstrong(action=id_action), headerstrong(role=id_role)), confirm=1, id_role=id_role, id_action=id_action, reverse=reverse) else: output += 'no authorizations' # confirmation is given - if confirm: + if confirm: subtitle = 'step 4 - confirm authorizations removed ' res = acca.acc_deleteRoleAction(id_role=id_role, id_action=id_action) if res: output += '

confirm: removed %s from %s
' % (headerstrong(action=id_action), headerstrong(role=id_role)) output += '%s entries were removed.

' % (res, ) else: output += '

sorry, no entries could be removed.

' - + return index(req=req, title=title, subtitle=subtitle, body=[output], adminarea=adminarea) - + def perform_modifyauthorizations(req, id_role="0", id_action="0", reverse=0, confirm=0, errortext='', sel='', authids=[]): """given ids of a role and an action, show all possible action combinations - with checkboxes and allow user to access other functions. + with checkboxes and allow user to access other functions. id_role - id of the role id_action - id of the action reverse - 0: ask for role first 1: ask for action first sel - which button and modification that is selected - + errortext - text to print when no connection exist between role and action - + authids - ids of checked checkboxes """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) name_role = acca.acc_getRoleName(id_role) name_action = acca.acc_getActionName(id_action) output = '' - + try: id_role, id_action, reverse = int(id_role), int(id_action), int(reverse) except ValueError: pass extra = """
Create new role
go here to add a new role.
Create new action
go here to add a new action.
""" if id_role or id_action: extra += '\n
\n' if id_role and id_action: extra += """
Add authorizations
add an authorization to the existing ones.
""" % (id_role, id_action, reverse) if id_role: extra += """
Add authorizations
add to role %s.
""" % (id_role, name_role) if id_action: extra += """
Add authorizations
add to action %s.
""" % (id_action, name_action) extra += '\n
\n' - + if not reverse: # role -> action adminarea = 3 subtitle = 'step 1 - select the role' output += createroleselect(id_role=str(id_role), action="modifyauthorizations", step=1, roles=acca.acc_getAllRoles(), reverse=reverse) if id_role: rolacts = acca.acc_getRoleActions(id_role=id_role) subtitle = 'step 2 - select the action' output += createactionselect(id_action=str(id_action), action="modifyauthorizations", step=2, actions=rolacts, id_role=id_role, reverse=reverse) else: adminarea = 4 # action -> role subtitle = 'step 1 - select the action' output += createactionselect(id_action=str(id_action), action="modifyauthorizations", step=1, actions=acca.acc_getAllActions(), reverse=reverse) if id_action: actroles = acca.acc_getActionRoles(id_action=id_action) subtitle = 'step 2 - select the role' output += createroleselect(id_role=str(id_role), action="modifyauthorizations", step=2, roles=actroles, id_action=id_action, reverse=reverse) if errortext: output += '

%s

' % (errortext, ) if id_role and id_action: # adding to main area if type(authids) is not list: authids = [authids] subtitle = 'step 3 - select groups and modification' - # get info + # get info res = acca.acc_findPossibleActions(id_role, id_action) # clean the authids hiddenids = [] if sel in ['delete selected']: hiddenids = authids[:] elif sel in ['split groups', 'merge groups']: for authid in authids: arghlp = res[int(authid)][0] if authid not in hiddenids and arghlp not in [-1, '-1', 0, '0']: hiddenids.append(authid) authids = hiddenids[:] - + if confirm: # do selected modification and output with new authorizations if sel == 'split groups': res = splitgroups(id_role, id_action, authids) elif sel == 'merge groups': res = mergegroups(id_role, id_action, authids) elif sel == 'delete selected': res = deleteselected(id_role, id_action, authids) authids = [] res = acca.acc_findPossibleActions(id_role, id_action) output += 'authorizations after %s.
\n' % (sel, ) elif sel and authids: output += 'confirm choice of authorizations and modification.
\n' else: output += 'select authorizations and perform modification.
\n' - + if not res: errortext='all connections deleted, try different ' if reverse in ["0", 0]: return perform_modifyauthorizations(req=req, id_role=id_role, errortext=errortext + 'action.') else: return perform_modifyauthorizations(req=req, id_action=id_action, reverse=reverse, errortext=errortext + 'role.') - - # display + + # display output += modifyauthorizationsmenu(id_role, id_action, header=res[0], tuple=res[1:], checked=authids, reverse=reverse) - + if sel and authids: subtitle = 'step 4 - confirm to perform modification' # form with hidden authids output += '
\n' % ('modifyauthorizations', ) - for hiddenid in hiddenids: + for hiddenid in hiddenids: output += '\n' % (hiddenid, ) # choose what to do if sel == 'split groups': output += '

split groups containing:

' - elif sel == 'merge groups': + elif sel == 'merge groups': output += '

merge groups containing:

' - elif sel == 'delete selected': + elif sel == 'delete selected': output += '

delete selected entries:

' extracolumn = '\n' extracolumn += '\n' # show the entries here... output += tupletotable_onlyselected(header=res[0], tuple=res[1:], selected=hiddenids, extracolumn=extracolumn) - + output += '\n' % (id_role, ) output += '\n' % (id_action, ) output += '\n' % (sel, ) output += '\n' % (reverse, ) output += '
' # tried to perform modification without something selected - elif sel and not authids and not confirm: + elif sel and not authids and not confirm: output += '

no valid groups selected

' # trying to put extra link on the right side try: body = [output, extra] except NameError: body = [output] # Display the page return index(req=req, title='Modify Authorizations', subtitle=subtitle, body=body, adminarea=adminarea) def modifyauthorizationsmenu(id_role, id_action, tuple=[], header=[], checked=[], reverse=0): """create table with header and checkboxes, used for multiple choice. makes use of tupletotable to add the actual table id_role - selected role, hidden value in the form id_action - selected action, hidden value in the form tuple - all rows to be put in the table (with checkboxes) header - column headers, empty strings added at start and end checked - ids of rows to be checked """ if not tuple: return 'no authorisations...' argnum = len(acca.acc_getActionKeywords(id_action=id_action)) - + tuple2 = [] for t in tuple: tuple2.append(t[:]) - + tuple2 = addcheckboxes(datalist=tuple2, name='authids', startindex=1, checked=checked) hidden = ' \n' % (id_role, ) hidden += ' \n' % (id_action, ) hidden += ' \n' % (reverse, ) - + button = '\n' - if argnum > 1: + if argnum > 1: button += '\n' button += '\n' - + hdrstr = '' for h in [''] + header + ['']: hdrstr += ' %s\n' % (h, ) if hdrstr: hdrstr = ' \n%s\n \n' % (hdrstr, ) - + output = '
\n' output += ' \n' output += hdrstr output += '\n' % (hidden, ) align = ['admintdleft'] * len(tuple2[0]) try: align[1] = 'admintdright' except IndexError: pass output += '' for i in range(len(tuple2[0])): output += '\n' % (align[i], tuple2[0][i]) output += '\n' % (len(tuple2), button) - + output += '\n' for row in tuple2[1:]: output += ' \n' for i in range(len(row)): output += '\n' % (align[i], row[i]) output += ' \n' output += '
%s
%s\n%s\n
%s
\n
\n' return output def splitgroups(id_role=0, id_action=0, authids=[]): """get all the old ones, gather up the arglistids find a list of arglistidgroups to be split, unique get all actions in groups outside of the old ones, (old arglistid is allowed). - + show them like in showselect. """ if not id_role or not id_action or not authids: return 0 - + # find all the actions datalist = acca.acc_findPossibleActions(id_role, id_action) if type(authids) is str: authids = [authids] for i in range(len(authids)): authids[i] = int(authids[i]) - + # argumentlistids of groups to be split splitgrps = [] for authid in authids: hlp = datalist[authid][0] if hlp not in splitgrps and authid in range(1,len(datalist)): splitgrps.append(hlp) # split groups and return success or failure result = 1 for splitgroup in splitgrps: result = 1 and acca.acc_splitArgumentGroup(id_role, id_action, splitgroup) return result def mergegroups(id_role=0, id_action=0, authids=[]): """get all the old ones, gather up the argauthids find a list of arglistidgroups to be split, unique get all actions in groups outside of the old ones, (old arglistid is allowed). show them like in showselect.""" if not id_role or not id_action or not authids: return 0 - + datalist = acca.acc_findPossibleActions(id_role, id_action) if type(authids) is str: authids = [authids] for i in range(len(authids)): authids[i] = int(authids[i]) - + # argumentlistids of groups to be merged mergegroups = [] for authid in authids: hlp = datalist[authid][0] if hlp not in mergegroups and authid in range(1, len(datalist)): mergegroups.append(hlp) # merge groups and return success or failure if acca.acc_mergeArgumentGroups(id_role, id_action, mergegroups): return 1 else: return 0 def deleteselected(id_role=0, id_action=0, authids=[]): """delete checked authorizations/possible actions, ids in authids. id_role - role to delete from id_action - action to delete from authids - listids for which possible actions to delete.""" - + if not id_role or not id_action or not authids: return 0 if type(authids) in [str, int]: authids = [authids] for i in range(len(authids)): authids[i] = int(authids[i]) - + result = acca.acc_deletePossibleActions(id_role=id_role, id_action=id_action, authids=authids) return result def headeritalic(**ids): """transform keyword=value pairs to string with value in italics. **ids - a dictionary of pairs to create string from """ - + output = '' value = '' table = '' for key in ids.keys(): if key in ['User', 'user']: value, table = 'email', 'user' elif key in ['Role', 'role']: value, table = 'name', 'accROLE' elif key in ['Action', 'action']: value, table = 'name', 'accACTION' else: if output: output += ' and ' output += ' %s %s' % (key, ids[key]) continue - + res = run_sql("""SELECT %s FROM %s WHERE id = %s""" % (value, table, ids[key])) - + if res: if output: output += ' and ' output += ' %s %s' % (key, res[0][0]) return output def headerstrong(query=1, **ids): """transform keyword=value pairs to string with value in strong text. **ids - a dictionary of pairs to create string from - + query - 1 -> try to find names to ids of role, user and action. 0 -> do not try to find names, use the value passed on """ output = '' value = '' table = '' for key in ids.keys(): if key in ['User', 'user']: value, table = 'email', 'user' elif key in ['Role', 'role']: value, table = 'name', 'accROLE' elif key in ['Action', 'action']: value, table = 'name', 'accACTION' else: if output: output += ' and ' output += ' %s %s' % (key, ids[key]) continue if query: res = run_sql("""SELECT %s FROM %s WHERE id = %s""" % (value, table, ids[key])) if res: if output: output += ' and ' output += ' %s %s' % (key, res[0][0]) else: if output: output += ' and ' output += ' %s %s' % (key, ids[key]) return output def startpage(): """create the menu for the startpage""" - + body = """ -
selection for WebAccess Admin
Role Area
main area to configure administration rights and authorization rules.
Action Area
configure administration rights with the actions as starting point.
User Area
configure administration rights with the users as starting point.
Reset Area
reset roles, actions and authorizations.
""" + """ return body def rankarea(): return "Rankmethod area" def perform_simpleauthorization(req, id_role=0, id_action=0): """show a page with simple overview of authorizations between a connected role and action. """ - + (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) res = acca.acc_findPossibleActions(id_role, id_action) if res: extra = createhiddenform(action='modifyauthorizations', button='modify authorizations', id_role=id_role, id_action=id_action) - + output = '

authorizations for %s:

' % (headerstrong(action=id_action, role=id_role), ) output += tupletotable(header=res[0], tuple=res[1:], extracolumn=extra) else: output = 'no details to show' return index(req=req, title='Simple authorization details', - subtitle='simple authorization details', + subtitle='simple authorization details', body=[output], adminarea=3) def perform_showroleusers(req, id_role=0): """show a page with simple overview of a role and connected users. """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) res = acca.acc_getRoleUsers(id_role=id_role) name_role = acca.acc_getRoleName(id_role=id_role) - + if res: users = [] for (id, name, dontcare) in res: users.append([id, name, 'show user details' % (id, )]) output = '

users connected to %s:

' % (headerstrong(role=id_role), ) output += tupletotable(header=['id', 'name', ''], tuple=users) else: output = 'no users connected to role %s' % (name_role, ) extra = """
Connect user
connect users to the role.
""" % (id_role, ) return index(req=req, title='Users connected to role %s' % (name_role, ), - subtitle='simple details', + subtitle='simple details', body=[output, extra], adminarea=3) - + def createselect(id_input="0", label="", step=0, name="", action="", list=[], extralist=[], extrastamp='', button="", **hidden): """create form with select and hidden values id - the one to choose as selected if exists - + label - label shown to the left of the select - + name - the name of the select on which to reference it - + list - primary list to select from - + extralist - list of options to be put in paranthesis - + extrastamp - stamp extralist entries with this if not '' usually paranthesis around the entry - + button - the value/text to be put on the button - + **hidden - name=value pairs to be put as hidden in the form. """ step = step and '%s. ' % step or '' - + output = '
\n' % (action, ) output += ' %s\n' % (step + label, ) output += ' \n' for key in hidden.keys(): output += ' \n' % (key, hidden[key]) output += ' \n' % (button, ) output += '
\n' return output def createactionselect(id_action="0", label="select action", step=0, name="id_action", action="", actions=[], extraactions=[], extrastamp='', button="select action", **hidden): """create a select for roles in a form. see createselect.""" return createselect(id_input=id_action, label=label, step=step, name=name, - action=action, list=actions, extralist=extraactions, extrastamp=extrastamp, + action=action, list=actions, extralist=extraactions, extrastamp=extrastamp, button=button, **hidden) def createroleselect(id_role="0", label="select role", step=0, name="id_role", action="", roles=[], extraroles=[], extrastamp='', button="select role", **hidden): """create a select for roles in a form. see createselect.""" return createselect(id_input=id_role, label=label, step=step, name=name, action=action, list=roles, extralist=extraroles, extrastamp=extrastamp, button=button, **hidden) def createuserselect(id_user="0", label="select user", step=0, name="id_user", - action="", users=[], extrausers=[], extrastamp='(connected)', + action="", users=[], extrausers=[], extrastamp='(connected)', button="select user", **hidden): """create a select for users in a form.see createselect.""" - + return createselect(id_input=id_user, label=label, step=step, name=name, action=action, list=users, extralist=extrausers, extrastamp=extrastamp, button=button, **hidden) def cleanstring(str='', comma=0): """clean all the strings before submitting to access control admin. remove characters not letter, number or underscore, also remove leading underscores and numbers. return cleaned string. str - string to be cleaned comma - 1 -> allow the comma to divide multiple arguments 0 -> wash commas as well """ # remove not allowed characters str = re.sub(r'[^a-zA-Z0-9_,]', '', str) # split string on commas items = str.split(',') str = '' for item in items: if not item: continue if comma and str: str += ',' # create valid variable names str += re.sub(r'^([0-9_])*', '', item) return str def cleanstring_argumentvalue(str=''): """clean the value of an argument before submitting it. - allowed characters: a-z A-Z 0-9 _ and space + allowed characters: a-z A-Z 0-9 _ and space str - string to be cleaned """ # remove not allowed characters str = re.sub(r'[^a-zA-Z0-9_ .]', '', str) # trim leading and ending spaces str = re.sub(r'^ *| *$', '', str) return str def cleanstring_email(str=''): """clean the string and return a valid email address. - + str - string to be cleaned """ # remove not allowed characters str = re.sub(r'[^a-zA-Z0-9_.@-]', '', str) return str def check_email(str=''): """control that submitted emails are correct. this little check is not very good, but better than nothing. """ r = re.compile(r'(.)+\@(.)+\.(.)+') return r.match(str) and 1 or 0 def sendAccountActivatedMessage(AccountEmail, sendTo, password, ln=cdslang): """Send an email to the address given by sendTo about the new activated account.""" fromaddr = "From: %s" % supportemail toaddrs = "To: %s" % sendTo to = toaddrs + "\n" sub = "Subject: Your account on '%s' has been activated\n\n" % cdsname body = "Your account earlier created on '%s' has been activated:\n\n" % cdsname body += " Username/Email: %s\n" % AccountEmail body += " Password: %s\n" % ("*" * len(password)) body += "\n---------------------------------" body += "\n%s" % cdsname body += "\nContact: %s" % supportemail msg = to + sub + body server = smtplib.SMTP('localhost') server.set_debuglevel(1) try: server.sendmail(fromaddr, toaddrs, msg) except smtplib.SMTPRecipientsRefused,e: return 0 server.quit() return 1 def sendNewUserAccountWarning(newAccountEmail, sendTo, password, ln=cdslang): """Send an email to the address given by sendTo about the new account newAccountEmail.""" fromaddr = "From: %s" % supportemail toaddrs = "To: %s" % sendTo to = toaddrs + "\n" sub = "Subject: Account created on '%s'\n\n" % cdsname body = "An account has been created for you on '%s':\n\n" % cdsname body += " Username/Email: %s\n" % newAccountEmail body += " Password: %s\n" % ("*" * len(password)) body += "\n---------------------------------" body += "\n%s" % cdsname body += "\nContact: %s" % supportemail msg = to + sub + body server = smtplib.SMTP('localhost') server.set_debuglevel(1) try: server.sendmail(fromaddr, toaddrs, msg) except smtplib.SMTPRecipientsRefused,e: return 0 server.quit() return 1 def sendAccountRejectedMessage(newAccountEmail, sendTo, ln=cdslang): """Send an email to the address given by sendTo about the new account newAccountEmail.""" fromaddr = "From: %s" % supportemail toaddrs = "To: %s" % sendTo to = toaddrs + "\n" sub = "Subject: Account rejected on '%s'\n\n" % cdsname body = "Your request for an account has been rejected on '%s':\n\n" % cdsname body += " Username/Email: %s\n" % newAccountEmail body += "\n---------------------------------" body += "\n%s" % cdsname body += "\nContact: %s" % supportemail msg = to + sub + body server = smtplib.SMTP('localhost') server.set_debuglevel(1) try: server.sendmail(fromaddr, toaddrs, msg) except smtplib.SMTPRecipientsRefused,e: return 0 server.quit() return 1 def sendAccountDeletedMessage(newAccountEmail, sendTo, ln=cdslang): """Send an email to the address given by sendTo about the new account newAccountEmail.""" fromaddr = "From: %s" % supportemail toaddrs = "To: %s" % sendTo to = toaddrs + "\n" sub = "Subject: Account deleted on '%s'\n\n" % cdsname body = "Your account on '%s' has been deleted:\n\n" % cdsname body += " Username/Email: %s\n" % newAccountEmail body += "\n---------------------------------" body += "\n%s" % cdsname body += "\nContact: %s" % supportemail msg = to + sub + body server = smtplib.SMTP('localhost') server.set_debuglevel(1) try: server.sendmail(fromaddr, toaddrs, msg) except smtplib.SMTPRecipientsRefused,e: return 0 server.quit() return 1 diff --git a/modules/webaccess/web/admin/webaccessadmin.py b/modules/webaccess/web/admin/webaccessadmin.py index 177445b11..e911ad225 100644 --- a/modules/webaccess/web/admin/webaccessadmin.py +++ b/modules/webaccess/web/admin/webaccessadmin.py @@ -1,342 +1,366 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio WebAccess Administrator Interface.""" __revision__ = "$Id$" import sys import invenio.webaccessadmin_lib as wal +from invenio.access_control_config import CFG_ACC_EMPTY_ROLE_DEFINITION_SRC # reload(wal) # from invenio.webaccessadmin_lib import index index = wal.index def rolearea(req): """create the role area menu page.""" return wal.perform_rolearea(req=req) def actionarea(req): """create the role area menu page.""" return wal.perform_actionarea(req=req) def userarea(req, email_user_pattern=''): """create the user area menu page. """ return wal.perform_userarea(req=req, email_user_pattern=email_user_pattern) def resetarea(req): """create the role area menu page.""" return wal.perform_resetarea(req=req) -def resetdefaultsettings(req, superusers=[], confirm=0): +def resetdefaultsettings(req, superusers=[], confirm=0): """create the reset default settings page. """ return wal.perform_resetdefaultsettings(req=req, superusers=superusers, confirm=confirm) def adddefaultsettings(req, superusers=[], confirm=0): """create the add default settings page. """ - return wal.perform_adddefaultsettings(req=req, + return wal.perform_adddefaultsettings(req=req, superusers=superusers, confirm=confirm) def manageaccounts(req, mtype='', content='', confirm=0): """enable, disable and edit accounts""" - + return wal.perform_manageaccounts(req=req, mtype=mtype, content=content, confirm=confirm) def modifyaccountstatus(req, userID, email_user_pattern='', limit_to=-1, maxpage=25, page=1, callback='yes', confirm=0): """enable or disable account""" - + return wal.perform_modifyaccountstatus(req=req, userID=userID, email_user_pattern=email_user_pattern, limit_to=limit_to, maxpage=maxpage, page=page, callback=callback, confirm=confirm) def modifypreferences(req, userID, login_method='', callback='yes', confirm=0): """modify the preferences of an account""" - + return wal.perform_modifypreferences(req=req, userID=userID, login_method=login_method, callback=callback, confirm=confirm) def modifylogindata(req, userID, email='', password='', callback='yes', confirm=0): """modify the email/password of an account""" - + return wal.perform_modifylogindata(req=req, userID=userID, email=email, password=password, callback=callback, confirm=confirm) def rejectaccount(req, userID, email_user_pattern='', limit_to=-1, maxpage=25, page=1, callback='yes', confirm=0): """Set account inactive, delete it and send email to the owner.""" - + return wal.perform_rejectaccount(req=req, userID=userID, email_user_pattern=email_user_pattern, limit_to=limit_to, maxpage=maxpage, page=page, callback=callback, confirm=confirm) def deleteaccount(req, userID, callback='yes', confirm=0): """delete account""" - + return wal.perform_deleteaccount(req=req, userID=userID, callback=callback, confirm=confirm) def createaccount(req, email='', password='', callback='yes', confirm=0): """create account""" - + return wal.perform_createaccount(req=req, email=email, password=password, callback=callback, confirm=confirm) def editaccount(req, userID, mtype='', content='', callback='yes', confirm=0): """edit account. """ return wal.perform_editaccount(req=req, userID=userID, mtype=mtype, content=content, callback=callback, confirm=confirm) def modifyaccounts(req, email_user_pattern='', limit_to=-1, maxpage=25, page=1, callback='yes', confirm=0): """Modify accounts. """ return wal.perform_modifyaccounts(req=req, email_user_pattern=email_user_pattern, limit_to=limit_to, maxpage=maxpage, page=page, callback=callback,confirm=confirm) def delegate_startarea(req): """add info here""" - + return wal.perform_delegate_startarea(req=req) def delegate_adminsetup(req, id_role_admin=0, id_role_delegate=0, confirm=0): """add info here""" - + return wal.perform_delegate_adminsetup(req=req, id_role_admin=id_role_admin, id_role_delegate=id_role_delegate, confirm=confirm) def delegate_adduserrole(req, id_role=0, email_user_pattern='', id_user=0, confirm=0): """add info here""" - + return wal.perform_delegate_adduserrole(req=req, id_role=id_role, email_user_pattern=email_user_pattern, id_user=id_user, confirm=confirm) def delegate_deleteuserrole(req, id_role=0, id_user=0, confirm=0): """add info here""" - + return wal.perform_delegate_deleteuserrole(req=req, id_role=id_role, id_user=id_user, confirm=confirm) def addaction(req, name_action='', arguments='', optional='no', description='put description here.', confirm=0): """form to add a new action with these values: name_action - name of the new action arguments - allowedkeywords, separated by whitespace description - optional description of the action""" return wal.perform_addaction(req=req, name_action=name_action, arguments=arguments, optional=optional, description=description, confirm=confirm) def deleteaction(req, id_action="0", confirm=0): """show all roles connected, and ask for confirmation.""" - + return wal.perform_deleteaction(req=req, id_action=id_action, confirm=confirm) -def addrole(req, name_role='', description='put description here.', confirm=0): +def addrole(req, name_role='', description='put description here.', firerole_def_src=CFG_ACC_EMPTY_ROLE_DEFINITION_SRC, confirm=0): """form to add a new role with these values: - + name_role - name of the new role - - description - optional description of the role """ - + + description - optional description of the role + + firerole_def_src - optional firerole like definition + """ + return wal.perform_addrole(req=req, name_role=name_role, description=description, + firerole_def_src=firerole_def_src, + confirm=confirm) + + +def modifyrole(req, id_role='0', name_role='', description='put description here.', firerole_def_src='', modified='0', confirm=0): + """form to add a new role with these values: + + name_role - name of the new role + + description - optional description of the role + + firerole_def_src - optional firerole like definition + """ + + return wal.perform_modifyrole(req=req, + id_role=id_role, + name_role=name_role, + description=description, + firerole_def_src=firerole_def_src, + modified=modified, confirm=confirm) def deleterole(req, id_role="0", confirm=0): """select a role and show all connected information, users - users that can access the role. actions - actions with possible authorizations.""" - + return wal.perform_deleterole(req=req, id_role=id_role, confirm=confirm) def showroledetails(req, id_role='0'): """show the details of a role.""" return wal.perform_showroledetails(req=req, id_role=id_role) def showactiondetails(req, id_action="0"): """show the details of an action. """ return wal.perform_showactiondetails(req=req, id_action=id_action) def showuserdetails(req, id_user="0"): """show the details of an action. """ return wal.perform_showuserdetails(req=req, id_user=id_user) def adduserrole(req, id_role='0', email_user_pattern='', id_user='0', confirm=0): """create connection between user and role. id_role - id of the role to add user to email_user_pattern - search for users using this pattern id_user - id of user to add to the role. """ - + return wal.perform_adduserrole(req=req, id_role=id_role, email_user_pattern=email_user_pattern, id_user=id_user, confirm=confirm) def addroleuser(req, email_user_pattern='', id_user='0', id_role='0', confirm=0): """create connection between user and role. email_user_pattern - search for users using this pattern id_user - id of user to add to the role. - + id_role - id of the role to add user to. """ return wal.perform_addroleuser(req=req, email_user_pattern=email_user_pattern, id_user=id_user, id_role=id_role, confirm=confirm) def deleteuserrole(req, id_role='0', id_user='0', reverse=0, confirm=0): """delete connection between role and user. id_role - id of role to disconnect id_user - id of user to disconnect. """ return wal.perform_deleteuserrole(req=req, id_role=id_role, id_user=id_user, reverse=reverse, confirm=confirm) def addauthorization(req, id_role="0", id_action="0", reverse="0", confirm=0, **keywords): """ form to add new connection between user and role: - id_role - role to connect + id_role - role to connect id_action - action to connect reverse - role or action first? """ return wal.perform_addauthorization(req=req, id_role=id_role, id_action=id_action, reverse=reverse, confirm=confirm, **keywords) def deleteroleaction(req, id_role="0", id_action="0", reverse=0, confirm=0): """delete all connections between a role and an action. id_role - id of the role id_action - id of the action reverse - 0: ask for role first 1: ask for action first""" - + return wal.perform_deleteroleaction(req=req, id_role=id_role, id_action=id_action, reverse=reverse, confirm=confirm) def modifyauthorizations(req, id_role="0", id_action="0", reverse=0, confirm=0, sel='', errortext='', authids=[]): """given ids of a role and an action, show all possible action combinations with checkboxes and allow user to access other functions. id_role - id of the role id_action - id of the action reverse - 0: ask for role first 1: ask for action first sel - which button and modification that is selected - + errortext - text to print when no connection exist between role and action - + authids - ids of checked checkboxes """ return wal.perform_modifyauthorizations(req=req, id_role=id_role, id_action=id_action, reverse=reverse, confirm=confirm, sel=sel, authids=authids) def simpleauthorization(req, id_role=0, id_action=0): """show a page with simple overview of authorizations between a connected role and action. """ return wal.perform_simpleauthorization(req=req, id_role=id_role, id_action=id_action) def showroleusers(req, id_role=0): """show a page with simple overview of a role and connected users. """ - + return wal.perform_showroleusers(req=req, id_role=id_role) diff --git a/modules/webcomment/web/admin/webcommentadmin.py b/modules/webcomment/web/admin/webcommentadmin.py index 7ae40b675..896a796df 100644 --- a/modules/webcomment/web/admin/webcommentadmin.py +++ b/modules/webcomment/web/admin/webcommentadmin.py @@ -1,228 +1,228 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """Comments and reviews administrative interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" from invenio.webcommentadminlib import * from invenio.bibrankadminlib import check_user from invenio.webpage import page, create_error_box from invenio.config import weburl,cdslang,cdsname -from invenio.dbquery import Error +from invenio.dbquery import Error from invenio.webuser import getUid, page_not_authorized from invenio.urlutils import wash_url_argument, redirect_to_url from invenio.messages import wash_language, gettext_set_language def index(req, ln=cdslang): """ Menu of admin options - @param ln: language + @param ln: language """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail() navtrail_previous_links +=' > ' % weburl navtrail_previous_links += _("Comment Management") + '' try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebcomment') + (auth_code, auth_msg) = check_user(req, 'cfgwebcomment') if (auth_code != 'false'): return page(title=_("Comment Management"), body=perform_request_index(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, - req=req) + req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def delete(req, ln=cdslang, comid=""): """ Delete a comment by giving its comment id @param ln: language @param comid: comment id """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail() navtrail_previous_links += ' > ' % weburl navtrail_previous_links += _("Comment Management") + '' try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - - (auth_code, auth_msg) = check_user(uid,'cfgwebcomment') + + (auth_code, auth_msg) = check_user(req,'cfgwebcomment') if (auth_code != 'false'): (body, errors, warnings) = perform_request_delete(ln=ln, comID=comid) return page(title=_("Delete Comment"), body=body, uid=uid, language=ln, navtrail = navtrail_previous_links, req = req, - errors = errors, + errors = errors, warnings = warnings, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def comments(req, ln=cdslang, uid="", comid="", reviews=0): """ View reported comments, filter by either user or a specific comment (only one given at a time) @param ln: language @param uid: user id @param comid: comment id @param reviews: boolean enabled for reviews, disabled for comments """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail() navtrail_previous_links += ' > ' % weburl navtrail_previous_links += _("Comment Management") + '' - + try: auid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - + (auth_code, auth_msg) = check_user(auid, 'cfgwebcomment') if (auth_code != 'false'): return page(title=_("View all reported comments"), body=perform_request_comments(ln=ln, uid=uid, comID=comid, reviews=reviews), uid=auid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def users(req, ln=cdslang): """ View a list of all the users that have been reported, sorted by most reported - @param ln: language + @param ln: language """ ln = wash_language(ln) _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail() navtrail_previous_links += ' > ' % weburl navtrail_previous_links += _("Comment Management") + '' try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid,'cfgwebcomment') + (auth_code, auth_msg) = check_user(req,'cfgwebcomment') if (auth_code != 'false'): return page(title=_("View all reported users"), body=perform_request_users(ln=ln), uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) def del_com(req, ln=cdslang, action="delete", **hidden): """ private funciton Delete a comment @param ln: language @param **hidden: ids of comments to delete sent as individual variables comidX=on, where X is id """ ln = wash_language(ln) action = wash_url_argument(action, 'str') _ = gettext_set_language(ln) navtrail_previous_links = getnavtrail() navtrail_previous_links += ' > ' % weburl navtrail_previous_links += _("Comment Management") + '' try: uid = getUid(req) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=0, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) - (auth_code, auth_msg) = check_user(uid,'cfgwebcomment') + (auth_code, auth_msg) = check_user(req,'cfgwebcomment') if (auth_code != 'false'): comIDs = [] - args = hidden.keys() + args = hidden.keys() for var in args: try: comIDs.append(int(var.split('comid')[1])) except: pass if action == 'delete': body = perform_request_del_com(ln=ln, comIDs=comIDs) title = _("Delete comments") elif action == 'unreport': body = suppress_abuse_report(ln=ln, comIDs=comIDs) title = _("Suppress abuse reports") else: redirect_to_url(req, weburl + '/admin/webcomment/webcommentadmin.py') return page(title=title, body=body, uid=uid, language=ln, navtrail = navtrail_previous_links, lastupdated=__lastupdated__, req=req) else: return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) diff --git a/modules/websearch/lib/search_engine.py b/modules/websearch/lib/search_engine.py index e7a84573c..805b7744f 100644 --- a/modules/websearch/lib/search_engine.py +++ b/modules/websearch/lib/search_engine.py @@ -1,3604 +1,3757 @@ # -*- coding: utf-8 -*- ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 Search Engine in mod_python.""" __lastupdated__ = """$Date$""" __revision__ = "$Id$" ## import general modules: import cgi import copy import string import os import sre import time import urllib import zlib import Numeric ## import CDS Invenio stuff: from invenio.config import \ CFG_CERN_SITE, \ CFG_MAX_RECID, \ CFG_OAI_ID_FIELD, \ CFG_WEBCOMMENT_ALLOW_COMMENTS, \ CFG_WEBCOMMENT_ALLOW_REVIEWS, \ CFG_WEBCOMMENT_NB_COMMENTS_IN_DETAILED_VIEW, \ CFG_WEBCOMMENT_NB_REVIEWS_IN_DETAILED_VIEW, \ CFG_WEBSEARCH_CALL_BIBFORMAT, \ CFG_WEBSEARCH_CREATE_SIMILARLY_NAMED_AUTHORS_LINK_BOX, \ CFG_WEBSEARCH_FIELDS_CONVERT, \ CFG_WEBSEARCH_NB_RECORDS_TO_SORT, \ CFG_WEBSEARCH_SEARCH_CACHE_SIZE, \ CFG_BIBRANK_SHOW_DOWNLOAD_GRAPHS, \ cdslang, \ cdsname, \ cdsnameintl, \ logdir, \ weburl from invenio.search_engine_config import CFG_EXPERIMENTAL_FEATURES, InvenioWebSearchUnknownCollectionError from invenio.bibrank_record_sorter import get_bibrank_methods, rank_records from invenio.bibrank_downloads_similarity import register_page_view_event, calculate_reading_similarity_list from invenio.bibformat import format_record, format_records, get_output_format_content_type, create_excel from invenio.bibformat_config import CFG_BIBFORMAT_USE_OLD_BIBFORMAT from invenio.bibrank_downloads_grapher import create_download_history_graph_and_box - +from invenio.data_cacher import DataCacher from invenio.websearch_external_collections import print_external_results_overview, perform_external_collection_search +from invenio.access_control_admin import acc_getActionId +from invenio.access_control_config import VIEWRESTRCOLL if CFG_EXPERIMENTAL_FEATURES: from invenio.bibrank_citation_searcher import calculate_cited_by_list, calculate_co_cited_with_list from invenio.bibrank_citation_grapher import create_citation_history_graph_and_box from invenio.dbquery import run_sql, get_table_update_time, escape_string, Error try: from mod_python import apache from invenio.webuser import getUid from invenio.webpage import page, pageheaderonly, pagefooteronly, create_error_box except ImportError, e: pass # ignore user personalisation, needed e.g. for command-line from invenio.messages import gettext_set_language try: import invenio.template websearch_templates = invenio.template.load('websearch') except: pass ## global vars: search_cache = {} # will cache results of previous searches cfg_nb_browse_seen_records = 100 # limit of the number of records to check when browsing certain collection cfg_nicely_ordered_collection_list = 0 # do we propose collection list nicely ordered or alphabetical? collection_reclist_cache_timestamp = 0 field_i18nname_cache_timestamp = 0 collection_i18nname_cache_timestamp = 0 ## precompile some often-used regexp for speed reasons: sre_word = sre.compile('[\s]') sre_quotes = sre.compile('[\'\"]') sre_doublequote = sre.compile('\"') sre_equal = sre.compile('\=') sre_logical_and = sre.compile('\sand\s', sre.I) sre_logical_or = sre.compile('\sor\s', sre.I) sre_logical_not = sre.compile('\snot\s', sre.I) sre_operators = sre.compile(r'\s([\+\-\|])\s') sre_pattern_wildcards_at_beginning = sre.compile(r'(\s)[\*\%]+') sre_pattern_single_quotes = sre.compile("'(.*?)'") sre_pattern_double_quotes = sre.compile("\"(.*?)\"") sre_pattern_regexp_quotes = sre.compile("\/(.*?)\/") sre_pattern_short_words = sre.compile(r'([\s\"]\w{1,3})[\*\%]+') sre_pattern_space = sre.compile("__SPACE__") sre_pattern_today = sre.compile("\$TODAY\$") sre_unicode_lowercase_a = sre.compile(unicode(r"(?u)[áàäâãå]", "utf-8")) sre_unicode_lowercase_ae = sre.compile(unicode(r"(?u)[æ]", "utf-8")) sre_unicode_lowercase_e = sre.compile(unicode(r"(?u)[éèëê]", "utf-8")) sre_unicode_lowercase_i = sre.compile(unicode(r"(?u)[íìïî]", "utf-8")) sre_unicode_lowercase_o = sre.compile(unicode(r"(?u)[óòöôõø]", "utf-8")) sre_unicode_lowercase_u = sre.compile(unicode(r"(?u)[úùüû]", "utf-8")) sre_unicode_lowercase_y = sre.compile(unicode(r"(?u)[ýÿ]", "utf-8")) sre_unicode_lowercase_c = sre.compile(unicode(r"(?u)[çć]", "utf-8")) sre_unicode_lowercase_n = sre.compile(unicode(r"(?u)[ñ]", "utf-8")) sre_unicode_uppercase_a = sre.compile(unicode(r"(?u)[ÁÀÄÂÃÅ]", "utf-8")) sre_unicode_uppercase_ae = sre.compile(unicode(r"(?u)[Æ]", "utf-8")) sre_unicode_uppercase_e = sre.compile(unicode(r"(?u)[ÉÈËÊ]", "utf-8")) sre_unicode_uppercase_i = sre.compile(unicode(r"(?u)[ÍÌÏÎ]", "utf-8")) sre_unicode_uppercase_o = sre.compile(unicode(r"(?u)[ÓÒÖÔÕØ]", "utf-8")) sre_unicode_uppercase_u = sre.compile(unicode(r"(?u)[ÚÙÜÛ]", "utf-8")) sre_unicode_uppercase_y = sre.compile(unicode(r"(?u)[Ý]", "utf-8")) sre_unicode_uppercase_c = sre.compile(unicode(r"(?u)[ÇĆ]", "utf-8")) sre_unicode_uppercase_n = sre.compile(unicode(r"(?u)[Ñ]", "utf-8")) +class RestrictedCollectionDataCacher(DataCacher): + def __init__(self): + def cache_filler(): + ret = [] + try: + viewcollid = acc_getActionId(VIEWRESTRCOLL) + res = run_sql("""SELECT DISTINCT ar.value + FROM accROLE_accACTION_accARGUMENT raa JOIN accARGUMENT ar ON raa.id_accARGUMENT = ar.id + WHERE ar.keyword = 'collection' AND raa.id_accACTION = %s""", (viewcollid,)) + except Exception: + # database problems, return empty cache + return [] + for coll in res: + ret.append(coll[0]) + return ret + + def timestamp_getter(): + return max(get_table_update_time('accROLE_accACTION_accARGUMENT'), get_table_update_time('accARGUMENT')) + + DataCacher.__init__(self, cache_filler, timestamp_getter) + + def collection_restricted_p(self, collection): + cache = self.get_cache() + return collection in cache + +try: + restricted_collection_cache.is_ok_p +except Exception: + restricted_collection_cache = RestrictedCollectionDataCacher() + + +class FieldI18nNameDataCacher(DataCacher): + def __init__(self): + def cache_filler(): + ret = {} + try: + res = run_sql("SELECT f.name,fn.ln,fn.value FROM fieldname AS fn, field AS f WHERE fn.id_field=f.id AND fn.type='ln'") # ln=long name + except Exception: + # database problems, return empty cache + return {} + for f, ln, i18nname in res: + if i18nname: + if not ret.has_key(f): + ret[f] = {} + ret[f][ln] = i18nname + return ret + + def timestamp_getter(): + return get_table_update_time('fieldname') + + DataCacher.__init__(self, cache_filler, timestamp_getter) + + def get_field_i18nname(self, f, ln=cdslang): + out = f + try: + out = self.get_cache()[f][ln] + except KeyError: + pass # translation in LN does not exist + return out + +try: + if not field_i18n_name_cache.is_ok_p: + raise Exception +except Exception: + field_i18n_name_cache = FieldI18nNameDataCacher() + + +class CollectionRecListDataCacher(DataCacher): + def __init__(self): + def cache_filler(): + ret = {} + try: + res = run_sql("SELECT name,reclist FROM collection") + except Exception: + # database problems, return empty cache + return {} + for name, reclist in res: + ret[name] = None # this will be filled later during runtime by calling get_collection_reclist(coll) + return ret + + def timestamp_getter(): + return get_table_update_time('collection') + + DataCacher.__init__(self, cache_filler, timestamp_getter) + + def get_collection_reclist(self, coll): + cache = self.get_cache() + if not cache[coll]: + # not yet it the cache, so calculate it and fill the cache: + set = HitSet() + query = "SELECT nbrecs,reclist FROM collection WHERE name='%s'" % coll + res = run_sql(query, None, 1) + if res: + try: + set._nbhits, set._set = res[0][0], Numeric.loads(zlib.decompress(res[0][1])) + except: + set._nbhits = 0 + self.cache[coll] = set + cache[coll] = set + # finally, return reclist: + return cache[coll] + +try: + if not collection_reclist_cache.is_ok_p: + raise Exception +except Exception: + collection_reclist_cache = CollectionRecListDataCacher() + + +class CollectionI18nDataCacher(DataCacher): + def __init__(self): + def cache_filler(): + ret = {} + try: + res = run_sql("SELECT c.name,cn.ln,cn.value FROM collectionname AS cn, collection AS c WHERE cn.id_collection=c.id AND cn.type='ln'") # ln=long name + except Exception: + # database problems, + return {} + for c, ln, i18nname in res: + if i18nname: + if not ret.has_key(c): + ret[c] = {} + ret[c][ln] = i18nname + return ret + + def timestamp_getter(): + return get_table_update_time('collectionname') + + DataCacher.__init__(self, cache_filler, timestamp_getter) + + def get_coll_i18nname(self, c, ln=cdslang): + """Return nicely formatted collection name (of name type 'ln', + 'long name') for collection C in language LN.""" + cache = self.get_cache() + out = c + try: + out = cache[c][ln] + except KeyError: + pass # translation in LN does not exist + return out + +try: + if not collection_i18n_name_cache.is_ok_p: + raise Exception +except Exception: + collection_i18n_name_cache = CollectionI18nDataCacher() + + def get_alphabetically_ordered_collection_list(level=0, ln=cdslang): """Returns nicely ordered (score respected) list of collections, more exactly list of tuples (collection name, printable collection name). Suitable for create_search_box().""" out = [] query = "SELECT id,name FROM collection ORDER BY name ASC" res = run_sql(query) for c_id, c_name in res: # make a nice printable name (e.g. truncate c_printable for # long collection names in given language): c_printable = get_coll_i18nname(c_name, ln) if len(c_printable)>30: c_printable = c_printable[:30] + "..." if level: c_printable = " " + level * '-' + " " + c_printable out.append([c_name, c_printable]) return out def get_nicely_ordered_collection_list(collid=1, level=0, ln=cdslang): """Returns nicely ordered (score respected) list of collections, more exactly list of tuples (collection name, printable collection name). Suitable for create_search_box().""" colls_nicely_ordered = [] query = "SELECT c.name,cc.id_son FROM collection_collection AS cc, collection AS c "\ " WHERE c.id=cc.id_son AND cc.id_dad='%s' ORDER BY score DESC" % collid res = run_sql(query) for c, cid in res: # make a nice printable name (e.g. truncate c_printable for # long collection names in given language): c_printable = get_coll_i18nname(c, ln) if len(c_printable)>30: c_printable = c_printable[:30] + "..." if level: c_printable = " " + level * '-' + " " + c_printable colls_nicely_ordered.append([c, c_printable]) colls_nicely_ordered = colls_nicely_ordered + get_nicely_ordered_collection_list(cid, level+1, ln=ln) return colls_nicely_ordered def get_index_id(field): """Returns first index id where the field code FIELD is indexed. Returns zero in case there is no table for this index. Example: field='author', output=4.""" out = 0 query = """SELECT w.id FROM idxINDEX AS w, idxINDEX_field AS wf, field AS f WHERE f.code='%s' AND wf.id_field=f.id AND w.id=wf.id_idxINDEX LIMIT 1""" % escape_string(field) res = run_sql(query, None, 1) if res: out = res[0][0] return out def get_words_from_pattern(pattern): "Returns list of whitespace-separated words from pattern." words = {} for word in string.split(pattern): if not words.has_key(word): words[word] = 1; return words.keys() def create_basic_search_units(req, p, f, m=None, of='hb'): """Splits search pattern and search field into a list of independently searchable units. - A search unit consists of '(operator, pattern, field, type, hitset)' tuples where 'operator' is set union (|), set intersection (+) or set exclusion (-); 'pattern' is either a word (e.g. muon*) or a phrase (e.g. 'nuclear physics'); 'field' is either a code like 'title' or MARC tag like '100__a'; 'type' is the search type ('w' for word file search, 'a' for access file search). - Optionally, the function accepts the match type argument 'm'. If it is set (e.g. from advanced search interface), then it performs this kind of matching. If it is not set, then a guess is made. 'm' can have values: 'a'='all of the words', 'o'='any of the words', 'p'='phrase/substring', 'r'='regular expression', 'e'='exact value'. - Warnings are printed on req (when not None) in case of HTML output formats.""" opfts = [] # will hold (o,p,f,t,h) units ## check arguments: if matching type phrase/string/regexp, do we have field defined? if (m=='p' or m=='r' or m=='e') and not f: m = 'a' if of.startswith("h"): print_warning(req, "This matching type cannot be used within any field. I will perform a word search instead." ) print_warning(req, "If you want to phrase/substring/regexp search in a specific field, e.g. inside title, then please choose within title search option.") ## is desired matching type set? if m: ## A - matching type is known; good! if m == 'e': # A1 - exact value: opfts.append(['+', p, f, 'a']) # '+' since we have only one unit elif m == 'p': # A2 - phrase/substring: opfts.append(['+', "%" + p + "%", f, 'a']) # '+' since we have only one unit elif m == 'r': # A3 - regular expression: opfts.append(['+', p, f, 'r']) # '+' since we have only one unit elif m == 'a' or m == 'w': # A4 - all of the words: p = strip_accents(p) # strip accents for 'w' mode, FIXME: delete when not needed for word in get_words_from_pattern(p): opfts.append(['+', word, f, 'w']) # '+' in all units elif m == 'o': # A5 - any of the words: p = strip_accents(p) # strip accents for 'w' mode, FIXME: delete when not needed for word in get_words_from_pattern(p): if len(opfts)==0: opfts.append(['+', word, f, 'w']) # '+' in the first unit else: opfts.append(['|', word, f, 'w']) # '|' in further units else: if of.startswith("h"): print_warning(req, "Matching type '%s' is not implemented yet." % m, "Warning") opfts.append(['+', "%" + p + "%", f, 'a']) else: ## B - matching type is not known: let us try to determine it by some heuristics if f and p[0] == '"' and p[-1] == '"': ## B0 - does 'p' start and end by double quote, and is 'f' defined? => doing ACC search opfts.append(['+', p[1:-1], f, 'a']) elif f and p[0] == "'" and p[-1] == "'": ## B0bis - does 'p' start and end by single quote, and is 'f' defined? => doing ACC search opfts.append(['+', '%' + p[1:-1] + '%', f, 'a']) elif f and p[0] == "/" and p[-1] == "/": ## B0ter - does 'p' start and end by a slash, and is 'f' defined? => doing regexp search opfts.append(['+', p[1:-1], f, 'r']) elif f and string.find(p, ',') >= 0: ## B1 - does 'p' contain comma, and is 'f' defined? => doing ACC search opfts.append(['+', p, f, 'a']) elif f and str(f[0:2]).isdigit(): ## B2 - does 'f' exist and starts by two digits? => doing ACC search opfts.append(['+', p, f, 'a']) else: ## B3 - doing WRD search, but maybe ACC too # search units are separated by spaces unless the space is within single or double quotes # so, let us replace temporarily any space within quotes by '__SPACE__' p = sre_pattern_single_quotes.sub(lambda x: "'"+string.replace(x.group(1), ' ', '__SPACE__')+"'", p) p = sre_pattern_double_quotes.sub(lambda x: "\""+string.replace(x.group(1), ' ', '__SPACE__')+"\"", p) p = sre_pattern_regexp_quotes.sub(lambda x: "/"+string.replace(x.group(1), ' ', '__SPACE__')+"/", p) # wash argument: p = sre_equal.sub(":", p) p = sre_logical_and.sub(" ", p) p = sre_logical_or.sub(" |", p) p = sre_logical_not.sub(" -", p) p = sre_operators.sub(r' \1', p) for pi in string.split(p): # iterate through separated units (or items, as "pi" stands for "p item") pi = sre_pattern_space.sub(" ", pi) # replace back '__SPACE__' by ' ' # firstly, determine set operator if pi[0] == '+' or pi[0] == '-' or pi[0] == '|': oi = pi[0] pi = pi[1:] else: # okay, there is no operator, so let us decide what to do by default oi = '+' # by default we are doing set intersection... # secondly, determine search pattern and field: if string.find(pi, ":") > 0: fi, pi = string.split(pi, ":", 1) else: fi, pi = f, pi # look also for old ALEPH field names: if fi and CFG_WEBSEARCH_FIELDS_CONVERT.has_key(string.lower(fi)): fi = CFG_WEBSEARCH_FIELDS_CONVERT[string.lower(fi)] # wash 'pi' argument: if sre_quotes.match(pi): # B3a - quotes are found => do ACC search (phrase search) if fi: if pi[0] == '"' and pi[-1] == '"': pi = string.replace(pi, '"', '') # remove quote signs opfts.append([oi, pi, fi, 'a']) elif pi[0] == "'" and pi[-1] == "'": pi = string.replace(pi, "'", "") # remove quote signs opfts.append([oi, "%" + pi + "%", fi, 'a']) else: # unbalanced quotes, so do WRD query: opfts.append([oi, pi, fi, 'w']) else: # fi is not defined, look at where we are doing exact or subphrase search (single/double quotes): if pi[0] == '"' and pi[-1] == '"': opfts.append([oi, pi[1:-1], "anyfield", 'a']) if of.startswith("h"): print_warning(req, "Searching for an exact match inside any field may be slow. You may want to search for words instead, or choose to search within specific field.") else: # nope, subphrase in global index is not possible => change back to WRD search pi = strip_accents(pi) # strip accents for 'w' mode, FIXME: delete when not needed for pii in get_words_from_pattern(pi): # since there may be '-' and other chars that we do not index in WRD opfts.append([oi, pii, fi, 'w']) if of.startswith("h"): print_warning(req, "The partial phrase search does not work in any field. I'll do a boolean AND searching instead.") print_warning(req, "If you want to do a partial phrase search in a specific field, e.g. inside title, then please choose 'within title' search option.", "Tip") print_warning(req, "If you want to do exact phrase matching, then please use double quotes.", "Tip") elif fi and str(fi[0]).isdigit() and str(fi[0]).isdigit(): # B3b - fi exists and starts by two digits => do ACC search opfts.append([oi, pi, fi, 'a']) elif fi and not get_index_id(fi): # B3c - fi exists but there is no words table for fi => try ACC search opfts.append([oi, pi, fi, 'a']) elif fi and pi.startswith('/') and pi.endswith('/'): # B3d - fi exists and slashes found => try regexp search opfts.append([oi, pi[1:-1], fi, 'r']) else: # B3e - general case => do WRD search pi = strip_accents(pi) # strip accents for 'w' mode, FIXME: delete when not needed for pii in get_words_from_pattern(pi): opfts.append([oi, pii, fi, 'w']) ## sanity check: for i in range(0, len(opfts)): try: pi = opfts[i][1] if pi == '*': if of.startswith("h"): print_warning(req, "Ignoring standalone wildcard word.", "Warning") del opfts[i] if pi == '' or pi == ' ': fi = opfts[i][2] if fi: if of.startswith("h"): print_warning(req, "Ignoring empty %s search term." % fi, "Warning") del opfts[i] except: pass ## return search units: return opfts def page_start(req, of, cc, as, ln, uid, title_message=None, description='', keywords=''): "Start page according to given output format." _ = gettext_set_language(ln) if not title_message: title_message = _("Search Results") if not req: return # we were called from CLI content_type = get_output_format_content_type(of) if of.startswith('x'): if of == 'xr': # we are doing RSS output req.content_type = "application/rss+xml" req.send_http_header() req.write("""\n""") else: # we are doing XML output: req.content_type = "text/xml" req.send_http_header() req.write("""\n""") elif of.startswith('t') or str(of[0:3]).isdigit(): # we are doing plain text output: req.content_type = "text/plain" req.send_http_header() elif of == "id": pass # nothing to do, we shall only return list of recIDs elif content_type == 'text/html': # we are doing HTML output: req.content_type = "text/html" req.send_http_header() if not description: description = "%s %s." % (cc, _("Search Results")) if not keywords: keywords = "CDS Invenio, WebSearch, %s" % cc req.write(pageheaderonly(req=req, title=title_message, navtrail=create_navtrail_links(cc, as, ln), description=description, keywords=keywords, uid=uid, language=ln, navmenuid='search')) req.write(websearch_templates.tmpl_search_pagestart(ln=ln)) #else: # req.send_http_header() def page_end(req, of="hb", ln=cdslang): "End page according to given output format: e.g. close XML tags, add HTML footer, etc." if of == "id": return [] # empty recID list if not req: return # we were called from CLI if of.startswith('h'): req.write(websearch_templates.tmpl_search_pageend(ln = ln)) # pagebody end req.write(pagefooteronly(lastupdated=__lastupdated__, language=ln, req=req)) return "\n" def create_inputdate_box(name="d1", selected_year=0, selected_month=0, selected_day=0, ln=cdslang): "Produces 'From Date', 'Until Date' kind of selection box. Suitable for search options." _ = gettext_set_language(ln) box = "" # day box += """""" # month box += """""" # year box += """""" return box def create_search_box(cc, colls, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1, p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, ec, action=""): - "Create search box for 'search again in the results page' functionality." + """Create search box for 'search again in the results page' functionality.""" # load the right message language _ = gettext_set_language(ln) # some computations if cc == cdsname: cc_intl = cdsnameintl[ln] else: cc_intl = get_coll_i18nname(cc, ln) colls_nicely_ordered = [] if cfg_nicely_ordered_collection_list: colls_nicely_ordered = get_nicely_ordered_collection_list(ln=ln) else: colls_nicely_ordered = get_alphabetically_ordered_collection_list(ln=ln) colls_nice = [] for (cx, cx_printable) in colls_nicely_ordered: if not cx.startswith("Unnamed collection"): colls_nice.append({ 'value' : cx, 'text' : cx_printable }) coll_selects = [] if colls and colls[0] != cdsname: # some collections are defined, so print these first, and only then print 'add another collection' heading: for c in colls: if c: temp = [] temp.append({ 'value' : '', 'text' : '*** %s ***' % _("any collection") }) for val in colls_nice: # print collection: if not cx.startswith("Unnamed collection"): temp.append({ 'value' : val['value'], 'text' : val['text'], 'selected' : (c == sre.sub("^[\s\-]*","", val['value'])) }) coll_selects.append(temp) coll_selects.append([{ 'value' : '', 'text' : '*** %s ***' % _("add another collection") }] + colls_nice) else: # we searched in CDSNAME, so print 'any collection' heading coll_selects.append([{ 'value' : '', 'text' : '*** %s ***' % _("any collection") }] + colls_nice) sort_formats = [{ 'value' : '', 'text' : _("latest first") }] query = """SELECT DISTINCT(f.code),f.name FROM field AS f, collection_field_fieldvalue AS cff WHERE cff.type='soo' AND cff.id_field=f.id ORDER BY cff.score DESC, f.name ASC""" res = run_sql(query) for code, name in res: sort_formats.append({ 'value' : code, 'text' : name, }) ## ranking methods ranks = [{ 'value' : '', 'text' : "- %s %s -" % (_("OR").lower (), _("rank by")), }] for (code, name) in get_bibrank_methods(get_colID(cc), ln): # propose found rank methods: ranks.append({ 'value' : code, 'text' : name, }) formats = [] query = """SELECT code,name FROM format ORDER BY name ASC""" res = run_sql(query) if res: # propose found formats: for code, name in res: formats.append({ 'value' : code, 'text' : name }) else: formats.append({'value' : 'hb', 'text' : _("HTML brief") }) return websearch_templates.tmpl_search_box( ln = ln, as = as, cc_intl = cc_intl, cc = cc, ot = ot, sp = sp, action = action, fieldslist = get_searchwithin_fields(ln = ln), f1 = f1, f2 = f2, f3 = f3, m1 = m1, m2 = m2, m3 = m3, p1 = p1, p2 = p2, p3 = p3, op1 = op1, op2 = op2, rm = rm, p = p, f = f, coll_selects = coll_selects, d1y = d1y, d2y = d2y, d1m = d1m, d2m = d2m, d1d = d1d, d2d = d2d, sort_formats = sort_formats, sf = sf, so = so, ranks = ranks, sc = sc, rg = rg, formats = formats, of = of, pl = pl, jrec = jrec, ec = ec, ) def create_navtrail_links(cc=cdsname, as=0, ln=cdslang, self_p=1): """Creates navigation trail links, i.e. links to collection ancestors (except Home collection). If as==1, then links to Advanced Search interfaces; otherwise Simple Search. """ dads = [] for dad in get_coll_ancestors(cc): if dad != cdsname: # exclude Home collection dads.append ((dad, get_coll_i18nname (dad, ln))) if self_p and cc != cdsname: dads.append((cc, get_coll_i18nname(cc, ln))) return websearch_templates.tmpl_navtrail_links( as=as, ln=ln, dads=dads) def create_searchwithin_selection_box(fieldname='f', value='', ln='en'): - "Produces 'search within' selection box for the current collection." + """Produces 'search within' selection box for the current collection.""" + out = "" out += """""" return out def get_searchwithin_fields(ln='en'): - "Retrieves the fields name used in the 'search within' selection box for the current collection." + """Retrieves the fields name used in the 'search within' selection box for the current collection.""" + query = "SELECT code,name FROM field ORDER BY name ASC" res = run_sql(query) fields = [{ 'value' : '', 'text' : get_field_i18nname("any field", ln) }] for field_code, field_name in res: if field_code and field_code != "anyfield": fields.append({ 'value' : field_code, 'text' : get_field_i18nname(field_name, ln) }) return fields def create_andornot_box(name='op', value='', ln='en'): "Returns HTML code for the AND/OR/NOT selection box." _ = gettext_set_language(ln) out = """ """ % (name, is_selected('a', value), _("AND"), is_selected('o', value), _("OR"), is_selected('n', value), _("AND NOT")) return out def create_matchtype_box(name='m', value='', ln='en'): "Returns HTML code for the 'match type' selection box." _ = gettext_set_language(ln) out = """ """ % (name, is_selected('a', value), _("All of the words:"), is_selected('o', value), _("Any of the words:"), is_selected('e', value), _("Exact phrase:"), is_selected('p', value), _("Partial phrase:"), is_selected('r', value), _("Regular expression:")) return out def is_selected(var, fld): "Checks if the two are equal, and if yes, returns ' selected'. Useful for select boxes." if type(var) is int and type(fld) is int: if var == fld: return " selected" elif str(var) == str(fld): return " selected" elif fld and len(fld)==3 and fld[0] == "w" and var == fld[1:]: return " selected" return "" class HitSet: """Class describing set of records, implemented as bit vectors of recIDs. Using Numeric arrays for speed (1 value = 8 bits), can use later "real" bit vectors to save space.""" def __init__(self, init_set=None): self._nbhits = -1 if init_set: self._set = init_set else: self._set = Numeric.zeros(CFG_MAX_RECID+1, Numeric.Int0) def __repr__(self, join=string.join): return "%s(%s)" % (self.__class__.__name__, join(map(repr, self._set), ', ')) def add(self, recID): "Adds a record to the set." self._set[recID] = 1 def addmany(self, recIDs): "Adds several recIDs to the set." for recID in recIDs: self._set[recID] = 1 def addlist(self, arr): "Adds an array of recIDs to the set." Numeric.put(self._set, arr, 1) def remove(self, recID): "Removes a record from the set." self._set[recID] = 0 def removemany(self, recIDs): "Removes several records from the set." for recID in recIDs: self.remove(recID) def intersect(self, other): "Does a set intersection with other. Keep result in self." self._set = Numeric.bitwise_and(self._set, other._set) def union(self, other): "Does a set union with other. Keep result in self." self._set = Numeric.bitwise_or(self._set, other._set) def difference(self, other): "Does a set difference with other. Keep result in self." #self._set = Numeric.bitwise_not(self._set, other._set) for recID in Numeric.nonzero(other._set): self.remove(recID) def contains(self, recID): "Checks whether the set contains recID." return self._set[recID] __contains__ = contains # Higher performance member-test for python 2.0 and above def __getitem__(self, index): "Support for the 'for item in set:' protocol." return Numeric.nonzero(self._set)[index] def calculate_nbhits(self): "Calculates the number of records set in the hitset." self._nbhits = Numeric.sum(self._set.copy().astype(Numeric.Int)) def items(self): "Return an array containing all recID." return Numeric.nonzero(self._set) def tolist(self): "Return an array containing all recID." return Numeric.nonzero(self._set).tolist() # speed up HitSet operations by ~20% if Psyco is installed: try: import psyco psyco.bind(HitSet) except: pass def wash_colls(cc, c, split_colls=0): - """Wash collection list by checking whether user has deselected anything under 'Narrow search'. Checks also if cc is a list or not. Return list of cc, colls_to_display, colls_to_search since the list of collections to display is different from that to search in. This is because users might have chosen 'split by collection' functionality. The behaviour of "collections to display" depends solely whether user has deselected a particular collection: e.g. if it started from 'Articles and Preprints' page, and deselected 'Preprints', then collection to display is 'Articles'. If he did not deselect anything, then collection to display is 'Articles & Preprints'. The behaviour of "collections to search in" depends on the 'split_colls' parameter: * if is equal to 1, then we can wash the colls list down and search solely in the collection the user started from; * if is equal to 0, then we are splitting to the first level of collections, i.e. collections as they appear on the page we started to search from; The function raises exception InvenioWebSearchUnknownCollectionError if cc or one of c collections is not known. """ colls_out = [] colls_out_for_display = [] # check what type is 'cc': if type(cc) is list: for ci in cc: if collection_reclist_cache.has_key(ci): # yes this collection is real, so use it: cc = ci break else: # check once if cc is real: if not collection_reclist_cache.has_key(cc): if cc: raise InvenioWebSearchUnknownCollectionError(cc) else: cc = cdsname # cc is not set, so replace it with Home collection # check type of 'c' argument: if type(c) is list: colls = c else: colls = [c] # remove all 'unreal' collections: colls_real = [] for coll in colls: if collection_reclist_cache.has_key(coll): colls_real.append(coll) else: if coll: raise InvenioWebSearchUnknownCollectionError(coll) colls = colls_real # check if some real collections remain: if len(colls)==0: colls = [cc] # then let us check the list of non-restricted "real" sons of 'cc' and compare it to 'coll': query = "SELECT c.name FROM collection AS c, collection_collection AS cc, collection AS ccc WHERE c.id=cc.id_son AND cc.id_dad=ccc.id AND ccc.name='%s' AND cc.type='r' AND c.restricted IS NULL" % escape_string(cc) res = run_sql(query) l_cc_nonrestricted_sons = [] l_c = colls for row in res: l_cc_nonrestricted_sons.append(row[0]) l_c.sort() l_cc_nonrestricted_sons.sort() if l_cc_nonrestricted_sons == l_c: colls_out_for_display = [cc] # yep, washing permitted, it is sufficient to display 'cc' else: colls_out_for_display = colls # nope, we need to display all 'colls' successively # remove duplicates: colls_out_for_display_nondups=filter(lambda x, colls_out_for_display=colls_out_for_display: colls_out_for_display[x-1] not in colls_out_for_display[x:], range(1, len(colls_out_for_display)+1)) colls_out_for_display = map(lambda x, colls_out_for_display=colls_out_for_display:colls_out_for_display[x-1], colls_out_for_display_nondups) # second, let us decide on collection splitting: if split_colls == 0: # type A - no sons are wanted colls_out = colls_out_for_display # elif split_colls == 1: else: # type B - sons (first-level descendants) are wanted for coll in colls_out_for_display: coll_sons = get_coll_sons(coll) if coll_sons == []: colls_out.append(coll) else: colls_out = colls_out + coll_sons # remove duplicates: colls_out_nondups=filter(lambda x, colls_out=colls_out: colls_out[x-1] not in colls_out[x:], range(1, len(colls_out)+1)) colls_out = map(lambda x, colls_out=colls_out:colls_out[x-1], colls_out_nondups) return (cc, colls_out_for_display, colls_out) def strip_accents(x): """Strip accents in the input phrase X (assumed in UTF-8) by replacing accented characters with their unaccented cousins (e.g. é by e). Return such a stripped X.""" # convert input into Unicode string: try: y = unicode(x, "utf-8") except: return x # something went wrong, probably the input wasn't UTF-8 # asciify Latin-1 lowercase characters: y = sre_unicode_lowercase_a.sub("a", y) y = sre_unicode_lowercase_ae.sub("ae", y) y = sre_unicode_lowercase_e.sub("e", y) y = sre_unicode_lowercase_i.sub("i", y) y = sre_unicode_lowercase_o.sub("o", y) y = sre_unicode_lowercase_u.sub("u", y) y = sre_unicode_lowercase_y.sub("y", y) y = sre_unicode_lowercase_c.sub("c", y) y = sre_unicode_lowercase_n.sub("n", y) # asciify Latin-1 uppercase characters: y = sre_unicode_uppercase_a.sub("A", y) y = sre_unicode_uppercase_ae.sub("AE", y) y = sre_unicode_uppercase_e.sub("E", y) y = sre_unicode_uppercase_i.sub("I", y) y = sre_unicode_uppercase_o.sub("O", y) y = sre_unicode_uppercase_u.sub("U", y) y = sre_unicode_uppercase_y.sub("Y", y) y = sre_unicode_uppercase_c.sub("C", y) y = sre_unicode_uppercase_n.sub("N", y) # return UTF-8 representation of the Unicode string: return y.encode("utf-8") def wash_pattern(p): """Wash pattern passed by URL. Check for sanity of the wildcard by removing wildcards if they are appended to extremely short words (1-3 letters). TODO: instead of this approximative treatment, it will be much better to introduce a temporal limit, e.g. to kill a query if it does not finish in 10 seconds.""" # strip accents: # p = strip_accents(p) # FIXME: when available, strip accents all the time # add leading/trailing whitespace for the two following wildcard-sanity checking regexps: p = " " + p + " " # get rid of wildcards at the beginning of words: p = sre_pattern_wildcards_at_beginning.sub("\\1", p) # replace spaces within quotes by __SPACE__ temporarily: p = sre_pattern_single_quotes.sub(lambda x: "'"+string.replace(x.group(1), ' ', '__SPACE__')+"'", p) p = sre_pattern_double_quotes.sub(lambda x: "\""+string.replace(x.group(1), ' ', '__SPACE__')+"\"", p) p = sre_pattern_regexp_quotes.sub(lambda x: "/"+string.replace(x.group(1), ' ', '__SPACE__')+"/", p) # get rid of extremely short words (1-3 letters with wildcards): p = sre_pattern_short_words.sub("\\1", p) # replace back __SPACE__ by spaces: p = sre_pattern_space.sub(" ", p) # replace special terms: p = sre_pattern_today.sub(time.strftime("%Y-%m-%d", time.localtime()), p) # remove unnecessary whitespace: p = string.strip(p) return p def wash_field(f): """Wash field passed by URL.""" # get rid of unnecessary whitespace: f = string.strip(f) # wash old-style CDS Invenio/ALEPH 'f' field argument, e.g. replaces 'wau' and 'au' by 'author' if CFG_WEBSEARCH_FIELDS_CONVERT.has_key(string.lower(f)): f = CFG_WEBSEARCH_FIELDS_CONVERT[f] return f def wash_dates(d1y=0, d1m=0, d1d=0, d2y=0, d2m=0, d2d=0): """Take user-submitted washed date arguments (D1Y, D1M, D1Y) and (D2Y, D2M, D2Y) and return (YYY1-M1-D2, YYY2-M2-D2) strings in the YYYY-MM-DD format suitable for time restricted searching. I.e. pay attention when months are not there to put 01 or 12 according to whether it's the starting or the ending date, etc. """ day1, day2 = "", "" # sanity checking: if d1y == 0 and d1m == 0 and d1d == 0 and d2y == 0 and d2m == 0 and d2d == 0: return ("", "") # nothing selected, so return empty values # construct day1 (from): if d1y: day1 += "%04d" % d1y else: day1 += "0000" if d1m: day1 += "-%02d" % d1m else: day1 += "-01" if d1d: day1 += "-%02d" % d1d else: day1 += "-01" # construct day2 (until): if d2y: day2 += "%04d" % d2y else: day2 += "9999" if d2m: day2 += "-%02d" % d2m else: day2 += "-12" if d2d: day2 += "-%02d" % d2d else: day2 += "-31" # NOTE: perhaps we should add max(datenumber) in # given month, but for our quering it's not # needed, 31 will always do # okay, return constructed YYYY-MM-DD dates return (day1, day2) def get_colID(c): "Return collection ID for collection name C. Return None if no match found." colID = None res = run_sql("SELECT id FROM collection WHERE name=%s", (c,), 1) if res: colID = res[0][0] return colID def get_coll_i18nname(c, ln=cdslang): """Return nicely formatted collection name (of name type 'ln', 'long name') for collection C in language LN.""" global collection_i18nname_cache global collection_i18nname_cache_timestamp # firstly, check whether the collectionname table was modified: if get_table_update_time('collectionname') > collection_i18nname_cache_timestamp: # yes it was, cache clear-up needed: collection_i18nname_cache = create_collection_i18nname_cache() # secondly, read i18n name from either the cache or return common name: out = c try: out = collection_i18nname_cache[c][ln] except KeyError: pass # translation in LN does not exist return out def get_field_i18nname(f, ln=cdslang): """Return nicely formatted field name (of type 'ln', 'long name') for field F in language LN.""" global field_i18nname_cache global field_i18nname_cache_timestamp # firstly, check whether the fieldname table was modified: if get_table_update_time('fieldname') > field_i18nname_cache_timestamp: # yes it was, cache clear-up needed: field_i18nname_cache = create_field_i18nname_cache() # secondly, read i18n name from either the cache or return common name: out = f try: out = field_i18nname_cache[f][ln] except KeyError: pass # translation in LN does not exist return out def get_coll_ancestors(coll): "Returns a list of ancestors for collection 'coll'." coll_ancestors = [] coll_ancestor = coll while 1: query = "SELECT c.name FROM collection AS c "\ "LEFT JOIN collection_collection AS cc ON c.id=cc.id_dad "\ "LEFT JOIN collection AS ccc ON ccc.id=cc.id_son "\ "WHERE ccc.name='%s' ORDER BY cc.id_dad ASC LIMIT 1" \ % escape_string(coll_ancestor) res = run_sql(query, None, 1) if res: coll_name = res[0][0] coll_ancestors.append(coll_name) coll_ancestor = coll_name else: break # ancestors found, return reversed list: coll_ancestors.reverse() return coll_ancestors def get_coll_sons(coll, type='r', public_only=1): """Return a list of sons (first-level descendants) of type 'type' for collection 'coll'. If public_only, then return only non-restricted son collections. """ coll_sons = [] query = "SELECT c.name FROM collection AS c "\ "LEFT JOIN collection_collection AS cc ON c.id=cc.id_son "\ "LEFT JOIN collection AS ccc ON ccc.id=cc.id_dad "\ "WHERE cc.type='%s' AND ccc.name='%s'" \ % (escape_string(type), escape_string(coll)) if public_only: query += " AND c.restricted IS NULL " query += " ORDER BY cc.score DESC" res = run_sql(query) for name in res: coll_sons.append(name[0]) return coll_sons def get_coll_real_descendants(coll): """Return a list of all descendants of collection 'coll' that are defined by a 'dbquery'. IOW, we need to decompose compound collections like "A & B" into "A" and "B" provided that "A & B" has no associated database query defined. """ coll_sons = [] query = "SELECT c.name,c.dbquery FROM collection AS c "\ "LEFT JOIN collection_collection AS cc ON c.id=cc.id_son "\ "LEFT JOIN collection AS ccc ON ccc.id=cc.id_dad "\ "WHERE ccc.name='%s' ORDER BY cc.score DESC" \ % escape_string(coll) res = run_sql(query) for name, dbquery in res: if dbquery: # this is 'real' collection, so return it: coll_sons.append(name) else: # this is 'composed' collection, so recurse: coll_sons.extend(get_coll_real_descendants(name)) return coll_sons def get_collection_reclist(coll): """Return hitset of recIDs that belong to the collection 'coll'. But firstly check the last updated date of the collection table. If it's newer than the cache timestamp, then empty the cache, since new records could have been added.""" global collection_reclist_cache global collection_reclist_cache_timestamp # firstly, check whether the collection table was modified: if get_table_update_time('collection') > collection_reclist_cache_timestamp: # yes it was, cache clear-up needed: collection_reclist_cache = create_collection_reclist_cache() # secondly, read reclist from either the cache or the database: if not collection_reclist_cache[coll]: # not yet it the cache, so calculate it and fill the cache: set = HitSet() query = "SELECT nbrecs,reclist FROM collection WHERE name='%s'" % coll res = run_sql(query, None, 1) if res: try: set._nbhits, set._set = res[0][0], Numeric.loads(zlib.decompress(res[0][1])) except: set._nbhits = 0 collection_reclist_cache[coll] = set # finally, return reclist: return collection_reclist_cache[coll] def coll_restricted_p(coll): "Predicate to test if the collection coll is restricted or not." if not coll: return 0 query = "SELECT restricted FROM collection WHERE name='%s'" % escape_string(coll) res = run_sql(query, None, 1) if res and res[0][0] is not None: return 1 else: return 0 def coll_restricted_group(coll): "Return Apache group to which the collection is restricted. Return None if it's public." if not coll: return None query = "SELECT restricted FROM collection WHERE name='%s'" % escape_string(coll) res = run_sql(query, None, 1) if res: return res[0][0] else: return None def create_collection_reclist_cache(): """Creates list of records belonging to collections. Called on startup and used later for intersecting search results with collection universe.""" global collection_reclist_cache_timestamp # populate collection reclist cache: collrecs = {} try: res = run_sql("SELECT name,reclist FROM collection") except Error: # database problems, set timestamp to zero and return empty cache collection_reclist_cache_timestamp = 0 return collrecs for name, reclist in res: collrecs[name] = None # this will be filled later during runtime by calling get_collection_reclist(coll) # update timestamp: try: collection_reclist_cache_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) except NameError: collection_reclist_cache_timestamp = 0 return collrecs try: collection_reclist_cache.has_key(cdsname) except: try: collection_reclist_cache = create_collection_reclist_cache() except: collection_reclist_cache = {} def create_collection_i18nname_cache(): """Create cache of I18N collection names of type 'ln' (=long name). Called on startup and used later during the search time.""" global collection_i18nname_cache_timestamp # populate collection I18N name cache: names = {} try: res = run_sql("SELECT c.name,cn.ln,cn.value FROM collectionname AS cn, collection AS c WHERE cn.id_collection=c.id AND cn.type='ln'") # ln=long name except Error: # database problems, set timestamp to zero and return empty cache collection_i18nname_cache_timestamp = 0 return names for c, ln, i18nname in res: if i18nname: if not names.has_key(c): names[c] = {} names[c][ln] = i18nname # update timestamp: try: collection_i18nname_cache_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) except NameError: collection_i18nname_cache_timestamp = 0 return names try: collection_i18nname_cache.has_key(cdsname) except: try: collection_i18nname_cache = create_collection_i18nname_cache() except: collection_i18nname_cache = {} def create_field_i18nname_cache(): """Create cache of I18N field names of type 'ln' (=long name). Called on startup and used later during the search time.""" global field_i18nname_cache_timestamp # populate field I18 name cache: names = {} try: res = run_sql("SELECT f.name,fn.ln,fn.value FROM fieldname AS fn, field AS f WHERE fn.id_field=f.id AND fn.type='ln'") # ln=long name except Error: # database problems, set timestamp to zero and return empty cache field_i18nname_cache_timestamp = 0 return names for f, ln, i18nname in res: if i18nname: if not names.has_key(f): names[f] = {} names[f][ln] = i18nname # update timestamp: try: field_i18nname_cache_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) except NameError: field_i18nname_cache_timestamp = 0 return names try: field_i18nname_cache.has_key(cdsname) except: try: field_i18nname_cache = create_field_i18nname_cache() except: field_i18nname_cache = {} def browse_pattern(req, colls, p, f, rg, ln=cdslang): """Browse either biliographic phrases or words indexes, and display it.""" # load the right message language _ = gettext_set_language(ln) ## do we search in words indexes? if not f: return browse_in_bibwords(req, p, f) p_orig = p ## okay, "real browse" follows: browsed_phrases = get_nearest_terms_in_bibxxx(p, f, rg, 1) while not browsed_phrases: # try again and again with shorter and shorter pattern: try: p = p[:-1] browsed_phrases = get_nearest_terms_in_bibxxx(p, f, rg, 1) except: # probably there are no hits at all: req.write(_("No values found.")) return ## try to check hits in these particular collection selection: browsed_phrases_in_colls = [] if 0: for phrase in browsed_phrases: phrase_hitset = HitSet() phrase_hitsets = search_pattern("", phrase, f, 'e') for coll in colls: phrase_hitset.union(phrase_hitsets[coll]) phrase_hitset.calculate_nbhits() if phrase_hitset._nbhits > 0: # okay, this phrase has some hits in colls, so add it: browsed_phrases_in_colls.append([phrase, phrase_hitset._nbhits]) ## were there hits in collections? if browsed_phrases_in_colls == []: if browsed_phrases != []: #print_warning(req, """

No match close to %s found in given collections. #Please try different term.

Displaying matches in any collection...""" % p_orig) ## try to get nbhits for these phrases in any collection: for phrase in browsed_phrases: browsed_phrases_in_colls.append([phrase, get_nbhits_in_bibxxx(phrase, f)]) ## display results now: out = websearch_templates.tmpl_browse_pattern( f=get_field_i18nname(f, ln), ln=ln, browsed_phrases_in_colls=browsed_phrases_in_colls, colls=colls, ) req.write(out) return def browse_in_bibwords(req, p, f, ln=cdslang): """Browse inside words indexes.""" if not p: return _ = gettext_set_language(ln) urlargd = {} urlargd.update(req.argd) urlargd['action'] = 'search' nearest_box = create_nearest_terms_box(urlargd, p, f, 'w', ln=ln, intro_text_p=0) req.write(websearch_templates.tmpl_search_in_bibwords( p = p, f = f, ln = ln, nearest_box = nearest_box )) return def search_pattern(req=None, p=None, f=None, m=None, ap=0, of="id", verbose=0, ln=cdslang): """Search for complex pattern 'p' within field 'f' according to matching type 'm'. Return hitset of recIDs. The function uses multi-stage searching algorithm in case of no exact match found. See the Search Internals document for detailed description. The 'ap' argument governs whether an alternative patterns are to be used in case there is no direct hit for (p,f,m). For example, whether to replace non-alphanumeric characters by spaces if it would give some hits. See the Search Internals document for detailed description. (ap=0 forbits the alternative pattern usage, ap=1 permits it.) The 'of' argument governs whether to print or not some information to the user in case of no match found. (Usually it prints the information in case of HTML formats, otherwise it's silent). The 'verbose' argument controls the level of debugging information to be printed (0=least, 9=most). All the parameters are assumed to have been previously washed. This function is suitable as a mid-level API. """ _ = gettext_set_language(ln) hitset_empty = HitSet() hitset_empty._nbhits = 0 # sanity check: if not p: hitset_full = HitSet(Numeric.ones(CFG_MAX_RECID+1, Numeric.Int0)) hitset_full._nbhits = CFG_MAX_RECID # no pattern, so return all universe return hitset_full # search stage 1: break up arguments into basic search units: if verbose and of.startswith("h"): t1 = os.times()[4] basic_search_units = create_basic_search_units(req, p, f, m, of) if verbose and of.startswith("h"): t2 = os.times()[4] print_warning(req, "Search stage 1: basic search units are: %s" % basic_search_units) print_warning(req, "Search stage 1: execution took %.2f seconds." % (t2 - t1)) # search stage 2: do search for each search unit and verify hit presence: if verbose and of.startswith("h"): t1 = os.times()[4] basic_search_units_hitsets = [] for idx_unit in range(0, len(basic_search_units)): bsu_o, bsu_p, bsu_f, bsu_m = basic_search_units[idx_unit] basic_search_unit_hitset = search_unit(bsu_p, bsu_f, bsu_m) if verbose >= 9 and of.startswith("h"): print_warning(req, "Search stage 1: pattern %s gave hitlist %s" % (bsu_p, Numeric.nonzero(basic_search_unit_hitset._set))) if basic_search_unit_hitset._nbhits > 0 or \ ap==0 or \ bsu_o=="|" or \ ((idx_unit+1) 0: # we retain the new unit instead if of.startswith('h'): print_warning(req, _("No exact match found for %(x_query1)s, using %(x_query2)s instead...") % {'x_query1': "" + cgi.escape(bsu_p) + "", 'x_query2': "" + cgi.escape(bsu_pn) + ""}) basic_search_units[idx_unit][1] = bsu_pn basic_search_units_hitsets.append(basic_search_unit_hitset) else: # stage 2-3: no hits found either, propose nearest indexed terms: if of.startswith('h'): if req: if bsu_f == "recid": print_warning(req, "Requested record does not seem to exist.") else: print_warning(req, create_nearest_terms_box(req.argd, bsu_p, bsu_f, bsu_m, ln=ln)) return hitset_empty else: # stage 2-3: no hits found either, propose nearest indexed terms: if of.startswith('h'): if req: if bsu_f == "recid": print_warning(req, "Requested record does not seem to exist.") else: print_warning(req, create_nearest_terms_box(req.argd, bsu_p, bsu_f, bsu_m, ln=ln)) return hitset_empty if verbose and of.startswith("h"): t2 = os.times()[4] for idx_unit in range(0, len(basic_search_units)): print_warning(req, "Search stage 2: basic search unit %s gave %d hits." % (basic_search_units[idx_unit][1:], basic_search_units_hitsets[idx_unit]._nbhits)) print_warning(req, "Search stage 2: execution took %.2f seconds." % (t2 - t1)) # search stage 3: apply boolean query for each search unit: if verbose and of.startswith("h"): t1 = os.times()[4] # let the initial set be the complete universe: hitset_in_any_collection = HitSet(Numeric.ones(CFG_MAX_RECID+1, Numeric.Int0)) for idx_unit in range(0, len(basic_search_units)): this_unit_operation = basic_search_units[idx_unit][0] this_unit_hitset = basic_search_units_hitsets[idx_unit] if this_unit_operation == '+': hitset_in_any_collection.intersect(this_unit_hitset) elif this_unit_operation == '-': hitset_in_any_collection.difference(this_unit_hitset) elif this_unit_operation == '|': hitset_in_any_collection.union(this_unit_hitset) else: if of.startswith("h"): print_warning(req, "Invalid set operation %s." % this_unit_operation, "Error") hitset_in_any_collection.calculate_nbhits() if hitset_in_any_collection._nbhits == 0: # no hits found, propose alternative boolean query: if of.startswith('h'): nearestterms = [] for idx_unit in range(0, len(basic_search_units)): bsu_o, bsu_p, bsu_f, bsu_m = basic_search_units[idx_unit] if bsu_p.startswith("%") and bsu_p.endswith("%"): bsu_p = "'" + bsu_p[1:-1] + "'" bsu_nbhits = basic_search_units_hitsets[idx_unit]._nbhits # create a similar query, but with the basic search unit only argd = {} argd.update(req.argd) argd['p'] = bsu_p argd['f'] = bsu_f nearestterms.append((bsu_p, bsu_nbhits, argd)) text = websearch_templates.tmpl_search_no_boolean_hits( ln=ln, nearestterms=nearestterms) print_warning(req, text) if verbose and of.startswith("h"): t2 = os.times()[4] print_warning(req, "Search stage 3: boolean query gave %d hits." % hitset_in_any_collection._nbhits) print_warning(req, "Search stage 3: execution took %.2f seconds." % (t2 - t1)) return hitset_in_any_collection def search_unit(p, f=None, m=None): """Search for basic search unit defined by pattern 'p' and field 'f' and matching type 'm'. Return hitset of recIDs. All the parameters are assumed to have been previously washed. 'p' is assumed to be already a ``basic search unit'' so that it is searched as such and is not broken up in any way. Only wildcard and span queries are being detected inside 'p'. This function is suitable as a low-level API. """ ## create empty output results set: set = HitSet() if not p: # sanity checking return set if m == 'a' or m == 'r': # we are doing either direct bibxxx search or phrase search or regexp search set = search_unit_in_bibxxx(p, f, m) else: # we are doing bibwords search by default set = search_unit_in_bibwords(p, f) set.calculate_nbhits() return set def search_unit_in_bibwords(word, f, decompress=zlib.decompress): """Searches for 'word' inside bibwordsX table for field 'f' and returns hitset of recIDs.""" set = HitSet() # will hold output result set set_used = 0 # not-yet-used flag, to be able to circumvent set operations # deduce into which bibwordsX table we will search: bibwordsX = "idxWORD%02dF" % get_index_id("anyfield") if f: index_id = get_index_id(f) if index_id: bibwordsX = "idxWORD%02dF" % index_id else: return HitSet() # word index f does not exist # wash 'word' argument and construct query: word = string.replace(word, '*', '%') # we now use '*' as the truncation character words = string.split(word, "->", 1) # check for span query if len(words) == 2: word0 = sre_word.sub('', words[0]) word1 = sre_word.sub('', words[1]) query = "SELECT term,hitlist FROM %s WHERE term BETWEEN '%s' AND '%s'" % (bibwordsX, escape_string(word0[:50]), escape_string(word1[:50])) else: word = sre_word.sub('', word) if string.find(word, '%') >= 0: # do we have wildcard in the word? query = "SELECT term,hitlist FROM %s WHERE term LIKE '%s'" % (bibwordsX, escape_string(word[:50])) else: query = "SELECT term,hitlist FROM %s WHERE term='%s'" % (bibwordsX, escape_string(word[:50])) # launch the query: res = run_sql(query) # fill the result set: for word, hitlist in res: hitset_bibwrd = HitSet(Numeric.loads(decompress(hitlist))) # add the results: if set_used: set.union(hitset_bibwrd) else: set = hitset_bibwrd set_used = 1 # okay, return result set: return set def search_unit_in_bibxxx(p, f, type): """Searches for pattern 'p' inside bibxxx tables for field 'f' and returns hitset of recIDs found. The search type is defined by 'type' (e.g. equals to 'r' for a regexp search).""" p_orig = p # saving for eventual future 'no match' reporting # wash arguments: f = string.replace(f, '*', '%') # replace truncation char '*' in field definition if type == 'r': pattern = "REGEXP '%s'" % escape_string(p) else: p = string.replace(p, '*', '%') # we now use '*' as the truncation character ps = string.split(p, "->", 1) # check for span query: if len(ps) == 2: pattern = "BETWEEN '%s' AND '%s'" % (escape_string(ps[0]), escape_string(ps[1])) else: if string.find(p, '%') > -1: pattern = "LIKE '%s'" % escape_string(ps[0]) else: pattern = "='%s'" % escape_string(ps[0]) # construct 'tl' which defines the tag list (MARC tags) to search in: tl = [] if str(f[0]).isdigit() and str(f[1]).isdigit(): tl.append(f) # 'f' seems to be okay as it starts by two digits else: # convert old ALEPH tag names, if appropriate: (TODO: get rid of this before entering this function) if CFG_WEBSEARCH_FIELDS_CONVERT.has_key(string.lower(f)): f = CFG_WEBSEARCH_FIELDS_CONVERT[string.lower(f)] # deduce desired MARC tags on the basis of chosen 'f' tl = get_field_tags(f) if not tl: # f index does not exist, nevermind pass # okay, start search: l = [] # will hold list of recID that matched for t in tl: # deduce into which bibxxx table we will search: digit1, digit2 = int(t[0]), int(t[1]) bx = "bib%d%dx" % (digit1, digit2) bibx = "bibrec_bib%d%dx" % (digit1, digit2) # construct query: if t == "001": query = "SELECT id FROM bibrec WHERE id %s" % pattern else: if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character: query = "SELECT bibx.id_bibrec FROM %s AS bx LEFT JOIN %s AS bibx ON bx.id=bibx.id_bibxxx WHERE bx.value %s AND bx.tag LIKE '%s%%'" % \ (bx, bibx, pattern, t) else: query = "SELECT bibx.id_bibrec FROM %s AS bx LEFT JOIN %s AS bibx ON bx.id=bibx.id_bibxxx WHERE bx.value %s AND bx.tag='%s'" % \ (bx, bibx, pattern, t) # launch the query: res = run_sql(query) # fill the result set: for id_bibrec in res: if id_bibrec[0]: l.append(id_bibrec[0]) # check no of hits found: nb_hits = len(l) # okay, return result set: set = HitSet() set.addlist(Numeric.array(l)) return set def search_unit_in_bibrec(day1, day2, type='creation_date'): """Return hitset of recIDs found that were either created or modified (see 'type' arg) from day1 until day2, inclusive. Does not pay attention to pattern, collection, anything. Useful to intersect later on with the 'real' query.""" set = HitSet() if type != "creation_date" and type != "modification_date": # type argument is invalid, so search for creation dates by default type = "creation_date" res = run_sql("SELECT id FROM bibrec WHERE %s>=%s AND %s<=%s" % (type, "%s", type, "%s"), (day1, day2)) l = [] for row in res: l.append(row[0]) set.addlist(Numeric.array(l)) return set def intersect_results_with_collrecs(req, hitset_in_any_collection, colls, ap=0, of="hb", verbose=0, ln=cdslang): """Return dict of hitsets given by intersection of hitset with the collection universes.""" _ = gettext_set_language(ln) # search stage 4: intersect with the collection universe: if verbose and of.startswith("h"): t1 = os.times()[4] results = {} results_nbhits = 0 for coll in colls: results[coll] = HitSet() results[coll]._set = Numeric.bitwise_and(hitset_in_any_collection._set, get_collection_reclist(coll)._set) results[coll].calculate_nbhits() results_nbhits += results[coll]._nbhits if results_nbhits == 0: # no hits found, try to search in Home: results_in_Home = HitSet() results_in_Home._set = Numeric.bitwise_and(hitset_in_any_collection._set, get_collection_reclist(cdsname)._set) results_in_Home.calculate_nbhits() if results_in_Home._nbhits > 0: # some hits found in Home, so propose this search: if of.startswith("h"): url = websearch_templates.build_search_url(req.argd, cc=cdsname, c=[]) print_warning(req, _("No match found in collection %(x_collection)s. Other public collections gave %(x_url_open)s%(x_nb_hits)d hits%(x_url_close)s.") %\ {'x_collection': '' + string.join([get_coll_i18nname(coll, ln) for coll in colls], ', ') + '', 'x_url_open': '' % (url), 'x_nb_hits': results_in_Home._nbhits, 'x_url_close': ''}) results = {} else: # no hits found in Home, recommend different search terms: if of.startswith("h"): print_warning(req, _("No public collection matched your query. " "If you were looking for a non-public document, please choose " "the desired restricted collection first.")) results = {} if verbose and of.startswith("h"): t2 = os.times()[4] print_warning(req, "Search stage 4: intersecting with collection universe gave %d hits." % results_nbhits) print_warning(req, "Search stage 4: execution took %.2f seconds." % (t2 - t1)) return results def intersect_results_with_hitset(req, results, hitset, ap=0, aptext="", of="hb"): """Return intersection of search 'results' (a dict of hitsets with collection as key) with the 'hitset', i.e. apply 'hitset' intersection to each collection within search 'results'. If the final 'results' set is to be empty, and 'ap' (approximate pattern) is true, and then print the `warningtext' and return the original 'results' set unchanged. If 'ap' is false, then return empty results set. """ if ap: results_ap = copy.deepcopy(results) else: results_ap = {} # will return empty dict in case of no hits found nb_total = 0 for coll in results.keys(): results[coll].intersect(hitset) results[coll].calculate_nbhits() nb_total += results[coll]._nbhits if nb_total == 0: if of.startswith("h"): print_warning(req, aptext) results = results_ap return results def create_similarly_named_authors_link_box(author_name, ln=cdslang): """Return a box similar to ``Not satisfied...'' one by proposing author searches for similar names. Namely, take AUTHOR_NAME and the first initial of the firstame (after comma) and look into author index whether authors with e.g. middle names exist. Useful mainly for CERN Library that sometimes contains name forms like Ellis-N, Ellis-Nick, Ellis-Nicolas all denoting the same person. The box isn't proposed if no similarly named authors are found to exist. """ # return nothing if not configured: if CFG_WEBSEARCH_CREATE_SIMILARLY_NAMED_AUTHORS_LINK_BOX == 0: return "" # return empty box if there is no initial: if sre.match(r'[^ ,]+, [^ ]', author_name) is None: return "" # firstly find name comma initial: author_name_to_search = sre.sub(r'^([^ ,]+, +[^ ,]).*$', '\\1', author_name) # secondly search for similar name forms: similar_author_names = {} for name in author_name_to_search, strip_accents(author_name_to_search): for tag in get_field_tags("author"): # deduce into which bibxxx table we will search: digit1, digit2 = int(tag[0]), int(tag[1]) bx = "bib%d%dx" % (digit1, digit2) bibx = "bibrec_bib%d%dx" % (digit1, digit2) if len(tag) != 6 or tag[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character: query = "SELECT bx.value FROM %s AS bx WHERE bx.value LIKE '%s%%' AND bx.tag LIKE '%s%%'" \ % (bx, escape_string(name), tag) else: query = "SELECT bx.value FROM %s AS bx WHERE bx.value LIKE '%s%%' AND bx.tag='%s'" \ % (bx, escape_string(name), tag) res = run_sql(query) for row in res: similar_author_names[row[0]] = 1 # remove the original name and sort the list: try: del similar_author_names[author_name] except KeyError: pass # thirdly print the box: out = "" if similar_author_names: out_authors = similar_author_names.keys() out_authors.sort() tmp_authors = [] for out_author in out_authors: nbhits = get_nbhits_in_bibxxx(out_author, "author") if nbhits: tmp_authors.append((out_author, nbhits)) out += websearch_templates.tmpl_similar_author_names( authors=tmp_authors, ln=ln) return out def create_nearest_terms_box(urlargd, p, f, t='w', n=5, ln=cdslang, intro_text_p=True): """Return text box containing list of 'n' nearest terms above/below 'p' for the field 'f' for matching type 't' (words/phrases) in language 'ln'. Propose new searches according to `urlargs' with the new words. If `intro_text_p' is true, then display the introductory message, otherwise print only the nearest terms in the box content. """ # load the right message language _ = gettext_set_language(ln) out = "" nearest_terms = [] if not p: # sanity check p = "." # look for nearest terms: if t == 'w': nearest_terms = get_nearest_terms_in_bibwords(p, f, n, n) if not nearest_terms: return "%s %s." % (_("No words index available for"), get_field_i18nname(f, ln)) else: nearest_terms = get_nearest_terms_in_bibxxx(p, f, n, n) if not nearest_terms: return "%s %s." % (_("No phrase index available for"), get_field_i18nname(f, ln)) terminfo = [] for term in nearest_terms: if t == 'w': hits = get_nbhits_in_bibwords(term, f) else: hits = get_nbhits_in_bibxxx(term, f) argd = {} argd.update(urlargd) # check which fields contained the requested parameter, and replace it. for (px, fx) in ('p', 'f'), ('p1', 'f1'), ('p2', 'f2'), ('p3', 'f3'): if px in argd: if f == argd[fx] or f == "anyfield" or f == "": if string.find(argd[px], p) > -1: argd[px] = string.replace(argd[px], p, term) break else: if string.find(argd[px], f+':'+p) > -1: argd[px] = string.replace(argd[px], f+':'+p, f+':'+term) break elif string.find(argd[px], f+':"'+p+'"') > -1: argd[px] = string.replace(argd[px], f+':"'+p+'"', f+':"'+term+'"') break terminfo.append((term, hits, argd)) intro = "" if intro_text_p: # add full leading introductory text if f: intro = _("Search term %(x_term)s inside index %(x_index)s did not match any record. Nearest terms in any collection are:") % \ {'x_term': "" + cgi.escape(p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "", 'x_index': "" + cgi.escape(get_field_i18nname(f, ln)) + ""} else: intro = _("Search term %s did not match any record. Nearest terms in any collection are:") % \ ("" + cgi.escape(p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "") return websearch_templates.tmpl_nearest_term_box(p=p, ln=ln, f=f, terminfo=terminfo, intro=intro) def get_nearest_terms_in_bibwords(p, f, n_below, n_above): """Return list of +n -n nearest terms to word `p' in index for field `f'.""" nearest_words = [] # will hold the (sorted) list of nearest words to return # deduce into which bibwordsX table we will search: bibwordsX = "idxWORD%02dF" % get_index_id("anyfield") if f: index_id = get_index_id(f) if index_id: bibwordsX = "idxWORD%02dF" % index_id else: return nearest_words # firstly try to get `n' closest words above `p': query = "SELECT term FROM %s WHERE term<'%s' ORDER BY term DESC LIMIT %d" % (bibwordsX, escape_string(p), n_above) res = run_sql(query) for row in res: nearest_words.append(row[0]) nearest_words.reverse() # secondly insert given word `p': nearest_words.append(p) # finally try to get `n' closest words below `p': query = "SELECT term FROM %s WHERE term>'%s' ORDER BY term ASC LIMIT %d" % (bibwordsX, escape_string(p), n_below) res = run_sql(query) for row in res: nearest_words.append(row[0]) return nearest_words def get_nearest_terms_in_bibxxx(p, f, n_below, n_above): """Browse (-n_above, +n_below) closest bibliographic phrases for the given pattern p in the given field f, regardless of collection. Return list of [phrase1, phrase2, ... , phrase_n].""" ## determine browse field: if not f and string.find(p, ":") > 0: # does 'p' contain ':'? f, p = string.split(p, ":", 1) ## We are going to take max(n_below, n_above) as the number of ## values to ferch from bibXXx. This is needed to work around ## MySQL UTF-8 sorting troubles in 4.0.x. Proper solution is to ## use MySQL 4.1.x or our own idxPHRASE in the future. n_fetch = 2*max(n_below, n_above) ## construct 'tl' which defines the tag list (MARC tags) to search in: tl = [] if str(f[0]).isdigit() and str(f[1]).isdigit(): tl.append(f) # 'f' seems to be okay as it starts by two digits else: # deduce desired MARC tags on the basis of chosen 'f' tl = get_field_tags(f) ## start browsing to fetch list of hits: browsed_phrases = {} # will hold {phrase1: 1, phrase2: 1, ..., phraseN: 1} dict of browsed phrases (to make them unique) # always add self to the results set: browsed_phrases[p.startswith("%") and p.endswith("%") and p[1:-1] or p] = 1 for t in tl: # deduce into which bibxxx table we will search: digit1, digit2 = int(t[0]), int(t[1]) bx = "bib%d%dx" % (digit1, digit2) bibx = "bibrec_bib%d%dx" % (digit1, digit2) # firstly try to get `n' closest phrases above `p': if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character: query = "SELECT bx.value FROM %s AS bx WHERE bx.value<'%s' AND bx.tag LIKE '%s%%' ORDER BY bx.value DESC LIMIT %d" \ % (bx, escape_string(p), t, n_fetch) else: query = "SELECT bx.value FROM %s AS bx WHERE bx.value<'%s' AND bx.tag='%s' ORDER BY bx.value DESC LIMIT %d" \ % (bx, escape_string(p), t, n_fetch) res = run_sql(query) for row in res: browsed_phrases[row[0]] = 1 # secondly try to get `n' closest phrases equal to or below `p': if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character: query = "SELECT bx.value FROM %s AS bx WHERE bx.value>='%s' AND bx.tag LIKE '%s%%' ORDER BY bx.value ASC LIMIT %d" \ % (bx, escape_string(p), t, n_fetch) else: query = "SELECT bx.value FROM %s AS bx WHERE bx.value>='%s' AND bx.tag='%s' ORDER BY bx.value ASC LIMIT %d" \ % (bx, escape_string(p), t, n_fetch) res = run_sql(query) for row in res: browsed_phrases[row[0]] = 1 # select first n words only: (this is needed as we were searching # in many different tables and so aren't sure we have more than n # words right; this of course won't be needed when we shall have # one ACC table only for given field): phrases_out = browsed_phrases.keys() phrases_out.sort(lambda x, y: cmp(string.lower(strip_accents(x)), string.lower(strip_accents(y)))) # find position of self: try: idx_p = phrases_out.index(p) except: idx_p = len(phrases_out)/2 # return n_above and n_below: return phrases_out[max(0, idx_p-n_above):idx_p+n_below] def get_nbhits_in_bibwords(word, f): """Return number of hits for word 'word' inside words index for field 'f'.""" out = 0 # deduce into which bibwordsX table we will search: bibwordsX = "idxWORD%02dF" % get_index_id("anyfield") if f: index_id = get_index_id(f) if index_id: bibwordsX = "idxWORD%02dF" % index_id else: return 0 if word: query = "SELECT hitlist FROM %s WHERE term='%s'" % (bibwordsX, escape_string(word)) res = run_sql(query) for hitlist in res: out += Numeric.sum(Numeric.loads(zlib.decompress(hitlist[0])).copy().astype(Numeric.Int)) return out def get_nbhits_in_bibxxx(p, f): """Return number of hits for word 'word' inside words index for field 'f'.""" ## determine browse field: if not f and string.find(p, ":") > 0: # does 'p' contain ':'? f, p = string.split(p, ":", 1) ## construct 'tl' which defines the tag list (MARC tags) to search in: tl = [] if str(f[0]).isdigit() and str(f[1]).isdigit(): tl.append(f) # 'f' seems to be okay as it starts by two digits else: # deduce desired MARC tags on the basis of chosen 'f' tl = get_field_tags(f) # start searching: recIDs = {} # will hold dict of {recID1: 1, recID2: 1, ..., } (unique recIDs, therefore) for t in tl: # deduce into which bibxxx table we will search: digit1, digit2 = int(t[0]), int(t[1]) bx = "bib%d%dx" % (digit1, digit2) bibx = "bibrec_bib%d%dx" % (digit1, digit2) if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character: query = """SELECT bibx.id_bibrec FROM %s AS bibx, %s AS bx WHERE bx.value='%s' AND bx.tag LIKE '%s%%' AND bibx.id_bibxxx=bx.id""" \ % (bibx, bx, escape_string(p), t) else: query = """SELECT bibx.id_bibrec FROM %s AS bibx, %s AS bx WHERE bx.value='%s' AND bx.tag='%s' AND bibx.id_bibxxx=bx.id""" \ % (bibx, bx, escape_string(p), t) res = run_sql(query) for row in res: recIDs[row[0]] = 1 return len(recIDs) def get_mysql_recid_from_aleph_sysno(sysno): """Returns DB's recID for ALEPH sysno passed in the argument (e.g. "002379334CER"). Returns None in case of failure.""" out = None query = "SELECT bb.id_bibrec FROM bibrec_bib97x AS bb, bib97x AS b WHERE b.value='%s' AND b.tag='970__a' AND bb.id_bibxxx=b.id" % \ (escape_string(sysno)) res = run_sql(query, None, 1) if res: out = res[0][0] return out def guess_primary_collection_of_a_record(recID): """Return primary collection name a record recid belongs to, by testing 980 identifier. May lead to bad guesses when a collection is defined dynamically bia dbquery. In that case, return 'cdsname'.""" out = cdsname dbcollids = get_fieldvalues(recID, "980__a") if dbcollids: dbquery = "collection:" + dbcollids[0] res = run_sql("SELECT name FROM collection WHERE dbquery=%s", (dbquery,)) if res: out = res[0][0] return out def get_tag_name(tag_value, prolog="", epilog=""): """Return tag name from the known tag value, by looking up the 'tag' table. Return empty string in case of failure. Example: input='100__%', output=first author'.""" out = "" res = run_sql("SELECT name FROM tag WHERE value=%s", (tag_value,)) if res: out = prolog + res[0][0] + epilog return out def get_fieldcodes(): """Returns a list of field codes that may have been passed as 'search options' in URL. Example: output=['subject','division'].""" out = [] res = run_sql("SELECT DISTINCT(code) FROM field") for row in res: out.append(row[0]) return out def get_field_tags(field): """Returns a list of MARC tags for the field code 'field'. Returns empty list in case of error. Example: field='author', output=['100__%','700__%'].""" out = [] query = """SELECT t.value FROM tag AS t, field_tag AS ft, field AS f WHERE f.code='%s' AND ft.id_field=f.id AND t.id=ft.id_tag ORDER BY ft.score DESC""" % field res = run_sql(query) for val in res: out.append(val[0]) return out def get_fieldvalues(recID, tag): """Return list of field values for field TAG inside record RECID.""" out = [] if tag == "001___": # we have asked for recID that is not stored in bibXXx tables out.append(str(recID)) else: # we are going to look inside bibXXx tables digits = tag[0:2] try: intdigits = int(digits) if intdigits < 0 or intdigits > 99: raise ValueError except ValueError: # invalid tag value asked for return [] bx = "bib%sx" % digits bibx = "bibrec_bib%sx" % digits query = "SELECT bx.value FROM %s AS bx, %s AS bibx " \ " WHERE bibx.id_bibrec='%s' AND bx.id=bibx.id_bibxxx AND bx.tag LIKE '%s' " \ " ORDER BY bibx.field_number, bx.tag ASC" % (bx, bibx, recID, tag) res = run_sql(query) for row in res: out.append(row[0]) return out def get_fieldvalues_alephseq_like(recID, tags_in): """Return buffer of ALEPH sequential-like textual format with fields found in the list TAGS_IN for record RECID.""" out = "" if type(tags_in) is not list: tags_in = [tags_in,] if len(tags_in) == 1 and len(tags_in[0]) == 6: ## case A: one concrete subfield asked, so print its value if found ## (use with care: can false you if field has multiple occurrences) out += string.join(get_fieldvalues(recID, tags_in[0]),"\n") else: ## case B: print our "text MARC" format; works safely all the time # find out which tags to output: dict_of_tags_out = {} if not tags_in: for i in range(0, 10): for j in range(0, 10): dict_of_tags_out["%d%d%%" % (i, j)] = 1 else: for tag in tags_in: if len(tag) == 0: for i in range(0, 10): for j in range(0, 10): dict_of_tags_out["%d%d%%" % (i, j)] = 1 elif len(tag) == 1: for j in range(0, 10): dict_of_tags_out["%s%d%%" % (tag, j)] = 1 elif len(tag) < 5: dict_of_tags_out["%s%%" % tag] = 1 elif tag >= 6: dict_of_tags_out[tag[0:5]] = 1 tags_out = dict_of_tags_out.keys() tags_out.sort() # search all bibXXx tables as needed: for tag in tags_out: digits = tag[0:2] try: intdigits = int(digits) if intdigits < 0 or intdigits > 99: raise ValueError except ValueError: # invalid tag value asked for continue if tag.startswith("001") or tag.startswith("00%"): if out: out += "\n" out += "%09d %s %d" % (recID, "001__", recID) bx = "bib%sx" % digits bibx = "bibrec_bib%sx" % digits query = "SELECT b.tag,b.value,bb.field_number FROM %s AS b, %s AS bb "\ "WHERE bb.id_bibrec='%s' AND b.id=bb.id_bibxxx AND b.tag LIKE '%s%%' "\ "ORDER BY bb.field_number, b.tag ASC" % (bx, bibx, recID, tag) res = run_sql(query) # go through fields: field_number_old = -999 field_old = "" for row in res: field, value, field_number = row[0], row[1], row[2] ind1, ind2 = field[3], field[4] if ind1 == "_": ind1 = "" if ind2 == "_": ind2 = "" # print field tag if field_number != field_number_old or field[:-1] != field_old[:-1]: if out: out += "\n" out += "%09d %s " % (recID, field[:5]) field_number_old = field_number field_old = field # print subfield value if field[0:2] == "00" and field[-1:] == "_": out += value else: out += "$$%s%s" % (field[-1:], value) return out def record_exists(recID): """Return 1 if record RECID exists. Return 0 if it doesn't exist. Return -1 if it exists but is marked as deleted.""" out = 0 query = "SELECT id FROM bibrec WHERE id='%s'" % recID res = run_sql(query, None, 1) if res: # record exists; now check whether it isn't marked as deleted: dbcollids = get_fieldvalues(recID, "980__%") if ("DELETED" in dbcollids) or (CFG_CERN_SITE and "DUMMY" in dbcollids): out = -1 # exists, but marked as deleted else: out = 1 # exists fine return out def record_public_p(recID): """Return 1 if the record is public, i.e. if it can be found in the Home collection. Return 0 otherwise. """ return get_collection_reclist(cdsname).contains(recID) def get_creation_date(recID, fmt="%Y-%m-%d"): "Returns the creation date of the record 'recID'." out = "" res = run_sql("SELECT DATE_FORMAT(creation_date,%s) FROM bibrec WHERE id=%s", (fmt, recID), 1) if res: out = res[0][0] return out def get_modification_date(recID, fmt="%Y-%m-%d"): "Returns the date of last modification for the record 'recID'." out = "" res = run_sql("SELECT DATE_FORMAT(modification_date,%s) FROM bibrec WHERE id=%s", (fmt, recID), 1) if res: out = res[0][0] return out def print_warning(req, msg, type='', prologue='
', epilogue='
'): "Prints warning message and flushes output." if req and msg: req.write(websearch_templates.tmpl_print_warning( msg = msg, type = type, prologue = prologue, epilogue = epilogue, )) return def print_search_info(p, f, sf, so, sp, rm, of, ot, collection=cdsname, nb_found=-1, jrec=1, rg=10, as=0, ln=cdslang, p1="", p2="", p3="", f1="", f2="", f3="", m1="", m2="", m3="", op1="", op2="", sc=1, pl_in_url="", d1y=0, d1m=0, d1d=0, d2y=0, d2m=0, d2d=0, cpu_time=-1, middle_only=0): """Prints stripe with the information on 'collection' and 'nb_found' results and CPU time. Also, prints navigation links (beg/next/prev/end) inside the results set. If middle_only is set to 1, it will only print the middle box information (beg/netx/prev/end/etc) links. This is suitable for displaying navigation links at the bottom of the search results page.""" out = "" # sanity check: if jrec < 1: jrec = 1 if jrec > nb_found: jrec = max(nb_found-rg+1, 1) return websearch_templates.tmpl_print_search_info( ln = ln, weburl = weburl, collection = collection, as = as, collection_name = get_coll_i18nname(collection, ln), collection_id = get_colID(collection), middle_only = middle_only, rg = rg, nb_found = nb_found, sf = sf, so = so, rm = rm, of = of, ot = ot, p = p, f = f, p1 = p1, p2 = p2, p3 = p3, f1 = f1, f2 = f2, f3 = f3, m1 = m1, m2 = m2, m3 = m3, op1 = op1, op2 = op2, pl_in_url = pl_in_url, d1y = d1y, d1m = d1m, d1d = d1d, d2y = d2y, d2m = d2m, d2d = d2d, jrec = jrec, sc = sc, sp = sp, all_fieldcodes = get_fieldcodes(), cpu_time = cpu_time, ) def print_results_overview(req, colls, results_final_nb_total, results_final_nb, cpu_time, ln=cdslang, ec=[]): - "Prints results overview box with links to particular collections below." + """Prints results overview box with links to particular collections below.""" + out = "" new_colls = [] for coll in colls: new_colls.append({ 'id': get_colID(coll), 'code': coll, 'name': get_coll_i18nname(coll, ln), }) return websearch_templates.tmpl_print_results_overview( ln = ln, weburl = weburl, results_final_nb_total = results_final_nb_total, results_final_nb = results_final_nb, cpu_time = cpu_time, colls = new_colls, ec = ec, ) def sort_records(req, recIDs, sort_field='', sort_order='d', sort_pattern='', verbose=0, of='hb', ln=cdslang): """Sort records in 'recIDs' list according sort field 'sort_field' in order 'sort_order'. If more than one instance of 'sort_field' is found for a given record, try to choose that that is given by 'sort pattern', for example "sort by report number that starts by CERN-PS". Note that 'sort_field' can be field code like 'author' or MARC tag like '100__a' directly.""" _ = gettext_set_language(ln) ## check arguments: if not sort_field: return recIDs if len(recIDs) > CFG_WEBSEARCH_NB_RECORDS_TO_SORT: if of.startswith('h'): print_warning(req, _("Sorry, sorting is allowed on sets of up to %d records only. Using default sort order.") % CFG_WEBSEARCH_NB_RECORDS_TO_SORT, "Warning") return recIDs sort_fields = string.split(sort_field, ",") recIDs_dict = {} recIDs_out = [] ## first deduce sorting MARC tag out of the 'sort_field' argument: tags = [] for sort_field in sort_fields: if sort_field and str(sort_field[0:2]).isdigit(): # sort_field starts by two digits, so this is probably a MARC tag already tags.append(sort_field) else: # let us check the 'field' table query = """SELECT DISTINCT(t.value) FROM tag AS t, field_tag AS ft, field AS f WHERE f.code='%s' AND ft.id_field=f.id AND t.id=ft.id_tag ORDER BY ft.score DESC""" % sort_field res = run_sql(query) if res: for row in res: tags.append(row[0]) else: if of.startswith('h'): print_warning(req, _("Sorry, %s does not seem to be a valid sort option. Choosing title sort instead.") % sort_field, "Error") tags.append("245__a") if verbose >= 3: print_warning(req, "Sorting by tags %s." % tags) if sort_pattern: print_warning(req, "Sorting preferentially by %s." % sort_pattern) ## check if we have sorting tag defined: if tags: # fetch the necessary field values: for recID in recIDs: val = "" # will hold value for recID according to which sort vals = [] # will hold all values found in sorting tag for recID for tag in tags: vals.extend(get_fieldvalues(recID, tag)) if sort_pattern: # try to pick that tag value that corresponds to sort pattern bingo = 0 for v in vals: if v.lower().startswith(sort_pattern.lower()): # bingo! bingo = 1 val = v break if not bingo: # sort_pattern not present, so add other vals after spaces val = sort_pattern + " " + string.join(vals) else: # no sort pattern defined, so join them all together val = string.join(vals) val = val.lower() if recIDs_dict.has_key(val): recIDs_dict[val].append(recID) else: recIDs_dict[val] = [recID] # sort them: recIDs_dict_keys = recIDs_dict.keys() recIDs_dict_keys.sort() # now that keys are sorted, create output array: for k in recIDs_dict_keys: for s in recIDs_dict[k]: recIDs_out.append(s) # ascending or descending? if sort_order == 'a': recIDs_out.reverse() # okay, we are done return recIDs_out else: # good, no sort needed return recIDs def print_records(req, recIDs, jrec=1, rg=10, format='hb', ot='', ln=cdslang, relevances=[], relevances_prologue="(", relevances_epilogue="%%)", decompress=zlib.decompress, search_pattern='', print_records_prologue_p=True, print_records_epilogue_p=True, verbose=0): """ Prints list of records 'recIDs' formatted accoding to 'format' in groups of 'rg' starting from 'jrec'. Assumes that the input list 'recIDs' is sorted in reverse order, so it counts records from tail to head. A value of 'rg=-9999' means to print all records: to be used with care. Print also list of RELEVANCES for each record (if defined), in between RELEVANCE_PROLOGUE and RELEVANCE_EPILOGUE. Print prologue and/or epilogue specific to 'format' if 'print_records_prologue_p' and/or print_records_epilogue_p' are True. """ # load the right message language _ = gettext_set_language(ln) # sanity checking: if req is None: return # get user id (for formatting based on priviledge) uid = getUid(req) if len(recIDs): nb_found = len(recIDs) if rg == -9999: # print all records rg = nb_found else: rg = abs(rg) if jrec < 1: # sanity checks jrec = 1 if jrec > nb_found: jrec = max(nb_found-rg+1, 1) # will print records from irec_max to irec_min excluded: irec_max = nb_found - jrec irec_min = nb_found - jrec - rg if irec_min < 0: irec_min = -1 if irec_max >= nb_found: irec_max = nb_found - 1 #req.write("%s:%d-%d" % (recIDs, irec_min, irec_max)) if format.startswith('x'): # print header if needed if print_records_prologue_p: print_records_prologue(req, format) # print records recIDs_to_print = [recIDs[x] for x in range(irec_max, irec_min, -1)] req.write(format_records(recIDs_to_print, format, ln=ln, search_pattern=search_pattern, record_separator="\n", uid=uid)) # print footer if needed if print_records_epilogue_p: print_records_epilogue(req, format) elif format.startswith('t') or str(format[0:3]).isdigit(): # we are doing plain text output: for irec in range(irec_max, irec_min, -1): x = print_record(recIDs[irec], format, ot, ln, search_pattern=search_pattern, uid=uid, verbose=verbose) req.write(x) if x: req.write('\n') elif format == 'excel': recIDs_to_print = [recIDs[x] for x in range(irec_max, irec_min, -1)] create_excel(recIDs=recIDs_to_print, req=req, ln=ln) else: # we are doing HTML output: if format == 'hp' or format.startswith("hb_") or format.startswith("hd_"): # portfolio and on-the-fly formats: for irec in range(irec_max, irec_min, -1): req.write(print_record(recIDs[irec], format, ot, ln, search_pattern=search_pattern, uid=uid, verbose=verbose)) elif format.startswith("hb"): # HTML brief format: rows = [] for irec in range(irec_max, irec_min, -1): temp = { 'number' : jrec+irec_max-irec, 'recid' : recIDs[irec], } if relevances and relevances[irec]: temp['relevance'] = relevances[irec] else: temp['relevance'] = '' temp['record'] = print_record(recIDs[irec], format, ot, ln, search_pattern=search_pattern, uid=uid, verbose=verbose) rows.append(temp) req.write(websearch_templates.tmpl_records_format_htmlbrief( ln = ln, weburl = weburl, rows = rows, relevances_prologue = relevances_prologue, relevances_epilogue = relevances_epilogue, )) else: # HTML detailed format: # print other formatting choices: rows = [] for irec in range(irec_max, irec_min, -1): temp = { 'record' : print_record(recIDs[irec], format, ot, ln, search_pattern=search_pattern, uid=uid, verbose=verbose), 'recid' : recIDs[irec], 'creationdate': '', 'modifydate' : '', } if record_exists(recIDs[irec])==1: temp['creationdate'] = get_creation_date(recIDs[irec]) temp['modifydate'] = get_modification_date(recIDs[irec]) if CFG_EXPERIMENTAL_FEATURES: r = calculate_cited_by_list(recIDs[irec]) if r: temp ['citinglist'] = r temp ['citationhistory'] = create_citation_history_graph_and_box(recIDs[irec], ln) r = calculate_co_cited_with_list(recIDs[irec]) if r: temp ['cociting'] = r if CFG_BIBRANK_SHOW_DOWNLOAD_GRAPHS: r = calculate_reading_similarity_list(recIDs[irec], "downloads") if r: temp ['downloadsimilarity'] = r temp ['downloadhistory'] = create_download_history_graph_and_box(recIDs[irec], ln) # Get comments and reviews for this record if exist # FIXME: templatize me if CFG_WEBCOMMENT_ALLOW_COMMENTS or CFG_WEBCOMMENT_ALLOW_REVIEWS: from invenio.webcomment import get_first_comments_or_remarks (comments, reviews) = get_first_comments_or_remarks(recID=recIDs[irec], ln=ln, nb_comments=CFG_WEBCOMMENT_NB_COMMENTS_IN_DETAILED_VIEW, nb_reviews=CFG_WEBCOMMENT_NB_REVIEWS_IN_DETAILED_VIEW) temp['comments'] = comments temp['reviews'] = reviews r = calculate_reading_similarity_list(recIDs[irec], "pageviews") if r: temp ['viewsimilarity'] = r rows.append(temp) req.write(websearch_templates.tmpl_records_format_other( ln = ln, weburl = weburl, url_argd = req.argd, rows = rows, format = format, )) else: print_warning(req, _("Use different search terms.")) def print_records_prologue(req, format): """ Print the appropriate prologue for list of records in the given format. """ prologue = "" # no prologue needed for HTML or Text formats if format.startswith('xm'): prologue = websearch_templates.tmpl_xml_marc_prologue() elif format.startswith('xn'): prologue = websearch_templates.tmpl_xml_nlm_prologue() elif format.startswith('xr'): prologue = websearch_templates.tmpl_xml_rss_prologue() elif format.startswith('x'): prologue = websearch_templates.tmpl_xml_default_prologue() req.write(prologue) def print_records_epilogue(req, format): """ Print the appropriate epilogue for list of records in the given format. """ epilogue = "" # no epilogue needed for HTML or Text formats if format.startswith('xm'): epilogue = websearch_templates.tmpl_xml_marc_epilogue() elif format.startswith('xn'): epilogue = websearch_templates.tmpl_xml_nlm_epilogue() elif format.startswith('xr'): epilogue = websearch_templates.tmpl_xml_rss_epilogue() elif format.startswith('x'): epilogue = websearch_templates.tmpl_xml_default_epilogue() req.write(epilogue) def print_record(recID, format='hb', ot='', ln=cdslang, decompress=zlib.decompress, search_pattern=None, uid=None, verbose=0): - "Prints record 'recID' formatted accoding to 'format'." + """Prints record 'recID' formatted accoding to 'format'.""" + _ = gettext_set_language(ln) out = "" # sanity check: record_exist_p = record_exists(recID) if record_exist_p == 0: # doesn't exist return out # New Python BibFormat procedure for formatting # Old procedure follows further below # We must still check some special formats, but these # should disappear when BibFormat improves. if not (CFG_BIBFORMAT_USE_OLD_BIBFORMAT \ or format.lower().startswith('t') \ or format.lower().startswith('hm') \ or str(format[0:3]).isdigit() \ or ot): # Unspecified format is hd if format == '': format = 'hd' if record_exist_p == -1 and get_output_format_content_type(format) == 'text/html': # HTML output displays a default value for deleted records. # Other format have to deal with it. out += _("The record has been deleted.") else: out += call_bibformat(recID, format, ln, search_pattern=search_pattern, uid=uid, verbose=verbose) # at the end of HTML brief mode, print the "Detailed record" functionality: if format.lower().startswith('hb') and \ format.lower() != 'hb_p': out += websearch_templates.tmpl_print_record_brief_links( ln = ln, recID = recID, weburl = weburl ) return out # Old PHP BibFormat procedure for formatting # print record opening tags, if needed: if format == "marcxml" or format == "oai_dc": out += " \n" out += "

\n" for oai_id in get_fieldvalues(recID, CFG_OAI_ID_FIELD): out += " %s\n" % oai_id out += " %s\n" % get_modification_date(recID) out += "
\n" out += " \n" if format.startswith("xm") or format == "marcxml": # look for detailed format existence: query = "SELECT value FROM bibfmt WHERE id_bibrec='%s' AND format='%s'" % (recID, format) res = run_sql(query, None, 1) if res and record_exist_p == 1: # record 'recID' is formatted in 'format', so print it out += "%s" % decompress(res[0][0]) else: # record 'recID' is not formatted in 'format' -- they are not in "bibfmt" table; so fetch all the data from "bibXXx" tables: if format == "marcxml": out += """ \n""" out += " %d\n" % int(recID) elif format.startswith("xm"): out += """ \n""" out += " %d\n" % int(recID) if record_exist_p == -1: # deleted record, so display only OAI ID and 980: oai_ids = get_fieldvalues(recID, CFG_OAI_ID_FIELD) if oai_ids: out += "%s\n" % \ (CFG_OAI_ID_FIELD[0:3], CFG_OAI_ID_FIELD[3:4], CFG_OAI_ID_FIELD[4:5], CFG_OAI_ID_FIELD[5:6], oai_ids[0]) out += "DELETED\n" else: for digit1 in range(0, 10): for digit2 in range(0, 10): bx = "bib%d%dx" % (digit1, digit2) bibx = "bibrec_bib%d%dx" % (digit1, digit2) query = "SELECT b.tag,b.value,bb.field_number FROM %s AS b, %s AS bb "\ "WHERE bb.id_bibrec='%s' AND b.id=bb.id_bibxxx AND b.tag LIKE '%s%%' "\ "ORDER BY bb.field_number, b.tag ASC" % (bx, bibx, recID, str(digit1)+str(digit2)) res = run_sql(query) field_number_old = -999 field_old = "" for row in res: field, value, field_number = row[0], row[1], row[2] ind1, ind2 = field[3], field[4] if ind1 == "_": ind1 = "" if ind2 == "_": ind2 = "" # print field tag if field_number != field_number_old or field[:-1] != field_old[:-1]: if format.startswith("xm") or format == "marcxml": if field_number_old != -999: out += """ \n""" out += """ \n""" % \ (encode_for_xml(field[0:3]), encode_for_xml(ind1), encode_for_xml(ind2)) field_number_old = field_number field_old = field # print subfield value if format.startswith("xm") or format == "marcxml": value = encode_for_xml(value) out += """ %s\n""" % (encode_for_xml(field[-1:]), value) # all fields/subfields printed in this run, so close the tag: if (format.startswith("xm") or format == "marcxml") and field_number_old != -999: out += """ \n""" # we are at the end of printing the record: if format.startswith("xm") or format == "marcxml": out += " \n" elif format == "xd" or format == "oai_dc": # XML Dublin Core format, possibly OAI -- select only some bibXXx fields: out += """ \n""" if record_exist_p == -1: out += "" else: for f in get_fieldvalues(recID, "041__a"): out += " %s\n" % f for f in get_fieldvalues(recID, "100__a"): out += " %s\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "700__a"): out += " %s\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "245__a"): out += " %s\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "65017a"): out += " %s\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "8564_u"): out += " %s\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "520__a"): out += " %s\n" % encode_for_xml(f) out += " %s\n" % get_creation_date(recID) out += " \n" elif str(format[0:3]).isdigit(): # user has asked to print some fields only if format == "001": out += "%s\n" % (format, recID, format) else: vals = get_fieldvalues(recID, format) for val in vals: out += "%s\n" % (format, val, format) elif format.startswith('t'): ## user directly asked for some tags to be displayed only if record_exist_p == -1: out += get_fieldvalues_alephseq_like(recID, ["001", CFG_OAI_ID_FIELD, "980"]) else: out += get_fieldvalues_alephseq_like(recID, ot) elif format == "hm": if record_exist_p == -1: out += "
" + cgi.escape(get_fieldvalues_alephseq_like(recID, ["001", CFG_OAI_ID_FIELD, "980"])) + "
" else: out += "
" + cgi.escape(get_fieldvalues_alephseq_like(recID, ot)) + "
" elif format.startswith("h") and ot: ## user directly asked for some tags to be displayed only if record_exist_p == -1: out += "
" + get_fieldvalues_alephseq_like(recID, ["001", CFG_OAI_ID_FIELD, "980"]) + "
" else: out += "
" + get_fieldvalues_alephseq_like(recID, ot) + "
" elif format == "hd": # HTML detailed format if record_exist_p == -1: out += _("The record has been deleted.") else: # look for detailed format existence: query = "SELECT value FROM bibfmt WHERE id_bibrec='%s' AND format='%s'" % (recID, format) res = run_sql(query, None, 1) if res: # record 'recID' is formatted in 'format', so print it out += "%s" % decompress(res[0][0]) else: # record 'recID' is not formatted in 'format', so try to call BibFormat on the fly or use default format: out_record_in_format = call_bibformat(recID, format, ln, search_pattern=search_pattern, uid=uid, verbose=verbose) if out_record_in_format: out += out_record_in_format else: out += websearch_templates.tmpl_print_record_detailed( ln = ln, recID = recID, weburl = weburl, ) elif format.startswith("hb_") or format.startswith("hd_"): # underscore means that HTML brief/detailed formats should be called on-the-fly; suitable for testing formats if record_exist_p == -1: out += _("The record has been deleted.") else: out += call_bibformat(recID, format, ln, search_pattern=search_pattern, uid=uid, verbose=verbose) elif format.startswith("hx"): # BibTeX format, called on the fly: if record_exist_p == -1: out += _("The record has been deleted.") else: out += call_bibformat(recID, format, ln, search_pattern=search_pattern, uid=uid, verbose=verbose) elif format.startswith("hs"): # for citation/download similarity navigation links: if record_exist_p == -1: out += _("The record has been deleted.") else: out += '' % websearch_templates.build_search_url(recid=recID, ln=ln) # firstly, title: titles = get_fieldvalues(recID, "245__a") if titles: for title in titles: out += "%s" % title else: # usual title not found, try conference title: titles = get_fieldvalues(recID, "111__a") if titles: for title in titles: out += "%s" % title else: # just print record ID: out += "%s %d" % (get_field_i18nname("record ID", ln), recID) out += "" # secondly, authors: authors = get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a") if authors: out += " - %s" % authors[0] if len(authors) > 1: out += " et al" # thirdly publication info: publinfos = get_fieldvalues(recID, "773__s") if not publinfos: publinfos = get_fieldvalues(recID, "909C4s") if not publinfos: publinfos = get_fieldvalues(recID, "037__a") if not publinfos: publinfos = get_fieldvalues(recID, "088__a") if publinfos: out += " - %s" % publinfos[0] else: # fourthly publication year (if not publication info): years = get_fieldvalues(recID, "773__y") if not years: years = get_fieldvalues(recID, "909C4y") if not years: years = get_fieldvalues(recID, "260__c") if years: out += " (%s)" % years[0] else: # HTML brief format by default if record_exist_p == -1: out += _("The record has been deleted.") else: query = "SELECT value FROM bibfmt WHERE id_bibrec='%s' AND format='%s'" % (recID, format) res = run_sql(query) if res: # record 'recID' is formatted in 'format', so print it out += "%s" % decompress(res[0][0]) else: # record 'recID' is not formatted in 'format', so try to call BibFormat on the fly: or use default format: if CFG_WEBSEARCH_CALL_BIBFORMAT: out_record_in_format = call_bibformat(recID, format, ln, search_pattern=search_pattern, uid=uid, verbose=verbose) if out_record_in_format: out += out_record_in_format else: out += websearch_templates.tmpl_print_record_brief( ln = ln, recID = recID, weburl = weburl, ) else: out += websearch_templates.tmpl_print_record_brief( ln = ln, recID = recID, weburl = weburl, ) # at the end of HTML brief mode, print the "Detailed record" functionality: if format == 'hp' or format.startswith("hb_") or format.startswith("hd_"): pass # do nothing for portfolio and on-the-fly formats else: out += websearch_templates.tmpl_print_record_brief_links( ln = ln, recID = recID, weburl = weburl, ) # print record closing tags, if needed: if format == "marcxml" or format == "oai_dc": out += "
\n" out += " \n" return out def encode_for_xml(s): "Encode special chars in string so that it would be XML-compliant." s = string.replace(s, '&', '&') s = string.replace(s, '<', '<') return s def call_bibformat(recID, format="HD", ln=cdslang, search_pattern=None, uid=None, verbose=0): """ Calls BibFormat and returns formatted record. BibFormat will decide by itself if old or new BibFormat must be used. """ keywords = [] if search_pattern is not None: units = create_basic_search_units(None, str(search_pattern), None) keywords = [unit[1] for unit in units if unit[0] != '-'] return format_record(recID, of=format, ln=ln, search_pattern=keywords, uid=uid, verbose=verbose) def log_query(hostname, query_args, uid=-1): """ Log query into the query and user_query tables. Return id_query or None in case of problems. """ id_query = None if uid > 0: # log the query only if uid is reasonable res = run_sql("SELECT id FROM query WHERE urlargs=%s", (query_args,), 1) try: id_query = res[0][0] except: id_query = run_sql("INSERT INTO query (type, urlargs) VALUES ('r', %s)", (query_args,)) if id_query: run_sql("INSERT INTO user_query (id_user, id_query, hostname, date) VALUES (%s, %s, %s, %s)", (uid, id_query, hostname, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))) return id_query def log_query_info(action, p, f, colls, nb_records_found_total=-1): """Write some info to the log file for later analysis.""" try: log = open(logdir + "/search.log", "a") log.write(time.strftime("%Y%m%d%H%M%S#", time.localtime())) log.write(action+"#") log.write(p+"#") log.write(f+"#") for coll in colls[:-1]: log.write("%s," % coll) log.write("%s#" % colls[-1]) log.write("%d" % nb_records_found_total) log.write("\n") log.close() except: pass return def wash_url_argument(var, new_type): """Wash list argument into 'new_type', that can be 'list', 'str', or 'int'. Useful for washing mod_python passed arguments, that are all lists of strings (URL args may be multiple), but we sometimes want only to take the first value, and sometimes to represent it as string or numerical value.""" out = [] if new_type == 'list': # return lst if type(var) is list: out = var else: out = [var] elif new_type == 'str': # return str if type(var) is list: try: out = "%s" % var[0] except: out = "" elif type(var) is str: out = var else: out = "%s" % var elif new_type == 'int': # return int if type(var) is list: try: out = string.atoi(var[0]) except: out = 0 elif type(var) is int: out = var elif type(var) is str: try: out = string.atoi(var) except: out = 0 else: out = 0 return out ### CALLABLES def perform_request_search(req=None, cc=cdsname, c=None, p="", f="", rg=10, sf="", so="d", sp="", rm="", of="id", ot="", as=0, p1="", f1="", m1="", op1="", p2="", f2="", m2="", op2="", p3="", f3="", m3="", sc=0, jrec=0, recid=-1, recidb=-1, sysno="", id=-1, idb=-1, sysnb="", action="", d1y=0, d1m=0, d1d=0, d2y=0, d2m=0, d2d=0, verbose=0, ap=0, ln=cdslang, ec = None): """Perform search or browse request, without checking for authentication. Return list of recIDs found, if of=id. Otherwise create web page. The arguments are as follows: req - mod_python Request class instance. cc - current collection (e.g. "ATLAS"). The collection the user started to search/browse from. c - collectin list (e.g. ["Theses", "Books"]). The collections user may have selected/deselected when starting to search from 'cc'. p - pattern to search for (e.g. "ellis and muon or kaon"). f - field to search within (e.g. "author"). rg - records in groups of (e.g. "10"). Defines how many hits per collection in the search results page are displayed. sf - sort field (e.g. "title"). so - sort order ("a"=ascending, "d"=descending). sp - sort pattern (e.g. "CERN-") -- in case there are more values in a sort field, this argument tells which one to prefer rm - ranking method (e.g. "jif"). Defines whether results should be ranked by some known ranking method. of - output format (e.g. "hb"). Usually starting "h" means HTML output (and "hb" for HTML brief, "hd" for HTML detailed), "x" means XML output, "t" means plain text output, "id" means no output at all but to return list of recIDs found. (Suitable for high-level API.) ot - output only these MARC tags (e.g. "100,700,909C0b"). Useful if only some fields are to be shown in the output, e.g. for library to control some fields. as - advanced search ("0" means no, "1" means yes). Whether search was called from within the advanced search interface. p1 - first pattern to search for in the advanced search interface. Much like 'p'. f1 - first field to search within in the advanced search interface. Much like 'f'. m1 - first matching type in the advanced search interface. ("a" all of the words, "o" any of the words, "e" exact phrase, "p" partial phrase, "r" regular expression). op1 - first operator, to join the first and the second unit in the advanced search interface. ("a" add, "o" or, "n" not). p2 - second pattern to search for in the advanced search interface. Much like 'p'. f2 - second field to search within in the advanced search interface. Much like 'f'. m2 - second matching type in the advanced search interface. ("a" all of the words, "o" any of the words, "e" exact phrase, "p" partial phrase, "r" regular expression). op2 - second operator, to join the second and the third unit in the advanced search interface. ("a" add, "o" or, "n" not). p3 - third pattern to search for in the advanced search interface. Much like 'p'. f3 - third field to search within in the advanced search interface. Much like 'f'. m3 - third matching type in the advanced search interface. ("a" all of the words, "o" any of the words, "e" exact phrase, "p" partial phrase, "r" regular expression). sc - split by collection ("0" no, "1" yes). Governs whether we want to present the results in a single huge list, or splitted by collection. jrec - jump to record (e.g. "234"). Used for navigation inside the search results. recid - display record ID (e.g. "20000"). Do not search/browse but go straight away to the Detailed record page for the given recID. recidb - display record ID bis (e.g. "20010"). If greater than 'recid', then display records from recid to recidb. Useful for example for dumping records from the database for reformatting. sysno - display old system SYS number (e.g. ""). If you migrate to CDS Invenio from another system, and store your old SYS call numbers, you can use them instead of recid if you wish so. id - the same as recid, in case recid is not set. For backwards compatibility. idb - the same as recid, in case recidb is not set. For backwards compatibility. sysnb - the same as sysno, in case sysno is not set. For backwards compatibility. action - action to do. "SEARCH" for searching, "Browse" for browsing. Default is to search. d1y - first date year (e.g. "1998"). Useful for search limits on creation date. d1m - first date month (e.g. "08"). Useful for search limits on creation date. d1d - first date day (e.g. "23"). Useful for search limits on creation date. d2y - second date year (e.g. "1998"). Useful for search limits on creation date. d2m - second date month (e.g. "09"). Useful for search limits on creation date. d2d - second date day (e.g. "02"). Useful for search limits on creation date. verbose - verbose level (0=min, 9=max). Useful to print some internal information on the searching process in case something goes wrong. ap - alternative patterns (0=no, 1=yes). In case no exact match is found, the search engine can try alternative patterns e.g. to replace non-alphanumeric characters by a boolean query. ap defines if this is wanted. ln - language of the search interface (e.g. "en"). Useful for internationalization. ec - List of external search engines enabled. """ selected_external_collections_infos = None # wash all arguments requiring special care try: (cc, colls_to_display, colls_to_search) = wash_colls(cc, c, sc) # which colls to search and to display? except InvenioWebSearchUnknownCollectionError, exc: colname = exc.colname if of.startswith("h"): page_start(req, of, cc, as, ln, getUid(req), websearch_templates.tmpl_collection_not_found_page_title(colname, ln)) req.write(websearch_templates.tmpl_collection_not_found_page_body(colname, ln)) return page_end(req, of, ln) elif of == "id": return [] else: return page_end(req, of, ln) p = wash_pattern(p) f = wash_field(f) p1 = wash_pattern(p1) f1 = wash_field(f1) p2 = wash_pattern(p2) f2 = wash_field(f2) p3 = wash_pattern(p3) f3 = wash_field(f3) day1, day2 = wash_dates(d1y, d1m, d1d, d2y, d2m, d2d) _ = gettext_set_language(ln) # backwards compatibility: id, idb, sysnb -> recid, recidb, sysno (if applicable) if sysnb != "" and sysno == "": sysno = sysnb if id > 0 and recid == -1: recid = id if idb > 0 and recidb == -1: recidb = idb # TODO deduce passed search limiting criterias (if applicable) pl, pl_in_url = "", "" # no limits by default if action != "browse" and req and req.args: # we do not want to add options while browsing or while calling via command-line fieldargs = cgi.parse_qs(req.args) for fieldcode in get_fieldcodes(): if fieldargs.has_key(fieldcode): for val in fieldargs[fieldcode]: pl += "+%s:\"%s\" " % (fieldcode, val) pl_in_url += "&%s=%s" % (urllib.quote(fieldcode), urllib.quote(val)) # deduce recid from sysno argument (if applicable): if sysno: # ALEPH SYS number was passed, so deduce DB recID for the record: recid = get_mysql_recid_from_aleph_sysno(sysno) # deduce collection we are in (if applicable): if recid > 0: cc = guess_primary_collection_of_a_record(recid) # deduce user id (if applicable): try: uid = getUid(req) except: uid = 0 ## 0 - start output if recid > 0: ## 1 - detailed record display title, description, keywords = \ websearch_templates.tmpl_record_page_header_content(req, recid, ln) page_start(req, of, cc, as, ln, uid, title, description, keywords) # Default format is hb but we are in detailed -> change 'of' if of == "hb": of = "hd" if record_exists(recid): if recidb <= recid: # sanity check recidb = recid + 1 if of == "id": return [recidx for recidx in range(recid, recidb) if record_exists(recidx)] else: print_records(req, range(recid, recidb), -1, -9999, of, ot, ln, search_pattern=p, verbose=verbose) if req and of.startswith("h"): # register detailed record page view event client_ip_address = str(req.get_remote_host(apache.REMOTE_NOLOOKUP)) register_page_view_event(recid, uid, client_ip_address) else: # record does not exist if of == "id": return [] elif of.startswith("h"): print_warning(req, "Requested record does not seem to exist.") elif action == "browse": ## 2 - browse needed page_start(req, of, cc, as, ln, uid, _("Browse")) if of.startswith("h"): req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1, p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, ec, action)) try: if as == 1 or (p1 or p2 or p3): browse_pattern(req, colls_to_search, p1, f1, rg) browse_pattern(req, colls_to_search, p2, f2, rg) browse_pattern(req, colls_to_search, p3, f3, rg) else: browse_pattern(req, colls_to_search, p, f, rg) except: if of.startswith("h"): req.write(create_error_box(req, verbose=verbose, ln=ln)) return page_end(req, of, ln) elif rm and p.startswith("recid:"): ## 3-ter - similarity search needed page_start(req, of, cc, as, ln, uid, _("Search Results")) if of.startswith("h"): req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1, p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, ec, action)) if record_exists(p[6:]) != 1: # record does not exist if of.startswith("h"): print_warning(req, "Requested record does not seem to exist.") if of == "id": return [] else: # record well exists, so find similar ones to it t1 = os.times()[4] results_similar_recIDs, results_similar_relevances, results_similar_relevances_prologue, results_similar_relevances_epilogue, results_similar_comments = \ rank_records(rm, 0, get_collection_reclist(cdsname), string.split(p), verbose) if results_similar_recIDs: t2 = os.times()[4] cpu_time = t2 - t1 if of.startswith("h"): req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, cdsname, len(results_similar_recIDs), jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2, sc, pl_in_url, d1y, d1m, d1d, d2y, d2m, d2d, cpu_time)) print_warning(req, results_similar_comments) print_records(req, results_similar_recIDs, jrec, rg, of, ot, ln, results_similar_relevances, results_similar_relevances_prologue, results_similar_relevances_epilogue, search_pattern=p, verbose=verbose) elif of=="id": return results_similar_recIDs else: # rank_records failed and returned some error message to display: if of.startswith("h"): print_warning(req, results_similar_relevances_prologue) print_warning(req, results_similar_relevances_epilogue) print_warning(req, results_similar_comments) if of == "id": return [] elif CFG_EXPERIMENTAL_FEATURES and p.startswith("cocitedwith:"): ## 3-terter - cited by search needed page_start(req, of, cc, as, ln, uid, _("Search Results")) if of.startswith("h"): req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1, p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, ec, action)) recID = p[12:] if record_exists(recID) != 1: # record does not exist if of.startswith("h"): print_warning(req, "Requested record does not seem to exist.") if of == "id": return [] else: # record well exists, so find co-cited ones: t1 = os.times()[4] results_cocited_recIDs = map(lambda x: x[0], calculate_co_cited_with_list(int(recID))) if results_cocited_recIDs: t2 = os.times()[4] cpu_time = t2 - t1 if of.startswith("h"): req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, cdsname, len(results_cocited_recIDs), jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2, sc, pl_in_url, d1y, d1m, d1d, d2y, d2m, d2d, cpu_time)) print_records(req, results_cocited_recIDs, jrec, rg, of, ot, ln, search_pattern=p, verbose=verbose) elif of=="id": return results_cocited_recIDs else: # cited rank_records failed and returned some error message to display: if of.startswith("h"): print_warning(req, "nothing found") if of == "id": return [] else: ## 3 - common search needed page_start(req, of, cc, as, ln, uid, _("Search Results")) if of.startswith("h"): req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1, p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, ec, action)) t1 = os.times()[4] results_in_any_collection = HitSet() if as == 1 or (p1 or p2 or p3): ## 3A - advanced search try: results_in_any_collection = search_pattern(req, p1, f1, m1, ap=ap, of=of, verbose=verbose, ln=ln) if results_in_any_collection._nbhits == 0: if of.startswith("h"): perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) if p2: results_tmp = search_pattern(req, p2, f2, m2, ap=ap, of=of, verbose=verbose, ln=ln) if op1 == "a": # add results_in_any_collection.intersect(results_tmp) elif op1 == "o": # or results_in_any_collection.union(results_tmp) elif op1 == "n": # not results_in_any_collection.difference(results_tmp) else: if of.startswith("h"): print_warning(req, "Invalid set operation %s." % op1, "Error") results_in_any_collection.calculate_nbhits() if results_in_any_collection._nbhits == 0: if of.startswith("h"): perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) if p3: results_tmp = search_pattern(req, p3, f3, m3, ap=ap, of=of, verbose=verbose, ln=ln) if op2 == "a": # add results_in_any_collection.intersect(results_tmp) elif op2 == "o": # or results_in_any_collection.union(results_tmp) elif op2 == "n": # not results_in_any_collection.difference(results_tmp) else: if of.startswith("h"): print_warning(req, "Invalid set operation %s." % op2, "Error") results_in_any_collection.calculate_nbhits() except: if of.startswith("h"): req.write(create_error_box(req, verbose=verbose, ln=ln)) perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) else: ## 3B - simple search try: results_in_any_collection = search_pattern(req, p, f, ap=ap, of=of, verbose=verbose, ln=ln) except: if of.startswith("h"): req.write(create_error_box(req, verbose=verbose, ln=ln)) perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) if results_in_any_collection._nbhits == 0: if of.startswith("h"): perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) # search_cache_key = p+"@"+f+"@"+string.join(colls_to_search,",") # if search_cache.has_key(search_cache_key): # is the result in search cache? # results_final = search_cache[search_cache_key] # else: # results_final = search_pattern(req, p, f, colls_to_search) # search_cache[search_cache_key] = results_final # if len(search_cache) > CFG_WEBSEARCH_SEARCH_CACHE_SIZE: # is the cache full? (sanity cleaning) # search_cache.clear() # search stage 4: intersection with collection universe: try: results_final = intersect_results_with_collrecs(req, results_in_any_collection, colls_to_search, ap, of, verbose, ln) except: if of.startswith("h"): req.write(create_error_box(req, verbose=verbose, ln=ln)) perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) if results_final == {}: if of.startswith("h"): perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) # search stage 5: apply search option limits and restrictions: if day1 != "": try: results_final = intersect_results_with_hitset(req, results_final, search_unit_in_bibrec(day1, day2), ap, aptext= _("No match within your time limits, " "discarding this condition..."), of=of) except: if of.startswith("h"): req.write(create_error_box(req, verbose=verbose, ln=ln)) perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) if results_final == {}: if of.startswith("h"): perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) if pl: pl = wash_pattern(pl) try: results_final = intersect_results_with_hitset(req, results_final, search_pattern(req, pl, ap=0, ln=ln), ap, aptext=_("No match within your search limits, " "discarding this condition..."), of=of) except: if of.startswith("h"): req.write(create_error_box(req, verbose=verbose, ln=ln)) perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) if results_final == {}: if of.startswith("h"): perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) t2 = os.times()[4] cpu_time = t2 - t1 ## search stage 6: display results: results_final_nb_total = 0 results_final_nb = {} # will hold number of records found in each collection # (in simple dict to display overview more easily; may refactor later) for coll in results_final.keys(): results_final_nb[coll] = results_final[coll]._nbhits results_final_nb_total += results_final_nb[coll] if results_final_nb_total == 0: if of.startswith('h'): print_warning(req, "No match found, please enter different search terms.") else: # yes, some hits found: good! # collection list may have changed due to not-exact-match-found policy so check it out: for coll in results_final.keys(): if coll not in colls_to_search: colls_to_search.append(coll) # print results overview: if of == "id": # we have been asked to return list of recIDs results_final_for_all_colls = HitSet() for coll in results_final.keys(): results_final_for_all_colls.union(results_final[coll]) recIDs = results_final_for_all_colls.items().tolist() if sf: # do we have to sort? recIDs = sort_records(req, recIDs, sf, so, sp, verbose, of) elif rm: # do we have to rank? results_final_for_all_colls_rank_records_output = rank_records(rm, 0, results_final_for_all_colls, string.split(p) + string.split(p1) + string.split(p2) + string.split(p3), verbose) if results_final_for_all_colls_rank_records_output[0]: recIDs = results_final_for_all_colls_rank_records_output[0] return recIDs elif of.startswith("h"): req.write(print_results_overview(req, colls_to_search, results_final_nb_total, results_final_nb, cpu_time, ln, ec)) selected_external_collections_infos = print_external_results_overview(req, cc, [p, p1, p2, p3], f, ec, verbose, ln) # print records: if len(colls_to_search)>1: cpu_time = -1 # we do not want to have search time printed on each collection print_records_prologue(req, of) for coll in colls_to_search: if results_final.has_key(coll) and results_final[coll]._nbhits: if of.startswith("h"): req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, coll, results_final_nb[coll], jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2, sc, pl_in_url, d1y, d1m, d1d, d2y, d2m, d2d, cpu_time)) results_final_recIDs = results_final[coll].items() results_final_relevances = [] results_final_relevances_prologue = "" results_final_relevances_epilogue = "" if sf: # do we have to sort? results_final_recIDs = sort_records(req, results_final_recIDs, sf, so, sp, verbose, of) elif rm: # do we have to rank? results_final_recIDs_ranked, results_final_relevances, results_final_relevances_prologue, results_final_relevances_epilogue, results_final_comments = \ rank_records(rm, 0, results_final[coll], string.split(p) + string.split(p1) + string.split(p2) + string.split(p3), verbose) if of.startswith("h"): print_warning(req, results_final_comments) if results_final_recIDs_ranked: results_final_recIDs = results_final_recIDs_ranked else: # rank_records failed and returned some error message to display: print_warning(req, results_final_relevances_prologue) print_warning(req, results_final_relevances_epilogue) print_records(req, results_final_recIDs, jrec, rg, of, ot, ln, results_final_relevances, results_final_relevances_prologue, results_final_relevances_epilogue, search_pattern=p, print_records_prologue_p=False, print_records_epilogue_p=False, verbose=verbose) if of.startswith("h"): req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, coll, results_final_nb[coll], jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2, sc, pl_in_url, d1y, d1m, d1d, d2y, d2m, d2d, cpu_time, 1)) print_records_epilogue(req, of) if f == "author" and of.startswith("h"): req.write(create_similarly_named_authors_link_box(p, ln)) # log query: try: id_query = log_query(req.get_remote_host(), req.args, uid) if of.startswith("h") and id_query: # Alert/RSS teaser: req.write(websearch_templates.tmpl_alert_rss_teaser_box_for_query(id_query, ln=ln)) except: # do not log query if req is None (used by CLI interface) pass log_query_info("ss", p, f, colls_to_search, results_final_nb_total) # External searches if of.startswith("h"): perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos) return page_end(req, of, ln) def perform_request_cache(req, action="show"): """Manipulates the search engine cache.""" global search_cache global collection_reclist_cache global collection_reclist_cache_timestamp global field_i18nname_cache global field_i18nname_cache_timestamp global collection_i18nname_cache global collection_i18nname_cache_timestamp req.content_type = "text/html" req.send_http_header() out = "" out += "

Search Cache

" # clear cache if requested: if action == "clear": search_cache = {} collection_reclist_cache = create_collection_reclist_cache() # show collection reclist cache: out += "

Collection reclist cache

" out += "- collection table last updated: %s" % get_table_update_time('collection') out += "
- reclist cache timestamp: %s" % collection_reclist_cache_timestamp out += "
- reclist cache contents:" out += "
" for coll in collection_reclist_cache.keys(): if collection_reclist_cache[coll]: out += "%s (%d)
" % (coll, get_collection_reclist(coll)._nbhits) out += "
" # show search cache: out += "

Search Cache

" out += "
" if len(search_cache): out += """""" out += "" % \ ("Pattern", "Field", "Collection", "Number of Hits") for search_cache_key in search_cache.keys(): p, f, c = string.split(search_cache_key, "@", 2) # find out about length of cached data: l = 0 for coll in search_cache[search_cache_key]: l += search_cache[search_cache_key][coll]._nbhits out += "" % (p, f, c, l) out += "
%s%s%s%s
%s%s%s%d
" else: out += "

Search cache is empty." out += "

" out += """

clear cache""" % weburl # show field i18nname cache: out += "

Field I18N names cache

" out += "- fieldname table last updated: %s" % get_table_update_time('fieldname') out += "
- i18nname cache timestamp: %s" % field_i18nname_cache_timestamp out += "
- i18nname cache contents:" out += "
" for field in field_i18nname_cache.keys(): for ln in field_i18nname_cache[field].keys(): out += "%s, %s = %s
" % (field, ln, field_i18nname_cache[field][ln]) out += "
" # show collection i18nname cache: out += "

Collection I18N names cache

" out += "- collectionname table last updated: %s" % get_table_update_time('collectionname') out += "
- i18nname cache timestamp: %s" % collection_i18nname_cache_timestamp out += "
- i18nname cache contents:" out += "
" for coll in collection_i18nname_cache.keys(): for ln in collection_i18nname_cache[coll].keys(): out += "%s, %s = %s
" % (coll, ln, collection_i18nname_cache[coll][ln]) out += "
" req.write("") req.write(out) req.write("") return "\n" def perform_request_log(req, date=""): """Display search log information for given date.""" req.content_type = "text/html" req.send_http_header() req.write("") req.write("

Search Log

") if date: # case A: display stats for a day yyyymmdd = string.atoi(date) req.write("

Date: %d

" % yyyymmdd) req.write("""""") req.write("" % ("No.", "Time", "Pattern", "Field", "Collection", "Number of Hits")) # read file: p = os.popen("grep ^%d %s/search.log" % (yyyymmdd, logdir), 'r') lines = p.readlines() p.close() # process lines: i = 0 for line in lines: try: datetime, as, p, f, c, nbhits = string.split(line,"#") i += 1 req.write("" \ % (i, datetime[8:10], datetime[10:12], datetime[12:], p, f, c, nbhits)) except: pass # ignore eventual wrong log lines req.write("
%s%s%s%s%s%s
#%d%s:%s:%s%s%s%s%s
") else: # case B: display summary stats per day yyyymm01 = int(time.strftime("%Y%m01", time.localtime())) yyyymmdd = int(time.strftime("%Y%m%d", time.localtime())) req.write("""""") req.write("" % ("Day", "Number of Queries")) for day in range(yyyymm01, yyyymmdd + 1): p = os.popen("grep -c ^%d %s/search.log" % (day, logdir), 'r') for line in p.readlines(): req.write("""""" % \ (day, weburl, day, line)) p.close() req.write("
%s%s
%s%s
") req.write("") return "\n" def profile(p="", f="", c=cdsname): """Profile search time.""" import profile import pstats profile.run("perform_request_search(p='%s',f='%s', c='%s')" % (p, f, c), "perform_request_search_profile") p = pstats.Stats("perform_request_search_profile") p.strip_dirs().sort_stats("cumulative").print_stats() return 0 ## test cases: #print wash_colls(cdsname,"Library Catalogue", 0) #print wash_colls("Periodicals & Progress Reports",["Periodicals","Progress Reports"], 0) #print wash_field("wau") #print print_record(20,"tm","001,245") #print create_opft_search_units(None, "PHE-87-13","reportnumber") #print ":"+wash_pattern("* and % doo * %")+":\n" #print ":"+wash_pattern("*")+":\n" #print ":"+wash_pattern("ellis* ell* e*%")+":\n" #print run_sql("SELECT name,dbquery from collection") #print get_index_id("author") #print get_coll_ancestors("Theses") #print get_coll_sons("Articles & Preprints") #print get_coll_real_descendants("Articles & Preprints") #print get_collection_reclist("Theses") #print log(sys.stdin) #print search_unit_in_bibrec('2002-12-01','2002-12-12') #print type(wash_url_argument("-1",'int')) #print get_nearest_terms_in_bibxxx("ellis", "author", 5, 5) #print call_bibformat(68, "HB_FLY") #print create_collection_i18nname_cache() #print get_fieldvalues(10, "980__a") #print get_fieldvalues_alephseq_like(10,"001___") #print get_fieldvalues_alephseq_like(10,"980__a") #print get_fieldvalues_alephseq_like(10,"foo") #print get_fieldvalues_alephseq_like(10,"-1") #print get_fieldvalues_alephseq_like(10,"99") #print get_fieldvalues_alephseq_like(10,["001", "980"]) ## profiling: #profile("of the this") #print perform_request_search(p="ellis") diff --git a/modules/websearch/lib/websearch_regression_tests.py b/modules/websearch/lib/websearch_regression_tests.py index a4fb0f50e..4107394d6 100644 --- a/modules/websearch/lib/websearch_regression_tests.py +++ b/modules/websearch/lib/websearch_regression_tests.py @@ -1,1033 +1,1004 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """WebSearch module regression tests.""" __revision__ = "$Id$" import unittest import re import urlparse, cgi from sets import Set from mechanize import Browser, LinkNotFoundError, HTTPError from invenio.config import weburl, cdsname, cdslang from invenio.testutils import make_test_suite, \ warn_user_about_tests_and_run, \ make_url, test_web_page_content, \ merge_error_messages from invenio.urlutils import same_urls_p from invenio.search_engine import perform_request_search def parse_url(url): parts = urlparse.urlparse(url) query = cgi.parse_qs(parts[4], True) return parts[2].split('/')[1:], query class WebSearchWebPagesAvailabilityTest(unittest.TestCase): """Check WebSearch web pages whether they are up or not.""" def test_search_interface_pages_availability(self): - """websearch - availability of search interface pages""" + """websearch - availability of search interface pages""" baseurl = weburl + '/' _exports = ['', 'collection/Poetry', 'collection/Poetry?as=1'] - + error_messages = [] for url in [baseurl + page for page in _exports]: error_messages.extend(test_web_page_content(url)) if error_messages: self.fail(merge_error_messages(error_messages)) return def test_search_results_pages_availability(self): - """websearch - availability of search results pages""" + """websearch - availability of search results pages""" baseurl = weburl + '/search' _exports = ['', '?c=Poetry', '?p=ellis', '/cache', '/log'] - + error_messages = [] for url in [baseurl + page for page in _exports]: error_messages.extend(test_web_page_content(url)) if error_messages: self.fail(merge_error_messages(error_messages)) return def test_search_detailed_record_pages_availability(self): - """websearch - availability of search detailed record pages""" + """websearch - availability of search detailed record pages""" baseurl = weburl + '/record/' _exports = ['', '1', '1/', '1/files', '1/files/'] - + error_messages = [] for url in [baseurl + page for page in _exports]: error_messages.extend(test_web_page_content(url)) if error_messages: self.fail(merge_error_messages(error_messages)) return def test_browse_results_pages_availability(self): - """websearch - availability of browse results pages""" + """websearch - availability of browse results pages""" baseurl = weburl + '/search' _exports = ['?p=ellis&f=author&action_browse=Browse'] - + error_messages = [] for url in [baseurl + page for page in _exports]: error_messages.extend(test_web_page_content(url)) if error_messages: self.fail(merge_error_messages(error_messages)) return def test_search_user_help_pages_availability(self): - """websearch - availability of search user help pages""" + """websearch - availability of search user help pages""" baseurl = weburl + '/help/search/' _exports = ['', 'index.fr.html', 'tips.fr.html', 'guide.fr.html'] - + error_messages = [] for url in [baseurl + page for page in _exports]: error_messages.extend(test_web_page_content(url)) if error_messages: self.fail(merge_error_messages(error_messages)) return class WebSearchTestLegacyURLs(unittest.TestCase): """ Check that the application still responds to legacy URLs for navigating, searching and browsing.""" def test_legacy_collections(self): """ websearch - collections handle legacy urls """ browser = Browser() def check(legacy, new): browser.open(legacy) got = browser.geturl() - + self.failUnless(same_urls_p(got, new), got) # Use the root URL unless we need more check(make_url('/', c=cdsname), make_url('/')) # Other collections are redirected in the /collection area check(make_url('/', c='Poetry'), make_url('/collection/Poetry')) # Drop unnecessary arguments, like ln and as (when they are # the default value) check(make_url('/', c='Poetry', as=0, ln=cdslang), make_url('/collection/Poetry')) # Otherwise, keep them check(make_url('/', c='Poetry', as=1, ln=cdslang), make_url('/collection/Poetry', as=1)) # Support the /index.py addressing too check(make_url('/index.py', c='Poetry'), make_url('/collection/Poetry')) - + def test_legacy_search(self): """ websearch - search queries handle legacy urls """ browser = Browser() def check(legacy, new): browser.open(legacy) got = browser.geturl() - + self.failUnless(same_urls_p(got, new), got) # /search.py is redirected on /search check(make_url('/search.py', p='nuclear', as=1), make_url('/search', p='nuclear', as=1)) # direct recid searches are redirected to /record check(make_url('/search.py', recid=1, ln='es'), make_url('/record/1', ln='es')) class WebSearchTestRecord(unittest.TestCase): """ Check the interface of the /record results """ def test_format_links(self): """ websearch - check format links for records """ browser = Browser() # We open the record in all known HTML formats for hformat in ('hd', 'hx', 'hm'): browser.open(make_url('/record/1', of=hformat)) # all except the selected links should be present in the # page. for oformat in ('hd', 'hx', 'hm', 'xm', 'xd'): target = make_url('/record/1', of=oformat) - + if oformat == hformat: try: browser.find_link(url=target) except LinkNotFoundError: continue self.fail('link %r should not be in page' % target) else: try: browser.find_link(url=target) except LinkNotFoundError: self.fail('link %r should be in page' % target) - + return class WebSearchTestCollections(unittest.TestCase): - + def test_traversal_links(self): """ websearch - traverse all the publications of a collection """ # Ensure that it is possible to traverse a collection as # /collection/My_Collection?jrec=... browser = Browser() try: for as in (0, 1): browser.open(make_url('/collection/Preprints', as=as)) for jrec in (11, 21, 11, 23): args = {'jrec': jrec, 'cc': 'Preprints'} if as: args['as'] = as - + url = make_url('/search', **args) browser.follow_link(url=url) - + except LinkNotFoundError: self.fail('no link %r in %r' % (url, browser.geturl())) - + def test_collections_links(self): """ websearch - enter in collections and subcollections """ browser = Browser() def tryfollow(url): cur = browser.geturl() body = browser.response().read() try: browser.follow_link(url=url) except LinkNotFoundError: print body self.fail("in %r: could not find %r" % ( cur, url)) return for as in (0, 1): if as: kargs = {'as': 1} else: kargs = {} - + # We navigate from immediate son to immediate son... browser.open(make_url('/', **kargs)) tryfollow(make_url('/collection/Articles%20%26%20Preprints', **kargs)) tryfollow(make_url('/collection/Articles', **kargs)) # But we can also jump to a grandson immediately browser.back() browser.back() tryfollow(make_url('/collection/ALEPH', **kargs)) return def test_records_links(self): """ websearch - check the links toward records in leaf collections """ - + browser = Browser() browser.open(make_url('/collection/Preprints')) def harvest(): """ Parse all the links in the page, and check that for each link to a detailed record, we also have the corresponding link to the similar records.""" - + records = Set() similar = Set() - + for link in browser.links(): path, q = parse_url(link.url) if not path: continue - + if path[0] == 'record': records.add(int(path[1])) continue if path[0] == 'search': if not q.get('rm') == ['wrd']: continue recid = q['p'][0].split(':')[1] similar.add(int(recid)) - + self.failUnlessEqual(records, similar) - + return records - + # We must have 10 links to the corresponding /records found = harvest() self.failUnlessEqual(len(found), 10) # When clicking on the "Search" button, we must also have # these 10 links on the records. browser.select_form(name="search") browser.submit() found = harvest() self.failUnlessEqual(len(found), 10) return class WebSearchTestBrowse(unittest.TestCase): def test_browse_field(self): """ websearch - check that browsing works """ browser = Browser() browser.open(make_url('/')) browser.select_form(name='search') browser['f'] = ['title'] browser.submit(name='action_browse') def collect(): # We'll get a few links to search for the actual hits, plus a # link to the following results. res = [] for link in browser.links(url_regex=re.compile(weburl + r'/search\?')): if link.text == 'Advanced Search': continue - + dummy, q = parse_url(link.url) res.append((link, q)) return res - + # if we follow the last link, we should get another # batch. There is an overlap of one item. batch_1 = collect() browser.follow_link(link=batch_1[-1][0]) batch_2 = collect() # FIXME: we cannot compare the whole query, as the collection # set is not equal self.failUnlessEqual(batch_1[-2][1]['p'], batch_2[0][1]['p']) - + class WebSearchTestSearch(unittest.TestCase): def test_hits_in_other_collection(self): """ websearch - check extension of a query to the home collection """ browser = Browser() - + # We do a precise search in an isolated collection browser.open(make_url('/collection/ISOLDE', ln='en')) - + browser.select_form(name='search') browser['f'] = ['author'] browser['p'] = 'matsubara' browser.submit() dummy, current_q = parse_url(browser.geturl()) - + link = browser.find_link(text_regex=re.compile('.*hit', re.I)) dummy, target_q = parse_url(link.url) # the target query should be the current query without any c # or cc specified. for f in ('cc', 'c', 'action_search', 'ln'): if f in current_q: del current_q[f] self.failUnlessEqual(current_q, target_q) def test_nearest_terms(self): """ websearch - provide a list of nearest terms """ - + browser = Browser() browser.open(make_url('')) # Search something weird browser.select_form(name='search') browser['p'] = 'gronf' browser.submit() dummy, original = parse_url(browser.geturl()) - + for to_drop in ('cc', 'action_search', 'f'): if to_drop in original: del original[to_drop] - + # we should get a few searches back, which are identical # except for the p field being substituted (and the cc field # being dropped). if 'cc' in original: del original['cc'] - + for link in browser.links(url_regex=re.compile(weburl + r'/search\?')): if link.text == 'Advanced Search': continue - + dummy, target = parse_url(link.url) original['p'] = [link.text] self.failUnlessEqual(original, target) return def test_switch_to_simple_search(self): """ websearch - switch to simple search """ - + browser = Browser() browser.open(make_url('/collection/ISOLDE', as=1)) browser.select_form(name='search') browser['p1'] = 'tandem' browser['f1'] = ['title'] browser.submit() browser.follow_link(text='Simple Search') dummy, q = parse_url(browser.geturl()) self.failUnlessEqual(q, {'cc': ['ISOLDE'], 'p': ['tandem'], 'f': ['title']}) - + def test_switch_to_advanced_search(self): """ websearch - switch to advanced search """ - + browser = Browser() browser.open(make_url('/collection/ISOLDE')) browser.select_form(name='search') browser['p'] = 'tandem' browser['f'] = ['title'] browser.submit() browser.follow_link(text='Advanced Search') dummy, q = parse_url(browser.geturl()) self.failUnlessEqual(q, {'cc': ['ISOLDE'], 'p1': ['tandem'], 'f1': ['title'], 'as': ['1']}) - + def test_no_boolean_hits(self): """ websearch - check the 'no boolean hits' proposed links """ - + browser = Browser() browser.open(make_url('')) browser.select_form(name='search') browser['p'] = 'quasinormal muon' browser.submit() dummy, q = parse_url(browser.geturl()) for to_drop in ('cc', 'action_search', 'f'): if to_drop in q: del q[to_drop] - + for bsu in ('quasinormal', 'muon'): l = browser.find_link(text=bsu) q['p'] = bsu if not same_urls_p(l.url, make_url('/search', **q)): self.fail(repr((l.url, make_url('/search', **q)))) def test_similar_authors(self): """ websearch - test similar authors box """ browser = Browser() browser.open(make_url('')) browser.select_form(name='search') browser['p'] = 'Ellis, R K' browser['f'] = ['author'] browser.submit() l = browser.find_link(text="Ellis, R S") self.failUnless(same_urls_p(l.url, make_url('/search', p="Ellis, R S", f='author'))) # pylint: disable-msg=C0301 class WebSearchNearestTermsTest(unittest.TestCase): """Check various alternatives of searches leading to the nearest terms box.""" def test_nearest_terms_box_in_okay_query(self): """ websearch - no nearest terms box for a successful query """ self.assertEqual([], test_web_page_content(weburl + '/search?p=ellis', expected_text="jump to record")) - + def test_nearest_terms_box_in_unsuccessful_simple_query(self): """ websearch - nearest terms box for unsuccessful simple query """ self.assertEqual([], test_web_page_content(weburl + '/search?p=ellisz', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=embed", expected_link_label='embed')) def test_nearest_terms_box_in_unsuccessful_structured_query(self): """ websearch - nearest terms box for unsuccessful structured query """ self.assertEqual([], test_web_page_content(weburl + '/search?p=ellisz&f=author', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=fabbro&f=author", expected_link_label='fabbro')) self.assertEqual([], test_web_page_content(weburl + '/search?p=author%3Aellisz', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=author%3Afabbro", expected_link_label='fabbro')) def test_nearest_terms_box_in_unsuccessful_phrase_query(self): """ websearch - nearest terms box for unsuccessful phrase query """ self.assertEqual([], test_web_page_content(weburl + '/search?p=author%3A%22Ellis%2C+Z%22', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=author%3A%22Enqvist%2C+K%22", expected_link_label='Enqvist, K')) self.assertEqual([], test_web_page_content(weburl + '/search?p=%22ellisz%22&f=author', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=%22Enqvist%2C+K%22&f=author", expected_link_label='Enqvist, K')) - + def test_nearest_terms_box_in_unsuccessful_boolean_query(self): """ websearch - nearest terms box for unsuccessful boolean query """ self.assertEqual([], test_web_page_content(weburl + '/search?p=title%3Aellisz+author%3Aellisz', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=title%3Aenergie+author%3Aellisz", expected_link_label='energie')) self.assertEqual([], test_web_page_content(weburl + '/search?p=title%3Aenergie+author%3Aenergie', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=title%3Aenergie+author%3Aenqvist", expected_link_label='enqvist')) self.assertEqual([], test_web_page_content(weburl + '/search?p=title%3Aellisz+author%3Aellisz&f=keyword', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=title%3Aenergie+author%3Aellisz&f=keyword", expected_link_label='energie')) self.assertEqual([], test_web_page_content(weburl + '/search?p=title%3Aenergie+author%3Aenergie&f=keyword', expected_text="Nearest terms in any collection are", expected_link_target=weburl+"/search?p=title%3Aenergie+author%3Aenqvist&f=keyword", expected_link_label='enqvist')) class WebSearchBooleanQueryTest(unittest.TestCase): """Check various boolean queries.""" def test_successful_boolean_query(self): """ websearch - successful boolean query """ self.assertEqual([], test_web_page_content(weburl + '/search?p=ellis+muon', expected_text="records found", expected_link_label="Detailed record")) def test_unsuccessful_boolean_query_where_all_individual_terms_match(self): """ websearch - unsuccessful boolean query where all individual terms match """ self.assertEqual([], test_web_page_content(weburl + '/search?p=ellis+muon+letter', expected_text="Boolean query returned no hits. Please combine your search terms differently.")) class WebSearchAuthorQueryTest(unittest.TestCase): """Check various author-related queries.""" def test_propose_similar_author_names_box(self): """ websearch - propose similar author names box """ self.assertEqual([], test_web_page_content(weburl + '/search?p=Ellis%2C+R&f=author', expected_text="See also: similar author names", expected_link_target=weburl+"/search?p=Ellis%2C+R+K&f=author", expected_link_label="Ellis, R K")) def test_do_not_propose_similar_author_names_box(self): """ websearch - do not propose similar author names box """ errmsgs = test_web_page_content(weburl + '/search?p=author%3A%22Ellis%2C+R%22', expected_link_target=weburl+"/search?p=Ellis%2C+R+K&f=author", expected_link_label="Ellis, R K") if errmsgs[0].find("does not contain link to") > -1: pass else: self.fail("Should not propose similar author names box.") return class WebSearchSearchEnginePythonAPITest(unittest.TestCase): """Check typical search engine Python API calls on the demo data.""" def test_search_engine_python_api_for_failed_query(self): """websearch - search engine Python API for failed query""" self.assertEqual([], - perform_request_search(p='aoeuidhtns')) + perform_request_search(p='aoeuidhtns')) def test_search_engine_python_api_for_successful_query(self): """websearch - search engine Python API for successful query""" self.assertEqual([8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 47], perform_request_search(p='ellis')) def test_search_engine_python_api_for_existing_record(self): """websearch - search engine Python API for existing record""" self.assertEqual([8], perform_request_search(recid=8)) def test_search_engine_python_api_for_nonexisting_record(self): """websearch - search engine Python API for non-existing record""" self.assertEqual([], perform_request_search(recid=1234567809)) def test_search_engine_python_api_for_nonexisting_collection(self): """websearch - search engine Python API for non-existing collection""" self.assertEqual([], perform_request_search(c='Foo')) def test_search_engine_python_api_for_range_of_records(self): """websearch - search engine Python API for range of records""" self.assertEqual([1, 2, 3, 4, 5, 6, 7, 8, 9], perform_request_search(recid=1, recidb=10)) class WebSearchSearchEngineWebAPITest(unittest.TestCase): """Check typical search engine Web API calls on the demo data.""" def test_search_engine_web_api_for_failed_query(self): """websearch - search engine Web API for failed query""" self.assertEqual([], test_web_page_content(weburl + '/search?p=aoeuidhtns&of=id', expected_text="[]")) - + def test_search_engine_web_api_for_successful_query(self): """websearch - search engine Web API for successful query""" self.assertEqual([], test_web_page_content(weburl + '/search?p=ellis&of=id', expected_text="[8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 47]")) def test_search_engine_web_api_for_existing_record(self): """websearch - search engine Web API for existing record""" self.assertEqual([], test_web_page_content(weburl + '/search?recid=8&of=id', expected_text="[8]")) def test_search_engine_web_api_for_nonexisting_record(self): """websearch - search engine Web API for non-existing record""" self.assertEqual([], test_web_page_content(weburl + '/search?recid=123456789&of=id', expected_text="[]")) def test_search_engine_web_api_for_nonexisting_collection(self): """websearch - search engine Web API for non-existing collection""" self.assertEqual([], test_web_page_content(weburl + '/search?c=Foo&of=id', expected_text="[]")) def test_search_engine_web_api_for_range_of_records(self): """websearch - search engine Web API for range of records""" self.assertEqual([], test_web_page_content(weburl + '/search?recid=1&recidb=10&of=id', expected_text="[1, 2, 3, 4, 5, 6, 7, 8, 9]")) class WebSearchRestrictedCollectionTest(unittest.TestCase): """Test of the restricted Theses collection behaviour.""" def test_restricted_collection_interface_page(self): """websearch - restricted collection interface page body""" self.assertEqual([], test_web_page_content(weburl + '/collection/Theses', expected_text="The contents of this collection is restricted.")) def test_restricted_search_as_anonymous_guest(self): """websearch - restricted collection not searchable by anonymous guest""" - errmsgs = test_web_page_content(weburl + '/search?c=Theses') - if errmsgs[0].find("HTTP Error 401: Authorization Required") > -1: + browser = Browser() + browser.open(weburl + '/search?c=Theses') + loginbox = browser.response().read() + if loginbox.find("If you already have an account, please login using the form below") > -1: pass else: - self.fail("Oops, searching restricted collection without password should have returned HTTP Error 401.") + self.fail("Oops, searching restricted collection without password should have redirected to login dialog.") return def test_restricted_search_as_authorized_person(self): """websearch - restricted collection searchable by authorized person""" - testurl = weburl + '/search?c=Theses' browser = Browser() - # Dr. Jekyll should be able to connect: - browser.add_password(testurl, "jekyll", "j123ekyll") - browser.open(testurl) + browser.open(weburl + '/search?c=Theses') + browser.select_form(nr=0) + browser['p_un'] = 'jekyll' + browser['p_pw'] = 'j123ekyll' + browser.submit() if browser.response().read().find("records found") > -1: pass else: self.fail("Oops, Dr. Jekyll should be able to search Theses collection.") def test_restricted_search_as_unauthorized_person(self): """websearch - restricted collection not searchable by unauthorized person""" - testurl = weburl + '/search?c=Theses' browser = Browser() + browser.open(weburl + '/search?c=Theses') + browser.select_form(nr=0) + browser['p_un'] = 'hyde' + browser['p_pw'] = 'h123yde' + browser.submit() # Mr. Hyde should not be able to connect: - browser.add_password(testurl, "hyde", "h123yde") - try: - browser.open(testurl) - except HTTPError, errmsg: - if str(errmsg) == "HTTP Error 401: Authorization Required": - # good, things worked - return - # if we got here, things are broken: - self.fail("Oops, Mr.Hyde should not be able to search Theses collection.") - - def test_restricted_search_with_wrong_credentials(self): - """websearch - restricted collection not searchable with wrong credentials""" - testurl = weburl + '/search?c=Theses' - browser = Browser() - # Dr. Jekyll with wrong password should not be able to connect: - browser.add_password(testurl, "jekyll", "h123yde") - try: - browser.open(testurl) - except HTTPError, errmsg: - if str(errmsg) == "HTTP Error 401: Authorization Required": - # good, things worked - return - # if we got here, things are broken: - self.fail("Oops, Dr. Jekyll with wrong password should not be able to search Theses collection.") + if browser.response().read().find("You are not authorized to view this area") <= -1: + # if we got here, things are broken: + self.fail("Oops, Mr.Hyde should not be able to search Theses collection.") def test_restricted_detailed_record_page_as_anonymous_guest(self): """websearch - restricted detailed record page not accessible to guests""" - errmsgs = test_web_page_content(weburl + '/record/35') - if errmsgs[0].find("HTTP Error 401: Authorization Required") > -1: - pass - else: - self.fail("Oops, accessing restricted detailed record page without password should have returned HTTP Error 401.") - return + browser = Browser() + browser.open(weburl + '/record/35') + if browser.response().read().find("You are not authorized to view this record") <= -1: + self.fail("Oops, accessing restricted detailed record page without password should have returned authorization error.") def test_restricted_detailed_record_page_as_authorized_person(self): """websearch - restricted detailed record page accessible to authorized person""" - testurl = weburl + '/record/35' browser = Browser() + browser.open(weburl + '/youraccount/login') + browser.select_form(nr=0) + browser['p_un'] = 'jekyll' + browser['p_pw'] = 'j123ekyll' + browser.submit() + browser.open(weburl + '/record/35') # Dr. Jekyll should be able to connect # (add the pw to the whole weburl because we shall be # redirected to '/reordrestricted/'): - browser.add_password(weburl, "jekyll", "j123ekyll") - browser.open(testurl) if browser.response().read().find("A High-performance Video Browsing System") > -1: pass else: self.fail("Oops, Dr. Jekyll should be able to access restricted detailed record page.") def test_restricted_detailed_record_page_as_unauthorized_person(self): """websearch - restricted detailed record page not accessible to unauthorized person""" - testurl = weburl + '/record/35' browser = Browser() + browser.open(weburl + '/youraccount/login') + browser.select_form(nr=0) + browser['p_un'] = 'hyde' + browser['p_pw'] = 'h123yde' + browser.submit() + browser.open(weburl + '/record/35') # Mr. Hyde should not be able to connect: - browser.add_password(testurl, "hyde", "h123yde") - try: - browser.open(testurl) - except HTTPError, errmsg: - if str(errmsg) == "HTTP Error 401: Authorization Required": - # good, things worked - return - # if we got here, things are broken: - self.fail("Oops, Mr.Hyde should not be able to access restricted detailed record page.") - - def test_restricted_detailed_record_page_with_wrong_credentials(self): - """websearch - restricted detailed record page not accessible with wrong credentials""" - testurl = weburl + '/record/35' - browser = Browser() - # Dr. Jekyll with wrong password should not be able to connect: - browser.add_password(testurl, "jekyll", "h123yde") - try: - browser.open(testurl) - except HTTPError, errmsg: - if str(errmsg) == "HTTP Error 401: Authorization Required": - # good, things worked - return - # if we got here, things are broken: - self.fail("Oops, Dr. Jekyll with wrong password should not be able to access restricted detailed record page.") + if browser.response().read().find('You are not authorized to view this record') <= -1: + # if we got here, things are broken: + self.fail("Oops, Mr.Hyde should not be able to access restricted detailed record page.") class WebSearchRSSFeedServiceTest(unittest.TestCase): """Test of the RSS feed service.""" def test_rss_feed_service(self): """websearch - RSS feed service""" self.assertEqual([], test_web_page_content(weburl + '/rss', expected_text='')) class WebSearchXSSVulnerabilityTest(unittest.TestCase): """Test possible XSS vulnerabilities of the search engine.""" def test_xss_in_collection_interface_page(self): """websearch - no XSS vulnerability in collection interface pages""" self.assertEqual([], test_web_page_content(weburl + '/?c=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E', expected_text='Collection <SCRIPT>alert("XSS");</SCRIPT> Not Found')) def test_xss_in_collection_search_page(self): """websearch - no XSS vulnerability in collection search pages""" self.assertEqual([], test_web_page_content(weburl + '/search?c=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E', expected_text='Collection <SCRIPT>alert("XSS");</SCRIPT> Not Found')) def test_xss_in_simple_search(self): """websearch - no XSS vulnerability in simple search""" self.assertEqual([], test_web_page_content(weburl + '/search?p=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E', expected_text='Search term <SCRIPT>alert("XSS");</SCRIPT> did not match any record.')) def test_xss_in_structured_search(self): """websearch - no XSS vulnerability in structured search""" self.assertEqual([], test_web_page_content(weburl + '/search?p=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&f=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E', expected_text='Search term <SCRIPT>alert("XSS");</SCRIPT> inside index <SCRIPT>alert("XSS");</SCRIPT> did not match any record.')) def test_xss_in_advanced_search(self): """websearch - no XSS vulnerability in advanced search""" self.assertEqual([], test_web_page_content(weburl + '/search?as=1&p1=ellis&f1=author&op1=a&p2=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&f2=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E', expected_text='Search term <SCRIPT>alert("XSS");</SCRIPT> inside index <SCRIPT>alert("XSS");</SCRIPT> did not match any record.')) - + def test_xss_in_browse(self): """websearch - no XSS vulnerability in browse""" self.assertEqual([], test_web_page_content(weburl + '/search?p=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&f=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&action_browse=Browse', expected_text='<SCRIPT>alert("XSS");</SCRIPT>')) class WebSearchResultsOverview(unittest.TestCase): """Test of the search results page's Results overview box and links.""" def test_results_overview_split_off(self): """websearch - results overview box when split by collection is off""" browser = Browser() browser.open(weburl + '/search?p=of&sc=0') body = browser.response().read() if body.find("Results overview") > -1: self.fail("Oops, when split by collection is off, " "results overview should not be present.") if body.find('') == -1: self.fail("Oops, when split by collection is off, " "Atlantis collection should be found.") if body.find('') > -1: self.fail("Oops, when split by collection is off, " "Multimedia & Arts should not be found.") try: browser.find_link(url='#Multimedia%20%26%20Arts') self.fail("Oops, when split by collection is off, " "a link to Multimedia & Arts should not be found.") except LinkNotFoundError: pass def test_results_overview_split_on(self): """websearch - results overview box when split by collection is on""" browser = Browser() browser.open(weburl + '/search?p=of&sc=1') body = browser.response().read() if body.find("Results overview") == -1: self.fail("Oops, when split by collection is on, " "results overview should be present.") if body.find('') > -1: self.fail("Oops, when split by collection is on, " "Atlantis collection should not be found.") if body.find('') == -1: self.fail("Oops, when split by collection is on, " "Multimedia & Arts should be found.") try: browser.find_link(url='#Multimedia%20%26%20Arts') except LinkNotFoundError: self.fail("Oops, when split by collection is on, " "a link to Multimedia & Arts should be found.") class WebSearchSortResultsTest(unittest.TestCase): """Test of the search results page's sorting capability.""" def test_sort_results_default(self): """websearch - search results sorting, default method""" self.assertEqual([], test_web_page_content(weburl + '/search?p=cern&rg=1', expected_text="hep-th/0003295")) def test_sort_results_ascending(self): """websearch - search results sorting, ascending field""" self.assertEqual([], test_web_page_content(weburl + '/search?p=cern&rg=1&sf=reportnumber&so=a', expected_text="ISOLTRAP")) def test_sort_results_descending(self): """websearch - search results sorting, descending field""" self.assertEqual([], test_web_page_content(weburl + '/search?p=cern&rg=1&sf=reportnumber&so=d', expected_text="SCAN-9605071")) def test_sort_results_sort_pattern(self): """websearch - search results sorting, preferential sort pattern""" self.assertEqual([], test_web_page_content(weburl + '/search?p=cern&rg=1&sf=reportnumber&so=d&sp=cern', expected_text="CERN-TH-4036")) class WebSearchSearchResultsXML(unittest.TestCase): """Test search results in various output""" - + def test_search_results_xm_output_split_on(self): """ websearch - check document element of search results in xm output (split by collection on)""" browser = Browser() browser.open(weburl + '/search?sc=1&of=xm') body = browser.response().read() num_doc_element = body.count("") if num_doc_element == 0: self.fail("Oops, no document element " "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") num_doc_element = body.count("") if num_doc_element == 0: self.fail("Oops, no document element " "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") - + def test_search_results_xm_output_split_off(self): """ websearch - check document element of search results in xm output (split by collection off)""" browser = Browser() browser.open(weburl + '/search?sc=0&of=xm') body = browser.response().read() num_doc_element = body.count("") if num_doc_element == 0: self.fail("Oops, no document element " "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") num_doc_element = body.count("") if num_doc_element == 0: self.fail("Oops, no document element " "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") def test_search_results_xd_output_split_on(self): """ websearch - check document element of search results in xd output (split by collection on)""" browser = Browser() browser.open(weburl + '/search?sc=1&of=xd') body = browser.response().read() num_doc_element = body.count("" "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") num_doc_element = body.count("") if num_doc_element == 0: self.fail("Oops, no document element " "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") - + def test_search_results_xd_output_split_off(self): """ websearch - check document element of search results in xd output (split by collection off)""" browser = Browser() browser.open(weburl + '/search?sc=0&of=xd') body = browser.response().read() num_doc_element = body.count("") if num_doc_element == 0: self.fail("Oops, no document element " "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") num_doc_element = body.count("") if num_doc_element == 0: self.fail("Oops, no document element " "found in search results.") elif num_doc_element > 1: self.fail("Oops, multiple document elements " "found in search results.") test_suite = make_test_suite(WebSearchWebPagesAvailabilityTest, WebSearchTestSearch, WebSearchTestBrowse, WebSearchTestCollections, WebSearchTestRecord, WebSearchTestLegacyURLs, WebSearchNearestTermsTest, WebSearchBooleanQueryTest, WebSearchAuthorQueryTest, WebSearchSearchEnginePythonAPITest, WebSearchSearchEngineWebAPITest, WebSearchRestrictedCollectionTest, WebSearchRSSFeedServiceTest, WebSearchXSSVulnerabilityTest, WebSearchResultsOverview, WebSearchSortResultsTest, WebSearchSearchResultsXML) if __name__ == "__main__": warn_user_about_tests_and_run(test_suite) - + diff --git a/modules/websearch/lib/websearch_webcoll.py b/modules/websearch/lib/websearch_webcoll.py index 914e0a80a..74f316555 100644 --- a/modules/websearch/lib/websearch_webcoll.py +++ b/modules/websearch/lib/websearch_webcoll.py @@ -1,1097 +1,1095 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """Creates CDS Invenio collection specific pages, using WML and MySQL configuration tables.""" __revision__ = "$Id$" import calendar import copy import getopt import getpass import marshal import signal import sys import cgi import sre import os import string import zlib import Numeric import time import traceback from invenio.config import \ CFG_CERN_SITE, \ CFG_WEBSEARCH_INSTANT_BROWSE, \ CFG_WEBSEARCH_NARROW_SEARCH_SHOW_GRANDSONS, \ cachedir, \ cdslang, \ cdsname, \ weburl from invenio.messages import gettext_set_language, language_list_long -from invenio.search_engine import HitSet, search_pattern, get_creation_date, get_field_i18nname +from invenio.search_engine import HitSet, search_pattern, get_creation_date, get_field_i18nname, restricted_collection_cache from invenio.dbquery import run_sql, escape_string, Error, get_table_update_time from invenio.access_control_engine import acc_authorize_action from invenio.bibrank_record_sorter import get_bibrank_methods from invenio.dateutils import convert_datestruct_to_dategui from invenio.bibformat import format_record from invenio.websearch_external_collections import \ external_collection_load_states, \ dico_collection_external_searches, \ - external_collection_sort_engine_by_name + external_collection_sort_engine_by_name import invenio.template websearch_templates = invenio.template.load('websearch') ## global vars collection_house = {} # will hold collections we treat in this run of the program; a dict of {collname2, collobject1}, ... options = {} # will hold task options # cfg_cache_last_updated_timestamp_tolerance -- cache timestamp # tolerance (in seconds), to account for the fact that an admin might # accidentally happen to edit the collection definitions at exactly # the same second when some webcoll process was about to be started. # In order to be safe, let's put an exaggerated timestamp tolerance # value such as 20 seconds: cfg_cache_last_updated_timestamp_tolerance = 20 # cfg_cache_last_updated_timestamp_file -- location of the cache # timestamp file: cfg_cache_last_updated_timestamp_file = "%s/collections/last_updated" % cachedir def get_collection(colname): """Return collection object from the collection house for given colname. If does not exist, then create it.""" if not collection_house.has_key(colname): colobject = Collection(colname) collection_house[colname] = colobject return collection_house[colname] ## auxiliary functions: def mymkdir(newdir, mode=0777): """works the way a good mkdir should :) - already exists, silently complete - regular file in the way, raise an exception - parent directory(ies) does not exist, make them as well """ if os.path.isdir(newdir): pass elif os.path.isfile(newdir): raise OSError("a file with the same name as the desired " \ "dir, '%s', already exists." % newdir) else: head, tail = os.path.split(newdir) if head and not os.path.isdir(head): mymkdir(head, mode) if tail: os.umask(022) os.mkdir(newdir, mode) def is_selected(var, fld): "Checks if the two are equal, and if yes, returns ' selected'. Useful for select boxes." if var == fld: return " selected" else: return "" def write_message(msg, stream=sys.stdout): """Write message and flush output stream (may be sys.stdout or sys.stderr). Useful for debugging stuff.""" if stream == sys.stdout or stream == sys.stderr: stream.write(time.strftime("%Y-%m-%d %H:%M:%S --> ", time.localtime())) try: stream.write("%s\n" % msg) except UnicodeEncodeError: stream.write("%s\n" % msg.encode('ascii', 'backslashreplace')) stream.flush() else: sys.stderr.write("Unknown stream %s. [must be sys.stdout or sys.stderr]\n" % stream) return def get_field(recID, tag): "Gets list of field 'tag' for the record with 'recID' system number." out = [] digit = tag[0:2] bx = "bib%sx" % digit bibx = "bibrec_bib%sx" % digit query = "SELECT bx.value FROM %s AS bx, %s AS bibx WHERE bibx.id_bibrec='%s' AND bx.id=bibx.id_bibxxx AND bx.tag='%s'" \ % (bx, bibx, recID, tag) res = run_sql(query) for row in res: out.append(row[0]) return out class Collection: "Holds the information on collections (id,name,dbquery)." def __init__(self, name=""): "Creates collection instance by querying the DB configuration database about 'name'." self.calculate_reclist_run_already = 0 # to speed things up without much refactoring self.update_reclist_run_already = 0 # to speed things up without much refactoring self.reclist_with_nonpublic_subcolls = HitSet() if not name: self.name = cdsname # by default we are working on the home page self.id = 1 self.dbquery = None self.nbrecs = None self.reclist = HitSet() else: self.name = name query = "SELECT id,name,dbquery,nbrecs,reclist FROM collection WHERE name='%s'" % escape_string(name) try: res = run_sql(query, None, 1) if res: self.id = res[0][0] self.name = res[0][1] self.dbquery = res[0][2] self.nbrecs = res[0][3] try: self.reclist = HitSet(Numeric.loads(zlib.decompress(res[0][4]))) except: self.reclist = HitSet() else: # collection does not exist! self.id = None self.dbquery = None self.nbrecs = None self.reclist = HitSet() except Error, e: print "Error %d: %s" % (e.args[0], e.args[1]) sys.exit(1) def get_name(self, ln=cdslang, name_type="ln", prolog="", epilog="", prolog_suffix=" ", epilog_suffix=""): """Return nicely formatted collection name for language LN. The NAME_TYPE may be 'ln' (=long name), 'sn' (=short name), etc.""" out = prolog i18name = "" res = run_sql("SELECT value FROM collectionname WHERE id_collection=%s AND ln=%s AND type=%s", (self.id, ln, name_type)) try: i18name += res[0][0] except IndexError: pass if i18name: out += i18name else: out += self.name out += epilog return out def get_ancestors(self): "Returns list of ancestors of the current collection." ancestors = [] id_son = self.id while 1: query = "SELECT cc.id_dad,c.name FROM collection_collection AS cc, collection AS c "\ "WHERE cc.id_son=%d AND c.id=cc.id_dad" % int(id_son) res = run_sql(query, None, 1) if res: col_ancestor = get_collection(res[0][1]) ancestors.append(col_ancestor) id_son = res[0][0] else: break ancestors.reverse() return ancestors def restricted_p(self): """Predicate to test if the collection is restricted or not. Return the contect of the `restrited' column of the collection table (typically Apache group). Otherwise return None if the collection is public.""" - out = None - query = "SELECT restricted FROM collection WHERE id=%d" % self.id - res = run_sql(query, None, 1) - try: - out = res[0][0] - except: - pass - return out + + if restricted_collection_cache.collection_restricted_p(self.name): + return 1 + return None def get_sons(self, type='r'): "Returns list of direct sons of type 'type' for the current collection." sons = [] id_dad = self.id query = "SELECT cc.id_son,c.name FROM collection_collection AS cc, collection AS c "\ "WHERE cc.id_dad=%d AND cc.type='%s' AND c.id=cc.id_son ORDER BY score DESC, c.name ASC" % (int(id_dad), type) res = run_sql(query) for row in res: sons.append(get_collection(row[1])) return sons def get_descendants(self, type='r'): "Returns list of all descendants of type 'type' for the current collection." descendants = [] id_dad = self.id query = "SELECT cc.id_son,c.name FROM collection_collection AS cc, collection AS c "\ "WHERE cc.id_dad=%d AND cc.type='%s' AND c.id=cc.id_son ORDER BY score DESC" % (int(id_dad), type) res = run_sql(query) for row in res: col_desc = get_collection(row[1]) descendants.append(col_desc) descendants += col_desc.get_descendants() return descendants def write_cache_file(self, filename='', filebody=''): "Write a file inside collection cache." # open file: dirname = "%s/collections/%d" % (cachedir, self.id) mymkdir(dirname) fullfilename = dirname + "/%s.html" % filename try: os.umask(022) f = open(fullfilename, "w") except IOError, v: try: (code, message) = v except: code = 0 message = v print "I/O Error: " + str(message) + " (" + str(code) + ")" sys.exit(1) # print user info: if options["verbose"] >= 6: write_message("... creating %s" % fullfilename) sys.stdout.flush() # print page body: f.write(filebody) # close file: f.close() def update_webpage_cache(self): """Create collection page header, navtrail, body (including left and right stripes) and footer, and call write_cache_file() afterwards to update the collection webpage cache.""" ## precalculate latest additions for non-aggregate - ## collections (the info is ln and as independent) + ## collections (the info is ln and as independent) if self.dbquery: self.create_latest_additions_info() - - ## do this for each language: + + ## do this for each language: for lang, lang_fullname in language_list_long(): # but only if some concrete language was not chosen only: if options.get("language", lang) == lang: # load the right message language _ = gettext_set_language(lang) ## first, update navtrail: for as in range(0, 2): self.write_cache_file("navtrail-as=%s-ln=%s" % (as, lang), self.create_navtrail_links(as, lang)) ## second, update page body: for as in range(0, 2): # do both simple search and advanced search pages: body = websearch_templates.tmpl_webcoll_body( ln=lang, collection=self.name, te_portalbox = self.create_portalbox(lang, 'te'), searchfor = self.create_searchfor(as, lang), np_portalbox = self.create_portalbox(lang, 'np'), narrowsearch = self.create_narrowsearch(as, lang, 'r'), focuson = self.create_narrowsearch(as, lang, "v") + \ self.create_external_collections_box(), instantbrowse = self.create_instant_browse(as=as, ln=lang), ne_portalbox = self.create_portalbox(lang, 'ne') ) self.write_cache_file("body-as=%s-ln=%s" % (as, lang), body) ## third, write portalboxes: self.write_cache_file("portalbox-tp-ln=%s" % lang, self.create_portalbox(lang, "tp")) self.write_cache_file("portalbox-te-ln=%s" % lang, self.create_portalbox(lang, "te")) self.write_cache_file("portalbox-lt-ln=%s" % lang, self.create_portalbox(lang, "lt")) self.write_cache_file("portalbox-rt-ln=%s" % lang, self.create_portalbox(lang, "rt")) ## fourth, write 'last updated' information: self.write_cache_file("last-updated-ln=%s" % lang, convert_datestruct_to_dategui(time.localtime(), ln=lang)) return def create_navtrail_links(self, as=0, ln=cdslang): """Creates navigation trail links, i.e. links to collection ancestors (except Home collection). If as==1, then links to Advanced Search interfaces; otherwise Simple Search. """ - + dads = [] for dad in self.get_ancestors(): if dad.name != cdsname: # exclude Home collection dads.append((dad.name, dad.get_name(ln))) return websearch_templates.tmpl_navtrail_links( as=as, ln=ln, dads=dads) def create_portalbox(self, lang=cdslang, position="rt"): """Creates portalboxes of language CDSLANG of the position POSITION by consulting DB configuration database. The position may be: 'lt'='left top', 'rt'='right top', etc.""" out = "" query = "SELECT p.title,p.body FROM portalbox AS p, collection_portalbox AS cp "\ " WHERE cp.id_collection=%d AND p.id=cp.id_portalbox AND cp.ln='%s' AND cp.position='%s' "\ " ORDER BY cp.score DESC" % (self.id, lang, position) res = run_sql(query) for row in res: title, body = row[0], row[1] if title: out += websearch_templates.tmpl_portalbox(title = title, body = body) else: # no title specified, so print body ``as is'' only: out += body return out def create_narrowsearch(self, as=0, ln=cdslang, type="r"): """Creates list of collection descendants of type 'type' under title 'title'. If as==1, then links to Advanced Search interfaces; otherwise Simple Search. Suitable for 'Narrow search' and 'Focus on' boxes.""" # get list of sons and analyse it sons = self.get_sons(type) if not sons: return '' - + # get descendents descendants = self.get_descendants(type) grandsons = [] if CFG_WEBSEARCH_NARROW_SEARCH_SHOW_GRANDSONS: # load grandsons for each son for son in sons: grandsons.append(son.get_sons()) # return "" return websearch_templates.tmpl_narrowsearch( as = as, ln = ln, type = type, father = self, has_grandchildren = len(descendants)>len(sons), sons = sons, display_grandsons = CFG_WEBSEARCH_NARROW_SEARCH_SHOW_GRANDSONS, grandsons = grandsons ) def create_external_collections_box(self, ln=cdslang): external_collection_load_states() if not dico_collection_external_searches.has_key(self.id): return "" engines_list = external_collection_sort_engine_by_name(dico_collection_external_searches[self.id]) return websearch_templates.tmpl_searchalso(ln, engines_list, self.id) def create_latest_additions_info(self, rg=CFG_WEBSEARCH_INSTANT_BROWSE): """ Create info about latest additions that will be used for create_instant_browse() later. """ self.latest_additions_info = [] if self.nbrecs and self.reclist: # firstly, get last 'rg' records: recIDs = Numeric.nonzero(self.reclist._set) total = len(recIDs) to_display = min(rg, total) for idx in range(total-1, total-to_display-1, -1): recid = recIDs[idx] self.latest_additions_info.append({'id': recid, - 'format': format_record(recid, "hb"), + 'format': format_record(recid, "hb"), 'date': get_creation_date(recid, fmt="%Y-%m-%d
%H:%i")}) return def create_instant_browse(self, rg=CFG_WEBSEARCH_INSTANT_BROWSE, as=0, ln=cdslang): "Searches database and produces list of last 'rg' records." - + if self.restricted_p(): return websearch_templates.tmpl_box_restricted_content(ln = ln) else: try: self.latest_additions_info latest_additions_info_p = True except: latest_additions_info_p = False if latest_additions_info_p: passIDs = [] for idx in range(0, min(len(self.latest_additions_info), rg)): passIDs.append({'id': self.latest_additions_info[idx]['id'], 'body': self.latest_additions_info[idx]['format'] + \ websearch_templates.tmpl_record_links(weburl=weburl, recid=self.latest_additions_info[idx]['id'], ln=ln), 'date': self.latest_additions_info[idx]['date']}) - + if self.nbrecs > rg: url = websearch_templates.build_search_url( cc=self.name, jrec=rg+1, ln=ln, as=as) else: url = "" - + return websearch_templates.tmpl_instant_browse( as=as, ln=ln, recids=passIDs, more_link=url) return websearch_templates.tmpl_box_no_records(ln=ln) def create_searchoptions(self): "Produces 'Search options' portal box." box = "" query = """SELECT DISTINCT(cff.id_field),f.code,f.name FROM collection_field_fieldvalue AS cff, field AS f WHERE cff.id_collection=%d AND cff.id_fieldvalue IS NOT NULL AND cff.id_field=f.id ORDER BY cff.score DESC""" % self.id res = run_sql(query) if res: for row in res: field_id = row[0] field_code = row[1] field_name = row[2] query_bis = """SELECT fv.value,fv.name FROM fieldvalue AS fv, collection_field_fieldvalue AS cff WHERE cff.id_collection=%d AND cff.type='seo' AND cff.id_field=%d AND fv.id=cff.id_fieldvalue ORDER BY cff.score_fieldvalue DESC, cff.score DESC, fv.name ASC""" % (self.id, field_id) res_bis = run_sql(query_bis) if res_bis: values = [{'value' : '', 'text' : 'any' + field_name}] # FIXME: internationalisation of "any" for row_bis in res_bis: values.append({'value' : cgi.escape(row_bis[0], 1), 'text' : row_bis[1]}) box += websearch_templates.tmpl_select( fieldname = field_code, values = values ) return box def create_sortoptions(self, ln=cdslang): - "Produces 'Sort options' portal box." + """Produces 'Sort options' portal box.""" + # load the right message language _ = gettext_set_language(ln) box = "" query = """SELECT f.code,f.name FROM field AS f, collection_field_fieldvalue AS cff WHERE id_collection=%d AND cff.type='soo' AND cff.id_field=f.id ORDER BY cff.score DESC, f.name ASC""" % self.id values = [{'value' : '', 'text': "- %s -" % _("latest first")}] res = run_sql(query) if res: for row in res: values.append({'value' : row[0], 'text': row[1]}) else: for tmp in ('title', 'author', 'report number', 'year'): values.append({'value' : tmp.replace(' ', ''), 'text' : get_field_i18nname(tmp, ln)}) box = websearch_templates.tmpl_select( fieldname = 'sf', css_class = 'address', values = values ) box += websearch_templates.tmpl_select( fieldname = 'so', css_class = 'address', values = [ {'value' : 'a' , 'text' : _("asc.")}, {'value' : 'd' , 'text' : _("desc.")} ] ) return box def create_rankoptions(self, ln=cdslang): "Produces 'Rank options' portal box." # load the right message language _ = gettext_set_language(ln) values = [{'value' : '', 'text': "- %s %s -" % (string.lower(_("OR")), _("rank by"))}] for (code, name) in get_bibrank_methods(self.id, ln): values.append({'value' : code, 'text': name}) box = websearch_templates.tmpl_select( fieldname = 'sf', css_class = 'address', values = values ) return box def create_displayoptions(self, ln=cdslang): "Produces 'Display options' portal box." # load the right message language _ = gettext_set_language(ln) values = [] for i in ['10', '25', '50', '100', '250', '500']: values.append({'value' : i, 'text' : i + ' ' + _("results")}) box = websearch_templates.tmpl_select( fieldname = 'rg', css_class = 'address', values = values ) if self.get_sons(): box += websearch_templates.tmpl_select( fieldname = 'sc', css_class = 'address', values = [ {'value' : '1' , 'text' : _("split by collection")}, {'value' : '0' , 'text' : _("single list")} ] ) return box def create_formatoptions(self, ln=cdslang): "Produces 'Output format options' portal box." # load the right message language _ = gettext_set_language(ln) box = "" values = [] query = """SELECT f.code,f.name FROM format AS f, collection_format AS cf WHERE cf.id_collection=%d AND cf.id_format=f.id ORDER BY cf.score DESC, f.name ASC""" % self.id res = run_sql(query) if res: for row in res: values.append({'value' : row[0], 'text': row[1]}) else: values.append({'value' : 'hb', 'text' : "HTML %s" % _("brief")}) box = websearch_templates.tmpl_select( fieldname = 'of', css_class = 'address', values = values ) return box def create_searchwithin_selection_box(self, fieldname='f', value='', ln='en'): - "Produces 'search within' selection box for the current collection." + """Produces 'search within' selection box for the current collection.""" + # get values query = """SELECT f.code,f.name FROM field AS f, collection_field_fieldvalue AS cff WHERE cff.type='sew' AND cff.id_collection=%d AND cff.id_field=f.id ORDER BY cff.score DESC, f.name ASC""" % self.id res = run_sql(query) values = [{'value' : '', 'text' : get_field_i18nname("any field", ln)}] if res: for row in res: values.append({'value' : row[0], 'text' : row[1]}) else: if CFG_CERN_SITE: for tmp in ['title', 'author', 'abstract', 'report number', 'year']: values.append({'value' : tmp.replace(' ', ''), 'text' : get_field_i18nname(tmp, ln)}) else: for tmp in ['title', 'author', 'abstract', 'keyword', 'report number', 'year', 'fulltext', 'reference']: values.append({'value' : tmp.replace(' ', ''), 'text' : get_field_i18nname(tmp, ln)}) return websearch_templates.tmpl_searchwithin_select( fieldname = fieldname, ln = ln, selected = value, values = values ) def create_searchexample(self): "Produces search example(s) for the current collection." out = "$collSearchExamples = getSearchExample(%d, $se);" % self.id return out def create_searchfor(self, as=0, ln=cdslang): "Produces either Simple or Advanced 'Search for' box for the current collection." if as == 1: return self.create_searchfor_advanced(ln) else: return self.create_searchfor_simple(ln) def create_searchfor_simple(self, ln=cdslang): "Produces simple 'Search for' box for the current collection." return websearch_templates.tmpl_searchfor_simple( ln=ln, collection_id = self.name, collection_name=self.get_name(ln=ln), record_count=self.nbrecs, middle_option = self.create_searchwithin_selection_box(ln=ln), ) def create_searchfor_advanced(self, ln=cdslang): "Produces advanced 'Search for' box for the current collection." return websearch_templates.tmpl_searchfor_advanced( ln = ln, collection_id = self.name, collection_name=self.get_name(ln=ln), record_count=self.nbrecs, middle_option_1 = self.create_searchwithin_selection_box('f1', ln=ln), middle_option_2 = self.create_searchwithin_selection_box('f2', ln=ln), middle_option_3 = self.create_searchwithin_selection_box('f3', ln=ln), searchoptions = self.create_searchoptions(), sortoptions = self.create_sortoptions(ln), rankoptions = self.create_rankoptions(ln), displayoptions = self.create_displayoptions(ln), formatoptions = self.create_formatoptions(ln) ) def calculate_reclist(self): """Calculate, set and return the (reclist, reclist_with_nonpublic_subcolls) tuple for given collection.""" if self.calculate_reclist_run_already: # do we have to recalculate? return (self.reclist, self.reclist_with_nonpublic_subcolls) if options["verbose"] >= 6: write_message("... calculating reclist of %s" % self.name) reclist = HitSet() # will hold results for public sons only; good for storing into DB reclist_with_nonpublic_subcolls = HitSet() # will hold results for both public and nonpublic sons; good for deducing total # number of documents if not self.dbquery: # A - collection does not have dbquery, so query recursively all its sons # that are either non-restricted or that have the same restriction rules for coll in self.get_sons(): coll_reclist, coll_reclist_with_nonpublic_subcolls = coll.calculate_reclist() if ((coll.restricted_p() is None) or (coll.restricted_p() == self.restricted_p())): # add this reclist ``for real'' only if it is public reclist.union(coll_reclist) reclist_with_nonpublic_subcolls.union(coll_reclist_with_nonpublic_subcolls) else: # B - collection does have dbquery, so compute it: # (note: explicitly remove DELETED records) if CFG_CERN_SITE: reclist = search_pattern(None, self.dbquery + \ ' -collection:"DELETED" -collection:"DUMMY"') else: reclist = search_pattern(None, self.dbquery + ' -collection:"DELETED"') reclist_with_nonpublic_subcolls = copy.deepcopy(reclist) # deduce the number of records: reclist.calculate_nbhits() reclist_with_nonpublic_subcolls.calculate_nbhits() # store the results: self.nbrecs = reclist_with_nonpublic_subcolls._nbhits self.reclist = reclist self.reclist_with_nonpublic_subcolls = reclist_with_nonpublic_subcolls # last but not least, update the speed-up flag: self.calculate_reclist_run_already = 1 # return the two sets: return (self.reclist, self.reclist_with_nonpublic_subcolls) def update_reclist(self): "Update the record universe for given collection; nbrecs, reclist of the collection table." if self.update_reclist_run_already: # do we have to reupdate? return 0 if options["verbose"] >= 6: write_message("... updating reclist of %s (%s recs)" % (self.name, self.nbrecs)) sys.stdout.flush() try: query = "UPDATE collection SET nbrecs=%d, reclist='%s' WHERE id=%d" % \ (self.nbrecs, escape_string(zlib.compress(Numeric.dumps(self.reclist._set))), self.id) run_sql(query) self.reclist_updated_since_start = 1 except Error, e: print "Database Query Error %d: %s." % (e.args[0], e.args[1]) sys.exit(1) # last but not least, update the speed-up flag: self.update_reclist_run_already = 1 return 0 def get_datetime(var, format_string="%Y-%m-%d %H:%M:%S"): """Returns a date string according to the format string. It can handle normal date strings and shifts with respect to now.""" date = time.time() shift_re = sre.compile("([-\+]{0,1})([\d]+)([dhms])") factors = {"d":24*3600, "h":3600, "m":60, "s":1} m = shift_re.match(var) if m: sign = m.groups()[0] == "-" and -1 or 1 factor = factors[m.groups()[2]] value = float(m.groups()[1]) date = time.localtime(date + sign * factor * value) date = time.strftime(format_string, date) else: date = time.strptime(var, format_string) date = time.strftime(format_string, date) return date def get_current_time_timestamp(): """Return timestamp corresponding to the current time.""" return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) - + def compare_timestamps_with_tolerance(timestamp1, timestamp2, tolerance=0): """Compare two timestamps TIMESTAMP1 and TIMESTAMP2, of the form '2005-03-31 17:37:26'. Optionally receives a TOLERANCE argument (in seconds). Return -1 if TIMESTAMP1 is less than TIMESTAMP2 minus TOLERANCE, 0 if they are equal within TOLERANCE limit, and 1 if TIMESTAMP1 is greater than TIMESTAMP2 plus TOLERANCE. """ # remove any trailing .00 in timestamps: timestamp1 = sre.sub(r'\.[0-9]+$', '', timestamp1) timestamp2 = sre.sub(r'\.[0-9]+$', '', timestamp2) # first convert timestamps to Unix epoch seconds: timestamp1_seconds = calendar.timegm(time.strptime(timestamp1, "%Y-%m-%d %H:%M:%S")) timestamp2_seconds = calendar.timegm(time.strptime(timestamp2, "%Y-%m-%d %H:%M:%S")) # now compare them: if timestamp1_seconds < timestamp2_seconds - tolerance: return -1 elif timestamp1_seconds > timestamp2_seconds + tolerance: return 1 else: return 0 def get_database_last_updated_timestamp(): """Return last updated timestamp for collection-related and record-related database tables. """ database_tables_timestamps = [] database_tables_timestamps.append(get_table_update_time('bibrec')) database_tables_timestamps.append(get_table_update_time('bibfmt')) database_tables_timestamps.append(get_table_update_time('idxWORD%')) database_tables_timestamps.append(get_table_update_time('collection%')) database_tables_timestamps.append(get_table_update_time('portalbox')) database_tables_timestamps.append(get_table_update_time('field%')) database_tables_timestamps.append(get_table_update_time('format%')) database_tables_timestamps.append(get_table_update_time('rnkMETHODNAME')) return max(database_tables_timestamps) def get_cache_last_updated_timestamp(): """Return last updated cache timestamp.""" try: f = open(cfg_cache_last_updated_timestamp_file, "r") except: return "1970-01-01 00:00:00" timestamp = f.read() f.close() return timestamp def set_cache_last_updated_timestamp(timestamp): """Set last updated cache timestamp to TIMESTAMP.""" try: f = open(cfg_cache_last_updated_timestamp_file, "w") except: pass f.write(timestamp) f.close() return timestamp def task_sig_sleep(sig, frame): """Signal handler for the 'sleep' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_sleep(), got signal %s frame %s" % (sig, frame)) write_message("sleeping...") task_update_status("SLEEPING") signal.pause() # wait for wake-up signal def task_sig_wakeup(sig, frame): """Signal handler for the 'wakeup' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_wakeup(), got signal %s frame %s" % (sig, frame)) write_message("continuing...") task_update_status("CONTINUING") def task_sig_stop(sig, frame): """Signal handler for the 'stop' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_stop(), got signal %s frame %s" % (sig, frame)) write_message("stopping...") task_update_status("STOPPING") pass # FIXME: is there anything to be done? task_update_status("STOPPED") sys.exit(0) def task_sig_suicide(sig, frame): """Signal handler for the 'suicide' signal sent by BibSched.""" if options["verbose"] >= 9: write_message("task_sig_suicide(), got signal %s frame %s" % (sig, frame)) write_message("suiciding myself now...") task_update_status("SUICIDING") write_message("suicided") task_update_status("SUICIDED") sys.exit(0) def task_sig_unknown(sig, frame): """Signal handler for the other unknown signals sent by shell or user.""" # do nothing for unknown signals: - write_message("unknown signal %d (frame %s) ignored" % (sig, frame)) + write_message("unknown signal %d (frame %s) ignored" % (sig, frame)) def authenticate(user, header="WebColl Task Submission", action="runwebcoll"): """Authenticate the user against the user database. Check for its password, if it exists. Check for action access rights. Return user name upon authorization success, do system exit upon authorization failure. """ print header print "=" * len(header) if user == "": print >> sys.stdout, "\rUsername: ", user = string.strip(string.lower(sys.stdin.readline())) else: print >> sys.stdout, "\rUsername:", user ## first check user pw: res = run_sql("select id,password from user where email=%s", (user,), 1) + \ run_sql("select id,password from user where nickname=%s", (user,), 1) if not res: print "Sorry, %s does not exist." % user sys.exit(1) else: (uid_db, password_db) = res[0] if password_db: password_entered = getpass.getpass() if password_db == password_entered: pass else: print "Sorry, wrong credentials for %s." % user sys.exit(1) ## secondly check authorization for the action: (auth_code, auth_message) = acc_authorize_action(uid_db, action) if auth_code != 0: print auth_message sys.exit(1) return user def task_submit(): """Submits task to the BibSched task queue. This is what people will be invoking via command line.""" global options ## sanity check: remove eventual "task" option: if options.has_key("task"): del options["task"] ## authenticate user: user = authenticate(options.get("user", "")) ## submit task: if options["verbose"] >= 9: print "" write_message("storing task options %s\n" % options) task_id = run_sql("""INSERT INTO schTASK (id,proc,user,runtime,sleeptime,status,arguments) VALUES (NULL,'webcoll',%s,%s,%s,'WAITING',%s)""", (user, options["runtime"], options["sleeptime"], marshal.dumps(options))) ## update task number: options["task"] = task_id run_sql("""UPDATE schTASK SET arguments=%s WHERE id=%s""", (marshal.dumps(options), task_id)) write_message("Task #%d submitted." % task_id) return task_id def task_update_progress(msg): """Updates progress information in the BibSched task table.""" global options return run_sql("UPDATE schTASK SET progress=%s where id=%s", (msg, options["task"])) def task_update_status(val): """Updates status information in the BibSched task table.""" global options return run_sql("UPDATE schTASK SET status=%s where id=%s", (val, options["task"])) def task_read_status(task_id): """Read status information in the BibSched task table.""" res = run_sql("SELECT status FROM schTASK where id=%s", (task_id,), 1) try: out = res[0][0] except: out = 'UNKNOWN' return out def task_get_options(id): """Returns options for the task 'id' read from the BibSched task queue table.""" out = {} res = run_sql("SELECT arguments FROM schTASK WHERE id=%s AND proc='webcoll'", (id,)) try: out = marshal.loads(res[0][0]) except: write_message("Error: WebColl task %d does not seem to exist." % id) sys.exit(1) return out def task_run(task_id): """Run the WebColl task by fetching arguments from the BibSched task queue. This is what BibSched will be invoking via daemon call. The task will update collection reclist cache and collection web pages for given collection. (default is all). Arguments described in usage() function. Return 1 in case of success and 0 in case of failure.""" global options task_run_start_timestamp = get_current_time_timestamp() options = task_get_options(task_id) # get options from BibSched task table ## check task id: if not options.has_key("task"): write_message("Error: The task #%d does not seem to be a WebColl task." % task_id) return 0 ## check task status: task_status = task_read_status(task_id) if task_status != "WAITING": write_message("Error: The task #%d is %s. I expected WAITING." % (task_id, task_status)) return 0 ## we can run the task now: if options["verbose"]: write_message("Task #%d started." % task_id) task_update_status("RUNNING") ## initialize signal handler: signal.signal(signal.SIGUSR1, task_sig_sleep) signal.signal(signal.SIGTERM, task_sig_stop) signal.signal(signal.SIGABRT, task_sig_suicide) signal.signal(signal.SIGCONT, task_sig_wakeup) signal.signal(signal.SIGINT, task_sig_unknown) colls = [] # decide whether we need to run or not, by comparing last updated timestamps: if options["verbose"] >= 3: write_message("Database timestamp is %s." % get_database_last_updated_timestamp()) write_message("Collection cache timestamp is %s." % get_cache_last_updated_timestamp()) if options.has_key("part"): write_message("Running cache update part %s only." % options["part"]) if options.has_key("force") or \ compare_timestamps_with_tolerance(get_database_last_updated_timestamp(), get_cache_last_updated_timestamp(), cfg_cache_last_updated_timestamp_tolerance) >= 0: ## either forced update was requested or cache is not up to date, so recreate it: # firstly, decide which collections to do: if options.has_key("collection"): coll = get_collection(options["collection"]) if coll.id is None: usage(1, 'Collection %s does not exist' % coll.name) colls.append(coll) else: res = run_sql("SELECT name FROM collection ORDER BY id") for row in res: colls.append(get_collection(row[0])) # secondly, update collection reclist cache: if options.get("part", 1) == 1: i = 0 for coll in colls: i += 1 if options["verbose"]: write_message("%s / reclist cache update" % coll.name) coll.calculate_reclist() coll.update_reclist() task_update_progress("Part 1/2: done %d/%d" % (i, len(colls))) # thirdly, update collection webpage cache: if options.get("part", 2) == 2: i = 0 for coll in colls: i += 1 if options["verbose"]: write_message("%s / webpage cache update" % coll.name) coll.update_webpage_cache() task_update_progress("Part 2/2: done %d/%d" % (i, len(colls))) # finally update the cache last updated timestamp: # (but only when all collections were updated, not when only # some of them were forced-updated as per admin's demand) if not options.has_key("collection"): set_cache_last_updated_timestamp(task_run_start_timestamp) if options["verbose"] >= 3: write_message("Collection cache timestamp is set to %s." % get_cache_last_updated_timestamp()) else: ## cache up to date, we don't have to run if options["verbose"]: - write_message("Collection cache is up to date, no need to run.") - pass + write_message("Collection cache is up to date, no need to run.") + pass ## we are done: task_update_progress("Done.") task_update_status("DONE") if options["verbose"]: write_message("Task #%d finished." % task_id) return 1 def usage(exitcode=1, msg=""): """Prints usage info.""" if msg: sys.stderr.write("Error: %s.\n" % msg) sys.stderr.write("Usage: %s [options]\n" % sys.argv[0]) sys.stderr.write("Command options:\n") sys.stderr.write(" -c, --collection\t Update cache for the given collection only. [all]\n") sys.stderr.write(" -f, --force\t Force update even if cache is up to date. [no]\n") sys.stderr.write(" -p, --part\t Update only certain cache parts (1=reclist, 2=webpage). [both]\n") sys.stderr.write(" -l, --language\t Update pages in only certain language (e.g. fr). [all]\n") sys.stderr.write("Scheduling options:\n") sys.stderr.write(" -u, --user=USER \t User name to submit the task as, password needed.\n") sys.stderr.write(" -t, --runtime=TIME \t Time to execute the task (now), e.g.: +15s, 5m, 3h, 2002-10-27 13:57:26\n") sys.stderr.write(" -s, --sleeptime=SLEEP \t Sleeping frequency after which to repeat task (no), e.g.: 30m, 2h, 1d\n") sys.stderr.write("General options:\n") sys.stderr.write(" -h, --help \t\t Print this help.\n") sys.stderr.write(" -V, --version \t\t Print version information.\n") sys.stderr.write(" -v, --verbose=LEVEL \t Verbose level (from 0 to 9, default 1).\n") sys.stderr.write("""Description: %s updates the collection cache (record universe for a given collection plus web page elements) based on WML and DB configuration parameters. If the collection name is passed as the second argument, it'll update this collection only. If the collection name is immediately followed by a plus sign, it will also update all its desdendants. The top-level collection name may be entered as the void string.\n""" % sys.argv[0]) sys.exit(exitcode) def main(): """Main function that analyzes command line input and calls whatever is appropriate. Useful for learning on how to write BibSched tasks.""" global options ## parse command line: if len(sys.argv) == 2 and sys.argv[1].isdigit(): ## A - run the task task_id = int(sys.argv[1]) try: if not task_run(task_id): write_message("Error occurred. Exiting.", sys.stderr) except StandardError, e: write_message("Unexpected error occurred: %s." % e, sys.stderr) write_message("Traceback is:", sys.stderr) traceback.print_tb(sys.exc_info()[2]) write_message("Exiting.", sys.stderr) task_update_status("ERROR") else: ## B - submit the task # set default values: options["runtime"] = time.strftime("%Y-%m-%d %H:%M:%S") options["verbose"] = 1 options["sleeptime"] = "" # set user-defined options: try: opts, args = getopt.getopt(sys.argv[1:], "hVv:u:s:t:c:fp:l:", ["help", "version", "verbose=", "user=", "sleep=", "time=", "collection=", "force", "part=", "language="]) except getopt.GetoptError, err: usage(1, err) try: for opt in opts: if opt[0] in ["-h", "--help"]: usage(0) elif opt[0] in ["-V", "--version"]: print __revision__ sys.exit(0) elif opt[0] in [ "-u", "--user"]: options["user"] = opt[1] elif opt[0] in ["-v", "--verbose"]: options["verbose"] = int(opt[1]) elif opt[0] in [ "-s", "--sleeptime" ]: get_datetime(opt[1]) # see if it is a valid shift options["sleeptime"] = opt[1] elif opt[0] in [ "-t", "--runtime" ]: options["runtime"] = get_datetime(opt[1]) elif opt[0] in [ "-c", "--collection"]: options["collection"] = opt[1] elif opt[0] in [ "-f", "--force"]: options["force"] = 1 elif opt[0] in [ "-p", "--part"]: options["part"] = int(opt[1]) elif opt[0] in [ "-l", "--language"]: options["language"] = opt[1] else: usage(1) except StandardError, e: usage(e) task_submit() return ### okay, here we go: if __name__ == '__main__': main() diff --git a/modules/websearch/lib/websearch_webinterface.py b/modules/websearch/lib/websearch_webinterface.py index 082c2db1c..cc5c6f3ec 100644 --- a/modules/websearch/lib/websearch_webinterface.py +++ b/modules/websearch/lib/websearch_webinterface.py @@ -1,485 +1,497 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """WebSearch URL handler.""" __revision__ = "$Id$" import cgi from urllib import quote from mod_python import apache -from invenio.config import weburl, cdsname, cachedir, cdsnameintl +from invenio.config import weburl, cdsname, cachedir, cdsnameintl, cdslang from invenio.dbquery import Error -from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory, http_check_credentials +from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory from invenio.urlutils import redirect_to_url, make_canonical_urlargd, drop_default_urlargd from invenio.webuser import getUid, page_not_authorized, \ - get_user_preferences, auth_apache_user_collection_p + get_user_preferences, collect_user_info from invenio import search_engine from invenio.websubmit_webinterface import WebInterfaceFilesPages from invenio.webpage import page, create_error_box from invenio.messages import gettext_set_language -from invenio.search_engine import get_colID, get_coll_i18nname +from invenio.search_engine import get_colID, get_coll_i18nname, restricted_collection_cache +from invenio.access_control_engine import acc_authorize_action +from invenio.access_control_config import VIEWRESTRCOLL import invenio.template websearch_templates = invenio.template.load('websearch') search_results_default_urlargd = websearch_templates.search_results_default_urlargd search_interface_default_urlargd = websearch_templates.search_interface_default_urlargd def wash_search_urlargd(form): """ Create canonical search arguments from those passed via web form. """ - + argd = wash_urlargd(form, search_results_default_urlargd) # Sometimes, users pass ot=245,700 instead of # ot=245&ot=700. Normalize that. ots = [] for ot in argd['ot']: ots += ot.split(',') argd['ot'] = ots # We can either get the mode of function as # action=, or by setting action_browse or # action_search. if argd['action_browse']: argd['action'] = 'browse' elif argd['action_search']: argd['action'] = 'search' else: if argd['action'] not in ('browse', 'search'): argd['action'] = 'search' del argd['action_browse'] del argd['action_search'] return argd class WebInterfaceRecordPages(WebInterfaceDirectory): """ Handling of a /record/ URL fragment """ _exports = ['', 'files'] def __init__(self, recid): self.recid = recid self.files = WebInterfaceFilesPages(self.recid) return def __call__(self, req, form): argd = wash_search_urlargd(form) argd['recid'] = self.recid req.argd = argd uid = getUid(req) if uid == -1: - return page_not_authorized(req, "../", + return page_not_authorized(req, "../", \ + text="You are not authorized to view this record.", \ navmenuid='search') elif uid > 0: pref = get_user_preferences(uid) try: argd['rg'] = int(pref['websearch_group_records']) except (KeyError, ValueError): pass # Check if the record belongs to a restricted primary # collection. If yes, redirect to the authenticated URL. record_primary_collection = search_engine.guess_primary_collection_of_a_record(self.recid) - if search_engine.coll_restricted_p(record_primary_collection): + if restricted_collection_cache.collection_restricted_p(record_primary_collection): del argd['recid'] # not wanted argument for detailed record page target = '/record-restricted/' + str(self.recid) + '/' + \ make_canonical_urlargd(argd, search_results_default_urlargd) return redirect_to_url(req, target) # mod_python does not like to return [] in case when of=id: out = search_engine.perform_request_search(req, **argd) if out == []: return str(out) else: return out # Return the same page wether we ask for /record/123 or /record/123/ index = __call__ class WebInterfaceRecordRestrictedPages(WebInterfaceDirectory): """ Handling of a /record-restricted/ URL fragment """ _exports = ['', 'files'] def __init__(self, recid): self.recid = recid self.files = WebInterfaceFilesPages(self.recid) return def __call__(self, req, form): argd = wash_search_urlargd(form) argd['recid'] = self.recid req.argd = argd uid = getUid(req) + user_info = collect_user_info(req) if uid == -1: - return page_not_authorized(req, "../", + return page_not_authorized(req, "../", \ + text="You are not authorized to view this record.", \ navmenuid='search') elif uid > 0: pref = get_user_preferences(uid) try: argd['rg'] = int(pref['websearch_group_records']) except (KeyError, ValueError): pass record_primary_collection = search_engine.guess_primary_collection_of_a_record(self.recid) - def check_credentials(user, password): - """Validate user and password against Apache user database.""" - if not auth_apache_user_collection_p(user, password, - record_primary_collection): - return False - return True - # this function only returns if the credentials are valid - http_check_credentials(req, record_primary_collection, check_credentials) + if restricted_collection_cache.collection_restricted_p(record_primary_collection): + (ret, out) = acc_authorize_action(user_info, VIEWRESTRCOLL, collection=record_primary_collection) + if ret: + return page_not_authorized(req, "../", \ + text="You are not authorized to view this record.", \ + navmenuid='search') # Keep all the arguments, they might be reused in the # record page itself to derivate other queries req.argd = argd # mod_python does not like to return [] in case when of=id: out = search_engine.perform_request_search(req, **argd) if out == []: return str(out) else: return out # Return the same page wether we ask for /record/123 or /record/123/ index = __call__ class WebInterfaceSearchResultsPages(WebInterfaceDirectory): """ Handling of the /search URL and its sub-pages. """ _exports = ['', 'authenticate', 'cache', 'log'] def __call__(self, req, form): """ Perform a search. """ argd = wash_search_urlargd(form) if req.method == 'POST': raise apache.SERVER_RETURN, apache.HTTP_METHOD_NOT_ALLOWED uid = getUid(req) + user_info = collect_user_info(req) if uid == -1: - return page_not_authorized(req, "../search", + return page_not_authorized(req, "../", \ + text="You are not authorized to view this area.", \ navmenuid='search') elif uid > 0: pref = get_user_preferences(uid) try: argd['rg'] = int(pref['websearch_group_records']) except (KeyError, ValueError): pass # If any of the collection requires authentication, redirect # to the authentication form. for coll in argd['c'] + [argd['cc']]: - if search_engine.coll_restricted_p(coll): - target = '/search/authenticate' + \ - make_canonical_urlargd(argd, search_results_default_urlargd) - return redirect_to_url(req, target) + if restricted_collection_cache.collection_restricted_p(coll): + (ret, out) = acc_authorize_action(user_info, VIEWRESTRCOLL, collection=coll) + if ret and user_info['email'] == 'guest': + target = '/youraccount/login' + make_canonical_urlargd({'ln' : argd['ln'], 'referer' : weburl + '/search' + make_canonical_urlargd(argd, search_results_default_urlargd)}, {'ln' : cdslang}) + return redirect_to_url(req, target) + elif ret: + return page_not_authorized(req, "../", \ + text="You are not authorized to view this area.", \ + navmenuid='search') + # Keep all the arguments, they might be reused in the # search_engine itself to derivate other queries req.argd = argd # mod_python does not like to return [] in case when of=id: out = search_engine.perform_request_search(req, **argd) if out == []: return str(out) else: return out def cache(self, req, form): """Search cache page.""" argd = wash_urlargd(form, {'action': (str, 'show')}) return search_engine.perform_request_cache(req, action=argd['action']) def log(self, req, form): """Search log page.""" argd = wash_urlargd(form, {'date': (str, '')}) return search_engine.perform_request_log(req, date=argd['date']) def authenticate(self, req, form): """Restricted search results pages.""" - argd = wash_search_urlargd(form) - def check_credentials(user, password): - """Validate user and password against Apache user database.""" - for coll in argd['c'] + [argd['cc']]: - if not auth_apache_user_collection_p(user, password, coll): - return False - return True + argd = wash_search_urlargd(form) - # this function only returns if the credentials are valid - http_check_credentials(req, "restricted collection", check_credentials) + user_info = collect_user_info(req) + for coll in argd['c'] + [argd['cc']]: + if restricted_collection_cache.collection_restricted_p(coll): + (ret, out) = acc_authorize_action(user_info, VIEWRESTRCOLL, collection=coll) + if ret: + return page_not_authorized(req, "../", \ + text="You are not authorized to view this collection.", \ + navmenuid='search') # Keep all the arguments, they might be reused in the # search_engine itself to derivate other queries req.argd = argd uid = getUid(req) if uid > 0: pref = get_user_preferences(uid) try: argd['rg'] = int(pref['websearch_group_records']) except (KeyError, ValueError): pass # mod_python does not like to return [] in case when of=id: out = search_engine.perform_request_search(req, **argd) if out == []: return str(out) else: return out # Parameters for the legacy URLs, of the form /?c=ALEPH legacy_collection_default_urlargd = { 'as': (int, 0), 'verbose': (int, 0), 'c': (str, cdsname)} class WebInterfaceSearchInterfacePages(WebInterfaceDirectory): """ Handling of collection navigation.""" _exports = [('index.py', 'legacy_collection'), ('', 'legacy_collection'), ('search.py', 'legacy_search'), 'search'] search = WebInterfaceSearchResultsPages() def _lookup(self, component, path): """ This handler is invoked for the dynamic URLs (for collections and records)""" if component == 'collection': c = '/'.join(path) def answer(req, form): """Accessing collections cached pages.""" # Accessing collections: this is for accessing the # cached page on top of each collection. argd = wash_urlargd(form, search_interface_default_urlargd) # We simply return the cached page of the collection argd['c'] = c if not argd['c']: # collection argument not present; display # home collection by default argd['c'] = cdsname return display_collection(req, **argd) return answer, [] elif component == 'record' or component == 'record-restricted': try: recid = int(path[0]) except IndexError: # display record #1 for URL /record without a number recid = 1 except ValueError: if path[0] == '': # display record #1 for URL /record/ without a number recid = 1 else: # display page not found for URLs like /record/foo return None, [] if recid <= 0: # display page not found for URLs like /record/-5 or /record/0 return None, [] if component == 'record-restricted': return WebInterfaceRecordRestrictedPages(recid), path[1:] else: return WebInterfaceRecordPages(recid), path[1:] return None, [] def legacy_collection(self, req, form): """Collection URL backward compatibility handling.""" argd = wash_urlargd(form, legacy_collection_default_urlargd) # If we specify no collection, then we don't need to redirect # the user, so that accessing returns the # default collection. if not form.has_key('c'): return display_collection(req, **argd) # make the collection an element of the path, and keep the # other query elements as is. If the collection is cdsname, # however, redirect to the main URL. c = argd['c'] del argd['c'] if c == cdsname: target = '/' else: target = '/collection/' + quote(c) target += make_canonical_urlargd(argd, legacy_collection_default_urlargd) return redirect_to_url(req, target) def legacy_search(self, req, form): """Search URL backward compatibility handling.""" argd = wash_search_urlargd(form) # We either jump into the generic search form, or the specific # /record/... display if a recid is requested if argd['recid'] != -1: target = '/record/%d' % argd['recid'] del argd['recid'] else: target = '/search' target += make_canonical_urlargd(argd, search_results_default_urlargd) return redirect_to_url(req, target) def display_collection(req, c, as, verbose, ln): "Display search interface page for collection c by looking in the collection cache." _ = gettext_set_language(ln) req.argd = drop_default_urlargd({'as': as, 'verbose': verbose, 'ln': ln}, search_interface_default_urlargd) # get user ID: try: uid = getUid(req) user_preferences = {} if uid == -1: - return page_not_authorized(req, "../", + return page_not_authorized(req, "../", \ + text="You are not authorized to view this collection", \ navmenuid='search') elif uid > 0: user_preferences = get_user_preferences(uid) except Error: return page(title=_("Internal Error"), body = create_error_box(req, verbose=verbose, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req, navmenuid='search') # start display: req.content_type = "text/html" req.send_http_header() # deduce collection id: colID = get_colID(c) if type(colID) is not int: page_body = '

' + (_("Sorry, collection %s does not seem to exist.") % ('' + str(c) + '')) + '

' page_body = '

' + (_("You may want to start browsing from %s.") % ('' + cdsnameintl[ln] + '')) + '

' return page(title=_("Collection %s Not Found") % cgi.escape(c), body=page_body, description=(cdsname + ' - ' + _("Not found") + ': ' + cgi.escape(str(c))), keywords="%s, CDS Invenio" % cdsname, uid=uid, language=ln, req=req, navmenuid='search') # display collection interface page: try: filedesc = open("%s/collections/%d/navtrail-as=%d-ln=%s.html" % (cachedir, colID, as, ln), "r") c_navtrail = filedesc.read() filedesc.close() filedesc = open("%s/collections/%d/body-as=%d-ln=%s.html" % (cachedir, colID, as, ln), "r") c_body = filedesc.read() filedesc.close() filedesc = open("%s/collections/%d/portalbox-tp-ln=%s.html" % (cachedir, colID, ln), "r") c_portalbox_tp = filedesc.read() filedesc.close() filedesc = open("%s/collections/%d/portalbox-te-ln=%s.html" % (cachedir, colID, ln), "r") c_portalbox_te = filedesc.read() filedesc.close() filedesc = open("%s/collections/%d/portalbox-lt-ln=%s.html" % (cachedir, colID, ln), "r") c_portalbox_lt = filedesc.read() filedesc.close() - # show help boxes (usually located in "tr", "top right") + # show help boxes (usually located in "tr", "top right") # if users have not banned them in their preferences: c_portalbox_rt = "" if user_preferences.get('websearch_helpbox', 1) > 0: filedesc = open("%s/collections/%d/portalbox-rt-ln=%s.html" % (cachedir, colID, ln), "r") c_portalbox_rt = filedesc.read() filedesc.close() filedesc = open("%s/collections/%d/last-updated-ln=%s.html" % (cachedir, colID, ln), "r") c_last_updated = filedesc.read() filedesc.close() if c == cdsname: title = cdsnameintl[ln] else: title = get_coll_i18nname(c, ln) return page(title=title, body=c_body, navtrail=c_navtrail, description="%s - %s" % (cdsname, c), keywords="%s, CDS Invenio, %s" % (cdsname, c), uid=uid, language=ln, req=req, cdspageboxlefttopadd=c_portalbox_lt, cdspageboxrighttopadd=c_portalbox_rt, titleprologue=c_portalbox_tp, titleepilogue=c_portalbox_te, lastupdated=c_last_updated, navmenuid='search') except: if verbose >= 9: req.write("
c=%s" % c) req.write("
as=%s" % as) req.write("
ln=%s" % ln) req.write("
colID=%s" % colID) req.write("
uid=%s" % uid) return page(title=_("Internal Error"), body = create_error_box(req, ln=ln), description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, uid=uid, language=ln, req=req, navmenuid='search') return "\n" class WebInterfaceRSSFeedServicePages(WebInterfaceDirectory): """RSS 2.0 feed service pages.""" def __call__(self, req, form): """RSS 2.0 feed service.""" # FIXME: currently searching live, should put cache in place via webcoll return search_engine.perform_request_search(req, of="xr") index = __call__ diff --git a/modules/websearch/web/admin/websearchadmin.py b/modules/websearch/web/admin/websearchadmin.py index 3d1bf7740..29fcee125 100644 --- a/modules/websearch/web/admin/websearchadmin.py +++ b/modules/websearch/web/admin/websearchadmin.py @@ -1,1076 +1,1076 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio WebSearch Administrator Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" import sys import invenio.websearchadminlib as wsc from invenio.bibrankadminlib import check_user from invenio.webpage import page, create_error_box from invenio.config import weburl, sweburl, cdslang, cdsname from invenio.dbquery import Error from invenio.webuser import getUid, page_not_authorized from invenio.messages import gettext_set_language def switchfmtscore(req, colID, type, id_1, id_2, ln=cdslang): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_switchfmtscore(colID=colID, ln=ln, type=type, id_1=id_1, id_2=id_2), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def switchfldscore(req, colID, id_1, id_2, fmeth, ln=cdslang): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_switchfldscore(colID=colID, ln=ln, id_1=id_1, id_2=id_2, fmeth=fmeth), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def switchfldvaluescore(req, colID, id_1, id_fldvalue_1, id_fldvalue_2, ln=cdslang): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_switchfldvaluescore(colID=colID, ln=ln, id_1=id_1, id_fldvalue_1=id_fldvalue_1, id_fldvalue_2=id_fldvalue_2), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def runwebcoll(req, colID, ln=cdslang, confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Collection Management", body=wsc.perform_checkwebcollstatus(colID=colID, ln=ln, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def switchpbxscore(req, colID, id_1, id_2, sel_ln,ln=cdslang): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_switchpbxscore(colID=colID, ln=ln, id_1=id_1, id_2=id_2, sel_ln=sel_ln), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifydbquery(req, colID, ln=cdslang, dbquery='', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifydbquery(colID=colID, ln=ln, dbquery=dbquery, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showtree(req, colID, ln=cdslang): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Collection tree", body=wsc.perform_showtree(colID=colID, ln=ln), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifyrestricted(req, colID, ln=cdslang, rest='', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifyrestricted(colID=colID, ln=ln, rest=rest, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifytranslations(req, colID, ln=cdslang, sel_type='', trans = [], confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifytranslations(colID=colID, ln=ln, sel_type=sel_type, trans=trans, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addcollectiontotree(req, colID, ln=cdslang, add_dad='', add_son='', rtype='', mtype='', callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = check_user(uid,'cfgwebsearch') + + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Collection Management", body=wsc.perform_addcollectiontotree(colID=colID, ln=cdslang, add_dad=add_dad, add_son=add_son, rtype=rtype, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addcollection(req, colID, ln=cdslang, colNAME='', dbquery='', rest='', callback="yes", confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = check_user(uid,'cfgwebsearch') + + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Collection Management", body=wsc.perform_addcollection(colID=colID, ln=cdslang, colNAME=colNAME, dbquery=dbquery, rest=rest, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyrankmethods(req, colID, ln=cdslang, func='', rnkID='', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifyrankmethods(colID=colID, ln=ln, func=func, rnkID=rnkID, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def deletecollection(req, colID, ln=cdslang, confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_deletecollection(colID=colID, ln=ln, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def editcollection(req, colID=1, ln=cdslang, mtype=''): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_editcollection(colID=colID, ln=ln, mtype=mtype), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addoutputformat(req, colID, ln=cdslang, code='', name='', callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = check_user(uid,'cfgwebsearch') + + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_addoutputformat(colID=colID, ln=ln, code=code, name=name, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showoutputformats(req, colID, ln=cdslang, callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_showoutputformats(colID=colID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addexistingoutputformat(req, colID, ln=cdslang, fmtID=-1, callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_addexistingoutputformat(colID=colID, ln=ln, fmtID=fmtID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def deleteoutputformat(req, colID, ln=cdslang, fmtID=-1, callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_deleteoutputformat(colID=colID, ln=ln, fmtID=fmtID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def removeoutputformat(req, colID, ln=cdslang, fmtID='', callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_removeoutputformat(colID=colID, ln=ln, fmtID=fmtID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def update_external_collections(req, colID, ln=cdslang, state=None, recurse=None): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body = wsc.perform_update_external_collections(colID, ln, state, recurse), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def removefieldvalue(req, colID, ln=cdslang, fldID='', fldvID='', fmeth='', callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_removefieldvalue(colID=colID, ln=ln, fldID=fldID, fldvID=fldvID, fmeth=fmeth, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def removefield(req, colID, ln=cdslang, fldID='', fldvID='', fmeth='', callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_removefield(colID=colID, ln=ln, fldID=fldID, fldvID=fldvID, fmeth=fmeth, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifyfield(req, colID, fldID, fldvID='', ln=cdslang, callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifyfield(colID=colID, fldID=fldID, fldvID=fldvID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyoutputformat(req, colID, ln=cdslang, fmtID=-1, sel_type='', trans=[], confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifyoutputformat(colID=colID, ln=ln, fmtID=fmtID, sel_type=sel_type, trans=trans, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showsearchoptions(req, colID, ln=cdslang, callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_showsearchoptions(colID=colID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addexistingfield(req, colID, ln=cdslang, fldID=-1, fldvID=-1, fmeth='', callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_addexistingfield(colID=colID, ln=ln, fldID=fldID, fldvID=fldvID, fmeth=fmeth, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page(title='Authorization failure', uid=uid, body=wsc.adderrorbox('try to login first', datalist=["""You are not a user authorized to perform admin tasks, try to login with another account.""" % (sweburl, weburl)]), navtrail= navtrail_previous_links, lastupdated=__lastupdated__) - + def rearrangefield(req, colID, ln=cdslang, fmeth='', callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_rearrangefield(colID=colID, ln=ln, fmeth=fmeth, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page(title='Authorization failure', uid=uid, body=wsc.adderrorbox('try to login first', datalist=["""You are not a user authorized to perform admin tasks, try to login with another account.""" % (sweburl, weburl)]), navtrail= navtrail_previous_links, lastupdated=__lastupdated__) def addexistingfieldvalue(req, colID, fldID, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_addexistingfieldvalue(colID=colID, ln=ln, fldID=fldID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page(title='Authorization failure', uid=uid, body=wsc.adderrorbox('try to login first', datalist=["""You are not a user authorized to perform admin tasks, try to login with another account.""" % (sweburl, weburl)]), navtrail= navtrail_previous_links, lastupdated=__lastupdated__) def rearrangefieldvalue(req, colID, fldID, ln=cdslang, callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_rearrangefieldvalue(colID=colID, ln=ln, fldID=fldID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page(title='Authorization failure', uid=uid, body=wsc.adderrorbox('try to login first', datalist=["""You are not a user authorized to perform admin tasks, try to login with another account.""" % (sweburl, weburl)]), navtrail= navtrail_previous_links, lastupdated=__lastupdated__) def addnewfieldvalue(req, colID, fldID, ln=cdslang, name='', value='', callback="yes", confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = check_user(uid,'cfgwebsearch') + + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_addnewfieldvalue(colID=colID, fldID=fldID, ln=cdslang, name=name, value=value, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def modifyfieldvalue(req, colID, fldID, fldvID, ln=cdslang, name='', value='', callback="yes", confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - - auth = check_user(uid,'cfgwebsearch') + + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifyfieldvalue(colID=colID, - fldID=fldID, + fldID=fldID, fldvID=fldvID, ln=cdslang, name=name, value=value, callback=callback, confirm=confirm), uid=uid, language=ln, navtrail = navtrail_previous_links, req=req, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showsearchfields(req, colID, ln=cdslang, callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_showsearchfields(colID=colID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def showsortoptions(req, colID, ln=cdslang, callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_showsortoptions(colID=colID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifyportalbox(req, colID, ln=cdslang, pbxID=-1, score='', position='', sel_ln='', title='', body='', callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifyportalbox(colID=colID, ln=ln, pbxID=pbxID, score=score, position=position, sel_ln=sel_ln, title=title, body=body, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def removeportalbox(req, colID, ln=cdslang, pbxID='', sel_ln='', callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_removeportalbox(colID=colID, ln=ln, pbxID=pbxID, sel_ln=sel_ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def addexistingportalbox(req, colID, ln=cdslang, pbxID=-1, score=0, position='', sel_ln='', callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_addexistingportalbox(colID=colID, ln=ln, pbxID=pbxID, score=score, position=position, sel_ln=sel_ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page(title='Authorization failure', uid=uid, body=wsc.adderrorbox('try to login first', datalist=["""You are not a user authorized to perform admin tasks, try to login with another account.""" % (sweburl, weburl)]), navtrail= navtrail_previous_links, lastupdated=__lastupdated__) def deleteportalbox(req, colID, ln=cdslang, pbxID=-1, callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_deleteportalbox(colID=colID, ln=ln, pbxID=pbxID, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def showportalboxes(req, colID, ln=cdslang, callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) - + try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_showportalboxes(colID=colID, ln=ln, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def addportalbox(req, colID, ln=cdslang, title='', body='', callback='yes', confirm=-1): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - - auth = check_user(uid,'cfgwebsearch') + + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_addportalbox(colID=colID, ln=ln, title=title, body=body, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) - + def modifycollectiontree(req, colID, ln=cdslang, move_up='', move_down='', move_from='', move_to='', delete='', rtype='', callback='yes', confirm=0): navtrail_previous_links = wsc.getnavtrail() + """> Collection Management """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Collection Management", body=wsc.perform_modifycollectiontree(colID=colID, ln=ln, move_up=move_up, move_down=move_down, move_from=move_from, move_to=move_to, delete=delete, rtype=rtype, callback=callback, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def index(req, colID=1, ln=cdslang, mtype='', content='', confirm=0): navtrail_previous_links = wsc.getnavtrail() try: uid = getUid(req) except Error, e: return error_page(req) - auth = check_user(uid,'cfgwebsearch') + auth = check_user(req,'cfgwebsearch') if not auth[0]: return page(title="Collection Management", body=wsc.perform_index(colID=colID, ln=ln, mtype=mtype, content=content, confirm=confirm), uid=uid, language=ln, req=req, navtrail = navtrail_previous_links, - lastupdated=__lastupdated__) + lastupdated=__lastupdated__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def error_page(req, ln=cdslang, verbose=1): _ = gettext_set_language(ln) - + return page(title=_("Internal Error"), body = create_error_box(req, verbose=verbose, ln=ln), - description="%s - Internal Error" % cdsname, + description="%s - Internal Error" % cdsname, keywords="%s, CDS Invenio, Internal Error" % cdsname, language=ln, req=req) diff --git a/modules/websession/lib/webaccount.py b/modules/websession/lib/webaccount.py index 5a21a1da2..0efe138db 100644 --- a/modules/websession/lib/webaccount.py +++ b/modules/websession/lib/webaccount.py @@ -1,314 +1,316 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" import sys import string import cgi from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \ CFG_CERN_SITE, \ cdslang, \ cdsname, \ supportemail, \ sweburl, \ version, \ weburl from invenio.access_control_config import CFG_EXTERNAL_AUTHENTICATION from invenio.webpage import page from invenio.dbquery import run_sql -from invenio.webuser import getUid,isGuestUser, get_user_preferences, set_user_preferences -from invenio.access_control_admin import acc_findUserRoleActions +from invenio.webuser import getUid,isGuestUser, get_user_preferences, \ + set_user_preferences, collect_user_info +from invenio.access_control_admin import acc_findUserRoleActions_user_info from invenio.messages import gettext_set_language from invenio.external_authentication import WebAccessExternalAuthError import invenio.template websession_templates = invenio.template.load('websession') # perform_info(): display the main features of CDS personalize def perform_info(req, ln): out = "" uid = getUid(req) return websession_templates.tmpl_account_info( ln = ln, uid = uid, guest = isGuestUser(uid), CFG_CERN_SITE = CFG_CERN_SITE, ); def perform_display_external_user_settings(settings, ln): """show external user settings which is a dictionary.""" _ = gettext_set_language(ln) html_settings = "" print_settings = False settings_keys = settings.keys() settings_keys.sort() for key in settings_keys: value = settings[key] if key.startswith("EXTERNAL_") and not "HIDDEN_" in key: print_settings = True key = key[9:].capitalize() html_settings += websession_templates.tmpl_external_setting(ln, key, value) return print_settings and websession_templates.tmpl_external_user_settings(ln, html_settings) or "" -def perform_youradminactivities(uid, ln): +def perform_youradminactivities(user_info, ln): """Return text for the `Your Admin Activities' box. Analyze whether user UID has some admin roles, and if yes, then print suitable links for the actions he can do. If he's not admin, print a simple non-authorized message.""" - your_role_actions = acc_findUserRoleActions(uid) + your_role_actions = acc_findUserRoleActions_user_info(user_info) your_roles = [] your_admin_activities = [] - guest = isGuestUser(uid) + guest = isGuestUser(user_info['uid']) for (role, action) in your_role_actions: if role not in your_roles: your_roles.append(role) if action not in your_admin_activities: your_admin_activities.append(action) if "superadmin" in your_roles: for action in ["runbibedit", "cfgbibformat", "cfgbibharvest", "cfgbibrank", "cfgbibindex", "cfgwebaccess", "cfgwebcomment", "cfgwebsearch", "cfgwebsubmit"]: if action not in your_admin_activities: your_admin_activities.append(action) return websession_templates.tmpl_account_adminactivities( ln = ln, - uid = uid, + uid = user_info['uid'], guest = guest, roles = your_roles, activities = your_admin_activities, weburl = weburl, ) # perform_display_account(): display a dynamic page that shows the user's account def perform_display_account(req,username,bask,aler,sear,msgs,grps,ln): # load the right message language _ = gettext_set_language(ln) uid = getUid(req) + user_info = collect_user_info(req) #your account if isGuestUser(uid): user = "guest" login = "%s/youraccount/login?ln=%s" % (sweburl, ln) accBody = _("You are logged in as guest. You may want to %(x_url_open)slogin%(x_url_close)s as a regular user.") %\ {'x_url_open': '', 'x_url_close': ''} accBody += "

" bask=aler=msgs= _("The %(x_fmt_open)sguest%(x_fmt_close)s users need to %(x_url_open)sregister%(x_url_close)s first") %\ {'x_fmt_open': '', 'x_fmt_close': '', 'x_url_open': '', 'x_url_close': ''} sear= _("No queries found") else: user = username accBody = websession_templates.tmpl_account_body( ln = ln, user = user, ) return websession_templates.tmpl_account_page( ln = ln, weburl = weburl, accBody = accBody, baskets = bask, alerts = aler, searches = sear, messages = msgs, groups = grps, - administrative = perform_youradminactivities(uid, ln) + administrative = perform_youradminactivities(user_info, ln) ) # template_account() : it is a template for print each of the options from the user's account def template_account(title, body, ln): return websession_templates.tmpl_account_template( ln = ln, title = title, body = body ) # warning_guest_user(): It returns an alert message,showing that the user is a guest user and should log into the system def warning_guest_user(type, ln=cdslang): # load the right message language _ = gettext_set_language(ln) return websession_templates.tmpl_warning_guest_user( ln = ln, type = type, ) ## perform_delete():delete the account of the user, not implement yet def perform_delete(ln): return websession_templates.tmpl_account_delete(ln = ln) def perform_set(email,password, ln, verbose=0): - """Perform_set(email,password): edit your account parameters, email and + """Perform_set(email,password): edit your account parameters, email and password. """ try: res = run_sql("SELECT id, nickname FROM user WHERE email=%s", (email,)) uid = res[0][0] nickname = res[0][1] except: uid = 0 nickname = "" CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL = CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS prefs = get_user_preferences(uid) if CFG_EXTERNAL_AUTHENTICATION.has_key(prefs['login_method']) and not CFG_EXTERNAL_AUTHENTICATION[prefs['login_method']][1]: CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL = 3 out = websession_templates.tmpl_user_preferences( ln = ln, email = email, email_disabled = (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL >= 2), password = password, password_disabled = (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL >= 3), nickname = nickname, ) if len(CFG_EXTERNAL_AUTHENTICATION) > 1: try: uid = run_sql("SELECT id FROM user where email=%s", (email,)) uid = uid[0][0] except: uid = 0 current_login_method = prefs['login_method'] methods = CFG_EXTERNAL_AUTHENTICATION.keys() # Filtering out methods that don't provide user_exists to check if # a user exists in the external auth method before letting him/her # to switch. for method in methods: if CFG_EXTERNAL_AUTHENTICATION[method][0]: try: if not CFG_EXTERNAL_AUTHENTICATION[method][0].user_exists(email): methods.remove(method) except (AttributeError, WebAccessExternalAuthError): methods.remove(method) methods.sort() if len(methods) > 1: out += websession_templates.tmpl_user_external_auth( ln = ln, methods = methods, current = current_login_method, method_disabled = (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 4) ) try: current_group_records = prefs['websearch_group_records'] except KeyError: current_group_records = 10 try: show_latestbox = prefs['websearch_latestbox'] except KeyError: show_latestbox = True try: show_helpbox = prefs['websearch_helpbox'] except KeyError: show_helpbox = True out += websession_templates.tmpl_user_websearch_edit( ln = ln, current = current_group_records, show_latestbox = show_latestbox, show_helpbox = show_helpbox, ) if verbose >= 9: for key, value in prefs.items(): out += "%s:%s
" % (key, value) out += perform_display_external_user_settings(prefs, ln) return out ## create_register_page_box(): register a new account def create_register_page_box(referer='', ln=cdslang): return websession_templates.tmpl_register_page( referer = referer, ln = ln, level = CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, supportemail = supportemail, cdsname = cdsname ) ## create_login_page_box(): ask for the user's email and password, for login into the system def create_login_page_box(referer='', ln=cdslang): internal = None for system in CFG_EXTERNAL_AUTHENTICATION.keys(): if not CFG_EXTERNAL_AUTHENTICATION[system][0]: internal = system break register_available = CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS <= 1 and internal methods = CFG_EXTERNAL_AUTHENTICATION.keys() methods.sort() selected = '' for method in methods: if CFG_EXTERNAL_AUTHENTICATION[method][1]: selected = method break return websession_templates.tmpl_login_form( ln = ln, referer = referer, internal = internal, register_available = register_available, methods = methods, selected_method = selected, supportemail = supportemail, ) # perform_logout: display the message of not longer authorized, def perform_logout(req, ln): return websession_templates.tmpl_account_logout(ln = ln) #def perform_lost: ask the user for his email, in order to send him the lost password def perform_lost(ln): return websession_templates.tmpl_lost_password_form( ln = ln, msg = websession_templates.tmpl_lost_password_message(ln = ln, supportemail = supportemail), ) # perform_emailSent(email): confirm that the password has been emailed to 'email' address def perform_emailSent(email, ln): return websession_templates.tmpl_account_emailSent(ln = ln, email = email) # peform_emailMessage : display a error message when the email introduced is not correct, and sugest to try again def perform_emailMessage(eMsg, ln): return websession_templates.tmpl_account_emailMessage( ln = ln, msg = eMsg ) # perform_back(): template for return to a previous page, used for login,register and setting def perform_back(mess,act,linkname='', ln='en'): if not linkname: linkname = act return websession_templates.tmpl_back_form( ln = ln, message = mess, act = act, link = linkname, ) diff --git a/modules/websession/lib/webgroup_dblayer.py b/modules/websession/lib/webgroup_dblayer.py index 67655978d..cf121f464 100644 --- a/modules/websession/lib/webgroup_dblayer.py +++ b/modules/websession/lib/webgroup_dblayer.py @@ -1,435 +1,454 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """ Database related functions for groups""" __revision__ = "$Id$" from time import localtime from zlib import decompress from invenio.config import \ cdslang, \ version from invenio.dbquery import run_sql, escape_string from invenio.dateutils import convert_datestruct_to_datetext from invenio.messages import gettext_set_language from invenio.websession_config import CFG_WEBSESSION_GROUP_JOIN_POLICY def get_groups_by_user_status(uid, user_status, login_method='INTERNAL'): """Select all the groups the user is admin of. @param uid: user id @return ((id_usergroup, group_name, group_description, )) """ query = """SELECT g.id, g.name, g.description FROM usergroup g, user_usergroup ug WHERE ug.id_user=%i AND ug.id_usergroup=g.id AND ug.user_status='%s' AND g.login_method = '%s' ORDER BY g.name""" uid = int(uid) res = run_sql(query % (uid, escape_string(user_status), escape_string(login_method))) return res def get_groups_by_login_method(uid, login_method): """Select all the groups the user is member of selecting the login_method. @param uid: user id @param login_method: the login_method (>0 external) @return ((id_usergroup, group_name, group_description, )) """ query = """SELECT g.id, g.name, g.description FROM usergroup g, user_usergroup ug WHERE ug.id_user=%i AND ug.id_usergroup=g.id AND g.login_method='%s' ORDER BY g.name""" uid = int(uid) res = run_sql(query % (uid, escape_string(login_method))) return res +def get_groups(uid): + """Select all the groups the user is member of. + @param uid: user id + @return ((id_usergroup, + group_name, + group_description, )) + """ + query = """SELECT g.id, + g.name, + g.description + FROM usergroup g, user_usergroup ug + WHERE ug.id_user=%s AND + ug.id_usergroup=g.id + ORDER BY g.name""" + uid = int(uid) + res = run_sql(query, (uid, )) + return res + + def get_external_groups(uid): """Select all the groups the user is member of selecting the login_method. @param uid: user id @param login_method: the login_method (>0 external) @return ((id_usergroup, group_name, group_description, )) """ query = """SELECT g.id, g.name, g.description FROM usergroup g, user_usergroup ug WHERE ug.id_user=%i AND ug.id_usergroup=g.id AND g.login_method != 'INTERNAL' ORDER BY g.name""" uid = int(uid) res = run_sql(query % uid) return res def get_groups(uid): """Select all the groups id the user is member of.""" query = """SELECT g.id, g.name FROM usergroup g, user_usergroup ug WHERE ug.id_user=%s AND ug.id_usergroup=g.id """ res = run_sql(query, (uid, )) res = list(res) return res def get_group_id(group_name, login_method): """@return the id of the group called group_name with given login_method.""" return run_sql(""" SELECT id FROM usergroup WHERE login_method = %s AND name = %s""", (login_method, group_name,)) def get_login_method_groups(uid, login_method): """Select all the external groups of a particular login_method for which the user is subscrided. @return ((group_name, group_id)) """ uid=int(uid) # FIXME return run_sql(""" SELECT g.name as name, g.id as id FROM user_usergroup as u JOIN usergroup as g ON u.id_usergroup = g.id WHERE u.id_user = %i and g.login_method = '%s'""" % (uid, escape_string(login_method,))) def get_all_login_method_groups(login_method): """Select all the external groups of a particular login_method. @return ({group_name: group_id, ...}) """ return dict(run_sql(""" SELECT name, id FROM usergroup WHERE login_method = '%s'""" % (escape_string(login_method),))) def get_all_users_with_groups_with_login_method(login_method): """Select all the users that belong at least to one external group of kind login_method. """ return dict(run_sql(""" SELECT DISTINCT u.email, u.id FROM user AS u JOIN user_usergroup AS uu ON u.id = uu.id_user JOIN usergroup AS ug ON ug.id = uu.id_usergroup WHERE ug.login_method = %s""", (login_method, ))) def get_visible_group_list(uid, pattern=""): """List the group the user can join (not already member of the group regardless user's status). @return groups {id : name} whose name matches pattern """ grpID = [] groups = {} #list the group the user is member of""" query = """SELECT distinct(id_usergroup) FROM user_usergroup WHERE id_user=%i """ uid = int(uid) query %= uid res = run_sql(query) map(lambda x: grpID.append(int(x[0])), res) query2 = """SELECT id,name FROM usergroup WHERE (join_policy='%s' OR join_policy='%s')""" % ( CFG_WEBSESSION_GROUP_JOIN_POLICY['VISIBLEOPEN'], CFG_WEBSESSION_GROUP_JOIN_POLICY['VISIBLEMAIL']) if len(grpID) == 1 : query2 += """ AND id!=%i""" % grpID[0] elif len(grpID) > 1: query2 += """ AND id NOT IN %s""" % str(tuple(grpID)) if pattern: pattern_query = """ AND name RLIKE '%s'""" % escape_string(pattern) query2 += pattern_query query2 += """ ORDER BY name""" res2 = run_sql(query2) map(lambda x: groups.setdefault(x[0], x[1]), res2) return groups def insert_new_group(uid, new_group_name, new_group_description, join_policy, login_method='INTERNAL'): """Create a new group and affiliate a user.""" query1 = """INSERT INTO usergroup VALUES (NULL,%s,%s,%s,%s) """ params1 = (new_group_name, new_group_description, join_policy, login_method) res1 = run_sql(query1, params1) date = convert_datestruct_to_datetext(localtime()) uid = int(uid) query2 = """INSERT INTO user_usergroup VALUES (%i,'%i','A','%s') """ params2 = (uid, res1, date) res2 = run_sql(query2 % params2) return res1 def insert_only_new_group(new_group_name, new_group_description, join_policy, login_method='INTERNAL'): """Create a group with no user in (yet). @return its id """ query = """INSERT INTO usergroup (name, description, join_policy, login_method) VALUES (%s, %s, %s, %s) """ res = run_sql(query, (new_group_name, new_group_description, join_policy, login_method)) return res def insert_new_member(uid, grpID, status): """Insert new member.""" query = """INSERT INTO user_usergroup VALUES (%i,%i,'%s','%s') """ date = convert_datestruct_to_datetext(localtime()) uid = int(uid) grpID = int(grpID) query %= (uid, grpID, escape_string(status), date) res = run_sql(query) return res def get_group_infos(grpID): """Get group infos.""" query = """SELECT * FROM usergroup WHERE id = %i""" grpID = int(grpID) res = run_sql(query % grpID) return res def get_all_groups_description(login_method): """Get all groups description, dictionary with key name.""" query = """SELECT name, description FROM usergroup WHERE login_method = %s """ res = run_sql(query, (login_method, )) if res: return dict(res) else: return {} def update_group_infos(grpID, group_name, group_description, join_policy): """Update group.""" query = """UPDATE usergroup SET name="%s", description="%s", join_policy="%s" WHERE id = %i""" grpID = int(grpID) res = run_sql(query% (escape_string(group_name), escape_string(group_description), escape_string(join_policy), grpID)) return res def get_user_status(uid, grpID): """Get the status of the user for the given group.""" query = """SELECT user_status FROM user_usergroup WHERE id_user = %i AND id_usergroup=%i""" uid = int(uid) grpID = int(grpID) res = run_sql(query% (uid, grpID)) return res def get_users_by_status(grpID, status, ln=cdslang): """Get the list of users with the given status. @return ((id, nickname),) nickname= user # uid if the user has no nickname """ _ = gettext_set_language(ln) query = """SELECT ug.id_user, u.nickname FROM user_usergroup ug, user u WHERE ug.id_usergroup = %i AND ug.id_user=u.id AND user_status = '%s'""" grpID = int(grpID) res = run_sql(query% (grpID, escape_string(status))) users = [] if res: for (mid, nickname) in res: nn = nickname if not nickname: nn = _("user") + "#%i" % mid users.append((mid, nn)) return tuple(users) def delete_member(grpID, member_id): """Delete member.""" query = """DELETE FROM user_usergroup WHERE id_usergroup = %i AND id_user = %i""" grpID = int(grpID) member_id = int(member_id) res = run_sql(query% (grpID, member_id)) return res def delete_group_and_members(grpID): """Delete the group and its members.""" query = """DELETE FROM usergroup WHERE id = %i """ grpID = int(grpID) res = run_sql(query% grpID) query = """DELETE FROM user_usergroup WHERE id_usergroup = %i """ res = run_sql(query% grpID) return res def add_pending_member(grpID, member_id, user_status): """Change user status: Pending member becomes normal member""" query = """UPDATE user_usergroup SET user_status = '%s',user_status_date='%s' WHERE id_usergroup = %i AND id_user = %i""" date = convert_datestruct_to_datetext(localtime()) grpID = int(grpID) member_id = int(member_id) res = run_sql(query% (escape_string(user_status), date, grpID, member_id)) return res def leave_group(grpID, uid): """Remove user from the group member list.""" query = """DELETE FROM user_usergroup WHERE id_usergroup=%i AND id_user=%i""" grpID = int(grpID) uid = int(uid) res = run_sql(query% (grpID, uid)) return res def drop_external_groups(userId): """Drops all the external groups memberships of userid.""" query = """DELETE user_usergroup FROM user_usergroup, usergroup WHERE user_usergroup.id_user=%i AND usergroup.id = user_usergroup.id_usergroup AND usergroup.login_method <> 'INTERNAL'""" return run_sql(query % (userId,)) def group_name_exist(group_name, login_method='INTERNAL'): """Get all group id whose name like group_name and login_method.""" query = """SELECT id FROM usergroup WHERE login_method=%s AND name=%s""" res = run_sql(query, (group_name, login_method,)) return res def get_group_login_method(grpID): """Return the login_method of the group or None if the grpID doesn't exist.""" query = """SELECT login_method FROM usergroup WHERE id=%i""" res = run_sql(query % grpID) if res: return res[0][0] else: return None def count_nb_group_user(uid, user_status): """ @param uid: user id @param status: member status @return integer of number of groups the user belongs to with the given status, 0 if none """ uid = int(uid) query = """SELECT count(id_user) FROM user_usergroup WHERE id_user=%i AND user_status = '%s' """ res = run_sql(query%(uid, escape_string(user_status))) if res: return int(res[0][0]) else: return 0 def get_all_users(): """@return all the email:id""" query = """SELECT UPPER(email), id FROM user WHERE email != '' """ res = run_sql(query) if res: return dict(res) else: return {} def get_users_in_group(grpID): """@return all uids of users belonging to group grpID""" grpID = int(grpID) query = """SELECT id_user FROM user_usergroup WHERE id_usergroup = %i """ res = run_sql(query % grpID) return [uid[0] for uid in res] ########################## helpful functions ################################## def __decompress_last(item): """private function, used to shorten code""" item = list(item) item[-1] = decompress(item[-1]) return item diff --git a/modules/websession/lib/websession.py b/modules/websession/lib/websession.py index 1cf6359ba..4155bc85b 100644 --- a/modules/websession/lib/websession.py +++ b/modules/websession/lib/websession.py @@ -1,181 +1,185 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """ Classes necessary for using in CDS Invenio, as a complement of session, which adds persistence to sessions by using a MySQL table. Consists of the following classes: - SessionNotInDb: Exception to be raised when a session doesn't exit - pSession(Session): Specialisation of the class Session which adds persistence to session - pSessionMapping: Implements only the necessary methods to make it work with the session manager """ __revision__ = "$Id$" import cPickle from UserDict import UserDict from invenio.dbquery import run_sql, blob_to_string, \ OperationalError, IntegrityError from invenio.session import Session class SessionNotInDb(Exception): """Exception to be raised when a requested session doesn't exist in the DB """ pass class pSession(Session): - """Specialisation of the class Session which adds persistence to sessions - by using a database table (it pickles itself into the corresponding row of - the table). The class provides methods to save and retrieve an instance - to/from the DB and to access the main session attributes (uid). The + """Specialisation of the class Session which adds persistence to sessions + by using a database table (it pickles itself into the corresponding row of + the table). The class provides methods to save and retrieve an instance + to/from the DB and to access the main session attributes (uid). The table in the DB must have the following structure: session_key - text - unique uid - int session_object - blob Attributes: - __tableName -- (string) name of the table in the DB where the + __tableName -- (string) name of the table in the DB where the sessions are going to be stored __uid -- (int) user identifier who initiated the session - __dirty -- (bool) flag indicating whether the session has been + __dirty -- (bool) flag indicating whether the session has been modified (and therefore needs to be saved back to the DB) or not """ - - __tableName = "session" + + __tableName = "session" __ExpireTime = 1050043127 - + def __init__( self, request, id, uid=-1 ): Session.__init__( self, request, id ) self.__uid = uid self.__dirty = 0 def is_dirty( self ): return self.__dirty def getUid( self ): return self.__uid def setUid( self, newUid ): if newUid: self.__uid = int(newUid) self.__dirty = 1 else: # something bad happened, e.g. database down, so return user id -1 self.__uid = -1 self.__dirty = 1 def retrieve( cls, sessionId ): """method for retrieving a session from the DB for the given id. If the id has no corresponding session an exception is raised """ sql = "select session_object from %s where session_key='%s'" % \ (cls.__tableName, sessionId) - try: + try: res = run_sql(sql) except OperationalError: raise SessionNotInDb("Session %s doesn't exist" % \ - sessionId) + sessionId) if len(res)==0: raise SessionNotInDb("Session %s doesn't exist" % \ sessionId) - s = cPickle.loads(blob_to_string(res[0][0])) + try: + s = cPickle.loads(blob_to_string(res[0][0])) + except cPickle.UnpicklingError: + raise SessionNotInDb("Session %s is broken" % \ + sessionId) return s retrieve = classmethod( retrieve ) def __getRepr( self ): return cPickle.dumps( self ) def save( self ): - """method that tries to insert the session as NEW in the DB. If this + """method that tries to insert the session as NEW in the DB. If this fails (giving an integrity error) it means the session already - exists there and it must be updated, so it performs the + exists there and it must be updated, so it performs the corresponding SQL update """ - + sessrepr = self.__getRepr().replace("'", "\\\'") sessrepr = sessrepr.replace('"', '\\\"') try: sql = """INSERT INTO %s (session_key, session_expiry, session_object, uid) VALUES ("%s","%s","%s","%s")""" % \ (self.__class__.__tableName, self.id, self.get_access_time()+60*60*24*2, sessrepr, int(self.getUid())) run_sql(sql) except IntegrityError: try: sql = """UPDATE %s SET uid=%s, session_expiry=%s, - session_object="%s" + session_object="%s" WHERE session_key="%s" """ % \ (self.__class__.__tableName, int(self.getUid()), self.get_access_time()+60*60*24*2, sessrepr, self.id) run_sql(sql) except OperationalError: pass self.__dirty = 0 except OperationalError: - self.__dirty = 0 + self.__dirty = 0 class pSessionMapping(UserDict): - """Only the necessary methods to make it work with the session manager + """Only the necessary methods to make it work with the session manager have been implemented. """ - + def __includeItemFromDB(self, key): if key not in self.data.keys(): try: s = pSession.retrieve( key ) self.data[key] = s except SessionNotInDb: pass def __setitem__(self, key, v): - """when a session is added or updated in the dictionary it means it + """when a session is added or updated in the dictionary it means it must be updated within the DB """ v.save() UserDict.__setitem__(self, key, v) def __getitem__(self, key): - """in order not to have to load all the sessions in the dictionary - (normally only a single session is needed on each web request) when - a session is requested the object looks to see if it is in the - dictionary (memory) and if not it tries to retrieve it from the - DB, puts it in the dictionary and returns the requested item. If + """in order not to have to load all the sessions in the dictionary + (normally only a single session is needed on each web request) when + a session is requested the object looks to see if it is in the + dictionary (memory) and if not it tries to retrieve it from the + DB, puts it in the dictionary and returns the requested item. If the session doesn't exist a normal KeyError exception is raised """ self.__includeItemFromDB( key ) return UserDict.__getitem__(self, key) def has_key(self, key): """same as for "__getitem__": it checks whether the session exist in the local dictionary or in the DB. """ self.__includeItemFromDB( key ) return UserDict.has_key( self, key ) diff --git a/modules/websession/lib/websession_webinterface.py b/modules/websession/lib/websession_webinterface.py index 3c4159c34..d745497ca 100644 --- a/modules/websession/lib/websession_webinterface.py +++ b/modules/websession/lib/websession_webinterface.py @@ -1,990 +1,991 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """CDS Invenio ACCOUNT HANDLING""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" from mod_python import apache import smtplib from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \ CFG_ACCESS_CONTROL_LEVEL_SITE, \ CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT, \ cdsname, \ supportemail, \ sweburl, \ weburl from invenio import webuser from invenio.webpage import page from invenio import webaccount from invenio import webbasket from invenio import webalert from invenio.dbquery import run_sql from invenio.webmessage import account_new_mail from invenio.access_control_config import * from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory from invenio.urlutils import redirect_to_url, make_canonical_urlargd from invenio import webgroup from invenio import webgroup_dblayer from invenio.messages import gettext_set_language import invenio.template websession_templates = invenio.template.load('websession') class WebInterfaceYourAccountPages(WebInterfaceDirectory): _exports = ['', 'edit', 'change', 'lost', 'display', 'send_email', 'youradminactivities', 'delete', 'logout', 'login', 'register'] _force_https = True def index(self, req, form): redirect_to_url(req, '%s/youraccount/display' % sweburl) def display(self, req, form): args = wash_urlargd(form, {}) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/display", navmenuid='youraccount') if webuser.isGuestUser(uid): return page(title=_("Your Account"), body=webaccount.perform_info(req, args['ln']), description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='youraccount') username = webuser.get_nickname_or_email(uid) bask = webbasket.account_list_baskets(uid, ln=args['ln']) aler = webalert.account_list_alerts(uid, ln=args['ln']) sear = webalert.account_list_searches(uid, ln=args['ln']) msgs = account_new_mail(uid, ln=args['ln']) grps = webgroup.account_group(uid, ln=args['ln']) return page(title=_("Your Account"), body=webaccount.perform_display_account(req,username,bask,aler,sear,msgs,grps,args['ln']), description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='youraccount') def edit(self, req, form): args = wash_urlargd(form, {"verbose" : (int, 0)}) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/edit", navmenuid='youraccount') if webuser.isGuestUser(uid): return webuser.page_not_authorized(req, "../youraccount/edit", text=_("This functionality is forbidden to guest users."), navmenuid='youraccount') return page(title= _("Your Settings"), body=webaccount.perform_set(webuser.get_email(uid), webuser.get_password(uid), args['ln'], verbose=args['verbose']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Your Settings", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='youraccount') def change(self, req, form): args = wash_urlargd(form, { 'nickname': (str, None), 'email': (str, None), 'old_password': (str, None), 'password': (str, None), 'password2': (str, None), 'login_method': (str, ""), 'group_records' : (int, None), 'latestbox' : (int, None), 'helpbox' : (int, None), }) uid = webuser.getUid(req) current_password = webuser.get_password(uid) if current_password == None: current_password = "" # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/change", navmenuid='youraccount') prefs = webuser.get_user_preferences(uid) if args['login_method'] and CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 4 \ and args['login_method'] in CFG_EXTERNAL_AUTHENTICATION.keys(): title = _("Settings edited") act = "display" linkname = _("Show account") if prefs['login_method'] != args['login_method']: if not CFG_EXTERNAL_AUTHENTICATION[args['login_method']][0]: # Switching to internal authentication: we drop any external datas p_email = webuser.get_email(uid) webuser.drop_external_settings(uid) webgroup_dblayer.drop_external_groups(uid) prefs['login_method'] = args['login_method'] webuser.set_user_preferences(uid, prefs) mess = _("

Switched to internal login method. ") mess += _("""Please note, that if this is the first time that you are using this account with the internal method then the system has set for you a random generated password which you can obtain via email clicking on the following button:

""") mess += """

""" % (p_email, _("Send Password")) else: query = """SELECT email FROM user WHERE id = %i""" res = run_sql(query % uid) if res: email = res[0][0] else: email = None if not email: mess = _("Unable to switch to external login method %s, because your email address is unknown.") % args['login_method'] else: try: if not CFG_EXTERNAL_AUTHENTICATION[args['login_method']][0].user_exists(email): mess = _("Unable to switch to external login method %s, because your email address is unknown to the external login system.") % args['login_method'] else: prefs['login_method'] = args['login_method'] webuser.set_user_preferences(uid, prefs) mess = _("Login method successfully selected.") except AttributeError: mess = _("The external login method %s does not support email address based logins. Please contact the site administrators.") % args['login_method'] elif args['login_method'] and CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 4: return webuser.page_not_authorized(req, "../youraccount/change", navmenuid='youraccount') elif args['email']: # We should ignore the password if the authentication method is an # external one. ignore_password_p = CFG_EXTERNAL_AUTHENTICATION[prefs['login_method']][0] != None uid2 = webuser.emailUnique(args['email']) uid_with_the_same_nickname = webuser.nicknameUnique(args['nickname']) if (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 2 or (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS <= 1 and \ webuser.email_valid_p(args['email']))) \ and (args['nickname'] is None or webuser.nickname_valid_p(args['nickname'])) \ and uid2 != -1 and (uid2 == uid or uid2 == 0) \ and uid_with_the_same_nickname != -1 and (uid_with_the_same_nickname == uid or uid_with_the_same_nickname == 0): if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 3: change = webuser.updateDataUser(uid, args['email'], args['nickname']) else: return webuser.page_not_authorized(req, "../youraccount/change", navmenuid='youraccount') if change: mess = _("Settings successfully edited.") act = "display" linkname = _("Show account") title = _("Settings edited") elif args['nickname'] is not None and not webuser.nickname_valid_p(args['nickname']): mess = _("Desired nickname %s is invalid.") % args['nickname'] mess += " " + _("Please try again.") act = "edit" linkname = _("Edit settings") title = _("Editing settings failed") elif not webuser.email_valid_p(args['email']): mess = _("Supplied email address %s is invalid.") % args['email'] mess += " " + _("Please try again.") act = "edit" linkname = _("Edit settings") title = _("Editing settings failed") elif uid2 == -1 or uid2 != uid and not uid2 == 0: mess = _("Supplied email address %s already exists in the database.") % args['email'] mess += " " + websession_templates.tmpl_lost_your_password_teaser(args['ln']) mess += " " + _("Or please try again.") act = "edit" linkname = _("Edit settings") title = _("Editing settings failed") elif uid_with_the_same_nickname == -1 or uid_with_the_same_nickname != uid and not uid_with_the_same_nickname == 0: mess = _("Desired nickname %s is already in use.") % args['nickname'] mess += " " + _("Please try again.") act = "edit" linkname = _("Edit settings") title = _("Editing settings failed") elif args['old_password'] != None and CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 3: if args['old_password'] == current_password: if args['password'] == args['password2']: webuser.updatePasswordUser(uid, args['password']) mess = _("Password successfully edited.") act = "display" linkname = _("Show account") title = _("Password edited") else: mess = _("Both passwords must match.") mess += " " + _("Please try again.") act = "edit" linkname = _("Edit settings") title = _("Editing password failed") else: mess = _("Wrong old password inserted.") mess += " " + _("Please try again.") act = "edit" linkname = _("Edit settings") title = _("Editing password failed") elif args['group_records']: prefs = webuser.get_user_preferences(uid) prefs['websearch_group_records'] = args['group_records'] prefs['websearch_latestbox'] = args['latestbox'] prefs['websearch_helpbox'] = args['helpbox'] webuser.set_user_preferences(uid, prefs) title = _("Settings edited") act = "display" linkname = _("Show account") mess = _("User settings saved correctly.") else: mess = _("Unable to update settings.") act = "edit" linkname = _("Edit settings") title = _("Editing settings failed") return page(title=title, body=webaccount.perform_back(mess, act, linkname, args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='youraccount') def lost(self, req, form): args = wash_urlargd(form, {}) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/lost", navmenuid='login') return page(title=_("Lost your password?"), body=webaccount.perform_lost(args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') def send_email(self, req, form): # set all the declared query fields as local variables args = wash_urlargd(form, {'p_email': (str, None)}) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/send_email", navmenuid='login') user_prefs = webuser.get_user_preferences(webuser.emailUnique(args['p_email'])) if user_prefs: if CFG_EXTERNAL_AUTHENTICATION.has_key(user_prefs['login_method']) and \ CFG_EXTERNAL_AUTHENTICATION[user_prefs['login_method']][0] is not None: eMsg = _("Cannot send password by email since you are using external authentication system.") return page(title=_("Your Account"), body=webaccount.perform_emailMessage(eMsg, args['ln']), description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') passw = webuser.givePassword(args['p_email']) if passw == -999: eMsg = _("The entered email address does not exist in the database.") return page(title=_("Your Account"), body=webaccount.perform_emailMessage(eMsg, args['ln']), description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') fromaddr = "From: %s" % supportemail toaddr = "To: " + args['p_email'] subject = "Subject: %s %s" % (_("Credentials for"), cdsname) body = websession_templates.tmpl_account_lost_password_email_body(args['p_email'], passw, args['ln']) msg = toaddr + "\n" + subject + "\n\n" + body server = smtplib.SMTP('localhost') server.set_debuglevel(1) try: server.sendmail(fromaddr, toaddr, msg) except smtplib.SMTPRecipientsRefused: eMsg = _("The entered email address is incorrect, please check that it is written correctly (e.g. johndoe@example.com).") return page(title=_("Incorrect email address"), body=webaccount.perform_emailMessage(eMsg, args['ln']), description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') server.quit() return page(title=_("Lost password sent"), body=webaccount.perform_emailSent(args['p_email'], args['ln']), description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') def youradminactivities(self, req, form): args = wash_urlargd(form, {}) uid = webuser.getUid(req) + user_info = webuser.collect_user_info(req) # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/youradminactivities", navmenuid='admin') return page(title=_("Your Administrative Activities"), - body=webaccount.perform_youradminactivities(uid, args['ln']), + body=webaccount.perform_youradminactivities(user_info, args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='admin') def delete(self, req, form): args = wash_urlargd(form, {}) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/delete", navmenuid='login') return page(title=_("Delete Account"), body=webaccount.perform_delete(args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') def logout(self, req, form): args = wash_urlargd(form, {}) uid = webuser.logoutUser(req) # load the right message language _ = gettext_set_language(args['ln']) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../youraccount/logout", navmenuid='login') return page(title=_("Logout"), body=webaccount.perform_logout(req, args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') def login(self, req, form): args = wash_urlargd(form, { 'p_un': (str, None), 'p_pw': (str, None), 'login_method': (str, None), 'action': (str, 'login'), 'referer': (str, '')}) locals().update(args) if CFG_ACCESS_CONTROL_LEVEL_SITE > 0: return webuser.page_not_authorized(req, "../youraccount/login?ln=%s" % args['ln'], navmenuid='login') uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(args['ln']) #return action+_("login") if args['action'] == "login" or args['action'] == _("login") or CFG_EXTERNAL_AUTH_USING_SSO: if not CFG_EXTERNAL_AUTH_USING_SSO: if args['p_un'] is None or not args['login_method']: return page(title=_("Login"), body=webaccount.create_login_page_box(args['referer'], args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') (iden, args['p_un'], args['p_pw'], msgcode) = webuser.loginUser(req, args['p_un'], args['p_pw'], args['login_method']) else: # Fake parameters for p_un & p_pw because SSO takes them from the environment (iden, args['p_un'], args['p_pw'], msgcode) = webuser.loginUser(req, '', '', 'SSO') if len(iden)>0: uid = webuser.update_Uid(req, args['p_un']) uid2 = webuser.getUid(req) if uid2 == -1: webuser.logoutUser(req) return webuser.page_not_authorized(req, "../youraccount/login?ln=%s" % args['ln'], uid=uid, navmenuid='login') # login successful! if args['referer']: req.err_headers_out.add("Location", args['referer']) raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY else: return self.display(req, form) else: mess = CFG_WEBACCESS_WARNING_MSGS[msgcode] % args['login_method'] if msgcode == 14: if webuser.username_exists_p(args['p_un']): mess = CFG_WEBACCESS_WARNING_MSGS[15] % args['login_method'] act = "login" return page(title=_("Login"), body=webaccount.perform_back(mess, act, _("login"), args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') else: return "This should have never happened. Please contact %s." % supportemail def register(self, req, form): args = wash_urlargd(form, { 'p_nickname': (str, None), 'p_email': (str, None), 'p_pw': (str, None), 'p_pw2': (str, None), 'action': (str, "login"), 'referer': (str, "")}) if CFG_ACCESS_CONTROL_LEVEL_SITE > 0: return webuser.page_not_authorized(req, "../youraccount/register?ln=%s" % args['ln'], navmenuid='login') uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(args['ln']) if args['p_nickname'] is None or args['p_email'] is None: return page(title=_("Register"), body=webaccount.create_register_page_box(args['referer'], args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') mess = "" act = "" if args['p_pw'] == args['p_pw2']: ruid = webuser.registerUser(req, args['p_email'], args['p_pw'], args['p_nickname']) else: ruid = -2 if ruid == 0: uid = webuser.update_Uid(req, args['p_email']) mess = _("Your account has been successfully created.") title = _("Account created") if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1: mess += _("An email has been sent to the given address with the account information.") if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1: mess += _("A second email will be sent when the account has been activated and can be used.") else: mess += " " + _("You can now access your %(x_url_open)saccount%(x_url_close)s.") %\ {'x_url_open': '', 'x_url_close': ''} elif ruid == -2: mess = _("Both passwords must match.") mess += " " + _("Please try again.") act = "register" title = _("Registration failure") elif ruid == 1: mess = _("Supplied email address %s is invalid.") % args['p_email'] mess += " " + _("Please try again.") act = "register" title = _("Registration failure") elif ruid == 2: mess = _("Desired nickname %s is invalid.") % args['p_nickname'] mess += " " + _("Please try again.") act = "register" title = _("Registration failure") elif ruid == 3: mess = _("Supplied email address %s already exists in the database.") % args['p_email'] mess += " " + websession_templates.tmpl_lost_your_password_teaser(args['ln']) mess += " " + _("Or please try again.") act = "register" title = _("Registration failure") elif ruid == 4: mess = _("Desired nickname %s already exists in the database.") % args['p_nickname'] mess += " " + _("Please try again.") act = "register" title = _("Registration failure") elif ruid == 5: mess = _("Users cannot register themselves, only admin can register them.") act = "register" title = _("Registration failure") else: # this should never happen mess = _("Internal Error") act = "register" title = _("Registration failure") return page(title=title, body=webaccount.perform_back(mess,act, (act == 'register' and _("register") or ""), args['ln']), navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""", description="CDS Personalize, Main page", keywords="CDS, personalize", uid=uid, req=req, secure_page_p = 1, language=args['ln'], lastupdated=__lastupdated__, navmenuid='login') class WebInterfaceYourGroupsPages(WebInterfaceDirectory): _exports = ['', 'display', 'create', 'join', 'leave', 'edit', 'members'] def index(self, req, form): redirect_to_url(req, '/yourgroups/display') def display(self, req, form): """ Displays groups the user is admin of and the groups the user is member of(but not admin) @param ln: language @return the page for all the groups """ argd = wash_urlargd(form, {}) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(argd['ln']) if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../yourgroups/display", navmenuid='yourgroups') (body, errors, warnings) = webgroup.perform_request_groups_display(uid=uid, ln=argd['ln']) return page(title = _("Your Groups"), body = body, navtrail = webgroup.get_navtrail(argd['ln']), uid = uid, req = req, language = argd['ln'], lastupdated = __lastupdated__, errors = errors, warnings = warnings, navmenuid = 'yourgroups') def create(self, req, form): """create(): interface for creating a new group @param group_name : name of the new webgroup.Must be filled @param group_description : description of the new webgroup.(optionnal) @param join_policy : join policy of the new webgroup.Must be chosen @param *button: which button was pressed @param ln: language @return the compose page Create group """ argd = wash_urlargd(form, {'group_name': (str, ""), 'group_description': (str, ""), 'join_policy': (str, ""), 'create_button':(str, ""), 'cancel':(str, "") }) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(argd['ln']) if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../yourgroups/create", navmenuid='yourgroups') if argd['cancel']: url = weburl + '/yourgroups/display?ln=%s' url %= argd['ln'] redirect_to_url(req, url) if argd['create_button'] : (body, errors, warnings)= webgroup.perform_request_create_group(uid=uid, group_name=argd['group_name'], group_description=argd['group_description'], join_policy=argd['join_policy'], ln = argd['ln']) else: (body, errors, warnings) = webgroup.perform_request_input_create_group(group_name=argd['group_name'], group_description=argd['group_description'], join_policy=argd['join_policy'], ln=argd['ln']) title = _("Create new group") return page(title = title, body = body, navtrail = webgroup.get_navtrail(argd['ln'], title), uid = uid, req = req, language = argd['ln'], lastupdated = __lastupdated__, errors = errors, warnings = warnings, navmenuid = 'yourgroups') def join(self, req, form): """join(): interface for joining a new group @param grpID : list of the group the user wants to become a member. The user must select only one group. @param group_name : will search for groups matching group_name @param *button: which button was pressed @param ln: language @return the compose page Join group """ argd = wash_urlargd(form, {'grpID':(list, []), 'group_name':(str, ""), 'find_button':(str, ""), 'join_button':(str, ""), 'cancel':(str, "") }) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(argd['ln']) if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../yourgroups/join", navmenuid='yourgroups') if argd['cancel']: url = weburl + '/yourgroups/display?ln=%s' url %= argd['ln'] redirect_to_url(req, url) if argd['join_button']: search = 0 if argd['group_name']: search = 1 (body, errors, warnings) = webgroup.perform_request_join_group(uid, argd['grpID'], argd['group_name'], search, argd['ln']) else: search = 0 if argd['find_button']: search = 1 (body, errors, warnings) = webgroup.perform_request_input_join_group(uid, argd['group_name'], search, ln=argd['ln']) title = _("Join New Group") return page(title = title, body = body, navtrail = webgroup.get_navtrail(argd['ln'], title), uid = uid, req = req, language = argd['ln'], lastupdated = __lastupdated__, errors = errors, warnings = warnings, navmenuid = 'yourgroups') def leave(self, req, form): """leave(): interface for leaving a group @param grpID : group the user wants to leave. @param group_name : name of the group the user wants to leave @param *button: which button was pressed @param confirmed : the user is first asked to confirm @param ln: language @return the compose page Leave group """ argd = wash_urlargd(form, {'grpID':(str, ""), 'group_name':(str, ""), 'leave_button':(str, ""), 'cancel':(str, ""), 'confirmed': (int, 0) }) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(argd['ln']) if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../yourgroups/leave", navmenuid='yourgroups') if argd['cancel']: url = weburl + '/yourgroups/display?ln=%s' url %= argd['ln'] redirect_to_url(req, url) if argd['leave_button']: (body, errors, warnings) = webgroup.perform_request_leave_group(uid, argd['grpID'], argd['confirmed'], argd['ln']) else: (body, errors, warnings) = webgroup.perform_request_input_leave_group(uid=uid, ln=argd['ln']) title = _("Leave Group") return page(title = title, body = body, navtrail = webgroup.get_navtrail(argd['ln'], title), uid = uid, req = req, language = argd['ln'], lastupdated = __lastupdated__, errors = errors, warnings = warnings, navmenuid = 'yourgroups') def edit(self, req, form): """edit(): interface for editing group @param grpID : group ID @param group_name : name of the new webgroup.Must be filled @param group_description : description of the new webgroup.(optionnal) @param join_policy : join policy of the new webgroup.Must be chosen @param update: button update group pressed @param delete: button delete group pressed @param cancel: button cancel pressed @param confirmed : the user is first asked to confirm before deleting @param ln: language @return the main page displaying all the groups """ argd = wash_urlargd(form, {'grpID': (str, ""), 'update': (str, ""), 'cancel': (str, ""), 'delete': (str, ""), 'group_name': (str, ""), 'group_description': (str, ""), 'join_policy': (str, ""), 'confirmed': (int, 0) }) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(argd['ln']) if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../yourgroups/display", navmenuid='yourgroups') if argd['cancel']: url = weburl + '/yourgroups/display?ln=%s' url %= argd['ln'] redirect_to_url(req, url) elif argd['delete']: (body, errors, warnings) = webgroup.perform_request_delete_group(uid=uid, grpID=argd['grpID'], confirmed=argd['confirmed']) elif argd['update']: (body, errors, warnings) = webgroup.perform_request_update_group(uid= uid, grpID=argd['grpID'], group_name=argd['group_name'], group_description=argd['group_description'], join_policy=argd['join_policy'], ln=argd['ln']) else : (body, errors, warnings)= webgroup.perform_request_edit_group(uid=uid, grpID=argd['grpID'], ln=argd['ln']) title = _("Edit Group") return page(title = title, body = body, navtrail = webgroup.get_navtrail(argd['ln'], title), uid = uid, req = req, language = argd['ln'], lastupdated = __lastupdated__, errors = errors, warnings = warnings, navmenuid = 'yourgroups') def members(self, req, form): """member(): interface for managing members of a group @param grpID : group ID @param add_member: button add_member pressed @param remove_member: button remove_member pressed @param reject_member: button reject__member pressed @param delete: button delete group pressed @param member_id : ID of the existing member selected @param pending_member_id : ID of the pending member selected @param cancel: button cancel pressed @param info : info about last user action @param ln: language @return the same page with data updated """ argd = wash_urlargd(form, {'grpID': (int, 0), 'cancel': (str, ""), 'add_member': (str, ""), 'remove_member': (str, ""), 'reject_member': (str, ""), 'member_id': (int, 0), 'pending_member_id': (int, 0) }) uid = webuser.getUid(req) # load the right message language _ = gettext_set_language(argd['ln']) if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return webuser.page_not_authorized(req, "../yourgroups/display", navmenuid='yourgroups') if argd['cancel']: url = weburl + '/yourgroups/display?ln=%s' url %= argd['ln'] redirect_to_url(req, url) if argd['remove_member']: (body, errors, warnings) = webgroup.perform_request_remove_member(uid=uid, grpID=argd['grpID'], member_id=argd['member_id'], ln=argd['ln']) elif argd['reject_member']: (body, errors, warnings) = webgroup.perform_request_reject_member(uid=uid, grpID=argd['grpID'], user_id=argd['pending_member_id'], ln=argd['ln']) elif argd['add_member']: (body, errors, warnings) = webgroup.perform_request_add_member(uid=uid, grpID=argd['grpID'], user_id=argd['pending_member_id'], ln=argd['ln']) else: (body, errors, warnings)= webgroup.perform_request_manage_member(uid=uid, grpID=argd['grpID'], ln=argd['ln']) title = _("Edit group members") return page(title = title, body = body, navtrail = webgroup.get_navtrail(argd['ln'], title), uid = uid, req = req, language = argd['ln'], lastupdated = __lastupdated__, errors = errors, warnings = warnings, navmenuid = 'yourgroups') diff --git a/modules/websession/lib/webuser.py b/modules/websession/lib/webuser.py index d2484646f..bfea2a047 100644 --- a/modules/websession/lib/webuser.py +++ b/modules/websession/lib/webuser.py @@ -1,845 +1,831 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """ This file implements all methods necessary for working with users and sessions in CDS Invenio. Contains methods for logging/registration when a user log/register into the system, checking if it is a guest user or not. At the same time this presents all the stuff it could need with sessions managements, working with websession. It also contains Apache-related user authentication stuff. """ __revision__ = "$Id$" -from marshal import loads, dumps +import marshal from zlib import compress, decompress +from socket import gethostbyname import time import os import crypt import string import smtplib import sre from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \ CFG_ACCESS_CONTROL_LEVEL_GUESTS, \ CFG_ACCESS_CONTROL_LEVEL_SITE, \ CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN, \ CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS, \ CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT, \ CFG_APACHE_GROUP_FILE, \ CFG_APACHE_PASSWORD_FILE, \ adminemail, \ cdslang, \ cdsname, \ supportemail, \ sweburl, \ tmpdir, \ version, \ weburl from invenio import session, websession from invenio.dbquery import run_sql, escape_string, OperationalError from invenio.websession import pSession, pSessionMapping from invenio.session import SessionError from invenio.access_control_config import * -from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import acc_findUserRoleActions from invenio.messages import gettext_set_language from invenio.webinterface_handler import http_get_credentials +from invenio.webgroup_dblayer import get_groups from invenio.external_authentication import WebAccessExternalAuthError import invenio.template tmpl = invenio.template.load('websession') sre_invalid_nickname = sre.compile(""".*[,'@]+.*""") # pylint: disable-msg=C0301 def createGuestUser(): """Create a guest user , insert into user null values in all fields createGuestUser() -> GuestUserID """ if CFG_ACCESS_CONTROL_LEVEL_GUESTS == 0: try: return run_sql("insert into user (email, note) values ('', '1')") except OperationalError: return None elif CFG_ACCESS_CONTROL_LEVEL_GUESTS >= 1: try: return run_sql("insert into user (email, note) values ('', '0')") except OperationalError: return None def page_not_authorized(req, referer='', uid='', text='', navtrail='', ln=cdslang, navmenuid=""): """Show error message when account is not activated""" from invenio.webpage import page _ = gettext_set_language(ln) if not CFG_ACCESS_CONTROL_LEVEL_SITE: title = CFG_WEBACCESS_MSGS[5] if not uid: uid = getUid(req) try: res = run_sql("SELECT email FROM user WHERE id=%s" % uid) if res and res[0][0]: if text: body = text else: body = "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[9] % res[0][0], ("%s %s" % (CFG_WEBACCESS_MSGS[0] % referer, CFG_WEBACCESS_MSGS[1]))) else: if text: body = text else: if CFG_ACCESS_CONTROL_LEVEL_GUESTS == 1: body = CFG_WEBACCESS_MSGS[3] else: body = CFG_WEBACCESS_WARNING_MSGS[4] + CFG_WEBACCESS_MSGS[2] except OperationalError, e: body = _("Database problem") + ': ' + str(e) elif CFG_ACCESS_CONTROL_LEVEL_SITE == 1: title = CFG_WEBACCESS_MSGS[8] body = "%s %s" % (CFG_WEBACCESS_MSGS[7], CFG_WEBACCESS_MSGS[2]) elif CFG_ACCESS_CONTROL_LEVEL_SITE == 2: title = CFG_WEBACCESS_MSGS[6] body = "%s %s" % (CFG_WEBACCESS_MSGS[4], CFG_WEBACCESS_MSGS[2]) return page(title=title, uid=getUid(req), body=body, navtrail=navtrail, req=req, navmenuid=navmenuid) def getUid (req): """Return user ID taking it from the cookie of the request. Includes control mechanism for the guest users, inserting in the database table when need be, raising the cookie back to the client. User ID is set to 0 when client refuses cookie or we are in the read-only site operation mode. User ID is set to -1 when we are in the permission denied site operation mode. getUid(req) -> userId """ if CFG_ACCESS_CONTROL_LEVEL_SITE == 1: return 0 if CFG_ACCESS_CONTROL_LEVEL_SITE == 2: return -1 guest = 0 sm = session.MPSessionManager(pSession, pSessionMapping()) try: s = sm.get_session(req) except SessionError: sm.revoke_session_cookie (req) s = sm.get_session(req) userId = s.getUid() if userId == -1: # first time, so create a guest user s.setUid(createGuestUser()) userId = s.getUid() guest = 1 sm.maintain_session(req, s) if guest == 0: guest = isGuestUser(userId) if guest: if CFG_ACCESS_CONTROL_LEVEL_GUESTS == 0: return userId elif CFG_ACCESS_CONTROL_LEVEL_GUESTS >= 1: return -1 else: res = run_sql("SELECT note FROM user WHERE id=%s" % userId) if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 0: return userId elif CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1 and res and res[0][0] in [1, "1"]: return userId else: return -1 def setUid(req, uid): """It sets the userId into the session, and raise the cookie to the client. """ sm = session.MPSessionManager(pSession, pSessionMapping()) try: s = sm.get_session(req) except SessionError: sm.revoke_session_cookie(req) s = sm.get_session(req) s.setUid(uid) sm.maintain_session(req, s) return uid def get_user_info(uid, ln=cdslang): """Get infos for a given user. @param uid: user id (int) @return tuple: (uid, nickname, display_name) """ _ = gettext_set_language(ln) query = """SELECT id, nickname FROM user WHERE id=%i""" res = run_sql(query%uid) if res: if res[0]: user = list(res[0]) if user[1]: user.append(user[1]) else: user[1] = str(user[0]) user.append(_("user") + ' #' + str(user[0])) return tuple(user) return (uid, '', _("N/A")) def isGuestUser(uid): """It Checks if the userId corresponds to a guestUser or not isGuestUser(uid) -> boolean """ out = 1 try: res = run_sql("select email from user where id=%s", (uid,)) if res: if res[0][0]: out = 0 except OperationalError: pass return out -def isUserSubmitter(uid): - u_email = get_email(uid) - res = run_sql("select * from sbmSUBMISSIONS where email=%s", (u_email,)) - if len(res) > 0: - return 1 - else: - return 0 - -def isUserReferee(uid): - res = run_sql("select sdocname from sbmDOCTYPE") - for row in res: - doctype = row[0] - categ = "*" - (auth_code, auth_message) = acc_authorize_action(uid, "referee", doctype=doctype, categ=categ) - if auth_code == 0: - return 1 - res2 = run_sql("select sname from sbmCATEGORIES where doctype=%s", (doctype,)) - for row2 in res2: - categ = row2[0] - (auth_code, auth_message) = acc_authorize_action(uid, "referee", doctype=doctype, categ=categ) - if auth_code == 0: - return 1 - return 0 - -def isUserAdmin(uid): - "Return 1 if the user UID has some admin rights; 0 otherwise." - out = 0 - if acc_findUserRoleActions(uid): - out = 1 - return out +#def isUserSubmitter(uid): + #u_email = get_email(uid) + #res = run_sql("select * from sbmSUBMISSIONS where email=%s", (u_email,)) + #if len(res) > 0: + #return 1 + #else: + #return 0 + +#def isUserReferee(req): + #res = run_sql("select sdocname from sbmDOCTYPE") + #for row in res: + #doctype = row[0] + #categ = "*" + #(auth_code, auth_message) = ace.acc_authorize_action_req(req, "referee", doctype=doctype, categ=categ) + #if auth_code == 0: + #return 1 + #res2 = run_sql("select sname from sbmCATEGORIES where doctype=%s", (doctype,)) + #for row2 in res2: + #categ = row2[0] + #(auth_code, auth_message) = ace.acc_authorize_action_req(req, "referee", doctype=doctype, categ=categ) + #if auth_code == 0: + #return 1 + #return 0 + +#def isUserAdmin(req): + #"Return 1 if the user UID has some admin rights; 0 otherwise." + #out = 0 + #if acc_findUserRoleActions_req(req): + #out = 1 + #return out def nickname_valid_p(nickname): """Check whether wanted NICKNAME supplied by the user is valid. At the moment we just check whether it is not empty, does not contain blanks or @, is not equal to `guest', etc. This check relies on sre_invalid_nickname regexp (see above) Return 1 if nickname is okay, return 0 if it is not. """ if nickname and \ not(nickname.startswith(' ') or nickname.endswith(' ')) and \ nickname.lower() != 'guest': if not sre_invalid_nickname.match(nickname): return 1 return 0 def email_valid_p(email): """Check whether wanted EMAIL address supplied by the user is valid. At the moment we just check whether it contains '@' and whether it doesn't contain blanks. We also check the email domain if CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN is set. Return 1 if email is okay, return 0 if it is not. """ if (string.find(email, "@") <= 0) or (string.find(email, " ") > 0): return 0 elif CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN: if not email.endswith(CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN): return 0 return 1 def registerUser(req, email, passw, nickname, register_without_nickname=False): """Register user with the desired values of NICKNAME, EMAIL and PASSW. If REGISTER_WITHOUT_NICKNAME is set to True, then ignore desired NICKNAME and do not set any. This is suitable for external authentications so that people can login without having to register an internal account first. Return 0 if the registration is successful, 1 if email is not valid, 2 if nickname is not valid, 3 if email is already in the database, 4 if nickname is already in the database, 5 when users cannot register themselves because of the site policy. """ # is email valid? if not email_valid_p(email): return 1 # is email already taken? res = run_sql("SELECT * FROM user WHERE email=%s", (email,)) if len(res) > 0: return 3 if register_without_nickname: # ignore desired nick and use default empty string one: nickname = "" else: # is nickname valid? if not nickname_valid_p(nickname): return 2 # is nickname already taken? res = run_sql("SELECT * FROM user WHERE nickname=%s", (nickname,)) if len(res) > 0: return 4 # okay, go on and register the user: if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 0: activated = 1 elif CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 1: activated = 0 elif CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 2: return 5 user_preference = get_default_user_preferences() setUid(req, run_sql("INSERT INTO user (nickname, email, password, note, settings) VALUES (%s,%s,%s,%s,%s)", (nickname, email, passw, activated, serialize_via_marshal(user_preference),))) if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT: sendNewUserAccountWarning(email, email, passw) if CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS: sendNewAdminAccountWarning(email, adminemail) return 0 def updateDataUser(uid, email, nickname): """ Update user data. Used when a user changed his email or password or nickname. """ if email == 'guest': return 0 if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 2: run_sql("update user set email=%s where id=%s", (email, uid)) if nickname and nickname != '': run_sql("update user set nickname=%s where id=%s", (nickname, uid)) return 1 def updatePasswordUser(uid, password): """Update the password of a user.""" if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 3: run_sql("update user set password=%s where id=%s", (password, uid)) return 1 def loginUser(req, p_un, p_pw, login_method): """It is a first simple version for the authentication of user. It returns the id of the user, for checking afterwards if the login is correct """ # p_un passed may be an email or a nickname: p_email = get_email_from_username(p_un) # go on with the old stuff based on p_email: if not CFG_EXTERNAL_AUTHENTICATION.has_key(login_method): return ([], p_email, p_pw, 12) if CFG_EXTERNAL_AUTHENTICATION[login_method][0]: # External Authenthication try: p_email = CFG_EXTERNAL_AUTHENTICATION[login_method][0].auth_user(p_email, p_pw, req) except WebAccessExternalAuthError: return([], p_email, p_pw, 16) if p_email: # Authenthicated externally query_result = run_sql("SELECT id from user where email=%s", (p_email,)) if not query_result: # First time user import random p_pw_local = int(random.random() * 1000000) p_nickname = '' if CFG_EXTERNAL_AUTHENTICATION[login_method][0].enforce_external_nicknames: try: # Let's discover the external nickname! p_nickname = CFG_EXTERNAL_AUTHENTICATION[login_method][0].fetch_user_nickname(p_email, p_pw, req) except (AttributeError, NotImplementedError): pass res = registerUser(req, p_email, p_pw_local, p_nickname, \ register_without_nickname=p_nickname == '') if res == 4 or res == 2: # The nickname was already taken res = registerUser(req, p_email, p_pw_local, '', register_without_nickname=True) if res == 0: # Everything was ok, with or without nickname. query_result = run_sql("SELECT id from user where email=%s", (p_email,)) else: return([], p_email, p_pw_local, 13) try: groups = CFG_EXTERNAL_AUTHENTICATION[login_method][0].fetch_user_groups_membership(p_email, p_pw, req) # groups is a dictionary {group_name : group_description,} new_groups = {} for key, value in groups.items(): new_groups[key + " [" + str(login_method) + "]"] = value groups = new_groups except (AttributeError, NotImplementedError): pass except WebAccessExternalAuthError: return([], p_email, p_pw, 16) else: # Groups synchronization if groups != 0: userid = query_result[0][0] from invenio.webgroup import synchronize_external_groups synchronize_external_groups(userid, groups, login_method) user_prefs = get_user_preferences(query_result[0][0]) if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 4: # Let's prevent the user to switch login_method if user_prefs.has_key("login_method") and \ user_prefs["login_method"] != login_method: return([], p_email, p_pw, 11) user_prefs["login_method"] = login_method # Cleaning external settings for key in user_prefs.keys(): if key.startswith('EXTERNAL_'): del user_prefs[key] try: # Importing external settings new_prefs = CFG_EXTERNAL_AUTHENTICATION[login_method][0].fetch_user_preferences(p_email, p_pw, req) for key, value in new_prefs.items(): user_prefs['EXTERNAL_' + key] = value except (AttributeError, NotImplementedError): pass except WebAccessExternalAuthError: return([], p_email, p_pw, 16) # Storing settings set_user_preferences(query_result[0][0], user_prefs) else: return ([], p_un, p_pw, 10) else: # Internal Authenthication query_result = run_sql("SELECT id,email from user where email=%s and password=%s", (p_email, p_pw,)) if query_result: #FIXME drop external groups and settings preferred_login_method = get_user_preferences(query_result[0][0])['login_method'] p_email = query_result[0][1] if login_method != preferred_login_method: if CFG_EXTERNAL_AUTHENTICATION.has_key(preferred_login_method): return ([], p_email, p_pw, 11) else: return ([], p_email, p_pw, 14) # Login successful! Updating the last access time run_sql("UPDATE user SET last_login=NOW() WHERE email=%s", (p_email, )) return (query_result, p_email, p_pw, 0) def drop_external_settings(userId): """Drop the external (EXTERNAL_) settings of userid.""" prefs = get_user_preferences(userId) for key in prefs.keys(): if key.startswith('EXTERNAL_'): del prefs[key] set_user_preferences(userId, prefs) def logoutUser(req): """It logout the user of the system, creating a guest user. """ getUid(req) sm = session.MPSessionManager(pSession, pSessionMapping()) try: s = sm.get_session(req) except SessionError: sm.revoke_session_cookie(req) s = sm.get_session(req) id1 = createGuestUser() s.setUid(id1) sm.maintain_session(req, s) return id1 def username_exists_p(username): """Check if USERNAME exists in the system. Username may be either nickname or email. Return 1 if it does exist, 0 if it does not. """ if username == "": # return not exists if asked for guest users return 0 res = run_sql("SELECT email FROM user WHERE email=%s", (username,)) + \ run_sql("SELECT email FROM user WHERE nickname=%s", (username,)) if len(res) > 0: return 1 return 0 def emailUnique(p_email): """Check if the email address only exists once. If yes, return userid, if not, -1 """ query_result = run_sql("select id, email from user where email=%s", (p_email,)) if len(query_result) == 1: return query_result[0][0] elif len(query_result) == 0: return 0 return -1 def nicknameUnique(p_nickname): """Check if the nickname only exists once. If yes, return userid, if not, -1 """ query_result = run_sql("select id, nickname from user where nickname=%s", (p_nickname,)) if len(query_result) == 1: return query_result[0][0] elif len(query_result) == 0: return 0 return -1 def update_Uid(req, p_email): """It updates the userId of the session. It is used when a guest user is logged in succesfully in the system with a given email and password """ query_ID = int(run_sql("select id from user where email=%s", (p_email,))[0][0]) setUid(req, query_ID) return query_ID def givePassword(email): """ It checks in the database the password for a given email. It is used to send the password to the email of the user.It returns the password if the user exists, otherwise it returns -999 """ query_pass = run_sql("select password from user where email =%s", (email,)) if len(query_pass)>0: return query_pass[0][0] return -999 def sendNewAdminAccountWarning(newAccountEmail, sendTo, ln=cdslang): """Send an email to the address given by sendTo about the new account newAccountEmail.""" _ = gettext_set_language(ln) fromaddr = "From: %s" % supportemail toaddrs = "To: %s" % sendTo to = toaddrs + "\n" sub = "Subject: New account on '%s'" % cdsname if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 1: sub += " - PLEASE ACTIVATE" sub += "\n\n" body = "A new account has been created on '%s'" % cdsname if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 1: body += " and is awaiting activation" body += ":\n\n" body += " Username/Email: %s\n\n" % newAccountEmail body += "You can approve or reject this account request at: %s/admin/webaccess/webaccessadmin.py/manageaccounts\n" % weburl body += "\n---------------------------------" body += "\n%s" % cdsname body += "\nContact: %s" % supportemail msg = to + sub + body server = smtplib.SMTP('localhost') server.set_debuglevel(1) try: server.sendmail(fromaddr, toaddrs, msg) except smtplib.SMTPRecipientsRefused: return 0 server.quit() return 1 def sendNewUserAccountWarning(newAccountEmail, sendTo, password, ln=cdslang): """Send an email to the address given by sendTo about the new account newAccountEmail.""" _ = gettext_set_language(ln) fromaddr = "From: %s" % supportemail toaddrs = "To: %s" % sendTo to = toaddrs + "\n" sub = "Subject: Your account created on '%s'\n\n" % cdsname body = "You have created a new account on '%s':\n\n" % cdsname body += " Username/Email: %s\n" % newAccountEmail body += " Password: %s\n\n" % ("*" * len(password)) if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1: body += "This account is awaiting approval by the site administrators and therefore cannot be used as of yet.\nYou will receive an email notification as soon as your account request has been processed.\n" body += "\n---------------------------------" body += "\n%s" % cdsname body += "\nContact: %s" % supportemail msg = to + sub + body server = smtplib.SMTP('localhost') server.set_debuglevel(1) try: server.sendmail(fromaddr, toaddrs, msg) except smtplib.SMTPRecipientsRefused: return 0 server.quit() return 1 def get_email(uid): """Return email address of the user uid. Return string 'guest' in case the user is not found.""" out = "guest" res = run_sql("SELECT email FROM user WHERE id=%s", (uid,), 1) if res and res[0][0]: out = res[0][0] return out def get_email_from_username(username): """Return email address of the user corresponding to USERNAME. The username may be either nickname or email. Return USERNAME untouched if not found in the database or if found several matching entries. """ out = username res = run_sql("SELECT email FROM user WHERE email=%s", (username,), 1) + \ run_sql("SELECT email FROM user WHERE nickname=%s", (username,), 1) if res and len(res) == 1: out = res[0][0] return out def get_password(uid): """Return password of the user uid. Return None in case the user is not found.""" out = None res = run_sql("SELECT password FROM user WHERE id=%s", (uid,), 1) if res and res[0][0] != None: out = res[0][0] return out def get_nickname(uid): """Return nickname of the user uid. Return None in case the user is not found.""" out = None res = run_sql("SELECT nickname FROM user WHERE id=%s", (uid,), 1) if res and res[0][0]: out = res[0][0] return out def get_nickname_or_email(uid): """Return nickname (preferred) or the email address of the user uid. Return string 'guest' in case the user is not found.""" out = "guest" res = run_sql("SELECT nickname, email FROM user WHERE id=%s", (uid,), 1) if res and res[0]: if res[0][0]: out = res[0][0] elif res[0][1]: out = res[0][1] return out def create_userinfobox_body(req, uid, language="en"): """Create user info box body for user UID in language LANGUAGE.""" if req: if req.subprocess_env.has_key('HTTPS') \ and req.subprocess_env['HTTPS'] == 'on': url_referer = sweburl + req.unparsed_uri else: url_referer = weburl + req.unparsed_uri else: url_referer = weburl try: return tmpl.tmpl_create_userinfobox(ln=language, url_referer=url_referer, guest = isGuestUser(uid), username = get_nickname_or_email(uid), - submitter = isUserSubmitter(uid), - referee = isUserReferee(uid), - admin = isUserAdmin(uid), + submitter = True, # FIXME isUserSubmitter(uid), + referee = True, # FIXME isUserReferee(req), + admin = True # FIXME isUserAdmin(req), ) except OperationalError: return "" def list_registered_users(): """List all registered users.""" return run_sql("SELECT id,email FROM user where email!=''") def list_users_in_role(role): """List all users of a given role (see table accROLE) @param role: role of user (string) @return list of uids """ query = """SELECT uacc.id_user FROM user_accROLE uacc JOIN accROLE acc ON uacc.id_accROLE=acc.id WHERE acc.name='%s'""" res = run_sql(query% escape_string(role)) if res: return map(lambda x: int(x[0]), res) return [] def list_users_in_roles(role_list): """List all users of given roles (see table accROLE) @param role_list: list of roles [string] @return list of uids """ if not(type(role_list) is list or type(role_list) is tuple): role_list = [role_list] params = '' query = """SELECT distinct(uacc.id_user) FROM user_accROLE uacc JOIN accROLE acc ON uacc.id_accROLE=acc.id %s""" if len(role_list) > 0: params = 'WHERE ' for role in role_list[:-1]: params += "acc.name='%s' OR " % escape_string(role) params += "acc.name='%s'" % escape_string(role_list[-1]) res = run_sql(query% params) if res: return map(lambda x: int(x[0]), res) return [] ## --- follow some functions for Apache user/group authentication def auth_apache_user_p(user, password, apache_password_file=CFG_APACHE_PASSWORD_FILE): """Check whether user-supplied credentials correspond to valid Apache password data file. Return 0 in case of failure, 1 in case of success.""" try: if not apache_password_file.startswith("/"): apache_password_file = tmpdir + "/" + apache_password_file dummy, pipe_output = os.popen2(["grep", "^" + user + ":", apache_password_file], 'r') line = pipe_output.readlines()[0] password_apache = string.split(string.strip(line),":")[1] except: # no pw found, so return not-allowed status return 0 salt = password_apache[:2] if crypt.crypt(password, salt) == password_apache: return 1 else: return 0 def auth_apache_user_in_groups(user, apache_group_file=CFG_APACHE_GROUP_FILE): """Return list of Apache groups to which Apache user belong.""" out = [] try: if not apache_group_file.startswith("/"): apache_group_file = tmpdir + "/" + apache_group_file dummy, pipe_output = os.popen2(["grep", user, apache_group_file], 'r') for line in pipe_output.readlines(): out.append(string.split(string.strip(line),":")[0]) except: # no groups found, so return empty list pass return out -def auth_apache_user_collection_p(user, password, coll): - """Check whether user-supplied credentials correspond to valid - Apache password data file, and whether this user is authorized to - see the given collections. Return 0 in case of failure, 1 in case - of success.""" - from invenio.search_engine import coll_restricted_p, coll_restricted_group - if not auth_apache_user_p(user, password): - return 0 - if not coll_restricted_p(coll): - return 1 - if coll_restricted_group(coll) in auth_apache_user_in_groups(user): - return 1 - else: - return 0 - def get_user_preferences(uid): pref = run_sql("SELECT id, settings FROM user WHERE id=%s", (uid,)) if pref: try: return deserialize_via_marshal(pref[0][1]) except: - return get_default_user_preferences() - return {} # empty dict mean no preferences + pass + return get_default_user_preferences() # empty dict mean no preferences def set_user_preferences(uid, pref): assert(type(pref) == type({})) run_sql("UPDATE user SET settings=%s WHERE id=%s", (serialize_via_marshal(pref), uid)) def get_default_user_preferences(): user_preference = { 'login_method': ''} for system in CFG_EXTERNAL_AUTHENTICATION.keys(): if CFG_EXTERNAL_AUTHENTICATION[system][1]: user_preference['login_method'] = system break return user_preference -def extract_user_info(req): - """Return a tuple (uid, nickname, email, groupids, remote_ip, remote_host, external) - containing all the useful info to identificate a user in order - to restrict his/her rights. +def collect_user_info(req): + """Given the mod_python request object rec it returns a dictionary + containing at least the keys uid, apache_user, apache_groups, nickname, + email, groups, remote_ip, remote_host, plus any external keys in + the user preferences (collected at login time and built by the different + external authentication plugins) """ user_info = {} uid = getUid(req) - userinfo['uid'] = uid - user_info['apache_user'], apache_pwd = http_get_credentials(req) - if apache_user: - if not auth_apache_user_p(apache_user, apache_pwd): - apache_user = None - apache_pwd = None - if user_info['apache_user']: - user_info['apache_groups'] = auth_apache_user_in_groups(user_info['apache_user']) - else: - user_info['apache_groups'] = [] + user_info['uid'] = uid + #apache_user, apache_pwd = http_get_credentials(req) + #if apache_user: + #if not auth_apache_user_p(apache_user, apache_pwd): + #apache_user = None + #apache_pwd = None + #user_info['apache_user'] = apache_user + #user_info['apache_group'] = [] + #if user_info['apache_user']: + #user_info['apache_group'] = auth_apache_user_in_groups(user_info['apache_user']) user_info['nickname'] = get_nickname(uid) or None user_info['email'] = get_email(uid) or None - prefs = get_user_preferences(uid) - for key, value in prefs: - user_info[key] = value + user_info['group'] = [] if uid: - user_info['groups'] = [group[1] for group in get_groups(uid)] - else: - user_info['groups'] = [] + user_info['group'] = [group[1] for group in get_groups(uid)] user_info['remote_ip'] = gethostbyname(req.connection.remote_ip) user_info['remote_host'] = req.connection.remote_host or None - for key, value in prefs: - user_info[key.lower()] = value + prefs = get_user_preferences(uid) + if prefs: + for key, value in prefs.items(): + user_info[key.lower()] = value return user_info def serialize_via_marshal(obj): """Serialize Python object via marshal into a compressed string.""" - return compress(dumps(obj)) + return compress(marshal.dumps(obj)) def deserialize_via_marshal(string): """Decompress and deserialize string into a Python object via marshal.""" - return loads(decompress(string)) + return marshal.loads(decompress(string)) diff --git a/modules/websubmit/lib/functions/Is_Original_Submitter.py b/modules/websubmit/lib/functions/Is_Original_Submitter.py index 929aaaa0c..65de3ba21 100644 --- a/modules/websubmit/lib/functions/Is_Original_Submitter.py +++ b/modules/websubmit/lib/functions/Is_Original_Submitter.py @@ -1,64 +1,64 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" ## ## Name: Is_Original_Submitter ## Description: function Is_Original_Submitter - ## This function compares the email of the current logged + ## This function compares the email of the current logged ## user with the original submitter of the document, then ## check whether the user has special rights. ## Author: T.Baron ## ## PARAMETERS: - ## OUTPUT: HTML ## import re from invenio.access_control_engine import acc_authorize_action from invenio.websubmit_config import InvenioWebSubmitFunctionStop from invenio.websubmit_functions.Retrieve_Data import Get_Field def Is_Original_Submitter(parameters,curdir,form): - global uid_email,sysno,uid + global uid_email,sysno,uid,user_info doctype = form['doctype'] act = form['act'] email = Get_Field("8560_f",sysno) email = re.sub("[\n\r ]+","",email) uid_email = re.sub("[\n\r ]+","",uid_email) - (auth_code, auth_message) = acc_authorize_action(uid, "submit",verbose=0,doctype=doctype, act=act) + (auth_code, auth_message) = acc_authorize_action(user_info, "submit",verbose=0,doctype=doctype, act=act) if re.search(uid_email,email,re.IGNORECASE) is None and auth_code != 0: raise InvenioWebSubmitFunctionStop(""" """ % (uid_email,email)) elif re.search(uid_email,email,re.IGNORECASE) is None and auth_code == 0: return (""" """ % (uid_email,email)) return "" diff --git a/modules/websubmit/lib/functions/Is_Referee.py b/modules/websubmit/lib/functions/Is_Referee.py index 1f7696801..7b508fbdc 100644 --- a/modules/websubmit/lib/functions/Is_Referee.py +++ b/modules/websubmit/lib/functions/Is_Referee.py @@ -1,48 +1,48 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" from invenio.config import supportemail from invenio.dbquery import run_sql from invenio.access_control_engine import acc_authorize_action from invenio.websubmit_config import InvenioWebSubmitFunctionStop def Is_Referee(parameters,curdir,form): - global uid_email,sysno,rn,uid + global uid_email,sysno,rn,uid,req doctype = form['doctype'] # Get document category res = run_sql("SELECT categ FROM sbmAPPROVAL WHERE rn=%s", (rn,)) if len(res) >0: categ = res[0][0] else: categ="" # Try to retrieve the referee's email from the referee's database - (auth_code, auth_message) = acc_authorize_action(uid, "referee",doctype=doctype, categ=categ) + (auth_code, auth_message) = acc_authorize_action(req, "referee",doctype=doctype, categ=categ) if auth_code != 0: raise InvenioWebSubmitFunctionStop(""" -""" % (uid_email,supportemail)) return "" diff --git a/modules/websubmit/lib/websubmit_engine.py b/modules/websubmit/lib/websubmit_engine.py index e08dfb0ed..190c8f380 100644 --- a/modules/websubmit/lib/websubmit_engine.py +++ b/modules/websubmit/lib/websubmit_engine.py @@ -1,1472 +1,1473 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. """WebSubmit: the mechanism for the submission of new records into CDS Invenio via a Web interface. """ __revision__ = "$Id$" ## import interesting modules: import string import os import sys import time import types import re import shutil from mod_python import apache from invenio.config import \ bibconvert, \ cdslang, \ cdsname, \ images, \ pylibdir, \ storage, \ urlpath, \ version, \ weburl from invenio.dbquery import run_sql, Error from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import acc_isRole from invenio.webpage import page, create_error_box -from invenio.webuser import getUid, get_email +from invenio.webuser import getUid, get_email, collect_user_info from invenio.websubmit_config import * from invenio.file import * from invenio.messages import gettext_set_language, wash_language from websubmit_dblayer import \ get_storage_directory_of_action, \ get_longname_of_doctype, \ get_longname_of_action, \ get_num_pages_of_submission, \ get_parameter_value_for_doctype, \ submission_exists_in_log, \ log_new_pending_submission, \ log_new_completed_submission, \ update_submission_modified_date_in_log, \ update_submission_reference_in_log, \ update_submission_reference_and_status_in_log, \ get_form_fields_on_submission_page, \ get_element_description, \ get_element_check_description, \ get_form_fields_not_on_submission_page, \ function_step_is_last, \ get_collection_children_of_submission_collection, \ get_submission_collection_name, \ get_doctype_children_of_submission_collection, \ get_categories_of_doctype, \ get_doctype_details, \ get_actions_on_submission_page_for_doctype, \ get_action_details, \ get_parameters_of_function, \ get_details_of_submission, \ get_functions_for_submission_step, \ get_submissions_at_level_X_with_score_above_N, \ submission_is_finished import invenio.template websubmit_templates = invenio.template.load('websubmit') def interface(req, c=cdsname, ln=cdslang, doctype="", act="", startPg=1, indir="", access="", mainmenu="", fromdir="", file="", nextPg="", nbPg="", curpage=1): """This function is called after a user has visited a document type's "homepage" and selected the type of "action" to perform. Having clicked an action-button (e.g. "Submit a New Record"), this function will be called . It performs the task of initialising a new submission session (retrieving information about the submission, creating a working submission-directory, etc), and "drawing" a submission page containing the WebSubmit form that the user uses to input the metadata to be submitted. When a user moves between pages in the submission interface, this function is recalled so that it can save the metadata entered into the previous page by the user, and draw the current submission-page. Note: During a submission, for each page refresh, this function will be called while the variable "step" (a form variable, seen by websubmit_webinterface, which calls this function) is 0 (ZERO). In other words, this function handles the FRONT-END phase of a submission, BEFORE the WebSubmit functions are called. @param req: (apache request object) *** NOTE: Added into this object, is a variable called "form" (req.form). This is added into the object in the index function of websubmit_webinterface. It contains a "mod_python.util.FieldStorage" instance, that contains the form-fields found on the previous submission page. @param c: (string), defaulted to cdsname. The name of the CDS Invenio installation. @param ln: (string), defaulted to cdslang. The language in which to display the pages. @param doctype: (string) - the doctype ID of the doctype for which the submission is being made. @param act: (string) - The ID of the action being performed (e.g. submission of bibliographic information; modification of bibliographic information, etc). @param startPg: (integer) - Starting page for the submission? Defaults to 1. @param indir: (string) - the directory used to store all submissions of the given "type" of this submission. For example, if the submission is of the type "modify bibliographic information", this variable would contain "modify". @param access: (string) - the "access" number for the submission (e.g. 1174062451_7010). This number is also used as the name for the current working submission directory. @param mainmenu: (string) - contains the URL (minus the CDS Invenio home stem) for the submission's home-page. (E.g. If this submission is "PICT", the "mainmenu" file would contain "/submit?doctype=PICT". @param fromdir: (integer) @param file: (string) @param nextPg: (string) @param nbPg: (string) @param curpage: (integer) - the current submission page number. Defaults to 1. """ ln = wash_language(ln) # load the right message language _ = gettext_set_language(ln) sys.stdout = req # get user ID: try: uid = getUid(req) uid_email = get_email(uid) except Error, e: return errorMsg(e, req, c, ln) # variable initialisation t = "" field = [] fieldhtml = [] level = [] fullDesc = [] text = [] check = [] select = [] radio = [] upload = [] txt = [] noPage = [] # Preliminary tasks # check that the user is logged in if uid_email == "" or uid_email == "guest": return warningMsg(websubmit_templates.tmpl_warning_message( ln = ln, msg = _("Sorry, you must log in to perform this action.") ), req, ln) # warningMsg("""
""",req, ln) # check we have minimum fields if "" in (doctype, act, access): ## We don't have all the necessary information to go ahead ## with this submission: return errorMsg(_("Invalid parameter"), req, c, ln) ## Before continuing to display the submission form interface, ## verify that this submission has not already been completed: if submission_is_finished(doctype, act, access, uid_email): ## This submission has already been completed. ## This situation can arise when, having completed a submission, ## the user uses the browser's back-button to go back to the form ## stage of the submission and then tries to submit once more. ## This is unsafe and should not be allowed. Instead of re-displaying ## the submission forms, display an error message to the user: wrnmsg = """This submission has been completed. Please go to the""" \ """ """ \ """main menu to start a new submission.""" \ % { 'doctype' : doctype, 'ln' : ln } return warningMsg(wrnmsg, req) ## retrieve the action and doctype data: ## Concatenate action ID and doctype ID to make the submission ID: subname = "%s%s" % (act, doctype) if indir == "": ## Get the submission storage directory from the DB: submission_dir = get_storage_directory_of_action(act) if submission_dir not in ("", None): indir = submission_dir else: ## Unable to determine the submission-directory: return errorMsg(_("Unable to find the submission directory."), req, c, ln) ## get the document type's long-name: doctype_lname = get_longname_of_doctype(doctype) if doctype_lname is not None: ## Got the doctype long-name: replace spaces with HTML chars: docname = doctype_lname.replace(" ", " ") else: ## Unknown document type: return errorMsg(_("Unknown document type"), req, c, ln) ## get the action's long-name: action_lname = get_longname_of_action(act) if action_lname is not None: ## Got the action long-name: replace spaces with HTML chars: actname = action_lname.replace(" ", " ") else: ## Unknown action: return errorMsg(_("Unknown action"), req, c, ln) ## Get the number of pages for this submission: num_submission_pages = get_num_pages_of_submission(subname) if num_submission_pages is not None: nbpages = num_submission_pages else: ## Unable to determine the number of pages for this submission: return errorMsg(_("Unable to determine the number of submission pages."), req, c, ln) ## If unknown, get the current page of submission: if startPg != "" and curpage in ("", 0): curpage = startPg ## retrieve the name of the file in which the reference of ## the submitted document will be stored rn_filename = get_parameter_value_for_doctype(doctype, "edsrn") if rn_filename is not None: edsrn = rn_filename else: ## Unknown value for edsrn - set it to an empty string: edsrn = "" ## This defines the path to the directory containing the action data curdir = "%s/%s/%s/%s" % (storage, indir, doctype, access) ## if this submission comes from another one (fromdir is then set) ## We retrieve the previous submission directory and put it in the proper one if fromdir != "": olddir = "%s/%s/%s/%s" % (storage, fromdir, doctype, access) if os.path.exists(olddir): os.rename(olddir, curdir) ## If the submission directory still does not exist, we create it if not os.path.exists(curdir): try: os.makedirs(curdir) except: return errorMsg(_("Unable to create a directory for this submission."), req, c, ln) # retrieve the original main menu url and save it in the "mainmenu" file if mainmenu != "": fp = open("%s/mainmenu" % curdir, "w") fp.write(mainmenu) fp.close() # and if the file containing the URL to the main menu exists # we retrieve it and store it in the $mainmenu variable if os.path.exists("%s/mainmenu" % curdir): fp = open("%s/mainmenu" % curdir, "r"); mainmenu = fp.read() fp.close() else: mainmenu = "%s/submit" % (urlpath,) # various authentication related tasks... if uid_email != "guest" and uid_email != "": #First save the username (email address) in the SuE file. This way bibconvert will be able to use it if needed fp = open("%s/SuE" % curdir, "w") fp.write(uid_email) fp.close() # is user authorized to perform this action? - (auth_code, auth_message) = acc_authorize_action(uid, "submit", verbose=0, doctype=doctype, act=act) + (auth_code, auth_message) = acc_authorize_action(req, "submit", verbose=0, doctype=doctype, act=act) if acc_isRole("submit", doctype=doctype, act=act) and auth_code != 0: return warningMsg("""
%s
""" % auth_message, req) ## update the "journal of submission": ## Does the submission already exist in the log? submission_exists = \ submission_exists_in_log(doctype, act, access, uid_email) if submission_exists == 1: ## update the modification-date of this submission in the log: update_submission_modified_date_in_log(doctype, act, access, uid_email) else: ## Submission doesn't exist in log - create it: log_new_pending_submission(doctype, act, access, uid_email) # Save the form fields entered in the previous submission page # If the form was sent with the GET method form = req.form value = "" # we parse all the form variables for key in form.keys(): formfields = form[key] if re.search("\[\]", key): filename = key.replace("[]", "") else: filename = key # the field is an array if isinstance(formfields, types.ListType): fp = open("%s/%s" % (curdir, filename), "w") for formfield in formfields: #stripslashes(value) value = specialchars(formfield) fp.write(value+"\n") fp.close() # the field is a normal string elif isinstance(formfields, types.StringTypes) and formfields != "": value = formfields fp = open("%s/%s" % (curdir, filename), "w") fp.write(specialchars(value)) fp.close() # the field is a file elif hasattr(formfields,"filename") and formfields.filename is not None: if not os.path.exists("%s/files/%s" % (curdir, key)): try: os.makedirs("%s/files/%s" % (curdir, key)) except: return errorMsg(_("Cannot create submission directory."), req, c, ln) filename = formfields.filename if filename != "": # This may be dangerous if the file size is bigger than the available memory data = formfields.file.read() fp = open("%s/files/%s/%s" % (curdir, key, filename), "w") fp.write(data) fp.close() fp = open("%s/lastuploadedfile" % curdir, "w") fp.write(filename) fp.close() fp = open("%s/%s" % (curdir, key), "w") fp.write(filename) fp.close() ## if the found field is the reference of the document, ## save this value in the "journal of submissions": if uid_email != "" and uid_email != "guest": if key == edsrn: update_submission_reference_in_log(doctype, access, uid_email, value) ## create the interface: subname = "%s%s" % (act, doctype) ## Get all of the form fields that appear on this page, ordered by fieldnum: form_fields = get_form_fields_on_submission_page(subname, curpage) full_fields = [] values = [] for field_instance in form_fields: full_field = {} ## Retrieve the field's description: element_descr = get_element_description(field_instance[3]) if element_descr is None: ## The form field doesn't seem to exist - return with error message: return \ errorMsg(_("Unknown form field found on submission page."), \ req, c, ln) if element_descr[8] is None: val = "" else: val = element_descr[8] ## we also retrieve and add the javascript code of the checking function, if needed ## Set it to empty string to begin with: full_field['javascript'] = '' if field_instance[7] != '': check_descr = get_element_check_description(field_instance[7]) if check_descr is not None: ## Retrieved the check description: full_field['javascript'] = check_descr full_field['type'] = element_descr[3] full_field['name'] = field_instance[3] full_field['rows'] = element_descr[5] full_field['cols'] = element_descr[6] full_field['val'] = val full_field['size'] = element_descr[4] full_field['maxlength'] = element_descr[7] full_field['htmlcode'] = element_descr[9] full_field['typename'] = field_instance[1] ## TODO: Investigate this, Not used? ## It also seems to refer to pagenum. # The 'R' fields must be executed in the engine's environment, # as the runtime functions access some global and local # variables. if full_field ['type'] == 'R': co = compile (full_field ['htmlcode'].replace("\r\n","\n"), "", "exec") exec(co) else: text = websubmit_templates.tmpl_submit_field (ln = ln, field = full_field) # we now determine the exact type of the created field if full_field['type'] not in [ 'D','R']: field.append(full_field['name']) level.append(field_instance[5]) fullDesc.append(field_instance[4]) txt.append(field_instance[6]) check.append(field_instance[7]) # If the field is not user-defined, we try to determine its type # (select, radio, file upload...) # check whether it is a select field or not if re.search("SELECT", text, re.IGNORECASE) is not None: select.append(1) else: select.append(0) # checks whether it is a radio field or not if re.search(r"TYPE=[\"']?radio", text, re.IGNORECASE) is not None: radio.append(1) else: radio.append(0) # checks whether it is a file upload or not if re.search(r"TYPE=[\"']?file", text, re.IGNORECASE) is not None: upload.append(1) else: upload.append(0) # if the field description contains the "" string, replace # it by the category selected on the document page submission page combofile = "combo%s" % doctype if os.path.exists("%s/%s" % (curdir, combofile)): f = open("%s/%s" % (curdir, combofile), "r") combo = f.read() f.close() else: combo="" text = text.replace("", combo) # if there is a tag in it, replace it by the current year year = time.strftime("%Y"); text = text.replace("", year) # if there is a tag in it, replace it by the current year today = time.strftime("%d/%m/%Y"); text = text.replace("", today) fieldhtml.append(text) else: select.append(0) radio.append(0) upload.append(0) # field.append(value) - initial version, not working with JS, taking a submitted value field.append(field_instance[3]) level.append(field_instance[5]) txt.append(field_instance[6]) fullDesc.append(field_instance[4]) check.append(field_instance[7]) fieldhtml.append(text) full_field['fullDesc'] = field_instance[4] full_field['text'] = text # If a file exists with the name of the field we extract the saved value text = '' if os.path.exists("%s/%s" % (curdir, full_field['name'])): file = open("%s/%s" % (curdir, full_field['name']), "r"); text = file.read() text = re.compile("[\n\r]*$").sub("", text) text = re.compile("\n").sub("\\n", text) text = re.compile("\r").sub("", text) file.close() values.append(text) full_fields.append(full_field) returnto = {} if int(curpage) == int(nbpages): subname = "%s%s" % (act, doctype) other_form_fields = \ get_form_fields_not_on_submission_page(subname, curpage) nbFields = 0 message = "" fullcheck_select = [] fullcheck_radio = [] fullcheck_upload = [] fullcheck_field = [] fullcheck_level = [] fullcheck_txt = [] fullcheck_noPage = [] fullcheck_check = [] for field_instance in other_form_fields: if field_instance[5] == "M": ## If this field is mandatory, get its description: element_descr = get_element_description(field_instance[3]) if element_descr is None: ## The form field doesn't seem to exist - return with error message: return \ errorMsg(_("Unknown form field found on one of the submission pages."), \ req, c, ln) if element_descr[3] in ['D', 'R']: if element_descr[3] == "D": text = element_descr[9] else: text = eval(element_descr[9]) formfields = text.split(">") for formfield in formfields: match = re.match("name=([^ <>]+)", formfield, re.IGNORECASE) if match is not None: names = match.groups for value in names: if value != "": value = re.compile("[\"']+").sub("", value) fullcheck_field.append(value) fullcheck_level.append(field_instance[5]) fullcheck_txt.append(field_instance[6]) fullcheck_noPage.append(field_instance[1]) fullcheck_check.append(field_instance[7]) nbFields = nbFields + 1 else: fullcheck_noPage.append(field_instance[1]) fullcheck_field.append(field_instance[3]) fullcheck_level.append(field_instance[5]) fullcheck_txt.append(field_instance[6]) fullcheck_check.append(field_instance[7]) nbFields = nbFields+1 # tests each mandatory field fld = 0 res = 1 for i in range (0, nbFields): res = 1 if not os.path.exists("%s/%s" % (curdir, fullcheck_field[i])): res=0 else: file = open("%s/%s" % (curdir, fullcheck_field[i]), "r") text = file.read() if text == '': res=0 else: if text == "Select:": res=0 if res == 0: fld = i break if not res: returnto = { 'field' : fullcheck_txt[fld], 'page' : fullcheck_noPage[fld], } t += websubmit_templates.tmpl_page_interface( ln = ln, docname = docname, actname = actname, curpage = curpage, nbpages = nbpages, file = file, nextPg = nextPg, access = access, nbPg = nbPg, doctype = doctype, act = act, indir = indir, fields = full_fields, javascript = websubmit_templates.tmpl_page_interface_js( ln = ln, upload = upload, field = field, fieldhtml = fieldhtml, txt = txt, check = check, level = level, curdir = curdir, values = values, select = select, radio = radio, curpage = curpage, nbpages = nbpages, images = images, returnto = returnto, ), images = images, mainmenu = mainmenu, ) # start display: req.content_type = "text/html" req.send_http_header() p_navtrail = """%(submit)s > %(docname)s """ % { 'submit' : _("Submit"), 'doctype' : doctype, 'docname' : docname, } return page(title= actname, body = t, navtrail = p_navtrail, description = "submit documents", keywords = "submit", uid = uid, language = ln, req = req, navmenuid='submit') def endaction(req, c=cdsname, ln=cdslang, doctype="", act="", startPg=1, indir="", access="", mainmenu="", fromdir="", file="", nextPg="", nbPg="", curpage=1, step=1, mode="U"): """Having filled-in the WebSubmit form created for metadata by the interface function, the user clicks a button to either "finish the submission" or to "proceed" to the next stage of the submission. At this point, a variable called "step" will be given a value of 1 or above, which means that this function is called by websubmit_webinterface. So, during all non-zero steps of the submission, this function is called. In other words, this function is called during the BACK-END phase of a submission, in which WebSubmit *functions* are being called. The function first ensures that all of the WebSubmit form field values have been saved in the current working submission directory, in text- files with the same name as the field elements have. It then determines the functions to be called for the given step of the submission, and executes them. Following this, if this is the last step of the submission, it logs the submission as "finished" in the journal of submissions. @param req: (apache request object) *** NOTE: Added into this object, is a variable called "form" (req.form). This is added into the object in the index function of websubmit_webinterface. It contains a "mod_python.util.FieldStorage" instance, that contains the form-fields found on the previous submission page. @param c: (string), defaulted to cdsname. The name of the CDS Invenio installation. @param ln: (string), defaulted to cdslang. The language in which to display the pages. @param doctype: (string) - the doctype ID of the doctype for which the submission is being made. @param act: (string) - The ID of the action being performed (e.g. submission of bibliographic information; modification of bibliographic information, etc). @param startPg: (integer) - Starting page for the submission? Defaults to 1. @param indir: (string) - the directory used to store all submissions of the given "type" of this submission. For example, if the submission is of the type "modify bibliographic information", this variable would contain "modify". @param access: (string) - the "access" number for the submission (e.g. 1174062451_7010). This number is also used as the name for the current working submission directory. @param mainmenu: (string) - contains the URL (minus the CDS Invenio home stem) for the submission's home-page. (E.g. If this submission is "PICT", the "mainmenu" file would contain "/submit?doctype=PICT". @param fromdir: @param file: @param nextPg: @param nbPg: @param curpage: (integer) - the current submission page number. Defaults to 1. @param step: (integer) - the current step of the submission. Defaults to 1. @param mode: """ global rn, sysno, dismode, curdir, uid, uid_email, last_step, action_score # load the right message language _ = gettext_set_language(ln) try: rn except NameError: rn = "" dismode = mode ln = wash_language(ln) sys.stdout = req t = "" # get user ID: try: uid = getUid(req) uid_email = get_email(uid) except Error, e: return errorMsg(e, req, c, ln) # Preliminary tasks # check that the user is logged in if uid_email == "" or uid_email == "guest": return warningMsg(websubmit_templates.tmpl_warning_message( ln = ln, msg = _("Sorry, you must log in to perform this action.") ), req, ln) ## check we have minimum fields if "" in (doctype, act, access): ## We don't have all the necessary information to go ahead ## with this submission: return errorMsg(_("Invalid parameter"), req, c, ln) ## Before continuing to process the submitted data, verify that ## this submission has not already been completed: if submission_is_finished(doctype, act, access, uid_email): ## This submission has already been completed. ## This situation can arise when, having completed a submission, ## the user uses the browser's back-button to go back to the form ## stage of the submission and then tries to submit once more. ## This is unsafe and should not be allowed. Instead of re-processing ## the submitted data, display an error message to the user: wrnmsg = """This submission has been completed. Please go to the""" \ """ """ \ """main menu to start a new submission.""" \ % { 'doctype' : doctype, 'ln' : ln } return warningMsg(wrnmsg, req) ## retrieve the action and doctype data if indir == "": ## Get the submission storage directory from the DB: submission_dir = get_storage_directory_of_action(act) if submission_dir not in ("", None): indir = submission_dir else: ## Unable to determine the submission-directory: return errorMsg(_("Unable to find the submission directory."), \ req, c, ln) # The following words are reserved and should not be used as field names reserved_words = ["stop", "file", "nextPg", "startPg", "access", "curpage", "nbPg", "act", \ "indir", "doctype", "mode", "step", "deleted", "file_path", "userfile_name"] # This defines the path to the directory containing the action data curdir = "%s/%s/%s/%s" % (storage, indir, doctype, access) # If the submission directory still does not exist, we create it if not os.path.exists(curdir): try: os.makedirs(curdir) except: return errorMsg(_("Cannot create submission directory."), req, c, ln) # retrieve the original main menu url ans save it in the "mainmenu" file if mainmenu != "": fp = open("%s/mainmenu" % curdir, "w") fp.write(mainmenu) fp.close() # and if the file containing the URL to the main menu exists # we retrieve it and store it in the $mainmenu variable if os.path.exists("%s/mainmenu" % curdir): fp = open("%s/mainmenu" % curdir, "r"); mainmenu = fp.read() fp.close() else: mainmenu = "%s/submit" % (urlpath,) ## retrieve the name of the file in which the reference of ## the submitted document will be stored rn_filename = get_parameter_value_for_doctype(doctype, "edsrn") if rn_filename is not None: edsrn = rn_filename else: ## Unknown value for edsrn - set it to an empty string: edsrn = "" ## Determine whether the action is finished ## (ie there are no other steps after the current one): finished = function_step_is_last(doctype, act, step) # Save the form fields entered in the previous submission page # If the form was sent with the GET method form = req.form value = "" # we parse all the form variables for key in form.keys(): formfields = form[key] if re.search("\[\]", key): filename = key.replace("[]", "") else: filename = key # the field is an array if isinstance(formfields,types.ListType): fp = open("%s/%s" % (curdir, filename), "w") for formfield in formfields: #stripslashes(value) value = specialchars(formfield) fp.write(value+"\n") fp.close() # the field is a normal string elif isinstance(formfields, types.StringTypes) and formfields != "": value = formfields fp = open("%s/%s" % (curdir, filename), "w") fp.write(specialchars(value)) fp.close() # the field is a file elif hasattr(formfields, "filename") and formfields.filename is not None: if not os.path.exists("%s/files/%s" % (curdir, key)): try: os.makedirs("%s/files/%s" % (curdir, key)) except: return errorMsg("can't create submission directory", req, cdsname, ln) filename = formfields.filename if filename != "": # This may be dangerous if the file size is bigger than the available memory data = formfields.file.read() fp = open("%s/files/%s/%s" % (curdir, key, filename), "w") fp.write(data) fp.close() fp = open("%s/lastuploadedfile" % curdir, "w") fp.write(filename) fp.close() fp = open("%s/%s" % (curdir, key), "w") fp.write(filename) fp.close() ## if the found field is the reference of the document ## we save this value in the "journal of submissions" if uid_email != "" and uid_email != "guest": if key == edsrn: update_submission_reference_in_log(doctype, access, uid_email, value) ## get the document type's long-name: doctype_lname = get_longname_of_doctype(doctype) if doctype_lname is not None: ## Got the doctype long-name: replace spaces with HTML chars: docname = doctype_lname.replace(" ", " ") else: ## Unknown document type: return errorMsg(_("Unknown document type"), req, c, ln) ## get the action's long-name: action_lname = get_longname_of_action(act) if action_lname is not None: ## Got the action long-name: replace spaces with HTML chars: actname = action_lname.replace(" ", " ") else: ## Unknown action: return errorMsg(_("Unknown action"), req, c, ln) ## Get the number of pages for this submission: subname = "%s%s" % (act, doctype) num_submission_pages = get_num_pages_of_submission(subname) if num_submission_pages is not None: nbpages = num_submission_pages else: ## Unable to determine the number of pages for this submission: return errorMsg(_("Unable to determine the number of submission pages."), \ req, cdsname, ln) ## Determine whether the action is finished ## (ie there are no other steps after the current one): last_step = function_step_is_last(doctype, act, step) next_action = '' ## The next action to be proposed to the user # Prints the action details, returning the mandatory score action_score = action_details(doctype, act) current_level = get_level(doctype, act) # Calls all the function's actions function_content = '' try: ## Handle the execution of the functions for this ## submission/step: - function_content = print_function_calls(doctype=doctype, + function_content = print_function_calls(req=req, doctype=doctype, action=act, step=step, form=form, ln=ln) except InvenioWebSubmitFunctionError, e: ## There was a serious function-error. Execution ends. return errorMsg(e.value, req, c, ln) except InvenioWebSubmitFunctionStop, e: ## For one reason or another, one of the functions has determined that ## the data-processing phase (i.e. the functions execution) should be ## halted and the user should be returned to the form interface once ## more. (NOTE: Redirecting the user to the Web-form interface is ## currently done using JavaScript. The "InvenioWebSubmitFunctionStop" ## exception contains a "value" string, which is effectively JavaScript ## - probably an alert box and a form that is submitted). **THIS WILL ## CHANGE IN THE FUTURE WHEN JavaScript IS REMOVED!** if e.value is not None: function_content = e.value else: function_content = e else: ## No function exceptions (InvenioWebSubmitFunctionStop, ## InvenioWebSubmitFunctionError) were raised by the functions. Propose ## the next action (if applicable), and log the submission as finished: ## If the action was mandatory we propose the next ## mandatory action (if any) if action_score != -1 and last_step == 1: next_action = Propose_Next_Action(doctype, \ action_score, \ access, \ current_level, \ indir) ## If we are in the last step of an action, we can update ## the "journal of submissions" if last_step == 1: if uid_email != "" and uid_email != "guest" and rn != "": ## update the "journal of submission": ## Does the submission already exist in the log? submission_exists = \ submission_exists_in_log(doctype, act, access, uid_email) if submission_exists == 1: ## update the rn and status to finished for this submission ## in the log: update_submission_reference_and_status_in_log(doctype, \ act, \ access, \ uid_email, \ rn, \ "finished") else: ## Submission doesn't exist in log - create it: log_new_completed_submission(doctype, \ act, \ access, \ uid_email, \ rn) ## Having executed the functions, create the page that will be displayed ## to the user: t = websubmit_templates.tmpl_page_endaction( ln = ln, weburl = weburl, # these fields are necessary for the navigation file = file, nextPg = nextPg, startPg = startPg, access = access, curpage = curpage, nbPg = nbPg, nbpages = nbpages, doctype = doctype, act = act, docname = docname, actname = actname, indir = indir, mainmenu = mainmenu, finished = finished, images = images, function_content = function_content, next_action = next_action, ) # start display: req.content_type = "text/html" req.send_http_header() p_navtrail = """""" + _("Submit") +\ """ > %(docname)s""" % { 'doctype' : doctype, 'docname' : docname, } return page(title= actname, body = t, navtrail = p_navtrail, description="submit documents", keywords="submit", uid = uid, language = ln, req = req, navmenuid='submit') def home(req, c=cdsname, ln=cdslang): """This function generates the WebSubmit "home page". Basically, this page contains a list of submission-collections in WebSubmit, and gives links to the various document-type submissions. Document-types only appear on this page when they have been connected to a submission-collection in WebSubmit. @param req: (apache request object) @param c: (string) - defaults to cdsname @param ln: (string) - The CDS Invenio interface language of choice. Defaults to cdslang (the default language of the installation). @return: (string) - the Web page to be displayed. """ ln = wash_language(ln) # get user ID: try: uid = getUid(req) except Error, e: return errorMsg(e, req, c, ln) # start display: req.content_type = "text/html" req.send_http_header() # load the right message language _ = gettext_set_language(ln) finaltext = websubmit_templates.tmpl_submit_home_page( ln = ln, catalogues = makeCataloguesTable(ln) ) return page(title=_("Submit"), body=finaltext, navtrail=[], description="submit documents", keywords="submit", uid=uid, language=ln, req=req, navmenuid='submit' ) def makeCataloguesTable(ln=cdslang): """Build the 'catalogues' (submission-collections) tree for the WebSubmit home-page. This tree contains the links to the various document types in WebSubmit. @param ln: (string) - the language of the interface. (defaults to 'cdslang'). @return: (string) - the submission-collections tree. """ text = "" catalogues = [] ## Get the submission-collections attached at the top level ## of the submission-collection tree: top_level_collctns = get_collection_children_of_submission_collection(0) if len(top_level_collctns) != 0: ## There are submission-collections attatched to the top level. ## retrieve their details for displaying: for child_collctn in top_level_collctns: catalogues.append(getCatalogueBranch(child_collctn[0], 1)) text = websubmit_templates.tmpl_submit_home_catalogs( ln=ln, catalogs=catalogues ) else: text = websubmit_templates.tmpl_submit_home_catalog_no_content(ln=ln) return text def getCatalogueBranch(id_father, level): """Build up a given branch of the submission-collection tree. I.e. given a parent submission-collection ID, build up the tree below it. This tree will include doctype-children, as well as other submission- collections and their children. Finally, return the branch as a dictionary. @param id_father: (integer) - the ID of the submission-collection from which to begin building the branch. @param level: (integer) - the level of the current submission- collection branch. @return: (dictionary) - the branch and its sub-branches. """ elem = {} ## The dictionary to contain this branch of the tree. ## First, get the submission-collection-details: collctn_name = get_submission_collection_name(id_father) if collctn_name is not None: ## Got the submission-collection's name: elem['name'] = collctn_name else: ## The submission-collection is unknown to the DB ## set its name as empty: elem['name'] = "" elem['id'] = id_father elem['level'] = level ## Now get details of the doctype-children of this ## submission-collection: elem['docs'] = [] ## List to hold the doctype-children ## of the submission-collection doctype_children = \ get_doctype_children_of_submission_collection(id_father) for child_doctype in doctype_children: elem['docs'].append(getDoctypeBranch(child_doctype[0])) ## Now, get the collection-children of this submission-collection: elem['sons'] = [] collctn_children = \ get_collection_children_of_submission_collection(id_father) for child_collctn in collctn_children: elem['sons'].append(getCatalogueBranch(child_collctn[0], level + 1)) ## Now return this branch of the built-up 'collection-tree': return elem def getDoctypeBranch(doctype): """Create a document-type 'leaf-node' for the submission-collections tree. Basically, this leaf is a dictionary containing the name and ID of the document-type submission to which it links. @param doctype: (string) - the ID of the document type. @return: (dictionary) - the document-type 'leaf node'. Contains the following values: + id: (string) - the document-type ID. + name: (string) - the (long) name of the document-type. """ ldocname = get_longname_of_doctype(doctype) if ldocname is None: ldocname = "Unknown Document Type" return { 'id' : doctype, 'name' : ldocname, } def displayCatalogueBranch(id_father, level, catalogues): text = "" collctn_name = get_submission_collection_name(id_father) if collctn_name is None: ## If this submission-collection wasn't known in the DB, ## give it the name "Unknown Submission-Collection" to ## avoid errors: collctn_name = "Unknown Submission-Collection" ## Now, create the display for this submission-collection: if level == 1: text = "
  • %s\n" \ % collctn_name else: ## TODO: These are the same (and the if is ugly.) Why? if level == 2: text = "
  • %s\n" % collctn_name else: if level > 2: text = "
  • %s\n" % collctn_name ## Now display the children document-types that are attached ## to this submission-collection: ## First, get the children: doctype_children = get_doctype_children_of_submission_collection(id_father) collctn_children = get_collection_children_of_submission_collection(id_father) if len(doctype_children) > 0 or len(collctn_children) > 0: ## There is something to display, so open a list: text = text + "
      \n" ## First, add the doctype leaves of this branch: for child_doctype in doctype_children: ## Add the doctype 'leaf-node': text = text + displayDoctypeBranch(child_doctype[0], catalogues) ## Now add the submission-collection sub-branches: for child_collctn in collctn_children: catalogues.append(child_collctn[0]) text = text + displayCatalogueBranch(child_collctn[0], level+1, catalogues) ## Finally, close up the list if there were nodes to display ## at this branch: if len(doctype_children) > 0 or len(collctn_children) > 0: text = text + "
    \n" return text def displayDoctypeBranch(doctype, catalogues): text = "" ldocname = get_longname_of_doctype(doctype) if ldocname is None: ldocname = "Unknown Document Type" text = "
  • %s\n" \ % (doctype, doctype, doctype, ldocname) return text def action(req, c=cdsname, ln=cdslang, doctype=""): # load the right message language _ = gettext_set_language(ln) nbCateg = 0 snameCateg = [] lnameCateg = [] actionShortDesc = [] indir = [] actionbutton = [] statustext = [] t = "" ln = wash_language(ln) # get user ID: try: uid = getUid(req) uid_email = get_email(uid) except Error, e: return errorMsg(e, req, c, ln) #parses database to get all data ## first, get the list of categories doctype_categs = get_categories_of_doctype(doctype) for doctype_categ in doctype_categs: nbCateg = nbCateg+1 snameCateg.append(doctype_categ[0]) lnameCateg.append(doctype_categ[1]) ## Now get the details of the document type: doctype_details = get_doctype_details(doctype) if doctype_details is None: ## Doctype doesn't exist - raise error: return errorMsg (_("Unable to find document type.") + str(doctype), req) else: docFullDesc = doctype_details[0] docShortDesc = doctype_details[1] description = doctype_details[4] ## Get the details of the actions supported by this document-type: doctype_actions = get_actions_on_submission_page_for_doctype(doctype) for doctype_action in doctype_actions: ## Get the details of this action: action_details = get_action_details(doctype_action[0]) if action_details is not None: actionShortDesc.append(doctype_action[0]) indir.append(action_details[1]) actionbutton.append(action_details[4]) statustext.append(action_details[5]) ## Send the gathered information to the template so that the doctype's ## home-page can be displayed: t = websubmit_templates.tmpl_action_page( ln=ln, uid=uid, guest=(uid_email == "" or uid_email == "guest"), pid = os.getpid(), now = time.time(), doctype = doctype, description = description, docfulldesc = docFullDesc, snameCateg = snameCateg, lnameCateg = lnameCateg, actionShortDesc = actionShortDesc, indir = indir, # actionbutton = actionbutton, statustext = statustext, ) p_navtrail = """%(submit)s""" % {'submit' : _("Submit")} return page(title = docFullDesc, body=t, navtrail=p_navtrail, description="submit documents", keywords="submit", uid=uid, language=ln, req=req, navmenuid='submit' ) def Request_Print(m, txt): """The argumemts to this function are the display mode (m) and the text to be displayed (txt). If the argument mode is 'ALL' then the text is unconditionally echoed m can also take values S (Supervisor Mode) and U (User Mode). In these circumstances txt is only echoed if the argument mode is the same as the current mode """ global dismode if m == "A" or m == dismode: return txt else: return "" def Evaluate_Parameter (field, doctype): # Returns the literal value of the parameter. Assumes that the value is # uniquely determined by the doctype, i.e. doctype is the primary key in # the table # If the table name is not null, evaluate the parameter ## TODO: The above comment looks like nonesense? This ## function only seems to get the values of parameters ## from the db... ## Get the value for the parameter: param_val = get_parameter_value_for_doctype(doctype, field) if param_val is None: ## Couldn't find a value for this parameter for this doctype. ## Instead, try with the default doctype (DEF): param_val = get_parameter_value_for_doctype("DEF", field) if param_val is None: ## There was no value for the parameter for the default doctype. ## Nothing can be done about it - return an empty string: return "" else: ## There was some kind of value for the parameter; return it: return param_val def Get_Parameters (function, doctype): """For a given function of a given document type, a dictionary of the parameter names and values are returned. @param function: (string) - the name of the function for which the parameters are to be retrieved. @param doctype: (string) - the ID of the document type. @return: (dictionary) - of the parameters of the function. Keyed by the parameter name, values are of course the parameter values. """ parray = {} ## Get the names of the parameters expected by this function: func_params = get_parameters_of_function(function) for func_param in func_params: ## For each of the parameters, get its value for this document- ## type and add it into the dictionary of parameters: parameter = func_param[0] parray[parameter] = Evaluate_Parameter (parameter, doctype) return parray def get_level(doctype, action): """Get the level of a given submission. If unknown, return 0 as the level. @param doctype: (string) - the ID of the document type. @param action: (string) - the ID of the action. @return: (integer) - the level of the submission; 0 otherwise. """ subm_details = get_details_of_submission(doctype, action) if subm_details is not None: ## Return the level of this action subm_level = subm_details[9] try: int(subm_level) except ValueError: return 0 else: return subm_level else: return 0 def action_details (doctype, action): # Prints whether the action is mandatory or optional. The score of the # action is returned (-1 if the action was optional) subm_details = get_details_of_submission(doctype, action) if subm_details is not None: if subm_details[9] != "0": ## This action is mandatory; return the score: return subm_details[10] else: return -1 else: return -1 -def print_function_calls (doctype, action, step, form, ln=cdslang): +def print_function_calls (req, doctype, action, step, form, ln=cdslang): # Calls the functions required by an "action" action on a "doctype" document # In supervisor mode, a table of the function calls is produced - global htdocsdir,storage,access,pylibdir,dismode + global htdocsdir,storage,access,pylibdir,dismode,user_info + user_info = collect_user_info(req) # load the right message language _ = gettext_set_language(ln) t = "" ## Get the list of functions to be called funcs_to_call = get_functions_for_submission_step(doctype, action, step) ## If no functions are found at this step for this doctype, ## get the functions for the DEF(ault) doctype: if len(funcs_to_call) == 0: funcs_to_call = get_functions_for_submission_step("DEF", action, step) if len(funcs_to_call) > 0: # while there are functions left... functions = [] for function in funcs_to_call: function_name = function[0] function_score = function[1] currfunction = { 'name' : function_name, 'score' : function_score, 'error' : 0, 'text' : '', } if os.path.exists("%s/invenio/websubmit_functions/%s.py" % (pylibdir, function_name)): # import the function itself #function = getattr(invenio.websubmit_functions, function_name) execfile("%s/invenio/websubmit_functions/%s.py" % (pylibdir, function_name), globals()) if not globals().has_key(function_name): currfunction['error'] = 1 else: function = globals()[function_name] # Evaluate the parameters, and place them in an array parameters = Get_Parameters(function_name, doctype) # Call function: func_returnval = function(parameters, curdir, form) if func_returnval is not None: ## Append the returned value as a string: currfunction['text'] = str(func_returnval) else: ## The function the NoneType. Don't keep that value as ## the currfunction->text. Replace it with the empty ## string. currfunction['text'] = "" else: currfunction['error'] = 1 functions.append(currfunction) t = websubmit_templates.tmpl_function_output( ln = ln, display_on = (dismode == 'S'), action = action, doctype = doctype, step = step, functions = functions, ) else : if dismode == 'S': t = "

    " + _("The chosen action is not supported by the document type.") + "" return t def Propose_Next_Action (doctype, action_score, access, currentlevel, indir, ln=cdslang): global machine, storage, act, rn t = "" next_submissions = \ get_submissions_at_level_X_with_score_above_N(doctype, currentlevel, action_score) if len(next_submissions) > 0: actions = [] first_score = next_submissions[0][10] for action in next_submissions: if action[10] == first_score: ## Get the submission directory of this action: nextdir = get_storage_directory_of_action(action[1]) if nextdir is None: nextdir = "" curraction = { 'page' : action[11], 'action' : action[1], 'doctype' : doctype, 'nextdir' : nextdir, 'access' : access, 'indir' : indir, 'name' : action[12], } actions.append(curraction) t = websubmit_templates.tmpl_next_action( ln = ln, actions = actions, ) return t def errorMsg(title, req, c=cdsname, ln=cdslang): # load the right message language _ = gettext_set_language(ln) return page(title = _("Error"), body = create_error_box(req, title=title, verbose=0, ln=ln), description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='submit') def warningMsg(title, req, c=cdsname, ln=cdslang): # load the right message language _ = gettext_set_language(ln) return page(title = _("Warning"), body = title, description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='submit') def specialchars(text): text = string.replace(text, "“", "\042"); text = string.replace(text, "”", "\042"); text = string.replace(text, "’", "\047"); text = string.replace(text, "—", "\055"); text = string.replace(text, "…", "\056\056\056"); return text diff --git a/modules/websubmit/lib/websubmit_webinterface.py b/modules/websubmit/lib/websubmit_webinterface.py index f08455084..0ddf756be 100644 --- a/modules/websubmit/lib/websubmit_webinterface.py +++ b/modules/websubmit/lib/websubmit_webinterface.py @@ -1,418 +1,418 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" import string import os import time import types import re from mod_python import apache import sys from urllib import quote from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_SITE, \ cdslang, \ cdsname, \ images, \ storage, \ urlpath, \ version, \ weburl from invenio.dbquery import run_sql, Error from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import acc_isRole from invenio.webpage import page, create_error_box from invenio.webuser import getUid, get_email, page_not_authorized from invenio.websubmit_config import * from invenio.file import * from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory from invenio.urlutils import make_canonical_urlargd, redirect_to_url from invenio.messages import gettext_set_language import invenio.template websubmit_templates = invenio.template.load('websubmit') class WebInterfaceFilesPages(WebInterfaceDirectory): def __init__(self,recid): self.recid = recid - + def _lookup(self, component, path): # after /record//files/ every part is used as the file # name (with possible path in the case of archives to be # uncompressed) filename = component def getfile(req, form): - args = wash_urlargd(form, websubmit_templates.files_default_urlargd) + args = wash_urlargd(form, websubmit_templates.files_default_urlargd) ln = args['ln'] - + _ = gettext_set_language(ln) uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE > 1: return page_not_authorized(req, "../getfile.py/index", navmenuid='submit') uid_email = get_email(uid) readonly = CFG_ACCESS_CONTROL_LEVEL_SITE == 1 # From now on: either the user provided a specific file # name (and a possible version), or we return a list of # all the available files. In no case are the docids # visible. bibarchive = BibRecDocs(self.recid) if filename: # We know the complete file name, guess which docid it # refers to ## TODO: Change the extension system according to ext.py from setlink ## and have a uniform extension mechanism... name = file_strip_ext(filename) format = filename[len(name):] if format and format[0] == '.': format = format[1:] - + # search this filename in the complete list of files for doc in bibarchive.listBibDocs(): if filename in [f.fullname for f in doc.listAllFiles()]: docfile=doc.getFile(name,format,args['version']) if docfile is None: return warningMsg(_("Unable to find file."), req, cdsname, ln) - + if docfile.isRestricted(): return warningMsg(_("This file is restricted!"), req, cdsname, ln) - + if not readonly: ip = str(req.get_remote_host(apache.REMOTE_NOLOOKUP)) res = doc.registerDownload(ip, version, format, uid) - + return docfile.stream(req) else: return warningMsg(_("Unable to find file."), req, cdsname, ln) filelist = bibarchive.display("", args['version'], ln=ln) t = websubmit_templates.tmpl_filelist( ln=ln, recid=self.recid, docid="", version=args['version'], filelist=filelist) - + return page(title="", body=t, navtrail=_("Access to Fulltext"), description="", keywords="keywords", uid=uid, language=ln, req=req, navmenuid='submit') return getfile, [] def __call__(self, req, form): """Called in case of URLs like /record/123/files without trailing slash. """ return redirect_to_url(req, '%s/record/%s/files/' % (weburl, self.recid)) def websubmit_legacy_getfile(req, form): """ Handle legacy /getfile.py URLs """ # FIXME: this should _redirect_ to the proper # /record/.../files/... URL. - + args = wash_urlargd(form, { 'c': (str, cdsname), 'recid': (str, ''), 'docid': (str, ''), 'version': (str, ''), 'name': (str, ''), 'format': (str, '') }) def _getfile_py(req,c=cdsname,ln=cdslang,recid="",docid="",version="",name="",format=""): _ = gettext_set_language(ln) # get user ID: try: uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../getfile.py/index", navmenuid='submit') uid_email = get_email(uid) except Error, e: return errorMsg(e.value,req) filelist="" # redirect to a canonical URL as far as it is possible (what # if we only have a docid, and no file supplied?) if name!="": if docid=="": return errorMsg(_("Parameter docid missing"), req, c, ln) doc = BibDoc(bibdocid=docid) docfile=doc.getFile(name,format,version) - + if docfile is None: return warningMsg(_("Unable to find file."),req, c, ln) # redirect to this specific file, possibly dropping # the version if we are referring to the latest one. target = '%s/record/%d/files/%s.%s' % ( weburl, doc.recid, quote(docfile.name), docfile.format) if version and int(version) == int(doc.getLatestVersion()): version = '' - + target += make_canonical_urlargd({ 'version': version}, websubmit_templates.files_default_urlargd) return redirect_to_url(req, target) - + # all files attached to a record elif recid!="": return redirect_to_url(req, '%s/record/%s/files/' % (weburl, recid)) # a precise filename elif docid!="": bibdoc = BibDoc(bibdocid=docid) recid = bibdoc.getRecid() filelist = bibdoc.display(version, ln=ln) - + t = websubmit_templates.tmpl_filelist( ln = ln, recid = recid, docid = docid, version = version, filelist = filelist, ) p_navtrail = _("Access to Fulltext") return page(title="", body=t, navtrail = p_navtrail, description="", keywords="keywords", uid=uid, language=ln, req=req, navmenuid='submit') - + return _getfile_py(req, **args) # -------------------------------------------------- from invenio.websubmit_engine import home, action, interface, endaction class WebInterfaceSubmitPages(WebInterfaceDirectory): _exports = ['summary', 'sub', 'direct', ''] def direct(self, req, form): args = wash_urlargd(form, {'sub': (str, '')}) sub = args['sub'] - + uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../direct.py/index", navmenuid='submit') myQuery = req.args if sub == "": return errorMsg("Sorry parameter missing...",req) res = run_sql("select docname,actname from sbmIMPLEMENT where subname=%s", (sub,)) if len(res)==0: return errorMsg("Sorry. Cannot analyse parameter",req) else: # get document type doctype = res[0][0] # get action name action = res[0][1] # retrieve other parameter values params = re.sub("sub=[^&]*","",myQuery) # find existing access number result = re.search("access=([^&]*)",params) if result is not None: access = result.group(1) params = re.sub("access=[^&]*","",params) else: # create 'unique' access number pid = os.getpid() now = time.time() access = "%i_%s" % (now,pid) # retrieve 'dir' value res = run_sql ("select dir from sbmACTION where sactname=%s",(action,)) dir = res[0][0] try: mainmenu = req.headers_in['Referer'] except: mainmenu = "" url = "/submit?doctype=%s&dir=%s&access=%s&act=%s&startPg=1%s&mainmenu=%s" % ( doctype,dir,access,action,params,quote(mainmenu)) req.err_headers_out.add("Location", url) raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY return "" def sub(self, req, form): uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../sub/", navmenuid='submit') myQuery = req.args if myQuery: if re.search("@",myQuery): param = re.sub("@.*","",myQuery) IN = re.sub(".*@","",myQuery) else: IN = myQuery url = "%s/submit/direct?sub=%s&%s" % (urlpath,IN,param) req.err_headers_out.add("Location", url) raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY return "" else: return "Illegal page access" def summary(self, req, form): args = wash_urlargd(form, { 'doctype': (str, ''), 'act': (str, ''), 'access': (str, ''), 'indir': (str, '')}) - + uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../summary.py/index", navmenuid='submit') t="" curdir = "%s/%s/%s/%s" % (storage,args['indir'],args['doctype'],args['access']) subname = "%s%s" % (args['act'], args['doctype']) - + res = run_sql("select sdesc,fidesc,pagenb,level from sbmFIELD where subname=%s " "order by pagenb,fieldnb", (subname,)) nbFields = 0 values = [] for arr in res: if arr[0] != "": val = { 'mandatory' : (arr[3] == 'M'), 'value' : '', 'page' : arr[2], 'name' : arr[0], } if os.path.exists("%s/%s" % (curdir,arr[1])): fd = open("%s/%s" % (curdir,arr[1]),"r") value = fd.read() fd.close() value = value.replace("\n"," ") value = value.replace("Select:","") else: value = "" val['value'] = value values.append(val) return websubmit_templates.tmpl_submit_summary( ln = args['ln'], values = values, images = images, ) def index(self, req, form): args = wash_urlargd(form, { 'c': (str, cdsname), 'doctype': (str, ''), 'act': (str, ''), 'startPg': (str, "1"), 'indir': (str, ''), 'access': (str, ''), 'mainmenu': (str, ''), 'fromdir': (str, ''), 'file': (str, ''), 'nextPg': (str, ''), 'nbPg': (str, ''), 'curpage': (str, '1'), 'step': (str, '0'), 'mode': (str, 'U'), }) req.form = form def _index(req, c, ln, doctype, act, startPg, indir, access, mainmenu, fromdir, file, nextPg, nbPg, curpage, step, mode): uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../submit", navmenuid='submit') if doctype=="": return home(req,c,ln) elif act=="": return action(req,c,ln,doctype) elif int(step)==0: return interface(req,c,ln, doctype, act, startPg, indir, access, mainmenu, fromdir, file, nextPg, nbPg, curpage) else: return endaction(req,c,ln, doctype, act, startPg, indir, access,mainmenu, fromdir, file, nextPg, nbPg, curpage, step, mode) return _index(req, **args) # Answer to both /submit/ and /submit __call__ = index def errorMsg(title,req,c=cdsname,ln=cdslang): _ = gettext_set_language(ln) return page(title=_("Error"), body = create_error_box(req, title=title,verbose=0, ln=ln), description=_("Internal Error"), keywords="CDS Invenio, Internal Error", language=ln, req=req, navmenuid='submit') def warningMsg(title,req,c=cdsname,ln=cdslang): _ = gettext_set_language(ln) return page(title=_("Warning"), body = title, description=_("Internal Error"), keywords="CDS Invenio, Internal Error", language=ln, req=req, navmenuid='submit') diff --git a/modules/websubmit/lib/websubmitadmin_engine.py b/modules/websubmit/lib/websubmitadmin_engine.py index 47faee9fc..653810a34 100644 --- a/modules/websubmit/lib/websubmitadmin_engine.py +++ b/modules/websubmit/lib/websubmitadmin_engine.py @@ -1,4243 +1,4242 @@ # -*- coding: utf-8 -*- ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" import re from random import randint, seed from os.path import split, basename, isfile from os import access, F_OK, R_OK, W_OK, getpid, rename, unlink from time import strftime, localtime from invenio.websubmitadmin_dblayer import * from invenio.websubmitadmin_config import * from invenio.access_control_admin import acc_getAllRoles, acc_getRoleUsers, acc_deleteUserRole from invenio.config import cdslang, bibconvertconf from invenio.access_control_engine import acc_authorize_action - import invenio.template try: websubmitadmin_templates = invenio.template.load('websubmitadmin') except: pass ## utility functions: -def is_adminuser(uid, role): +def is_adminuser(req, role): """check if user is a registered administrator. """ - return acc_authorize_action(uid, role) + return acc_authorize_action(req, role) -def check_user(uid, role, adminarea=2, authorized=0): - (auth_code, auth_message) = is_adminuser(uid, role) +def check_user(req, role, adminarea=2, authorized=0): + (auth_code, auth_message) = is_adminuser(req, role) if not authorized and auth_code != 0: return ("false", auth_message) return ("", auth_message) def get_navtrail(ln=cdslang): """gets the navtrail for title... @param title: title of the page @param ln: language @return HTML output """ navtrail = websubmitadmin_templates.tmpl_navtrail(ln) return navtrail def stringify_listvars(mylist): """Accept a list (or a list of lists) (or tuples). Convert each item in the list, into a string (replace None with the empty string ""). @param mylist: A list/tuple of values, or a list/tuple of value list/tuples. @return: a tuple of string values or a tuple of string value tuples """ string_list = [] try: if type(mylist[0]) in (tuple,list): for row in mylist: string_list.append(map(lambda x: x is not None and str(x) or "", row)) else: string_list = map(lambda x: x is not None and str(x) or "", mylist) except IndexError: pass return string_list def save_update_to_file(filepath, filecontent, notruncate=0, appendmode=0): """Save a string value to a file. Save will create a new file if the file does not exist. Mode can be set to truncate an older file or to refuse to create the file if it already exists. There is also a mode to "append" the string value to a file. @param filepath: (string) the full path to the file @param filecontent: (string) the content to be written to the file @param notruncate: (integer) should be 1 or 0, defaults to 0 (ZERO). If 0, existing file will be truncated; if 1, file will not be written if it already exists @param appendmode: (integer) should be 1 or 0, defaults to 0 (ZERO). If 1, data will be appended to the file if it exists; if 0, file will be truncated (or not, depending on the notruncate mode) by new data. @return: None @exceptions raised: - InvenioWebSubmitAdminWarningIOError: when operations involving writing to file failed. """ ## sanity checking: if notruncate not in (0, 1): notruncate = 0 if appendmode not in (0, 1): appendmode = 0 (fpath, fname) = split(filepath) if fname == "": ## error opening file msg = """Unable to open filepath [%s] - couldn't determine a valid filename""" % (filepath,) raise InvenioWebSubmitAdminWarningIOError(msg) ## if fpath is not empty, append the trailing "/": if fpath != "": fpath += "/" if appendmode == 0: if notruncate != 0 and access("%s%s" % (fpath, fname), F_OK): ## in no-truncate mode, but file already exists! msg = """Unable to write to file [%s] in "no-truncate mode" because file already exists"""\ % (fname,) raise InvenioWebSubmitAdminWarningIOError(msg) ## file already exists, make temporary file first, then move it later tmpfname = "%s_%s_%s" % (fname, strftime("%Y%m%d%H%M%S", localtime()), getpid()) ## open temp file for writing: try: fp = open("%s%s" % (fpath, tmpfname), "w") except IOError, e: ## cannot open file msg = """Unable to write to file [%s%s] - cannot open file for writing""" % (fpath, fname) raise InvenioWebSubmitAdminWarningIOError(msg) ## write contents to temp file: try: fp.write(filecontent) fp.flush() fp.close() except IOError, e: ## could not write to temp file msg = """Unable to write to file [%s]""" % (tmpfname,) ## remove the "temp file" try: fp.close() unlink("%s%s" % (fpath, tmpfname)) except IOError: pass raise InvenioWebSubmitAdminWarningIOError(msg) ## rename temp file to final filename: try: rename("%s%s" % (fpath, tmpfname), "%s%s" % (fpath, fname)) except OSError: ## couldnt rename the tmp file to final file name msg = """Unable to write to file [%s] - created temporary file [%s], but could not then rename it to [%s]"""\ % (fname, tmpfname, fname) raise InvenioWebSubmitAdminWarningIOError(msg) else: ## append mode: try: fp = open("%s%s" % (fpath, fname), "a") except IOError, e: ## cannot open file msg = """Unable to write to file [%s] - cannot open file for writing in append mode""" % (fname,) raise InvenioWebSubmitAdminWarningIOError(msg) ## write contents to temp file: try: fp.write(filecontent) fp.flush() fp.close() except IOError, e: ## could not write to temp file msg = """Unable to write to file [%s] in append mode""" % (fname,) ## close the file try: fp.close() except IOError: pass raise InvenioWebSubmitAdminWarningIOError(msg) return def string_is_alphanumeric_including_underscore(txtstring): p_txtstring = re.compile(r'^\w*$') m_txtstring = p_txtstring.search(txtstring) if m_txtstring is not None: return 1 else: return 0 def function_name_is_valid(fname): p_fname = re.compile(r'^(_|[a-zA-Z])\w*$') m_fname = p_fname.search(fname) if m_fname is not None: return 1 else: return 0 def wash_single_urlarg(urlarg, argreqdtype, argdefault, maxstrlen=None, minstrlen=None, truncatestr=0): """Wash a single argument according to some specifications. @param urlarg: the argument to be tested, as passed from the form/url, etc @param argreqdtype: (a python type) the type that the argument should conform to (argument required type) @argdefault: the default value that should be returned for the argument in the case that it doesn't comply with the washing specifications @param maxstrlen: (integer) the maximum length for a string argument; defaults to None, which means that no maximum length is forced upon the string @param minstrlen: (integer) the minimum length for a string argument; defaults to None, which means that no minimum length is forced upon the string @truncatestr: (integer) should be 1 or 0 (ZERO). A flag used to determine whether or not a string argument that overstretches the maximum length (if one if provided) should be truncated, or reset to the default for the argument. 0, means don't truncate and reset the argument; 1 means truncate the string. @return: the washed argument @exceptions raised: - ValueError: when it is not possible to cast an argument to the type passed as argreqdtype """ ## sanity checking: if maxstrlen is not None and type(maxstrlen) is not int: maxstrlen = None elif maxstrlen is int and maxstrlen < 1: maxstrlen = None if minstrlen is not None and type(minstrlen) is not int: minstrlen = None elif minstrlen is int and minstrlen < 1: minstrlen = None result = "" arg_dst_type = argreqdtype ## if no urlarg, return the default for that argument: if urlarg is None: result = argdefault return result ## get the type of the argument passed: arg_src_type = type(urlarg) value = urlarg # First, handle the case where we want all the results. In # this case, we need to ensure all the elements are strings, # and not Field instances. if arg_src_type in (list, tuple): if arg_dst_type is list: result = [str(x) for x in value] return result if arg_dst_type is tuple: result = tuple([str(x) for x in value]) return result # in all the other cases, we are only interested in the # first value. value = value[0] # Maybe we already have what is expected? Then don't change # anything. if arg_src_type is arg_dst_type: result = value if arg_dst_type is str and maxstrlen is not None and len(result) > maxstrlen: if truncatestr != 0: result = result[0:maxstrlen] else: result = argdefault elif arg_dst_type is str and minstrlen is not None and len(result) < minstrlen: result = argdefault return result if arg_dst_type in (str, int): try: result = arg_dst_type(value) if arg_dst_type is str and maxstrlen is not None and len(result) > maxstrlen: if truncatestr != 0: result = result[0:maxstrlen] else: result = argdefault elif arg_dst_type is str and minstrlen is not None and len(result) < minstrlen: result = argdefault except: result = argdefault elif arg_dst_type is tuple: result = (value,) elif arg_dst_type is list: result = [value] elif arg_dst_type is dict: result = {0: str(value)} else: raise ValueError('cannot cast form argument into type %r' % (arg_dst_type,)) return result ## Internal Business-Logic functions ## Functions for managing collection order, etc: def build_submission_collection_tree(collection_id, has_brother_above=0, has_brother_below=0): ## get the name of this collection: collection_name = get_collection_name(collection_id) if collection_name is None: collection_name = "Unknown Collection" ## make a data-structure containing the details of the collection: collection_node = { 'collection_id' : collection_id, ## collection ID 'collection_name' : collection_name, ## collection Name 'collection_children' : [], ## list of 'collection' children nodes 'doctype_children' : [], ## list of 'doctype' children 'has_brother_above' : has_brother_above, ## has a sibling collection above in score 'has_brother_below' : has_brother_below, ## has a sibling collection below in score } ## get the IDs and names of all doctypes attached to this collection: res_doctype_children = get_doctype_children_of_collection(collection_id) ## for each child, add its details to the list of doctype children for this node: for doctype in res_doctype_children: doctype_node = { 'doctype_id' : doctype[0], 'doctype_lname' : doctype[1], 'catalogue_order' : doctype[2], } collection_node['doctype_children'].append(doctype_node) ## now get details of all collections attached to this one: res_collection_children = get_collection_children_of_collection(collection_id) num_collection_children = len(res_collection_children) for child_num in xrange(0, num_collection_children): brother_below = brother_above = 0 if child_num > 0: ## this is not the first brother - it has a brother above brother_above = 1 if child_num < num_collection_children - 1: ## this is not the last brother - it has a brother below brother_below = 1 collection_node['collection_children'].append(\ build_submission_collection_tree(collection_id=res_collection_children[child_num][0], has_brother_above=brother_above, has_brother_below=brother_below)) - + ## return the built collection tree: return collection_node def _organise_submission_page_display_submission_tree(errors, warnings, user_msg=""): title = "Organise WebSubmit Main Page" body = "" if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode): user_msg = [] ## Get the submissions tree: submission_collection_tree = build_submission_collection_tree(0) ## Get all 'submission collections': submission_collections = get_details_of_all_submission_collections() sub_col = [('0', 'Top Level')] for collection in submission_collections: sub_col.append((str(collection[0]), str(collection[1]))) ## Get all document types: doctypes = get_docid_docname_and_docid_alldoctypes() ## build the page: body = websubmitadmin_templates.tmpl_display_submission_page_organisation(submission_collection_tree=submission_collection_tree, submission_collections=sub_col, doctypes=doctypes, user_msg=user_msg) return (title, body) def _delete_submission_collection(sbmcolid): """Recursively calls itself to delete a submission-collection and all of its attached children (and their children, etc) from the submission-tree. @param sbmcolid: (integer) - the ID of the submission-collection to be deleted. @return: None @Exceptions raised: InvenioWebSubmitAdminWarningDeleteFailed when it was not possible to delete the submission-collection or some of its children. """ ## Get the collection-children of this submission-collection: collection_children = get_collection_children_of_collection(sbmcolid) ## recursively move through each collection-child: for collection_child in collection_children: _delete_submission_collection(collection_child[0]) ## delete all document-types attached to this submission-collection: error_code = delete_doctype_children_from_submission_collection(sbmcolid) if error_code != 0: ## Unable to delete all doctype-children: err_msg = "Unable to delete doctype children of submission-collection [%s]" % sbmcolid raise InvenioWebSubmitAdminWarningDeleteFailed(err_msg) ## delete this submission-collection's entry from the sbmCOLLECTION_sbmCOLLECTION table: error_code = delete_submission_collection_from_submission_tree(sbmcolid) if error_code != 0: ## Unable to delete submission-collection from the submission-tree: err_msg = "Unable to delete submission-collection [%s] from submission-tree" % sbmcolid raise InvenioWebSubmitAdminWarningDeleteFailed(err_msg) ## Now delete this submission-collection's details: error_code = delete_submission_collection_details(sbmcolid) if error_code != 0: ## Unable to delete the details of the submission-collection: err_msg = "Unable to delete details of submission-collection [%s]" % sbmcolid raise InvenioWebSubmitAdminWarningDeleteFailed(err_msg) ## return return def perform_request_organise_submission_page(doctype="", sbmcolid="", catscore="", addsbmcollection="", deletesbmcollection="", addtosbmcollection="", adddoctypes="", movesbmcollectionup="", movesbmcollectiondown="", deletedoctypefromsbmcollection="", movedoctypeupinsbmcollection="", movedoctypedowninsbmcollection=""): user_msg = [] errors = [] warnings = [] body = "" if "" not in (deletedoctypefromsbmcollection, sbmcolid, catscore, doctype): ## delete a document type from it's position in the tree error_code = delete_doctype_from_position_on_submission_page(doctype, sbmcolid, catscore) if error_code == 0: ## doctype deleted - now normalize scores of remaining doctypes: normalize_scores_of_doctype_children_for_submission_collection(sbmcolid) user_msg.append("Document type successfully deleted from submissions tree") else: user_msg.append("Unable to delete document type from submission-collection") ## display submission-collections: (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) elif "" not in (deletesbmcollection, sbmcolid): ## try to delete the submission-collection from the tree: try: _delete_submission_collection(sbmcolid) user_msg.append("Submission-collection successfully deleted from submissions tree") except InvenioWebSubmitAdminWarningDeleteFailed, excptn: user_msg.append(str(excptn)) ## re-display submission-collections: (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) elif "" not in (movedoctypedowninsbmcollection, sbmcolid, doctype, catscore): ## move a doctype down in order for a submission-collection: ## normalize scores of all doctype-children of the submission-collection: normalize_scores_of_doctype_children_for_submission_collection(sbmcolid) ## swap this doctype with that below it: ## Get score of doctype to move: score_doctype_to_move = get_catalogue_score_of_doctype_child_of_submission_collection(sbmcolid, doctype) ## Get score of the doctype brother directly below the doctype to be moved: score_brother_below = get_score_of_next_doctype_child_below(sbmcolid, score_doctype_to_move) if None in (score_doctype_to_move, score_brother_below): user_msg.append("Unable to move document type down") else: ## update the brother below the doctype to be moved to have a score the same as the doctype to be moved: update_score_of_doctype_child_of_submission_collection_at_scorex(sbmcolid, score_brother_below, score_doctype_to_move) ## Update the doctype to be moved to have a score of the brother directly below it: update_score_of_doctype_child_of_submission_collection_with_doctypeid_and_scorex(sbmcolid, doctype, score_doctype_to_move, score_brother_below) user_msg.append("Document type moved down") (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) elif "" not in (movedoctypeupinsbmcollection, sbmcolid, doctype, catscore): ## move a doctype up in order for a submission-collection: ## normalize scores of all doctype-children of the submission-collection: normalize_scores_of_doctype_children_for_submission_collection(sbmcolid) ## swap this doctype with that above it: ## Get score of doctype to move: score_doctype_to_move = get_catalogue_score_of_doctype_child_of_submission_collection(sbmcolid, doctype) ## Get score of the doctype brother directly above the doctype to be moved: score_brother_above = get_score_of_previous_doctype_child_above(sbmcolid, score_doctype_to_move) if None in (score_doctype_to_move, score_brother_above): user_msg.append("Unable to move document type up") else: ## update the brother above the doctype to be moved to have a score the same as the doctype to be moved: update_score_of_doctype_child_of_submission_collection_at_scorex(sbmcolid, score_brother_above, score_doctype_to_move) ## Update the doctype to be moved to have a score of the brother directly above it: update_score_of_doctype_child_of_submission_collection_with_doctypeid_and_scorex(sbmcolid, doctype, score_doctype_to_move, score_brother_above) user_msg.append("Document type moved up") (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) elif "" not in (movesbmcollectiondown, sbmcolid): ## move a submission-collection down in order: - + ## Sanity checking: try: int(sbmcolid) except ValueError: sbmcolid = 0 if int(sbmcolid) != 0: ## Get father ID of submission-collection: sbmcolidfather = get_id_father_of_collection(sbmcolid) if sbmcolidfather is None: user_msg.append("Unable to move submission-collection downwards") else: ## normalize scores of all collection-children of the father submission-collection: normalize_scores_of_collection_children_of_collection(sbmcolidfather) ## swap this collection with the one above it: ## get the score of the collection to move: score_col_to_move = get_score_of_collection_child_of_submission_collection(sbmcolidfather, sbmcolid) ## get the score of the collection brother directly below the collection to be moved: score_brother_below = get_score_of_next_collection_child_below(sbmcolidfather, score_col_to_move) if None in (score_col_to_move, score_brother_below): ## Invalid movement user_msg.append("Unable to move submission collection downwards") else: ## update the brother below the collection to be moved to have a score the same as the collection to be moved: update_score_of_collection_child_of_submission_collection_at_scorex(sbmcolidfather, score_brother_below, score_col_to_move) ## Update the collection to be moved to have a score of the brother directly below it: update_score_of_collection_child_of_submission_collection_with_colid_and_scorex(sbmcolidfather, sbmcolid, score_col_to_move, score_brother_below) user_msg.append("Submission-collection moved downwards") else: ## cannot move the master (0) collection user_msg.append("Unable to move submission-collection downwards") (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) elif "" not in (movesbmcollectionup, sbmcolid): ## move a submission-collection up in order: ## Sanity checking: try: int(sbmcolid) except ValueError: sbmcolid = 0 if int(sbmcolid) != 0: ## Get father ID of submission-collection: sbmcolidfather = get_id_father_of_collection(sbmcolid) if sbmcolidfather is None: user_msg.append("Unable to move submission-collection upwards") else: ## normalize scores of all collection-children of the father submission-collection: normalize_scores_of_collection_children_of_collection(sbmcolidfather) ## swap this collection with the one above it: ## get the score of the collection to move: score_col_to_move = get_score_of_collection_child_of_submission_collection(sbmcolidfather, sbmcolid) ## get the score of the collection brother directly above the collection to be moved: score_brother_above = get_score_of_previous_collection_child_above(sbmcolidfather, score_col_to_move) if None in (score_col_to_move, score_brother_above): ## Invalid movement user_msg.append("Unable to move submission collection upwards") else: ## update the brother above the collection to be moved to have a score the same as the collection to be moved: update_score_of_collection_child_of_submission_collection_at_scorex(sbmcolidfather, score_brother_above, score_col_to_move) ## Update the collection to be moved to have a score of the brother directly above it: update_score_of_collection_child_of_submission_collection_with_colid_and_scorex(sbmcolidfather, sbmcolid, score_col_to_move, score_brother_above) user_msg.append("Submission-collection moved upwards") else: ## cannot move the master (0) collection user_msg.append("Unable to move submission-collection upwards") (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) elif "" not in (addsbmcollection, addtosbmcollection): ## Add a submission-collection, attached to a submission-collection: ## check that the collection to attach to exists: parent_ok = 0 if int(addtosbmcollection) != 0: parent_name = get_collection_name(addtosbmcollection) if parent_name is not None: parent_ok = 1 else: parent_ok = 1 if parent_ok != 0: ## create the new collection: id_son = insert_submission_collection(addsbmcollection) ## get the maximum catalogue score of the existing collection children: max_child_score = \ get_maximum_catalogue_score_of_collection_children_of_submission_collection(addtosbmcollection) ## add it to the collection, at a higher score than the others have: new_score = max_child_score + 1 insert_collection_child_for_submission_collection(addtosbmcollection, id_son, new_score) user_msg.append("Submission-collection added to submissions tree") else: ## Parent submission-collection does not exist: user_msg.append("Unable to add submission-collection - parent unknown") (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) elif "" not in (adddoctypes, addtosbmcollection): ## Add document type(s) to a submission-collection: if type(adddoctypes) == str: adddoctypes = [adddoctypes,] ## Does submission-collection exist? num_collections_sbmcolid = get_number_of_rows_for_submission_collection(addtosbmcollection) if num_collections_sbmcolid > 0: for doctypeid in adddoctypes: ## Check that Doctype exists: num_doctypes_doctypeid = get_number_doctypes_docid(doctypeid) if num_doctypes_doctypeid < 1: ## Cannot connect an unknown doctype: user_msg.append("Unable to connect unknown document-type [%s] to a submission-collection" \ % doctypeid) continue else: ## insert the submission-collection/doctype link: ## get the maximum catalogue score of the existing doctype children: max_child_score = \ get_maximum_catalogue_score_of_doctype_children_of_submission_collection(addtosbmcollection) ## add it to the new doctype, at a higher score than the others have: new_score = max_child_score + 1 insert_doctype_child_for_submission_collection(addtosbmcollection, doctypeid, new_score) user_msg.append("Document-type added to submissions tree") else: ## submission-collection didn't exist user_msg.append("The selected submission-collection doesn't seem to exist") ## Check that submission-collection exists: ## insert (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) else: ## default action - display submission-collections: (title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg) return (title, body, errors, warnings) ## Functions for adding new catalgue to DB: def _add_new_action(actid,actname,working_dir,status_text): """Insert the details of a new action into the websubmit system database. @param actid: unique action id (sactname) @param actname: action name (lactname) @param working_dir: directory action works from (dir) @param status_text: text string indicating action status (statustext) """ (actid,actname,working_dir,status_text) = (str(actid).upper(),str(actname),str(working_dir),str(status_text)) err_code = insert_action_details(actid,actname,working_dir,status_text) return err_code def perform_request_add_function(funcname=None, funcdescr=None, funcaddcommit=""): user_msg = [] errors = [] warnings = [] body = "" title = "Create New WebSubmit Function" commit_error=0 ## wash args: if funcname is not None: try: funcname = wash_single_urlarg(urlarg=funcname, argreqdtype=str, argdefault="", maxstrlen=40, minstrlen=1) if function_name_is_valid(fname=funcname) == 0: funcname = "" except ValueError, e: funcname = "" else: funcname = "" if funcdescr is not None: try: funcdescr = wash_single_urlarg(urlarg=funcdescr, argreqdtype=str, argdefault="") except ValueError, e: funcdescr = "" else: funcdescr = "" ## process request: if funcaddcommit != "" and funcaddcommit is not None: if funcname == "": funcname = "" user_msg.append("""Function name is mandatory and must be a string with no more than 40 characters""") user_msg.append("""It must contain only alpha-numeric and underscore characters, beginning with a """\ """letter or underscore""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user body = websubmitadmin_templates.tmpl_display_addfunctionform(funcdescr=funcdescr, user_msg=user_msg) return (title, body, errors, warnings) ## Add a new function definition - IF it is not already present err_code = insert_function_details(funcname, funcdescr) ## Handle error code - redisplay form with warning about no DB commit, or display with options ## to edit function: if err_code == 0: user_msg.append("""'%s' Function Added to WebSubmit""" % (funcname,)) all_function_parameters = get_distinct_paramname_all_websubmit_function_parameters() body = websubmitadmin_templates.tmpl_display_addfunctionform(funcname=funcname, funcdescr=funcdescr, all_websubmit_func_parameters=all_function_parameters, perform_act="functionedit", user_msg=user_msg) else: ## Could not commit function to WebSubmit DB - redisplay form with function description: user_msg.append("""Could Not Add '%s' Function to WebSubmit""" % (funcname,)) body = websubmitadmin_templates.tmpl_display_addfunctionform(funcdescr=funcdescr, user_msg=user_msg) else: ## Display Web form for new function addition: body = websubmitadmin_templates.tmpl_display_addfunctionform() return (title, body, errors, warnings) def perform_request_add_action(actid=None, actname=None, working_dir=None, status_text=None, actcommit=""): """An interface for the addition of a new WebSubmit action. If form fields filled, will insert new action into WebSubmit database, else will display web form prompting for action details. @param actid: unique id for new action @param actname: name of new action @param working_dir: action working directory for WebSubmit core @param status_text: status text displayed at end of action @return: tuple containing "title" (title of page), body (page body), errors (list of errors), warnings (list of warnings). """ user_msg = [] errors = [] warnings = [] body = "" title = "Create New WebSubmit Action" commit_error=0 ## wash args: if actid is not None: try: actid = wash_single_urlarg(urlarg=actid, argreqdtype=str, argdefault="", maxstrlen=3, minstrlen=3) if string_is_alphanumeric_including_underscore(txtstring=actid) == 0: actid = "" except ValueError, e: actid = "" else: actid = "" if actname is not None: try: actname = wash_single_urlarg(urlarg=actname, argreqdtype=str, argdefault="") except ValueError, e: actname = "" else: actname = "" if working_dir is not None: try: working_dir = wash_single_urlarg(urlarg=working_dir, argreqdtype=str, argdefault="") except ValueError, e: working_dir = "" else: working_dir = "" if status_text is not None: try: status_text = wash_single_urlarg(urlarg=status_text, argreqdtype=str, argdefault="") except ValueError, e: status_text = "" else: status_text = "" ## process request: if actcommit != "" and actcommit is not None: if actid in ("", None): actid = "" user_msg.append("""Action ID is mandatory and must be a 3 letter string""") commit_error = 1 if actname in ("", None): actname = "" user_msg.append("""Action description is mandatory""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user body = websubmitadmin_templates.tmpl_display_addactionform(actid=actid, actname=actname, working_dir=working_dir,\ status_text=status_text, user_msg=user_msg) return (title, body, errors, warnings) ## Commit new action to WebSubmit DB: err_code = _add_new_action(actid,actname,working_dir,status_text) ## Handle error code - redisplay form with warning about no DB commit, or move to list ## of actions if err_code == 0: ## Action added: show page listing WebSubmit actions user_msg = """'%s' Action Added to WebSubmit""" % (actid,) all_actions = get_actid_actname_allactions() body = websubmitadmin_templates.tmpl_display_allactions(all_actions,user_msg=user_msg) title = "Available WebSubmit Actions" else: ## Could not commit action to WebSubmit DB redisplay form with completed details and error message ## warnings.append(('ERR_WEBSUBMIT_ADMIN_ADDACTIONFAILDUPLICATE',actid) ## TODO user_msg = """Could Not Add '%s' Action to WebSubmit""" % (actid,) body = websubmitadmin_templates.tmpl_display_addactionform(actid=actid, actname=actname, working_dir=working_dir, \ status_text=status_text, user_msg=user_msg) else: ## Display Web form for new action details: body = websubmitadmin_templates.tmpl_display_addactionform() return (title, body, errors, warnings) def perform_request_add_jscheck(chname=None, chdesc=None, chcommit=""): """An interface for the addition of a new WebSubmit JavaScript Check, as used on form elements. If form fields filled, will insert new Check into WebSubmit database, else will display Web form prompting for Check details. @param chname: unique id/name for new Check @param chdesc: description (JavaScript code body) of new Check @return: tuple containing "title" (title of page), body (page body), errors (list of errors), warnings (list of warnings). """ user_msg = [] errors = [] warnings = [] body = "" title = "Create New WebSubmit Checking Function" commit_error=0 ## wash args: if chname is not None: try: chname = wash_single_urlarg(urlarg=chname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1) if function_name_is_valid(fname=chname) == 0: chname = "" except ValueError, e: chname = "" else: chname = "" if chdesc is not None: try: chdesc = wash_single_urlarg(urlarg=chdesc, argreqdtype=str, argdefault="") except ValueError, e: chdesc = "" else: chdesc = "" ## process request: if chcommit != "" and chcommit is not None: if chname in ("", None): chname = "" user_msg.append("""Check name is mandatory and must be a string with no more than 15 characters""") user_msg.append("""It must contain only alpha-numeric and underscore characters, beginning with a """\ """letter or underscore""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=chname, chdesc=chdesc, user_msg=user_msg) return (title, body, errors, warnings) ## Commit new check to WebSubmit DB: err_code = insert_jscheck_details(chname, chdesc) ## Handle error code - redisplay form wih warning about no DB commit, or move to list ## of checks if err_code == 0: ## Check added: show page listing WebSubmit JS Checks user_msg.append("""'%s' Checking Function Added to WebSubmit""" % (chname,)) all_jschecks = get_chname_alljschecks() body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg) title = "Available WebSubmit Checking Functions" else: ## Could not commit Check to WebSubmit DB: redisplay form with completed details and error message ## TODO : Warning Message user_msg.append("""Could Not Add '%s' Checking Function to WebSubmit""" % (chname,)) body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=chname, chdesc=chdesc, user_msg=user_msg) else: ## Display Web form for new check details: body = websubmitadmin_templates.tmpl_display_addjscheckform() return (title, body, errors, warnings) def perform_request_add_element(elname=None, elmarccode=None, eltype=None, elsize=None, elrows=None, \ elcols=None, elmaxlength=None, elval=None, elfidesc=None, \ elmodifytext=None, elcommit=""): """An interface for adding a new ELEMENT to the WebSubmit DB. @param elname: (string) element name. @param elmarccode: (string) element's MARC code. @param eltype: (character) element type. @param elsize: (integer) element size. @param elrows: (integer) number of rows in element. @param elcols: (integer) number of columns in element. @param elmaxlength: (integer) maximum length of element @param elval: (string) default value of element @param elfidesc: (string) description of element @param elmodifytext: (string) modification text of element @param elcommit: (string) If this value is not empty, attempt to commit element details to WebSubmit DB @return: tuple containing "title" (title of page), body (page body), errors (list of errors), warnings (list of warnings). """ user_msg = [] errors = [] warnings = [] body = "" title = "Create New WebSubmit Element" commit_error=0 ## wash args: if elname is not None: try: elname = wash_single_urlarg(urlarg=elname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=elname) == 0: elname = "" except ValueError, e: elname = "" else: elname = "" if elmarccode is not None: try: elmarccode = wash_single_urlarg(urlarg=elmarccode, argreqdtype=str, argdefault="") except ValueError, e: elmarccode = "" else: elmarccode = "" if eltype is not None: try: eltype = wash_single_urlarg(urlarg=eltype, argreqdtype=str, argdefault="", maxstrlen=1, minstrlen=1) except ValueError, e: eltype = "" else: eltype = "" if elsize is not None: try: elsize = wash_single_urlarg(urlarg=elsize, argreqdtype=int, argdefault="") except ValueError, e: elsize = "" else: elsize = "" if elrows is not None: try: elrows = wash_single_urlarg(urlarg=elrows, argreqdtype=int, argdefault="") except ValueError, e: elrows = "" else: elrows = "" if elcols is not None: try: elcols = wash_single_urlarg(urlarg=elcols, argreqdtype=int, argdefault="") except ValueError, e: elcols = "" else: elcols = "" if elmaxlength is not None: try: elmaxlength = wash_single_urlarg(urlarg=elmaxlength, argreqdtype=int, argdefault="") except ValueError, e: elmaxlength = "" else: elmaxlength = "" if elval is not None: try: elval = wash_single_urlarg(urlarg=elval, argreqdtype=str, argdefault="") except ValueError, e: elval = "" else: elval = "" if elfidesc is not None: try: elfidesc = wash_single_urlarg(urlarg=elfidesc, argreqdtype=str, argdefault="") except ValueError, e: elfidesc = "" else: elfidesc = "" if elmodifytext is not None: try: elmodifytext = wash_single_urlarg(urlarg=elmodifytext, argreqdtype=str, argdefault="") except ValueError, e: elmodifytext = "" else: elmodifytext = "" ## process request: if elcommit != "" and elcommit is not None: if elname == "": elname = "" user_msg.append("""The element name is mandatory and must be a string with no more than 15 characters""") user_msg.append("""It must contain only alpha-numeric and underscore characters""") commit_error = 1 if eltype == "" or eltype not in ("D", "F", "H", "I", "R", "S", "T"): eltype = "" user_msg.append("""The element type is mandatory and must be selected from the list""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname, elmarccode=elmarccode, eltype=eltype, elsize=str(elsize), elrows=str(elrows), elcols=str(elcols), elmaxlength=str(elmaxlength), elval=elval, elfidesc=elfidesc, elmodifytext=elmodifytext, user_msg=user_msg, ) return (title, body, errors, warnings) ## Commit new element description to WebSubmit DB: err_code = insert_element_details(elname=elname, elmarccode=elmarccode, eltype=eltype, \ elsize=elsize, elrows=elrows, elcols=elcols, \ elmaxlength=elmaxlength, elval=elval, elfidesc=elfidesc, \ elmodifytext=elmodifytext) if err_code == 0: ## Element added: show page listing WebSubmit elements user_msg.append("""'%s' Element Added to WebSubmit""" % (elname,)) title = "Available WebSubmit Elements" all_elements = get_elename_allelements() body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg) else: ## Could not commit element to WebSubmit DB: redisplay form with completed details and error message ## TODO : Warning Message user_msg.append("""Could Not Add '%s' Element to WebSubmit""" % (elname,)) body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname, elmarccode=elmarccode, eltype=eltype, elsize=str(elsize), elrows=str(elrows), elcols=str(elcols), elmaxlength=str(elmaxlength), elval=elval, elfidesc=elfidesc, elmodifytext=elmodifytext, user_msg=user_msg, ) else: ## Display Web form for new element details: body = websubmitadmin_templates.tmpl_display_addelementform() return (title, body, errors, warnings) def perform_request_edit_element(elname, elmarccode=None, eltype=None, elsize=None, \ elrows=None, elcols=None, elmaxlength=None, elval=None, \ elfidesc=None, elmodifytext=None, elcommit=""): """An interface for the editing and updating the details of a WebSubmit ELEMENT. @param elname: element name. @param elmarccode: element's MARC code. @param eltype: element type. @param elsize: element size. @param elrows: number of rows in element. @param elcols: number of columns in element. @param elmaxlength: maximum length of element @param elval: default value of element @param elfidesc: description of element @param elmodifytext: modification text of element @param elcommit: If this value is not empty, attempt to commit element details to WebSubmit DB @return: tuple containing "title" (title of page), body (page body), errors (list of errors), warnings (list of warnings). """ user_msg = [] errors = [] warnings = [] body = "" title = "Edit WebSubmit Element" commit_error=0 ## wash args: if elname is not None: try: elname = wash_single_urlarg(urlarg=elname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=elname) == 0: elname = "" except ValueError, e: elname = "" else: elname = "" if elmarccode is not None: try: elmarccode = wash_single_urlarg(urlarg=elmarccode, argreqdtype=str, argdefault="") except ValueError, e: elmarccode = "" else: elmarccode = "" if eltype is not None: try: eltype = wash_single_urlarg(urlarg=eltype, argreqdtype=str, argdefault="", maxstrlen=1, minstrlen=1) except ValueError, e: eltype = "" else: eltype = "" if elsize is not None: try: elsize = wash_single_urlarg(urlarg=elsize, argreqdtype=int, argdefault="") except ValueError, e: elsize = "" else: elsize = "" if elrows is not None: try: elrows = wash_single_urlarg(urlarg=elrows, argreqdtype=int, argdefault="") except ValueError, e: elrows = "" else: elrows = "" if elcols is not None: try: elcols = wash_single_urlarg(urlarg=elcols, argreqdtype=int, argdefault="") except ValueError, e: elcols = "" else: elcols = "" if elmaxlength is not None: try: elmaxlength = wash_single_urlarg(urlarg=elmaxlength, argreqdtype=int, argdefault="") except ValueError, e: elmaxlength = "" else: elmaxlength = "" if elval is not None: try: elval = wash_single_urlarg(urlarg=elval, argreqdtype=str, argdefault="") except ValueError, e: elval = "" else: elval = "" if elfidesc is not None: try: elfidesc = wash_single_urlarg(urlarg=elfidesc, argreqdtype=str, argdefault="") except ValueError, e: elfidesc = "" else: elfidesc = "" if elmodifytext is not None: try: elmodifytext = wash_single_urlarg(urlarg=elmodifytext, argreqdtype=str, argdefault="") except ValueError, e: elmodifytext = "" else: elmodifytext = "" ## process request: if elcommit != "" and elcommit is not None: if elname == "": elname = "" user_msg.append("""Invalid Element Name!""") commit_error = 1 if eltype == "" or eltype not in ("D", "F", "H", "I", "R", "S", "T"): eltype = "" user_msg.append("""Invalid Element Type!""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user all_elements = get_elename_allelements() user_msg.append("""Could Not Update Element""") title = "Available WebSubmit Elements" body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg) return (title, body, errors, warnings) ## Commit updated element description to WebSubmit DB: err_code = update_element_details(elname=elname, elmarccode=elmarccode, eltype=eltype, \ elsize=elsize, elrows=elrows, elcols=elcols, \ elmaxlength=elmaxlength, elval=elval, elfidesc=elfidesc, \ elmodifytext=elmodifytext) if err_code == 0: ## Element Updated: Show All Element Details Again user_msg.append("""'%s' Element Updated""" % (elname,)) ## Get submission page usage of element: el_use = get_doctype_action_pagenb_for_submissions_using_element(elname) element_dets = get_element_details(elname) element_dets = stringify_listvars(element_dets) ## Take elements from results tuple: (elmarccode, eltype, elsize, elrows, elcols, elmaxlength, \ elval, elfidesc, elcd, elmd, elmodifytext) = \ (element_dets[0][0], element_dets[0][1], element_dets[0][2], element_dets[0][3], \ element_dets[0][4], element_dets[0][5], element_dets[0][6], element_dets[0][7], \ element_dets[0][8], element_dets[0][9], element_dets[0][10]) ## Pass to template: body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname, elmarccode=elmarccode, eltype=eltype, elsize=elsize, elrows=elrows, elcols=elcols, elmaxlength=elmaxlength, elval=elval, elfidesc=elfidesc, elcd=elcd, elmd=elmd, elmodifytext=elmodifytext, perform_act="elementedit", user_msg=user_msg, el_use_tuple=el_use ) else: ## Could Not Update Element: Maybe Key Violation, or Invalid elname? Redisplay all elements. ## TODO : LOGGING all_elements = get_elename_allelements() user_msg.append("""Could Not Update Element '%s'""" % (elname,)) title = "Available WebSubmit Elements" body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg) else: ## Display Web form containing existing details of element: element_dets = get_element_details(elname) ## Get submission page usage of element: el_use = get_doctype_action_pagenb_for_submissions_using_element(elname) num_rows_ret = len(element_dets) element_dets = stringify_listvars(element_dets) if num_rows_ret == 1: ## Display Element details ## Take elements from results tuple: (elmarccode, eltype, elsize, elrows, elcols, elmaxlength, \ elval, elfidesc, elcd, elmd, elmodifytext) = \ (element_dets[0][0], element_dets[0][1], element_dets[0][2], element_dets[0][3], \ element_dets[0][4], element_dets[0][5], element_dets[0][6], element_dets[0][7], \ element_dets[0][8], element_dets[0][9], element_dets[0][10]) ## Pass to template: body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname, elmarccode=elmarccode, eltype=eltype, elsize=elsize, elrows=elrows, elcols=elcols, elmaxlength=elmaxlength, elval=elval, elfidesc=elfidesc, elcd=elcd, elmd=elmd, elmodifytext=elmodifytext, perform_act="elementedit", el_use_tuple=el_use ) else: ## Either no rows, or more than one row for ELEMENT: log error, and display all Elements ## TODO : LOGGING title = "Available WebSubmit Elements" all_elements = get_elename_allelements() if num_rows_ret > 1: ## Key Error - duplicated elname user_msg.append("""Found Several Rows for Element with Name '%s' - Inform Administrator""" % (elname,)) ## LOG MESSAGE else: ## No rows for ELEMENT user_msg.append("""Could Not Find Any Rows for Element with Name '%s'""" % (elname,)) ## LOG MESSAGE body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg) return (title, body, errors, warnings) def _display_edit_check_form(errors, warnings, chname, user_msg=""): title = "Edit WebSubmit Checking Function" if user_msg == "": user_msg = [] jscheck_dets = get_jscheck_details(chname) num_rows_ret = len(jscheck_dets) if num_rows_ret == 1: ## Display Check details body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=jscheck_dets[0][0], chdesc=jscheck_dets[0][1], perform_act="jscheckedit", cd=jscheck_dets[0][2], md=jscheck_dets[0][3], user_msg=user_msg) else: ## Either no rows, or more than one row for Check: log error, and display all Checks ## TODO : LOGGING title = "Available WebSubmit Checking Functions" all_jschecks = get_chname_alljschecks() if num_rows_ret > 1: ## Key Error - duplicated chname user_msg.append("""Found Several Rows for Checking Function with Name '%s' - Inform Administrator""" % (chname,)) ## LOG MESSAGE else: ## No rows for action user_msg.append("""Could Not Find Any Rows for Checking Function with Name '%s'""" % (chname,)) ## LOG MESSAGE body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg) return (title, body) def perform_request_edit_jscheck(chname, chdesc=None, chcommit=""): """Interface for editing and updating the details of a WebSubmit Check. If only "chname" provided, will display the details of a Check in a Web form. If "chdesc" not empty, will assume that this is a call to commit update to Check details. @param chname: unique id for Check @param chdesc: modified value for WebSubmit Check description (code body) - (presence invokes update) @return: tuple containing "title" (title of page), body (page body), errors (list of errors), warnings (list of warnings). """ user_msg = [] errors = [] warnings = [] body = "" title = "Edit WebSubmit Checking Function" commit_error=0 ## wash args: if chname is not None: try: chname = wash_single_urlarg(urlarg=chname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1) if function_name_is_valid(fname=chname) == 0: chname = "" except ValueError, e: chname = "" else: chname = "" if chdesc is not None: try: chdesc = wash_single_urlarg(urlarg=chdesc, argreqdtype=str, argdefault="") except ValueError, e: chdesc = "" else: chdesc = "" (chname, chdesc) = (str(chname), str(chdesc)) if chcommit != "" and chcommit is not None: if chname in ("", None): chname = "" user_msg.append("""Check name is mandatory and must be a string with no more than 15 characters""") user_msg.append("""It must contain only alpha-numeric and underscore characters, beginning with a """\ """letter or underscore""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user all_jschecks = get_chname_alljschecks() user_msg.append("""Could Not Update Checking Function""") body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg) title = "Available WebSubmit Checking Functions" return (title, body, errors, warnings) ## Commit updated Check details to WebSubmit DB: err_code = update_jscheck_details(chname, chdesc) if err_code == 0: ## Check Updated: Show All Check Details Again user_msg.append("""'%s' Check Updated""" % (chname,)) jscheck_dets = get_jscheck_details(chname) body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=jscheck_dets[0][0], chdesc=jscheck_dets[0][1], perform_act="jscheckedit", cd=jscheck_dets[0][2], md=jscheck_dets[0][3], user_msg=user_msg ) else: ## Could Not Update Check: Maybe Key Violation, or Invalid chname? Redisplay all Checks. ## TODO : LOGGING all_jschecks = get_chname_alljschecks() user_msg.append("""Could Not Update Checking Function '%s'""" % (chname,)) body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg) title = "Available WebSubmit Checking Functions" else: ## Display Web form containing existing details of Check: (title, body) = _display_edit_check_form(errors, warnings, chname=chname) return (title, body, errors, warnings) def _display_edit_action_form(errors, warnings, actid, user_msg=""): title = "Edit WebSubmit Action" if user_msg == "": user_msg = [] action_dets = get_action_details(actid) num_rows_ret = len(action_dets) if num_rows_ret == 1: ## Display action details body = websubmitadmin_templates.tmpl_display_addactionform(actid=action_dets[0][0], actname=action_dets[0][1], working_dir=action_dets[0][2], status_text=action_dets[0][3], perform_act="actionedit", cd=action_dets[0][4], md=action_dets[0][5], user_msg=user_msg) else: ## Either no rows, or more than one row for action: log error, and display all actions ## TODO : LOGGING title = "Available WebSubmit Actions" all_actions = get_actid_actname_allactions() if num_rows_ret > 1: ## Key Error - duplicated actid user_msg.append("""Found Several Rows for Action with ID '%s' - Inform Administrator""" % (actid,)) ## LOG MESSAGE else: ## No rows for action user_msg.append("""Could Not Find Any Rows for Action with ID '%s'""" % (actid,)) ## LOG MESSAGE body = websubmitadmin_templates.tmpl_display_allactions(all_actions, user_msg=user_msg) return (title, body) def perform_request_edit_action(actid, actname=None, working_dir=None, status_text=None, actcommit=""): """Interface for editing and updating the details of a WebSubmit action. If only "actid" provided, will display the details of an action in a Web form. If "actname" not empty, will assume that this is a call to commit update to action details. @param actid: unique id for action @param actname: modified value for WebSubmit action name/description (presence invokes update) @param working_dir: modified value for WebSubmit action working_dir @param status_text: modified value for WebSubmit action status text @return: tuple containing "title" (title of page), body (page body), errors (list of errors), warnings (list of warnings). """ user_msg = [] errors = [] warnings = [] body = "" title = "Edit WebSubmit Action" commit_error = 0 ## wash args: if actid is not None: try: actid = wash_single_urlarg(urlarg=actid, argreqdtype=str, argdefault="", maxstrlen=3, minstrlen=3) if string_is_alphanumeric_including_underscore(txtstring=actid) == 0: actid = "" except ValueError, e: actid = "" actid = actid.upper() else: actid = "" if actname is not None: try: actname = wash_single_urlarg(urlarg=actname, argreqdtype=str, argdefault="") except ValueError, e: actname = "" else: actname = "" if working_dir is not None: try: working_dir = wash_single_urlarg(urlarg=working_dir, argreqdtype=str, argdefault="") except ValueError, e: working_dir = "" else: working_dir = "" if status_text is not None: try: status_text = wash_single_urlarg(urlarg=status_text, argreqdtype=str, argdefault="") except ValueError, e: status_text = "" else: status_text = "" ## process request: if actcommit != "" and actcommit is not None: if actname in ("", None): actname = "" user_msg.append("""Action description is mandatory""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user (title, body) = _display_edit_action_form(errors=errors, warnings=warnings, actid=actid, user_msg=user_msg) return (title, body, errors, warnings) ## Commit updated action details to WebSubmit DB: err_code = update_action_details(actid, actname, working_dir, status_text) if err_code == 0: ## Action Updated: Show Action Details Again user_msg.append("""'%s' Action Updated""" % (actid,)) action_dets = get_action_details(actid) body = websubmitadmin_templates.tmpl_display_addactionform(actid=action_dets[0][0], actname=action_dets[0][1], working_dir=action_dets[0][2], status_text=action_dets[0][3], perform_act="actionedit", cd=action_dets[0][4], md=action_dets[0][5], user_msg=user_msg ) else: ## Could Not Update Action: Maybe Key Violation, or Invalid actid? Redisplay all actions. ## TODO : LOGGING all_actions = get_actid_actname_allactions() user_msg.append("""Could Not Update Action '%s'""" % (actid,)) body = websubmitadmin_templates.tmpl_display_allactions(all_actions, user_msg=user_msg) title = "Available WebSubmit Actions" else: ## Display Web form containing existing details of action: (title, body) = _display_edit_action_form(errors=errors, warnings=warnings, actid=actid) return (title, body, errors, warnings) def _functionedit_display_function_details(errors, warnings, funcname, user_msg=""): """Display the details of a function, along with any message to the user that may have been provided. @param errors: LIST of errors (passed by reference from caller) - errors will be appended to it @param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it @param funcname: unique name of function to be updated @param user_msg: Any message to the user that is to be displayed on the page. @return: tuple containing (page title, HTML page body). """ if user_msg == "": user_msg = [] title = "Edit WebSubmit Function" func_descr_res = get_function_description(function=funcname) num_rows_ret = len(func_descr_res) if num_rows_ret == 1: ## Display action details funcdescr = func_descr_res[0][0] if funcdescr is None: funcdescr = "" ## get parameters for this function: this_function_parameters = get_function_parameters(function=funcname) ## get all function parameters in WebSubmit: all_function_parameters = get_distinct_paramname_all_websubmit_function_parameters() body = websubmitadmin_templates.tmpl_display_addfunctionform(funcname=funcname, funcdescr=funcdescr, func_parameters=this_function_parameters, all_websubmit_func_parameters=all_function_parameters, perform_act="functionedit", user_msg=user_msg ) else: ## Either no rows, or more than one row for function: log error, and display all functions ## TODO : LOGGING title = "Available WebSubmit Functions" all_functions = get_funcname_funcdesc_allfunctions() if num_rows_ret > 1: ## Key Error - duplicated function name user_msg.append("""Found Several Rows for Function with Name '%s' - Inform Administrator""" % (funcname,)) ## LOG MESSAGE else: ## No rows for function user_msg.append("""Could Not Find Any Rows for Function with Name '%s'""" % (funcname,)) ## LOG MESSAGE body = websubmitadmin_templates.tmpl_display_allfunctions(all_functions, user_msg=user_msg) return (title, body) def _functionedit_update_description(errors, warnings, funcname, funcdescr): """Perform an update of the description for a given function. @param errors: LIST of errors (passed by reference from caller) - errors will be appended to it @param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it @param funcname: unique name of function to be updated @param funcdescr: description to be updated for funcname @return: a tuple containing (page title, HTML body content) """ user_msg = [] err_code = update_function_description(funcname, funcdescr) if err_code == 0: ## Function updated - redisplay user_msg.append("""'%s' Function Description Updated""" % (funcname,)) else: ## Could not update function description ## TODO : ERROR LIBS user_msg.append("""Could Not Update Description for Function '%s'""" % (funcname,)) ## Display function details (title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname, user_msg=user_msg) return (title, body) def _functionedit_delete_parameter(errors, warnings, funcname, deleteparam): """Delete a parameter from a given function. Important: if any document types have been using the function from which this parameter will be deleted, and therefore have values for this parameter, these values will not be deleted from the WebSubmit DB. The deleted parameter therefore may continue to exist in the WebSubmit DB, but will be disassociated from this function. @param errors: LIST of errors (passed by reference from caller) - errors will be appended to it @param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it @param funcname: unique name of the function from which the parameter is to be deleted. @param deleteparam: the name of the parameter to be deleted from the function. @return: tuple containing (title, HTML body content) """ user_msg = [] err_code = delete_function_parameter(function=funcname, parameter_name=deleteparam) if err_code == 0: ## Parameter deleted - redisplay function details user_msg.append("""'%s' Parameter Deleted from '%s' Function""" % (deleteparam, funcname)) else: ## could not delete param - it does not exist for this function ## TODO : ERROR LIBS user_msg.append("""'%s' Parameter Does not Seem to Exist for Function '%s' - Could not Delete""" \ % (deleteparam, funcname)) ## Display function details (title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname, user_msg=user_msg) return (title, body) def _functionedit_add_parameter(errors, warnings, funcname, funceditaddparam="", funceditaddparamfree=""): """Add (connect) a parameter to a given WebSubmit function. @param errors: LIST of errors (passed by reference from caller) - errors will be appended to it @param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it @param funcname: unique name of the function to which the parameter is to be added. @param funceditaddparam: the value of a HTML select list: if present, will contain the name of the parameter to be added to the function. May also be empty - the user may have used the free-text field (funceditaddparamfree) to manually enter the name of a parameter. The important thing is that one must be present for the parameter to be added sucessfully. @param funceditaddparamfree: The name of the parameter to be added to the function, as taken from a free- text HTML input field. May also be empty - the user may have used the HTML select-list (funceditaddparam) field to choose the parameter. The important thing is that one must be present for the parameter to be added sucessfully. The value "funceditaddparamfree" value will take priority over the "funceditaddparam" list value. @return: tuple containing (title, HTML body content) """ user_msg = [] if funceditaddparam in ("", None, "NO_VALUE") and funceditaddparamfree in ("", None): ## no parameter chosen ## TODO : ERROR LIBS user_msg.append("""Unable to Find the Parameter to be Added to Function '%s' - Could not Add""" % (funcname,)) else: add_parameter = "" if funceditaddparam not in ("", None) and funceditaddparamfree not in ("", None): ## both select box and free-text values provided for parameter - prefer free-text add_parameter = funceditaddparamfree elif funceditaddparam not in ("", None): ## take add select-box chosen parameter add_parameter = funceditaddparam else: ## take add free-text chosen parameter add_parameter = funceditaddparamfree ## attempt to commit parameter: err_code = add_function_parameter(function=funcname, parameter_name=add_parameter) if err_code == 0: ## Parameter added - redisplay function details user_msg.append("""'%s' Parameter Added to '%s' Function""" % (add_parameter, funcname)) else: ## could not add param - perhaps it already exists for this function ## TODO : ERROR LIBS user_msg.append("""Could not Add '%s' Parameter to Function '%s' - It Already Exists for this Function""" \ % (add_parameter, funcname)) ## Display function details (title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname, user_msg=user_msg) return (title, body) def perform_request_edit_function(funcname, funcdescr=None, funceditaddparam=None, funceditaddparamfree=None, funceditdelparam=None, funcdescreditcommit="", funcparamdelcommit="", funcparamaddcommit=""): """Edit a WebSubmit function. 3 possibilities: edit the function description; delete a parameter from the function; add a new parameter to the function. @param funcname: the name of the function to be modified @param funcdescr: the new function description @param funceditaddparam: the name of the parameter to be added to the function (taken from HTML SELECT-list) @param funceditaddparamfree: the name of the parameter to be added to the function (taken from free-text input) @param funceditdelparam: the name of the parameter to be deleted from the function @param funcdescreditcommit: a flag to indicate that this request is to update the description of a function @param funcparamdelcommit: a flag to indicate that this request is to delete a parameter from a function @param funcparamaddcommit: a flag to indicate that this request is to add a new parameter to a function @return: tuple containing (page title, HTML page body, list of errors encountered, list of warnings) """ errors = [] warnings = [] body = "" title = "Edit WebSubmit Function" commit_error = 0 ## wash args: if funcname is not None: try: funcname = wash_single_urlarg(urlarg=funcname, argreqdtype=str, argdefault="") if string_is_alphanumeric_including_underscore(txtstring=funcname) == 0: funcname = "" except ValueError, e: funcname = "" else: funcname = "" if funcdescr is not None: try: funcdescr = wash_single_urlarg(urlarg=funcdescr, argreqdtype=str, argdefault="") except ValueError, e: funcdescr = "" else: funcdescr = "" if funceditaddparam is not None: try: funceditaddparam = wash_single_urlarg(urlarg=funceditaddparam, argreqdtype=str, argdefault="") if string_is_alphanumeric_including_underscore(txtstring=funceditaddparam) == 0: funceditaddparam = "" except ValueError, e: funceditaddparam = "" else: funceditaddparam = "" if funceditaddparamfree is not None: try: funceditaddparamfree = wash_single_urlarg(urlarg=funceditaddparamfree, argreqdtype=str, argdefault="") if string_is_alphanumeric_including_underscore(txtstring=funceditaddparamfree) == 0: funceditaddparamfree = "" except ValueError, e: funceditaddparamfree = "" else: funceditaddparamfree = "" if funceditdelparam is not None: try: funceditdelparam = wash_single_urlarg(urlarg=funceditdelparam, argreqdtype=str, argdefault="") except ValueError, e: funceditdelparam = "" else: funceditdelparam = "" if funcname == "": (title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname) return (title, body, errors, warnings) if funcdescreditcommit != "" and funcdescreditcommit is not None: ## Update the definition of a function: (title, body) = _functionedit_update_description(errors=errors, warnings=warnings, funcname=funcname, funcdescr=funcdescr) elif funcparamaddcommit != "" and funcparamaddcommit is not None: ## Request to add a new parameter to a function (title, body) = _functionedit_add_parameter(errors=errors, warnings=warnings, funcname=funcname, funceditaddparam=funceditaddparam, funceditaddparamfree=funceditaddparamfree) elif funcparamdelcommit != "" and funcparamdelcommit is not None: ## Request to delete a parameter from a function (title, body) = _functionedit_delete_parameter(errors=errors, warnings=warnings, funcname=funcname, deleteparam=funceditdelparam) else: ## Display Web form for new function addition: (title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname) return (title, body, errors, warnings) def perform_request_function_usage(funcname): """Display a page containing the usage details of a given function. @param funcname: the function name @return: page body """ errors = [] warnings = [] func_usage = get_function_usage_details(function=funcname) func_usage = stringify_listvars(func_usage) body = websubmitadmin_templates.tmpl_display_function_usage(funcname, func_usage) return (body, errors, warnings) def perform_request_list_actions(): """Display a list of all WebSubmit actions. @return: tuple: (body,errors,warnings), where errors and warnings are lists of errors/warnings encountered along the way, and body is a string of HTML, which is a page body. """ errors = [] warnings = [] body = "" all_actions = get_actid_actname_allactions() body = websubmitadmin_templates.tmpl_display_allactions(all_actions) return (body, errors, warnings) def perform_request_list_doctypes(): """Display a list of all WebSubmit document types. @return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings encountered along the way, and body is a string of HTML, which is a page body. """ errors = [] warnings = [] body = "" all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(all_doctypes) return (body, errors, warnings) def perform_request_list_jschecks(): """Display a list of all WebSubmit JavaScript element checking functions. @return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings encountered along the way, and body is a string of HTML, which is a page body. """ errors = [] warnings = [] body = "" all_jschecks = get_chname_alljschecks() body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks) return (body, errors, warnings) def perform_request_list_functions(): """Display a list of all WebSubmit FUNCTIONS. @return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings encountered along the way, and body is a string of HTML, which is a page body. """ errors = [] warnings = [] body = "" all_functions = get_funcname_funcdesc_allfunctions() body = websubmitadmin_templates.tmpl_display_allfunctions(all_functions) return (body, errors, warnings) def perform_request_list_elements(): """Display a list of all WebSubmit ELEMENTS. @return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings encountered along the way, and body is a string of HTML, which is a page body. """ errors = [] warnings = [] body = "" all_elements = get_elename_allelements() body = websubmitadmin_templates.tmpl_display_allelements(all_elements) return (body, errors, warnings) def _remove_doctype(errors, warnings, doctype): """Process removal of a document type. @param errors: LIST of errors (passed by reference from caller) - errors will be appended to it @param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it @param doctype: the document type to be removed. @return: a tuple containing page title, and HTML page body) """ title = "" body = "" user_msg = [] numrows_doctype = get_number_doctypes_docid(docid=doctype) if numrows_doctype == 1: ## Doctype is unique and can therefore be deleted: ## Delete any function parameters for this document type: error_code = delete_all_parameters_doctype(doctype=doctype) if error_code != 0: ## problem deleting some or all parameters - inform user and log error ## TODO : ERROR LOGGING user_msg.append("""Unable to delete some or all function parameter values for document type "%s".""" % (doctype,)) ## delete all functions called by this doctype's actions error_code = delete_all_functions_doctype(doctype=doctype) if error_code != 0: ## problem deleting some or all functions - inform user and log error ## TODO : ERROR LOGGING user_msg.append("""Unable to delete some or all functions for document type "%s".""" % (doctype,)) ## delete all categories of this doctype error_code = delete_all_categories_doctype(doctype=doctype) if error_code != 0: ## problem deleting some or all categories - inform user and log error ## TODO : ERROR LOGGING user_msg.append("""Unable to delete some or all parameters for document type "%s".""" % (doctype,)) ## delete all submission interface fields for this doctype error_code = delete_all_submissionfields_doctype(doctype=doctype) if error_code != 0: ## problem deleting some or all submission fields - inform user and log error ## TODO : ERROR LOGGING user_msg.append("""Unable to delete some or all submission fields for document type "%s".""" % (doctype,)) ## delete all submissions for this doctype error_code = delete_all_submissions_doctype(doctype) if error_code != 0: ## problem deleting some or all submissions - inform user and log error ## TODO : ERROR LOGGING user_msg.append("""Unable to delete some or all submissions for document type "%s".""" % (doctype,)) ## delete entry for this doctype in the collection-doctypes table error_code = delete_collection_doctype_entry_doctype(doctype) if error_code != 0: ## problem deleting this doctype from the collection-doctypes table ## TODO : ERROR LOGGING user_msg.append("""Unable to delete document type "%s" from the collection-doctypes table.""" % (doctype,)) ## delete the doctype itself error_code = delete_doctype(doctype) if error_code != 0: ## problem deleting this doctype from the doctypes table ## TODO : ERROR LOGGING user_msg.append("""Unable to delete document type "%s" from the document types table.""" % (doctype,)) user_msg.append("""The "%s" document type should now have been deleted, but you should not ignore any warnings.""" % (doctype,)) title = """Available WebSubmit Document Types""" all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) else: ## doctype is not unique and cannot be deleted if numrows_doctype > 1: ## doctype is duplicated - cannot delete - needs admin intervention ## TODO : LOG ERROR user_msg.append("""%s WebSubmit document types have been identified for doctype id "%s" - unable to delete.""" \ """ Please inform administrator.""" % (numrows_doctype, doctype)) else: ## no document types found for this doctype id ## TODO : LOG ERROR user_msg.append("""Unable to find any document types in the WebSubmit database for doctype id "%s" - unable to delete""" \ % (doctype,)) ## get a list of all document types, and once more display the delete form, with the message alldoctypes = get_docid_docname_and_docid_alldoctypes() title = "Remove WebSubmit Doctument Type" body = websubmitadmin_templates.tmpl_display_delete_doctype_form(doctype="", alldoctypes=alldoctypes, user_msg=user_msg) return (title, body) def perform_request_remove_doctype(doctype="", doctypedelete="", doctypedeleteconfirm=""): """Remove a document type from WebSubmit. @param doctype: the document type to be removed @doctypedelete: flag to signal that a confirmation for deletion should be displayed @doctypedeleteconfirm: flag to signal that confirmation for deletion has been received and the doctype should be removed @return: a tuple (title, body, errors, warnings) """ errors = [] warnings = [] body = "" title = "Remove WebSubmit Document Type" if doctypedeleteconfirm not in ("", None): ## Delete the document type: (title, body) = _remove_doctype(errors=errors, warnings=warnings, doctype=doctype) else: ## Display "doctype delete form" if doctypedelete not in ("", None) and doctype not in ("", None): ## don't bother to get list of doctypes - user will be prompted to confirm the deletion of "doctype" alldoctypes = None else: ## get list of all doctypes to pass to template so that it can prompt the user to choose a doctype to delete ## alldoctypes = get_docid_docname_alldoctypes() alldoctypes = get_docid_docname_and_docid_alldoctypes() body = websubmitadmin_templates.tmpl_display_delete_doctype_form(doctype=doctype, alldoctypes=alldoctypes) return (title, body, errors, warnings) def _create_add_doctype_form(doctype="", doctypename="", doctypedescr="", clonefrom="", user_msg=""): """Perform the steps necessary to create the "add a new doctype" form. @param doctype: The unique ID that is to be used for the new doctype. @param doctypename: the name that is to be given to a doctype. @param doctypedescr: the description to be allocated to the new doctype. @param user_msg: any message to be displayed to the user. @return: a tuple containing page title and HTML body of page: (title, body) """ title = """Add New WebSubmit Document Type""" alldoctypes = get_docid_docname_and_docid_alldoctypes() body = websubmitadmin_templates.tmpl_display_doctypedetails_form(doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom, alldoctypes=alldoctypes, user_msg=user_msg ) return (title, body) def _clone_categories_doctype(errors, warnings, user_msg, fromdoctype, todoctype): """Clone the categories of one document type, to another document type. @param errors: a list of errors encountered while cloning categories @param warnings: a list of warnings encountered while cloning categories @param user_msg: any message to be displayed to the user (this is a list) @param fromdoctype: the doctype from which categories are to be cloned @param todoctype: the doctype into which categories are to be cloned @return: integer value (0/1/2) - if doctype's categories couldn't be deleted, return 0 (cloning failed); if some categories could be cloned, return 1 (cloning partially successful); if all categories could be cloned, return 2 (cloning successful). """ error_code = clone_categories_fromdoctype_todoctype(fromdoctype=fromdoctype, todoctype=todoctype) if error_code == 1: ## doctype had existing categories and they could not be deleted ## TODO : LOG ERRORS user_msg.append("""Categories already existed for the document type "%s" but could not be deleted. Unable to clone""" \ """ categories of doctype "%s".""" % (todoctype, fromdoctype)) return 1 ## cloning failed elif error_code == 2: ## could not clone all categories for new doctype ## TODO : LOG ERRORS user_msg.append("""Unable to clone all categories from doctype "%s", for doctype "%s".""" % (fromdoctype, todoctype)) return 2 ## cloning at least partially successful else: return 0 ## cloning successful def _clone_functions_foraction_doctype(errors, warnings, user_msg, fromdoctype, todoctype, action): """Clone the functions of a given action of one document type, to the same action on another document type. @param errors: a list of errors encountered while cloning functions @param warnings: a list of warnings encountered while cloning functions @param user_msg: any message to be displayed to the user (this is a list) @param fromdoctype: the doctype from which functions are to be cloned @param todoctype: the doctype into which functions are to be cloned @param action: the action for which functions are to be cloned @return: an integer value (0/1/2). In the case that todoctype had existing functions for the given action and they could not be deleted return 0, signalling that this is a serious problem; in the case that some functions were cloned, return 1; in the case that all functions were cloned, return 2. """ error_code = clone_functions_foraction_fromdoctype_todoctype(fromdoctype=fromdoctype, todoctype=todoctype, action=action) if error_code == 1: ## doctype had existing functions for the given action and they could not be deleted ## TODO : LOG ERRORS user_msg.append("""Functions already existed for the "%s" action of the document type "%s" but they could not be """ \ """deleted. Unable to clone the functions of Document Type "%s" for action "%s".""" \ % (action, todoctype, fromdoctype, action)) ## critical - return 1 to signal this return 1 elif error_code == 2: ## could not clone all functions for given action for new doctype ## TODO : LOG ERRORS user_msg.append("""Unable to clone all functions for the "%s" action from doctype "%s", for doctype "%s".""" \ % (action, fromdoctype, todoctype)) return 2 ## not critical else: return 0 ## total success def _clone_functionparameters_foraction_fromdoctype_todoctype(errors, warnings, user_msg, fromdoctype, todoctype, action): """Clone the parameters/values of a given action of one document type, to the same action on another document type. @param errors: a list of errors encountered while cloning parameters @param warnings: a list of warnings encountered while cloning parameters @param user_msg: any message to be displayed to the user (this is a list) @param fromdoctype: the doctype from which parameters are to be cloned @param todoctype: the doctype into which parameters are to be cloned @param action: the action for which parameters are to be cloned @return: 0 if it was not possible to clone all parameters/values; 1 if all parameters/values were cloned successfully. """ error_code = clone_functionparameters_foraction_fromdoctype_todoctype(fromdoctype=fromdoctype, \ todoctype=todoctype, action=action) if error_code in (1, 2): ## something went wrong and it was not possible to clone all parameters/values of "action"/"fromdoctype" for "action"/"todoctype" ## TODO : LOG ERRORS user_msg.append("""It was not possible to clone all parameter values from the action "%(act)s" of the document type""" \ """ "%(fromdt)s" for the action "%(act)s" of the document type "%(todt)s".""" \ % { 'act' : action, 'fromdt' : fromdoctype, 'todt' : todoctype } ) return 2 ## to signal that addition wasn't 100% successful else: return 0 ## all parameters were cloned def _add_doctype(errors, warnings, doctype, doctypename, doctypedescr, clonefrom): title = "" body = "" user_msg = [] commit_error = 0 if doctype == "": user_msg.append("""The Document Type ID is mandatory and must be a string with no more than 10 alpha-numeric characters""") commit_error = 1 if commit_error != 0: ## don't commit - just re-display page with message to user (title, body) = _create_add_doctype_form(doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom, user_msg=user_msg) return (title, body) numrows_doctype = get_number_doctypes_docid(docid=doctype) if numrows_doctype > 0: ## this document type already exists - do not add ## TODO : LOG ERROR user_msg.append("""A document type identified by "%s" already seems to exist and there cannot be added. Choose another ID.""" \ % (doctype,)) (title, body) = _create_add_doctype_form(doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom, user_msg=user_msg) else: ## proceed with addition ## add the document type details: error_code = insert_doctype_details(doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr) if error_code == 0: ## added successfully if clonefrom not in ("", "None", None): ## document type should be cloned from "clonefrom" ## first, clone the categories from another doctype: error_code = _clone_categories_doctype(errors=errors, warnings=warnings, user_msg=user_msg, fromdoctype=clonefrom, todoctype=doctype) ## get details of clonefrom's submissions all_actnames_submissions_clonefrom = get_actname_all_submissions_doctype(doctype=clonefrom) if len(all_actnames_submissions_clonefrom) > 0: ## begin cloning for doc_submission_actname in all_actnames_submissions_clonefrom: ## clone submission details: action_name = doc_submission_actname[0] _clone_submission_fromdoctype_todoctype(errors=errors, warnings=errors, user_msg=user_msg, todoctype=doctype, action=action_name, clonefrom=clonefrom) user_msg.append("""The "%s" document type has been added.""" % (doctype,)) title = """Available WebSubmit Document Types""" all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) else: ## could not add document type details - do no more ## TODO : LOG ERROR! user_msg.append("""Unable to add details for document type "%s".""" % (doctype,)) (title, body) = _create_add_doctype_form(user_msg=user_msg) return (title, body) def perform_request_add_doctype(doctype=None, doctypename=None, doctypedescr=None, clonefrom=None, doctypedetailscommit=""): errors = [] warnings = [] body = "" ## wash args: if doctype is not None: try: doctype = wash_single_urlarg(urlarg=doctype, argreqdtype=str, argdefault="", maxstrlen=10, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=doctype) == 0: doctype = "" except ValueError, e: doctype = "" else: doctype = "" if doctypename is not None: try: doctypename = wash_single_urlarg(urlarg=doctypename, argreqdtype=str, argdefault="") except ValueError, e: doctypename = "" else: doctypename = "" if doctypedescr is not None: try: doctypedescr = wash_single_urlarg(urlarg=doctypedescr, argreqdtype=str, argdefault="") except ValueError, e: doctypedescr = "" else: doctypedescr = "" if clonefrom is not None: try: clonefrom = wash_single_urlarg(urlarg=clonefrom, argreqdtype=str, argdefault="None") except ValueError, e: clonefrom = "None" else: clonefrom = "None" if doctypedetailscommit not in ("", None): (title, body) = _add_doctype(errors=errors, warnings=warnings, doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom) else: (title, body) = _create_add_doctype_form() return (title, body, errors, warnings) def _delete_referee_doctype(errors, warnings, doctype, categid, refereeid): """Delete a referee from a given category of a document type. @param doctype: the document type from whose category the referee is to be removed @param categid: the name/ID of the category from which the referee is to be removed @param refereeid: the id of the referee to be removed from the given category @return: a tuple containing 2 strings: (page title, page body) """ user_msg = [] role_name = """referee_%s_%s""" % (doctype, categid) error_code = acc_deleteUserRole(id_user=refereeid, name_roll=role_name) if error_code > 0: ## referee was deleted from category user_msg.append(""" "%s".""" % (doctype,)) def _create_list_referees_doctype(doctype): referees = {} referees_details = {} ## get all CDS Invenio roles: all_roles = acc_getAllRoles() for role in all_roles: (roleid, rolename) = (role[0], role[1]) if re.match("^referee_%s_" % (doctype,), rolename): ## this is a "referee" role - get users of this role: role_users = acc_getRoleUsers(roleid) if role_users is not None and (type(role_users) in (tuple, list) and len(role_users) > 0): ## this role has users, record them in dictionary: referees[rolename] = role_users ## for each "group" of referees: for ref_role in referees.keys(): ## get category ID for this referee-role: try: categid = re.match("^referee_%s_(.*)" % (doctype,), ref_role).group(1) ## from WebSubmit DB, get categ name for "categid": if categid != "*": categ_details = get_all_categories_sname_lname_for_doctype_categsname(doctype=doctype, categsname=categid) if len(categ_details) > 0: ## if possible to receive details of this category, record them in a tuple in the format: ## ("categ name", (tuple of users details)): referees_details[ref_role] = (categid, categ_details[0][1], referees[ref_role]) else: ## general referee entry: referees_details[ref_role] = (categid, "General Referee(s)", referees[ref_role]) except AttributeError: ## there is no category for this role - it is broken, so pass it pass return referees_details def _create_edit_doctype_details_form(errors, warnings, doctype, doctypename="", doctypedescr="", doctypedetailscommit="", user_msg=""): if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode): user_msg = [] elif type(user_msg) in (str, unicode): user_msg = [user_msg] title = "Edit Document Type Details" doctype_details = get_doctype_docname_descr_cd_md_fordoctype(doctype) if len(doctype_details) == 1: docname = doctype_details[0][1] docdescr = doctype_details[0][2] (cd, md) = (doctype_details[0][3], doctype_details[0][4]) if doctypedetailscommit != "": ## could not commit details docname = doctypename docdescr = doctypedescr body = websubmitadmin_templates.tmpl_display_doctypedetails_form(doctype=doctype, doctypename=docname, doctypedescr=docdescr, cd=cd, md=md, user_msg=user_msg, perform_act="doctypeconfigure") else: ## problem retrieving details of doctype: user_msg.append("""Unable to retrieve details of doctype '%s' - cannot edit.""" % (doctype,),) ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body) def _create_add_submission_choose_clonefrom_form(errors, warnings, doctype, action, user_msg=""): if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode): user_msg = [] elif type(user_msg) in (str, unicode): user_msg = [user_msg] if action in ("", None): user_msg.append("""Unknown Submission""") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) ## does this doctype already have this action? numrows_doctype_action = get_number_submissions_doctype_action(doctype=doctype, action=action) if numrows_doctype_action < 1: ## action not present for this doctype - can be added ## get list of all doctypes implementing this action (for possible cloning purposes) doctypes_implementing_action = get_doctypeid_doctypes_implementing_action(action=action) ## create form to display document types to clone from title = "Add Submission '%s' to Document Type '%s'" % (action, doctype) body = websubmitadmin_templates.tmpl_display_submission_clone_form(doctype=doctype, action=action, clonefrom_list=doctypes_implementing_action, user_msg=user_msg ) else: ## warn user that action already exists for doctype and canot be added, then display all ## details of doctype again user_msg.append("The Document Type '%s' already implements the Submission '%s' - cannot add it again" \ % (doctype, action)) ## TODO : LOG WARNING (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _create_add_submission_form(errors, warnings, doctype, action, displayed="", buttonorder="", statustext="", level="", score="", stpage="", endtxt="", user_msg=""): if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode): user_msg = [] elif type(user_msg) in (str, unicode): user_msg = [user_msg] if action in ("", None): user_msg.append("""Unknown Submission""") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) title = "Add Submission '%s' to Document Type '%s'" % (action, doctype) body = websubmitadmin_templates.tmpl_display_submissiondetails_form(doctype=doctype, action=action, displayed=displayed, buttonorder=buttonorder, statustext=statustext, level=level, score=score, stpage=stpage, endtxt=endtxt, user_msg=user_msg, saveaction="add" ) return (title, body) def _create_delete_submission_form(errors, warnings, doctype, action): user_msg = [] title = """Delete Submission "%s" from Document Type "%s" """ % (action, doctype) numrows_doctypesubmission = get_number_submissions_doctype_action(doctype=doctype, action=action) if numrows_doctypesubmission > 0: ## submission exists: create form to delete it: body = websubmitadmin_templates.tmpl_display_delete_doctypesubmission_form(doctype=doctype, action=action) else: ## submission doesn't seem to exist. Display details of doctype only: user_msg.append("""The Submission "%s" doesn't seem to exist for the Document Type "%s" - unable to delete it""" % (action, doctype)) ## TODO : LOG ERRORS (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _create_edit_submission_form(errors, warnings, doctype, action, user_msg=""): if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode): user_msg = [] elif type(user_msg) in (str, unicode): user_msg = [user_msg] submission_details = get_submissiondetails_doctype_action(doctype=doctype, action=action) numrows_submission_details = len(submission_details) if numrows_submission_details == 1: ## correctly retrieved details of submission - display: submission_details = stringify_listvars(submission_details) displayed = submission_details[0][3] buttonorder = submission_details[0][7] statustext = submission_details[0][8] level = submission_details[0][9] score = submission_details[0][10] stpage = submission_details[0][11] endtxt = submission_details[0][12] cd = submission_details[0][5] md = submission_details[0][6] title = "Edit Details of '%s' Submission of '%s' Document Type" % (action, doctype) body = websubmitadmin_templates.tmpl_display_submissiondetails_form(doctype=doctype, action=action, displayed=displayed, buttonorder=buttonorder, statustext=statustext, level=level, score=score, stpage=stpage, endtxt=endtxt, cd=cd, md=md, user_msg=user_msg ) else: if numrows_submission_details > 1: ## multiple rows for this submission - this is a key violation user_msg.append("Found multiple rows for the Submission '%s' of the Document Type '%s'" \ % (action, doctype)) else: ## submission does not exist user_msg.append("The Submission '%s' of the Document Type '%s' doesn't seem to exist." \ % (action, doctype)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _create_edit_category_form(errors, warnings, doctype, categid): title = "Edit Category Description" categ_details = get_all_categories_sname_lname_for_doctype_categsname(doctype=doctype, categsname=categid) if len(categ_details) == 1: ## disaply details retrieved_categid=categ_details[0][0] retrieved_categdescr=categ_details[0][1] body = websubmitadmin_templates.tmpl_display_edit_category_form(doctype=doctype, categid=retrieved_categid, categdescr=retrieved_categdescr ) else: ## problem retrieving details of categ user_msg = """Unable to retrieve details of category '%s'""" % (categid,) ## TODO : LOG ERRORS (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _create_configure_doctype_form(doctype, jumpcategout="", user_msg=""): title = "Configure Document Type" body = "" if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode): user_msg = [] ## get details of doctype: doctype_details = get_doctype_docname_descr_cd_md_fordoctype(doctype) docname = doctype_details[0][1] docdescr = doctype_details[0][2] (cd, md) = (doctype_details[0][3], doctype_details[0][4]) ## get categories for doctype: doctype_categs = get_all_category_details_for_doctype(doctype=doctype) ## get submissions for doctype: doctype_submissions = get_submissiondetails_all_submissions_doctype(doctype=doctype) ## get list of actions that this doctype doesn't have: unlinked_actions = get_actions_sname_lname_not_linked_to_doctype(doctype=doctype) ## get referees for doctype: referees_dets = _create_list_referees_doctype(doctype=doctype) body = websubmitadmin_templates.tmpl_configure_doctype_overview(doctype=doctype, doctypename=docname, doctypedescr=docdescr, doctype_cdate=cd, doctype_mdate=md, doctype_categories=doctype_categs, jumpcategout=jumpcategout, doctype_submissions=doctype_submissions, doctype_referees=referees_dets, add_actions_list=unlinked_actions, user_msg=user_msg) return (title, body) def _clone_submission_fromdoctype_todoctype(errors, warnings, user_msg, todoctype, action, clonefrom): ## first, delete the submission from todoctype (if it exists): error_code = delete_submissiondetails_doctype(doctype=todoctype, action=action) if error_code == 0: ## could be deleted - now clone it error_code = insert_submission_details_clonefrom_submission(addtodoctype=todoctype, action=action, clonefromdoctype=clonefrom) if error_code == 0: ## submission inserted ## now clone functions: error_code = _clone_functions_foraction_doctype(errors=errors, warnings=warnings, user_msg=user_msg, \ fromdoctype=clonefrom, todoctype=todoctype, action=action) if error_code in (0, 2): ## no serious error - clone parameters: error_code = _clone_functionparameters_foraction_fromdoctype_todoctype(errors=errors, warnings=warnings, user_msg=user_msg, fromdoctype=clonefrom, todoctype=todoctype, action=action) ## now clone pages/elements error_code = clone_submissionfields_from_doctypesubmission_to_doctypesubmission(fromsub="%s%s" % (action, clonefrom), tosub="%s%s" % (action, todoctype)) if error_code == 1: ## could not delete all existing submission fields and therefore could no clone submission fields at all ## TODO : LOG ERROR user_msg.append("""Unable to delete existing submission fields for Submission "%s" of Document Type "%s" - """ \ """cannot clone submission fields!""" % (action, todoctype)) elif error_code == 2: ## could not clone all fields ## TODO : LOG ERROR user_msg.append("""Unable to clone all submission fields for submission "%s" on Document Type "%s" from Document""" \ """ Type "%s" """ % (action, todoctype, clonefrom)) else: ## could not insert submission details! user_msg.append("""Unable to successfully insert details of submission "%s" into Document Type "%s" - cannot clone from "%s" """ \ % (action, todoctype, clonefrom)) ## TODO : LOG ERROR else: ## could not delete details of existing submission (action) from 'todoctype' - cannot clone it as new user_msg.append("""Unable to delete details of existing Submission "%s" from Document Type "%s" - cannot clone it from "%s" """ \ % (action, todoctype, clonefrom)) ## TODO : LOG ERROR def _add_submission_to_doctype_clone(errors, warnings, doctype, action, clonefrom): user_msg = [] if action in ("", None) or clonefrom in ("", None): user_msg.append("Unknown action or document type to clone from - cannot add submission") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) ## does action exist? numrows_action = get_number_actions_with_actid(actid=action) if numrows_action > 0: ## The action exists, but is it already implemented as a submission by doctype? numrows_submission_doctype = get_number_submissions_doctype_action(doctype=doctype, action=action) if numrows_submission_doctype > 0: ## this submission already exists for this document type - unable to add it again user_msg.append("""The Submission "%s" already exists for Document Type "%s" - cannot add it again""" \ %(action, doctype)) ## TODO : LOG ERROR else: ## clone the submission _clone_submission_fromdoctype_todoctype(errors=errors, warnings=errors, user_msg=user_msg, todoctype=doctype, action=action, clonefrom=clonefrom) user_msg.append("""Cloning of Submission "%s" from Document Type "%s" has been carried out. You should not""" \ """ ignore any warnings that you may have seen.""" % (action, clonefrom)) ## TODO : LOG WARNING OF NEW SUBMISSION CREATION BY CLONING else: ## this action doesn't exist! cannot add a submission based upon it! user_msg.append("The Action '%s' does not seem to exist in WebSubmit. Cannot add it as a Submission!" \ % (action)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _add_submission_to_doctype(errors, warnings, doctype, action, displayed, buttonorder, statustext, level, score, stpage, endtxt): user_msg = [] ## does "action" exist? numrows_action = get_number_actions_with_actid(actid=action) if numrows_action < 1: ## this action does not exist! Can't add a submission based upon it! user_msg.append("'%s' does not exist in WebSubmit as an Action! Unable to add this submission."\ % (action,)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) ## Insert the new submission error_code = insert_submission_details(doctype=doctype, action=action, displayed=displayed, nbpg="0", buttonorder=buttonorder, statustext=statustext, level=level, score=score, stpage=stpage, endtext=endtxt) if error_code == 0: ## successful insert user_msg.append("""'%s' Submission Successfully Added to Document Type '%s'""" % (action, doctype)) else: ## could not insert submission into doctype user_msg.append("""Unable to Add '%s' Submission to '%s' Document Type""" % (action, doctype)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) - return (title, body) + return (title, body) def _delete_submission_from_doctype(errors, warnings, doctype, action): """Delete a submission (action) from the document type identified by "doctype". @param errors: a list of errors encountered while deleting the submission @param warnings: a list of warnings encountered while deleting the submission @param doctype: the unique ID of the document type from which the submission is to be deleted @param categid: the action ID of the submission to be deleted from doctype @return: a tuple containing 2 strings: (page title, page body) """ user_msg = [] if action in ("", None): user_msg.append("Unknown action - cannot delete submission") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) ## delete fields for this submission: error_code = delete_all_submissionfields_submission("""%s%s""" % (action, doctype) ) if error_code != 0: ## could not successfully delete all fields - report error user_msg.append("""When deleting Submission "%s" from Document Type "%s", it wasn't possible to delete all Submission Fields""" \ % (action, doctype)) ## TODO : LOG ERROR ## delete parameters for this submission: error_code = delete_functionparameters_doctype_submission(doctype=doctype, action=action) if error_code != 0: ## could not successfully delete all functions - report error user_msg.append("""When deleting Submission "%s" from Document Type "%s", it wasn't possible to delete all Function Parameters""" \ % (action, doctype)) ## TODO : LOG ERROR ## delete functions for this submission: error_code = delete_all_functions_foraction_doctype(doctype=doctype, action=action) if error_code != 0: ## could not successfully delete all functions - report error user_msg.append("""When deleting Submission "%s" from Document Type "%s", it wasn't possible to delete all Functions""" \ % (action, doctype)) ## TODO : LOG ERROR ## delete this submission itself: error_code = delete_submissiondetails_doctype(doctype=doctype, action=action) if error_code == 0: ## successful delete user_msg.append("""The "%s" Submission has been deleted from the "%s" Document Type""" % (action, doctype)) else: ## could not delete category user_msg.append("""Unable to successfully delete the "%s" Submission from the "%s" Document Type""" % (action, doctype)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _edit_submission_for_doctype(errors, warnings, doctype, action, displayed, buttonorder, statustext, level, score, stpage, endtxt): """Update the details of a given submission belonging to the document type identified by "doctype". @param errors: a list of errors encountered while updating the submission's details @param warnings: a list of warnings encountered while updating the submission's details @param doctype: the unique ID of the document type for which the submission is to be updated @param action: action name of the submission to be updated @param displayed: displayed on main submission page? (Y/N) @param buttonorder: button order @param statustext: statustext @param level: level @param score: score @param stpage: stpage @param endtxt: endtxt @return: a tuple of 2 strings: (page title, page body) """ user_msg = [] commit_error = 0 if action in ("", None): user_msg.append("Unknown Action - cannot update submission") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) error_code = update_submissiondetails_doctype_action(doctype=doctype, action=action, displayed=displayed, buttonorder=buttonorder, statustext=statustext, level=level, score=score, stpage=stpage, endtxt=endtxt) if error_code == 0: ## successful update user_msg.append("'%s' Submission of '%s' Document Type updated." % (action, doctype) ) else: ## could not update user_msg.append("Unable to update '%s' Submission of '%s' Document Type." % (action, doctype) ) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _edit_doctype_details(errors, warnings, doctype, doctypename, doctypedescr): """Update the details (name and/or description) of a document type (identified by doctype.) @param errors: a list of errors encountered while updating the doctype's details @param warnings: a list of warnings encountered while updating the doctype's details @param doctype: the unique ID of the document type to be updated @param doctypename: the new/updated name for the doctype @param doctypedescr: the new/updated description for the doctype @return: a tuple containing 2 strings: (page title, page body) """ user_msg = [] error_code = update_doctype_details(doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr) if error_code == 0: ## successful update user_msg.append("""'%s' Document Type Updated""" % (doctype,)) else: ## could not update user_msg.append("""Unable to Update Doctype '%s'""" % (doctype,)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _edit_category_for_doctype(errors, warnings, doctype, categid, categdescr): """Edit the description of a given category (identified by categid), belonging to the document type identified by doctype. @param errors: a list of errors encountered while modifying the category @param warnings: a list of warnings encountered while modifying the category @param doctype: the unique ID of the document type for which the category is to be modified @param categid: the unique category ID of the category to be modified @param categdescr: the new description for the category @return: at tuple containing 2 strings: (page title, page body) """ user_msg = [] if categid in ("", None) or categdescr in ("", None): ## cannot edit unknown category! user_msg.append("Category ID and Description are both mandatory") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) error_code = update_category_description_doctype_categ(doctype=doctype, categ=categid, categdescr=categdescr) if error_code == 0: ## successful update user_msg.append("""'%s' Category Description Successfully Updated""" % (categid,)) else: ## could not update category description user_msg.append("""Unable to Description for Category '%s'""" % (categid,)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _add_category_to_doctype(errors, warnings, doctype, categid, categdescr): """Add a new category to the document type identified by "doctype". Category ID, and category description are both mandatory. @param errors: a list of errors encountered while adding the category @param warnings: a list of warnings encountered while adding the category @param doctype: the unique ID of the document type to which the category is to be added @param categid: the unique category ID of the category to be added to doctype @param categdescr: the description of the category to be added @return: at tuple containing 2 strings: (page title, page body) """ user_msg = [] if categid in ("", None) or categdescr in ("", None): ## cannot add unknown category! user_msg.append("Category ID and Description are both mandatory") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) error_code = insert_category_into_doctype(doctype=doctype, categ=categid, categdescr=categdescr) if error_code == 0: ## successful insert user_msg.append("""'%s' Category Successfully Added""" % (categid,)) else: ## could not insert category into doctype user_msg.append("""Unable to Add '%s' Category""" % (categid,)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _delete_category_from_doctype(errors, warnings, doctype, categid): """Delete a category (categid) from the document type identified by "doctype". @param errors: a list of errors encountered while deleting the category @param warnings: a list of warnings encountered while deleting the category @param doctype: the unique ID of the document type from which the category is to be deleted @param categid: the unique category ID of the category to be deleted from doctype @return: a tuple containing 2 strings: (page title, page body) """ user_msg = [] if categid in ("", None): ## cannot delete unknown category! user_msg.append("Category ID is mandatory") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) error_code = delete_category_doctype(doctype=doctype, categ=categid) if error_code == 0: ## successful delete user_msg.append("""'%s' Category Successfully Deleted""" % (categid,)) else: ## could not delete category user_msg.append("""Unable to Delete '%s' Category""" % (categid,)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _jump_category_to_new_score(errors, warnings, doctype, jumpcategout, jumpcategin): user_msg = [] if jumpcategout in ("", None) or jumpcategin in ("", None): ## need both jumpcategout and jumpcategin to move a category: user_msg.append("Unable to move category - unknown source and/or destination score(s)") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) ## FIXME TODO: error_code = move_category_to_new_score(doctype, jumpcategout, jumpcategin) if error_code == 0: ## successful jump of category user_msg.append("""Successfully Moved [%s] Category""" % (jumpcategout,)) else: ## could not delete category user_msg.append("""Unable to Move [%s] Category""" % (jumpcategout,)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _move_category(errors, warnings, doctype, categid, movecategup=""): user_msg = [] if categid in ("", None): ## cannot move unknown category! user_msg.append("Cannot move an unknown category - category ID is mandatory") (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) if movecategup not in ("", None): ## move the category up in score: error_code = move_category_by_one_place_in_score(doctype=doctype, categsname=categid, direction="up") else: ## move the category down in score: error_code = move_category_by_one_place_in_score(doctype=doctype, categsname=categid, direction="down") - + if error_code == 0: ## successful move of category user_msg.append("""[%s] Category Successfully Moved""" % (categid,)) else: ## could not delete category user_msg.append("""Unable to Move [%s] Category""" % (categid,)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def perform_request_configure_doctype(doctype, doctypename=None, doctypedescr=None, doctypedetailsedit="", doctypedetailscommit="", doctypecategoryadd="", doctypecategoryedit="", doctypecategoryeditcommit="", doctypecategorydelete="", doctypesubmissionadd="", doctypesubmissiondelete="", doctypesubmissiondeleteconfirm="", doctypesubmissionedit="", doctypesubmissionaddclonechosen="", doctypesubmissionadddetailscommit="", doctypesubmissioneditdetailscommit="", categid=None, categdescr=None, movecategup=None, movecategdown=None, jumpcategout=None, jumpcategin=None, action=None, doctype_cloneactionfrom=None, displayed=None, buttonorder=None, statustext=None, level=None, score=None, stpage=None, endtxt=None ): user_msg = [] errors = [] warnings = [] body = "" if doctype is not None: try: doctype = wash_single_urlarg(urlarg=doctype, argreqdtype=str, argdefault="", maxstrlen=10, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=doctype) == 0: doctype = "" except ValueError, e: doctype = "" else: doctype = "" if action is not None: try: action = wash_single_urlarg(urlarg=action, argreqdtype=str, argdefault="", maxstrlen=3, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=action) == 0: action = "" except ValueError, e: action = "" else: action = "" if doctypename is not None: try: doctypename = wash_single_urlarg(urlarg=doctypename, argreqdtype=str, argdefault="") except ValueError, e: doctypename = "" else: doctypename = "" if doctypedescr is not None: try: doctypedescr = wash_single_urlarg(urlarg=doctypedescr, argreqdtype=str, argdefault="") except ValueError, e: doctypedescr = "" else: doctypedescr = "" if categid is not None: try: categid = wash_single_urlarg(urlarg=categid, argreqdtype=str, argdefault="") except ValueError, e: categid = "" else: categid = "" if categdescr is not None: try: categdescr = wash_single_urlarg(urlarg=categdescr, argreqdtype=str, argdefault="") except ValueError, e: categdescr = "" else: categdescr = "" if doctype_cloneactionfrom is not None: try: doctype_cloneactionfrom = wash_single_urlarg(urlarg=doctype_cloneactionfrom, argreqdtype=str, argdefault="", maxstrlen=10, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=doctype_cloneactionfrom) == 0: doctype_cloneactionfrom = "" except ValueError, e: doctype_cloneactionfrom = "" else: doctype_cloneactionfrom = "" if displayed is not None: try: displayed = wash_single_urlarg(urlarg=displayed, argreqdtype=str, argdefault="Y", maxstrlen=1, minstrlen=1) except ValueError, e: displayed = "Y" else: displayed = "Y" if buttonorder is not None: try: buttonorder = wash_single_urlarg(urlarg=buttonorder, argreqdtype=int, argdefault="") except ValueError, e: buttonorder = "" else: buttonorder = "" if level is not None: try: level = wash_single_urlarg(urlarg=level, argreqdtype=str, argdefault="", maxstrlen=1, minstrlen=1) except ValueError, e: level = "" else: level = "" if score is not None: try: score = wash_single_urlarg(urlarg=score, argreqdtype=int, argdefault="") except ValueError, e: score = "" else: score = "" if stpage is not None: try: stpage = wash_single_urlarg(urlarg=stpage, argreqdtype=int, argdefault="") except ValueError, e: stpage = "" else: stpage = "" if statustext is not None: try: statustext = wash_single_urlarg(urlarg=statustext, argreqdtype=str, argdefault="") except ValueError, e: statustext = "" else: statustext = "" if endtxt is not None: try: endtxt = wash_single_urlarg(urlarg=endtxt, argreqdtype=str, argdefault="") except ValueError, e: endtxt = "" else: endtxt = "" ## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not numrows_doctype = get_number_doctypes_docid(docid=doctype) if numrows_doctype > 1: ## there are multiple doctypes with this doctype ID: ## TODO : LOG ERROR user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \ % (doctype,)) all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) elif numrows_doctype == 0: ## this doctype does not seem to exist: user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \ % (doctype,)) ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) ## since doctype ID is OK, process doctype configuration request: if doctypedetailsedit not in ("", None): (title, body) = _create_edit_doctype_details_form(errors=errors, warnings=warnings, doctype=doctype) elif doctypedetailscommit not in ("", None): ## commit updated document type details (title, body) = _edit_doctype_details(errors=errors, warnings=warnings, doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr) elif doctypecategoryadd not in ("", None): ## add new category: (title, body) = _add_category_to_doctype(errors=errors, warnings=warnings, doctype=doctype, categid=categid, categdescr=categdescr) elif doctypecategoryedit not in ("", None): ## create form to update category description: (title, body) = _create_edit_category_form(errors=errors, warnings=warnings, doctype=doctype, categid=categid) elif doctypecategoryeditcommit not in ("", None): ## commit updated category description: (title, body) = _edit_category_for_doctype(errors=errors, warnings=warnings, doctype=doctype, categid=categid, categdescr=categdescr) elif doctypecategorydelete not in ("", None): ## delete a category (title, body) = _delete_category_from_doctype(errors=errors, warnings=warnings, doctype=doctype, categid=categid) elif movecategup not in ("", None) or movecategdown not in ("", None): ## move a category up or down in score: (title, body) = _move_category(errors=errors, warnings=warnings, doctype=doctype, categid=categid, movecategup=movecategup) elif jumpcategout not in ("", None) and jumpcategin not in ("", None): ## jump a category from one score to another: (title, body) = _jump_category_to_new_score(errors=errors, warnings=warnings, doctype=doctype, jumpcategout=jumpcategout, jumpcategin=jumpcategin) elif doctypesubmissionadd not in ("", None): ## form displaying option of adding doctype: (title, body) = _create_add_submission_choose_clonefrom_form(errors=errors, warnings=warnings, doctype=doctype, action=action) elif doctypesubmissionaddclonechosen not in ("", None): ## add a submission. if there is a document type to be cloned from, then process clone; ## otherwise, present form with details of doctype if doctype_cloneactionfrom in ("", None, "None"): ## no clone - present form into which details of new submission should be entered (title, body) = _create_add_submission_form(errors=errors, warnings=warnings, doctype=doctype, action=action) else: ## new submission should be cloned from doctype_cloneactionfrom (title, body) = _add_submission_to_doctype_clone(errors=errors, warnings=warnings, doctype=doctype, action=action, clonefrom=doctype_cloneactionfrom) elif doctypesubmissiondelete not in ("", None): ## create form to prompt for confirmation of deletion of a submission: (title, body) = _create_delete_submission_form(errors=errors, warnings=warnings, doctype=doctype, action=action) elif doctypesubmissiondeleteconfirm not in ("", None): ## process the deletion of a submission from the doctype concerned: (title, body) = _delete_submission_from_doctype(errors=errors, warnings=warnings, doctype=doctype, action=action) elif doctypesubmissionedit not in ("", None): ## create form to update details of a submission (title, body) = _create_edit_submission_form(errors=errors, warnings=warnings, doctype=doctype, action=action) elif doctypesubmissioneditdetailscommit not in ("", None): ## commit updated submission details: (title, body) = _edit_submission_for_doctype(errors=errors, warnings=warnings, doctype=doctype, action=action, displayed=displayed, buttonorder=buttonorder, statustext=statustext, level=level, score=score, stpage=stpage, endtxt=endtxt) elif doctypesubmissionadddetailscommit not in ("", None): ## commit new submission to doctype (not by cloning) (title, body) = _add_submission_to_doctype(errors=errors, warnings=warnings, doctype=doctype, action=action, displayed=displayed, buttonorder=buttonorder, statustext=statustext, level=level, score=score, stpage=stpage, endtxt=endtxt) else: ## default - display root of edit doctype (title, body) = _create_configure_doctype_form(doctype=doctype, jumpcategout=jumpcategout) return (title, body, errors, warnings) def _create_configure_doctype_submission_functions_form(doctype, action, movefromfunctionname="", movefromfunctionstep="", movefromfunctionscore="", user_msg=""): title = """Functions of the "%s" Submission of the "%s" Document Type:""" % (action, doctype) submission_functions = get_functionname_step_score_allfunctions_doctypesubmission(doctype=doctype, action=action) body = websubmitadmin_templates.tmpl_configuredoctype_display_submissionfunctions(doctype=doctype, action=action, movefromfunctionname=movefromfunctionname, movefromfunctionstep=movefromfunctionstep, movefromfunctionscore=movefromfunctionscore, submissionfunctions=submission_functions, user_msg=user_msg) return (title, body) def _create_configure_doctype_submission_functions_add_function_form(doctype, action, addfunctionname="", addfunctionstep="", addfunctionscore="", user_msg=""): """Create a form that allows a user to add a function a submission. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param addfunctionname: (string) the name of the function to be added to the submission (passed in case of page refresh) @param addfunctionstep: (integer) the step of the submission into which the function is to be added (passed in case of page refresh) @param addfunctionscore: (integer) the score at at which the function is to be added (passed in case of page refresh) @param user_msg: (string or list of strings) any message(s) to be displayed to the user @return: (tuple) containing 2 strings - (page-title, HTML page-body) """ title = """Add a function to the [%s] submission of the [%s] document type""" % (action, doctype) submission_functions = get_functionname_step_score_allfunctions_doctypesubmission(doctype=doctype, action=action) ## get names of all WebSubmit functions: all_websubmit_functions = get_names_of_all_functions() ## put names into a list of single-element tuples, so that template can make HTML select list with them: all_websubmit_functions = map(lambda x: (str(x),), all_websubmit_functions) ## create page body: body = websubmitadmin_templates.tmpl_configuredoctype_add_submissionfunction(doctype=doctype, action=action, cursubmissionfunctions=submission_functions, allWSfunctions=all_websubmit_functions, addfunctionname=addfunctionname, addfunctionstep=addfunctionstep, addfunctionscore=addfunctionscore, user_msg=user_msg) return (title, body) def _create_configure_doctype_submission_functions_list_parameters_form(doctype, action, functionname, user_msg=""): title = """Parameters of the %s function, as used in the %s document type"""\ % (functionname, doctype) funcparams = get_function_parameters(function=functionname) if len(funcparams) > 0: ## get the values paramslist = map(lambda x: str(x[0]), funcparams) params = get_function_parameter_vals_doctype(doctype=doctype, paramlist=paramslist) else: params = () ## params = get_parameters_name_and_value_for_function_of_doctype(doctype=doctype, function=functionname) body = websubmitadmin_templates.tmpl_configuredoctype_list_functionparameters(doctype=doctype, action=action, function=functionname, params=params, user_msg=user_msg) return (title, body) def _update_submission_function_parameter_file(doctype, action, functionname, paramname, paramfilecontent): user_msg = [] ## get the filename: paramval_res = get_value_of_parameter_for_doctype(doctype=doctype, parameter=paramname) if paramval_res is None: ## this parameter doesn't exist for this doctype! user_msg.append("The parameter [%s] doesn't exist for the document type [%s]!" % (paramname, doctype)) (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname, user_msg=user_msg) return (title, body) paramval = str(paramval_res) filename = basename(paramval) if filename == "": ## invalid filename user_msg.append("[%s] is an invalid filename - cannot save details" % (paramval,)) (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname, user_msg=user_msg) return (title, body) ## save file: try: save_update_to_file(filepath="%s/%s" % (bibconvertconf, filename), filecontent=paramfilecontent) except InvenioWebSubmitAdminWarningIOError, e: ## could not correctly update the file! user_msg.append(str(e)) (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname, user_msg=user_msg) return (title, body) ## redisplay form user_msg.append("""[%s] file updated""" % (filename,)) (title, body) = _create_configure_doctype_submission_functions_edit_parameter_file_form(doctype=doctype, action=action, functionname=functionname, paramname=paramname, user_msg=user_msg) return (title, body) def _create_configure_doctype_submission_functions_edit_parameter_file_form(doctype, action, functionname, paramname, user_msg=""): if type(user_msg) is not list: user_msg = [] paramval_res = get_value_of_parameter_for_doctype(doctype=doctype, parameter=paramname) if paramval_res is None: ## this parameter doesn't exist for this doctype! user_msg.append("The parameter [%s] doesn't exist for the document type [%s]!" % (paramname, doctype)) (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname) return (title, body) paramval = str(paramval_res) title = "Edit the [%s] file for the [%s] document type" % (paramval, doctype) ## get basename of file: filecontent = "" filename = basename(paramval) if filename == "": ## invalid filename user_msg.append("[%s] is an invalid filename" % (paramval,)) (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname, user_msg=user_msg) return (title, body) ## try to read file contents: if access("%s/%s" % (bibconvertconf, filename), F_OK): ## file exists if access("%s/%s" % (bibconvertconf, filename), R_OK) and \ isfile("%s/%s" % (bibconvertconf, filename)): ## file is a regular file and is readable - get contents filecontent = open("%s/%s" % (bibconvertconf, filename), "r").read() else: if not isfile("%s/%s" % (bibconvertconf, filename)): ## file is not a regular file user_msg.append("The parameter file [%s] is not regular file - unable to read" % (filename,)) else: ## file is not readable - error message user_msg.append("The parameter file [%s] could not be read - check permissions" % (filename,)) ## display page listing the parameters of this function: (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname, user_msg=user_msg) return (title, body) else: ## file does not exist: user_msg.append("The parameter file [%s] does not exist - it will be created" % (filename,)) ## make page body: body = websubmitadmin_templates.tmpl_configuredoctype_edit_functionparameter_file(doctype=doctype, action=action, function=functionname, paramname=paramname, paramfilename=filename, paramfilecontent=filecontent, user_msg=user_msg) return (title, body) def _create_configure_doctype_submission_functions_edit_parameter_value_form(doctype, action, functionname, paramname, paramval="", user_msg=""): title = """Edit the value of the [%s] Parameter""" % (paramname,) ## get the parameter's value from the DB: paramval_res = get_value_of_parameter_for_doctype(doctype=doctype, parameter=paramname) if paramval_res is None: ## this parameter doesn't exist for this doctype! (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname) if paramval == "": ## use whatever retrieved paramval_res contains: paramval = str(paramval_res) body = websubmitadmin_templates.tmpl_configuredoctype_edit_functionparameter_value(doctype=doctype, action=action, function=functionname, paramname=paramname, paramval=paramval) return (title, body) def _update_submissionfunction_parameter_value(doctype, action, functionname, paramname, paramval): user_msg = [] try: update_value_of_function_parameter_for_doctype(doctype=doctype, paramname=paramname, paramval=paramval) user_msg.append("""The value of the parameter [%s] was updated for document type [%s]""" % (paramname, doctype)) except InvenioWebSubmitAdminWarningTooManyRows, e: ## multiple rows found for param - update not carried out user_msg.append(str(e)) except InvenioWebSubmitAdminWarningNoRowsFound, e: ## no rows found - parameter does not exist for doctype, therefore no update user_msg.append(str(e)) (title, body) = \ _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname, user_msg=user_msg) return (title, body) def perform_request_configure_doctype_submissionfunctions_parameters(doctype, action, functionname, functionstep, functionscore, paramname="", paramval="", editfunctionparametervalue="", editfunctionparametervaluecommit="", editfunctionparameterfile="", editfunctionparameterfilecommit="", paramfilename="", paramfilecontent=""): errors = [] warnings = [] body = "" user_msg = [] ## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not if doctype in ("", None): user_msg.append("""Unknown Document Type""") ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) numrows_doctype = get_number_doctypes_docid(docid=doctype) if numrows_doctype > 1: ## there are multiple doctypes with this doctype ID: ## TODO : LOG ERROR user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \ % (doctype,)) all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) elif numrows_doctype == 0: ## this doctype does not seem to exist: user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \ % (doctype,)) ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) ## ensure that this submission exists for this doctype: numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action) if numrows_submission > 1: ## there are multiple submissions for this doctype/action ID: ## TODO : LOG ERROR user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \ % (action, doctype)) (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) elif numrows_submission == 0: ## this submission does not seem to exist for this doctype: user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \ % (action, doctype)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) if editfunctionparametervaluecommit not in ("", None): ## commit an update to a function parameter: (title, body) = _update_submissionfunction_parameter_value(doctype=doctype, action=action, functionname=functionname, paramname=paramname, paramval=paramval) elif editfunctionparametervalue not in ("", None): ## display a form for editing the value of a parameter: (title, body) = _create_configure_doctype_submission_functions_edit_parameter_value_form(doctype=doctype, action=action, functionname=functionname, paramname=paramname, paramval=paramval) elif editfunctionparameterfile not in ("", None): ## display a form for editing the contents of a file, named by the parameter's value: (title, body) = _create_configure_doctype_submission_functions_edit_parameter_file_form(doctype=doctype, action=action, functionname=functionname, paramname=paramname) elif editfunctionparameterfilecommit not in ("", None): (title, body) = _update_submission_function_parameter_file(doctype=doctype, action=action, functionname=functionname, paramname=paramname, paramfilecontent=paramfilecontent) else: ## default - display list of parameters for function: (title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action, functionname=functionname) return (title, body, errors, warnings) def perform_request_configure_doctype_submissionfunctions(doctype, action, moveupfunctionname="", moveupfunctionstep="", moveupfunctionscore="", movedownfunctionname="", movedownfunctionstep="", movedownfunctionscore="", movefromfunctionname="", movefromfunctionstep="", movefromfunctionscore="", movetofunctionname="", movetofunctionstep="", movetofunctionscore="", deletefunctionname="", deletefunctionstep="", deletefunctionscore="", configuresubmissionaddfunction="", configuresubmissionaddfunctioncommit="", addfunctionname="", addfunctionstep="", addfunctionscore=""): errors = [] warnings = [] body = "" user_msg = [] if addfunctionstep != "": try: addfunctionstep = str(wash_single_urlarg(urlarg=addfunctionstep, argreqdtype=int, argdefault="")) except ValueError, e: addfunctionstep = "" if addfunctionscore != "": try: addfunctionscore = str(wash_single_urlarg(urlarg=addfunctionscore, argreqdtype=int, argdefault="")) except ValueError, e: addfunctionscore = "" if deletefunctionstep != "": try: deletefunctionstep = str(wash_single_urlarg(urlarg=deletefunctionstep, argreqdtype=int, argdefault="")) except ValueError, e: deletefunctionstep = "" if deletefunctionscore != "": try: deletefunctionscore = str(wash_single_urlarg(urlarg=deletefunctionscore, argreqdtype=int, argdefault="")) except ValueError, e: deletefunctionscore = "" if movetofunctionstep != "": try: movetofunctionstep = str(wash_single_urlarg(urlarg=movetofunctionstep, argreqdtype=int, argdefault="")) except ValueError, e: movetofunctionstep = "" if movetofunctionscore != "": try: movetofunctionscore = str(wash_single_urlarg(urlarg=movetofunctionscore, argreqdtype=int, argdefault="")) except ValueError, e: movetofunctionscore = "" if moveupfunctionstep != "": try: moveupfunctionstep = str(wash_single_urlarg(urlarg=moveupfunctionstep, argreqdtype=int, argdefault="")) except ValueError, e: moveupfunctionstep = "" if moveupfunctionscore != "": try: moveupfunctionscore = str(wash_single_urlarg(urlarg=moveupfunctionscore, argreqdtype=int, argdefault="")) except ValueError, e: moveupfunctionscore = "" if movedownfunctionstep != "": try: movedownfunctionstep = str(wash_single_urlarg(urlarg=movedownfunctionstep, argreqdtype=int, argdefault="")) except ValueError, e: movedownfunctionstep = "" if movedownfunctionscore != "": try: movedownfunctionscore = str(wash_single_urlarg(urlarg=movedownfunctionscore, argreqdtype=int, argdefault="")) except ValueError, e: movedownfunctionscore = "" - + ## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not if doctype in ("", None): user_msg.append("""Unknown Document Type""") ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) numrows_doctype = get_number_doctypes_docid(docid=doctype) if numrows_doctype > 1: ## there are multiple doctypes with this doctype ID: ## TODO : LOG ERROR user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \ % (doctype,)) all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) elif numrows_doctype == 0: ## this doctype does not seem to exist: user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \ % (doctype,)) ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) ## ensure that this submission exists for this doctype: numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action) if numrows_submission > 1: ## there are multiple submissions for this doctype/action ID: ## TODO : LOG ERROR user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \ % (action, doctype)) (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) elif numrows_submission == 0: ## this submission does not seem to exist for this doctype: user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \ % (action, doctype)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) - + ## submission valid if movefromfunctionname != "" and movefromfunctionstep != "" and movefromfunctionscore != "" and \ movetofunctionname != "" and movetofunctionstep != "" and movetofunctionscore != "": ## process moving the function by jumping it to another position try: move_submission_function_from_one_position_to_another_position(doctype=doctype, action=action, movefuncname=movefromfunctionname, movefuncfromstep=movefromfunctionstep, movefuncfromscore=movefromfunctionscore, movefunctostep=movetofunctionstep, movefunctoscore=movetofunctionscore) user_msg.append("""The function [%s] at step [%s], score [%s] was successfully moved."""\ % (movefromfunctionname, movefromfunctionstep, movefromfunctionscore)) except Exception, e: ## there was a problem user_msg.append(str(e)) (title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) elif moveupfunctionname != "" and moveupfunctionstep != "" and moveupfunctionscore != "": ## process moving the function up one position error_code = move_position_submissionfunction_up(doctype=doctype, action=action, function=moveupfunctionname, funccurstep=moveupfunctionstep, funccurscore=moveupfunctionscore) if error_code == 0: ## success user_msg.append("""The Function "%s" that was located at step %s, score %s, has been moved upwards""" \ % (moveupfunctionname, moveupfunctionstep, moveupfunctionscore)) else: ## could not move it user_msg.append("""Unable to move the Function "%s" that is located at step %s, score %s""" \ % (moveupfunctionname, moveupfunctionstep, moveupfunctionscore)) (title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) elif movedownfunctionname != "" and movedownfunctionstep != "" and movedownfunctionscore != "": ## process moving the function down one position error_code = move_position_submissionfunction_down(doctype=doctype, action=action, function=movedownfunctionname, funccurstep=movedownfunctionstep, funccurscore=movedownfunctionscore) if error_code == 0: ## success user_msg.append("""The Function "%s" that was located at step %s, score %s, has been moved downwards""" \ % (movedownfunctionname, movedownfunctionstep, movedownfunctionscore)) else: ## could not move it user_msg.append("""Unable to move the Function "%s" that is located at step %s, score %s""" \ % (movedownfunctionname, movedownfunctionstep, movedownfunctionscore)) (title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) elif deletefunctionname != "" and deletefunctionstep != "" and deletefunctionscore != "": ## process deletion of function from the given position (title, body) = _delete_submission_function(doctype=doctype, action=action, deletefunctionname=deletefunctionname, deletefunctionstep=deletefunctionstep, deletefunctionscore=deletefunctionscore) elif configuresubmissionaddfunction != "": ## display a form that allows the addition of a new WebSubmit function (title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype, action=action) elif configuresubmissionaddfunctioncommit != "": ## process the addition of the new WebSubmit function to the submission: (title, body) = _add_function_to_submission(doctype=doctype, action=action, addfunctionname=addfunctionname, addfunctionstep=addfunctionstep, addfunctionscore=addfunctionscore) else: ## default - display functions for this submission (title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, movefromfunctionname=movefromfunctionname, movefromfunctionstep=movefromfunctionstep, movefromfunctionscore=movefromfunctionscore ) return (title, body, errors, warnings) def _add_function_to_submission(doctype, action, addfunctionname, addfunctionstep, addfunctionscore): """Process the addition of a function to a submission. The user can decide in which step and at which score to insert the function. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param addfunctionname: (string) the name of the function to be added to the submission @param addfunctionstep: (integer) the step at which the function is to be added @param addfunctionscore: (integer) the score at which the function is to be added @return: a tuple containing 2 strings: (page-title, page-body) """ user_msg = [] if addfunctionname == "" or addfunctionstep == "" or addfunctionscore == "": ## invalid details! user_msg.append("""Invalid function coordinates supplied!""") (title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) try: if int(addfunctionstep) < 1 or int(addfunctionscore) < 1: ## invalid details! user_msg.append("""Invalid function step and/or score!""") (title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) except ValueError: user_msg.append("""Invalid function step and/or score!""") (title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype, action=action, user_msg=user_msg) try: insert_function_into_submission_at_step_and_score_then_regulate_scores_of_functions_in_step(doctype=doctype, action=action, function=addfunctionname, step=addfunctionstep, score=addfunctionscore) except InvenioWebSubmitAdminWarningReferentialIntegrityViolation, e: ## Function didn't exist in WebSubmit! Not added to submission. user_msg.append(str(e)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype, action=action, addfunctionstep=addfunctionstep, addfunctionscore=addfunctionscore, user_msg=user_msg) return (title, body) except InvenioWebSubmitAdminWarningInsertFailed, e: ## insert failed - some functions within the step may have been corrupted! user_msg.append(str(e)) ## TODO : LOG ERROR (title, body) = \ _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) except InvenioWebSubmitAdminWarningDeleteFailed, e: ## when regulating the scores of functions within the step, could not delete some or all of the functions ## within the step that the function was added to. Some functions may have been lost! user_msg.append(str(e)) ## TODO : LOG ERROR (title, body) = \ _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) ## Successfully added user_msg.append("""The function [%s] has been added to submission [%s] at step [%s], score [%s]."""\ % (addfunctionname, "%s%s" % (action, doctype), addfunctionstep, addfunctionscore)) (title, body) = \ _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) def _delete_submission_function(doctype, action, deletefunctionname, deletefunctionstep, deletefunctionscore): """Delete a submission function from a given submission. Re-order all functions below it (within the same step) to fill the gap left by the deleted function. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param deletefunctionname: (string) the name of the function to be deleted from the submission @param deletefunctionstep: (string) the step of the function to be deleted from the submission @param deletefunctionscore: (string) the score of the function to be deleted from the submission @return: tuple containing 2 strings: (page-title, page-body) """ user_msg = [] ## first, delete the function: try: delete_function_at_step_and_score_from_submission(doctype=doctype, action=action, function=deletefunctionname, step=deletefunctionstep, score=deletefunctionscore) except InvenioWebSubmitAdminWarningDeleteFailed, e: ## unable to delete function - error message and return user_msg.append("""Unable to delete function [%s] at step [%s], score [%s] from submission [%s]""" \ % (deletefunctionname, deletefunctionstep, deletefunctionscore, "%s%s" % (action, doctype))) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) ## now, correct the scores of all functions in the step from which a function was just deleted: try: regulate_score_of_all_functions_in_step_to_ascending_multiples_of_10_for_submission(doctype=doctype, action=action, step=deletefunctionstep) except InvenioWebSubmitAdminWarningDeleteFailed, e: ## couldnt delete the functions before reordering them user_msg.append("""Deleted function [%s] at step [%s], score [%s] from submission [%s], but could not re-order""" \ """ scores of remaining functions within step [%s]""" \ % (deletefunctionname, deletefunctionstep, deletefunctionscore, "%s%s" % (action, doctype), deletefunctionstep)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) ## update submission "last-modification" date: update_modification_date_for_submission(doctype=doctype, action=action) ## success message: user_msg.append("""Successfully deleted function [%s] at step [%s], score [%s] from submission [%s]""" \ % (deletefunctionname, deletefunctionstep, deletefunctionscore, "%s%s" % (action, doctype))) ## TODO : LOG function Deletion (title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) def perform_request_configure_doctype_submissionpage_preview(doctype, action, pagenum): """Display a preview of a Submission Page and its fields. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param pagenum: (integer) the number of the submission page to be previewed @return: a tuple of four elements. (page-title, page-body, errors, warnings) """ errors = [] warnings = [] body = "" user_msg = [] try: pagenum = str(pagenum) except ValueError: pagenum = "" if pagenum != "": try: pagenum = str(wash_single_urlarg(urlarg=pagenum, argreqdtype=int, argdefault="")) except ValueError, e: pagenum = "" ## ensure that the page number for this submission is valid: num_pages_submission = get_numbersubmissionpages_doctype_action(doctype=doctype, action=action) try: if not (int(pagenum) > 0 and int(pagenum) <= num_pages_submission): user_msg.append("Invalid page number - out of range") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body, errors, warnings) except ValueError: ## invalid page number user_msg.append("Invalid page number - must be an integer value!") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body, errors, warnings) ## get details of all fields on submission page: fields = get_details_and_description_of_all_fields_on_submissionpage(doctype=doctype, action=action, pagenum=pagenum) ## ensure all values for each field are strings: string_fields = [] for field in fields: string_fields.append(stringify_list_elements(field)) title = """A preview of Page %s of the %s Submission""" % (pagenum, "%s%s" % (action, doctype)) body = websubmitadmin_templates.tmpl_configuredoctype_display_submissionpage_preview(doctype=doctype, action=action, pagenum=pagenum, fields=string_fields) return (title, body, errors, warnings) def perform_request_configure_doctype_submissionpage_elements(doctype, action, pagenum, movefieldfromposn="", movefieldtoposn="", deletefieldposn="", editfieldposn="", editfieldposncommit="", fieldname="", fieldtext="", fieldlevel="", fieldshortdesc="", fieldcheck="", addfield="", addfieldcommit=""): """Process requests relating to the elements of a particular submission page""" errors = [] warnings = [] body = "" user_msg = [] try: pagenum = str(pagenum) except ValueError: pagenum = "" if pagenum != "": try: pagenum = str(wash_single_urlarg(urlarg=pagenum, argreqdtype=int, argdefault="")) except ValueError, e: pagenum = "" if fieldname != "": try: fieldname = wash_single_urlarg(urlarg=fieldname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=fieldname) == 0: fieldname = "" except ValueError, e: fieldname = "" if fieldtext != "": try: fieldtext = wash_single_urlarg(urlarg=fieldtext, argreqdtype=str, argdefault="") except ValueError, e: fieldtext = "" if fieldlevel != "": try: fieldlevel = wash_single_urlarg(urlarg=fieldlevel, argreqdtype=str, argdefault="O", maxstrlen=1, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=fieldlevel) == 0: fieldlevel = "O" if fieldlevel not in ("m", "M", "o", "O"): fieldlevel = "O" fieldlevel = fieldlevel.upper() except ValueError, e: fieldlevel = "O" if fieldshortdesc != "": try: fieldshortdesc = wash_single_urlarg(urlarg=fieldshortdesc, argreqdtype=str, argdefault="") except ValueError, e: fieldshortdesc = "" if fieldcheck != "": try: fieldcheck = wash_single_urlarg(urlarg=fieldcheck, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1) if string_is_alphanumeric_including_underscore(txtstring=fieldcheck) == 0: fieldcheck = "" except ValueError, e: fieldcheck = "" if editfieldposn != "": try: editfieldposn = str(wash_single_urlarg(urlarg=editfieldposn, argreqdtype=int, argdefault="")) except ValueError, e: editfieldposn = "" if deletefieldposn != "": try: deletefieldposn = str(wash_single_urlarg(urlarg=deletefieldposn, argreqdtype=int, argdefault="")) except ValueError, e: deletefieldposn = "" if movefieldfromposn != "": try: movefieldfromposn = str(wash_single_urlarg(urlarg=movefieldfromposn, argreqdtype=int, argdefault="")) except ValueError, e: movefieldfromposn = "" if movefieldtoposn != "": try: movefieldtoposn = str(wash_single_urlarg(urlarg=movefieldtoposn, argreqdtype=int, argdefault="")) except ValueError, e: movefieldtoposn = "" ## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not if doctype in ("", None): user_msg.append("""Unknown Document Type""") ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) numrows_doctype = get_number_doctypes_docid(docid=doctype) if numrows_doctype > 1: ## there are multiple doctypes with this doctype ID: ## TODO : LOG ERROR user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \ % (doctype,)) all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) elif numrows_doctype == 0: ## this doctype does not seem to exist: user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \ % (doctype,)) ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) ## ensure that this submission exists for this doctype: numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action) if numrows_submission > 1: ## there are multiple submissions for this doctype/action ID: ## TODO : LOG ERROR user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \ % (action, doctype)) (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) elif numrows_submission == 0: ## this submission does not seem to exist for this doctype: user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \ % (action, doctype)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) ## ensure that the page number for this submission is valid: num_pages_submission = get_numbersubmissionpages_doctype_action(doctype=doctype, action=action) try: if not (int(pagenum) > 0 and int(pagenum) <= num_pages_submission): user_msg.append("Invalid page number - out of range") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body, errors, warnings) except ValueError: ## invalid page number user_msg.append("Invalid page number - must be an integer value!") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body, errors, warnings) - - + + ## submission valid if editfieldposn != "" and editfieldposncommit == "": ## display form for editing field (title, body) = _configure_doctype_edit_field_on_submissionpage_display_field_details(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum, fieldposn=editfieldposn) elif editfieldposn != "" and editfieldposncommit != "": ## commit changes to element (title, body) = _configure_doctype_edit_field_on_submissionpage(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum, fieldposn=editfieldposn, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck) elif movefieldfromposn != "" and movefieldtoposn != "": ## move a field (title, body) = _configure_doctype_move_field_on_submissionpage(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum, movefieldfromposn=movefieldfromposn, movefieldtoposn=movefieldtoposn) elif addfield != "": ## request to add a new field to a page - display form (title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype=doctype, action=action, pagenum=pagenum) elif addfieldcommit != "": ## commit a new field to the page (title, body) = _configure_doctype_add_field_to_submissionpage(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum, fieldname=fieldname, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck) elif deletefieldposn != "": ## user wishes to delete a field from the page: (title, body) = _configure_doctype_delete_field_from_submissionpage(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum, fieldnum=deletefieldposn) else: ## default visit to page - list its elements: (title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, movefieldfromposn=movefieldfromposn) return (title, body, errors, warnings) def stringify_list_elements(elementslist): o = [] for el in elementslist: o.append(str(el)) return o def _configure_doctype_edit_field_on_submissionpage(errors, warnings, doctype, action, pagenum, fieldposn, fieldtext, fieldlevel, fieldshortdesc, fieldcheck): """Perform an update to the details of a field on a submission page. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param pagenum: (integer) the number of the page on which the element to be updated is found @param fieldposn: (integer) the numeric position of the field to be editied @param fieldtext: (string) the text label displayed with a field @param fieldlevel: (char) M or O (whether the field is mandatory or optional) @param fieldshortdesc: (string) the short description of a field @param fieldcheck: (string) the name of a JavaScript check to be applied to a field @return: a tuple containing 2 strings - (page-title, page-body) """ user_msg = [] if fieldcheck not in ("", None): ## ensure check exists: checkres = get_number_jschecks_with_chname(chname=fieldcheck) if checkres < 1: user_msg.append("The Check '%s' does not exist in WebSubmit - changes to field not saved" % (fieldcheck,)) (title, body) = _configure_doctype_edit_field_on_submissionpage_display_field_details(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum, fieldposn=fieldposn, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, user_msg=user_msg) return (title, body) try: update_details_of_a_field_on_a_submissionpage(doctype=doctype, action=action, pagenum=pagenum, fieldposn=fieldposn, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck) user_msg.append("The details of the field at position %s have been updated successfully" % (fieldposn,)) update_modification_date_for_submission(doctype=doctype, action=action) except InvenioWebSubmitAdminWarningTooManyRows, e: ## multiple rows found at page position - not safe to edit: user_msg.append("Unable to update details of field at position %s on submission page %s - multiple fields found at this position" \ % (fieldposn, pagenum)) ## TODO : LOG WARNING except InvenioWebSubmitAdminWarningNoRowsFound, e: ## field not found - cannot edit user_msg.append("Unable to update details of field at position %s on submission page %s - field doesn't seem to exist there!" \ % (fieldposn, pagenum)) ## TODO : LOG WARNING (title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg) - return (title, body) + return (title, body) def _configure_doctype_edit_field_on_submissionpage_display_field_details(errors, warnings, doctype, action, pagenum, fieldposn, fieldtext=None, fieldlevel=None, fieldshortdesc=None, fieldcheck=None, user_msg=""): """Display a form used to edit a field on a submission page. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param pagenum: (integer) the number of the page on which the element to be updated is found @param fieldposn: (integer) the numeric position of the field to be editied @param fieldtext: (string) the text label displayed with a field @param fieldlevel: (char) M or O (whether the field is mandatory or optional) @param fieldshortdesc: (string) the short description of a field @param fieldcheck: (string) the name of a JavaScript check to be applied to a field @param user_msg: (list of strings, or string) any warning/error message to be displayed to the user @return: a tuple containing 2 strings (page-title, page-body) """ if type(user_msg) not in (list, tuple) or user_msg == "": user_msg = [] ## get a list of all check names: checks_res = get_all_jscheck_names() allchecks=[] for check in checks_res: allchecks.append((check,)) ## get the details for the field to be edited: fielddets = get_details_of_field_at_positionx_on_submissionpage(doctype=doctype, action=action, pagenum=pagenum, fieldposition=fieldposn) if len(fielddets) < 1: (title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum) return (title, body) fieldname = str(fielddets[2]) if fieldtext is not None: fieldtext = str(fieldtext) else: fieldtext = str(fielddets[3]) if fieldlevel is not None: fieldlevel = str(fieldlevel) else: fieldlevel = str(fielddets[4]) if fieldshortdesc is not None: fieldshortdesc = str(fieldshortdesc) else: fieldshortdesc = str(fielddets[5]) if fieldcheck is not None: fieldcheck = str(fieldcheck) else: fieldcheck = str(fielddets[6]) cd = str(fielddets[7]) md = str(fielddets[8]) title = """Edit the %(fieldname)s field as it appears at position %(fieldnum)s on Page %(pagenum)s of the %(submission)s Submission""" \ % { 'fieldname' : fieldname, 'fieldnum' : fieldposn, 'pagenum' : pagenum, 'submission' : "%s%s" % (action, doctype) } body = websubmitadmin_templates.tmpl_configuredoctype_edit_submissionfield(doctype=doctype, action=action, pagenum=pagenum, fieldnum=fieldposn, fieldname=fieldname, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck, cd=cd, md=md, allchecks=allchecks, user_msg=user_msg) return (title, body) def _configure_doctype_add_field_to_submissionpage(errors, warnings, doctype, action, pagenum, fieldname="", fieldtext="", fieldlevel="", fieldshortdesc="", fieldcheck=""): """Add a field to a submission page. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param pagenum: (integer) the number of the page on which the element to be updated is found @param fieldname: (string) the name of the field to be added to the page @param fieldtext: (string) the text label displayed with a field @param fieldlevel: (char) M or O (whether the field is mandatory or optional) @param fieldshortdesc: (string) the short description of a field @param fieldcheck: (string) the name of a JavaScript check to be applied to a field @return: a tuple containing 2 strings - (page-title, page-body) """ user_msg = [] ## ensure that a field "fieldname" actually exists: if fieldname == "": ## the field to be added has no element description in the WebSubmit DB - cannot add user_msg.append("""The field that you have chosen to add does not seem to exist in WebSubmit - cannot add""") (title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck, user_msg=user_msg) return (title, body) numelements_elname = get_number_elements_with_elname(elname=fieldname) if numelements_elname < 1: ## the field to be added has no element description in the WebSubmit DB - cannot add user_msg.append("""The field that you have chosen to add (%s) does not seem to exist in WebSubmit - cannot add""" % (fieldname,)) (title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck, user_msg=user_msg) return (title, body) ## if fieldcheck has been provided, ensure that it is a valid check name: if fieldcheck not in ("", None): ## ensure check exists: checkres = get_number_jschecks_with_chname(chname=fieldcheck) if checkres < 1: user_msg.append("The Check '%s' does not exist in WebSubmit - new field not saved to page" % (fieldcheck,)) (title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum, fieldname=fieldname, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, user_msg=user_msg) return (title, body) ## now add the new field to the page: try: insert_field_onto_submissionpage(doctype=doctype, action=action, pagenum=pagenum, fieldname=fieldname, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck) user_msg.append("""Successfully added the field "%s" to the last position on page %s of submission %s""" \ % (fieldname, pagenum, "%s%s" % (action, doctype))) update_modification_date_for_submission(doctype=doctype, action=action) (title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg) except InvenioWebSubmitAdminWarningInsertFailed, e: ## the insert of the new field failed for some reason ## TODO : LOG ERROR user_msg.append("""Couldn't add the field "%s" to page %s of submission %s - please try again""" \ % (fieldname, pagenum, "%s%s" % (action, doctype))) (title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum, fieldname=fieldname, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck, user_msg=user_msg) - return (title, body) + return (title, body) def _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum, fieldname="", fieldtext="", fieldlevel="", fieldshortdesc="", fieldcheck="", user_msg=""): title = """Add a Field to Page %(pagenum)s of the %(submission)s Submission""" \ % { 'pagenum' : pagenum, 'submission' : "%s%s" % (action, doctype) } ## sanity checking: if type(user_msg) not in (list, tuple) or user_msg == "": user_msg = [] ## get a list of all check names: checks_res = get_all_jscheck_names() allchecks=[] for check in checks_res: allchecks.append((check,)) ## get a list of all WebSubmit element names: elements_res = get_all_element_names() allelements = [] for el in elements_res: allelements.append((el,)) ## get form: body = websubmitadmin_templates.tmpl_configuredoctype_add_submissionfield(doctype=doctype, action=action, pagenum=pagenum, fieldname=fieldname, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck, allchecks=allchecks, allelements=allelements, user_msg=user_msg) return (title, body) def _configure_doctype_move_field_on_submissionpage(errors, warnings, doctype, action, pagenum, movefieldfromposn, movefieldtoposn): user_msg = [] movefield_res = move_field_on_submissionpage_from_positionx_to_positiony(doctype=doctype, action=action, pagenum=pagenum, movefieldfrom=movefieldfromposn, movefieldto=movefieldtoposn) if movefield_res == \ 'WRN_WEBSUBMITADMIN_INVALID_FIELD_NUMBERS_SUPPLIED_WHEN_TRYING_TO_MOVE_FIELD_ON_SUBMISSION_PAGE': ## invalid field numbers warnings.append(('WRN_WEBSUBMITADMIN_INVALID_FIELD_NUMBERS_SUPPLIED_WHEN_TRYING_TO_MOVE_FIELD_ON_SUBMISSION_PAGE', \ movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype))) user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - field position numbers invalid""" \ % (movefieldfromposn, movefieldtoposn, pagenum, action, doctype)) elif movefield_res == \ 'WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_TEMP_POSITION': ## failed to swap 2 fields - couldn't move field1 to temp position warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_TEMP_POSITION', \ movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype))) user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s""" \ % (movefieldfromposn, movefieldtoposn, pagenum, action, doctype)) elif movefield_res == \ 'WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD2_TO_FIELD1_POSITION': ## failed to swap 2 fields on submission page - couldn't move field2 to field1 position warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD2_TO_FIELD1_POSITION', \ movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldtoposn, movefieldfromposn)) user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - See Admin if field order is broken""" \ % (movefieldfromposn, movefieldtoposn, pagenum, action, doctype)) elif movefield_res == \ 'WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_POSITION_FIELD2_FROM_TEMPORARY_POSITION': ## failed to swap 2 fields in submission page - couldnt swap field at temp position to field2 position warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_POSITION_FIELD2_FROM_TEMPORARY_POSITION', \ movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldfromposn, movefieldtoposn)) user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - Field-order is now broken and must be corrected by Admin""" \ % (movefieldfromposn, movefieldtoposn, pagenum, action, doctype)) elif movefield_res == \ 'WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_DECREMENT_POSITION_OF_FIELDS_BELOW_FIELD1': ## failed to decrement the position of all fields below the field that was moved to a temp position warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_DECREMENT_POSITION_OF_FIELDS_BELOW_FIELD1', \ movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldfromposn)) user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - See Admin if field-order is broken""" \ % (movefieldfromposn, movefieldtoposn, pagenum, action, doctype)) elif movefield_res == \ 'WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_INCREMENT_POSITION_OF_FIELDS_AT_AND_BELOW_FIELD2': ## failed to increment position of fields in and below position into which 'movefromfieldposn' is to be inserted warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_INCREMENT_POSITION_OF_FIELDS_AT_AND_BELOW_FIELD2', \ movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldtoposn, movefieldfromposn)) user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - Field-order is now broken and must be corrected by Admin""" \ % (movefieldfromposn, movefieldtoposn, pagenum, action, doctype)) else: ## successful update: warnings.append(('WRN_WEBSUBMITADMIN_MOVED_FIELD_ON_SUBMISSION_PAGE', movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype))) user_msg.append("""Successfully moved field from position %s to position %s on page %s of submission %s%s""" \ % (movefieldfromposn, movefieldtoposn, pagenum, action, doctype)) (title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg) return (title, body) def _configure_doctype_delete_field_from_submissionpage(errors, warnings, doctype, action, pagenum, fieldnum): """Delete a field from a submission page""" user_msg = [] del_res = delete_a_field_from_submissionpage_then_reorder_fields_below_to_fill_vacant_position(doctype=doctype, action=action, pagenum=pagenum, fieldposn=fieldnum) if del_res == 'WRN_WEBSUBMITADMIN_UNABLE_TO_DELETE_FIELD_FROM_SUBMISSION_PAGE': warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_DELETE_FIELD_FROM_SUBMISSION_PAGE', fieldnum, pagenum, "%s%s" % (action, doctype))) user_msg.append("Unable to delete field at position %s from page number %s of submission %s%s" % (fieldnum, pagenum, action, doctype)) else: ## deletion was OK user_msg.append("Field deleted") warnings.append(('WRN_WEBSUBMITADMIN_DELETED_FIELD_FROM_SUBMISSION_PAGE', fieldnum, pagenum, "%s%s" % (action, doctype))) (title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg) return (title, body) def _create_configure_doctype_submission_page_elements_form(doctype, action, pagenum, movefieldfromposn="", user_msg=""): ## get list of elements for page: title = """Submission Elements found on Page %s of the "%s" Submission of the "%s" Document Type:"""\ % (pagenum, action, doctype) body = "" raw_page_elements = get_details_allsubmissionfields_on_submission_page(doctype=doctype, action=action, pagenum=pagenum) ## correctly stringify page elements for the template: page_elements = [] for element in raw_page_elements: page_elements.append(stringify_list_elements(element)) body = websubmitadmin_templates.tmpl_configuredoctype_list_submissionelements(doctype=doctype, action=action, pagenum=pagenum, page_elements=page_elements, movefieldfromposn=movefieldfromposn, user_msg=user_msg) return (title, body) def perform_request_configure_doctype_submissionpages(doctype, action, pagenum="", movepage="", movepagedirection="", deletepage="", deletepageconfirm="", addpage=""): """Process requests relating to the submission pages of a doctype/submission""" errors = [] warnings = [] body = "" user_msg = [] try: pagenum = int(pagenum) except ValueError: pagenum = "" - + ## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not if doctype in ("", None): user_msg.append("""Unknown Document Type""") ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) numrows_doctype = get_number_doctypes_docid(docid=doctype) if numrows_doctype > 1: ## there are multiple doctypes with this doctype ID: ## TODO : LOG ERROR user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \ % (doctype,)) all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) elif numrows_doctype == 0: ## this doctype does not seem to exist: user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \ % (doctype,)) ## TODO : LOG ERROR all_doctypes = get_docid_docname_alldoctypes() body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg) title = "Available WebSubmit Document Types" return (title, body, errors, warnings) ## ensure that this submission exists for this doctype: numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action) if numrows_submission > 1: ## there are multiple submissions for this doctype/action ID: ## TODO : LOG ERROR user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \ % (action, doctype)) (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) elif numrows_submission == 0: ## this submission does not seem to exist for this doctype: user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \ % (action, doctype)) ## TODO : LOG ERROR (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body, errors, warnings) ## submission valid if addpage != "": ## add a new page to a submission: error_code = add_submission_page_doctype_action(doctype=doctype, action=action) if error_code == 0: ## success user_msg.append("""A new Submission Page has been added into the last position""") else: ## could not move it user_msg.append("""Unable to add a new Submission Page""") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) elif movepage != "": ## user wants to move a page upwards in the order (title, body) = _configure_doctype_move_submission_page(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum, direction=movepagedirection) elif deletepage != "": ## user wants to delete a page: if deletepageconfirm != "": ## confirmation of deletion has been provided - proceed (title, body) = _configure_doctype_delete_submission_page(errors=errors, warnings=warnings, doctype=doctype, action=action, pagenum=pagenum) else: ## user has not yet confirmed the deletion of a page - prompt for confirmation (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, deletepagenum=pagenum) else: ## default - display details of submission pages for this submission: (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action) return (title, body, errors, warnings) def _configure_doctype_move_submission_page(errors, warnings, doctype, action, pagenum, direction): user_msg = [] ## Sanity checking: if direction.lower() not in ("up", "down"): ## invalid direction: user_msg.append("""Invalid Page destination - no action was taken""") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) ## swap the pages: if direction.lower() == "up": error_code = swap_elements_adjacent_pages_doctype_action(doctype=doctype, action=action, page1=pagenum, page2=pagenum-1) else: error_code = swap_elements_adjacent_pages_doctype_action(doctype=doctype, action=action, page1=pagenum, page2=pagenum+1) if error_code == 0: ## pages swapped successfully: ## TODO : LOG PAGE SWAP user_msg.append("""Page %s was successfully moved %swards""" % (pagenum, direction.capitalize())) elif error_code == 1: ## pages are not adjacent: user_msg.append("""Unable to move page - only adjacent pages can be swapped around""") elif error_code == 2: ## at least one page out of legal range (e.g. trying to move a page to a position higher or lower ## than the number of pages: user_msg.append("""Unable to move page to illegal position""") elif error_code in (3, 4): ## Some sort of problem moving fields around! ## TODO : LOG ERROR user_msg.append("""Error: there was a problem swapping the submission elements to their new pages.""") user_msg.append("""An attempt was made to return the elements to their original pages - you """\ """should verify that this was successful, or ask your administrator"""\ """ to fix the problem manually""") elif error_code == 5: ## the elements from the first page were left stranded in the temporary page! ## TODO : LOG ERROR user_msg.append("""Error: there was a problem swapping the submission elements to their new pages.""") user_msg.append("""Some elements were left stranded on a temporary page. Please ask your administrator to"""\ """ fix this problem manually""") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) return (title, body) def _configure_doctype_delete_submission_page(errors, warnings, doctype, action, pagenum): user_msg = [] num_pages = get_numbersubmissionpages_doctype_action(doctype=doctype, action=action) if num_pages > 0: ## proceed with deletion error_code = delete_allfields_submissionpage_doctype_action(doctype=doctype, action=action, pagenum=pagenum) if error_code == 0: ## everything OK ## move elements from pages above the deleted page down by one page: decrement_by_one_pagenumber_submissionelements_abovepage(doctype=doctype, action=action, frompage=pagenum) ## now decrement the number of pages associated with the submission: error_code = decrement_by_one_number_submissionpages_doctype_action(doctype=doctype, action=action) if error_code == 0: ## successfully deleted submission page ## TODO : LOG DELETION user_msg.append("""Page number %s of Submission %s was successfully deleted."""\ % (pagenum, action)) (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) else: ## error - either submission didn't exist, or multiple instances found ## TODO : LOG ERROR user_msg.append("""The Submission elements were deleted from Page %s of the Submission "%s"."""\ """ However, it was not possible to delete the page itself."""\ % (pagenum, action)) (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) else: ## unable to delete some or all fields from the page ## TODO : LOG ERROR user_msg.append("""Error: Unable to delete some field elements from Page %s of Submission %s%s - """\ """Page not deleted!""" % (pagenum, action, doctype)) (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) elif num_pages == 0: ## no pages to delete for this submission user_msg.append("""This Submission has no Pages - Cannot delete a Page!""") (title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg) else: ## error - couldn't determine the number of pages for submission ## TODO : LOG ERROR user_msg.append("""Unable to determine number of Submission Pages for Submission "%s" - """\ """Cannot delete page %s"""\ % (action, pagenum)) (title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg) return (title, body) def _create_configure_doctype_submission_pages_form(doctype, action, deletepagenum="", user_msg=""): """Perform the necessary steps in order to display a list of the pages belonging to a given submission of a given document type. @param doctype: (string) the unique ID of the document type. @param action: (string) the unique name/ID of the action. @param user_msg: (string, or list) any message(s) to be displayed to the user. @return: a tuple containing 2 strings - the page title and the page body. """ title = """Details of the Pages of the "%s" Submission of the "%s" Document Type:""" % (action, doctype) submission_dets = get_cd_md_numbersubmissionpages_doctype_action(doctype=doctype, action=action) if len(submission_dets) > 0: cd = str(submission_dets[0][0]) md = str(submission_dets[0][1]) num_pages = submission_dets[0][2] else: (cd, md, num_pages) = ("", "", "0") body = websubmitadmin_templates.tmpl_configuredoctype_list_submissionpages(doctype=doctype, action=action, number_pages=num_pages, cd=cd, md=md, deletepagenum=deletepagenum, user_msg=user_msg) return (title, body) diff --git a/modules/websubmit/web/admin/referees.py b/modules/websubmit/web/admin/referees.py index de4458010..8f29b74ba 100644 --- a/modules/websubmit/web/admin/referees.py +++ b/modules/websubmit/web/admin/referees.py @@ -1,227 +1,227 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" ## import interesting modules: import string import os import sys import time import types import re import shutil from invenio.config import \ cdslang, \ cdsname, \ images, \ version, \ weburl from invenio.dbquery import run_sql, Error from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import * from invenio.webpage import page, create_error_box from invenio.webuser import getUid, get_email, list_registered_users from invenio.messages import wash_language from invenio.websubmit_config import * def index(req,c=cdsname,ln=cdslang,todo="",id="",doctype="",categ="",addusers="",warningText="",role=""): ln = wash_language(ln) # get user ID: try: uid = getUid(req) uid_email = get_email(uid) except Error, e: return errorMsg(e.value,req) - (auth_code, auth_message) = acc_authorize_action(uid, "cfgwebsubmit",verbose=0) + (auth_code, auth_message) = acc_authorize_action(req, "cfgwebsubmit",verbose=0) if auth_code != 0: return errorMsg(auth_message, req, uid) # request for deleting a user if todo == "deleteuser": acc_deleteUserRole(id,name_role=role) # request for adding user(s) if todo == "adduser": role = "referee_%s_%s" % (doctype,categ[1]) roleId = acc_getRoleId(role) # if the role does not exists, we create it if roleId == 0: if acc_addRole(role,"referees for document type %s category %s" % (doctype,categ[1])) == 0: return errorMsg("Cannot create referee role",req) else: roleId = acc_getRoleId(role) # if the action does not exist, we create it actionId = acc_getActionId("referee") if actionId == 0: if acc_addAction("referee","","no",("doctype","categ")) == 0: return errorMsg("Cannot create action 'referee'",req) else: actionId = acc_getActionId("referee") #create arguments arg1Id = acc_addArgument("doctype",doctype) arg2Id = acc_addArgument("categ",categ[1]) # then link the role with the action if acc_addRoleActionArguments(roleId,actionId,-1,0,0,[arg1Id,arg2Id]) == 0: return errorMsg("Cannot link role with action",req) roleId = acc_getRoleId(role) # For each id in the array if isinstance(addusers,types.ListType): for adduser in addusers: # First check whether this id is not already associated with this rule myRoles = acc_getUserRoles(adduser) if not roleId in myRoles: # Actually add the role to the user acc_addUserRole(adduser,roleId) else: warningText = "Sorry... This user is already a referee for this category." else: # First check whether this id is not already associated with this rule myRoles = acc_getUserRoles(addusers) if not roleId in myRoles: # Actually add the role to the user acc_addUserRole(addusers,roleId) else: warningText = "Sorry... This user is already a referee for this category." return page(title="websubmit admin - referee selection", body=displayRefereesPage(doctype,warningText), description="", keywords="", uid=uid, language=ln, req=req) def displayRefereesPage(doctype,warningText): t="" if doctype == "*": docname = "all catalogues" else: res = run_sql("SELECT * FROM sbmDOCTYPE WHERE sdocname=%s", (doctype,)) docname = res[0][0] t+=warningText t+="""
    """ %doctype # call the function to display the table containing the list of associated emails t+=displayUserTable(doctype) t+=""" """ # call the function to display the form allowing the manager to add new users t+=displayAddUser(doctype) t+= """
    Finished
    """ % (weburl, doctype) return t - + def displayUserTable(doctype): t="" # start displaying the table which will contain the list of email addresses. t+= """ """ roles = acc_getAllRoles() referees = {} for role in roles: role_name = role[1] role_id = role[0] if re.match("^referee_%s_" % doctype,role_name): # Try to retrieve the referee's email from the referee's database if acc_getRoleUsers(role_id) is not None: referees[role_name] = acc_getRoleUsers(role_id) if len(referees) == 0: t+= "" % images i=0 for role in referees.keys(): categ = re.match("referee_%s_(.*)" % doctype,role).group(1) res = run_sql("SELECT lname FROM sbmCATEGORIES WHERE sname=%s and doctype=%s", (categ,doctype,)) if len(res) > 0: categname = "Referee(s) for category: %s" % res[0][0] else: categname = "General Referee(s)" t+= "" % categname for referee in referees[role]: if int(i/2) == i/2: bgcolor="#eeeeee" else: bgcolor="#dddddd" t+= "" % bgcolor t+= "" t+= ""; t+= ""; i+=1 # close table t+="" return t def displayAddUser(doctype): t="" # start displaying the table which will contain the add form t+= """ " return t def errorMsg(title,req,uid,c=cdsname,ln=cdslang): return page(title="error", body = create_error_box(req, title=title,verbose=0, ln=ln), - description="%s - Internal Error" % c, + description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, uid=uid, req=req) diff --git a/modules/websubmit/web/admin/websubmitadmin.py b/modules/websubmit/web/admin/websubmitadmin.py index dc89c26d1..f436a33c6 100644 --- a/modules/websubmit/web/admin/websubmitadmin.py +++ b/modules/websubmit/web/admin/websubmitadmin.py @@ -1,970 +1,970 @@ # -*- coding: utf-8 -*- ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" __lastupdated__ = """$Date$""" import sys from mod_python import apache from invenio.websubmitadmin_engine import * from invenio.config import cdslang from invenio.webuser import getUid, page_not_authorized from invenio.webpage import page from invenio.messages import wash_language, gettext_set_language def index(req, ln=cdslang): """Websubmit Admin home page. Default action: list all WebSubmit document types.""" - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_list_doctypes() return page(title = "Available WebSubmit Document Types", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def showall(req, ln=cdslang): """Placeholder for the showall functionality""" - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_list_doctypes() return page(title = "Available WebSubmit Document Types", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctypelist(req, ln=cdslang): """List all WebSubmit document types.""" - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_list_doctypes() return page(title = "Available WebSubmit Document Types", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def jschecklist(req, ln=cdslang): """List all WebSubmit JavaScript Checks (checks can be applied to form elements in WebSubmit.)""" - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_list_jschecks() return page(title = "Available WebSubmit Checking Functions", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def actionlist(req, ln=cdslang): """List all WebSubmit actions.""" - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_list_actions() return page(title = "Available WebSubmit Actions", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def functionlist(req, ln=cdslang): """List all WebSubmit FUNCTIONS (Functions do the work of processing a submission)""" - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_list_functions() return page(title = "Available WebSubmit Functions", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def elementlist(req, ln=cdslang): """List all WebSubmit form ELEMENTS (elements are input fields on a WebSubmit form)""" - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_list_elements() return page(title = "Available WebSubmit Elements", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def actionadd(req, actid=None, actname=None, working_dir=None, status_text=None, actcommit="", ln=cdslang): """Add a new action to the WebSubmit database. Web form for action details will be displayed if "actid" and "actname" are empty; else new action will be committed to websubmit. @param actid: unique id for new action (if empty, Web form will be displayed) @param actname: name of new action (if empty, Web form will be displayed) @param working_dir: action working directory for WebSubmit @param status_text: status text displayed at end of WebSubmit action @param ln: language @return page """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_add_action(actid, actname, working_dir, status_text, actcommit) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def actionedit(req, actid, actname=None, working_dir=None, status_text=None, actcommit="", ln=cdslang): """Display the details of a WebSubmit action in a Web form so that it can be viewed and/or edited. @param actid: The unique action identifier code. @param actname: name of action (if present, action will be updated, else action details will be displayed) @param working_dir: action working directory for websubmit @param status_text: status text displayed at end of websubmit action @param ln: language @return: page """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_edit_action(actid, actname, working_dir, status_text, actcommit) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def jscheckadd(req, chname=None, chdesc=None, chcommit="", ln=cdslang): """Add a new JavaScript CHECK to the WebSubmit database. Web form for action details will be displayed if "actid" and "actname" are empty; else new action will be committed to WebSubmit. @param chname: unique name/ID for new check (if empty, Web form will be displayed) @param chdesc: description of new JS check (the JavaScript code that is the check.) (If empty, Web form will be displayed) @param ln: language @return page """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_add_jscheck(chname, chdesc, chcommit) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def jscheckedit(req, chname, chdesc=None, chcommit="", ln=cdslang): """Display the details of a WebSubmit checking function in a Web form so that it can be viewed and/or edited. @param chname: The unique Check name/identifier code. @param chdesc: The description of the Check (if present, Check will be updated, else Check details will be displayed) @param ln: language @return: page """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_edit_jscheck(chname, chdesc, chcommit) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def elementadd(req, elname=None, elmarccode=None, eltype=None, elsize=None, elrows=None, elcols=None, elmaxlength=None, \ elval=None, elfidesc=None, elmodifytext=None, elcommit="", ln=cdslang): """Add a new WebSubmit ELEMENT to the WebSubmit database. @param elname: unique name/ID for new check (if empty, Web form will be displayed) @param elmarccode: MARC Code for element @param eltype: type of element. @param elsize: size of element. @param elrows: number of rows in element. @param elcols: number of columns in element. @param elmaxlength: element maximum length. @param elval: element value. @param elfidesc: element description. @param elmodifytext: Modification text for the element. @param elcommit: flag variable used to determine whether to commit element modifications or whether to simply display a form containing element details. @param ln: language @return page """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_add_element(elname, elmarccode, eltype, \ elsize, elrows, elcols, elmaxlength, \ elval, elfidesc, elmodifytext, \ elcommit) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def elementedit(req, elname, elmarccode=None, eltype=None, elsize=None, elrows=None, elcols=None, elmaxlength=None, \ elval=None, elfidesc=None, elmodifytext=None, elcommit="", ln=cdslang): """Display the details of a WebSubmit ELEMENT in a Web form so that it can be viewed and/or edited. @param elname: unique name/ID for new check (if empty, Web form will be displayed) @param elmarccode: MARC Code for element @param eltype: type of element. @param elsize: size of element. @param elrows: number of rows in element. @param elcols: number of columns in element. @param elmaxlength: element maximum length. @param elval: element value. @param elfidesc: element description. @param elmodifytext: Modification text for the element. @param elcommit: flag variable used to determine whether to commit element modifications or whether to simply display a form containing element details. @param ln: language @return page """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_edit_element(elname, elmarccode, eltype, \ elsize, elrows, elcols, elmaxlength, \ elval, elfidesc, elmodifytext, \ elcommit) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def functionadd(req, funcname=None, funcdescr=None, funcaddcommit="", ln=cdslang): """Add a new function to WebSubmit""" ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_add_function(funcname=funcname, funcdescr=funcdescr, funcaddcommit=funcaddcommit ) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def functionedit(req, funcname=None, funcdescr=None, funceditaddparam=None, funceditaddparamfree=None, \ funceditdelparam=None, funcdescreditcommit="", funcparamdelcommit="", funcparamaddcommit="", ln=cdslang): """Edit a WebSubmit function""" ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: # Generate content (title, body, errors, warnings) = perform_request_edit_function(funcname=funcname, funcdescr=funcdescr, funceditdelparam=funceditdelparam, funceditaddparam=funceditaddparam, funceditaddparamfree=funceditaddparamfree, funcdescreditcommit=funcdescreditcommit, funcparamdelcommit=funcparamdelcommit, funcparamaddcommit=funcparamaddcommit ) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def functionusage(req, funcname, ln=cdslang): """View the usage cases (document-type and actions) in which a function is used. @param function: the function name @param ln: the language @return: a web page """ - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (body, errors, warnings) = perform_request_function_usage(funcname) return page(title = "WebSubmit Function Usage", body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctyperemove(req, doctype="", doctypedelete="", doctypedeleteconfirm="", ln=cdslang): """Delete a WebSubmit document-type. @param doctype: the unique id of the document type to be deleted @param ln: the interface language @return: HTML page. """ - + ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = perform_request_remove_doctype(doctype=doctype, doctypedelete=doctypedelete, doctypedeleteconfirm=doctypedeleteconfirm) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctypeadd(req, doctype=None, doctypename=None, doctypedescr=None, clonefrom=None, doctypedetailscommit="", ln=cdslang): """Add a new document type to WebSubmit""" ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = perform_request_add_doctype(doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom, doctypedetailscommit=doctypedetailscommit ) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctypeconfiguresubmissionpageelements(req, doctype="", action="", pagenum="", movefieldfromposn="", movefieldtoposn="", deletefieldposn="", editfieldposn="", editfieldposncommit="", addfield="", addfieldcommit="", fieldname="", fieldtext="", fieldlevel="", fieldshortdesc="", fieldcheck="", ln=cdslang): ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = perform_request_configure_doctype_submissionpage_elements(doctype=doctype, action=action, pagenum=pagenum, movefieldfromposn=movefieldfromposn, movefieldtoposn=movefieldtoposn, deletefieldposn=deletefieldposn, editfieldposn=editfieldposn, editfieldposncommit=editfieldposncommit, addfield=addfield, addfieldcommit=addfieldcommit, fieldname=fieldname, fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctypeconfiguresubmissionpagespreview(req, doctype="", action="", pagenum="", ln=cdslang): ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = perform_request_configure_doctype_submissionpage_preview(doctype=doctype, action=action, pagenum=pagenum) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctypeconfiguresubmissionpages(req, doctype="", action="", pagenum="", movepage="", movepagedirection="", deletepage="", deletepageconfirm="", addpage="", ln=cdslang ): ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = perform_request_configure_doctype_submissionpages(doctype=doctype, action=action, pagenum=pagenum, movepage=movepage, movepagedirection=movepagedirection, deletepage=deletepage, deletepageconfirm=deletepageconfirm, addpage=addpage) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctypeconfiguresubmissionfunctionsparameters(req, doctype="", action="", functionname="", functionstep="", functionscore="", paramname="", paramval="", editfunctionparametervalue="", editfunctionparametervaluecommit="", editfunctionparameterfile="", editfunctionparameterfilecommit="", paramfilename="", paramfilecontent="", ln=cdslang): """Configure the parameters for a function belonging to a given submission. @param doctype: (string) the unique ID of a document type @param action: (string) the unique ID of an action @param functionname: (string) the name of a WebSubmit function @param functionstep: (integer) the step at which a WebSubmit function is located @param functionscore: (integer) the score (within a step) at which a WebSubmit function is located @param paramname: (string) the name of a parameter being edited @param paramval: (string) the value to be allocated to a parameter that is being editied @param editfunctionparametervalue: (string) a flag to signal that a form should be displayed for editing the value of a parameter @param editfunctionparametervaluecommit: (string) a flag to signal that a parameter value has been edited and should be committed @param editfunctionparameterfile: (string) a flag to signal that a form containing a parameter file is to be displayed @param editfunctionparameterfilecommit: (string) a flag to signal that a modified parameter file is to be committed @param paramfilename: (string) the name of a parameter file @param paramfilecontent: (string) the contents of a parameter file @param ln: (string) the language code (e.g. en, fr, de, etc); defaults to the default installation language @return: (string) HTML-page body """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) =\ perform_request_configure_doctype_submissionfunctions_parameters(doctype=doctype, action=action, functionname=functionname, functionstep=functionstep, functionscore=functionscore, paramname=paramname, paramval=paramval, editfunctionparametervalue=editfunctionparametervalue, editfunctionparametervaluecommit=editfunctionparametervaluecommit, editfunctionparameterfile=editfunctionparameterfile, editfunctionparameterfilecommit=editfunctionparameterfilecommit, paramfilename=paramfilename, paramfilecontent=paramfilecontent) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) - + def doctypeconfiguresubmissionfunctions(req, doctype="", action="", moveupfunctionname="", moveupfunctionstep="", moveupfunctionscore="", movedownfunctionname="", movedownfunctionstep="", movedownfunctionscore="", movefromfunctionname="", movefromfunctionstep="", movefromfunctionscore="", movetofunctionname="", movetofunctionstep="", movetofunctionscore="", deletefunctionname="", deletefunctionstep="", deletefunctionscore="", configuresubmissionaddfunction="", configuresubmissionaddfunctioncommit="", addfunctionname="", addfunctionstep="", addfunctionscore="", ln=cdslang): ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = \ perform_request_configure_doctype_submissionfunctions(doctype=doctype, action=action, moveupfunctionname=moveupfunctionname, moveupfunctionstep=moveupfunctionstep, moveupfunctionscore=moveupfunctionscore, movedownfunctionname=movedownfunctionname, movedownfunctionstep=movedownfunctionstep, movedownfunctionscore=movedownfunctionscore, movefromfunctionname=movefromfunctionname, movefromfunctionstep=movefromfunctionstep, movefromfunctionscore=movefromfunctionscore, movetofunctionname=movetofunctionname, movetofunctionstep=movetofunctionstep, movetofunctionscore=movetofunctionscore, deletefunctionname=deletefunctionname, deletefunctionstep=deletefunctionstep, deletefunctionscore=deletefunctionscore, configuresubmissionaddfunction=configuresubmissionaddfunction, configuresubmissionaddfunctioncommit=configuresubmissionaddfunctioncommit, addfunctionname=addfunctionname, addfunctionstep=addfunctionstep, addfunctionscore=addfunctionscore) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def doctypeconfigure(req, doctype, doctypename=None, doctypedescr=None, doctypedetailsedit="", doctypedetailscommit="", doctypecategoryadd="", doctypecategoryedit="", doctypecategoryeditcommit="", doctypecategorydelete="", doctypesubmissionadd="", doctypesubmissiondelete="", doctypesubmissiondeleteconfirm="", doctypesubmissionedit="", doctypesubmissionaddclonechosen="", doctypesubmissiondetailscommit="", doctypesubmissionadddetailscommit="", doctypesubmissioneditdetailscommit="", categid=None, categdescr=None, movecategup=None, movecategdown=None, jumpcategout=None, jumpcategin=None, action=None, displayed=None, buttonorder=None, statustext=None, level=None, score=None, stpage=None, endtxt=None, doctype_cloneactionfrom=None, ln=cdslang): """The main entry point to the configuration of a WebSubmit document type and its submission interfaces, functions, etc. """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = perform_request_configure_doctype(doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr, doctypedetailsedit=doctypedetailsedit, doctypedetailscommit=doctypedetailscommit, doctypecategoryadd=doctypecategoryadd, doctypecategoryedit=doctypecategoryedit, doctypecategoryeditcommit=doctypecategoryeditcommit, doctypecategorydelete=doctypecategorydelete, doctypesubmissionadd=doctypesubmissionadd, doctypesubmissiondelete=doctypesubmissiondelete, doctypesubmissiondeleteconfirm=doctypesubmissiondeleteconfirm, doctypesubmissionedit=doctypesubmissionedit, doctypesubmissionaddclonechosen=doctypesubmissionaddclonechosen, doctypesubmissionadddetailscommit=doctypesubmissionadddetailscommit, doctypesubmissioneditdetailscommit=doctypesubmissioneditdetailscommit, categid=categid, categdescr=categdescr, movecategup=movecategup, movecategdown=movecategdown, jumpcategout=jumpcategout, jumpcategin=jumpcategin, action=action, displayed=displayed, buttonorder=buttonorder, statustext=statustext, level=level, score=score, stpage=stpage, endtxt=endtxt, doctype_cloneactionfrom=doctype_cloneactionfrom) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) def organisesubmissionpage(req, doctype="", sbmcolid="", catscore="", addsbmcollection="", deletesbmcollection="", addtosbmcollection="", adddoctypes="", movesbmcollectionup="", movesbmcollectiondown="", deletedoctypefromsbmcollection="", movedoctypeupinsbmcollection="", movedoctypedowninsbmcollection="", ln=cdslang): """Entry point for organising the document types on a submission page. """ ln = wash_language(ln) _ = gettext_set_language(ln) uid = getUid(req) - (auth_code, auth_msg) = check_user(uid, 'cfgwebsubmit') + (auth_code, auth_msg) = check_user(req, 'cfgwebsubmit') if not auth_code: ## user is authorised to use WebSubmit Admin: (title, body, errors, warnings) = \ perform_request_organise_submission_page(doctype=doctype, sbmcolid=sbmcolid, catscore=catscore, addsbmcollection=addsbmcollection, deletesbmcollection=deletesbmcollection, addtosbmcollection=addtosbmcollection, adddoctypes=adddoctypes, movesbmcollectionup=movesbmcollectionup, movesbmcollectiondown=movesbmcollectiondown, deletedoctypefromsbmcollection=deletedoctypefromsbmcollection, movedoctypeupinsbmcollection=movedoctypeupinsbmcollection, movedoctypedowninsbmcollection=movedoctypedowninsbmcollection) return page(title = title, body = body, navtrail = get_navtrail(ln), uid = uid, lastupdated = __lastupdated__, req = req, language = ln, errors = errors, warnings = warnings) else: ## user is not authorised to use WebSubmit Admin: return page_not_authorized(req=req, text=auth_msg, navtrail=get_navtrail(ln)) diff --git a/modules/websubmit/web/approve.py b/modules/websubmit/web/approve.py index 0976b5298..99aeabf62 100644 --- a/modules/websubmit/web/approve.py +++ b/modules/websubmit/web/approve.py @@ -1,81 +1,81 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" - + ## import interesting modules: import string import os import sys import time import types import re from mod_python import apache from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_SITE, \ cdslang, \ cdsname, \ urlpath, \ version from invenio.dbquery import run_sql from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import acc_isRole from invenio.websubmit_config import * from invenio.webpage import page, create_error_box from invenio.webuser import getUid, get_email, page_not_authorized from invenio.messages import wash_language def index(req,c=cdsname,ln=cdslang): uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../approve.py/index", navmenuid='yourapprovals') ln = wash_language(ln) form = req.form if form.keys(): access = form.keys()[0] if access == "": return errorMsg("approve.py: cannot determine document reference",req) res = run_sql("select doctype,rn from sbmAPPROVAL where access=%s",(access,)) if len(res) == 0: return errorMsg("approve.py: cannot find document in database",req) else: doctype = res[0][0] rn = res[0][1] res = run_sql("select value from sbmPARAMETERS where name='edsrn' and doctype=%s",(doctype,)) edsrn = res[0][0] url = "%s/submit/sub?%s=%s&password=%s@APP%s" % (urlpath,edsrn,rn,access,doctype) req.err_headers_out.add("Location", url) raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY return "" else: return errorMsg("Sorry parameter missing...", req, c, ln) def errorMsg(title,req,c=cdsname,ln=cdslang): return page(title="error", body = create_error_box(req, title=title,verbose=0, ln=ln), - description="%s - Internal Error" % c, + description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='yourapprovals') diff --git a/modules/websubmit/web/publiline.py b/modules/websubmit/web/publiline.py index fecbd4b99..8f3e78326 100644 --- a/modules/websubmit/web/publiline.py +++ b/modules/websubmit/web/publiline.py @@ -1,383 +1,383 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" ## import interesting modules: import string import os import sys import time import types import re import shutil from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_SITE, \ accessurl, \ adminemail, \ cdslang, \ cdsname, \ images, \ pylibdir, \ storage, \ supportemail, \ sweburl, \ urlpath, \ version from invenio.dbquery import run_sql, Error from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import * from invenio.webpage import page, create_error_box from invenio.webuser import getUid, get_email, list_registered_users, page_not_authorized from invenio.messages import gettext_set_language, wash_language from invenio.websubmit_config import * from invenio.search_engine import search_pattern from invenio.websubmit_functions.Retrieve_Data import Get_Field from invenio.websubmit_functions.mail import forge_email, send_email execfile("%s/invenio/websubmit_functions/Retrieve_Data.py" % pylibdir) execfile("%s/invenio/websubmit_functions/mail.py" % pylibdir) import invenio.template websubmit_templates = invenio.template.load('websubmit') def index(req,c=cdsname,ln=cdslang,doctype="",categ="",RN="",send=""): global uid ln = wash_language(ln) # load the right message language _ = gettext_set_language(ln) t="" # get user ID: try: uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../publiline.py/index", navmenuid='yourapprovals') uid_email = get_email(uid) except Error, e: return errorMsg(e.value,req, ln = ln) if doctype == "": t = selectDoctype(ln) elif categ == "": t = selectCateg(doctype, ln) elif RN == "": t = selectDocument(doctype,categ, ln) else: - t = displayDocument(doctype,categ,RN,send, ln) + t = displayDocument(req, doctype,categ,RN,send, ln) return page(title="publication line", navtrail= """%(account)s""" % { 'sweburl' : sweburl, 'account' : _("Your Account"), }, body=t, description="", keywords="", uid=uid, language=ln, req=req, navmenuid='yourapprovals') def selectDoctype(ln = cdslang): res = run_sql("select DISTINCT doctype from sbmAPPROVAL") docs = [] for row in res: res2 = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (row[0],)) docs.append({ 'doctype' : row[0], 'docname' : res2[0][0], }) t = websubmit_templates.tmpl_publiline_selectdoctype( ln = ln, docs = docs, ) return t def selectCateg(doctype, ln = cdslang): t="" res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s",(doctype,)) title = res[0][0] sth = run_sql("select * from sbmCATEGORIES where doctype=%s order by lname",(doctype,)) if len(sth) == 0: categ = "unknown" return selectDocument(doctype,categ, ln = ln) categories = [] for arr in sth: waiting = 0 rejected = 0 approved = 0 sth2 = run_sql("select COUNT(*) from sbmAPPROVAL where doctype=%s and categ=%s and status='waiting'", (doctype,arr[1],)) waiting = sth2[0][0] sth2 = run_sql("select COUNT(*) from sbmAPPROVAL where doctype=%s and categ=%s and status='approved'",(doctype,arr[1],)) approved = sth2[0][0] sth2 = run_sql("select COUNT(*) from sbmAPPROVAL where doctype=%s and categ=%s and status='rejected'",(doctype,arr[1],)) rejected = sth2[0][0] categories.append({ 'waiting' : waiting, 'approved' : approved, 'rejected' : rejected, 'id' : arr[1], }) t = websubmit_templates.tmpl_publiline_selectcateg( ln = ln, categories = categories, doctype = doctype, title = title, images = images, ) return t def selectDocument(doctype,categ, ln = cdslang): t="" res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (doctype,)) title = res[0][0] if categ == "": categ == "unknown" docs = [] sth = run_sql("select rn,status from sbmAPPROVAL where doctype=%s and categ=%s order by status DESC,rn DESC",(doctype,categ)) for arr in sth: docs.append({ 'RN' : arr[0], 'status' : arr[1], }) t = websubmit_templates.tmpl_publiline_selectdocument( ln = ln, doctype = doctype, title = title, categ = categ, images = images, docs = docs, ) return t -def displayDocument(doctype,categ,RN,send, ln = cdslang): +def displayDocument(req, doctype,categ,RN,send, ln = cdslang): # load the right message language _ = gettext_set_language(ln) t="" res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (doctype,)) docname = res[0][0] if categ == "": categ = "unknown" sth = run_sql("select rn,status,dFirstReq,dLastReq,dAction,access from sbmAPPROVAL where rn=%s",(RN,)) if len(sth) > 0: arr = sth[0] rn = arr[0] status = arr[1] dFirstReq = arr[2] dLastReq = arr[3] dAction = arr[4] access = arr[5] else: return _("Approval has never been requested for this document.") + "
     " try: (authors,title,sysno,newrn) = getInfo(doctype,categ,RN) except TypeError: return _("Unable to display document.") confirm_send = 0 if send == _("Send Again"): if authors == "unknown" or title == "unknown": SendWarning(doctype,categ,RN,title,authors,access, ln = ln) else: # @todo - send in different languages SendEnglish(doctype,categ,RN,title,authors,access,sysno) run_sql("update sbmAPPROVAL set dLastReq=NOW() where rn=%s",(RN,)) confirm_send = 1 if status == "waiting": - (auth_code, auth_message) = acc_authorize_action(uid, "referee",verbose=0,doctype=doctype, categ=categ) + (auth_code, auth_message) = acc_authorize_action(req, "referee",verbose=0,doctype=doctype, categ=categ) else: (auth_code, auth_message) = (None, None) - + t = websubmit_templates.tmpl_publiline_displaydoc( ln = ln, docname = docname, doctype = doctype, categ = categ, rn = rn, status = status, dFirstReq = dFirstReq, dLastReq = dLastReq, dAction = dAction, access = access, images = images, accessurl = accessurl, confirm_send = confirm_send, auth_code = auth_code, auth_message = auth_message, authors = authors, title = title, sysno = sysno, newrn = newrn, ) return t # Retrieve info about document def getInfo(doctype,categ,RN): result = getInPending(doctype,categ,RN) if not result: result = getInAlice(doctype,categ,RN) return result #seek info in pending directory def getInPending(doctype,categ,RN): PENDIR="%s/pending" % storage if os.path.exists("%s/%s/%s/AU" % (PENDIR,doctype,RN)): fp = open("%s/%s/%s/AU" % (PENDIR,doctype,RN),"r") authors=fp.read() fp.close() else: authors = "" if os.path.exists("%s/%s/%s/TI" % (PENDIR,doctype,RN)): fp = open("%s/%s/%s/TI" % (PENDIR,doctype,RN),"r") title=fp.read() fp.close() else: title = "" if os.path.exists("%s/%s/%s/SN" % (PENDIR,doctype,RN)): fp = open("%s/%s/%s/SN" % (PENDIR,doctype,RN),"r") sysno=fp.read() fp.close() else: sysno = "" if title == "" and os.path.exists("%s/%s/%s/TIF" % (PENDIR,doctype,RN)): fp = open("%s/%s/%s/TIF" % (PENDIR,doctype,RN),"r") title=fp.read() fp.close() if title == "": return 0 else: return (authors,title,sysno,"") #seek info in Alice database def getInAlice(doctype,categ,RN): # initialize sysno variable sysno = "" searchresults = search_pattern(req=None, p=RN, f="reportnumber").items().tolist() if len(searchresults) == 0: return 0 sysno = searchresults[0] if sysno != "": title = Get_Field('245__a',sysno) emailvalue = Get_Field('8560_f',sysno) authors = Get_Field('100__a',sysno) authors += "\n%s" % Get_Field('700__a',sysno) newrn = Get_Field('037__a',sysno) return (authors,title,sysno,newrn) else: return 0 def SendEnglish(doctype,categ,RN,title,authors,access,sysno): FROMADDR = '%s Submission Engine <%s>' % (cdsname,supportemail) # retrieve useful information from webSubmit configuration res = run_sql("select value from sbmPARAMETERS where name='categformatDAM' and doctype=%s", (doctype,)) categformat = res[0][0] categformat = re.sub("","([^-]*)",categformat) categs = re.match(categformat,RN) if categs is not None: categ = categs.group(1) else: categ = "unknown" res = run_sql("select value from sbmPARAMETERS where name='addressesDAM' and doctype=%s",(doctype,)) if len(res) > 0: otheraddresses = res[0][0] otheraddresses = otheraddresses.replace("",categ) else: otheraddresses = "" # Build referee's email address refereeaddress = "" # Try to retrieve the referee's email from the referee's database for user in acc_getRoleUsers(acc_getRoleId("referee_%s_%s" % (doctype,categ))): refereeaddress += user[1] + "," # And if there are general referees for user in acc_getRoleUsers(acc_getRoleId("referee_%s_*" % doctype)): refereeaddress += user[1] + "," refereeaddress = re.sub(",$","",refereeaddress) # Creation of the mail for the referee addresses = "" if refereeaddress != "": addresses = refereeaddress + "," if otheraddresses != "": addresses += otheraddresses else: addresses = re.sub(",$","",addresses) if addresses=="": SendWarning(doctype,categ,RN,title,authors,access) return 0 if authors == "": authors = "-" res = run_sql("select value from sbmPARAMETERS where name='directory' and doctype=%s", (doctype,)) directory = res[0][0] message = """ The document %s has been published as a Communication. Your approval is requested for it to become an official Note. Title: %s Author(s): %s To access the document(s), select the file(s) from the location: <%s/record/%s/files/> To approve/reject the document, you should go to this URL: <%s/approve.py?%s> --------------------------------------------- Best regards. The submission team.""" % (RN,title,authors,urlpath,sysno,urlpath,access) # send the mail body = forge_email(FROMADDR,addresses,adminemail,"Request for Approval of %s" % RN,message) send_email(FROMADDR,addresses,body,0) return "" def SendWarning(doctype,categ,RN,title,authors,access): FROMADDR = '%s Submission Engine <%s>' % (cdsname,supportemail) message = "Failed sending approval email request for %s" % RN # send the mail body = forge_email(FROMADDR,adminemail,"","Failed sending approval email request",message) send_email(FROMADDR,adminemail,body,0) return "" def errorMsg(title,req,c=cdsname,ln=cdslang): return page(title="error", body = create_error_box(req, title=title,verbose=0, ln=ln), description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='yourapprovals') def warningMsg(title,req,c=cdsname,ln=cdslang): return page(title="warning", body = title, description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='yourapprovals') diff --git a/modules/websubmit/web/yourapprovals.py b/modules/websubmit/web/yourapprovals.py index 7b4f17870..531d86092 100644 --- a/modules/websubmit/web/yourapprovals.py +++ b/modules/websubmit/web/yourapprovals.py @@ -1,122 +1,122 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" ## import interesting modules: import os import sys from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_SITE, \ cdslang, \ cdsname, \ sweburl, \ version from invenio.dbquery import run_sql, Error from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import * from invenio.webpage import page, create_error_box from invenio.webuser import getUid, get_email, list_registered_users, page_not_authorized from invenio.messages import gettext_set_language, wash_language from invenio.websubmit_config import * from invenio.search_engine import search_pattern import invenio.template websubmit_templates = invenio.template.load('websubmit') def index(req,c=cdsname,ln=cdslang,order="",doctype="",deletedId="",deletedAction="",deletedDoctype=""): global uid ln = wash_language(ln) # load the right message language _ = gettext_set_language(ln) t="" # get user ID: try: uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../yourapprovals.py/index", navmenuid='yourapprovals') u_email = get_email(uid) except Error, e: return errorMsg(e.value,req, ln = ln) res = run_sql("select sdocname,ldocname from sbmDOCTYPE") referees = [] for row in res: doctype = row[0] docname = row[1] reftext = "" - if isReferee(uid,doctype,"*"): + if isReferee(req,doctype,"*"): referees.append ({'doctype': doctype, 'docname': docname, 'categories': None}) else: res2 = run_sql("select sname,lname from sbmCATEGORIES where doctype=%s",(doctype,)) categories = [] for row2 in res2: category = row2[0] categname = row2[1] - if isReferee(uid,doctype,category): + if isReferee(req,doctype,category): categories.append({ 'id' : category, 'name' : categname, }) referees.append({ 'doctype' : doctype, 'docname' : docname, 'categories' : categories }) t = websubmit_templates.tmpl_yourapprovals( ln = ln, referees = referees ) return page(title=_("Your Approvals"), navtrail= """%(account)s""" % { 'sweburl' : sweburl, 'account' : _("Your Account"), }, body=t, description="", keywords="", uid=uid, language=ln, req=req, navmenuid='yourapprovals') -def isReferee(uid,doctype="",categ=""): - (auth_code, auth_message) = acc_authorize_action(uid, "referee",verbose=0,doctype=doctype, categ=categ) +def isReferee(req,doctype="",categ=""): + (auth_code, auth_message) = acc_authorize_action(req, "referee",verbose=0,doctype=doctype, categ=categ) if auth_code == 0: return 1 else: return 0 def errorMsg(title,req,c=cdsname,ln=cdslang): return page(title="error", body = create_error_box(req, title=title,verbose=0, ln=ln), description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='yourapprovals') diff --git a/modules/websubmit/web/yoursubmissions.py b/modules/websubmit/web/yoursubmissions.py index 221ad7139..c729b3c10 100644 --- a/modules/websubmit/web/yoursubmissions.py +++ b/modules/websubmit/web/yoursubmissions.py @@ -1,216 +1,216 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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. __revision__ = "$Id$" ## import interesting modules: import string import os import sys import time import types import re import shutil import operator from invenio.config import \ CFG_ACCESS_CONTROL_LEVEL_SITE, \ cdslang, \ cdsname, \ images, \ storage, \ sweburl, \ version, \ weburl from invenio.dbquery import run_sql, Error from invenio.access_control_engine import acc_authorize_action from invenio.access_control_admin import * from invenio.webpage import page, create_error_box from invenio.webuser import getUid, get_email, list_registered_users, page_not_authorized from invenio.messages import gettext_set_language, wash_language from invenio.websubmit_config import * from invenio.search_engine import search_pattern import invenio.template websubmit_templates = invenio.template.load('websubmit') def index(req,c=cdsname,ln=cdslang,order="",doctype="",deletedId="",deletedAction="",deletedDoctype=""): global uid ln = wash_language(ln) # load the right message language _ = gettext_set_language(ln) t="" # get user ID: try: uid = getUid(req) if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1: return page_not_authorized(req, "../yoursubmissions.py/index", navmenuid='yoursubmissions') u_email = get_email(uid) except Error, e: return errorMsg(e.value, req, ln) if u_email == "guest" or u_email == "": return warningMsg(websubmit_templates.tmpl_warning_message( ln = ln, msg = _("Sorry, you must log in to perform this action."), ),req, ln = ln) if deletedId != "": t += deleteSubmission(deletedId,deletedAction,deletedDoctype,u_email) # doctypes res = run_sql("select ldocname,sdocname from sbmDOCTYPE order by ldocname") doctypes = [] for row in res: doctypes.append({ 'id' : row[1], 'name' : row[0], 'selected' : (doctype == row[1]), }) # submissions # request order default value reqorder = "sbmSUBMISSIONS.md DESC, lactname" # requested value if order == "actiondown": reqorder = "lactname ASC, sbmSUBMISSIONS.md DESC" elif order == "actionup": reqorder = "lactname DESC, sbmSUBMISSIONS.md DESC" elif order == "refdown": reqorder = "reference ASC, sbmSUBMISSIONS.md DESC, lactname DESC" elif order == "refup": reqorder = "reference DESC, sbmSUBMISSIONS.md DESC, lactname DESC" elif order == "cddown": reqorder = "sbmSUBMISSIONS.cd DESC, lactname" elif order == "cdup": reqorder = "sbmSUBMISSIONS.cd ASC, lactname" elif order == "mddown": reqorder = "sbmSUBMISSIONS.md DESC, lactname" elif order == "mdup": reqorder = "sbmSUBMISSIONS.md ASC, lactname" elif order == "statusdown": reqorder = "sbmSUBMISSIONS.status DESC, lactname" elif order == "statusup": reqorder = "sbmSUBMISSIONS.status ASC, lactname" if doctype != "": docselect = " and doctype='%s' " % doctype else: docselect = "" res = run_sql("SELECT sbmSUBMISSIONS.* FROM sbmSUBMISSIONS,sbmACTION WHERE sactname=action and email=%s and id!='' "+docselect+" ORDER BY doctype,"+reqorder,(u_email,)) currentdoctype = "" currentaction = "" currentstatus = "" submissions = [] for row in res: if currentdoctype != row[1]: currentdoctype = row[1] currentaction = "" currentstatus = "" res2 = run_sql("SELECT ldocname FROM sbmDOCTYPE WHERE sdocname=%s",(currentdoctype,)) if res2: ldocname = res2[0][0] else: ldocname = """***Unknown Document Type - (%s)""" % (currentdoctype,) if currentaction != row[2]: currentaction = row[2] res2 = run_sql("SELECT lactname FROM sbmACTION WHERE sactname=%s",(currentaction,)) if res2: lactname = res2[0][0] else: lactname = "\"" else: lactname = "\"" if currentstatus != row[3]: currentstatus = row[3] status=row[3] else: status = "\"" submissions.append({ 'docname' : ldocname, 'actname' : lactname, 'status' : status, 'cdate' : row[6], 'mdate' : row[7], 'reference' : row[5], 'id' : row[4], 'act' : currentaction, 'doctype' : currentdoctype, 'pending' : (row[3] == "pending") }) # display t += websubmit_templates.tmpl_yoursubmissions( ln = ln, weburl = weburl, images = images, order = order, doctypes = doctypes, submissions = submissions, ) return page(title=_("Your Submissions"), navtrail= """%(account)s""" % { 'sweburl' : sweburl, 'account' : _("Your Account"), }, body=t, description="", keywords="", uid=uid, language=ln, req=req, navmenuid='yoursubmissions') def deleteSubmission(id, action, doctype, u_email): global storage run_sql("delete from sbmSUBMISSIONS WHERE doctype=%s and action=%s and email=%s and status='pending' and id=%s",(doctype,action,u_email,id,)) res = run_sql("select dir from sbmACTION where sactname=%s",(action,)) dir = res[0][0] if not ('..' in doctype or '..' in id) and id != "": full = os.path.join(storage, dir, doctype, id) if os.path.isdir(full): - shutil.rmtree(full) + shutil.rmtree(full) return "" def warningMsg(title,req,c=cdsname,ln=cdslang): return page(title="warning", body = title, description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='yoursubmissions') def errorMsg(title,req,c=cdsname,ln=cdslang): return page(title="error", body = create_error_box(req, title=title,verbose=0, ln=ln), description="%s - Internal Error" % c, keywords="%s, CDS Invenio, Internal Error" % c, language=ln, req=req, navmenuid='yoursubmissions')